Initial Contribution

msm-2.6.38: tag AU_LINUX_ANDROID_GINGERBREAD.02.03.04.00.142

Signed-off-by: Bryan Huntsman <bryanh@codeaurora.org>
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 52798a1..4ba9432 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -443,4 +443,38 @@
 # TI's ST based wl128x FM radio
 source "drivers/media/radio/wl128x/Kconfig"
 
+config RADIO_TAVARUA
+	tristate "Qualcomm Tavaraua I2C FM support"
+	depends on I2C && VIDEO_V4L2 && MARIMBA_CORE
+	default n
+	---help---
+	  Say Y here if you want to use the Qualcomm FM chip (Tavarua).
+	  This FM chip uses I2C interface.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called radio-tavarua.
+
+config RADIO_IRIS
+        tristate "Qualcomm IRIS FM support"
+        depends on VIDEO_V4L2
+        default n
+        ---help---
+          Say Y here if you want to use the Qualcomm FM chip (IRIS).
+          This FM chip uses SMD interface
+
+          To compile this driver as a module, choose M here: the
+          module will be called radio-iris.
+
+
+config RADIO_IRIS_TRANSPORT
+        tristate "Qualcomm IRIS Transport"
+        depends on RADIO_IRIS
+        default n
+        ---help---
+          Say Y here if you want to use the Qualcomm FM chip (IRIS).
+          with SMD as transport.
+
+          To compile this driver as a module, choose M here: the
+          module will be called radio-iris-transport.
+
 endif # RADIO_ADAPTERS
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index f484a6e..3337f4b 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -26,5 +26,8 @@
 obj-$(CONFIG_RADIO_TIMBERDALE) += radio-timb.o
 obj-$(CONFIG_RADIO_WL1273) += radio-wl1273.o
 obj-$(CONFIG_RADIO_WL128X) += wl128x/
+obj-$(CONFIG_RADIO_TAVARUA) += radio-tavarua.o
+obj-$(CONFIG_RADIO_IRIS) += radio-iris.o
+obj-$(CONFIG_RADIO_IRIS_TRANSPORT) += radio-iris-transport.o
 
 EXTRA_CFLAGS += -Isound
diff --git a/drivers/media/radio/radio-iris-transport.c b/drivers/media/radio/radio-iris-transport.c
new file mode 100644
index 0000000..6628c9d
--- /dev/null
+++ b/drivers/media/radio/radio-iris-transport.c
@@ -0,0 +1,165 @@
+/*
+ *  Qualcomm's FM Shared Memory Transport Driver
+ *
+ *  FM HCI_SMD ( FM HCI Shared Memory Driver) is Qualcomm's Shared memory driver
+ *  for the HCI protocol. This file is based on drivers/bluetooth/hci_vhci.c
+ *
+ *  Copyright (c) 2000-2001, 2011 Code Aurora Forum. All rights reserved.
+ *
+ *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
+ *  Copyright (C) 2004-2006  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation
+ *
+ *  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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <mach/msm_smd.h>
+#include <media/radio-iris.h>
+
+struct radio_data {
+	struct radio_hci_dev *hdev;
+	struct tasklet_struct   rx_task;
+	struct smd_channel  *fm_channel;
+};
+struct radio_data hs;
+
+static void radio_hci_smd_destruct(struct radio_hci_dev *hdev)
+{
+	radio_hci_unregister_dev(hs.hdev);
+}
+
+
+static void radio_hci_smd_recv_event(unsigned long temp)
+{
+	int len;
+	int rc;
+	struct sk_buff *skb;
+	unsigned  char *buf;
+	struct radio_data *hsmd = &hs;
+	len = smd_read_avail(hsmd->fm_channel);
+
+	while (len) {
+		skb = alloc_skb(len, GFP_KERNEL);
+		if (!skb) {
+			FMDERR("Memory not allocated for the socket");
+			return;
+		}
+
+		buf = kmalloc(len, GFP_KERNEL);
+		if (!buf) {
+			kfree_skb(skb);
+			FMDERR("Error in allocating buffer memory");
+			return;
+		}
+
+		rc = smd_read_from_cb(hsmd->fm_channel, (void *)buf, len);
+
+		memcpy(skb_put(skb, len), buf, len);
+
+		skb_orphan(skb);
+		skb->dev = (struct net_device   *)hs.hdev;
+
+		rc = radio_hci_recv_frame(skb);
+
+		kfree(buf);
+		len = smd_read_avail(hsmd->fm_channel);
+	}
+}
+
+static int radio_hci_smd_send_frame(struct sk_buff *skb)
+{
+	int len = 0;
+
+	len = smd_write(hs.fm_channel, skb->data, skb->len);
+	if (len < skb->len) {
+		FMDERR("Failed to write Data %d", len);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static void radio_hci_smd_notify_cmd(void *data, unsigned int event)
+{
+	struct radio_hci_dev *hdev = hs.hdev;
+
+	if (!hdev) {
+		FMDERR("Frame for unknown HCI device (hdev=NULL)");
+		return;
+	}
+
+	switch (event) {
+	case SMD_EVENT_DATA:
+		tasklet_schedule(&hs.rx_task);
+		break;
+	case SMD_EVENT_OPEN:
+	case SMD_EVENT_CLOSE:
+		break;
+	default:
+		break;
+	}
+}
+
+static int radio_hci_smd_register_dev(struct radio_data *hsmd)
+{
+	struct radio_hci_dev *hdev;
+	int rc;
+
+	hdev = kmalloc(sizeof(struct radio_hci_dev), GFP_KERNEL);
+	hsmd->hdev = hdev;
+	tasklet_init(&hsmd->rx_task, radio_hci_smd_recv_event,
+		(unsigned long) hsmd);
+	hdev->send  = radio_hci_smd_send_frame;
+	hdev->destruct = radio_hci_smd_destruct;
+
+	/* Open the SMD Channel and device and register the callback function */
+	rc = smd_named_open_on_edge("APPS_FM", SMD_APPS_WCNSS,
+		&hsmd->fm_channel, hdev, radio_hci_smd_notify_cmd);
+
+	if (rc < 0) {
+		FMDERR("Cannot open the command channel");
+		return -ENODEV;
+	}
+
+	smd_disable_read_intr(hsmd->fm_channel);
+
+	if (radio_hci_register_dev(hdev) < 0) {
+		FMDERR("Can't register HCI device");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void radio_hci_smd_deregister(void)
+{
+	smd_close(hs.fm_channel);
+	hs.fm_channel = 0;
+}
+
+static int radio_hci_smd_init(void)
+{
+	return radio_hci_smd_register_dev(&hs);
+}
+module_init(radio_hci_smd_init);
+
+static void __exit radio_hci_smd_exit(void)
+{
+	radio_hci_smd_deregister();
+}
+module_exit(radio_hci_smd_exit);
+
+MODULE_DESCRIPTION("Bluetooth SMD driver");
+MODULE_AUTHOR("Ankur Nandwani <ankurn@codeaurora.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
new file mode 100644
index 0000000..fe53ca8
--- /dev/null
+++ b/drivers/media/radio/radio-iris.c
@@ -0,0 +1,2220 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#define DRIVER_AUTHOR "Archana Ramchandran <archanar@codeaurora.org>"
+#define DRIVER_NAME "radio-iris"
+#define DRIVER_CARD "Qualcomm FM Radio Transceiver"
+#define DRIVER_DESC "Driver for Qualcomm FM Radio Transceiver "
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/kfifo.h>
+#include <linux/param.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
+#include <linux/mutex.h>
+#include <linux/unistd.h>
+#include <linux/atomic.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/radio-iris.h>
+#include <asm/unaligned.h>
+
+static unsigned int rds_buf = 100;
+module_param(rds_buf, uint, 0);
+MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
+
+static void radio_hci_cmd_task(unsigned long arg);
+static void radio_hci_rx_task(unsigned long arg);
+static struct video_device *video_get_dev(void);
+static DEFINE_RWLOCK(hci_task_lock);
+
+struct iris_device {
+	struct device *dev;
+	struct kfifo data_buf[IRIS_BUF_MAX];
+
+	int pending_xfrs[IRIS_XFR_MAX];
+	int xfr_bytes_left;
+	int xfr_in_progress;
+	struct completion sync_xfr_start;
+	int tune_req;
+
+	struct video_device *videodev;
+
+	struct mutex lock;
+	spinlock_t buf_lock[IRIS_BUF_MAX];
+	wait_queue_head_t event_queue;
+	wait_queue_head_t read_queue;
+
+	struct radio_hci_dev *fm_hdev;
+
+	struct v4l2_capability *g_cap;
+	struct v4l2_control *g_ctl;
+
+	struct hci_fm_mute_mode_req mute_mode;
+	struct hci_fm_stereo_mode_req stereo_mode;
+	struct hci_fm_station_rsp fm_st_rsp;
+	struct hci_fm_search_station_req srch_st;
+	struct hci_fm_search_rds_station_req srch_rds;
+	struct hci_fm_search_station_list_req srch_st_list;
+	struct hci_fm_recv_conf_req recv_conf;
+	struct hci_fm_rds_grp_req rds_grp;
+	unsigned char g_search_mode;
+	unsigned char g_scan_time;
+	unsigned int g_antenna;
+	unsigned int g_rds_grp_proc_ps;
+	enum iris_region_t region;
+	struct hci_fm_dbg_param_rsp st_dbg_param;
+	struct hci_ev_srch_list_compl srch_st_result;
+};
+
+static struct video_device *priv_videodev;
+
+static struct v4l2_queryctrl iris_v4l2_queryctrl[] = {
+	{
+	.id	= V4L2_CID_AUDIO_VOLUME,
+	.type	= V4L2_CTRL_TYPE_INTEGER,
+	.name	= "Volume",
+	.minimum	= 0,
+	.maximum	= 15,
+	.step	=	1,
+	.default_value	=	15,
+	},
+	{
+	.id	=	V4L2_CID_AUDIO_BALANCE,
+	.flags	= V4L2_CTRL_FLAG_DISABLED,
+	},
+	{
+	.id	=	V4L2_CID_AUDIO_BASS,
+	.flags	=	V4L2_CTRL_FLAG_DISABLED,
+	},
+	{
+	.id	=	V4L2_CID_AUDIO_TREBLE,
+	.flags	=	V4L2_CTRL_FLAG_DISABLED,
+	},
+	{
+	.id	=	V4L2_CID_AUDIO_MUTE,
+	.type	=	V4L2_CTRL_TYPE_BOOLEAN,
+	.name	=	"Mute",
+	.minimum	=	0,
+	.maximum	=	1,
+	.step	=	1,
+	.default_value	= 1,
+	},
+	{
+	.id	=	V4L2_CID_AUDIO_LOUDNESS,
+	.flags	=	V4L2_CTRL_FLAG_DISABLED,
+	},
+	{
+	.id	=	V4L2_CID_PRIVATE_IRIS_SRCHMODE,
+	.type	=	V4L2_CTRL_TYPE_INTEGER,
+	.name	=	"Search mode",
+	.minimum	=	0,
+	.maximum	= 7,
+	.step	= 1,
+	.default_value	= 0,
+	},
+	{
+	.id	= V4L2_CID_PRIVATE_IRIS_SCANDWELL,
+	.type	= V4L2_CTRL_TYPE_INTEGER,
+	.name	=	"Search dwell time",
+	.minimum	= 0,
+	.maximum	= 7,
+	.step	= 1,
+	.default_value	= 0,
+	},
+	{
+	.id	= V4L2_CID_PRIVATE_IRIS_SRCHON,
+	.type	= V4L2_CTRL_TYPE_BOOLEAN,
+	.name	= "Search on/off",
+	.minimum	= 0,
+	.maximum	= 1,
+	.step	= 1,
+	.default_value	= 1,
+
+	},
+	{
+	.id	=	V4L2_CID_PRIVATE_IRIS_STATE,
+	.type	= V4L2_CTRL_TYPE_INTEGER,
+	.name	= "radio 0ff/rx/tx/reset",
+	.minimum	= 0,
+	.maximum	= 3,
+	.step	= 1,
+	.default_value	=	1,
+
+	},
+	{
+	.id	= V4L2_CID_PRIVATE_IRIS_REGION,
+	.type	= V4L2_CTRL_TYPE_INTEGER,
+	.name	=	"radio standard",
+	.minimum	=	0,
+	.maximum	=	2,
+	.step	=	1,
+	.default_value	=	0,
+	},
+	{
+	.id	=	V4L2_CID_PRIVATE_IRIS_SIGNAL_TH,
+	.type	=	V4L2_CTRL_TYPE_INTEGER,
+	.name	=	"Signal Threshold",
+	.minimum	=	0x80,
+	.maximum	=	0x7F,
+	.step	=	1,
+	.default_value	=	0,
+	},
+	{
+	.id	=	V4L2_CID_PRIVATE_IRIS_SRCH_PTY,
+	.type	=	V4L2_CTRL_TYPE_INTEGER,
+	.name	=	"Search PTY",
+	.minimum	=	0,
+	.maximum	=	31,
+	.default_value	=	0,
+	},
+	{
+	.id	=	V4L2_CID_PRIVATE_IRIS_SRCH_PI,
+	.type	=	V4L2_CTRL_TYPE_INTEGER,
+	.name	=	"Search PI",
+	.minimum	=	0,
+	.maximum	=	0xFF,
+	.default_value	=	0,
+	},
+	{
+	.id	=	V4L2_CID_PRIVATE_IRIS_SRCH_CNT,
+	.type	=	V4L2_CTRL_TYPE_INTEGER,
+	.name	=	"Preset num",
+	.minimum	=	0,
+	.maximum	=	12,
+	.default_value	=	0,
+	},
+	{
+	.id	=	V4L2_CID_PRIVATE_IRIS_EMPHASIS,
+	.type	=	V4L2_CTRL_TYPE_BOOLEAN,
+	.name	=	"Emphasis",
+	.minimum	=	0,
+	.maximum	=	1,
+	.default_value	=	0,
+	},
+	{
+	.id	=	V4L2_CID_PRIVATE_IRIS_RDS_STD,
+	.type	=	V4L2_CTRL_TYPE_BOOLEAN,
+	.name	=	"RDS standard",
+	.minimum	=	0,
+	.maximum	=	1,
+	.default_value	=	0,
+	},
+	{
+	.id	=	V4L2_CID_PRIVATE_IRIS_SPACING,
+	.type	=	V4L2_CTRL_TYPE_INTEGER,
+	.name	=	"Channel spacing",
+	.minimum	=	0,
+	.maximum	=	2,
+	.default_value	=	0,
+	},
+	{
+	.id	=	V4L2_CID_PRIVATE_IRIS_RDSON,
+	.type	=	V4L2_CTRL_TYPE_BOOLEAN,
+	.name	=	"RDS on/off",
+	.minimum	=	0,
+	.maximum	=	1,
+	.default_value	=	0,
+	},
+	{
+	.id	=	V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK,
+	.type	=	V4L2_CTRL_TYPE_INTEGER,
+	.name	=	"RDS group mask",
+	.minimum	=	0,
+	.maximum	=	0xFFFFFFFF,
+	.default_value	=	0,
+	},
+	{
+	.id	=	V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC,
+	.type	=	V4L2_CTRL_TYPE_INTEGER,
+	.name	=	"RDS processing",
+	.minimum	=	0,
+	.maximum	=	0xFF,
+	.default_value	=	0,
+	},
+	{
+	.id	=	V4L2_CID_PRIVATE_IRIS_RDSD_BUF,
+	.type	=	V4L2_CTRL_TYPE_INTEGER,
+	.name	=	"RDS data groups to buffer",
+	.minimum	=	1,
+	.maximum	=	21,
+	.default_value	=	0,
+	},
+	{
+	.id	=	V4L2_CID_PRIVATE_IRIS_PSALL,
+	.type	=	V4L2_CTRL_TYPE_BOOLEAN,
+	.name	=	"pass all ps strings",
+	.minimum	=	0,
+	.maximum	=	1,
+	.default_value	=	0,
+	},
+	{
+	.id	=	V4L2_CID_PRIVATE_IRIS_LP_MODE,
+	.type	=	V4L2_CTRL_TYPE_BOOLEAN,
+	.name	=	"Low power mode",
+	.minimum	=	0,
+	.maximum	=	1,
+	.default_value	=	0,
+	},
+	{
+	.id	=	V4L2_CID_PRIVATE_IRIS_ANTENNA,
+	.type	=	V4L2_CTRL_TYPE_BOOLEAN,
+	.name	=	"headset/internal",
+	.minimum	=	0,
+	.maximum	=	1,
+	.default_value	=	0,
+	},
+
+	{
+	.id	=	V4L2_CID_PRIVATE_IRIS_TX_SETPSREPEATCOUNT,
+	.type	=	V4L2_CTRL_TYPE_INTEGER,
+	.name	=	"Set PS REPEATCOUNT",
+	.minimum	=	0,
+	.maximum	=	15,
+	},
+	{
+	.id	=	V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_PS_NAME,
+	.type	=	V4L2_CTRL_TYPE_BOOLEAN,
+	.name	=	"Stop PS NAME",
+	.minimum	=	0,
+	.maximum	=	1,
+	},
+	{
+	.id	=	V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_RT,
+	.type	=	V4L2_CTRL_TYPE_BOOLEAN,
+	.name	=	"Stop RT",
+	.minimum	=	0,
+	.maximum	=	1,
+	},
+
+};
+
+static void iris_q_event(struct iris_device *radio,
+				enum iris_evt_t event)
+{
+	struct kfifo *data_b = &radio->data_buf[IRIS_BUF_EVENTS];
+	unsigned char evt = event;
+	if (kfifo_in_locked(data_b, &evt, 1, &radio->buf_lock[IRIS_BUF_EVENTS]))
+		wake_up_interruptible(&radio->event_queue);
+}
+
+static int hci_send_frame(struct sk_buff *skb)
+{
+	struct radio_hci_dev *hdev = (struct radio_hci_dev *) skb->dev;
+
+	if (!hdev) {
+		kfree_skb(skb);
+		return -ENODEV;
+	}
+
+	__net_timestamp(skb);
+
+	skb_orphan(skb);
+	return hdev->send(skb);
+}
+
+static void radio_hci_cmd_task(unsigned long arg)
+{
+	struct radio_hci_dev *hdev = (struct radio_hci_dev *) arg;
+	struct sk_buff *skb;
+	if (!(atomic_read(&hdev->cmd_cnt))
+		&& time_after(jiffies, hdev->cmd_last_tx + HZ)) {
+		FMDERR("%s command tx timeout", hdev->name);
+		atomic_set(&hdev->cmd_cnt, 1);
+	}
+
+	skb = skb_dequeue(&hdev->cmd_q);
+	if (atomic_read(&hdev->cmd_cnt) && skb) {
+		kfree_skb(hdev->sent_cmd);
+		hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC);
+		if (hdev->sent_cmd) {
+			atomic_dec(&hdev->cmd_cnt);
+			hci_send_frame(skb);
+			hdev->cmd_last_tx = jiffies;
+		} else {
+			skb_queue_head(&hdev->cmd_q, skb);
+			tasklet_schedule(&hdev->cmd_task);
+		}
+	}
+
+}
+
+static void radio_hci_rx_task(unsigned long arg)
+{
+	struct radio_hci_dev *hdev = (struct radio_hci_dev *) arg;
+	struct sk_buff *skb;
+
+	read_lock(&hci_task_lock);
+
+	skb = skb_dequeue(&hdev->rx_q);
+	radio_hci_event_packet(hdev, skb);
+
+	read_unlock(&hci_task_lock);
+}
+
+int radio_hci_register_dev(struct radio_hci_dev *hdev)
+{
+	struct iris_device *radio = video_get_drvdata(video_get_dev());
+	if (!radio) {
+		FMDERR(":radio is null");
+		return -EINVAL;
+	}
+
+	if (!hdev) {
+		FMDERR("hdev is null");
+		return -EINVAL;
+	}
+
+	hdev->flags = 0;
+
+	tasklet_init(&hdev->cmd_task, radio_hci_cmd_task, (unsigned long)
+		hdev);
+	tasklet_init(&hdev->rx_task, radio_hci_rx_task, (unsigned long)
+		hdev);
+
+	init_waitqueue_head(&hdev->req_wait_q);
+
+	skb_queue_head_init(&hdev->rx_q);
+	skb_queue_head_init(&hdev->cmd_q);
+	skb_queue_head_init(&hdev->raw_q);
+
+	if (!radio)
+		FMDERR(":radio is null");
+
+	radio->fm_hdev = hdev;
+
+	return 0;
+}
+EXPORT_SYMBOL(radio_hci_register_dev);
+
+int radio_hci_unregister_dev(struct radio_hci_dev *hdev)
+{
+	struct iris_device *radio = video_get_drvdata(video_get_dev());
+	if (!radio) {
+		FMDERR(":radio is null");
+		return -EINVAL;
+	}
+
+	tasklet_kill(&hdev->rx_task);
+	tasklet_kill(&hdev->cmd_task);
+	skb_queue_purge(&hdev->rx_q);
+	skb_queue_purge(&hdev->cmd_q);
+	skb_queue_purge(&hdev->raw_q);
+	kfree(radio->fm_hdev);
+	kfree(radio->videodev);
+
+	return 0;
+}
+EXPORT_SYMBOL(radio_hci_unregister_dev);
+
+int radio_hci_recv_frame(struct sk_buff *skb)
+{
+	struct radio_hci_dev *hdev = (struct radio_hci_dev *) skb->dev;
+	if (!hdev) {
+		FMDERR("%s hdev is null while receiving frame", hdev->name);
+		kfree_skb(skb);
+		return -ENXIO;
+	}
+
+	__net_timestamp(skb);
+
+	radio_hci_event_packet(hdev, skb);
+
+	return 0;
+}
+EXPORT_SYMBOL(radio_hci_recv_frame);
+
+int radio_hci_send_cmd(struct radio_hci_dev *hdev, __u16 opcode, __u32 plen,
+		void *param)
+{
+	int len = RADIO_HCI_COMMAND_HDR_SIZE + plen;
+	struct radio_hci_command_hdr *hdr;
+	struct sk_buff *skb;
+	int ret = 0;
+
+	skb = alloc_skb(len, GFP_ATOMIC);
+	if (!skb) {
+		FMDERR("%s no memory for command", hdev->name);
+		return -ENOMEM;
+	}
+
+	hdr = (struct radio_hci_command_hdr *) skb_put(skb,
+		RADIO_HCI_COMMAND_HDR_SIZE);
+	hdr->opcode = cpu_to_le16(opcode);
+	hdr->plen   = plen;
+
+	if (plen)
+		memcpy(skb_put(skb, plen), param, plen);
+
+	skb->dev = (void *) hdev;
+
+	ret = hci_send_frame(skb);
+
+	return ret;
+}
+EXPORT_SYMBOL(radio_hci_send_cmd);
+
+static int hci_fm_enable_recv_req(struct radio_hci_dev *hdev,
+	unsigned long param)
+{
+	__u16 opcode = 0;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+		HCI_OCF_FM_ENABLE_RECV_REQ);
+	return radio_hci_send_cmd(hdev, opcode, 0, NULL);
+}
+
+static int hci_fm_disable_recv_req(struct radio_hci_dev *hdev,
+	unsigned long param)
+{
+	__u16 opcode = 0;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+		HCI_OCF_FM_DISABLE_RECV_REQ);
+	return radio_hci_send_cmd(hdev, opcode, 0, NULL);
+}
+
+static int hci_get_fm_recv_conf_req(struct radio_hci_dev *hdev,
+	unsigned long param)
+{
+	__u16 opcode = 0;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+		HCI_OCF_FM_GET_RECV_CONF_REQ);
+	return radio_hci_send_cmd(hdev, opcode, 0, NULL);
+}
+
+static int hci_set_fm_recv_conf_req(struct radio_hci_dev *hdev,
+	unsigned long param)
+{
+	__u16 opcode = 0;
+
+	struct hci_fm_recv_conf_req *recv_conf_req =
+		(struct hci_fm_recv_conf_req *) param;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+		HCI_OCF_FM_SET_RECV_CONF_REQ);
+	return radio_hci_send_cmd(hdev, opcode, sizeof((*recv_conf_req)),
+		recv_conf_req);
+}
+
+static int hci_fm_get_station_param_req(struct radio_hci_dev *hdev,
+		unsigned long param)
+{
+	__u16 opcode = 0;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+		HCI_OCF_FM_GET_STATION_PARAM_REQ);
+	return radio_hci_send_cmd(hdev, opcode, 0, NULL);
+}
+
+static int hci_set_fm_mute_mode_req(struct radio_hci_dev *hdev,
+		unsigned long param)
+{
+	__u16 opcode = 0;
+	struct hci_fm_mute_mode_req *mute_mode_req =
+		(struct hci_fm_mute_mode_req *) param;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+		HCI_OCF_FM_SET_MUTE_MODE_REQ);
+	return radio_hci_send_cmd(hdev, opcode, sizeof((*mute_mode_req)),
+		mute_mode_req);
+}
+
+static int hci_set_fm_stereo_mode_req(struct radio_hci_dev *hdev,
+		unsigned long param)
+{
+	__u16 opcode = 0;
+	struct hci_fm_stereo_mode_req *stereo_mode_req =
+		(struct hci_fm_stereo_mode_req *) param;
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+		HCI_OCF_FM_SET_STEREO_MODE_REQ);
+	return radio_hci_send_cmd(hdev, opcode, sizeof((*stereo_mode_req)),
+		stereo_mode_req);
+}
+
+static int hci_fm_set_antenna_req(struct radio_hci_dev *hdev,
+	unsigned long param)
+{
+	__u16 opcode = 0;
+
+	__u8 antenna = param;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+		HCI_OCF_FM_SET_ANTENNA);
+	return radio_hci_send_cmd(hdev, opcode, sizeof(antenna), &antenna);
+}
+
+static int hci_fm_set_sig_threshold_req(struct radio_hci_dev *hdev,
+		unsigned long param)
+{
+	__u16 opcode = 0;
+
+	__u8 sig_threshold = param;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
+		HCI_OCF_FM_SET_SIGNAL_THRESHOLD);
+	return radio_hci_send_cmd(hdev, opcode, sizeof(sig_threshold),
+		&sig_threshold);
+}
+
+static int hci_fm_get_sig_threshold_req(struct radio_hci_dev *hdev,
+		unsigned long param)
+{
+	__u16 opcode = 0;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
+		HCI_OCF_FM_GET_SIGNAL_THRESHOLD);
+	return radio_hci_send_cmd(hdev, opcode, 0, NULL);
+}
+
+static int hci_fm_get_program_service_req(struct radio_hci_dev *hdev,
+		unsigned long param)
+{
+	__u16 opcode = 0;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
+		HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ);
+	return radio_hci_send_cmd(hdev, opcode, 0, NULL);
+}
+
+static int hci_fm_get_radio_text_req(struct radio_hci_dev *hdev,
+		unsigned long param)
+{
+	__u16 opcode = 0;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
+		HCI_OCF_FM_GET_RADIO_TEXT_REQ);
+	return radio_hci_send_cmd(hdev, opcode, 0, NULL);
+}
+
+static int hci_fm_get_af_list_req(struct radio_hci_dev *hdev,
+	unsigned long param)
+{
+	__u16 opcode = 0;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
+		HCI_OCF_FM_GET_AF_LIST_REQ);
+	return radio_hci_send_cmd(hdev, opcode, 0, NULL);
+}
+
+static int hci_fm_search_stations_req(struct radio_hci_dev *hdev,
+		unsigned long param)
+{
+	__u16 opcode = 0;
+	struct hci_fm_search_station_req *srch_stations =
+		(struct hci_fm_search_station_req *) param;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+		HCI_OCF_FM_SEARCH_STATIONS);
+	return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
+		srch_stations);
+}
+
+static int hci_fm_srch_rds_stations_req(struct radio_hci_dev *hdev,
+		unsigned long param)
+{
+	__u16 opcode = 0;
+	struct hci_fm_search_rds_station_req *srch_stations =
+		(struct hci_fm_search_rds_station_req *) param;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+		HCI_OCF_FM_SEARCH_RDS_STATIONS);
+	return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
+		srch_stations);
+}
+
+static int hci_fm_srch_station_list_req(struct radio_hci_dev *hdev,
+		unsigned long param)
+{
+	__u16 opcode = 0;
+	struct hci_fm_search_station_list_req *srch_list =
+		(struct hci_fm_search_station_list_req *) param;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+		HCI_OCF_FM_SEARCH_STATIONS_LIST);
+	return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_list)),
+		srch_list);
+}
+
+static int hci_fm_cancel_search_req(struct radio_hci_dev *hdev,
+		unsigned long param)
+{
+	__u16 opcode = 0;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+		HCI_OCF_FM_CANCEL_SEARCH);
+	return radio_hci_send_cmd(hdev, opcode, 0, NULL);
+}
+
+static int hci_fm_rds_grp_process_req(struct radio_hci_dev *hdev,
+		unsigned long param)
+{
+	__u16 opcode = 0;
+
+	__u32 fm_grps_process = param;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+		HCI_OCF_FM_RDS_GRP_PROCESS);
+	return radio_hci_send_cmd(hdev, opcode, sizeof(fm_grps_process),
+		&fm_grps_process);
+}
+
+static int hci_fm_tune_station_req(struct radio_hci_dev *hdev,
+	unsigned long param)
+{
+	__u16 opcode = 0;
+
+	__u32 tune_freq = param;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
+		HCI_OCF_FM_TUNE_STATION_REQ);
+	return radio_hci_send_cmd(hdev, opcode, sizeof(tune_freq), &tune_freq);
+}
+
+static int hci_def_data_read_req(struct radio_hci_dev *hdev,
+	unsigned long param)
+{
+	__u16 opcode = 0;
+	struct hci_fm_def_data_rd_req *def_data_rd =
+		(struct hci_fm_def_data_rd_req *) param;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+		HCI_OCF_FM_DEFAULT_DATA_READ);
+	return radio_hci_send_cmd(hdev, opcode, sizeof((*def_data_rd)),
+	def_data_rd);
+}
+
+static int hci_def_data_write_req(struct radio_hci_dev *hdev,
+	unsigned long param)
+{
+	__u16 opcode = 0;
+	struct hci_fm_def_data_wr_req *def_data_wr =
+		(struct hci_fm_def_data_wr_req *) param;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+		HCI_OCF_FM_DEFAULT_DATA_WRITE);
+	return radio_hci_send_cmd(hdev, opcode, sizeof((*def_data_wr)),
+	def_data_wr);
+}
+
+static int hci_fm_reset_req(struct radio_hci_dev *hdev, unsigned long param)
+{
+	__u16 opcode = 0;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
+		HCI_OCF_FM_RESET);
+	return radio_hci_send_cmd(hdev, opcode, 0, NULL);
+}
+
+static int hci_fm_get_feature_lists_req(struct radio_hci_dev *hdev,
+		unsigned long param)
+{
+	__u16 opcode = 0;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
+		HCI_OCF_FM_GET_FEATURE_LIST);
+	return radio_hci_send_cmd(hdev, opcode, 0, NULL);
+}
+
+static int hci_fm_do_calibration_req(struct radio_hci_dev *hdev,
+		unsigned long param)
+{
+	__u16 opcode = 0;
+
+	__u8 mode = param;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
+		HCI_OCF_FM_DO_CALIBRATION);
+	return radio_hci_send_cmd(hdev, opcode, sizeof(mode), &mode);
+}
+
+static int hci_read_grp_counters_req(struct radio_hci_dev *hdev,
+		unsigned long param)
+{
+	__u16 opcode = 0;
+
+	__u8 reset_counters = param;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
+		HCI_OCF_FM_READ_GRP_COUNTERS);
+	return radio_hci_send_cmd(hdev, opcode, sizeof(reset_counters),
+		&reset_counters);
+}
+
+static int hci_peek_data_req(struct radio_hci_dev *hdev, unsigned long param)
+{
+	__u16 opcode = 0;
+	struct hci_fm_peek_req *peek_data = (struct hci_fm_peek_req *) param;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+		HCI_OCF_FM_PEEK_DATA);
+	return radio_hci_send_cmd(hdev, opcode, sizeof((*peek_data)),
+	peek_data);
+}
+
+static int hci_poke_data_req(struct radio_hci_dev *hdev, unsigned long param)
+{
+	__u16 opcode = 0;
+	struct hci_fm_poke_req *poke_data = (struct hci_fm_poke_req *) param;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+		HCI_OCF_FM_POKE_DATA);
+	return radio_hci_send_cmd(hdev, opcode, sizeof((*poke_data)),
+	poke_data);
+}
+
+static int hci_ssbi_peek_reg_req(struct radio_hci_dev *hdev,
+	unsigned long param)
+{
+	__u16 opcode = 0;
+	struct hci_fm_ssbi_req *ssbi_peek = (struct hci_fm_ssbi_req *) param;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+		HCI_OCF_FM_SSBI_PEEK_REG);
+	return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_peek)),
+	ssbi_peek);
+}
+
+static int hci_ssbi_poke_reg_req(struct radio_hci_dev *hdev,
+	unsigned long param)
+{
+	__u16 opcode = 0;
+	struct hci_fm_ssbi_req *ssbi_poke = (struct hci_fm_ssbi_req *) param;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+		HCI_OCF_FM_SSBI_POKE_REG);
+	return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_poke)),
+	ssbi_poke);
+}
+
+static int hci_fm_get_station_dbg_param_req(struct radio_hci_dev *hdev,
+		unsigned long param)
+{
+	__u16 opcode = 0;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
+		HCI_OCF_FM_STATION_DBG_PARAM);
+	return radio_hci_send_cmd(hdev, opcode, 0, NULL);
+}
+
+static int radio_hci_err(__u16 code)
+{
+	switch (code) {
+	case 0:
+		return 0;
+	case 0x01:
+		return -EBADRQC;
+	case 0x02:
+		return -ENOTCONN;
+	case 0x03:
+		return -EIO;
+	case 0x07:
+		return -ENOMEM;
+	case 0x0c:
+		return -EBUSY;
+	case 0x11:
+		return -EOPNOTSUPP;
+	case 0x12:
+		return -EINVAL;
+	default:
+		return -ENOSYS;
+	}
+}
+
+static int __radio_hci_request(struct radio_hci_dev *hdev,
+		int (*req)(struct radio_hci_dev *hdev,
+			unsigned long param),
+			unsigned long param, __u32 timeout)
+{
+	int err = 0;
+
+	DECLARE_WAITQUEUE(wait, current);
+
+	hdev->req_status = HCI_REQ_PEND;
+
+	add_wait_queue(&hdev->req_wait_q, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+
+	err = req(hdev, param);
+
+	schedule_timeout(timeout);
+
+	remove_wait_queue(&hdev->req_wait_q, &wait);
+
+	if (signal_pending(current))
+		return -EINTR;
+
+	switch (hdev->req_status) {
+	case HCI_REQ_DONE:
+	case HCI_REQ_STATUS:
+		err = radio_hci_err(hdev->req_result);
+		break;
+
+	case HCI_REQ_CANCELED:
+		err = -hdev->req_result;
+		break;
+
+	default:
+		err = -ETIMEDOUT;
+		break;
+	}
+
+	hdev->req_status = hdev->req_result = 0;
+
+	return err;
+}
+
+static inline int radio_hci_request(struct radio_hci_dev *hdev,
+		int (*req)(struct
+		radio_hci_dev * hdev, unsigned long param),
+		unsigned long param, __u32 timeout)
+{
+	int ret = 0;
+
+	ret = __radio_hci_request(hdev, req, param, timeout);
+
+	return ret;
+}
+
+static int hci_set_fm_recv_conf(struct hci_fm_recv_conf_req *arg,
+		struct radio_hci_dev *hdev)
+{
+	int ret = 0;
+	struct hci_fm_recv_conf_req *set_recv_conf = arg;
+
+	ret = radio_hci_request(hdev, hci_set_fm_recv_conf_req, (unsigned
+		long)set_recv_conf, RADIO_HCI_TIMEOUT);
+
+	return ret;
+}
+
+static int hci_fm_tune_station(__u32 *arg, struct radio_hci_dev *hdev)
+{
+	int ret = 0;
+	__u32 tune_freq = *arg;
+
+	ret = radio_hci_request(hdev, hci_fm_tune_station_req, tune_freq,
+		RADIO_HCI_TIMEOUT);
+
+	return ret;
+}
+
+static int hci_set_fm_mute_mode(struct hci_fm_mute_mode_req *arg,
+	struct radio_hci_dev *hdev)
+{
+	int ret = 0;
+	struct hci_fm_mute_mode_req *set_mute_conf = arg;
+
+	ret = radio_hci_request(hdev, hci_set_fm_mute_mode_req, (unsigned
+		long)set_mute_conf, RADIO_HCI_TIMEOUT);
+
+	return ret;
+}
+
+static int hci_set_fm_stereo_mode(struct hci_fm_stereo_mode_req *arg,
+	struct radio_hci_dev *hdev)
+{
+	int ret = 0;
+	struct hci_fm_stereo_mode_req *set_stereo_conf = arg;
+
+	ret = radio_hci_request(hdev, hci_set_fm_stereo_mode_req, (unsigned
+		long)set_stereo_conf, RADIO_HCI_TIMEOUT);
+
+	return ret;
+}
+
+static int hci_fm_set_antenna(__u8 *arg, struct radio_hci_dev *hdev)
+{
+	int ret = 0;
+	__u8 antenna = *arg;
+
+	ret = radio_hci_request(hdev, hci_fm_set_antenna_req, antenna,
+		RADIO_HCI_TIMEOUT);
+
+	return ret;
+}
+
+static int hci_fm_set_signal_threshold(__u8 *arg,
+	struct radio_hci_dev *hdev)
+{
+	int ret = 0;
+	__u8 sig_threshold = *arg;
+
+	ret = radio_hci_request(hdev, hci_fm_set_sig_threshold_req,
+		sig_threshold, RADIO_HCI_TIMEOUT);
+
+	return ret;
+}
+
+static int hci_fm_search_stations(struct hci_fm_search_station_req *arg,
+	struct radio_hci_dev *hdev)
+{
+	int ret = 0;
+	struct hci_fm_search_station_req *srch_stations = arg;
+
+	ret = radio_hci_request(hdev, hci_fm_search_stations_req, (unsigned
+		long)srch_stations, RADIO_HCI_TIMEOUT);
+
+	return ret;
+}
+
+static int hci_fm_search_rds_stations(struct hci_fm_search_rds_station_req *arg,
+	struct radio_hci_dev *hdev)
+{
+	int ret = 0;
+	struct hci_fm_search_rds_station_req *srch_stations = arg;
+
+	ret = radio_hci_request(hdev, hci_fm_srch_rds_stations_req, (unsigned
+		long)srch_stations, RADIO_HCI_TIMEOUT);
+
+	return ret;
+}
+
+static int hci_fm_search_station_list
+	(struct hci_fm_search_station_list_req *arg,
+	struct radio_hci_dev *hdev)
+{
+	int ret = 0;
+	struct hci_fm_search_station_list_req *srch_list = arg;
+
+	ret = radio_hci_request(hdev, hci_fm_srch_station_list_req, (unsigned
+		long)srch_list, RADIO_HCI_TIMEOUT);
+
+	return ret;
+}
+
+static int hci_fm_rds_grp(struct hci_fm_rds_grp_req *arg,
+	struct radio_hci_dev *hdev)
+{
+	return 0;
+}
+
+static int hci_fm_rds_grps_process(__u32 *arg, struct radio_hci_dev *hdev)
+{
+	int ret = 0;
+	__u32 fm_grps_process = *arg;
+
+	ret = radio_hci_request(hdev, hci_fm_rds_grp_process_req,
+		fm_grps_process, RADIO_HCI_TIMEOUT);
+
+	return ret;
+}
+
+int hci_def_data_read(struct hci_fm_def_data_rd_req *arg,
+	struct radio_hci_dev *hdev)
+{
+	int ret = 0;
+	struct hci_fm_def_data_rd_req *def_data_rd = arg;
+
+	ret = radio_hci_request(hdev, hci_def_data_read_req, (unsigned
+		long)def_data_rd, RADIO_HCI_TIMEOUT);
+
+	return ret;
+}
+
+int hci_def_data_write(struct hci_fm_def_data_wr_req *arg,
+	struct radio_hci_dev *hdev)
+{
+	int ret = 0;
+	struct hci_fm_def_data_wr_req *def_data_wr = arg;
+
+	ret = radio_hci_request(hdev, hci_def_data_write_req, (unsigned
+		long)def_data_wr, RADIO_HCI_TIMEOUT);
+
+	return ret;
+}
+
+int hci_fm_do_calibration(__u8 *arg, struct radio_hci_dev *hdev)
+{
+	int ret = 0;
+	__u8 mode = *arg;
+
+	ret = radio_hci_request(hdev, hci_fm_do_calibration_req, mode,
+		RADIO_HCI_TIMEOUT);
+
+	return ret;
+}
+
+int hci_read_grp_counters(__u8 *arg, struct radio_hci_dev *hdev)
+{
+	int ret = 0;
+	__u8 reset_counters = *arg;
+
+	ret = radio_hci_request(hdev, hci_read_grp_counters_req,
+		reset_counters, RADIO_HCI_TIMEOUT);
+
+	return ret;
+}
+
+int hci_peek_data(struct hci_fm_peek_req *arg, struct radio_hci_dev *hdev)
+{
+	int ret = 0;
+	struct hci_fm_peek_req *peek_data = arg;
+
+	ret = radio_hci_request(hdev, hci_peek_data_req, (unsigned
+		long)peek_data, RADIO_HCI_TIMEOUT);
+
+	return ret;
+}
+
+int hci_poke_data(struct hci_fm_poke_req *arg, struct radio_hci_dev *hdev)
+{
+	int ret = 0;
+	struct hci_fm_poke_req *poke_data = arg;
+
+	ret = radio_hci_request(hdev, hci_poke_data_req, (unsigned
+		long)poke_data, RADIO_HCI_TIMEOUT);
+
+	return ret;
+}
+
+int hci_ssbi_peek_reg(struct hci_fm_ssbi_req *arg,
+	struct radio_hci_dev *hdev)
+{
+	int ret = 0;
+	struct hci_fm_ssbi_req *ssbi_peek_reg = arg;
+
+	ret = radio_hci_request(hdev, hci_ssbi_peek_reg_req, (unsigned
+		long)ssbi_peek_reg, RADIO_HCI_TIMEOUT);
+
+	return ret;
+}
+
+int hci_ssbi_poke_reg(struct hci_fm_ssbi_req *arg, struct radio_hci_dev *hdev)
+{
+	int ret = 0;
+	struct hci_fm_ssbi_req *ssbi_poke_reg = arg;
+
+	ret = radio_hci_request(hdev, hci_ssbi_poke_reg_req, (unsigned
+		long)ssbi_poke_reg, RADIO_HCI_TIMEOUT);
+
+	return ret;
+}
+
+static int hci_cmd(unsigned int cmd, struct radio_hci_dev *hdev)
+{
+	int ret = 0;
+	unsigned long arg = 0;
+
+	switch (cmd) {
+	case HCI_FM_ENABLE_RECV_CMD:
+		ret = radio_hci_request(hdev, hci_fm_enable_recv_req, arg,
+			msecs_to_jiffies(RADIO_HCI_TIMEOUT));
+		break;
+
+	case HCI_FM_DISABLE_RECV_CMD:
+		ret = radio_hci_request(hdev, hci_fm_disable_recv_req, arg,
+			msecs_to_jiffies(RADIO_HCI_TIMEOUT));
+		break;
+
+	case HCI_FM_GET_RECV_CONF_CMD:
+		ret = radio_hci_request(hdev, hci_get_fm_recv_conf_req, arg,
+			msecs_to_jiffies(RADIO_HCI_TIMEOUT));
+		break;
+
+	case HCI_FM_GET_STATION_PARAM_CMD:
+		ret = radio_hci_request(hdev,
+			hci_fm_get_station_param_req, arg,
+			msecs_to_jiffies(RADIO_HCI_TIMEOUT));
+		break;
+
+	case HCI_FM_GET_SIGNAL_TH_CMD:
+		ret = radio_hci_request(hdev,
+			hci_fm_get_sig_threshold_req, arg,
+			msecs_to_jiffies(RADIO_HCI_TIMEOUT));
+		break;
+
+	case HCI_FM_GET_PROGRAM_SERVICE_CMD:
+		ret = radio_hci_request(hdev,
+			hci_fm_get_program_service_req, arg,
+			msecs_to_jiffies(RADIO_HCI_TIMEOUT));
+		break;
+
+	case HCI_FM_GET_RADIO_TEXT_CMD:
+		ret = radio_hci_request(hdev, hci_fm_get_radio_text_req, arg,
+			msecs_to_jiffies(RADIO_HCI_TIMEOUT));
+		break;
+
+	case HCI_FM_GET_AF_LIST_CMD:
+		ret = radio_hci_request(hdev, hci_fm_get_af_list_req, arg,
+			msecs_to_jiffies(RADIO_HCI_TIMEOUT));
+		break;
+
+	case HCI_FM_CANCEL_SEARCH_CMD:
+		ret = radio_hci_request(hdev, hci_fm_cancel_search_req, arg,
+			msecs_to_jiffies(RADIO_HCI_TIMEOUT));
+		break;
+
+	case HCI_FM_RESET_CMD:
+		ret = radio_hci_request(hdev, hci_fm_reset_req, arg,
+			msecs_to_jiffies(RADIO_HCI_TIMEOUT));
+		break;
+
+	case HCI_FM_GET_FEATURES_CMD:
+		ret = radio_hci_request(hdev,
+		hci_fm_get_feature_lists_req, arg,
+			msecs_to_jiffies(RADIO_HCI_TIMEOUT));
+		break;
+
+	case HCI_FM_STATION_DBG_PARAM_CMD:
+		ret = radio_hci_request(hdev,
+		hci_fm_get_station_dbg_param_req, arg,
+			msecs_to_jiffies(RADIO_HCI_TIMEOUT));
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static void radio_hci_req_complete(struct radio_hci_dev *hdev, int result)
+{
+	hdev->req_result = result;
+	hdev->req_status = HCI_REQ_DONE;
+	wake_up_interruptible(&hdev->req_wait_q);
+}
+
+static void radio_hci_status_complete(struct radio_hci_dev *hdev, int result)
+{
+	hdev->req_result = result;
+	hdev->req_status = HCI_REQ_STATUS;
+	wake_up_interruptible(&hdev->req_wait_q);
+}
+
+static void hci_cc_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
+{
+	__u8 status = *((__u8 *) skb->data);
+
+	if (status)
+		return;
+
+	radio_hci_req_complete(hdev, status);
+}
+
+static void hci_cc_fm_disable_rsp(struct radio_hci_dev *hdev,
+	struct sk_buff *skb)
+{
+	__u8 status = *((__u8 *) skb->data);
+	struct iris_device *radio = video_get_drvdata(video_get_dev());
+
+	if (status)
+		return;
+
+	iris_q_event(radio, IRIS_EVT_RADIO_READY);
+
+	radio_hci_req_complete(hdev, status);
+}
+
+static void hci_cc_conf_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_fm_conf_rsp  *rsp = (void *)skb->data;
+	struct iris_device *radio = video_get_drvdata(video_get_dev());
+
+	if (rsp->status)
+		return;
+
+	radio->recv_conf = rsp->recv_conf_rsp;
+	radio_hci_req_complete(hdev, rsp->status);
+}
+
+static void hci_cc_fm_enable_rsp(struct radio_hci_dev *hdev,
+	struct sk_buff *skb)
+{
+	struct hci_fm_conf_rsp  *rsp = (void *)skb->data;
+	struct iris_device *radio = video_get_drvdata(video_get_dev());
+
+	if (rsp->status)
+		return;
+
+	iris_q_event(radio, IRIS_EVT_RADIO_READY);
+
+	radio_hci_req_complete(hdev, rsp->status);
+}
+
+static void hci_cc_sig_threshold_rsp(struct radio_hci_dev *hdev,
+		struct sk_buff *skb)
+{
+	struct hci_fm_sig_threshold_rsp  *rsp = (void *)skb->data;
+	struct iris_device *radio = video_get_drvdata(video_get_dev());
+	struct v4l2_control *v4l_ctl = radio->g_ctl;
+
+	if (rsp->status)
+		return;
+
+	v4l_ctl->value = rsp->sig_threshold;
+
+	radio_hci_req_complete(hdev, rsp->status);
+}
+
+static void hci_cc_station_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
+{
+	struct iris_device *radio = video_get_drvdata(video_get_dev());
+	struct hci_fm_station_rsp *rsp = (void *)skb->data;
+	radio->fm_st_rsp = *(rsp);
+
+	/* Tune is always succesful */
+	radio_hci_req_complete(hdev, 0);
+}
+
+static void hci_cc_prg_srv_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_fm_prgm_srv_rsp  *rsp = (void *)skb->data;
+
+	if (rsp->status)
+		return;
+
+	radio_hci_req_complete(hdev, rsp->status);
+}
+
+static void hci_cc_rd_txt_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_fm_radio_txt_rsp  *rsp = (void *)skb->data;
+
+	if (rsp->status)
+		return;
+
+	radio_hci_req_complete(hdev, rsp->status);
+}
+
+static void hci_cc_af_list_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_fm_af_list_rsp  *rsp = (void *)skb->data;
+
+	if (rsp->status)
+		return;
+
+	radio_hci_req_complete(hdev, rsp->status);
+}
+
+static void hci_cc_data_rd_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_fm_data_rd_rsp  *rsp = (void *)skb->data;
+
+	if (rsp->status)
+		return;
+
+	radio_hci_req_complete(hdev, rsp->status);
+}
+
+static void hci_cc_feature_list_rsp(struct radio_hci_dev *hdev,
+	struct sk_buff *skb)
+{
+	struct hci_fm_feature_list_rsp  *rsp = (void *)skb->data;
+	struct iris_device *radio = video_get_drvdata(video_get_dev());
+	struct v4l2_capability *v4l_cap = radio->g_cap;
+
+	if (rsp->status)
+		return;
+	v4l_cap->capabilities = (rsp->feature_mask & 0x000002) |
+		(rsp->feature_mask & 0x000001);
+
+	radio_hci_req_complete(hdev, rsp->status);
+}
+
+static void hci_cc_dbg_param_rsp(struct radio_hci_dev *hdev,
+	struct sk_buff *skb)
+{
+	struct iris_device *radio = video_get_drvdata(video_get_dev());
+	struct hci_fm_dbg_param_rsp *rsp = (void *)skb->data;
+	radio->st_dbg_param = *(rsp);
+
+	if (radio->st_dbg_param.status)
+		return;
+
+	radio_hci_req_complete(hdev, radio->st_dbg_param.status);
+}
+
+static inline void hci_cmd_complete_event(struct radio_hci_dev *hdev,
+		struct sk_buff *skb)
+{
+	struct hci_ev_cmd_complete *cmd_compl_ev = (void *) skb->data;
+	__u16 opcode;
+
+	skb_pull(skb, sizeof(*cmd_compl_ev));
+
+	opcode = __le16_to_cpu(cmd_compl_ev->cmd_opcode);
+
+	switch (opcode) {
+	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_RECV_REQ):
+		hci_cc_fm_enable_rsp(hdev, skb);
+		break;
+	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RECV_CONF_REQ):
+		hci_cc_conf_rsp(hdev, skb);
+		break;
+
+	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_RECV_REQ):
+		hci_cc_fm_disable_rsp(hdev, skb);
+		break;
+
+	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_RECV_CONF_REQ):
+	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_MUTE_MODE_REQ):
+	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_STEREO_MODE_REQ):
+	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_ANTENNA):
+	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_SIGNAL_THRESHOLD):
+	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_CANCEL_SEARCH):
+	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP):
+	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP_PROCESS):
+	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_WAN_AVD_CTRL):
+	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_NOTCH_CTRL):
+	case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_WRITE):
+	case hci_common_cmd_op_pack(HCI_OCF_FM_RESET):
+	case hci_status_param_op_pack(HCI_OCF_FM_READ_GRP_COUNTERS):
+	case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_POKE_DATA):
+	case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_PEEK_REG):
+	case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_POKE_REG):
+		hci_cc_rsp(hdev, skb);
+		break;
+
+	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_SIGNAL_THRESHOLD):
+		hci_cc_sig_threshold_rsp(hdev, skb);
+		break;
+
+	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_STATION_PARAM_REQ):
+		hci_cc_station_rsp(hdev, skb);
+		break;
+
+	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ):
+		hci_cc_prg_srv_rsp(hdev, skb);
+		break;
+
+	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RADIO_TEXT_REQ):
+		hci_cc_rd_txt_rsp(hdev, skb);
+		break;
+
+	case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_AF_LIST_REQ):
+		hci_cc_af_list_rsp(hdev, skb);
+		break;
+
+	case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_READ):
+	case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_PEEK_DATA):
+		hci_cc_data_rd_rsp(hdev, skb);
+		break;
+
+	case hci_common_cmd_op_pack(HCI_OCF_FM_GET_FEATURE_LIST):
+		hci_cc_feature_list_rsp(hdev, skb);
+		break;
+
+	case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_STATION_DBG_PARAM):
+		hci_cc_dbg_param_rsp(hdev, skb);
+		break;
+
+	default:
+		FMDERR("%s opcode 0x%x", hdev->name, opcode);
+		break;
+	}
+
+}
+
+static inline void hci_cmd_status_event(struct radio_hci_dev *hdev,
+		struct sk_buff *skb)
+{
+	struct hci_ev_cmd_status *ev = (void *) skb->data;
+	radio_hci_status_complete(hdev, ev->status);
+}
+
+static inline void hci_ev_tune_status(struct radio_hci_dev *hdev,
+		struct sk_buff *skb)
+{
+	int i;
+	int len;
+
+	struct iris_device *radio = video_get_drvdata(video_get_dev());
+
+	len = sizeof(struct hci_fm_station_rsp);
+
+	memcpy(&radio->fm_st_rsp.station_rsp, skb_pull(skb, len), len);
+
+	iris_q_event(radio, IRIS_EVT_TUNE_SUCC);
+
+	for (i = 0; i < IRIS_BUF_MAX; i++) {
+		if (i >= IRIS_BUF_RT_RDS)
+			kfifo_reset(&radio->data_buf[i]);
+	}
+
+	if (radio->fm_st_rsp.station_rsp.rssi)
+		iris_q_event(radio, IRIS_EVT_ABOVE_TH);
+	else
+		iris_q_event(radio, IRIS_EVT_BELOW_TH);
+
+	if (radio->fm_st_rsp.station_rsp.stereo_prg)
+		iris_q_event(radio, IRIS_EVT_STEREO);
+
+	if (radio->fm_st_rsp.station_rsp.mute_mode)
+		iris_q_event(radio, IRIS_EVT_MONO);
+
+	if (radio->fm_st_rsp.station_rsp.rds_sync_status)
+		iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
+	else
+		iris_q_event(radio, IRIS_EVT_RDS_NOT_AVAIL);
+}
+
+static inline void hci_ev_search_compl(struct radio_hci_dev *hdev,
+		struct sk_buff *skb)
+{
+	struct iris_device *radio = video_get_drvdata(video_get_dev());
+	iris_q_event(radio, IRIS_EVT_SEEK_COMPLETE);
+}
+
+static inline void hci_ev_srch_st_list_compl(struct radio_hci_dev *hdev,
+		struct sk_buff *skb)
+{
+	struct iris_device *radio = video_get_drvdata(video_get_dev());
+	struct hci_ev_srch_list_compl *ev = (void *) skb->data;
+	radio->srch_st_result = *ev;
+}
+
+static inline void hci_ev_search_next(struct radio_hci_dev *hdev,
+		struct sk_buff *skb)
+{
+	struct iris_device *radio = video_get_drvdata(video_get_dev());
+	iris_q_event(radio, IRIS_EVT_SCAN_NEXT);
+}
+
+static inline void hci_ev_stereo_status(struct radio_hci_dev *hdev,
+		struct sk_buff *skb)
+{
+	struct iris_device *radio = video_get_drvdata(video_get_dev());
+	__u8 st_status = *((__u8 *) skb->data);
+	if (st_status)
+		iris_q_event(radio, IRIS_EVT_STEREO);
+	else
+		iris_q_event(radio, IRIS_EVT_MONO);
+}
+
+void radio_hci_event_packet(struct radio_hci_dev *hdev, struct sk_buff *skb)
+{
+	struct radio_hci_event_hdr *hdr = (void *) skb->data;
+	__u8 event = hdr->evt;
+
+	skb_pull(skb, RADIO_HCI_EVENT_HDR_SIZE);
+
+	switch (event) {
+	case HCI_EV_TUNE_STATUS:
+		hci_ev_tune_status(hdev, skb);
+		break;
+	case HCI_EV_SEARCH_PROGRESS:
+	case HCI_EV_SEARCH_RDS_PROGRESS:
+	case HCI_EV_SEARCH_LIST_PROGRESS:
+		hci_ev_search_next(hdev, skb);
+		break;
+	case HCI_EV_STEREO_STATUS:
+		hci_ev_stereo_status(hdev, skb);
+		break;
+	case HCI_EV_RDS_LOCK_STATUS:
+	case HCI_EV_SERVICE_AVAILABLE:
+	case HCI_EV_RDS_RX_DATA:
+	case HCI_EV_PROGRAM_SERVICE:
+	case HCI_EV_RADIO_TEXT:
+	case HCI_EV_FM_AF_LIST:
+	case HCI_EV_TX_RDS_GRP_COMPL:
+	case HCI_EV_TX_RDS_CONT_GRP_COMPL:
+		break;
+
+	case HCI_EV_CMD_COMPLETE:
+		hci_cmd_complete_event(hdev, skb);
+		break;
+
+	case HCI_EV_CMD_STATUS:
+		hci_cmd_status_event(hdev, skb);
+		break;
+
+	case HCI_EV_SEARCH_COMPLETE:
+	case HCI_EV_SEARCH_RDS_COMPLETE:
+		hci_ev_search_compl(hdev, skb);
+		break;
+
+	case HCI_EV_SEARCH_LIST_COMPLETE:
+		break;
+
+	default:
+		break;
+	}
+}
+
+/*
+ * fops/IOCTL helper functions
+ */
+
+static int iris_search(struct iris_device *radio, int on, int dir)
+{
+	int retval = 0;
+	enum search_t srch = radio->g_search_mode & SRCH_MODE;
+
+	if (on) {
+		switch (srch) {
+		case SCAN_FOR_STRONG:
+		case SCAN_FOR_WEAK:
+			radio->srch_st_list.srch_list_dir = dir;
+			radio->srch_st_list.srch_list_mode = srch;
+			radio->srch_st_list.srch_list_max = 0;
+			retval = hci_fm_search_station_list(
+				&radio->srch_st_list, radio->fm_hdev);
+			break;
+		case RDS_SEEK_PTY:
+		case RDS_SCAN_PTY:
+		case RDS_SEEK_PI:
+			radio->srch_rds.srch_station.srch_mode = srch;
+			radio->srch_rds.srch_station.srch_dir = dir;
+			radio->srch_rds.srch_station.scan_time =
+				radio->g_scan_time;
+			retval = hci_fm_search_rds_stations(&radio->srch_rds,
+				radio->fm_hdev);
+			break;
+		default:
+			radio->srch_st.srch_mode = srch;
+			radio->srch_st.scan_time = radio->g_scan_time;
+			radio->srch_st.srch_dir = dir;
+			retval = hci_fm_search_stations(
+				&radio->srch_st, radio->fm_hdev);
+			break;
+		}
+
+	} else {
+		retval = hci_cmd(HCI_FM_CANCEL_SEARCH_CMD, radio->fm_hdev);
+	}
+
+	return retval;
+}
+
+static int iris_set_region(struct iris_device *radio, int req_region)
+{
+	int retval;
+	radio->region = req_region;
+
+	switch (radio->region) {
+	case IRIS_REGION_US:
+		{
+			radio->recv_conf.band_low_limit = 88100;
+			radio->recv_conf.band_high_limit = 108000;
+			radio->recv_conf.emphasis = 0;
+			radio->recv_conf.hlsi = 0;
+			radio->recv_conf.ch_spacing = 0;
+			radio->recv_conf.rds_std = 0;
+		}
+		break;
+	case IRIS_REGION_EU:
+		{
+			radio->recv_conf.band_low_limit = 88100;
+			radio->recv_conf.band_high_limit = 108000;
+			radio->recv_conf.emphasis = 0;
+			radio->recv_conf.hlsi = 0;
+			radio->recv_conf.ch_spacing = 0;
+			radio->recv_conf.rds_std = 0;
+		}
+		break;
+	case IRIS_REGION_JAPAN:
+		{
+			radio->recv_conf.band_low_limit = 76000;
+			radio->recv_conf.band_high_limit = 108000;
+			radio->recv_conf.emphasis = 0;
+			radio->recv_conf.hlsi = 0;
+			radio->recv_conf.ch_spacing = 0;
+		}
+		break;
+	default:
+		{
+			radio->recv_conf.emphasis = 0;
+			radio->recv_conf.hlsi = 0;
+			radio->recv_conf.ch_spacing = 0;
+			radio->recv_conf.rds_std = 0;
+		}
+		break;
+	}
+
+
+	retval = hci_set_fm_recv_conf(
+			&radio->recv_conf,
+			radio->fm_hdev);
+
+	return retval;
+}
+
+static int iris_set_freq(struct iris_device *radio, unsigned int freq)
+{
+
+	int retval;
+	retval = hci_fm_tune_station(&freq, radio->fm_hdev);
+	if (retval < 0)
+		FMDERR("Error while setting the frequency : %d\n", retval);
+	return retval;
+}
+
+
+static int iris_vidioc_queryctrl(struct file *file, void *priv,
+		struct v4l2_queryctrl *qc)
+{
+	unsigned char i;
+	int retval = -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(iris_v4l2_queryctrl); i++) {
+		if (qc->id && qc->id == iris_v4l2_queryctrl[i].id) {
+			memcpy(qc, &(iris_v4l2_queryctrl[i]), sizeof(*qc));
+			retval = 0;
+			break;
+		}
+	}
+
+	return retval;
+}
+
+static int iris_vidioc_g_ctrl(struct file *file, void *priv,
+		struct v4l2_control *ctrl)
+{
+	struct iris_device *radio = video_get_drvdata(video_devdata(file));
+	int retval = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_VOLUME:
+		break;
+	case V4L2_CID_AUDIO_MUTE:
+		ctrl->value = radio->mute_mode.hard_mute;
+		break;
+	case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
+		ctrl->value = radio->g_search_mode;
+		break;
+	case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
+		ctrl->value = radio->g_scan_time;
+		break;
+	case V4L2_CID_PRIVATE_IRIS_SRCHON:
+		break;
+	case V4L2_CID_PRIVATE_IRIS_STATE:
+		break;
+	case V4L2_CID_PRIVATE_IRIS_IOVERC:
+		retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
+		if (retval < 0)
+			return retval;
+		ctrl->value = radio->st_dbg_param.io_verc;
+		break;
+	case V4L2_CID_PRIVATE_IRIS_INTDET:
+		retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
+		if (retval < 0)
+			return retval;
+		ctrl->value = radio->st_dbg_param.in_det_out;
+		break;
+	case V4L2_CID_PRIVATE_IRIS_REGION:
+		ctrl->value = radio->region;
+		break;
+	case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
+		retval = hci_cmd(HCI_FM_GET_SIGNAL_TH_CMD, radio->fm_hdev);
+		break;
+	case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
+		break;
+	case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
+		break;
+	case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
+		break;
+	case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
+		retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
+							 radio->fm_hdev);
+		if (retval < 0)
+			FMDERR("Error get FM recv conf"
+				" %d\n", retval);
+		else
+			ctrl->value = radio->recv_conf.emphasis;
+		break;
+	case V4L2_CID_PRIVATE_IRIS_RDS_STD:
+		retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
+				 radio->fm_hdev);
+		if (retval < 0)
+			FMDERR("Error get FM recv conf"
+				" %d\n", retval);
+		else
+			ctrl->value = radio->recv_conf.rds_std;
+		break;
+	case V4L2_CID_PRIVATE_IRIS_SPACING:
+		retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
+				radio->fm_hdev);
+		if (retval < 0)
+			FMDERR("Error get FM recv conf"
+				" %d\n", retval);
+		else
+			ctrl->value = radio->recv_conf.ch_spacing;
+		break;
+	case V4L2_CID_PRIVATE_IRIS_RDSON:
+		retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
+				radio->fm_hdev);
+		if (retval < 0)
+			FMDERR("Error get FM recv conf"
+				" %d\n", retval);
+		else
+			ctrl->value = radio->recv_conf.rds_std;
+		break;
+	case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
+		ctrl->value = radio->rds_grp.rds_grp_enable_mask;
+		break;
+	case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
+		break;
+	case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
+		ctrl->value = radio->rds_grp.rds_buf_size;
+		break;
+	case V4L2_CID_PRIVATE_IRIS_PSALL:
+		ctrl->value = radio->g_rds_grp_proc_ps;
+		break;
+	case V4L2_CID_PRIVATE_IRIS_LP_MODE:
+		break;
+	case V4L2_CID_PRIVATE_IRIS_ANTENNA:
+		ctrl->value = radio->g_antenna;
+		break;
+	default:
+		retval = -EINVAL;
+	}
+	if (retval < 0)
+		FMDERR("get control failed with %d, id: %d\n",
+			retval, ctrl->id);
+	return retval;
+}
+
+static int iris_vidioc_s_ext_ctrls(struct file *file, void *priv,
+			struct v4l2_ext_controls *ctrl)
+{
+	return -ENOTSUPP;
+}
+
+static int iris_vidioc_s_ctrl(struct file *file, void *priv,
+		struct v4l2_control *ctrl)
+{
+	struct iris_device *radio = video_get_drvdata(video_devdata(file));
+	int retval = 0;
+	unsigned int rds_grps_proc = 0;
+	__u8 temp_val = 0;
+	radio->recv_conf.emphasis = 0;
+	radio->recv_conf.ch_spacing = 0;
+	radio->recv_conf.hlsi = 0;
+	radio->recv_conf.band_low_limit = 87500;
+	radio->recv_conf.band_high_limit = 108000;
+	radio->recv_conf.rds_std = 0;
+
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_VOLUME:
+		break;
+	case V4L2_CID_AUDIO_MUTE:
+		radio->mute_mode.hard_mute = ctrl->value;
+		radio->mute_mode.soft_mute = IOC_SFT_MUTE;
+		retval = hci_set_fm_mute_mode(
+				&radio->mute_mode,
+				radio->fm_hdev);
+		if (retval < 0)
+			FMDERR("Error while set FM hard mute"" %d\n",
+			retval);
+		break;
+	case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
+		radio->g_search_mode = ctrl->value;
+		break;
+	case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
+		radio->g_scan_time = ctrl->value;
+		break;
+	case V4L2_CID_PRIVATE_IRIS_SRCHON:
+		iris_search(radio, ctrl->value, SRCH_DIR_UP);
+		break;
+	case V4L2_CID_PRIVATE_IRIS_STATE:
+		if (ctrl->value == FM_RECV) {
+			retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
+							 radio->fm_hdev);
+		} else {
+			if (ctrl->value == FM_OFF) {
+				retval = hci_cmd(
+							HCI_FM_DISABLE_RECV_CMD,
+							radio->fm_hdev);
+				if (retval < 0)
+					FMDERR("Error on disable FM"
+							" %d\n", retval);
+			}
+		}
+		break;
+	case V4L2_CID_PRIVATE_IRIS_REGION:
+		retval = iris_set_region(radio, ctrl->value);
+		break;
+	case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
+		temp_val = ctrl->value;
+		retval = hci_fm_set_signal_threshold(
+				&temp_val,
+				radio->fm_hdev);
+		if (retval < 0) {
+			FMDERR("Error while setting signal threshold\n");
+			break;
+		}
+		break;
+	case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
+		radio->srch_rds.srch_pty = ctrl->value;
+		radio->srch_st_list.srch_pty = ctrl->value;
+		break;
+	case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
+		radio->srch_rds.srch_pi = ctrl->value;
+		break;
+	case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
+		break;
+	case V4L2_CID_PRIVATE_IRIS_SPACING:
+		radio->recv_conf.ch_spacing = ctrl->value;
+		break;
+	case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
+		radio->recv_conf.emphasis = ctrl->value;
+		retval =
+		hci_set_fm_recv_conf(&radio->recv_conf, radio->fm_hdev);
+		break;
+	case V4L2_CID_PRIVATE_IRIS_RDS_STD:
+		radio->recv_conf.rds_std = ctrl->value;
+		retval =
+		hci_set_fm_recv_conf(&radio->recv_conf, radio->fm_hdev);
+		break;
+	case V4L2_CID_PRIVATE_IRIS_RDSON:
+		radio->recv_conf.rds_std = ctrl->value;
+		retval =
+		hci_set_fm_recv_conf(&radio->recv_conf, radio->fm_hdev);
+		break;
+	case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
+		radio->rds_grp.rds_grp_enable_mask = ctrl->value;
+		retval = hci_fm_rds_grp(&radio->rds_grp, radio->fm_hdev);
+		break;
+	case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
+		rds_grps_proc = radio->g_rds_grp_proc_ps | ctrl->value;
+		retval = hci_fm_rds_grps_process(
+				&rds_grps_proc,
+				radio->fm_hdev);
+		break;
+	case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
+		radio->rds_grp.rds_buf_size = ctrl->value;
+		break;
+	case V4L2_CID_PRIVATE_IRIS_PSALL:
+		radio->g_rds_grp_proc_ps = ctrl->value;
+		break;
+	case V4L2_CID_PRIVATE_IRIS_LP_MODE:
+		break;
+	case V4L2_CID_PRIVATE_IRIS_ANTENNA:
+		temp_val = ctrl->value;
+		retval = hci_fm_set_antenna(&temp_val, radio->fm_hdev);
+		break;
+	case V4L2_CID_RDS_TX_PTY:
+		break;
+	case V4L2_CID_RDS_TX_PI:
+		break;
+	case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_PS_NAME:
+		break;
+	case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_RT:
+		break;
+	case V4L2_CID_PRIVATE_IRIS_TX_SETPSREPEATCOUNT:
+		break;
+	case V4L2_CID_TUNE_POWER_LEVEL:
+		break;
+	default:
+		retval = -EINVAL;
+	}
+	return retval;
+}
+
+static int iris_vidioc_g_tuner(struct file *file, void *priv,
+		struct v4l2_tuner *tuner)
+{
+	struct iris_device *radio = video_get_drvdata(video_devdata(file));
+	int retval;
+	if (tuner->index > 0)
+		return -EINVAL;
+
+	retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
+	if (retval < 0)
+		return retval;
+
+	tuner->type = V4L2_TUNER_RADIO;
+	tuner->rangelow  = radio->recv_conf.band_low_limit * TUNE_PARAM;
+	tuner->rangehigh = radio->recv_conf.band_high_limit * TUNE_PARAM;
+	tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+	tuner->capability = V4L2_TUNER_CAP_LOW;
+	tuner->signal = radio->fm_st_rsp.station_rsp.rssi;
+	tuner->audmode = radio->fm_st_rsp.station_rsp.stereo_prg;
+	tuner->afc = 0;
+
+	return 0;
+}
+
+static int iris_vidioc_s_tuner(struct file *file, void *priv,
+		struct v4l2_tuner *tuner)
+{
+	struct iris_device *radio = video_get_drvdata(video_devdata(file));
+	int retval;
+	if (tuner->index > 0)
+		return -EINVAL;
+
+	radio->recv_conf.band_low_limit = tuner->rangelow / TUNE_PARAM;
+	radio->recv_conf.band_high_limit = tuner->rangehigh / TUNE_PARAM;
+	if (tuner->audmode == V4L2_TUNER_MODE_MONO) {
+		radio->stereo_mode.stereo_mode = 0x01;
+		retval = hci_set_fm_stereo_mode(
+				&radio->stereo_mode,
+				radio->fm_hdev);
+	} else {
+		radio->stereo_mode.stereo_mode = 0x00;
+		retval = hci_set_fm_stereo_mode(
+				&radio->stereo_mode,
+				radio->fm_hdev);
+	}
+	if (retval < 0)
+		FMDERR(": set tuner failed with %d\n", retval);
+	return retval;
+}
+
+static int iris_vidioc_g_frequency(struct file *file, void *priv,
+		struct v4l2_frequency *freq)
+{
+	struct iris_device *radio = video_get_drvdata(video_devdata(file));
+	int retval;
+
+	freq->type = V4L2_TUNER_RADIO;
+	retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
+	if (retval < 0)
+		FMDERR("get frequency failed %d\n", retval);
+	else
+		freq->frequency =
+			radio->fm_st_rsp.station_rsp.station_freq * TUNE_PARAM;
+	return retval;
+}
+
+static int iris_vidioc_s_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *freq)
+{
+	struct iris_device  *radio = video_get_drvdata(video_devdata(file));
+	int retval = -1;
+	freq->frequency = freq->frequency / TUNE_PARAM;
+
+	if (freq->type != V4L2_TUNER_RADIO)
+		return -EINVAL;
+
+	retval = iris_set_freq(radio, freq->frequency);
+	if (retval < 0)
+		FMDERR(" set frequency failed with %d\n", retval);
+	return retval;
+}
+
+static int iris_vidioc_dqbuf(struct file *file, void *priv,
+				struct v4l2_buffer *buffer)
+{
+	struct iris_device  *radio = video_get_drvdata(video_devdata(file));
+	enum iris_buf_t buf_type = buffer->index;
+	struct kfifo *data_fifo;
+	unsigned char *buf = (unsigned char *)buffer->m.userptr;
+	unsigned int len = buffer->length;
+	if (!access_ok(VERIFY_WRITE, buf, len))
+		return -EFAULT;
+	if ((buf_type < IRIS_BUF_MAX) && (buf_type >= 0)) {
+		data_fifo = &radio->data_buf[buf_type];
+		if (buf_type == IRIS_BUF_EVENTS)
+			if (wait_event_interruptible(radio->event_queue,
+				kfifo_len(data_fifo)) < 0)
+				return -EINTR;
+	} else {
+		FMDERR("invalid buffer type\n");
+		return -EINVAL;
+	}
+	buffer->bytesused = kfifo_out_locked(data_fifo, buf, len,
+					&radio->buf_lock[buf_type]);
+
+	return 0;
+}
+
+static int iris_vidioc_g_fmt_type_private(struct file *file, void *priv,
+						struct v4l2_format *f)
+{
+	return 0;
+
+}
+
+static int iris_vidioc_s_hw_freq_seek(struct file *file, void *priv,
+					struct v4l2_hw_freq_seek *seek)
+{
+	struct iris_device *radio = video_get_drvdata(video_devdata(file));
+	int dir;
+	if (seek->seek_upward)
+		dir = SRCH_DIR_UP;
+	else
+		dir = SRCH_DIR_DOWN;
+	return iris_search(radio, CTRL_ON, dir);
+}
+
+static int iris_vidioc_querycap(struct file *file, void *priv,
+	struct v4l2_capability *capability)
+{
+	struct iris_device *radio;
+	radio = video_get_drvdata(video_devdata(file));
+	strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
+	strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
+	radio->g_cap = capability;
+	return 0;
+}
+
+
+static const struct v4l2_ioctl_ops iris_ioctl_ops = {
+	.vidioc_querycap              = iris_vidioc_querycap,
+	.vidioc_queryctrl             = iris_vidioc_queryctrl,
+	.vidioc_g_ctrl                = iris_vidioc_g_ctrl,
+	.vidioc_s_ctrl                = iris_vidioc_s_ctrl,
+	.vidioc_g_tuner               = iris_vidioc_g_tuner,
+	.vidioc_s_tuner               = iris_vidioc_s_tuner,
+	.vidioc_g_frequency           = iris_vidioc_g_frequency,
+	.vidioc_s_frequency           = iris_vidioc_s_frequency,
+	.vidioc_s_hw_freq_seek        = iris_vidioc_s_hw_freq_seek,
+	.vidioc_dqbuf                 = iris_vidioc_dqbuf,
+	.vidioc_g_fmt_type_private    = iris_vidioc_g_fmt_type_private,
+	.vidioc_s_ext_ctrls           = iris_vidioc_s_ext_ctrls,
+};
+
+static const struct v4l2_file_operations iris_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = video_ioctl2,
+};
+
+static struct video_device iris_viddev_template = {
+	.fops                   = &iris_fops,
+	.ioctl_ops              = &iris_ioctl_ops,
+	.name                   = DRIVER_NAME,
+	.release                = video_device_release,
+};
+
+static struct video_device *video_get_dev(void)
+{
+	return priv_videodev;
+}
+
+static int __init iris_probe(struct platform_device *pdev)
+{
+	struct iris_device *radio;
+	int retval;
+	int radio_nr = -1;
+	int i;
+
+	if (!pdev) {
+		FMDERR(": pdev is null\n");
+		return -ENOMEM;
+	}
+
+	radio = kzalloc(sizeof(struct iris_device), GFP_KERNEL);
+	if (!radio) {
+		FMDERR(": Could not allocate radio device\n");
+		return -ENOMEM;
+	}
+
+	radio->dev = &pdev->dev;
+	platform_set_drvdata(pdev, radio);
+
+	radio->videodev = video_device_alloc();
+	if (!radio->videodev) {
+		FMDERR(": Could not allocate V4L device\n");
+		kfree(radio);
+		return -ENOMEM;
+	}
+
+	memcpy(radio->videodev, &iris_viddev_template,
+	  sizeof(iris_viddev_template));
+
+	for (i = 0; i < IRIS_BUF_MAX; i++) {
+		int kfifo_alloc_rc = 0;
+		spin_lock_init(&radio->buf_lock[i]);
+
+		if (i == IRIS_BUF_RAW_RDS)
+			kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
+				rds_buf*3, GFP_KERNEL);
+		else
+			kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
+				STD_BUF_SIZE, GFP_KERNEL);
+
+		if (kfifo_alloc_rc != 0) {
+			FMDERR("failed allocating buffers %d\n",
+				   kfifo_alloc_rc);
+			for (; i > -1; i--) {
+				kfifo_free(&radio->data_buf[i]);
+				kfree(radio);
+				return -ENOMEM;
+			}
+		}
+	}
+
+	mutex_init(&radio->lock);
+	init_completion(&radio->sync_xfr_start);
+	radio->tune_req = 0;
+	init_waitqueue_head(&radio->event_queue);
+	init_waitqueue_head(&radio->read_queue);
+
+	video_set_drvdata(radio->videodev, radio);
+
+	if (NULL == video_get_drvdata(radio->videodev))
+		FMDERR(": video_get_drvdata failed\n");
+
+	retval = video_register_device(radio->videodev, VFL_TYPE_RADIO,
+								   radio_nr);
+	if (retval) {
+		FMDERR(": Could not register video device\n");
+		video_device_release(radio->videodev);
+		for (; i > -1; i--)
+			kfifo_free(&radio->data_buf[i]);
+		kfree(radio);
+		return retval;
+	} else {
+		priv_videodev = kzalloc(sizeof(struct video_device),
+			GFP_KERNEL);
+		memcpy(priv_videodev, radio->videodev,
+			sizeof(struct video_device));
+	}
+	return 0;
+}
+
+
+static int __devexit iris_remove(struct platform_device *pdev)
+{
+	int i;
+	struct iris_device *radio = platform_get_drvdata(pdev);
+
+	video_unregister_device(radio->videodev);
+
+	for (i = 0; i < IRIS_BUF_MAX; i++)
+		kfifo_free(&radio->data_buf[i]);
+
+	kfree(radio);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver iris_driver = {
+	.driver = {
+		.owner  = THIS_MODULE,
+		.name   = "iris_fm",
+	},
+	.remove = __devexit_p(iris_remove),
+};
+
+static int __init iris_radio_init(void)
+{
+	return platform_driver_probe(&iris_driver, iris_probe);
+}
+module_init(iris_radio_init);
+
+static void __exit iris_radio_exit(void)
+{
+	platform_driver_unregister(&iris_driver);
+}
+module_exit(iris_radio_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
new file mode 100644
index 0000000..f04dfe5
--- /dev/null
+++ b/drivers/media/radio/radio-tavarua.c
@@ -0,0 +1,3755 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+/*
+ * Qualcomm Tavarua FM core driver
+ */
+
+/* driver definitions */
+#define DRIVER_AUTHOR "Qualcomm"
+#define DRIVER_NAME "radio-tavarua"
+#define DRIVER_CARD "Qualcomm FM Radio Transceiver"
+#define DRIVER_DESC "I2C radio driver for Qualcomm FM Radio Transceiver "
+#define DRIVER_VERSION "1.0.0"
+
+#include <linux/version.h>
+#include <linux/init.h>         /* Initdata                     */
+#include <linux/delay.h>        /* udelay                       */
+#include <linux/uaccess.h>      /* copy to/from user            */
+#include <linux/kfifo.h>        /* lock free circular buffer    */
+#include <linux/param.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+/* kernel includes */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
+#include <linux/mutex.h>
+#include <media/v4l2-common.h>
+#include <asm/unaligned.h>
+#include <media/v4l2-ioctl.h>
+#include <linux/unistd.h>
+#include <asm/atomic.h>
+#include <media/tavarua.h>
+#include <linux/mfd/marimba.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+/*
+regional parameters for radio device
+*/
+struct region_params_t {
+	enum tavarua_region_t region;
+	unsigned int band_high;
+	unsigned int band_low;
+	char emphasis;
+	char rds_std;
+	char spacing;
+};
+
+struct srch_params_t {
+	unsigned short srch_pi;
+	unsigned char srch_pty;
+	unsigned int preset_num;
+	int get_list;
+};
+
+/* Main radio device structure,
+acts as a shadow copy of the
+actual tavaura registers */
+struct tavarua_device {
+	struct video_device *videodev;
+	/* driver management */
+	int users;
+	/* top level driver data */
+	struct marimba *marimba;
+	struct device *dev;
+	/* platform specific functionality */
+	struct marimba_fm_platform_data *pdata;
+	unsigned int chipID;
+	/*RDS buffers + Radio event buffer*/
+	struct kfifo data_buf[TAVARUA_BUF_MAX];
+	/* search paramters */
+	struct srch_params_t srch_params;
+	/* keep track of pending xfrs */
+	int pending_xfrs[TAVARUA_XFR_MAX];
+	int xfr_bytes_left;
+	int xfr_in_progress;
+	/* Transmit data */
+	enum tavarua_xfr_ctrl_t tx_mode;
+	/* synchrnous xfr data */
+	unsigned char sync_xfr_regs[XFR_REG_NUM];
+	struct completion sync_xfr_start;
+	struct completion sync_req_done;
+	int tune_req;
+	/* internal register status */
+	unsigned char registers[RADIO_REGISTERS];
+	/* regional settings */
+	struct region_params_t region_params;
+	/* power mode */
+	int lp_mode;
+	int handle_irq;
+	/* global lock */
+	struct mutex lock;
+	/* buffer locks*/
+	spinlock_t buf_lock[TAVARUA_BUF_MAX];
+	/* work queue */
+	struct workqueue_struct *wqueue;
+	struct delayed_work work;
+	/* wait queue for blocking event read */
+	wait_queue_head_t event_queue;
+	/* wait queue for raw rds read */
+	wait_queue_head_t read_queue;
+	/* PTY for FM Tx */
+	int pty;
+	/* PI for FM TX */
+	int pi;
+	/*PS repeatcount for PS Tx */
+	int ps_repeatcount;
+};
+
+/**************************************************************************
+ * Module Parameters
+ **************************************************************************/
+
+/* Radio Nr */
+static int radio_nr = -1;
+module_param(radio_nr, int, 0);
+MODULE_PARM_DESC(radio_nr, "Radio Nr");
+static int wait_timeout = WAIT_TIMEOUT;
+/* Bahama's version*/
+static u8 bahama_version;
+/* RDS buffer blocks */
+static unsigned int rds_buf = 100;
+module_param(rds_buf, uint, 0);
+MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
+/* static variables */
+static struct tavarua_device *private_data;
+/* forward declerations */
+static int tavarua_disable_interrupts(struct tavarua_device *radio);
+static int tavarua_setup_interrupts(struct tavarua_device *radio,
+					enum radio_state_t state);
+static int tavarua_start(struct tavarua_device *radio,
+			enum radio_state_t state);
+static int tavarua_request_irq(struct tavarua_device *radio);
+static void start_pending_xfr(struct tavarua_device *radio);
+/* work function */
+static void read_int_stat(struct work_struct *work);
+
+static int is_bahama(void)
+{
+	int id = 0;
+
+	switch (id = adie_get_detected_connectivity_type()) {
+	case BAHAMA_ID:
+		FMDBG("It is Bahama\n");
+		return 1;
+
+	case MARIMBA_ID:
+		FMDBG("It is Marimba\n");
+		return 0;
+	default:
+		printk(KERN_ERR "%s: unexpected adie connectivity type: %d\n",
+			__func__, id);
+		return -ENODEV;
+	}
+}
+
+static int set_fm_slave_id(struct tavarua_device *radio)
+{
+	int bahama_present = is_bahama();
+
+	if (bahama_present == -ENODEV)
+		return -ENODEV;
+
+	if (bahama_present)
+		radio->marimba->mod_id = SLAVE_ID_BAHAMA_FM;
+	else
+		radio->marimba->mod_id = MARIMBA_SLAVE_ID_FM;
+
+	return 0;
+}
+
+/*=============================================================================
+FUNCTION:  tavarua_isr
+=============================================================================*/
+/**
+  This function is called when GPIO is toggled. This functions queues the event
+  to interrupt queue, which is later handled by isr handling funcion.
+  i.e. INIT_DELAYED_WORK(&radio->work, read_int_stat);
+
+  @param irq: irq that is toggled.
+  @param dev_id: structure pointer passed by client.
+
+  @return IRQ_HANDLED.
+*/
+static irqreturn_t tavarua_isr(int irq, void *dev_id)
+{
+	struct tavarua_device *radio = dev_id;
+	/* schedule a tasklet to handle host intr */
+  /* The call to queue_delayed_work ensures that a minimum delay (in jiffies)
+   * passes before the work is actually executed. The return value from the
+   * function is nonzero if the work_struct was actually added to queue
+   * (otherwise, it may have already been there and will not be added a second
+   * time).
+   */
+	queue_delayed_work(radio->wqueue, &radio->work,
+				msecs_to_jiffies(TAVARUA_DELAY));
+	return IRQ_HANDLED;
+}
+
+/**************************************************************************
+ * Interface to radio internal registers over top level marimba driver
+ *************************************************************************/
+
+/*=============================================================================
+FUNCTION:  tavarua_read_registers
+=============================================================================*/
+/**
+  This function is called to read a number of bytes from an I2C interface.
+  The bytes read are stored in internal register status (shadow copy).
+
+  @param radio: structure pointer passed by client.
+  @param offset: register offset.
+  @param len: num of bytes.
+
+  @return => 0 if successful.
+  @return < 0 if failure.
+*/
+static int tavarua_read_registers(struct tavarua_device *radio,
+				unsigned char offset, int len)
+{
+	int retval = 0, i = 0;
+	retval = set_fm_slave_id(radio);
+
+	if (retval == -ENODEV)
+		return retval;
+
+	FMDBG_I2C("I2C Slave: %x, Read Offset(%x): Data [",
+						radio->marimba->mod_id,
+						offset);
+
+	retval =  marimba_read(radio->marimba, offset,
+				&radio->registers[offset], len);
+
+	if (retval > 0) {
+		for (i = 0; i < len; i++)
+			FMDBG_I2C("%02x ", radio->registers[offset+i]);
+		FMDBG_I2C(" ]\n");
+
+	}
+	return retval;
+}
+
+/*=============================================================================
+FUNCTION:  tavarua_write_register
+=============================================================================*/
+/**
+  This function is called to write a byte over the I2C interface.
+  The corresponding shadow copy is stored in internal register status.
+
+  @param radio: structure pointer passed by client.
+  @param offset: register offset.
+  @param value: buffer to be written to the registers.
+
+  @return => 0 if successful.
+  @return < 0 if failure.
+*/
+static int tavarua_write_register(struct tavarua_device *radio,
+			unsigned char offset, unsigned char value)
+{
+	int retval;
+	retval = set_fm_slave_id(radio);
+
+	if (retval == -ENODEV)
+		return retval;
+
+	FMDBG_I2C("I2C Slave: %x, Write Offset(%x): Data[",
+						radio->marimba->mod_id,
+						offset);
+	retval = marimba_write(radio->marimba, offset, &value, 1);
+	if (retval > 0) {
+		if (offset < RADIO_REGISTERS) {
+			radio->registers[offset] = value;
+			FMDBG_I2C("%02x ", radio->registers[offset]);
+		}
+		FMDBG_I2C(" ]\n");
+	}
+	return retval;
+}
+
+/*=============================================================================
+FUNCTION:  tavarua_write_registers
+=============================================================================*/
+/**
+  This function is called to write a number of bytes over the I2C interface.
+  The corresponding shadow copy is stored in internal register status.
+
+  @param radio: structure pointer passed by client.
+  @param offset: register offset.
+  @param buf: buffer to be written to the registers.
+  @param len: num of bytes.
+
+  @return => 0 if successful.
+  @return < 0 if failure.
+*/
+static int tavarua_write_registers(struct tavarua_device *radio,
+			unsigned char offset, unsigned char *buf, int len)
+{
+
+	int i;
+	int retval;
+	retval = set_fm_slave_id(radio);
+
+	if (retval == -ENODEV)
+		return retval;
+
+	FMDBG_I2C("I2C Slave: %x, Write Offset(%x): Data[",
+						radio->marimba->mod_id,
+						offset);
+	retval = marimba_write(radio->marimba, offset, buf, len);
+	if (retval > 0) { /* if write successful, update internal state too */
+		for (i = 0; i < len; i++) {
+			if ((offset+i) < RADIO_REGISTERS) {
+				radio->registers[offset+i] = buf[i];
+				FMDBG_I2C("%x ",  radio->registers[offset+i]);
+			}
+		}
+		FMDBG_I2C(" ]\n");
+	}
+	return retval;
+}
+
+/*=============================================================================
+FUNCTION:  read_data_blocks
+=============================================================================*/
+/**
+  This function reads Raw RDS blocks from Core regs to driver
+  internal regs (shadow copy).
+
+  @param radio: structure pointer passed by client.
+  @param offset: register offset.
+
+  @return => 0 if successful.
+  @return < 0 if failure.
+*/
+static int read_data_blocks(struct tavarua_device *radio, unsigned char offset)
+{
+	/* read all 3 RDS blocks */
+	return tavarua_read_registers(radio, offset, RDS_BLOCK*4);
+}
+
+/*=============================================================================
+FUNCTION:  tavarua_rds_read
+=============================================================================*/
+/**
+  This is a rds processing function reads that reads Raw RDS blocks from Core
+  regs to driver internal regs (shadow copy). It then fills the V4L2 RDS buffer,
+  which is read by App using JNI interface.
+
+  @param radio: structure pointer passed by client.
+
+  @return None.
+*/
+static void tavarua_rds_read(struct tavarua_device *radio)
+{
+	struct kfifo *rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
+	unsigned char blocknum;
+	unsigned char tmp[3];
+
+	if (read_data_blocks(radio, RAW_RDS) < 0)
+		return;
+	 /* copy all four RDS blocks to internal buffer */
+	for (blocknum = 0; blocknum < RDS_BLOCKS_NUM; blocknum++) {
+		/* Fill the V4L2 RDS buffer */
+		put_unaligned(cpu_to_le16(radio->registers[RAW_RDS +
+			blocknum*RDS_BLOCK]), (unsigned short *) tmp);
+		tmp[2] = blocknum;		/* offset name */
+		tmp[2] |= blocknum << 3;	/* received offset */
+		tmp[2] |= 0x40; /* corrected error(s) */
+
+		/* copy RDS block to internal buffer */
+		kfifo_in_locked(rds_buf, tmp, 3, &radio->buf_lock[TAVARUA_BUF_RAW_RDS]);
+	}
+	/* wake up read queue */
+	if (kfifo_len(rds_buf))
+		wake_up_interruptible(&radio->read_queue);
+
+}
+
+/*=============================================================================
+FUNCTION:  request_read_xfr
+=============================================================================*/
+/**
+  This function sets the desired MODE in the XFRCTRL register and also sets the
+  CTRL field to read.
+  This is an asynchronous way of reading the XFR registers. Client would request
+  by setting the desired mode in the XFRCTRL register and then would initiate
+  the actual data register read by calling copy_from_xfr up on SOC signals
+  success.
+
+  NOTE:
+
+  The Data Transfer (XFR) registers are used to pass various data and
+  configuration parameters between the Core and host processor.
+
+  To read from the XFR registers, the host processor must set the desired MODE
+  in the XFRCTRL register and set the CTRL field to read. The Core will then
+  populate the XFRDAT0 - XFRDAT15 registers with the defined mode bytes. The
+  Core will set the TRANSFER interrupt status bit and interrupt the host if the
+  TRANSFERCTRL interrupt control bit is set. The host can then extract the XFR
+  mode bytes once it detects that the Core has updated the registers.
+
+  @param radio: structure pointer passed by client.
+
+  @return Always returns 0.
+*/
+static int request_read_xfr(struct tavarua_device *radio,
+				enum tavarua_xfr_ctrl_t mode){
+
+	tavarua_write_register(radio, XFRCTRL, mode);
+	msleep(TAVARUA_DELAY);
+	return 0;
+}
+
+/*=============================================================================
+FUNCTION:  copy_from_xfr
+=============================================================================*/
+/**
+  This function is used to read XFR mode bytes once it detects that the Core
+  has updated the registers. It also updates XFR regs to the appropriate
+  internal buffer n bytes.
+
+  NOTE:
+
+  This function should be used in conjuction with request_read_xfr. Refer
+  request_read_xfr for XFR mode transaction details.
+
+  @param radio: structure pointer passed by client.
+  @param buf_type: Index into RDS/Radio event buffer to use.
+  @param len: num of bytes.
+
+  @return Always returns 0.
+*/
+static int copy_from_xfr(struct tavarua_device *radio,
+		enum tavarua_buf_t buf_type, unsigned int n){
+
+	struct kfifo *data_fifo = &radio->data_buf[buf_type];
+	unsigned char *xfr_regs = &radio->registers[XFRCTRL+1];
+	kfifo_in_locked(data_fifo, xfr_regs, n, &radio->buf_lock[buf_type]);
+	return 0;
+}
+
+/*=============================================================================
+FUNCTION:  write_to_xfr
+=============================================================================*/
+/**
+  This function sets the desired MODE in the XFRCTRL register and it also sets
+  the CTRL field and data to write.
+  This also writes all the XFRDATx registers with the desired input buffer.
+
+  NOTE:
+
+  The Data Transfer (XFR) registers are used to pass various data and
+  configuration parameters between the Core and host processor.
+
+  To write data to the Core, the host processor updates XFRDAT0 - XFRDAT15 with
+  the appropriate mode bytes. The host processor must then set the desired MODE
+  in the XFRCTRL register and set the CTRL field to write. The core will detect
+  that the XFRCTRL register was written to and will read the XFR mode bytes.
+  After reading all the mode bytes, the Core will set the TRANSFER interrupt
+  status bit and interrupt the host if the TRANSFERCTRL interrupt control bit
+  is set.
+
+  @param radio: structure pointer passed by client.
+  @param mode: XFR mode to write in XFRCTRL register.
+  @param buf: buffer to be written to the registers.
+  @param len: num of bytes.
+
+  @return => 0 if successful.
+  @return < 0 if failure.
+*/
+static int write_to_xfr(struct tavarua_device *radio, unsigned char mode,
+			char *buf, int len)
+{
+	char buffer[len+1];
+	memcpy(buffer+1, buf, len);
+	/* buffer[0] corresponds to XFRCTRL register
+	   set the CTRL bit to 1 for write mode
+	*/
+	buffer[0] = ((1<<7) | mode);
+	return tavarua_write_registers(radio, XFRCTRL, buffer, sizeof(buffer));
+}
+
+/*=============================================================================
+FUNCTION:  xfr_intf_own
+=============================================================================*/
+/**
+  This function is used to check if there is any pending XFR mode operation.
+  If yes, wait for it to complete, else update the flag to indicate XFR
+  operation is in progress
+
+  @param radio: structure pointer passed by client.
+
+  @return 0      on success.
+	-ETIME on timeout.
+*/
+static int xfr_intf_own(struct tavarua_device *radio)
+{
+
+	mutex_lock(&radio->lock);
+	if (radio->xfr_in_progress) {
+		radio->pending_xfrs[TAVARUA_XFR_SYNC] = 1;
+		mutex_unlock(&radio->lock);
+		if (!wait_for_completion_timeout(&radio->sync_xfr_start,
+			msecs_to_jiffies(wait_timeout)))
+			return -ETIME;
+	} else {
+		FMDBG("gained ownership of xfr\n");
+		radio->xfr_in_progress = 1;
+		mutex_unlock(&radio->lock);
+	}
+	return 0;
+}
+
+/*=============================================================================
+FUNCTION:  sync_read_xfr
+=============================================================================*/
+/**
+  This function is used to do synchronous XFR read operation.
+
+  @param radio: structure pointer passed by client.
+  @param xfr_type: XFR mode to write in XFRCTRL register.
+  @param buf: buffer to be read from the core.
+
+  @return => 0 if successful.
+  @return < 0 if failure.
+*/
+static int sync_read_xfr(struct tavarua_device *radio,
+			enum tavarua_xfr_ctrl_t xfr_type, unsigned char *buf)
+{
+	int retval;
+	retval = xfr_intf_own(radio);
+	if (retval < 0)
+		return retval;
+	retval = tavarua_write_register(radio, XFRCTRL, xfr_type);
+
+	if (retval >= 0) {
+		/* Wait for interrupt i.e. complete
+		(&radio->sync_req_done); call */
+		if (!wait_for_completion_timeout(&radio->sync_req_done,
+			msecs_to_jiffies(wait_timeout)) || (retval < 0)) {
+			retval = -ETIME;
+		} else {
+			memcpy(buf, radio->sync_xfr_regs, XFR_REG_NUM);
+		}
+	}
+	radio->xfr_in_progress = 0;
+	start_pending_xfr(radio);
+	FMDBG("%s: %d\n", __func__, retval);
+	return retval;
+}
+
+/*=============================================================================
+FUNCTION:  sync_write_xfr
+=============================================================================*/
+/**
+  This function is used to do synchronous XFR write operation.
+
+  @param radio: structure pointer passed by client.
+  @param xfr_type: XFR mode to write in XFRCTRL register.
+  @param buf: buffer to be written to the core.
+
+  @return => 0 if successful.
+  @return < 0 if failure.
+*/
+static int sync_write_xfr(struct tavarua_device *radio,
+		enum tavarua_xfr_ctrl_t xfr_type, unsigned char *buf)
+{
+	int retval;
+	retval = xfr_intf_own(radio);
+	if (retval < 0)
+		return retval;
+	retval = write_to_xfr(radio, xfr_type, buf, XFR_REG_NUM);
+
+	if (retval >= 0) {
+		/* Wait for interrupt i.e. complete
+		(&radio->sync_req_done); call */
+		if (!wait_for_completion_timeout(&radio->sync_req_done,
+			msecs_to_jiffies(wait_timeout)) || (retval < 0)) {
+			FMDBG("Write xfr timeout");
+		}
+	}
+	radio->xfr_in_progress = 0;
+	start_pending_xfr(radio);
+	FMDBG("%s: %d\n", __func__,  retval);
+	return retval;
+}
+
+
+/*=============================================================================
+FUNCTION:  start_pending_xfr
+=============================================================================*/
+/**
+  This function checks if their are any pending xfr interrupts and if
+  the interrupts are either RDS PS, RDS RT, RDS AF, SCANNEXT, SEARCH or SYNC
+  then initiates corresponding read operation. Preference is given to RAW RDS
+  data (SYNC) over processed data (PS, RT, AF, etc) from core.
+
+  @param radio: structure pointer passed by client.
+
+  @return None.
+*/
+static void start_pending_xfr(struct tavarua_device *radio)
+{
+	int i;
+	enum tavarua_xfr_t xfr;
+	for (i = 0; i < TAVARUA_XFR_MAX; i++) {
+		if (radio->pending_xfrs[i]) {
+			radio->xfr_in_progress = 1;
+			xfr = (enum tavarua_xfr_t)i;
+			switch (xfr) {
+			/* priority given to synchronous xfrs */
+			case TAVARUA_XFR_SYNC:
+				complete(&radio->sync_xfr_start);
+				break;
+			/* asynchrnous xfrs */
+			case TAVARUA_XFR_SRCH_LIST:
+				request_read_xfr(radio, RX_STATIONS_0);
+				break;
+			case TAVARUA_XFR_RT_RDS:
+				request_read_xfr(radio, RDS_RT_0);
+				break;
+			case TAVARUA_XFR_PS_RDS:
+				request_read_xfr(radio, RDS_PS_0);
+				break;
+			case TAVARUA_XFR_AF_LIST:
+				request_read_xfr(radio, RDS_AF_0);
+				break;
+			default:
+				FMDERR("%s: Unsupported XFR %d\n",
+					 __func__, xfr);
+			}
+			radio->pending_xfrs[i] = 0;
+			FMDBG("resurrect xfr %d\n", i);
+			}
+	}
+	return;
+}
+
+/*=============================================================================
+FUNCTION:  tavarua_q_event
+=============================================================================*/
+/**
+  This function is called to queue an event for user.
+
+  NOTE:
+  Applications call the VIDIOC_QBUF ioctl to enqueue an empty (capturing) or
+  filled (output) buffer in the driver's incoming queue.
+
+  Pleaes refer tavarua_probe where we register different ioctl's for FM.
+
+  @param radio: structure pointer passed by client.
+  @param event: event to be queued.
+
+  @return None.
+*/
+static void tavarua_q_event(struct tavarua_device *radio,
+				enum tavarua_evt_t event)
+{
+
+	struct kfifo *data_b = &radio->data_buf[TAVARUA_BUF_EVENTS];
+	unsigned char evt = event;
+	FMDBG("updating event_q with event %x\n", event);
+	if (kfifo_in_locked(data_b, &evt, 1, &radio->buf_lock[TAVARUA_BUF_EVENTS]))
+		wake_up_interruptible(&radio->event_queue);
+}
+
+/*=============================================================================
+FUNCTION:  tavarua_start_xfr
+=============================================================================*/
+/**
+  This function is called to process interrupts which require multiple XFR
+  operations (RDS search, RDS PS, RDS RT, etc). if any XFR operation is
+  already in progress we store information about pending interrupt, which
+  will be processed in future when current pending operation is done.
+
+  @param radio: structure pointer passed by client.
+  @param pending_id: XFR operation (which requires multiple XFR operations in
+	steps) to start.
+  @param xfr_id: XFR mode to write in XFRCTRL register.
+
+  @return None.
+*/
+static void tavarua_start_xfr(struct tavarua_device *radio,
+		enum tavarua_xfr_t pending_id, enum tavarua_xfr_ctrl_t xfr_id)
+{
+		if (radio->xfr_in_progress)
+			radio->pending_xfrs[pending_id] = 1;
+		else {
+			radio->xfr_in_progress = 1;
+			request_read_xfr(radio, xfr_id);
+		}
+}
+
+/*=============================================================================
+FUNCTION:  tavarua_handle_interrupts
+=============================================================================*/
+/**
+  This function processes the interrupts.
+
+  NOTE:
+  tavarua_q_event is used to queue events in App buffer. i.e. App calls the
+  VIDIOC_QBUF ioctl to enqueue an empty (capturing) buffer, which is filled
+  by tavarua_q_event call.
+
+  Any async event that requires multiple steps, i.e. search, RT, PS, etc is
+  handled one at a time. (We preserve other interrupts when processing one).
+  Sync interrupts are given priority.
+
+  @param radio: structure pointer passed by client.
+
+  @return None.
+*/
+static void tavarua_handle_interrupts(struct tavarua_device *radio)
+{
+	int i;
+	int retval;
+	unsigned char xfr_status;
+	if (!radio->handle_irq) {
+		FMDBG("IRQ happend, but I wont handle it\n");
+		return;
+	}
+	mutex_lock(&radio->lock);
+	tavarua_read_registers(radio, STATUS_REG1, STATUS_REG_NUM);
+
+	FMDBG("INTSTAT1 <%x>\n", radio->registers[STATUS_REG1]);
+	FMDBG("INTSTAT2 <%x>\n", radio->registers[STATUS_REG2]);
+	FMDBG("INTSTAT3 <%x>\n", radio->registers[STATUS_REG3]);
+
+	if (radio->registers[STATUS_REG1] & READY) {
+		complete(&radio->sync_req_done);
+		tavarua_q_event(radio, TAVARUA_EVT_RADIO_READY);
+	}
+
+	/* Tune completed */
+	if (radio->registers[STATUS_REG1] & TUNE) {
+		if (radio->tune_req) {
+			complete(&radio->sync_req_done);
+			radio->tune_req = 0;
+		}
+		tavarua_q_event(radio, TAVARUA_EVT_TUNE_SUCC);
+		if (radio->srch_params.get_list) {
+			tavarua_start_xfr(radio, TAVARUA_XFR_SRCH_LIST,
+							RX_STATIONS_0);
+		}
+		radio->srch_params.get_list = 0;
+		radio->xfr_in_progress = 0;
+		radio->xfr_bytes_left = 0;
+		for (i = 0; i < TAVARUA_BUF_MAX; i++) {
+			if (i >= TAVARUA_BUF_RT_RDS)
+				kfifo_reset(&radio->data_buf[i]);
+		}
+		for (i = 0; i < TAVARUA_XFR_MAX; i++) {
+			if (i >= TAVARUA_XFR_RT_RDS)
+				radio->pending_xfrs[i] = 0;
+		}
+		retval = tavarua_read_registers(radio, TUNECTRL, 1);
+		/* send to user station parameters */
+		if (retval > -1) {
+			/* Signal strength */
+			if (!(radio->registers[TUNECTRL] & SIGSTATE))
+				tavarua_q_event(radio, TAVARUA_EVT_BELOW_TH);
+			else
+				tavarua_q_event(radio, TAVARUA_EVT_ABOVE_TH);
+			/* mono/stereo */
+			if ((radio->registers[TUNECTRL] & MOSTSTATE))
+				tavarua_q_event(radio, TAVARUA_EVT_STEREO);
+			else
+				tavarua_q_event(radio, TAVARUA_EVT_MONO);
+			/* is RDS available */
+			if ((radio->registers[TUNECTRL] & RDSSYNC))
+				tavarua_q_event(radio, TAVARUA_EVT_RDS_AVAIL);
+			else
+				tavarua_q_event(radio,
+						TAVARUA_EVT_RDS_NOT_AVAIL);
+		}
+
+	} else {
+		if (radio->tune_req) {
+			FMDERR("Tune INT is pending\n");
+			mutex_unlock(&radio->lock);
+			return;
+		}
+	}
+	/* Search completed (read FREQ) */
+	if (radio->registers[STATUS_REG1] & SEARCH)
+		tavarua_q_event(radio, TAVARUA_EVT_SEEK_COMPLETE);
+
+	/* Scanning for next station */
+	if (radio->registers[STATUS_REG1] & SCANNEXT)
+		tavarua_q_event(radio, TAVARUA_EVT_SCAN_NEXT);
+
+	/* Signal indicator change (read SIGSTATE) */
+	if (radio->registers[STATUS_REG1] & SIGNAL) {
+		retval = tavarua_read_registers(radio, TUNECTRL, 1);
+		if (retval > -1) {
+			if (!(radio->registers[TUNECTRL] & SIGSTATE))
+				tavarua_q_event(radio, TAVARUA_EVT_BELOW_TH);
+			else
+				tavarua_q_event(radio, TAVARUA_EVT_ABOVE_TH);
+		}
+	}
+
+	/* RDS synchronization state change (read RDSSYNC) */
+	if (radio->registers[STATUS_REG1] & SYNC) {
+		retval = tavarua_read_registers(radio, TUNECTRL, 1);
+		if (retval > -1) {
+			if ((radio->registers[TUNECTRL] & RDSSYNC))
+				tavarua_q_event(radio, TAVARUA_EVT_RDS_AVAIL);
+			else
+				tavarua_q_event(radio,
+						TAVARUA_EVT_RDS_NOT_AVAIL);
+		}
+	}
+
+	/* Audio Control indicator (read AUDIOIND) */
+	if (radio->registers[STATUS_REG1] & AUDIO) {
+		retval = tavarua_read_registers(radio, AUDIOIND, 1);
+		if (retval > -1) {
+			if ((radio->registers[AUDIOIND] & 0x01))
+				tavarua_q_event(radio, TAVARUA_EVT_STEREO);
+			else
+				tavarua_q_event(radio, TAVARUA_EVT_MONO);
+		}
+	}
+
+	/* interrupt register 2 */
+
+	/* New unread RDS data group available */
+	if (radio->registers[STATUS_REG2] & RDSDAT) {
+		FMDBG("Raw RDS Available\n");
+		tavarua_rds_read(radio);
+		tavarua_q_event(radio, TAVARUA_EVT_NEW_RAW_RDS);
+	}
+
+	/* New RDS Program Service Table available */
+	if (radio->registers[STATUS_REG2] & RDSPS) {
+		FMDBG("New PS RDS\n");
+		tavarua_start_xfr(radio, TAVARUA_XFR_PS_RDS, RDS_PS_0);
+	}
+
+	/* New RDS Radio Text available */
+	if (radio->registers[STATUS_REG2] & RDSRT) {
+		FMDBG("New RT RDS\n");
+		tavarua_start_xfr(radio, TAVARUA_XFR_RT_RDS, RDS_RT_0);
+	}
+
+	/* New RDS Radio Text available */
+	if (radio->registers[STATUS_REG2] & RDSAF) {
+		FMDBG("New AF RDS\n");
+		tavarua_start_xfr(radio, TAVARUA_XFR_AF_LIST, RDS_AF_0);
+	}
+	/* Trasmitter an RDS Group */
+	if (radio->registers[STATUS_REG2] & TXRDSDAT) {
+		FMDBG("New TXRDSDAT\n");
+		tavarua_q_event(radio, TAVARUA_EVT_TXRDSDAT);
+	}
+
+	/* Complete RDS buffer is available for transmission */
+	if (radio->registers[STATUS_REG2] & TXRDSDONE) {
+		FMDBG("New TXRDSDAT\n");
+		tavarua_q_event(radio, TAVARUA_EVT_TXRDSDONE);
+	}
+	/* interrupt register 3 */
+
+	/* Data transfer (XFR) completed */
+	if (radio->registers[STATUS_REG3] & TRANSFER) {
+		FMDBG("XFR Interrupt\n");
+		tavarua_read_registers(radio, XFRCTRL, XFR_REG_NUM+1);
+		FMDBG("XFRCTRL IS: %x\n", radio->registers[XFRCTRL]);
+		xfr_status = radio->registers[XFRCTRL];
+		switch (xfr_status) {
+		case RDS_PS_0:
+			FMDBG("PS Header\n");
+			copy_from_xfr(radio, TAVARUA_BUF_PS_RDS, 5);
+			radio->xfr_bytes_left = (radio->registers[XFRCTRL+1] &
+								0x0F) * 8;
+			FMDBG("PS RDS Length: %d\n", radio->xfr_bytes_left);
+			if ((radio->xfr_bytes_left > 0) &&
+			    (radio->xfr_bytes_left < 97))
+				request_read_xfr(radio,	RDS_PS_1);
+			else
+				radio->xfr_in_progress = 0;
+			break;
+		case RDS_PS_1:
+		case RDS_PS_2:
+		case RDS_PS_3:
+		case RDS_PS_4:
+		case RDS_PS_5:
+		case RDS_PS_6:
+			FMDBG("PS Data\n");
+			copy_from_xfr(radio, TAVARUA_BUF_PS_RDS, XFR_REG_NUM);
+			radio->xfr_bytes_left -= XFR_REG_NUM;
+			if (radio->xfr_bytes_left > 0) {
+				if ((xfr_status + 1) > RDS_PS_6)
+					request_read_xfr(radio,	RDS_PS_6);
+				else
+					request_read_xfr(radio,	xfr_status+1);
+			} else {
+				radio->xfr_in_progress = 0;
+				tavarua_q_event(radio, TAVARUA_EVT_NEW_PS_RDS);
+			}
+			break;
+		case RDS_RT_0:
+			FMDBG("RT Header\n");
+			copy_from_xfr(radio, TAVARUA_BUF_RT_RDS, 5);
+			radio->xfr_bytes_left = radio->registers[XFRCTRL+1]
+									& 0x7F;
+			FMDBG("RT RDS Length: %d\n", radio->xfr_bytes_left);
+			/*RT_1 to RT_4  16 byte registers so 64 bytes */
+			if ((radio->xfr_bytes_left > 0)
+					 && (radio->xfr_bytes_left < 65))
+				request_read_xfr(radio, RDS_RT_1);
+			break;
+		case RDS_RT_1:
+		case RDS_RT_2:
+		case RDS_RT_3:
+		case RDS_RT_4:
+			FMDBG("xfr interrupt RT data\n");
+			copy_from_xfr(radio, TAVARUA_BUF_RT_RDS, XFR_REG_NUM);
+			radio->xfr_bytes_left -= XFR_REG_NUM;
+			if (radio->xfr_bytes_left > 0)
+				request_read_xfr(radio,	xfr_status+1);
+			else {
+				radio->xfr_in_progress = 0;
+				tavarua_q_event(radio, TAVARUA_EVT_NEW_RT_RDS);
+			}
+			break;
+		case RDS_AF_0:
+			copy_from_xfr(radio, TAVARUA_BUF_AF_LIST,
+						XFR_REG_NUM);
+			radio->xfr_bytes_left = radio->registers[XFRCTRL+5]-11;
+			if (radio->xfr_bytes_left > 0)
+				request_read_xfr(radio,	RDS_AF_1);
+			else
+				radio->xfr_in_progress = 0;
+			break;
+		case RDS_AF_1:
+			copy_from_xfr(radio, TAVARUA_BUF_AF_LIST,
+						radio->xfr_bytes_left);
+			tavarua_q_event(radio, TAVARUA_EVT_NEW_AF_LIST);
+			radio->xfr_in_progress = 0;
+			break;
+		case RX_CONFIG:
+		case RADIO_CONFIG:
+		case RDS_CONFIG:
+			memcpy(radio->sync_xfr_regs,
+				&radio->registers[XFRCTRL+1], XFR_REG_NUM);
+			complete(&radio->sync_req_done);
+			break;
+		case RX_STATIONS_0:
+			FMDBG("Search list has %d stations\n",
+						radio->registers[XFRCTRL+1]);
+			radio->xfr_bytes_left = radio->registers[XFRCTRL+1]*2;
+			if (radio->xfr_bytes_left > 14) {
+				copy_from_xfr(radio, TAVARUA_BUF_SRCH_LIST,
+							XFR_REG_NUM);
+				request_read_xfr(radio,	RX_STATIONS_1);
+			} else if (radio->xfr_bytes_left) {
+				FMDBG("In else RX_STATIONS_0\n");
+				copy_from_xfr(radio, TAVARUA_BUF_SRCH_LIST,
+						radio->xfr_bytes_left+1);
+				tavarua_q_event(radio,
+						TAVARUA_EVT_NEW_SRCH_LIST);
+				radio->xfr_in_progress = 0;
+			}
+			break;
+		case RX_STATIONS_1:
+			FMDBG("In RX_STATIONS_1");
+			copy_from_xfr(radio, TAVARUA_BUF_SRCH_LIST,
+						radio->xfr_bytes_left);
+			tavarua_q_event(radio, TAVARUA_EVT_NEW_SRCH_LIST);
+			radio->xfr_in_progress = 0;
+			break;
+		case PHY_TXGAIN:
+			FMDBG("read PHY_TXGAIN is successful");
+			complete(&radio->sync_req_done);
+			break;
+		case (0x80 | RX_CONFIG):
+		case (0x80 | RADIO_CONFIG):
+		case (0x80 | RDS_CONFIG):
+		case (0x80 | INT_CTRL):
+			complete(&radio->sync_req_done);
+			break;
+		case (0x80 | RDS_RT_0):
+			FMDBG("RT Header Sent\n");
+			complete(&radio->sync_req_done);
+			break;
+		case (0x80 | RDS_RT_1):
+		case (0x80 | RDS_RT_2):
+		case (0x80 | RDS_RT_3):
+		case (0x80 | RDS_RT_4):
+			FMDBG("xfr interrupt RT data Sent\n");
+			complete(&radio->sync_req_done);
+			break;
+		/*TX Specific transfer */
+		case (0x80 | RDS_PS_0):
+			FMDBG("PS Header Sent\n");
+			complete(&radio->sync_req_done);
+			break;
+		case (0x80 | RDS_PS_1):
+		case (0x80 | RDS_PS_2):
+		case (0x80 | RDS_PS_3):
+		case (0x80 | RDS_PS_4):
+		case (0x80 | RDS_PS_5):
+		case (0x80 | RDS_PS_6):
+			FMDBG("xfr interrupt PS data Sent\n");
+			complete(&radio->sync_req_done);
+			break;
+		case (0x80 | PHY_TXGAIN):
+			FMDBG("write PHY_TXGAIN is successful");
+			complete(&radio->sync_req_done);
+			break;
+		default:
+			FMDERR("UNKNOWN XFR = %d\n", xfr_status);
+		}
+		if (!radio->xfr_in_progress)
+			start_pending_xfr(radio);
+
+	}
+
+	/* Error occurred. Read ERRCODE to determine cause */
+	if (radio->registers[STATUS_REG3] & ERROR) {
+#ifdef FM_DEBUG
+		unsigned char xfr_buf[XFR_REG_NUM];
+		int retval = sync_read_xfr(radio, ERROR_CODE, xfr_buf);
+		FMDBG("retval of ERROR_CODE read : %d\n", retval);
+#endif
+		FMDERR("ERROR STATE\n");
+	}
+
+	mutex_unlock(&radio->lock);
+	FMDBG("Work is done\n");
+
+}
+
+/*=============================================================================
+FUNCTION:  read_int_stat
+=============================================================================*/
+/**
+  This function is scheduled whenever there is an interrupt pending in interrupt
+  queue. i.e. kfmradio.
+
+  Whenever there is a GPIO interrupt, a delayed work will be queued in to the
+  'kfmradio' work queue. Upon execution of this work in the queue, a  a call
+  to read_int_stat function will be made , which would in turn handle the
+  interrupts by reading the INTSTATx registers.
+  NOTE:
+  Tasks to be run out of a workqueue need to be packaged in a struct
+  work_struct structure.
+
+  @param work: work_struct structure.
+
+  @return None.
+*/
+static void read_int_stat(struct work_struct *work)
+{
+	struct tavarua_device *radio = container_of(work,
+					struct tavarua_device, work.work);
+	tavarua_handle_interrupts(radio);
+}
+
+/*************************************************************************
+ * irq helper functions
+ ************************************************************************/
+
+/*=============================================================================
+FUNCTION:  tavarua_request_irq
+=============================================================================*/
+/**
+  This function is called to acquire a FM GPIO and enable FM interrupts.
+
+  @param radio: structure pointer passed by client.
+
+  @return 0 if success else otherwise.
+*/
+static int tavarua_request_irq(struct tavarua_device *radio)
+{
+	int retval;
+	int irq = radio->pdata->irq;
+	if (radio == NULL)
+		return -EINVAL;
+
+  /* A workqueue created with create_workqueue() will have one worker thread
+   * for each CPU on the system; create_singlethread_workqueue(), instead,
+   * creates a workqueue with a single worker process. The name of the queue
+   * is limited to ten characters; it is only used for generating the "command"
+   * for the kernel thread(s) (which can be seen in ps or top).
+   */
+	radio->wqueue  = create_singlethread_workqueue("kfmradio");
+	if (!radio->wqueue)
+		return -ENOMEM;
+  /* allocate an interrupt line */
+  /* On success, request_irq() returns 0 if everything goes  as
+     planned.  Your interrupt handler will start receiving its
+     interrupts immediately. On failure, request_irq()
+     returns:
+	-EINVAL
+		The  IRQ  number  you  requested  was either
+		invalid or reserved, or your passed  a  NULL
+		pointer for the handler() parameter.
+
+	-EBUSY The  IRQ you requested is already being
+		handled, and the IRQ cannot  be  shared.
+
+	-ENXIO The m68k returns this value for  an  invalid
+		IRQ number.
+  */
+	/* Use request_any_context_irq, So that it might work for nested or
+	nested interrupts. in MSM8x60, FM is connected to PMIC GPIO and it
+	is a nested interrupt*/
+	retval = request_any_context_irq(irq, tavarua_isr,
+				IRQ_TYPE_EDGE_FALLING, "fm interrupt", radio);
+	if (retval < 0) {
+		FMDERR("Couldn't acquire FM gpio %d\n", irq);
+		return retval;
+	} else {
+		FMDBG("FM GPIO %d registered\n", irq);
+	}
+	retval = enable_irq_wake(irq);
+	if (retval < 0) {
+		FMDERR("Could not enable FM interrupt\n ");
+		free_irq(irq , radio);
+	}
+	return retval;
+}
+
+/*=============================================================================
+FUNCTION:  tavarua_disable_irq
+=============================================================================*/
+/**
+  This function is called to disable FM irq and free up FM interrupt handling
+  resources.
+
+  @param radio: structure pointer passed by client.
+
+  @return 0 if success else otherwise.
+*/
+static int tavarua_disable_irq(struct tavarua_device *radio)
+{
+	int irq;
+	if (!radio)
+		return -EINVAL;
+	irq = radio->pdata->irq;
+	disable_irq_wake(irq);
+	cancel_delayed_work_sync(&radio->work);
+	flush_workqueue(radio->wqueue);
+	free_irq(irq, radio);
+	destroy_workqueue(radio->wqueue);
+	return 0;
+}
+
+/*************************************************************************
+ * fops/IOCTL helper functions
+ ************************************************************************/
+
+/*=============================================================================
+FUNCTION:  tavarua_search
+=============================================================================*/
+/**
+  This interface sets the search control features.
+
+  @param radio: structure pointer passed by client.
+  @param on: The value of a control.
+  @param dir: FM search direction.
+
+  @return => 0 if successful.
+  @return < 0 if failure.
+*/
+static int tavarua_search(struct tavarua_device *radio, int on, int dir)
+{
+	enum search_t srch = radio->registers[SRCHCTRL] & SRCH_MODE;
+
+	FMDBG("In tavarua_search\n");
+	if (on) {
+		radio->registers[SRCHRDS1] = 0x00;
+		radio->registers[SRCHRDS2] = 0x00;
+		/* Set freq band */
+		switch (srch) {
+		case SCAN_FOR_STRONG:
+		case SCAN_FOR_WEAK:
+			radio->srch_params.get_list = 1;
+			radio->registers[SRCHRDS2] =
+					radio->srch_params.preset_num;
+			break;
+		case RDS_SEEK_PTY:
+		case RDS_SCAN_PTY:
+			radio->registers[SRCHRDS2] =
+					radio->srch_params.srch_pty;
+			break;
+		case RDS_SEEK_PI:
+			radio->registers[SRCHRDS1] =
+				(radio->srch_params.srch_pi & 0xFF00) >> 8;
+			radio->registers[SRCHRDS2] =
+				(radio->srch_params.srch_pi & 0x00FF);
+			break;
+		default:
+			break;
+		}
+		radio->registers[SRCHCTRL] |= SRCH_ON;
+	} else {
+		radio->registers[SRCHCTRL] &= ~SRCH_ON;
+		radio->srch_params.get_list = 0;
+	}
+	radio->registers[SRCHCTRL] = (dir << 3) |
+				(radio->registers[SRCHCTRL] & 0xF7);
+
+	FMDBG("SRCHCTRL <%x>\n", radio->registers[SRCHCTRL]);
+	FMDBG("Search Started\n");
+	return tavarua_write_registers(radio, SRCHRDS1,
+				&radio->registers[SRCHRDS1], 3);
+}
+
+/*=============================================================================
+FUNCTION:  tavarua_set_region
+=============================================================================*/
+/**
+  This interface configures the FM radio.
+
+  @param radio: structure pointer passed by client.
+  @param req_region: FM band types.  These types defines the FM band minimum and
+  maximum frequencies in the FM band.
+
+  @return => 0 if successful.
+  @return < 0 if failure.
+*/
+static int tavarua_set_region(struct tavarua_device *radio,
+				int req_region)
+{
+	int retval = 0;
+	unsigned char xfr_buf[XFR_REG_NUM];
+	unsigned char value;
+	unsigned int spacing = 0.100 * FREQ_MUL;
+	unsigned int band_low, band_high;
+	unsigned int low_band_limit = 76.0 * FREQ_MUL;
+	enum tavarua_region_t region = req_region;
+
+	/* Set freq band */
+	switch (region) {
+	case TAVARUA_REGION_US:
+	case TAVARUA_REGION_EU:
+	case TAVARUA_REGION_JAPAN_WIDE:
+		SET_REG_FIELD(radio->registers[RDCTRL], 0,
+			RDCTRL_BAND_OFFSET, RDCTRL_BAND_MASK);
+		break;
+	case TAVARUA_REGION_JAPAN:
+		SET_REG_FIELD(radio->registers[RDCTRL], 1,
+			RDCTRL_BAND_OFFSET, RDCTRL_BAND_MASK);
+		break;
+	default:
+		retval = sync_read_xfr(radio, RADIO_CONFIG, xfr_buf);
+		if (retval < 0) {
+			FMDERR("failed to get RADIO_CONFIG\n");
+			return retval;
+		}
+		band_low = (radio->region_params.band_low -
+					low_band_limit) / spacing;
+		band_high = (radio->region_params.band_high -
+					low_band_limit) / spacing;
+		FMDBG("low_band: %x, high_band: %x\n", band_low, band_high);
+		xfr_buf[0] = band_low >> 8;
+		xfr_buf[1] = band_low & 0xFF;
+		xfr_buf[2] = band_high >> 8;
+		xfr_buf[3] = band_high & 0xFF;
+		retval = sync_write_xfr(radio, RADIO_CONFIG, xfr_buf);
+		if (retval < 0) {
+			FMDERR("Could not set regional settings\n");
+			return retval;
+		}
+		break;
+	}
+
+	/* Set channel spacing */
+	switch (region) {
+	case TAVARUA_REGION_US:
+	case TAVARUA_REGION_EU:
+		value = 0;
+		break;
+	case TAVARUA_REGION_JAPAN:
+		value = 1;
+		break;
+	case TAVARUA_REGION_JAPAN_WIDE:
+		value = 2;
+		break;
+	default:
+		value = radio->region_params.spacing;
+	}
+
+	SET_REG_FIELD(radio->registers[RDCTRL], value,
+		RDCTRL_CHSPACE_OFFSET, RDCTRL_CHSPACE_MASK);
+
+	/* Set De-emphasis and soft band range*/
+	switch (region) {
+	case TAVARUA_REGION_US:
+	case TAVARUA_REGION_JAPAN:
+	case TAVARUA_REGION_JAPAN_WIDE:
+		value = 0;
+		break;
+	case TAVARUA_REGION_EU:
+		value = 1;
+		break;
+	default:
+		value = radio->region_params.emphasis;
+	}
+
+	SET_REG_FIELD(radio->registers[RDCTRL], value,
+		RDCTRL_DEEMPHASIS_OFFSET, RDCTRL_DEEMPHASIS_MASK);
+
+	/* set RDS standard */
+	switch (region) {
+	default:
+		value = radio->region_params.rds_std;
+		break;
+	case TAVARUA_REGION_US:
+		value = 0;
+		break;
+	case TAVARUA_REGION_EU:
+		value = 1;
+		break;
+	}
+	SET_REG_FIELD(radio->registers[RDSCTRL], value,
+		RDSCTRL_STANDARD_OFFSET, RDSCTRL_STANDARD_MASK);
+
+	FMDBG("RDSCTRLL %x\n", radio->registers[RDSCTRL]);
+	retval = tavarua_write_register(radio, RDSCTRL,
+					radio->registers[RDSCTRL]);
+	if (retval < 0)
+		return retval;
+
+	FMDBG("RDCTRL: %x\n", radio->registers[RDCTRL]);
+	retval = tavarua_write_register(radio, RDCTRL,
+					radio->registers[RDCTRL]);
+	if (retval < 0) {
+		FMDERR("Could not set region in rdctrl\n");
+		return retval;
+	}
+
+	/* setting soft band */
+	switch (region) {
+	case TAVARUA_REGION_US:
+	case TAVARUA_REGION_EU:
+		radio->region_params.band_low = 87.5 * FREQ_MUL;
+		radio->region_params.band_high = 108 * FREQ_MUL;
+		break;
+	case TAVARUA_REGION_JAPAN:
+		radio->region_params.band_low = 76 * FREQ_MUL;
+		radio->region_params.band_high = 90 * FREQ_MUL;
+		break;
+	case TAVARUA_REGION_JAPAN_WIDE:
+		radio->region_params.band_low = 90 * FREQ_MUL;
+		radio->region_params.band_high = 108 * FREQ_MUL;
+		break;
+	default:
+		break;
+	}
+	radio->region_params.region = region;
+	return retval;
+}
+
+/*=============================================================================
+FUNCTION:  tavarua_get_freq
+=============================================================================*/
+/**
+  This interface gets the current frequency.
+
+  @param radio: structure pointer passed by client.
+  @param freq: struct v4l2_frequency. This will be set to the resultant
+  frequency in units of 62.5 kHz on success.
+
+  NOTE:
+  To get the current tuner or modulator radio frequency applications set the
+  tuner field of a struct v4l2_frequency to the respective tuner or modulator
+  number (only input devices have tuners, only output devices have modulators),
+  zero out the reserved array and call the VIDIOC_G_FREQUENCY ioctl with a
+  pointer to this structure. The driver stores the current frequency in the
+  frequency field.
+
+  Tuning frequency is in units of 62.5 kHz, or if the struct v4l2_tuner or
+  struct v4l2_modulator capabilities flag V4L2_TUNER_CAP_LOW is set, in
+  units of 62.5 Hz.
+
+  @return => 0 if successful.
+  @return < 0 if failure.
+*/
+static int tavarua_get_freq(struct tavarua_device *radio,
+				struct v4l2_frequency *freq)
+{
+	int retval;
+	unsigned short chan;
+	unsigned int band_bottom;
+	unsigned int spacing;
+	band_bottom = radio->region_params.band_low;
+	spacing  = 0.100 * FREQ_MUL;
+	/* read channel */
+	retval = tavarua_read_registers(radio, FREQ, 2);
+	chan = radio->registers[FREQ];
+
+	/* Frequency (MHz) = 100 (kHz) x Channel + Bottom of Band (MHz) */
+	freq->frequency = spacing * chan + band_bottom;
+	if (radio->registers[TUNECTRL] & ADD_OFFSET)
+		freq->frequency += 800;
+	return retval;
+}
+
+/*=============================================================================
+FUNCTION:  tavarua_set_freq
+=============================================================================*/
+/**
+  This interface sets the current frequency.
+
+  @param radio: structure pointer passed by client.
+  @param freq: desired frequency sent by the client in 62.5 kHz units.
+
+  NOTE:
+  To change the current tuner or modulator radio frequency, applications
+  initialize the tuner, type and frequency fields, and the reserved array of a
+  struct v4l2_frequency and call the VIDIOC_S_FREQUENCY ioctl with a pointer to
+  this structure. When the requested frequency is not possible the driver
+  assumes the closest possible value. However VIDIOC_S_FREQUENCY is a
+  write-only ioctl, it does not return the actual new frequency.
+
+  Tuning frequency is in units of 62.5 kHz, or if the struct v4l2_tuner
+  or struct v4l2_modulator capabilities flag V4L2_TUNER_CAP_LOW is set,
+  in units of 62.5 Hz.
+
+  @return => 0 if successful.
+  @return < 0 if failure.
+*/
+static int tavarua_set_freq(struct tavarua_device *radio, unsigned int freq)
+{
+
+	unsigned int band_bottom;
+	unsigned char chan;
+	unsigned char cmd[] = {0x00, 0x00};
+	unsigned int spacing;
+	int retval;
+	band_bottom = radio->region_params.band_low;
+	spacing  = 0.100 * FREQ_MUL;
+	if ((freq % 1600) == 800) {
+		cmd[1] = ADD_OFFSET;
+		freq -= 800;
+	}
+	/* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / 100 (kHz) */
+	chan = (freq - band_bottom) / spacing;
+
+	cmd[0] = chan;
+	cmd[1] |= TUNE_STATION;
+	radio->tune_req = 1;
+	retval = tavarua_write_registers(radio, FREQ, cmd, 2);
+	if (retval < 0)
+		radio->tune_req = 0;
+	return retval;
+
+}
+
+/**************************************************************************
+ * File Operations Interface
+ *************************************************************************/
+
+/*=============================================================================
+FUNCTION:  tavarua_fops_read
+=============================================================================*/
+/**
+  This function is called when a process, which already opened the dev file,
+  attempts to read from it.
+
+  In case of tavarua driver, it is called to read RDS data.
+
+  @param file: file descriptor.
+	@param buf: The buffer to fill with data.
+	@param count: The length of the buffer in bytes.
+	@param ppos: Our offset in the file.
+
+  @return The number of bytes put into the buffer on sucess.
+	-EFAULT if there is no access to user buffer
+*/
+static ssize_t tavarua_fops_read(struct file *file, char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
+	struct kfifo *rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
+
+	/* block if no new data available */
+	while (!kfifo_len(rds_buf)) {
+		if (file->f_flags & O_NONBLOCK)
+			return -EWOULDBLOCK;
+		if (wait_event_interruptible(radio->read_queue,
+			kfifo_len(rds_buf)) < 0)
+			return -EINTR;
+	}
+
+	/* calculate block count from byte count */
+	count /= BYTES_PER_BLOCK;
+
+
+	/* check if we can write to the user buffer */
+	if (!access_ok(VERIFY_WRITE, buf, count*BYTES_PER_BLOCK))
+		return -EFAULT;
+
+	/* copy RDS block out of internal buffer and to user buffer */
+	return kfifo_out_locked(rds_buf, buf, count*BYTES_PER_BLOCK,
+				&radio->buf_lock[TAVARUA_BUF_RAW_RDS]);
+}
+
+/*=============================================================================
+FUNCTION:  tavarua_fops_write
+=============================================================================*/
+/**
+  This function is called when a process, which already opened the dev file,
+  attempts to write to it.
+
+  In case of tavarua driver, it is called to write RDS data to host.
+
+  @param file: file descriptor.
+	@param buf: The buffer which has data to write.
+	@param count: The length of the buffer.
+	@param ppos: Our offset in the file.
+
+  @return The number of bytes written from the buffer.
+*/
+static ssize_t tavarua_fops_write(struct file *file, const char __user *data,
+			size_t count, loff_t *ppos)
+{
+	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
+	int retval = 0;
+	int bytes_to_copy;
+	int bytes_copied = 0;
+	int bytes_left;
+	int chunk_index = 0;
+	unsigned char tx_data[XFR_REG_NUM];
+	/* Disable TX of this type first */
+	switch (radio->tx_mode) {
+	case TAVARUA_TX_RT:
+		bytes_left = min((int)count, MAX_RT_LENGTH);
+		tx_data[1] = 0;
+		break;
+	case TAVARUA_TX_PS:
+		bytes_left = min((int)count, MAX_PS_LENGTH);
+		tx_data[4] = 0;
+		break;
+	default:
+		FMDERR("%s: Unknown TX mode\n", __func__);
+		return -1;
+	}
+	retval = sync_write_xfr(radio, radio->tx_mode, tx_data);
+	if (retval < 0)
+		return retval;
+
+	/* send payload to FM hardware */
+	while (bytes_left) {
+		chunk_index++;
+		bytes_to_copy = min(bytes_left, XFR_REG_NUM);
+		if (copy_from_user(tx_data, data + bytes_copied, bytes_to_copy))
+			return -EFAULT;
+		retval = sync_write_xfr(radio, radio->tx_mode +
+						chunk_index, tx_data);
+		if (retval < 0)
+			return retval;
+
+		bytes_copied += bytes_to_copy;
+		bytes_left -= bytes_to_copy;
+	}
+
+	/* send the header */
+	switch (radio->tx_mode) {
+	case TAVARUA_TX_RT:
+		FMDBG("Writing RT header\n");
+		tx_data[0] = bytes_copied;
+		tx_data[1] = TX_ON | 0x03; /* on | PTY */
+		tx_data[2] = 0x12; /* PI high */
+		tx_data[3] = 0x34; /* PI low */
+		break;
+	case TAVARUA_TX_PS:
+		FMDBG("Writing PS header\n");
+		tx_data[0] = chunk_index;
+		tx_data[1] = 0x03; /* PTY */
+		tx_data[2] = 0x12; /* PI high */
+		tx_data[3] = 0x34; /* PI low */
+		tx_data[4] = TX_ON | 0x01;
+		break;
+	default:
+		FMDERR("%s: Unknown TX mode\n", __func__);
+		return -1;
+	}
+	retval = sync_write_xfr(radio, radio->tx_mode, tx_data);
+	if (retval < 0)
+		return retval;
+	FMDBG("done writing: %d\n", retval);
+	return bytes_copied;
+}
+
+/*=============================================================================
+FUNCTION:  tavarua_fops_open
+=============================================================================*/
+/**
+  This function is called when a process tries to open the device file, like
+	"cat /dev/mycharfile"
+
+  @param file: file descriptor.
+
+  @return => 0 if successful.
+  @return < 0 if failure.
+*/
+static int tavarua_fops_open(struct file *file)
+{
+	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
+	int retval = -ENODEV;
+	unsigned char value;
+	/* FM core bring up */
+	int i = 0;
+	char fm_ctl0_part1[] = { 0xCA, 0xCE, 0xD6 };
+	char fm_ctl1[] = { 0x03 };
+	char fm_ctl0_part2[] = { 0xB6, 0xB7 };
+	char buffer[] = {0x00, 0x48, 0x8A, 0x8E, 0x97, 0xB7};
+	int bahama_present = -ENODEV;
+
+	mutex_lock(&radio->lock);
+	if (radio->users) {
+		mutex_unlock(&radio->lock);
+		return -EBUSY;
+	} else {
+		radio->users++;
+	}
+	mutex_unlock(&radio->lock);
+
+	/* initial gpio pin config & Power up */
+	retval = radio->pdata->fm_setup(radio->pdata);
+	if (retval) {
+		printk(KERN_ERR "%s: failed config gpio & pmic\n", __func__);
+		goto open_err_setup;
+	}
+	if (radio->pdata->config_i2s_gpio != NULL) {
+		retval = radio->pdata->config_i2s_gpio(FM_I2S_ON);
+		if (retval) {
+			printk(KERN_ERR "%s: failed config gpio\n", __func__);
+			goto config_i2s_err;
+		}
+	}
+	/* enable irq */
+	retval = tavarua_request_irq(radio);
+	if (retval < 0) {
+		printk(KERN_ERR "%s: failed to request irq\n", __func__);
+		goto open_err_req_irq;
+	}
+	/* call top level marimba interface here to enable FM core */
+	FMDBG("initializing SoC\n");
+
+	bahama_present = is_bahama();
+
+	if (bahama_present == -ENODEV)
+		return -ENODEV;
+
+	if (bahama_present)
+		radio->marimba->mod_id = SLAVE_ID_BAHAMA;
+	else
+		radio->marimba->mod_id = MARIMBA_SLAVE_ID_MARIMBA;
+
+	value = FM_ENABLE;
+	retval = marimba_write_bit_mask(radio->marimba,
+			MARIMBA_XO_BUFF_CNTRL, &value, 1, value);
+	if (retval < 0) {
+		printk(KERN_ERR "%s:XO_BUFF_CNTRL write failed\n",
+					__func__);
+		goto open_err_all;
+	}
+
+
+	/* Bring up FM core */
+	if (bahama_present)	{
+
+		radio->marimba->mod_id = SLAVE_ID_BAHAMA;
+		/* Read the Bahama version*/
+		retval = marimba_read_bit_mask(radio->marimba,
+				0x00,  &bahama_version, 1, 0x1F);
+		if (retval < 0) {
+			printk(KERN_ERR "%s: version read failed",
+				__func__);
+			goto open_err_all;
+		}
+		/* Check for Bahama V2 variant*/
+		if (bahama_version == 0x09)	{
+
+			/* In case of Bahama v2, forcefully enable the
+			 * internal analog and digital voltage controllers
+			 */
+			value = 0x06;
+			/* value itself used as mask in these writes*/
+			retval = marimba_write_bit_mask(radio->marimba,
+			BAHAMA_LDO_DREG_CTL0, &value, 1, value);
+			if (retval < 0) {
+				printk(KERN_ERR "%s:0xF0 write failed\n",
+					__func__);
+				goto open_err_all;
+			}
+			value = 0x86;
+			retval = marimba_write_bit_mask(radio->marimba,
+				BAHAMA_LDO_AREG_CTL0, &value, 1, value);
+			if (retval < 0) {
+				printk(KERN_ERR "%s:0xF4 write failed\n",
+					__func__);
+				goto open_err_all;
+			}
+		}
+
+		/*write FM mode*/
+		retval = tavarua_write_register(radio, BAHAMA_FM_MODE_REG,
+					BAHAMA_FM_MODE_NORMAL);
+		if (retval < 0) {
+			printk(KERN_ERR "failed to set the FM mode: %d\n",
+					retval);
+			goto open_err_all;
+		}
+		/*Write first sequence of bytes to FM_CTL0*/
+		for (i = 0; i < 3; i++)  {
+			retval = tavarua_write_register(radio,
+					BAHAMA_FM_CTL0_REG, fm_ctl0_part1[i]);
+			if (retval < 0) {
+				printk(KERN_ERR "FM_CTL0:set-1 failure: %d\n",
+							retval);
+				goto open_err_all;
+			}
+		}
+		/*Write the FM_CTL1 sequence*/
+		for (i = 0; i < 1; i++)  {
+			retval = tavarua_write_register(radio,
+					BAHAMA_FM_CTL1_REG, fm_ctl1[i]);
+			if (retval < 0) {
+				printk(KERN_ERR "FM_CTL1 write failure: %d\n",
+							retval);
+				goto open_err_all;
+			}
+		}
+		/*Write second sequence of bytes to FM_CTL0*/
+		for (i = 0; i < 2; i++)  {
+			retval = tavarua_write_register(radio,
+					BAHAMA_FM_CTL0_REG, fm_ctl0_part2[i]);
+			if (retval < 0) {
+				printk(KERN_ERR "FM_CTL0:set-2 failure: %d\n",
+					retval);
+			goto open_err_all;
+			}
+		}
+	} else {
+		retval = tavarua_write_registers(radio, LEAKAGE_CNTRL,
+						buffer, 6);
+		if (retval < 0) {
+			printk(KERN_ERR "%s: failed to bring up FM Core\n",
+						__func__);
+			goto open_err_all;
+		}
+	}
+	/* Wait for interrupt i.e. complete(&radio->sync_req_done); call */
+	/*Initialize the completion variable for
+	for the proper behavior*/
+	init_completion(&radio->sync_req_done);
+	if (!wait_for_completion_timeout(&radio->sync_req_done,
+		msecs_to_jiffies(wait_timeout))) {
+		retval = -1;
+		FMDERR("Timeout waiting for initialization\n");
+	}
+
+	/* get Chip ID */
+	retval = tavarua_write_register(radio, XFRCTRL, CHIPID);
+	if (retval < 0)
+		goto open_err_all;
+	msleep(TAVARUA_DELAY);
+	tavarua_read_registers(radio, XFRCTRL, XFR_REG_NUM+1);
+	if (radio->registers[XFRCTRL] != CHIPID)
+		goto open_err_all;
+
+	radio->chipID = (radio->registers[XFRCTRL+2] << 24) |
+			(radio->registers[XFRCTRL+5] << 16) |
+			(radio->registers[XFRCTRL+6] << 8)  |
+			(radio->registers[XFRCTRL+7]);
+
+	printk(KERN_WARNING DRIVER_NAME ": Chip ID %x\n", radio->chipID);
+	if (radio->chipID == MARIMBA_A0) {
+		printk(KERN_WARNING DRIVER_NAME ": Unsupported hardware: %x\n",
+						radio->chipID);
+		retval = -1;
+		goto open_err_all;
+	}
+
+	radio->handle_irq = 0;
+	radio->marimba->mod_id = SLAVE_ID_BAHAMA;
+	marimba_set_fm_status(radio->marimba, true);
+	return 0;
+
+
+open_err_all:
+    /*Disable FM in case of error*/
+	value = 0x00;
+	marimba_write_bit_mask(radio->marimba, MARIMBA_XO_BUFF_CNTRL,
+							&value, 1, value);
+	tavarua_disable_irq(radio);
+open_err_req_irq:
+	if (radio->pdata->config_i2s_gpio != NULL)
+		radio->pdata->config_i2s_gpio(FM_I2S_OFF);
+config_i2s_err:
+	radio->pdata->fm_shutdown(radio->pdata);
+open_err_setup:
+	radio->handle_irq = 1;
+	radio->users = 0;
+	return retval;
+}
+
+/*=============================================================================
+FUNCTION:  tavarua_fops_release
+=============================================================================*/
+/**
+  This function is called when a process closes the device file.
+
+  @param file: file descriptor.
+
+  @return => 0 if successful.
+  @return < 0 if failure.
+*/
+static int tavarua_fops_release(struct file *file)
+{
+	int retval;
+	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
+	unsigned char value;
+	int i = 0;
+	/*FM Core shutdown sequence for Bahama*/
+	char fm_ctl0_part1[] = { 0xB7 };
+	char fm_ctl1[] = { 0x03 };
+	char fm_ctl0_part2[] = { 0x9F, 0x48, 0x02 };
+	int bahama_present = -ENODEV;
+	/*FM Core shutdown sequence for Marimba*/
+	char buffer[] = {0x18, 0xB7, 0x48};
+	bool bt_status = false;
+	int index;
+	/* internal regulator controllers DREG_CTL0, AREG_CTL0
+	 * has to be kept in the valid state based on the bt status.
+	 * 1st row is the state when no clients are active,
+	 * and the second when bt is in on state.
+	 */
+	char internal_vreg_ctl[2][2] = {
+		{ 0x04, 0x84 },
+		{ 0x00, 0x80 }
+	};
+
+	if (!radio)
+		return -ENODEV;
+	FMDBG("In %s", __func__);
+
+	/* disable radio ctrl */
+	retval = tavarua_write_register(radio, RDCTRL, 0x00);
+
+	FMDBG("%s, Disable IRQs\n", __func__);
+	/* disable irq */
+	retval = tavarua_disable_irq(radio);
+	if (retval < 0) {
+		printk(KERN_ERR "%s: failed to disable irq\n", __func__);
+		return retval;
+	}
+
+	bahama_present = is_bahama();
+
+	if (bahama_present == -ENODEV)
+		return -ENODEV;
+
+	if (bahama_present)	{
+		/*Write first sequence of bytes to FM_CTL0*/
+		for (i = 0; i < 1; i++) {
+			retval = tavarua_write_register(radio,
+					BAHAMA_FM_CTL0_REG, fm_ctl0_part1[i]);
+			if (retval < 0) {
+				printk(KERN_ERR "FM_CTL0:Set-1 failure: %d\n",
+						retval);
+				break;
+			}
+		}
+		/*Write the FM_CTL1 sequence*/
+		for (i = 0; i < 1; i++)  {
+			retval = tavarua_write_register(radio,
+					BAHAMA_FM_CTL1_REG, fm_ctl1[i]);
+			if (retval < 0) {
+				printk(KERN_ERR "FM_CTL1 failure: %d\n",
+						retval);
+				break;
+			}
+		}
+		/*Write second sequence of bytes to FM_CTL0*/
+		for (i = 0; i < 3; i++)   {
+			retval = tavarua_write_register(radio,
+					BAHAMA_FM_CTL0_REG, fm_ctl0_part2[i]);
+			if (retval < 0) {
+				printk(KERN_ERR "FM_CTL0:Set-2 failure: %d\n",
+						retval);
+			break;
+			}
+		}
+	}	else	{
+
+		retval = tavarua_write_registers(radio, FM_CTL0,
+				buffer, sizeof(buffer)/sizeof(buffer[0]));
+		if (retval < 0) {
+			printk(KERN_ERR "%s: failed to bring down the  FM Core\n",
+							__func__);
+			return retval;
+		}
+	}
+	radio->marimba->mod_id = SLAVE_ID_BAHAMA;
+	bt_status = marimba_get_bt_status(radio->marimba);
+	/* Set the index based on the bt status*/
+	index = bt_status ?  1 : 0;
+	/* Check for Bahama's existance and Bahama V2 variant*/
+	if (bahama_present && (bahama_version == 0x09))   {
+		radio->marimba->mod_id = SLAVE_ID_BAHAMA;
+		/* actual value itself used as mask*/
+		retval = marimba_write_bit_mask(radio->marimba,
+			BAHAMA_LDO_DREG_CTL0, &internal_vreg_ctl[bt_status][0],
+			 1, internal_vreg_ctl[index][0]);
+		if (retval < 0) {
+			printk(KERN_ERR "%s:0xF0 write failed\n", __func__);
+			return retval;
+		}
+		/* actual value itself used as mask*/
+		retval = marimba_write_bit_mask(radio->marimba,
+			BAHAMA_LDO_AREG_CTL0, &internal_vreg_ctl[bt_status][1],
+			1, internal_vreg_ctl[index][1]);
+		if (retval < 0) {
+			printk(KERN_ERR "%s:0xF4 write failed\n", __func__);
+			return retval;
+		}
+	} else    {
+		/* disable fm core */
+		radio->marimba->mod_id = MARIMBA_SLAVE_ID_MARIMBA;
+	}
+
+	value = 0x00;
+	retval = marimba_write_bit_mask(radio->marimba, MARIMBA_XO_BUFF_CNTRL,
+							&value, 1, FM_ENABLE);
+	if (retval < 0) {
+		printk(KERN_ERR "%s:XO_BUFF_CNTRL write failed\n", __func__);
+		return retval;
+	}
+	FMDBG("%s, Calling fm_shutdown\n", __func__);
+	/* teardown gpio and pmic */
+	radio->pdata->fm_shutdown(radio->pdata);
+	if (radio->pdata->config_i2s_gpio != NULL)
+		radio->pdata->config_i2s_gpio(FM_I2S_OFF);
+	radio->handle_irq = 1;
+	radio->users = 0;
+	radio->marimba->mod_id = SLAVE_ID_BAHAMA;
+	marimba_set_fm_status(radio->marimba, false);
+	return 0;
+}
+
+/*
+ * tavarua_fops - file operations interface
+ */
+static const struct v4l2_file_operations tavarua_fops = {
+	.owner = THIS_MODULE,
+	.read = tavarua_fops_read,
+	.write = tavarua_fops_write,
+	.ioctl = video_ioctl2,
+	.open  = tavarua_fops_open,
+	.release = tavarua_fops_release,
+};
+
+/*************************************************************************
+ * Video4Linux Interface
+ *************************************************************************/
+
+/*
+ * tavarua_v4l2_queryctrl - query control
+ */
+static struct v4l2_queryctrl tavarua_v4l2_queryctrl[] = {
+	{
+		.id	       = V4L2_CID_AUDIO_VOLUME,
+		.type	       = V4L2_CTRL_TYPE_INTEGER,
+		.name	       = "Volume",
+		.minimum       = 0,
+		.maximum       = 15,
+		.step	       = 1,
+		.default_value = 15,
+	},
+	{
+		.id	       = V4L2_CID_AUDIO_BALANCE,
+		.flags	       = V4L2_CTRL_FLAG_DISABLED,
+	},
+	{
+		.id	       = V4L2_CID_AUDIO_BASS,
+		.flags	       = V4L2_CTRL_FLAG_DISABLED,
+	},
+	{
+		.id	       = V4L2_CID_AUDIO_TREBLE,
+		.flags	       = V4L2_CTRL_FLAG_DISABLED,
+	},
+	{
+		.id	       = V4L2_CID_AUDIO_MUTE,
+		.type	       = V4L2_CTRL_TYPE_BOOLEAN,
+		.name	       = "Mute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.step	       = 1,
+		.default_value = 1,
+	},
+	{
+		.id	       = V4L2_CID_AUDIO_LOUDNESS,
+		.flags	       = V4L2_CTRL_FLAG_DISABLED,
+	},
+	{
+		.id	       = V4L2_CID_PRIVATE_TAVARUA_SRCHMODE,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name	       = "Search mode",
+		.minimum       = 0,
+		.maximum       = 7,
+		.step	       = 1,
+		.default_value = 0,
+	},
+	{
+		.id            = V4L2_CID_PRIVATE_TAVARUA_SCANDWELL,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Search dwell time",
+		.minimum       = 0,
+		.maximum       = 7,
+		.step          = 1,
+		.default_value = 0,
+	},
+	{
+		.id            = V4L2_CID_PRIVATE_TAVARUA_SRCHON,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+		.name          = "Search on/off",
+		.minimum       = 0,
+		.maximum       = 1,
+		.step          = 1,
+		.default_value = 1,
+
+	},
+	{
+		.id            = V4L2_CID_PRIVATE_TAVARUA_STATE,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "radio 0ff/rx/tx/reset",
+		.minimum       = 0,
+		.maximum       = 3,
+		.step          = 1,
+		.default_value = 1,
+
+	},
+	{
+		.id            = V4L2_CID_PRIVATE_TAVARUA_REGION,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "radio standard",
+		.minimum       = 0,
+		.maximum       = 2,
+		.step          = 1,
+		.default_value = 0,
+	},
+	{
+		.id            = V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Signal Threshold",
+		.minimum       = 0x80,
+		.maximum       = 0x7F,
+		.step          = 1,
+		.default_value = 0,
+	},
+	{
+		.id            = V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Search PTY",
+		.minimum       = 0,
+		.maximum       = 31,
+		.default_value = 0,
+	},
+	{
+		.id            = V4L2_CID_PRIVATE_TAVARUA_SRCH_PI,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Search PI",
+		.minimum       = 0,
+		.maximum       = 0xFF,
+		.default_value = 0,
+	},
+	{
+		.id            = V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Preset num",
+		.minimum       = 0,
+		.maximum       = 12,
+		.default_value = 0,
+	},
+	{
+		.id            = V4L2_CID_PRIVATE_TAVARUA_EMPHASIS,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+		.name          = "Emphasis",
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 0,
+	},
+	{
+		.id            = V4L2_CID_PRIVATE_TAVARUA_RDS_STD,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+		.name          = "RDS standard",
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 0,
+	},
+	{
+		.id            = V4L2_CID_PRIVATE_TAVARUA_SPACING,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Channel spacing",
+		.minimum       = 0,
+		.maximum       = 2,
+		.default_value = 0,
+	},
+	{
+		.id            = V4L2_CID_PRIVATE_TAVARUA_RDSON,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+		.name          = "RDS on/off",
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 0,
+	},
+	{
+		.id            = V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "RDS group mask",
+		.minimum       = 0,
+		.maximum       = 0xFFFFFFFF,
+		.default_value = 0,
+	},
+	{
+		.id            = V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "RDS processing",
+		.minimum       = 0,
+		.maximum       = 0xFF,
+		.default_value = 0,
+	},
+	{
+		.id            = V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "RDS data groups to buffer",
+		.minimum       = 1,
+		.maximum       = 21,
+		.default_value = 0,
+	},
+	{
+		.id            = V4L2_CID_PRIVATE_TAVARUA_PSALL,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+		.name          = "pass all ps strings",
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 0,
+	},
+	{
+		.id            = V4L2_CID_PRIVATE_TAVARUA_LP_MODE,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+		.name          = "Low power mode",
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 0,
+	},
+	{
+		.id            = V4L2_CID_PRIVATE_TAVARUA_ANTENNA,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+		.name          = "headset/internal",
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 0,
+	},
+	/* Private controls for FM TX*/
+	{
+		.id            = V4L2_CID_PRIVATE_TAVARUA_TX_SETPSREPEATCOUNT,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Set PS REPEATCOUNT",
+		.minimum       = 0,
+		.maximum       = 15,
+	},
+	{
+		.id            = V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_PS_NAME,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+		.name          = "Stop PS NAME",
+		.minimum       = 0,
+		.maximum       = 1,
+	},
+	{
+		.id            = V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_RT,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+		.name          = "Stop RT",
+		.minimum       = 0,
+		.maximum       = 1,
+	},
+
+};
+
+/*=============================================================================
+FUNCTION:  tavarua_vidioc_querycap
+=============================================================================*/
+/**
+  This function is called to query device capabilities.
+
+  NOTE:
+  All V4L2 devices support the VIDIOC_QUERYCAP ioctl. It is used to identify
+  kernel devices compatible with this specification and to obtain information
+  about driver and hardware capabilities. The ioctl takes a pointer to a struct
+  v4l2_capability which is filled by the driver. When the driver is not
+  compatible with this specification the ioctl returns an EINVAL error code.
+
+  @param file: File descriptor returned by open().
+  @param capability: pointer to struct v4l2_capability.
+
+  @return On success 0 is returned, else error code.
+  @return EINVAL: The device is not compatible with this specification.
+*/
+static int tavarua_vidioc_querycap(struct file *file, void *priv,
+		struct v4l2_capability *capability)
+{
+	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
+
+	strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
+	strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
+	sprintf(capability->bus_info, "I2C");
+	capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+
+	capability->version = radio->chipID;
+
+	return 0;
+}
+
+/*=============================================================================
+FUNCTION:  tavarua_vidioc_queryctrl
+=============================================================================*/
+/**
+  This function is called to query the device and driver for supported video
+  controls (enumerate control items).
+
+  NOTE:
+  To query the attributes of a control, the applications set the id field of
+  a struct v4l2_queryctrl and call the VIDIOC_QUERYCTRL ioctl with a pointer
+  to this structure. The driver fills the rest of the structure or returns an
+  EINVAL error code when the id is invalid.
+
+  @param file: File descriptor returned by open().
+  @param qc: pointer to struct v4l2_queryctrl.
+
+  @return On success 0 is returned, else error code.
+  @return EINVAL: The struct v4l2_queryctrl id is invalid.
+*/
+static int tavarua_vidioc_queryctrl(struct file *file, void *priv,
+		struct v4l2_queryctrl *qc)
+{
+	unsigned char i;
+	int retval = -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(tavarua_v4l2_queryctrl); i++) {
+		if (qc->id && qc->id == tavarua_v4l2_queryctrl[i].id) {
+			memcpy(qc, &(tavarua_v4l2_queryctrl[i]), sizeof(*qc));
+			retval = 0;
+			break;
+		}
+	}
+	if (retval < 0)
+		printk(KERN_WARNING DRIVER_NAME
+			": query conv4ltrol failed with %d\n", retval);
+
+	return retval;
+}
+static int peek_MPX_DCC(struct tavarua_device *radio)
+{
+	int retval = 0;
+	unsigned char xfr_buf[XFR_REG_NUM];
+	int MPX_DCC[] = { 0 };
+	int DCC = 0;
+	int ct = 0;
+	unsigned char size = 0;
+
+	/*
+	Poking the MPX_DCC_BYPASS register to freeze the
+	value of MPX_DCC from changing while we access it
+	*/
+
+	/*Poking the MPX_DCC_BYPASS register : 0x88C0 */
+	size = 0x01;
+	xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
+	xfr_buf[1] = MPX_DCC_BYPASS_POKE_MSB;
+	xfr_buf[2] = MPX_DCC_BYPASS_POKE_LSB;
+	xfr_buf[3] = 0x01;
+
+	retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 4);
+	if (retval < 0) {
+		FMDBG("Failed to write\n");
+		return retval;
+	}
+	/*Wait for the XFR interrupt */
+	msleep(TAVARUA_DELAY*15);
+
+	for (ct = 0; ct < 5; ct++)
+		xfr_buf[ct] = 0;
+
+	/* Peeking Regs 0x88C2-0x88C4 */
+	size = 0x03;
+	xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
+	xfr_buf[1] = MPX_DCC_PEEK_MSB_REG1;
+	xfr_buf[2] = MPX_DCC_PEEK_LSB_REG1;
+	retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
+	if (retval < 0) {
+		FMDBG("Failed to write\n");
+		return retval;
+	}
+	/*Wait for the XFR interrupt */
+	msleep(TAVARUA_DELAY*10);
+	retval = tavarua_read_registers(radio, XFRDAT0, 3);
+	if (retval < 0) {
+		printk(KERN_INFO "INT_DET: Read failure\n");
+		return retval;
+	}
+	MPX_DCC[0] = (int)radio->registers[XFRDAT0];
+	MPX_DCC[1] = (int)radio->registers[XFRDAT1];
+	MPX_DCC[2] = (int)radio->registers[XFRDAT2];
+
+	/*
+	Form the final MPX_DCC parameter
+	MPX_DCC[0] will form the LSB part
+	MPX_DCC[1] will be the middle part and 4 bits of
+	MPX_DCC[2] will be the MSB par of the 20-bit signed MPX_DCC
+	*/
+
+	DCC = ((int)MPX_DCC[2] << 16) | ((int)MPX_DCC[1] << 8) |
+		((int)MPX_DCC[0]);
+
+	/*
+	if bit-19 is '1',set remaining bits to '1' &  make it -tive
+	*/
+	if (DCC & 0x00080000) {
+		FMDBG(KERN_INFO "bit-19 is '1'\n");
+		DCC |= 0xFFF00000;
+	}
+
+	/*
+	Poking the MPX_DCC_BYPASS register to be back to normal
+	*/
+
+	/*Poking the MPX_DCC_BYPASS register : 0x88C0 */
+	size = 0x01;
+	xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
+	xfr_buf[1] = MPX_DCC_BYPASS_POKE_MSB;
+	xfr_buf[2] = MPX_DCC_BYPASS_POKE_LSB;
+	xfr_buf[3] = 0x00;
+
+	retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 4);
+	if (retval < 0) {
+		FMDBG("Failed to write\n");
+		return retval;
+	}
+	/*Wait for the XFR interrupt */
+	msleep(TAVARUA_DELAY*10);
+
+	return DCC;
+}
+/*=============================================================================
+FUNCTION:  tavarua_vidioc_g_ctrl
+=============================================================================*/
+/**
+  This function is called to get the value of a control.
+
+  NOTE:
+  To get the current value of a control, applications initialize the id field
+  of a struct v4l2_control and call the VIDIOC_G_CTRL ioctl with a pointer to
+  this structure.
+
+  When the id is invalid drivers return an EINVAL error code. When the value is
+  out of bounds drivers can choose to take the closest valid value or return an
+  ERANGE error code, whatever seems more appropriate.
+
+  @param file: File descriptor returned by open().
+  @param ctrl: pointer to struct v4l2_control.
+
+  @return On success 0 is returned, else error code.
+  @return EINVAL: The struct v4l2_control id is invalid.
+  @return ERANGE: The struct v4l2_control value is out of bounds.
+  @return EBUSY: The control is temporarily not changeable, possibly because
+  another applications took over control of the device function this control
+  belongs to.
+*/
+static int tavarua_vidioc_g_ctrl(struct file *file, void *priv,
+		struct v4l2_control *ctrl)
+{
+	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
+	int retval = 0;
+	unsigned char xfr_buf[XFR_REG_NUM];
+	signed char cRmssiThreshold;
+	signed char ioc;
+	unsigned char size = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_VOLUME:
+		break;
+	case V4L2_CID_AUDIO_MUTE:
+		ctrl->value = radio->registers[IOCTRL] & 0x03 ;
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_SRCHMODE:
+		ctrl->value = radio->registers[SRCHCTRL] & SRCH_MODE;
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_SCANDWELL:
+		ctrl->value = (radio->registers[SRCHCTRL] & SCAN_DWELL) >> 4;
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_SRCHON:
+		ctrl->value = (radio->registers[SRCHCTRL] & SRCH_ON) >> 7 ;
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_STATE:
+		ctrl->value = (radio->registers[RDCTRL] & 0x03);
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_IOVERC:
+		retval = tavarua_read_registers(radio, IOVERC, 1);
+		if (retval < 0)
+			return retval;
+		ioc = radio->registers[IOVERC];
+		ctrl->value = ioc;
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_INTDET:
+		size = 0x1;
+		xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
+		xfr_buf[1] = INTDET_PEEK_MSB;
+		xfr_buf[2] = INTDET_PEEK_LSB;
+		retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
+		if (retval < 0) {
+			FMDBG("Failed to write\n");
+			return retval;
+		}
+		FMDBG("INT_DET:Sync write success\n");
+		/*Wait for the XFR interrupt */
+		msleep(TAVARUA_DELAY*10);
+		/* Read the XFRDAT0 register populated by FM SoC */
+		retval = tavarua_read_registers(radio, XFRDAT0, 3);
+		if (retval < 0) {
+			FMDBG("INT_DET: Read failure\n");
+			return retval;
+		}
+		ctrl->value = radio->registers[XFRDAT0];
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_MPX_DCC:
+		ctrl->value = peek_MPX_DCC(radio);
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_REGION:
+		ctrl->value = radio->region_params.region;
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH:
+		retval = sync_read_xfr(radio, RX_CONFIG, xfr_buf);
+		if (retval < 0) {
+			FMDBG("[G IOCTL=V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH]\n");
+			FMDBG("sync_read_xfr error: [retval=%d]\n", retval);
+			break;
+		}
+		/* Since RMSSI Threshold is signed value */
+		cRmssiThreshold = (signed char)xfr_buf[0];
+		ctrl->value  = cRmssiThreshold;
+		FMDBG("cRmssiThreshold: %d\n", cRmssiThreshold);
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY:
+		ctrl->value = radio->srch_params.srch_pty;
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_SRCH_PI:
+		ctrl->value = radio->srch_params.srch_pi;
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT:
+		ctrl->value = radio->srch_params.preset_num;
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_EMPHASIS:
+		ctrl->value = radio->region_params.emphasis;
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_RDS_STD:
+		ctrl->value = radio->region_params.rds_std;
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_SPACING:
+		ctrl->value = radio->region_params.spacing;
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_RDSON:
+		ctrl->value = radio->registers[RDSCTRL] & RDS_ON;
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK:
+		retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
+		if (retval > -1)
+			ctrl->value =   (xfr_buf[8] << 24) |
+					(xfr_buf[9] << 16) |
+					(xfr_buf[10] << 8) |
+					 xfr_buf[11];
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC:
+		retval = tavarua_read_registers(radio, ADVCTRL, 1);
+		if (retval > -1)
+			ctrl->value = radio->registers[ADVCTRL];
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF:
+		retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
+		if (retval > -1)
+			ctrl->value = xfr_buf[1];
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_PSALL:
+		retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
+		if (retval > -1)
+			ctrl->value = xfr_buf[12] & RDS_CONFIG_PSALL;
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_LP_MODE:
+		ctrl->value = radio->lp_mode;
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_ANTENNA:
+		ctrl->value = GET_REG_FIELD(radio->registers[IOCTRL],
+			IOC_ANTENNA_OFFSET, IOC_ANTENNA_MASK);
+		break;
+	default:
+		retval = -EINVAL;
+	}
+	if (retval < 0)
+		printk(KERN_WARNING DRIVER_NAME
+		": get control failed with %d, id: %d\n", retval, ctrl->id);
+
+	return retval;
+}
+
+static int tavarua_vidioc_s_ext_ctrls(struct file *file, void *priv,
+			struct v4l2_ext_controls *ctrl)
+{
+	int retval = 0;
+	int bytes_to_copy;
+	int bytes_copied = 0;
+	int bytes_left = 0;
+	int chunk_index = 0;
+	char tx_data[XFR_REG_NUM];
+	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
+	char *data = NULL;
+	int extra_name_byte = 0;
+	int name_bytes = 0;
+
+	switch ((ctrl->controls[0]).id)	{
+	case V4L2_CID_RDS_TX_PS_NAME: {
+		FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
+		/*Pass a sample PS string */
+
+		chunk_index = 0;
+		bytes_copied = 0;
+		bytes_left = min((int)(ctrl->controls[0]).size,
+			MAX_PS_LENGTH);
+		data = (ctrl->controls[0]).string;
+
+		/* send payload to FM hardware */
+		while (bytes_left) {
+			chunk_index++;
+			FMDBG("chunk is %d", chunk_index);
+			bytes_to_copy = min(bytes_left, XFR_REG_NUM);
+			/*Clear the tx_data */
+			memset(tx_data, 0, XFR_REG_NUM);
+			if (copy_from_user(tx_data,
+				data + bytes_copied, bytes_to_copy))
+				return -EFAULT;
+			retval = sync_write_xfr(radio,
+				RDS_PS_0 + chunk_index, tx_data);
+			if (retval < 0)	{
+				FMDBG("sync_write_xfr:  %d", retval);
+				return retval;
+			}
+			bytes_copied += bytes_to_copy;
+			bytes_left -= bytes_to_copy;
+		}
+		memset(tx_data, 0, XFR_REG_NUM);
+		/*Write the PS Header*/
+		FMDBG("Writing PS header\n");
+		extra_name_byte = (bytes_copied%8) ? 1 : 0;
+		name_bytes = (bytes_copied/8) + extra_name_byte;
+		/*8 bytes are grouped as 1 name */
+		tx_data[0] = (name_bytes) & MASK_TXREPCOUNT;
+		tx_data[1] = radio->pty & MASK_PTY; /* PTY */
+		tx_data[2] = ((radio->pi & MASK_PI_MSB) >> 8);
+		tx_data[3] = radio->pi & MASK_PI_LSB;
+		/* TX ctrl + repeatCount*/
+		tx_data[4] = TX_ON |
+		    (radio->ps_repeatcount & MASK_TXREPCOUNT);
+		retval = sync_write_xfr(radio, RDS_PS_0, tx_data);
+		if (retval < 0)	{
+			FMDBG("sync_write_xfr returned %d", retval);
+			return retval;
+		}
+	} break;
+	case V4L2_CID_RDS_TX_RADIO_TEXT: {
+		chunk_index = 0;
+		bytes_copied = 0;
+		FMDBG("In V4L2_CID_RDS_TX_RADIO_TEXT\n");
+		/*Pass a sample PS string */
+		FMDBG("Passed RT String : %s\n",
+			(ctrl->controls[0]).string);
+		bytes_left =
+		    min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
+		data = (ctrl->controls[0]).string;
+		/* send payload to FM hardware */
+		while (bytes_left) {
+			chunk_index++;
+			bytes_to_copy = min(bytes_left, XFR_REG_NUM);
+			memset(tx_data, 0, XFR_REG_NUM);
+			if (copy_from_user(tx_data,
+				    data + bytes_copied, bytes_to_copy))
+				return -EFAULT;
+			retval = sync_write_xfr(radio,
+				RDS_RT_0 + chunk_index, tx_data);
+			if (retval < 0)
+				return retval;
+			bytes_copied += bytes_to_copy;
+			bytes_left -= bytes_to_copy;
+		}
+		/*Write the RT  Header */
+		tx_data[0] = bytes_copied;
+		/* PTY */
+		tx_data[1] = TX_ON | ((radio->pty & MASK_PTY) >> 8);
+		/* PI high */
+		tx_data[2] = ((radio->pi & MASK_PI_MSB) >> 8);
+		/* PI low */
+		tx_data[3] = radio->pi & MASK_PI_LSB;
+		retval = sync_write_xfr(radio, RDS_RT_0 , tx_data);
+		if (retval < 0)
+			return retval;
+		FMDBG("done RT writing: %d\n", retval);
+	} break;
+	default:
+	{
+		FMDBG("Shouldn't reach here\n");
+		retval = -1;
+	}
+	}
+	return retval;
+}
+
+/*=============================================================================
+FUNCTION:  tavarua_vidioc_s_ctrl
+=============================================================================*/
+/**
+  This function is called to set the value of a control.
+
+  NOTE:
+  To change the value of a control, applications initialize the id and value
+  fields of a struct v4l2_control and call the VIDIOC_S_CTRL ioctl.
+
+  When the id is invalid drivers return an EINVAL error code. When the value is
+  out of bounds drivers can choose to take the closest valid value or return an
+  ERANGE error code, whatever seems more appropriate.
+
+  @param file: File descriptor returned by open().
+  @param ctrl: pointer to struct v4l2_control.
+
+  @return On success 0 is returned, else error code.
+  @return EINVAL: The struct v4l2_control id is invalid.
+  @return ERANGE: The struct v4l2_control value is out of bounds.
+  @return EBUSY: The control is temporarily not changeable, possibly because
+  another applications took over control of the device function this control
+  belongs to.
+*/
+static int tavarua_vidioc_s_ctrl(struct file *file, void *priv,
+		struct v4l2_control *ctrl)
+{
+	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
+	int retval = 0;
+	unsigned char value;
+	unsigned char xfr_buf[XFR_REG_NUM];
+	unsigned char tx_data[XFR_REG_NUM];
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_VOLUME:
+		break;
+	case V4L2_CID_AUDIO_MUTE:
+		value = (radio->registers[IOCTRL] & ~IOC_HRD_MUTE) |
+							(ctrl->value & 0x03);
+		retval = tavarua_write_register(radio, IOCTRL, value);
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_SRCHMODE:
+		value = (radio->registers[SRCHCTRL] & ~SRCH_MODE) |
+							ctrl->value;
+		radio->registers[SRCHCTRL] = value;
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_SCANDWELL:
+		value = (radio->registers[SRCHCTRL] & ~SCAN_DWELL) |
+						(ctrl->value << 4);
+		radio->registers[SRCHCTRL] = value;
+		break;
+	/* start/stop search */
+	case V4L2_CID_PRIVATE_TAVARUA_SRCHON:
+		FMDBG("starting search\n");
+		tavarua_search(radio, ctrl->value, SRCH_DIR_UP);
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_STATE:
+		/* check if already on */
+		radio->handle_irq = 1;
+		if (((ctrl->value == FM_RECV) || (ctrl->value == FM_TRANS))
+				    && !(radio->registers[RDCTRL] &
+							ctrl->value)) {
+			FMDBG("clearing flags\n");
+			init_completion(&radio->sync_xfr_start);
+			init_completion(&radio->sync_req_done);
+			radio->xfr_in_progress = 0;
+			radio->xfr_bytes_left = 0;
+			FMDBG("turning on ..\n");
+			retval = tavarua_start(radio, ctrl->value);
+			if (retval >= 0) {
+				FMDBG("Setting audio path ...\n");
+				retval = tavarua_set_audio_path(
+					TAVARUA_AUDIO_OUT_DIGITAL_ON,
+					TAVARUA_AUDIO_OUT_ANALOG_OFF);
+				if (retval < 0) {
+					FMDERR("Error in tavarua_set_audio_path"
+						" %d\n", retval);
+				}
+			 /* Enabling 'SoftMute' and 'SignalBlending' features */
+			value = (radio->registers[IOCTRL] |
+				    IOC_SFT_MUTE | IOC_SIG_BLND);
+			retval = tavarua_write_register(radio, IOCTRL, value);
+			if (retval < 0)
+				FMDBG("SMute and SBlending not enabled\n");
+			}
+		}
+		/* check if off */
+		else if ((ctrl->value == FM_OFF) && radio->registers[RDCTRL]) {
+			FMDBG("turning off...\n");
+			retval = tavarua_write_register(radio, RDCTRL,
+							ctrl->value);
+			/*Make it synchronous
+			Block it till READY interrupt
+			Wait for interrupt i.e.
+			complete(&radio->sync_req_done)
+			*/
+
+			if (retval >= 0) {
+
+				if (!wait_for_completion_timeout(
+					&radio->sync_req_done,
+					msecs_to_jiffies(wait_timeout)))
+					FMDBG("turning off timedout...\n");
+			}
+		}
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_REGION:
+		retval = tavarua_set_region(radio, ctrl->value);
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH:
+		retval = sync_read_xfr(radio, RX_CONFIG, xfr_buf);
+		if (retval < 0)	{
+			FMDERR("V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH]\n");
+			FMDERR("sync_read_xfr [retval=%d]\n", retval);
+			break;
+		}
+		/* RMSSI Threshold is a signed 8 bit value */
+		xfr_buf[0] = (unsigned char)ctrl->value;
+		xfr_buf[1] = (unsigned char)ctrl->value;
+		xfr_buf[4] = 0x01;
+		retval = sync_write_xfr(radio, RX_CONFIG, xfr_buf);
+		if (retval < 0) {
+			FMDERR("V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH]\n");
+			FMDERR("sync_write_xfr [retval=%d]\n", retval);
+			break;
+		}
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY:
+		radio->srch_params.srch_pty = ctrl->value;
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_SRCH_PI:
+		radio->srch_params.srch_pi = ctrl->value;
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT:
+		radio->srch_params.preset_num = ctrl->value;
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_EMPHASIS:
+		radio->region_params.emphasis = ctrl->value;
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_RDS_STD:
+		radio->region_params.rds_std = ctrl->value;
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_SPACING:
+		radio->region_params.spacing = ctrl->value;
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_RDSON:
+		retval = 0;
+		if (ctrl->value != (radio->registers[RDSCTRL] & RDS_ON)) {
+			value = radio->registers[RDSCTRL] | ctrl->value;
+			retval = tavarua_write_register(radio, RDSCTRL, value);
+		}
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK:
+		retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
+		if (retval < 0)
+			break;
+		xfr_buf[8] = (ctrl->value & 0xFF000000) >> 24;
+		xfr_buf[9] = (ctrl->value & 0x00FF0000) >> 16;
+		xfr_buf[10] = (ctrl->value & 0x0000FF00) >> 8;
+		xfr_buf[11] = (ctrl->value & 0x000000FF);
+		retval = sync_write_xfr(radio, RDS_CONFIG, xfr_buf);
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC:
+		value  = radio->registers[ADVCTRL] | ctrl->value  ;
+		retval = tavarua_write_register(radio, ADVCTRL, value);
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF:
+		retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
+		if (retval < 0)
+			break;
+		xfr_buf[1] = ctrl->value;
+		retval = sync_write_xfr(radio, RDS_CONFIG, xfr_buf);
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_PSALL:
+		retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
+		value = ctrl->value & RDS_CONFIG_PSALL;
+		if (retval < 0)
+			break;
+		xfr_buf[12] &= ~RDS_CONFIG_PSALL;
+		xfr_buf[12] |= value;
+		retval = sync_write_xfr(radio, RDS_CONFIG, xfr_buf);
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_LP_MODE:
+		retval = 0;
+		if (ctrl->value == radio->lp_mode)
+			break;
+		if (ctrl->value) {
+			FMDBG("going into low power mode\n");
+			retval = tavarua_disable_interrupts(radio);
+		} else {
+			FMDBG("going into normal power mode\n");
+			tavarua_setup_interrupts(radio,
+				(radio->registers[RDCTRL] & 0x03));
+		}
+		break;
+	case V4L2_CID_PRIVATE_TAVARUA_ANTENNA:
+		SET_REG_FIELD(radio->registers[IOCTRL], ctrl->value,
+					IOC_ANTENNA_OFFSET, IOC_ANTENNA_MASK);
+		break;
+	/* TX Controls */
+
+	case V4L2_CID_RDS_TX_PTY: {
+			radio->pty = ctrl->value;
+		} break;
+	case V4L2_CID_RDS_TX_PI: {
+			radio->pi = ctrl->value;
+		} break;
+	case V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_PS_NAME: {
+			FMDBG("In STOP_RDS_TX_PS_NAME\n");
+			/*Pass a sample PS string */
+			memset(tx_data, '0', XFR_REG_NUM);
+			FMDBG("Writing PS header\n");
+			retval = sync_write_xfr(radio, RDS_PS_0, tx_data);
+			FMDBG("retval of PS Header write: %d", retval);
+
+		} break;
+
+	case V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_RT: {
+			memset(tx_data, '0', XFR_REG_NUM);
+			FMDBG("Writing RT header\n");
+			retval = sync_write_xfr(radio, RDS_RT_0, tx_data);
+			FMDBG("retval of Header write: %d", retval);
+
+		} break;
+
+	case V4L2_CID_PRIVATE_TAVARUA_TX_SETPSREPEATCOUNT: {
+			radio->ps_repeatcount = ctrl->value;
+		} break;
+	case V4L2_CID_TUNE_POWER_LEVEL: {
+		unsigned char tx_power_lvl_config[FM_TX_PWR_LVL_MAX+1] = {
+			0x85, /* tx_da<5:3> = 0  lpf<2:0> = 5*/
+			0x95, /* tx_da<5:3> = 2  lpf<2:0> = 5*/
+			0x9D, /* tx_da<5:3> = 3  lpf<2:0> = 5*/
+			0xA5, /* tx_da<5:3> = 4  lpf<2:0> = 5*/
+			0xAD, /* tx_da<5:3> = 5  lpf<2:0> = 5*/
+			0xB5, /* tx_da<5:3> = 6  lpf<2:0> = 5*/
+			0xBD, /* tx_da<5:3> = 7  lpf<2:0> = 5*/
+			0xBF  /* tx_da<5:3> = 7  lpf<2:0> = 7*/
+		};
+		if (ctrl->value > FM_TX_PWR_LVL_MAX)
+			ctrl->value = FM_TX_PWR_LVL_MAX;
+		if (ctrl->value < FM_TX_PWR_LVL_0)
+			ctrl->value = FM_TX_PWR_LVL_0;
+		retval = sync_read_xfr(radio, PHY_TXGAIN, xfr_buf);
+		FMDBG("return for PHY_TXGAIN is %d", retval);
+		if (retval < 0) {
+			FMDBG("read failed");
+			break;
+		}
+		xfr_buf[2] = tx_power_lvl_config[ctrl->value];
+		retval = sync_write_xfr(radio, PHY_TXGAIN, xfr_buf);
+		FMDBG("return for write PHY_TXGAIN is %d", retval);
+		if (retval < 0)
+			FMDBG("write failed");
+	} break;
+
+	default:
+		retval = -EINVAL;
+	}
+	if (retval < 0)
+		printk(KERN_WARNING DRIVER_NAME
+		": set control failed with %d, id : %d\n", retval, ctrl->id);
+
+	return retval;
+}
+
+/*=============================================================================
+FUNCTION:  tavarua_vidioc_g_tuner
+=============================================================================*/
+/**
+  This function is called to get tuner attributes.
+
+  NOTE:
+  To query the attributes of a tuner, applications initialize the index field
+  and zero out the reserved array of a struct v4l2_tuner and call the
+  VIDIOC_G_TUNER ioctl with a pointer to this structure. Drivers fill the rest
+  of the structure or return an EINVAL error code when the index is out of
+  bounds. To enumerate all tuners applications shall begin at index zero,
+  incrementing by one until the driver returns EINVAL.
+
+  @param file: File descriptor returned by open().
+  @param tuner: pointer to struct v4l2_tuner.
+
+  @return On success 0 is returned, else error code.
+  @return EINVAL: The struct v4l2_tuner index is out of bounds.
+*/
+static int tavarua_vidioc_g_tuner(struct file *file, void *priv,
+		struct v4l2_tuner *tuner)
+{
+	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
+	int retval;
+	unsigned char xfr_buf[XFR_REG_NUM];
+	char rmssi = 0;
+	unsigned char size = 0;
+
+	if (tuner->index > 0)
+		return -EINVAL;
+
+	/* read status rssi */
+	retval = tavarua_read_registers(radio, IOCTRL, 1);
+	if (retval < 0)
+		return retval;
+	/* read RMSSI */
+	size = 0x1;
+	xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
+	xfr_buf[1] = RMSSI_PEEK_MSB;
+	xfr_buf[2] = RMSSI_PEEK_LSB;
+	retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
+	msleep(TAVARUA_DELAY*10);
+	retval = tavarua_read_registers(radio, XFRDAT0, 3);
+	rmssi = radio->registers[XFRDAT0];
+	tuner->signal = rmssi;
+
+	strcpy(tuner->name, "FM");
+	tuner->type = V4L2_TUNER_RADIO;
+	tuner->rangelow  =  radio->region_params.band_low;
+	tuner->rangehigh =  radio->region_params.band_high;
+	tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+	tuner->capability = V4L2_TUNER_CAP_LOW;
+
+	/* Stereo indicator == Stereo (instead of Mono) */
+	if (radio->registers[IOCTRL] & IOC_MON_STR)
+		tuner->audmode = V4L2_TUNER_MODE_STEREO;
+	else
+	  tuner->audmode = V4L2_TUNER_MODE_MONO;
+
+	/* automatic frequency control: -1: freq to low, 1 freq to high */
+	tuner->afc = 0;
+
+	return 0;
+}
+
+/*=============================================================================
+FUNCTION:  tavarua_vidioc_s_tuner
+=============================================================================*/
+/**
+  This function is called to set tuner attributes. Used to set mono/stereo mode.
+
+  NOTE:
+  Tuners have two writable properties, the audio mode and the radio frequency.
+  To change the audio mode, applications initialize the index, audmode and
+  reserved fields and call the VIDIOC_S_TUNER ioctl. This will not change the
+  current tuner, which is determined by the current video input. Drivers may
+  choose a different audio mode if the requested mode is invalid or unsupported.
+  Since this is a write-only ioctl, it does not return the actually selected
+  audio mode.
+
+  To change the radio frequency the VIDIOC_S_FREQUENCY ioctl is available.
+
+  @param file: File descriptor returned by open().
+  @param tuner: pointer to struct v4l2_tuner.
+
+  @return On success 0 is returned, else error code.
+  @return -EINVAL: The struct v4l2_tuner index is out of bounds.
+*/
+static int tavarua_vidioc_s_tuner(struct file *file, void *priv,
+		struct v4l2_tuner *tuner)
+{
+	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
+	int retval;
+	int audmode;
+	if (tuner->index > 0)
+		return -EINVAL;
+
+	FMDBG("%s: set low to %d\n", __func__, tuner->rangelow);
+	radio->region_params.band_low = tuner->rangelow;
+	radio->region_params.band_high = tuner->rangehigh;
+	if (tuner->audmode == V4L2_TUNER_MODE_MONO)
+		/* Mono */
+		audmode = (radio->registers[IOCTRL] | IOC_MON_STR);
+	 else
+		/* Stereo */
+		audmode = (radio->registers[IOCTRL] & ~IOC_MON_STR);
+	retval = tavarua_write_register(radio, IOCTRL, audmode);
+	if (retval < 0)
+		printk(KERN_WARNING DRIVER_NAME
+			": set tuner failed with %d\n", retval);
+
+	return retval;
+}
+
+/*=============================================================================
+FUNCTION:  tavarua_vidioc_g_frequency
+=============================================================================*/
+/**
+  This function is called to get tuner or modulator radio frequency.
+
+  NOTE:
+  To get the current tuner or modulator radio frequency applications set the
+  tuner field of a struct v4l2_frequency to the respective tuner or modulator
+  number (only input devices have tuners, only output devices have modulators),
+  zero out the reserved array and call the VIDIOC_G_FREQUENCY ioctl with a
+  pointer to this structure. The driver stores the current frequency in the
+  frequency field.
+
+  @param file: File descriptor returned by open().
+  @param freq: pointer to struct v4l2_frequency. This will be set to the
+   resultant
+  frequency in 62.5 khz on success.
+
+  @return On success 0 is returned, else error code.
+  @return EINVAL: The tuner index is out of bounds or the value in the type
+  field is wrong.
+*/
+static int tavarua_vidioc_g_frequency(struct file *file, void *priv,
+		struct v4l2_frequency *freq)
+{
+	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
+	freq->type = V4L2_TUNER_RADIO;
+	return tavarua_get_freq(radio, freq);
+
+}
+
+/*=============================================================================
+FUNCTION:  tavarua_vidioc_s_frequency
+=============================================================================*/
+/**
+  This function is called to set tuner or modulator radio frequency.
+
+  NOTE:
+  To change the current tuner or modulator radio frequency applications
+  initialize the tuner, type and frequency fields, and the reserved array of
+  a struct v4l2_frequency and call the VIDIOC_S_FREQUENCY ioctl with a pointer
+  to this structure. When the requested frequency is not possible the driver
+  assumes the closest possible value. However VIDIOC_S_FREQUENCY is a
+  write-only ioctl, it does not return the actual new frequency.
+
+  @param file: File descriptor returned by open().
+  @param freq: pointer to struct v4l2_frequency.
+
+  @return On success 0 is returned, else error code.
+  @return EINVAL: The tuner index is out of bounds or the value in the type
+  field is wrong.
+*/
+static int tavarua_vidioc_s_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *freq)
+{
+	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
+	int retval = -1;
+	struct v4l2_frequency getFreq;
+
+	FMDBG("%s\n", __func__);
+
+	if (freq->type != V4L2_TUNER_RADIO)
+		return -EINVAL;
+
+	FMDBG("Calling tavarua_set_freq\n");
+
+	INIT_COMPLETION(radio->sync_req_done);
+	retval = tavarua_set_freq(radio, freq->frequency);
+	if (retval < 0) {
+		printk(KERN_WARNING DRIVER_NAME
+			": set frequency failed with %d\n", retval);
+	} else {
+		/* Wait for interrupt i.e. complete
+		(&radio->sync_req_done); call */
+		if (!wait_for_completion_timeout(&radio->sync_req_done,
+			msecs_to_jiffies(wait_timeout))) {
+			FMDERR("Timeout: No Tune response");
+			retval = tavarua_get_freq(radio, &getFreq);
+			radio->tune_req = 0;
+			if (retval > 0) {
+				if (getFreq.frequency == freq->frequency) {
+					/** This is success, queut the event*/
+					tavarua_q_event(radio,
+						TAVARUA_EVT_TUNE_SUCC);
+					return 0;
+				} else {
+					return -EIO;
+				}
+			}
+		}
+	}
+	radio->tune_req = 0;
+	return retval;
+}
+
+/*=============================================================================
+FUNCTION:  tavarua_vidioc_dqbuf
+=============================================================================*/
+/**
+  This function is called to exchange a buffer with the driver.
+  This is main buffer function, in essense its equivalent to a blocking
+  read call.
+
+  Applications call the VIDIOC_DQBUF ioctl to dequeue a filled (capturing) or
+  displayed (output) buffer from the driver's outgoing queue. They just set
+  the type and memory fields of a struct v4l2_buffer as above, when VIDIOC_DQBUF
+  is called with a pointer to this structure the driver fills the remaining
+  fields or returns an error code.
+
+  NOTE:
+  By default VIDIOC_DQBUF blocks when no buffer is in the outgoing queue.
+  When the O_NONBLOCK flag was given to the open() function, VIDIOC_DQBUF
+  returns immediately with an EAGAIN error code when no buffer is available.
+
+  @param file: File descriptor returned by open().
+  @param buffer: pointer to struct v4l2_buffer.
+
+  @return On success 0 is returned, else error code.
+  @return EAGAIN: Non-blocking I/O has been selected using O_NONBLOCK and no
+  buffer was in the outgoing queue.
+  @return EINVAL: The buffer type is not supported, or the index is out of
+  bounds, or no buffers have been allocated yet, or the userptr or length are
+  invalid.
+  @return ENOMEM: Not enough physical or virtual memory was available to enqueue
+  a user pointer buffer.
+  @return EIO: VIDIOC_DQBUF failed due to an internal error. Can also indicate
+  temporary problems like signal loss. Note the driver might dequeue an (empty)
+  buffer despite returning an error, or even stop capturing.
+*/
+static int tavarua_vidioc_dqbuf(struct file *file, void *priv,
+				struct v4l2_buffer *buffer)
+{
+
+	struct tavarua_device  *radio = video_get_drvdata(video_devdata(file));
+	enum tavarua_buf_t buf_type = buffer->index;
+	struct kfifo *data_fifo;
+	unsigned char *buf = (unsigned char *)buffer->m.userptr;
+	unsigned int len = buffer->length;
+	FMDBG("%s: requesting buffer %d\n", __func__, buf_type);
+	/* check if we can access the user buffer */
+	if (!access_ok(VERIFY_WRITE, buf, len))
+		return -EFAULT;
+	if ((buf_type < TAVARUA_BUF_MAX) && (buf_type >= 0)) {
+		data_fifo = &radio->data_buf[buf_type];
+		if (buf_type == TAVARUA_BUF_EVENTS) {
+			if (wait_event_interruptible(radio->event_queue,
+				kfifo_len(data_fifo)) < 0) {
+				return -EINTR;
+			}
+		}
+	} else {
+		FMDERR("invalid buffer type\n");
+		return -EINVAL;
+	}
+	buffer->bytesused = kfifo_out_locked(data_fifo, buf, len,
+					&radio->buf_lock[buf_type]);
+
+	return 0;
+}
+
+/*=============================================================================
+FUNCTION:  tavarua_vidioc_g_fmt_type_private
+=============================================================================*/
+/**
+  This function is here to make the v4l2 framework happy.
+  We cannot use private buffers without it.
+
+  @param file: File descriptor returned by open().
+  @param f: pointer to struct v4l2_format.
+
+  @return On success 0 is returned, else error code.
+  @return EINVAL: The tuner index is out of bounds or the value in the type
+  field is wrong.
+*/
+static int tavarua_vidioc_g_fmt_type_private(struct file *file, void *priv,
+						struct v4l2_format *f)
+{
+	return 0;
+
+}
+
+/*=============================================================================
+FUNCTION:  tavarua_vidioc_s_hw_freq_seek
+=============================================================================*/
+/**
+  This function is called to perform a hardware frequency seek.
+
+  Start a hardware frequency seek from the current frequency. To do this
+  applications initialize the tuner, type, seek_upward and wrap_around fields,
+  and zero out the reserved array of a struct v4l2_hw_freq_seek and call the
+  VIDIOC_S_HW_FREQ_SEEK ioctl with a pointer to this structure.
+
+  This ioctl is supported if the V4L2_CAP_HW_FREQ_SEEK capability is set.
+
+  @param file: File descriptor returned by open().
+  @param seek: pointer to struct v4l2_hw_freq_seek.
+
+  @return On success 0 is returned, else error code.
+  @return EINVAL: The tuner index is out of bounds or the value in the type
+  field is wrong.
+  @return EAGAIN: The ioctl timed-out. Try again.
+*/
+static int tavarua_vidioc_s_hw_freq_seek(struct file *file, void *priv,
+					struct v4l2_hw_freq_seek *seek)
+{
+	struct tavarua_device  *radio = video_get_drvdata(video_devdata(file));
+	int dir;
+	if (seek->seek_upward)
+		dir = SRCH_DIR_UP;
+	else
+		dir = SRCH_DIR_DOWN;
+	FMDBG("starting search\n");
+	return tavarua_search(radio, CTRL_ON, dir);
+}
+
+/*
+ * tavarua_viddev_tamples - video device interface
+ */
+static const struct v4l2_ioctl_ops tavarua_ioctl_ops = {
+	.vidioc_querycap              = tavarua_vidioc_querycap,
+	.vidioc_queryctrl             = tavarua_vidioc_queryctrl,
+	.vidioc_g_ctrl                = tavarua_vidioc_g_ctrl,
+	.vidioc_s_ctrl                = tavarua_vidioc_s_ctrl,
+	.vidioc_g_tuner               = tavarua_vidioc_g_tuner,
+	.vidioc_s_tuner               = tavarua_vidioc_s_tuner,
+	.vidioc_g_frequency           = tavarua_vidioc_g_frequency,
+	.vidioc_s_frequency           = tavarua_vidioc_s_frequency,
+	.vidioc_s_hw_freq_seek        = tavarua_vidioc_s_hw_freq_seek,
+	.vidioc_dqbuf                 = tavarua_vidioc_dqbuf,
+	.vidioc_g_fmt_type_private    = tavarua_vidioc_g_fmt_type_private,
+	.vidioc_s_ext_ctrls           = tavarua_vidioc_s_ext_ctrls,
+};
+
+static struct video_device tavarua_viddev_template = {
+	.fops                   = &tavarua_fops,
+	.ioctl_ops              = &tavarua_ioctl_ops,
+	.name                   = DRIVER_NAME,
+	.release                = video_device_release,
+};
+
+/*==============================================================
+FUNCTION:  FmQSocCom_EnableInterrupts
+==============================================================*/
+/**
+  This function enable interrupts.
+
+  @param radio: structure pointer passed by client.
+  @param state: FM radio state (receiver/transmitter/off/reset).
+
+  @return => 0 if successful.
+  @return < 0 if failure.
+*/
+static int tavarua_setup_interrupts(struct tavarua_device *radio,
+					enum radio_state_t state)
+{
+	int retval;
+	unsigned char int_ctrl[XFR_REG_NUM];
+
+	if (!radio->lp_mode)
+		return 0;
+
+	int_ctrl[STATUS_REG1] = READY | TUNE | SEARCH | SCANNEXT |
+				SIGNAL | INTF | SYNC | AUDIO;
+	if (state == FM_RECV)
+		int_ctrl[STATUS_REG2] =  RDSDAT | RDSRT | RDSPS | RDSAF;
+	else
+		int_ctrl[STATUS_REG2] = TXRDSDAT | TXRDSDONE;
+
+	int_ctrl[STATUS_REG3] = TRANSFER | ERROR;
+
+	/* use xfr for interrupt setup */
+    if (radio->chipID == MARIMBA_2_1 || radio->chipID == BAHAMA_1_0
+		|| radio->chipID == BAHAMA_2_0) {
+		FMDBG("Setting interrupts\n");
+		retval =  sync_write_xfr(radio, INT_CTRL, int_ctrl);
+	/* use register write to setup interrupts */
+	} else {
+		retval = tavarua_write_register(radio,
+					STATUS_REG1, int_ctrl[STATUS_REG1]);
+		if (retval < 0)
+			return retval;
+
+		retval = tavarua_write_register(radio,
+					STATUS_REG2, int_ctrl[STATUS_REG2]);
+		if (retval < 0)
+			return retval;
+
+		retval = tavarua_write_register(radio,
+					STATUS_REG3, int_ctrl[STATUS_REG3]);
+		if (retval < 0)
+			return retval;
+	}
+
+	radio->lp_mode = 0;
+	/* tavarua_handle_interrupts force reads all the interrupt status
+	*  registers and it is not valid for MBA 2.1
+	*/
+	if ((radio->chipID != MARIMBA_2_1) && (radio->chipID != BAHAMA_1_0)
+		&& (radio->chipID != BAHAMA_2_0))
+		tavarua_handle_interrupts(radio);
+
+	return retval;
+
+}
+
+/*==============================================================
+FUNCTION:  tavarua_disable_interrupts
+==============================================================*/
+/**
+  This function disables interrupts.
+
+  @param radio: structure pointer passed by client.
+
+  @return => 0 if successful.
+  @return < 0 if failure.
+*/
+static int tavarua_disable_interrupts(struct tavarua_device *radio)
+{
+	unsigned char lpm_buf[XFR_REG_NUM];
+	int retval;
+	if (radio->lp_mode)
+		return 0;
+	FMDBG("%s\n", __func__);
+	/* In Low power mode, disable all the interrupts that are not being
+		 waited by the Application */
+	lpm_buf[STATUS_REG1] = TUNE | SEARCH | SCANNEXT;
+	lpm_buf[STATUS_REG2] = 0x00;
+	lpm_buf[STATUS_REG3] = TRANSFER;
+	/* use xfr for interrupt setup */
+	wait_timeout = 100;
+	if (radio->chipID == MARIMBA_2_1 || radio->chipID == BAHAMA_1_0
+		|| radio->chipID == BAHAMA_2_0)
+		retval = sync_write_xfr(radio, INT_CTRL, lpm_buf);
+	/* use register write to setup interrupts */
+	else
+		retval = tavarua_write_registers(radio, STATUS_REG1, lpm_buf,
+							ARRAY_SIZE(lpm_buf));
+
+	/*INT_CTL writes may fail with TIME_OUT as all the
+	interrupts have been disabled
+	*/
+	if (retval > -1 || retval == -ETIME) {
+		radio->lp_mode = 1;
+		/*Consider timeout as a valid case here*/
+		retval = 0;
+	}
+	wait_timeout = WAIT_TIMEOUT;
+	return retval;
+
+}
+
+/*==============================================================
+FUNCTION:  tavarua_start
+==============================================================*/
+/**
+  Starts/enables the device (FM radio).
+
+  @param radio: structure pointer passed by client.
+  @param state: FM radio state (receiver/transmitter/off/reset).
+
+  @return On success 0 is returned, else error code.
+*/
+static int tavarua_start(struct tavarua_device *radio,
+				enum radio_state_t state)
+{
+
+	int retval;
+	FMDBG("%s <%d>\n", __func__, state);
+	/* set geographic region */
+	radio->region_params.region = TAVARUA_REGION_US;
+
+	/* set radio mode */
+	retval = tavarua_write_register(radio, RDCTRL, state);
+	if (retval < 0)
+		return retval;
+	/* wait for radio to init */
+	msleep(RADIO_INIT_TIME);
+	/* enable interrupts */
+	tavarua_setup_interrupts(radio, state);
+	/* default region is US */
+	radio->region_params.band_low = US_LOW_BAND * FREQ_MUL;
+	radio->region_params.band_high = US_HIGH_BAND * FREQ_MUL;
+
+	return 0;
+}
+
+/*==============================================================
+FUNCTION:  tavarua_suspend
+==============================================================*/
+/**
+  Save state and stop all devices in system.
+
+  @param pdev: platform device to be suspended.
+  @param state: Power state to put each device in.
+
+  @return On success 0 is returned, else error code.
+*/
+static int tavarua_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct tavarua_device *radio = platform_get_drvdata(pdev);
+	int retval;
+	int users = 0;
+	printk(KERN_INFO DRIVER_NAME "%s: radio suspend\n\n", __func__);
+	if (radio) {
+		mutex_lock(&radio->lock);
+		users = radio->users;
+		mutex_unlock(&radio->lock);
+		if (users) {
+			retval = tavarua_disable_interrupts(radio);
+			if (retval < 0) {
+				printk(KERN_INFO DRIVER_NAME
+					"tavarua_suspend error %d\n", retval);
+				return -EIO;
+			}
+		}
+	}
+	return 0;
+}
+
+/*==============================================================
+FUNCTION:  tavarua_resume
+==============================================================*/
+/**
+  Restore state of each device in system.
+
+  @param pdev: platform device to be resumed.
+
+  @return On success 0 is returned, else error code.
+*/
+static int tavarua_resume(struct platform_device *pdev)
+{
+
+	struct tavarua_device *radio = platform_get_drvdata(pdev);
+	int retval;
+	int users = 0;
+	printk(KERN_INFO DRIVER_NAME "%s: radio resume\n\n", __func__);
+	if (radio) {
+		mutex_lock(&radio->lock);
+		users = radio->users;
+		mutex_unlock(&radio->lock);
+
+		if (users) {
+			retval = tavarua_setup_interrupts(radio,
+			(radio->registers[RDCTRL] & 0x03));
+			if (retval < 0) {
+				printk(KERN_INFO DRIVER_NAME "Error in \
+					tavarua_resume %d\n", retval);
+				return -EIO;
+			}
+		}
+	}
+	return 0;
+}
+
+/*==============================================================
+FUNCTION:  tavarua_set_audio_path
+==============================================================*/
+/**
+  This function will configure the audio path to and from the
+  FM core.
+
+  This interface is expected to be called from the multimedia
+  driver's thread.  This interface should only be called when
+  the FM hardware is enabled.  If the FM hardware is not
+  currently enabled, this interface will return an error.
+
+  @param digital_on: Digital audio from the FM core should be enabled/disbled.
+  @param analog_on: Analog audio from the FM core should be enabled/disbled.
+
+  @return On success 0 is returned, else error code.
+*/
+int tavarua_set_audio_path(int digital_on, int analog_on)
+{
+	struct tavarua_device *radio = private_data;
+	int rx_on = radio->registers[RDCTRL] & FM_RECV;
+	if (!radio)
+		return -ENOMEM;
+	/* RX */
+	FMDBG("%s: digital: %d analog: %d\n", __func__, digital_on, analog_on);
+	SET_REG_FIELD(radio->registers[AUDIOCTRL],
+		((rx_on && analog_on) ? 1 : 0),
+		AUDIORX_ANALOG_OFFSET,
+		AUDIORX_ANALOG_MASK);
+	SET_REG_FIELD(radio->registers[AUDIOCTRL],
+		((rx_on && digital_on) ? 1 : 0),
+		AUDIORX_DIGITAL_OFFSET,
+		AUDIORX_DIGITAL_MASK);
+	SET_REG_FIELD(radio->registers[AUDIOCTRL],
+		(rx_on ? 0 : 1),
+		AUDIOTX_OFFSET,
+		AUDIOTX_MASK);
+	/*
+
+	I2S Master/Slave configuration:
+	Setting the FM SoC as I2S Master/Slave
+		'false'		- FM SoC is I2S Slave
+		'true'		- FM SoC is I2S Master
+
+	We get this infomation from the respective target's board file :
+		MSM7x30         - FM SoC is I2S Slave
+		MSM8x60         - FM SoC is I2S Slave
+		MSM7x27A        - FM SoC is I2S Master
+	*/
+
+	if (!radio->pdata->is_fm_soc_i2s_master) {
+		FMDBG("FM SoC is I2S Slave\n");
+		SET_REG_FIELD(radio->registers[AUDIOCTRL],
+		(0),
+		I2SCTRL_OFFSET,
+		I2SCTRL_MASK);
+	} else {
+		FMDBG("FM SoC is I2S Master\n");
+		SET_REG_FIELD(radio->registers[AUDIOCTRL],
+		(1),
+		I2SCTRL_OFFSET,
+		I2SCTRL_MASK);
+	}
+	FMDBG("%s: %x\n", __func__, radio->registers[AUDIOCTRL]);
+	return tavarua_write_register(radio, AUDIOCTRL,
+					radio->registers[AUDIOCTRL]);
+
+}
+
+/*==============================================================
+FUNCTION:  tavarua_probe
+==============================================================*/
+/**
+  Once called this functions initiates, allocates resources and registers video
+  tuner device with the v4l2 framework.
+
+  NOTE:
+  probe() should verify that the specified device hardware
+  actually exists; sometimes platform setup code can't be sure.  The probing
+  can use device resources, including clocks, and device platform_data.
+
+  @param pdev: platform device to be probed.
+
+  @return On success 0 is returned, else error code.
+	-ENOMEM in low memory cases
+*/
+static int  __init tavarua_probe(struct platform_device *pdev)
+{
+
+	struct marimba_fm_platform_data *tavarua_pdata;
+	struct tavarua_device *radio;
+	int retval;
+	int i;
+	FMDBG("%s: probe called\n", __func__);
+	/* private data allocation */
+	radio = kzalloc(sizeof(struct tavarua_device), GFP_KERNEL);
+	if (!radio) {
+		retval = -ENOMEM;
+	goto err_initial;
+	}
+
+	radio->marimba = platform_get_drvdata(pdev);
+	tavarua_pdata = pdev->dev.platform_data;
+	radio->pdata = tavarua_pdata;
+	radio->dev = &pdev->dev;
+	platform_set_drvdata(pdev, radio);
+
+	/* video device allocation */
+	radio->videodev = video_device_alloc();
+	if (!radio->videodev)
+		goto err_radio;
+
+	/* initial configuration */
+	memcpy(radio->videodev, &tavarua_viddev_template,
+	  sizeof(tavarua_viddev_template));
+
+	/*allocate internal buffers for decoded rds and event buffer*/
+	for (i = 0; i < TAVARUA_BUF_MAX; i++) {
+		int kfifo_alloc_rc=0;
+		spin_lock_init(&radio->buf_lock[i]);
+
+		if (i == TAVARUA_BUF_RAW_RDS)
+			kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
+				rds_buf*3, GFP_KERNEL);
+		else
+			kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
+				STD_BUF_SIZE, GFP_KERNEL);
+
+		if (kfifo_alloc_rc!=0) {
+			printk(KERN_ERR "%s: failed allocating buffers %d\n",
+				__func__, kfifo_alloc_rc);
+			goto err_bufs;
+		}
+	}
+	/* init xfr status */
+	radio->users = 0;
+	radio->xfr_in_progress = 0;
+	radio->xfr_bytes_left = 0;
+	for (i = 0; i < TAVARUA_XFR_MAX; i++)
+		radio->pending_xfrs[i] = 0;
+
+	/* init transmit data */
+	radio->tx_mode = TAVARUA_TX_RT;
+		/* Init RT and PS Tx datas*/
+	radio->pty = 0;
+	radio->pi = 0;
+	radio->ps_repeatcount = 0;
+		/* init search params */
+	radio->srch_params.srch_pty = 0;
+	radio->srch_params.srch_pi = 0;
+	radio->srch_params.preset_num = 0;
+	radio->srch_params.get_list = 0;
+	/* radio initializes to low power mode */
+	radio->lp_mode = 1;
+	radio->handle_irq = 1;
+	/* init lock */
+	mutex_init(&radio->lock);
+	/* init completion flags */
+	init_completion(&radio->sync_xfr_start);
+	init_completion(&radio->sync_req_done);
+	radio->tune_req = 0;
+	/* initialize wait queue for event read */
+	init_waitqueue_head(&radio->event_queue);
+	/* initialize wait queue for raw rds read */
+	init_waitqueue_head(&radio->read_queue);
+
+	video_set_drvdata(radio->videodev, radio);
+    /*Start the worker thread for event handling and register read_int_stat
+	as worker function*/
+	INIT_DELAYED_WORK(&radio->work, read_int_stat);
+
+	/* register video device */
+	if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
+		printk(KERN_WARNING DRIVER_NAME
+				": Could not register video device\n");
+		goto err_all;
+	}
+	private_data = radio;
+	return 0;
+
+err_all:
+	video_device_release(radio->videodev);
+err_bufs:
+	for (; i > -1; i--)
+		kfifo_free(&radio->data_buf[i]);
+err_radio:
+	kfree(radio);
+err_initial:
+	return retval;
+}
+
+/*==============================================================
+FUNCTION:  tavarua_remove
+==============================================================*/
+/**
+  Removes the device.
+
+  @param pdev: platform device to be removed.
+
+  @return On success 0 is returned, else error code.
+*/
+static int __devexit tavarua_remove(struct platform_device *pdev)
+{
+	int i;
+	struct tavarua_device *radio = platform_get_drvdata(pdev);
+
+	/* disable irq */
+	tavarua_disable_irq(radio);
+
+	video_unregister_device(radio->videodev);
+
+	/* free internal buffers */
+	for (i = 0; i < TAVARUA_BUF_MAX; i++)
+		kfifo_free(&radio->data_buf[i]);
+
+	/* free state struct */
+	kfree(radio);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+/*
+ Platform drivers follow the standard driver model convention, where
+ discovery/enumeration is handled outside the drivers, and drivers
+ provide probe() and remove() methods.  They support power management
+ and shutdown notifications using the standard conventions.
+*/
+static struct platform_driver tavarua_driver = {
+	.driver = {
+		.owner  = THIS_MODULE,
+		.name   = "marimba_fm",
+	},
+	.remove = __devexit_p(tavarua_remove),
+	.suspend = tavarua_suspend,
+	.resume = tavarua_resume,
+}; /* platform device we're adding */
+
+
+/*************************************************************************
+ * Module Interface
+ ************************************************************************/
+
+/*==============================================================
+FUNCTION:  radio_module_init
+==============================================================*/
+/**
+  Module entry - add a platform-level device.
+
+  @return Returns zero if the driver registered and bound to a device, else
+  returns a negative error code when the driver not registered.
+*/
+static int __init radio_module_init(void)
+{
+	printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n");
+	return platform_driver_probe(&tavarua_driver, tavarua_probe);
+}
+
+/*==============================================================
+FUNCTION:  radio_module_exit
+==============================================================*/
+/**
+  Module exit - removes a platform-level device.
+
+  NOTE:
+  Note that this function will also release all memory- and port-based
+  resources owned by the device (dev->resource).
+
+  @return none.
+*/
+static void __exit radio_module_exit(void)
+{
+  platform_driver_unregister(&tavarua_driver);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+
+module_init(radio_module_init);
+module_exit(radio_module_exit);
+
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index bb53de7..95255fe 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -1031,6 +1031,31 @@
 	  This driver can be compiled as a module, called s2255drv.
 
 endif # V4L_USB_DRIVERS
+
+#
+# MSM camera configuration
+#
+
+comment "Qualcomm MSM Camera And Video"
+
+menuconfig MSM_CAMERA
+	bool "Qualcomm MSM camera and video capture support"
+	depends on ARCH_MSM && VIDEO_V4L2 && I2C
+	default y
+	help
+	  Say Y here to enable selecting the video adapters for
+	  Qualcomm msm camera and video encoding
+
+config MSM_CAMERA_DEBUG
+	bool "Qualcomm MSM camera debugging with printk"
+	depends on MSM_CAMERA
+	default n
+	help
+	  Enable printk() debug for msm camera
+
+
+source "drivers/media/video/msm/Kconfig"
+
 endif # VIDEO_CAPTURE_DRIVERS
 
 menuconfig V4L_MEM2MEM_DRIVERS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index f0fecd6..724c7a3 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -10,8 +10,8 @@
 
 omap2cam-objs	:=	omap24xxcam.o omap24xxcam-dma.o
 
-videodev-objs	:=	v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
-			v4l2-event.o v4l2-ctrls.o v4l2-subdev.o
+videodev-objs	:=	v4l2-dev.o v4l2-ioctl.o v4l2-device.o   v4l2-fh.o \
+			v4l2-event.o v4l2-ctrls.o v4l2-subdev.o videobuf-core.o videobuf-msm-mem.o videobuf-dma-contig.o
 
 # V4L2 core modules
 
@@ -182,6 +182,7 @@
 
 obj-y	+= davinci/
 
+obj-$(CONFIG_MSM_CAMERA) += msm/
 obj-$(CONFIG_ARCH_OMAP)	+= omap/
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
new file mode 100644
index 0000000..6ba1abd
--- /dev/null
+++ b/drivers/media/video/msm/Kconfig
@@ -0,0 +1,194 @@
+config MSM_CAMERA_V4L2
+        bool "MSM Camera V4L2 Interface"
+        depends on MSM_CAMERA
+        default n
+        ---help---
+          This flag enables V4L2 interface of MSM
+          camera driver. If enabled, application interacts
+          with /dev/video0 through V4L2 APIs. Otherwise,
+          native APIs are used through /dev/config0, /dev/frame0,
+          and /dev/control0.
+
+comment "Camera Sensor Selection"
+config MT9T013
+	bool "Sensor mt9t013 (BAYER 3M)"
+	depends on MSM_CAMERA && !ARCH_MSM8X60 && !ARCH_MSM8960 && !MSM_CAMERA_V4L2
+	default y
+	---help---
+	  MICRON 3M Bayer Sensor with AutoFocus
+config MT9D113
+	bool "Sensor mt9d113 (YUV 2M)"
+	depends on MSM_CAMERA && ARCH_MSM8X60 && !MSM_CAMERA_V4L2
+	default y
+	---help---
+	  MICRON 2M YUV Sensor
+	  This sensor is the front camera on QT8660.
+	  This uses csi mipi interface.
+	  This sensor is used only on QT device.
+config MT9D112
+	bool "Sensor mt9d112 (YUV 2M)"
+	depends on MSM_CAMERA && !ARCH_MSM8X60 && !ARCH_MSM8960 && !MSM_CAMERA_V4L2
+	default y
+	---help---
+	  MICRON 2M YUV Sensor
+config IMX074
+	bool "Sensor IMX074 (BAYER 13.5M)"
+	depends on MSM_CAMERA && (ARCH_MSM8X60 || ARCH_MSM8960)
+	default y
+	---help---
+	SONY 13.5 MP Bayer Sensor
+config WEBCAM_OV7692
+	bool "Sensor OV7692 (VGA YUV)"
+	depends on MSM_CAMERA && ARCH_MSM8X60 && !MSM_CAMERA_V4L2
+	default y
+	---help---
+	  Omni Vision VGA YUV Sensor.
+config WEBCAM_OV9726
+	bool "Sensor OV9726 (VGA Bayer)"
+	depends on MSM_CAMERA && (ARCH_MSM8X60 || ARCH_MSM7X30 || ARCH_MSM7X27A) && !MSM_CAMERA_V4L2
+	default n
+	---help---
+	  Omni Vision VGA Bayer Sensor.
+#	This Senosr is used as a webcam.
+#	This uses the CSI interface.
+config VX6953
+	bool "Sensor VX6953 (BAYER 5M)"
+	depends on MSM_CAMERA && ARCH_MSM7X30
+	default y
+	---help---
+	STM 5M Bayer Sensor with EDOF
+config SN12M0PZ
+	bool "Sensor sn12m0pz (Bayer 12 MP)"
+	depends on MSM_CAMERA && ARCH_MSM7X30 && !MSM_CAMERA_V4L2
+	default y
+	---help---
+	  Sony 12 MP Bayer Sensor
+config MT9P012
+	bool "Sensor mt9p012 (BAYER 5M)"
+	depends on MSM_CAMERA && !ARCH_MSM8X60 && !MSM_CAMERA_V4L2
+	default y
+	---help---
+	  MICRON 5M Bayer Sensor with Autofocus
+
+choice
+	prompt "AF module"
+	depends on MT9P012 && !ARCH_MSM8X60 && !MSM_CAMERA_V4L2
+	default MSM_CAMERA_AF_FOXCONN
+
+config MSM_CAMERA_AF_FOXCONN
+	bool "FOXCONN Module"
+	help
+	  This driver supports FOXCONN AF module for 5M Bayer sensor
+
+config MSM_CAMERA_AF_BAM
+	bool "BAM Module"
+	help
+	  This driver supports BAM AF module for 5M Bayer sensor
+
+endchoice
+
+config MT9P012_KM
+	bool "Sensor mt9p012 KM module (BAYER 5M)"
+	depends on MSM_CAMERA && !ARCH_MSM8X60 && !MSM_CAMERA_V4L2
+	default y
+	---help---
+	  MICRON 5M Bayer Sensor KM modules with Autofocus
+
+config MT9E013
+	bool "Sensor mt9e013 module (BAYER 8M)"
+	depends on MSM_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_MSM7X27A) && !MSM_CAMERA_V4L2
+	default n
+	---help---
+	  Aptina 8M Bayer Sensor modules with Autofocus
+
+config S5K3E2FX
+	bool "Sensor s5k3e2fx (Samsung 5M)"
+	depends on MSM_CAMERA && !ARCH_MSM8X60 && !MSM_CAMERA_V4L2
+	default y
+	---help---
+	  Samsung 5M with Autofocus
+
+config QS_S5K4E1
+	bool "Sensor qs_s5k4e1 (Samsung 5M)"
+	depends on MSM_CAMERA && ARCH_MSM8X60 && !MSM_CAMERA_V4L2
+	default y
+	---help---
+	  Samsung 5M with Autofocus
+
+config S5K4E1
+	bool "Sensor Sensor s5k4e1 (Samsung 5M)"
+	depends on MSM_CAMERA
+	default n
+	---help---
+	  Support for S5k4E1 samsung sensor driver.
+	  It is a Bayer 5MP sensor with auto focus and it supports
+	  two mipi lanes, required for msm7x2xA platform.
+	  Say Y here if this is msm7x2xA variant platform.
+
+config MSM_CAMERA_FLASH_SC628A
+	bool "Qualcomm MSM camera sc628a flash support"
+	depends on MSM_CAMERA
+	default n
+	---help---
+	  Enable support for LED flash for msm camera.
+	  It is a samtech charge pump flash driver and it
+	  supports spotlight and flash light modes with
+	  differrent current levels.
+
+config IMX072
+	bool "Sensor imx072 (Sony 5M)"
+	default n
+	---help---
+	  Support for IMX072 sony sensor driver.
+	  It is a Bayer 5MP sensor with auto focus and it supports
+	  two mipi lanes, required for msm7x2xA platform.
+	  Say Y here if this is msm7x2xA variant platform.
+
+config OV2720
+	bool "Sensor ov2720 (Omnivision 2MP)"
+	depends on MSM_CAMERA && ARCH_MSM8960
+	default y
+
+config VB6801
+	bool "Sensor vb6801"
+	depends on MSM_CAMERA && !ARCH_MSM8X60 && !MSM_CAMERA_V4L2
+	---help---
+	  5M with flash
+
+config MSM_CAMERA_FLASH
+	bool "Qualcomm MSM camera flash support"
+	depends on MSM_CAMERA
+	default y
+	---help---
+	  Enable support for LED flash for msm camera
+
+config MSM_CAMERA_SENSOR
+	bool "Qualcomm MSM camera sensor support"
+	depends on MSM_CAMERA
+	default y
+
+config MSM_GEMINI
+	tristate "Qualcomm MSM Gemini Jpeg Engine support"
+	depends on MSM_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_MSM8960)
+	default n
+	---help---
+	  Enable support for Gemini Jpeg Engine
+
+config MSM_VPE
+	tristate "Qualcomm MSM Video Pre-processing Engine support"
+	depends on MSM_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60)
+	default y
+	---help---
+	  Enable support for Video Pre-processing Engine
+
+config QUP_EXCLUSIVE_TO_CAMERA
+	bool "QUP exclusive to camera"
+	depends on MSM_CAMERA
+	default y
+	---help---
+	  This flag enabled states that QUP
+	  is exclusive to camera. In case this
+	  is disabled, the lvs1 voltage is enabled
+	  by QUP in the board file as QUP is used by
+	  applications other than camera.
+
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
new file mode 100644
index 0000000..c366834
--- /dev/null
+++ b/drivers/media/video/msm/Makefile
@@ -0,0 +1,46 @@
+GCC_VERSION      := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
+ifeq ($(GCC_VERSION),0404)
+CFLAGS_REMOVE_msm_vfe8x.o = -Wframe-larger-than=1024
+endif
+
+ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
+  obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o
+else
+  obj-$(CONFIG_MSM_CAMERA) += msm_camera.o
+endif
+obj-$(CONFIG_MSM_CAMERA) += msm_axi_qos.o
+obj-$(CONFIG_MSM_CAMERA_FLASH) += flash.o
+obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor.o
+obj-$(CONFIG_ARCH_MSM_ARM11) += msm_vfe7x.o msm_io7x.o
+obj-$(CONFIG_ARCH_MSM7X27A) += msm_vfe7x27a.o msm_io_7x27a.o
+obj-$(CONFIG_ARCH_MSM7X30) += msm_vfe31.o msm_io_vfe31.o msm_vpe1.o
+obj-$(CONFIG_ARCH_QSD8X50) += msm_vfe8x.o msm_vfe8x_proc.o msm_io8x.o
+obj-$(CONFIG_ARCH_MSM8X60) += msm_vfe31.o msm_io_8x60.o msm_vpe1.o
+obj-$(CONFIG_ARCH_MSM8960) += msm_io_8960.o msm_ispif.o msm_vfe32.o msm_vpe1.o
+obj-$(CONFIG_MT9T013) += mt9t013.o mt9t013_reg.o
+obj-$(CONFIG_SN12M0PZ) += sn12m0pz.o sn12m0pz_reg.o
+obj-$(CONFIG_MT9P012) += mt9p012_reg.o
+obj-$(CONFIG_MSM_CAMERA_AF_FOXCONN) += mt9p012_fox.o
+obj-$(CONFIG_MSM_CAMERA_AF_BAM) += mt9p012_bam.o
+obj-$(CONFIG_MT9P012_KM) += mt9p012_km.o mt9p012_km_reg.o
+obj-$(CONFIG_MT9E013) += mt9e013.o mt9e013_reg.o
+obj-$(CONFIG_S5K3E2FX) += s5k3e2fx.o
+obj-$(CONFIG_S5K4E1) += s5k4e1.o s5k4e1_reg.o
+#FIXME: Merge the two ifeq causes VX6953 preview not coming up.
+ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
+  obj-$(CONFIG_VX6953) += vx6953_v4l2.o vx6953_reg_v4l2.o
+  obj-$(CONFIG_IMX074) += imx074_v4l2.o imx074_reg.o
+else
+  obj-$(CONFIG_VX6953) += vx6953.o vx6953_reg.o
+  obj-$(CONFIG_IMX074) += imx074.o imx074_reg.o
+endif
+obj-$(CONFIG_QS_S5K4E1) += qs_s5k4e1.o qs_s5k4e1_reg.o
+obj-$(CONFIG_VB6801) += vb6801.o
+obj-$(CONFIG_IMX072) += imx072.o imx072_reg.o
+obj-$(CONFIG_OV2720) += ov2720.o
+obj-$(CONFIG_WEBCAM_OV9726) += ov9726.o ov9726_reg.o
+obj-$(CONFIG_WEBCAM_OV7692) += ov7692.o
+obj-$(CONFIG_MT9D112) += mt9d112.o mt9d112_reg.o
+
+obj-$(CONFIG_MT9D113) += mt9d113.o mt9d113_reg.o
+obj-$(CONFIG_MSM_GEMINI) += msm_gemini_dev.o msm_gemini_sync.o msm_gemini_core.o msm_gemini_hw.o msm_gemini_platform.o
diff --git a/drivers/media/video/msm/flash.c b/drivers/media/video/msm/flash.c
new file mode 100644
index 0000000..cd81125
--- /dev/null
+++ b/drivers/media/video/msm/flash.c
@@ -0,0 +1,563 @@
+
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/leds-pmic8058.h>
+#include <linux/pwm.h>
+#include <linux/pmic8058-pwm.h>
+#include <linux/hrtimer.h>
+#include <linux/i2c.h>
+#include <mach/pmic.h>
+#include <mach/camera.h>
+#include <mach/gpio.h>
+
+struct timer_list timer_flash;
+
+enum msm_cam_flash_stat{
+	MSM_CAM_FLASH_OFF,
+	MSM_CAM_FLASH_ON,
+};
+
+#if defined CONFIG_MSM_CAMERA_FLASH_SC628A
+static struct sc628a_work_t *sc628a_flash;
+static struct i2c_client *sc628a_client;
+static DECLARE_WAIT_QUEUE_HEAD(sc628a_wait_queue);
+
+struct sc628a_work_t {
+	struct work_struct work;
+};
+
+static const struct i2c_device_id sc628a_i2c_id[] = {
+	{"sc628a", 0},
+	{ }
+};
+
+static int32_t sc628a_i2c_txdata(unsigned short saddr,
+		unsigned char *txdata, int length)
+{
+	struct i2c_msg msg[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = length,
+			.buf = txdata,
+		},
+	};
+	if (i2c_transfer(sc628a_client->adapter, msg, 1) < 0) {
+		pr_err("sc628a_i2c_txdata faild 0x%x\n", saddr);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t sc628a_i2c_write_b_flash(uint8_t waddr, uint8_t bdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[2];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = waddr;
+	buf[1] = bdata;
+
+	rc = sc628a_i2c_txdata(sc628a_client->addr, buf, 2);
+	if (rc < 0) {
+		pr_err("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+				waddr, bdata);
+	}
+	return rc;
+}
+
+static int sc628a_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&sc628a_wait_queue);
+	return 0;
+}
+
+static int sc628a_i2c_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	int rc = 0;
+	CDBG("sc628a_probe called!\n");
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	sc628a_flash = kzalloc(sizeof(struct sc628a_work_t), GFP_KERNEL);
+	if (!sc628a_flash) {
+		pr_err("kzalloc failed.\n");
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, sc628a_flash);
+	sc628a_init_client(client);
+	sc628a_client = client;
+
+	msleep(50);
+
+	CDBG("sc628a_probe successed! rc = %d\n", rc);
+	return 0;
+
+probe_failure:
+	pr_err("sc628a_probe failed! rc = %d\n", rc);
+	return rc;
+}
+
+static struct i2c_driver sc628a_i2c_driver = {
+	.id_table = sc628a_i2c_id,
+	.probe  = sc628a_i2c_probe,
+	.remove = __exit_p(sc628a_i2c_remove),
+	.driver = {
+		.name = "sc628a",
+	},
+};
+#endif
+
+static int config_flash_gpio_table(enum msm_cam_flash_stat stat,
+			struct msm_camera_sensor_strobe_flash_data *sfdata)
+{
+	int rc = 0, i = 0;
+	int msm_cam_flash_gpio_tbl[][2] = {
+		{sfdata->flash_trigger, 1},
+		{sfdata->flash_charge, 1},
+		{sfdata->flash_charge_done, 0}
+	};
+
+	if (stat == MSM_CAM_FLASH_ON) {
+		for (i = 0; i < ARRAY_SIZE(msm_cam_flash_gpio_tbl); i++) {
+			rc = gpio_request(msm_cam_flash_gpio_tbl[i][0],
+							  "CAM_FLASH_GPIO");
+			if (unlikely(rc < 0)) {
+				pr_err("%s not able to get gpio\n", __func__);
+				for (i--; i >= 0; i--)
+					gpio_free(msm_cam_flash_gpio_tbl[i][0]);
+				break;
+			}
+			if (msm_cam_flash_gpio_tbl[i][1])
+				gpio_direction_output(
+					msm_cam_flash_gpio_tbl[i][0], 0);
+			else
+				gpio_direction_input(
+					msm_cam_flash_gpio_tbl[i][0]);
+		}
+	} else {
+		for (i = 0; i < ARRAY_SIZE(msm_cam_flash_gpio_tbl); i++) {
+			gpio_direction_input(msm_cam_flash_gpio_tbl[i][0]);
+			gpio_free(msm_cam_flash_gpio_tbl[i][0]);
+		}
+	}
+	return rc;
+}
+
+int msm_camera_flash_current_driver(
+	struct msm_camera_sensor_flash_current_driver *current_driver,
+	unsigned led_state)
+{
+	int rc = 0;
+#if defined CONFIG_LEDS_PMIC8058
+	int idx;
+	const struct pmic8058_leds_platform_data *driver_channel =
+		current_driver->driver_channel;
+	int num_leds = driver_channel->num_leds;
+
+	CDBG("%s: led_state = %d\n", __func__, led_state);
+
+	/* Evenly distribute current across all channels */
+	switch (led_state) {
+	case MSM_CAMERA_LED_OFF:
+		for (idx = 0; idx < num_leds; ++idx) {
+			rc = pm8058_set_led_current(
+				driver_channel->leds[idx].id, 0);
+			if (rc < 0)
+				pr_err(
+					"%s: FAIL name = %s, rc = %d\n",
+					__func__,
+					driver_channel->leds[idx].name,
+					rc);
+		}
+		break;
+
+	case MSM_CAMERA_LED_LOW:
+		for (idx = 0; idx < num_leds; ++idx) {
+			rc = pm8058_set_led_current(
+				driver_channel->leds[idx].id,
+				current_driver->low_current/num_leds);
+			if (rc < 0)
+				pr_err(
+					"%s: FAIL name = %s, rc = %d\n",
+					__func__,
+					driver_channel->leds[idx].name,
+					rc);
+		}
+		break;
+
+	case MSM_CAMERA_LED_HIGH:
+		for (idx = 0; idx < num_leds; ++idx) {
+			rc = pm8058_set_led_current(
+				driver_channel->leds[idx].id,
+				current_driver->high_current/num_leds);
+			if (rc < 0)
+				pr_err(
+					"%s: FAIL name = %s, rc = %d\n",
+					__func__,
+					driver_channel->leds[idx].name,
+					rc);
+		}
+		break;
+
+	default:
+		rc = -EFAULT;
+		break;
+	}
+	CDBG("msm_camera_flash_led_pmic8058: return %d\n", rc);
+#endif /* CONFIG_LEDS_PMIC8058 */
+#if defined CONFIG_MSM_CAMERA_FLASH_SC628A
+	if (!sc628a_client) {
+		rc = i2c_add_driver(&sc628a_i2c_driver);
+		if (rc < 0 || sc628a_client == NULL) {
+			rc = -ENOTSUPP;
+			pr_err("I2C add driver failed");
+			return rc;
+		}
+		rc = gpio_request(current_driver->led1, "sc628a");
+		if (!rc) {
+			gpio_direction_output(current_driver->led1, 0);
+			gpio_set_value_cansleep(current_driver->led1, 1);
+		} else
+			i2c_del_driver(&sc628a_i2c_driver);
+		rc = gpio_request(current_driver->led2, "sc628a");
+		if (!rc) {
+			gpio_direction_output(current_driver->led2, 0);
+			gpio_set_value_cansleep(current_driver->led2, 1);
+		} else {
+			i2c_del_driver(&sc628a_i2c_driver);
+			gpio_free(current_driver->led1);
+		}
+	}
+	switch (led_state) {
+	case MSM_CAMERA_LED_OFF:
+		sc628a_i2c_write_b_flash(0x02, 0x0);
+		break;
+	case MSM_CAMERA_LED_LOW:
+		sc628a_i2c_write_b_flash(0x02, 0x06);
+		break;
+	case MSM_CAMERA_LED_HIGH:
+		sc628a_i2c_write_b_flash(0x02, 0x49);
+		break;
+	default:
+		rc = -EFAULT;
+		break;
+	}
+#endif
+
+	return rc;
+}
+
+
+static int msm_camera_flash_pwm(
+	struct msm_camera_sensor_flash_pwm *pwm,
+	unsigned led_state)
+{
+	int rc = 0;
+	int PWM_PERIOD = USEC_PER_SEC / pwm->freq;
+
+	static struct pwm_device *flash_pwm;
+
+	if (!flash_pwm) {
+		flash_pwm = pwm_request(pwm->channel, "camera-flash");
+		if (flash_pwm == NULL || IS_ERR(flash_pwm)) {
+			pr_err("%s: FAIL pwm_request(): flash_pwm=%p\n",
+			       __func__, flash_pwm);
+			flash_pwm = NULL;
+			return -ENXIO;
+		}
+	}
+
+	switch (led_state) {
+	case MSM_CAMERA_LED_LOW:
+		rc = pwm_config(flash_pwm,
+			(PWM_PERIOD/pwm->max_load)*pwm->low_load,
+			PWM_PERIOD);
+		if (rc >= 0)
+			rc = pwm_enable(flash_pwm);
+		break;
+
+	case MSM_CAMERA_LED_HIGH:
+		rc = pwm_config(flash_pwm,
+			(PWM_PERIOD/pwm->max_load)*pwm->high_load,
+			PWM_PERIOD);
+		if (rc >= 0)
+			rc = pwm_enable(flash_pwm);
+		break;
+
+	case MSM_CAMERA_LED_OFF:
+		pwm_disable(flash_pwm);
+		break;
+
+	default:
+		rc = -EFAULT;
+		break;
+	}
+
+	return rc;
+}
+
+int msm_camera_flash_pmic(
+	struct msm_camera_sensor_flash_pmic *pmic,
+	unsigned led_state)
+{
+	int rc = 0;
+
+	switch (led_state) {
+	case MSM_CAMERA_LED_OFF:
+		rc = pmic->pmic_set_current(pmic->led_src_1, 0);
+		if (pmic->num_of_src > 1)
+			rc = pmic->pmic_set_current(pmic->led_src_2, 0);
+		break;
+
+	case MSM_CAMERA_LED_LOW:
+		rc = pmic->pmic_set_current(pmic->led_src_1,
+				pmic->low_current);
+		if (pmic->num_of_src > 1)
+			rc = pmic->pmic_set_current(pmic->led_src_2, 0);
+		break;
+
+	case MSM_CAMERA_LED_HIGH:
+		rc = pmic->pmic_set_current(pmic->led_src_1,
+			pmic->high_current);
+		if (pmic->num_of_src > 1)
+			rc = pmic->pmic_set_current(pmic->led_src_2,
+				pmic->high_current);
+		break;
+
+	default:
+		rc = -EFAULT;
+		break;
+	}
+	CDBG("flash_set_led_state: return %d\n", rc);
+
+	return rc;
+}
+
+int32_t msm_camera_flash_set_led_state(
+	struct msm_camera_sensor_flash_data *fdata, unsigned led_state)
+{
+	int32_t rc;
+
+	CDBG("flash_set_led_state: %d flash_sr_type=%d\n", led_state,
+	    fdata->flash_src->flash_sr_type);
+
+	if (fdata->flash_type != MSM_CAMERA_FLASH_LED)
+		return -ENODEV;
+
+	switch (fdata->flash_src->flash_sr_type) {
+	case MSM_CAMERA_FLASH_SRC_PMIC:
+		rc = msm_camera_flash_pmic(&fdata->flash_src->_fsrc.pmic_src,
+			led_state);
+		break;
+
+	case MSM_CAMERA_FLASH_SRC_PWM:
+		rc = msm_camera_flash_pwm(&fdata->flash_src->_fsrc.pwm_src,
+			led_state);
+		break;
+
+	case MSM_CAMERA_FLASH_SRC_CURRENT_DRIVER:
+		rc = msm_camera_flash_current_driver(
+			&fdata->flash_src->_fsrc.current_driver_src,
+			led_state);
+		break;
+
+	default:
+		rc = -ENODEV;
+		break;
+	}
+
+	return rc;
+}
+
+static int msm_strobe_flash_xenon_charge(int32_t flash_charge,
+		int32_t charge_enable, uint32_t flash_recharge_duration)
+{
+	gpio_set_value_cansleep(flash_charge, charge_enable);
+	if (charge_enable) {
+		timer_flash.expires = jiffies +
+			msecs_to_jiffies(flash_recharge_duration);
+		/* add timer for the recharge */
+		if (!timer_pending(&timer_flash))
+			add_timer(&timer_flash);
+	} else
+		del_timer_sync(&timer_flash);
+	return 0;
+}
+
+static void strobe_flash_xenon_recharge_handler(unsigned long data)
+{
+	unsigned long flags;
+	struct msm_camera_sensor_strobe_flash_data *sfdata =
+		(struct msm_camera_sensor_strobe_flash_data *)data;
+
+	spin_lock_irqsave(&sfdata->timer_lock, flags);
+	msm_strobe_flash_xenon_charge(sfdata->flash_charge, 1,
+		sfdata->flash_recharge_duration);
+	spin_unlock_irqrestore(&sfdata->timer_lock, flags);
+
+	return;
+}
+
+static irqreturn_t strobe_flash_charge_ready_irq(int irq_num, void *data)
+{
+	struct msm_camera_sensor_strobe_flash_data *sfdata =
+		(struct msm_camera_sensor_strobe_flash_data *)data;
+
+	/* put the charge signal to low */
+	gpio_set_value_cansleep(sfdata->flash_charge, 0);
+
+	return IRQ_HANDLED;
+}
+
+static int msm_strobe_flash_xenon_init(
+	struct msm_camera_sensor_strobe_flash_data *sfdata)
+{
+	unsigned long flags;
+	int rc = 0;
+
+	spin_lock_irqsave(&sfdata->spin_lock, flags);
+	if (!sfdata->state) {
+
+		rc = config_flash_gpio_table(MSM_CAM_FLASH_ON, sfdata);
+		if (rc < 0) {
+			pr_err("%s: gpio_request failed\n", __func__);
+			goto go_out;
+		}
+		rc = request_irq(sfdata->irq, strobe_flash_charge_ready_irq,
+			IRQF_TRIGGER_RISING, "charge_ready", sfdata);
+		if (rc < 0) {
+			pr_err("%s: request_irq failed %d\n", __func__, rc);
+			goto go_out;
+		}
+
+		spin_lock_init(&sfdata->timer_lock);
+		/* setup timer */
+		init_timer(&timer_flash);
+		timer_flash.function = strobe_flash_xenon_recharge_handler;
+		timer_flash.data = (unsigned long)sfdata;
+	}
+	sfdata->state++;
+go_out:
+	spin_unlock_irqrestore(&sfdata->spin_lock, flags);
+
+	return rc;
+}
+
+static int msm_strobe_flash_xenon_release
+(struct msm_camera_sensor_strobe_flash_data *sfdata, int32_t final_release)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&sfdata->spin_lock, flags);
+	if (sfdata->state > 0) {
+		if (final_release)
+			sfdata->state = 0;
+		else
+			sfdata->state--;
+
+		if (!sfdata->state) {
+			free_irq(sfdata->irq, sfdata);
+			config_flash_gpio_table(MSM_CAM_FLASH_OFF, sfdata);
+			if (timer_pending(&timer_flash))
+				del_timer_sync(&timer_flash);
+		}
+	}
+	spin_unlock_irqrestore(&sfdata->spin_lock, flags);
+	return 0;
+}
+
+static void msm_strobe_flash_xenon_fn_init
+	(struct msm_strobe_flash_ctrl *strobe_flash_ptr)
+{
+	strobe_flash_ptr->strobe_flash_init =
+				msm_strobe_flash_xenon_init;
+	strobe_flash_ptr->strobe_flash_charge =
+				msm_strobe_flash_xenon_charge;
+	strobe_flash_ptr->strobe_flash_release =
+				msm_strobe_flash_xenon_release;
+}
+
+int msm_strobe_flash_init(struct msm_sync *sync, uint32_t sftype)
+{
+	int rc = 0;
+	switch (sftype) {
+	case MSM_CAMERA_STROBE_FLASH_XENON:
+		if (sync->sdata->strobe_flash_data) {
+			msm_strobe_flash_xenon_fn_init(&sync->sfctrl);
+			rc = sync->sfctrl.strobe_flash_init(
+			sync->sdata->strobe_flash_data);
+		} else
+			return -ENODEV;
+		break;
+	default:
+		rc = -ENODEV;
+	}
+	return rc;
+}
+
+int msm_strobe_flash_ctrl(struct msm_camera_sensor_strobe_flash_data *sfdata,
+	struct strobe_flash_ctrl_data *strobe_ctrl)
+{
+	int rc = 0;
+	switch (strobe_ctrl->type) {
+	case STROBE_FLASH_CTRL_INIT:
+		if (!sfdata)
+			return -ENODEV;
+		rc = msm_strobe_flash_xenon_init(sfdata);
+		break;
+	case STROBE_FLASH_CTRL_CHARGE:
+		rc = msm_strobe_flash_xenon_charge(sfdata->flash_charge,
+			strobe_ctrl->charge_en,
+			sfdata->flash_recharge_duration);
+		break;
+	case STROBE_FLASH_CTRL_RELEASE:
+		if (sfdata)
+			rc = msm_strobe_flash_xenon_release(sfdata, 0);
+		break;
+	default:
+		pr_err("Invalid Strobe Flash State\n");
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+int msm_flash_ctrl(struct msm_camera_sensor_info *sdata,
+	struct flash_ctrl_data *flash_info)
+{
+	int rc = 0;
+	switch (flash_info->flashtype) {
+	case LED_FLASH:
+		rc = msm_camera_flash_set_led_state(sdata->flash_data,
+			flash_info->ctrl_data.led_state);
+			break;
+	case STROBE_FLASH:
+		rc = msm_strobe_flash_ctrl(sdata->strobe_flash_data,
+			&(flash_info->ctrl_data.strobe_ctrl));
+		break;
+	default:
+		pr_err("Invalid Flash MODE\n");
+		rc = -EINVAL;
+	}
+	return rc;
+}
diff --git a/drivers/media/video/msm/imx072.c b/drivers/media/video/msm/imx072.c
new file mode 100644
index 0000000..d9ee051
--- /dev/null
+++ b/drivers/media/video/msm/imx072.c
@@ -0,0 +1,1164 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <media/msm_camera.h>
+#include <mach/gpio.h>
+#include <mach/camera.h>
+#include "imx072.h"
+
+/* SENSOR REGISTER DEFINES */
+#define REG_GROUPED_PARAMETER_HOLD		0x0104
+#define GROUPED_PARAMETER_HOLD_OFF		0x00
+#define GROUPED_PARAMETER_HOLD			0x01
+/* Integration Time */
+#define REG_COARSE_INTEGRATION_TIME		0x0202
+/* Gain */
+#define REG_GLOBAL_GAIN					0x0204
+
+/* PLL registers */
+#define REG_FRAME_LENGTH_LINES			0x0340
+#define REG_LINE_LENGTH_PCK				0x0342
+
+/* 16bit address - 8 bit context register structure */
+#define Q8  0x00000100
+#define Q10 0x00000400
+#define IMX072_MASTER_CLK_RATE 24000000
+#define IMX072_OFFSET		3
+
+/* AF Total steps parameters */
+#define IMX072_AF_I2C_ADDR	0x18
+#define IMX072_TOTAL_STEPS_NEAR_TO_FAR    30
+
+static uint16_t imx072_step_position_table[IMX072_TOTAL_STEPS_NEAR_TO_FAR+1];
+static uint16_t imx072_nl_region_boundary1;
+static uint16_t imx072_nl_region_code_per_step1;
+static uint16_t imx072_l_region_code_per_step = 12;
+static uint16_t imx072_sw_damping_time_wait = 8;
+static uint16_t imx072_af_initial_code = 350;
+static uint16_t imx072_damping_threshold = 10;
+
+struct imx072_work_t {
+	struct work_struct work;
+};
+
+static struct imx072_work_t *imx072_sensorw;
+static struct i2c_client *imx072_client;
+
+struct imx072_ctrl_t {
+	const struct  msm_camera_sensor_info *sensordata;
+
+	uint32_t sensormode;
+	uint32_t fps_divider;/* init to 1 * 0x00000400 */
+	uint32_t pict_fps_divider;/* init to 1 * 0x00000400 */
+	uint16_t fps;
+
+	uint16_t curr_lens_pos;
+	uint16_t curr_step_pos;
+	uint16_t my_reg_gain;
+	uint32_t my_reg_line_count;
+	uint16_t total_lines_per_frame;
+
+	enum imx072_resolution_t prev_res;
+	enum imx072_resolution_t pict_res;
+	enum imx072_resolution_t curr_res;
+	enum imx072_test_mode_t  set_test;
+	enum imx072_cam_mode_t cam_mode;
+};
+
+static uint16_t prev_line_length_pck;
+static uint16_t prev_frame_length_lines;
+static uint16_t snap_line_length_pck;
+static uint16_t snap_frame_length_lines;
+
+static bool CSI_CONFIG;
+static struct imx072_ctrl_t *imx072_ctrl;
+static DECLARE_WAIT_QUEUE_HEAD(imx072_wait_queue);
+DEFINE_MUTEX(imx072_mut);
+
+#ifdef CONFIG_DEBUG_FS
+static int cam_debug_init(void);
+static struct dentry *debugfs_base;
+#endif
+
+static int imx072_i2c_rxdata(unsigned short saddr,
+	unsigned char *rxdata, int length)
+{
+	struct i2c_msg msgs[] = {
+		{
+			.addr  = saddr,
+			.flags = 0,
+			.len   = length,
+			.buf   = rxdata,
+		},
+		{
+			.addr  = saddr,
+			.flags = I2C_M_RD,
+			.len   = length,
+			.buf   = rxdata,
+		},
+	};
+	if (i2c_transfer(imx072_client->adapter, msgs, 2) < 0) {
+		pr_err("imx072_i2c_rxdata faild 0x%x\n", saddr);
+		return -EIO;
+	}
+	return 0;
+}
+
+static int32_t imx072_i2c_txdata(unsigned short saddr,
+				unsigned char *txdata, int length)
+{
+	struct i2c_msg msg[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = length,
+			.buf = txdata,
+		 },
+	};
+	if (i2c_transfer(imx072_client->adapter, msg, 1) < 0) {
+		pr_err("imx072_i2c_txdata faild 0x%x\n", saddr);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t imx072_i2c_read(unsigned short raddr,
+	unsigned short *rdata, int rlen)
+{
+	int32_t rc = 0;
+	unsigned char buf[2];
+	if (!rdata)
+		return -EIO;
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (raddr & 0xFF00) >> 8;
+	buf[1] = (raddr & 0x00FF);
+	rc = imx072_i2c_rxdata(imx072_client->addr>>1, buf, rlen);
+	if (rc < 0) {
+		pr_err("imx072_i2c_read 0x%x failed!\n", raddr);
+		return rc;
+	}
+	*rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]);
+	CDBG("imx072_i2c_read 0x%x val = 0x%x!\n", raddr, *rdata);
+	return rc;
+}
+
+static int32_t imx072_i2c_write_w_sensor(unsigned short waddr,
+	uint16_t wdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[4];
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = (wdata & 0xFF00) >> 8;
+	buf[3] = (wdata & 0x00FF);
+	CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, wdata);
+	rc = imx072_i2c_txdata(imx072_client->addr>>1, buf, 4);
+	if (rc < 0) {
+		pr_err("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+			waddr, wdata);
+	}
+	return rc;
+}
+
+static int32_t imx072_i2c_write_b_sensor(unsigned short waddr,
+	uint8_t bdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[3];
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = bdata;
+	CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata);
+	rc = imx072_i2c_txdata(imx072_client->addr>>1, buf, 3);
+	if (rc < 0)
+		pr_err("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+			waddr, bdata);
+	return rc;
+}
+
+static int32_t imx072_i2c_write_b_af(uint8_t msb, uint8_t lsb)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[2];
+
+	buf[0] = msb;
+	buf[1] = lsb;
+	rc = imx072_i2c_txdata(IMX072_AF_I2C_ADDR>>1, buf, 2);
+	if (rc < 0)
+		pr_err("af_i2c_write faield msb = 0x%x lsb = 0x%x",
+			msb, lsb);
+	return rc;
+}
+
+static int32_t imx072_i2c_write_w_table(struct imx072_i2c_reg_conf const
+					 *reg_conf_tbl, int num)
+{
+	int i;
+	int32_t rc = -EIO;
+	for (i = 0; i < num; i++) {
+		rc = imx072_i2c_write_b_sensor(reg_conf_tbl->waddr,
+			reg_conf_tbl->wdata);
+		if (rc < 0)
+			break;
+		reg_conf_tbl++;
+	}
+	return rc;
+}
+
+static void imx072_group_hold_on(void)
+{
+	imx072_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
+						GROUPED_PARAMETER_HOLD);
+}
+
+static void imx072_group_hold_off(void)
+{
+	imx072_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
+						GROUPED_PARAMETER_HOLD_OFF);
+}
+
+static void imx072_start_stream(void)
+{
+	imx072_i2c_write_b_sensor(0x0100, 0x01);
+}
+
+static void imx072_stop_stream(void)
+{
+	imx072_i2c_write_b_sensor(0x0100, 0x00);
+}
+
+static void imx072_get_pict_fps(uint16_t fps, uint16_t *pfps)
+{
+	/* input fps is preview fps in Q8 format */
+	uint32_t divider, d1, d2;
+
+	d1 = prev_frame_length_lines * 0x00000400 / snap_frame_length_lines;
+	d2 = prev_line_length_pck * 0x00000400 / snap_line_length_pck;
+	divider = d1 * d2 / 0x400;
+
+	/*Verify PCLK settings and frame sizes.*/
+	*pfps = (uint16_t) (fps * divider / 0x400);
+}
+
+static uint16_t imx072_get_prev_lines_pf(void)
+{
+	return prev_frame_length_lines;
+}
+
+static uint16_t imx072_get_prev_pixels_pl(void)
+{
+	return prev_line_length_pck;
+}
+
+static uint16_t imx072_get_pict_lines_pf(void)
+{
+	return snap_frame_length_lines;
+}
+
+static uint16_t imx072_get_pict_pixels_pl(void)
+{
+	return snap_line_length_pck;
+}
+
+static uint32_t imx072_get_pict_max_exp_lc(void)
+{
+	return snap_frame_length_lines  * 24;
+}
+
+static int32_t imx072_set_fps(struct fps_cfg   *fps)
+{
+	uint16_t total_lines_per_frame;
+	int32_t rc = 0;
+	total_lines_per_frame = (uint16_t)
+		((prev_frame_length_lines *
+		imx072_ctrl->fps_divider)/0x400);
+	imx072_ctrl->fps_divider = fps->fps_div;
+	imx072_ctrl->pict_fps_divider = fps->pict_fps_div;
+
+	imx072_group_hold_on();
+	rc = imx072_i2c_write_w_sensor(REG_FRAME_LENGTH_LINES,
+							total_lines_per_frame);
+	imx072_group_hold_off();
+	return rc;
+}
+
+static int32_t imx072_write_exp_gain(uint16_t gain, uint32_t line)
+{
+	uint32_t fl_lines = 0;
+	uint8_t offset;
+	int32_t rc = 0;
+	if (imx072_ctrl->curr_res == imx072_ctrl->prev_res)
+		fl_lines = prev_frame_length_lines;
+	else if (imx072_ctrl->curr_res == imx072_ctrl->pict_res)
+		fl_lines = snap_frame_length_lines;
+	line = (line * imx072_ctrl->fps_divider) / Q10;
+	offset = IMX072_OFFSET;
+	if (line > (fl_lines - offset))
+		fl_lines = line + offset;
+
+	imx072_group_hold_on();
+	rc = imx072_i2c_write_w_sensor(REG_FRAME_LENGTH_LINES, fl_lines);
+	rc = imx072_i2c_write_w_sensor(REG_COARSE_INTEGRATION_TIME, line);
+	rc = imx072_i2c_write_w_sensor(REG_GLOBAL_GAIN, gain);
+	imx072_group_hold_off();
+	return rc;
+}
+
+static int32_t imx072_set_pict_exp_gain(uint16_t gain, uint32_t line)
+{
+	int32_t rc = 0;
+	rc = imx072_write_exp_gain(gain, line);
+	return rc;
+}
+
+static int32_t imx072_sensor_setting(int update_type, int rt)
+{
+
+	int32_t rc = 0;
+	struct msm_camera_csi_params imx072_csi_params;
+
+	imx072_stop_stream();
+	msleep(30);
+	if (update_type == REG_INIT) {
+		msleep(20);
+		CSI_CONFIG = 0;
+		imx072_i2c_write_w_table(imx072_regs.rec_settings,
+			imx072_regs.rec_size);
+	} else if (update_type == UPDATE_PERIODIC) {
+#ifdef CONFIG_DEBUG_FS
+		cam_debug_init();
+#endif
+		msleep(20);
+		if (!CSI_CONFIG) {
+			imx072_csi_params.lane_cnt = 2;
+			imx072_csi_params.data_format = CSI_10BIT;
+			imx072_csi_params.lane_assign = 0xe4;
+			imx072_csi_params.dpcm_scheme = 0;
+			imx072_csi_params.settle_cnt = 0x18;
+			msm_camio_vfe_clk_rate_set(192000000);
+			rc = msm_camio_csi_config(&imx072_csi_params);
+			msleep(100);
+			CSI_CONFIG = 1;
+		}
+		imx072_i2c_write_w_table(
+			imx072_regs.conf_array[rt].conf,
+			imx072_regs.conf_array[rt].size);
+		imx072_start_stream();
+		msleep(30);
+	}
+	return rc;
+}
+
+static int32_t imx072_video_config(int mode)
+{
+
+	int32_t rc = 0;
+	/* change sensor resolution if needed */
+	if (imx072_sensor_setting(UPDATE_PERIODIC,
+		imx072_ctrl->prev_res) < 0)
+		return rc;
+
+	imx072_ctrl->curr_res = imx072_ctrl->prev_res;
+	imx072_ctrl->sensormode = mode;
+	return rc;
+}
+
+static int32_t imx072_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+	/*change sensor resolution if needed */
+	if (imx072_ctrl->curr_res != imx072_ctrl->pict_res) {
+		if (imx072_sensor_setting(UPDATE_PERIODIC,
+					imx072_ctrl->pict_res) < 0)
+			return rc;
+	}
+
+	imx072_ctrl->curr_res = imx072_ctrl->pict_res;
+	imx072_ctrl->sensormode = mode;
+	return rc;
+}
+
+static int32_t imx072_raw_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+	/* change sensor resolution if needed */
+	if (imx072_ctrl->curr_res != imx072_ctrl->pict_res) {
+		if (imx072_sensor_setting(UPDATE_PERIODIC,
+					imx072_ctrl->pict_res) < 0)
+			return rc;
+	}
+
+	imx072_ctrl->curr_res = imx072_ctrl->pict_res;
+	imx072_ctrl->sensormode = mode;
+	return rc;
+}
+
+static int32_t imx072_mode_init(int mode, struct sensor_init_cfg init_info)
+{
+	int32_t rc = 0;
+	CDBG("%s: %d\n", __func__, __LINE__);
+	if (mode != imx072_ctrl->cam_mode) {
+		imx072_ctrl->prev_res = init_info.prev_res;
+		imx072_ctrl->pict_res = init_info.pict_res;
+		imx072_ctrl->cam_mode = mode;
+
+		prev_frame_length_lines =
+			imx072_regs.conf_array[imx072_ctrl->prev_res].
+			conf[IMX072_FRAME_LENGTH_LINES_HI].wdata << 8 |
+			imx072_regs.conf_array[imx072_ctrl->prev_res].
+			conf[IMX072_FRAME_LENGTH_LINES_LO].wdata;
+		prev_line_length_pck =
+			imx072_regs.conf_array[imx072_ctrl->prev_res].
+			conf[IMX072_LINE_LENGTH_PCK_HI].wdata << 8 |
+			imx072_regs.conf_array[imx072_ctrl->prev_res].
+			conf[IMX072_LINE_LENGTH_PCK_LO].wdata;
+		snap_frame_length_lines =
+			imx072_regs.conf_array[imx072_ctrl->pict_res].
+			conf[IMX072_FRAME_LENGTH_LINES_HI].wdata << 8 |
+			imx072_regs.conf_array[imx072_ctrl->pict_res].
+			conf[IMX072_FRAME_LENGTH_LINES_LO].wdata;
+		snap_line_length_pck =
+			imx072_regs.conf_array[imx072_ctrl->pict_res].
+			conf[IMX072_LINE_LENGTH_PCK_HI].wdata << 8 |
+			imx072_regs.conf_array[imx072_ctrl->pict_res].
+			conf[IMX072_LINE_LENGTH_PCK_LO].wdata;
+
+		rc = imx072_sensor_setting(REG_INIT,
+			imx072_ctrl->prev_res);
+	}
+	return rc;
+}
+
+static int32_t imx072_set_sensor_mode(int mode,
+	int res)
+{
+	int32_t rc = 0;
+
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		imx072_ctrl->prev_res = res;
+		rc = imx072_video_config(mode);
+		break;
+	case SENSOR_SNAPSHOT_MODE:
+		imx072_ctrl->pict_res = res;
+		rc = imx072_snapshot_config(mode);
+		break;
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		imx072_ctrl->pict_res = res;
+		rc = imx072_raw_snapshot_config(mode);
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+#define DIV_CEIL(x, y) ((x/y + ((x%y) ? 1 : 0)))
+static int32_t imx072_move_focus(int direction,
+	int32_t num_steps)
+{
+	int32_t rc = 0;
+	int16_t step_direction, dest_lens_position, dest_step_position;
+	uint8_t code_val_msb, code_val_lsb;
+	int16_t next_lens_position, target_dist, small_step;
+
+	if (direction == MOVE_NEAR)
+		step_direction = 1;
+	else if (direction == MOVE_FAR)
+		step_direction = -1;
+	else {
+		pr_err("Illegal focus direction\n");
+		return -EINVAL;
+	}
+	dest_step_position = imx072_ctrl->curr_step_pos +
+			(step_direction * num_steps);
+
+	if (dest_step_position < 0)
+		dest_step_position = 0;
+	else if (dest_step_position > IMX072_TOTAL_STEPS_NEAR_TO_FAR)
+		dest_step_position = IMX072_TOTAL_STEPS_NEAR_TO_FAR;
+
+	if (dest_step_position == imx072_ctrl->curr_step_pos) {
+		CDBG("imx072 same position No-Move exit\n");
+		return rc;
+	}
+	CDBG("%s Index = [%d]\n", __func__, dest_step_position);
+
+	dest_lens_position = imx072_step_position_table[dest_step_position];
+	CDBG("%s lens_position value = %d\n", __func__, dest_lens_position);
+	target_dist = step_direction * (dest_lens_position -
+		imx072_ctrl->curr_lens_pos);
+	if (step_direction < 0 && (target_dist >=
+		(imx072_step_position_table[imx072_damping_threshold]
+			- imx072_af_initial_code))) {
+		small_step = DIV_CEIL(target_dist, 10);
+		imx072_sw_damping_time_wait = 30;
+	} else {
+		small_step = DIV_CEIL(target_dist, 4);
+		imx072_sw_damping_time_wait = 20;
+	}
+
+	CDBG("%s: small_step:%d, wait_time:%d\n", __func__, small_step,
+		imx072_sw_damping_time_wait);
+	for (next_lens_position = imx072_ctrl->curr_lens_pos +
+		(step_direction * small_step);
+		(step_direction * next_lens_position) <=
+		(step_direction * dest_lens_position);
+		next_lens_position += (step_direction * small_step)) {
+
+		code_val_msb = ((next_lens_position & 0x03F0) >> 4);
+		code_val_lsb = ((next_lens_position & 0x000F) << 4);
+		CDBG("position value = %d\n", next_lens_position);
+		CDBG("movefocus vcm_msb = %d\n", code_val_msb);
+		CDBG("movefocus vcm_lsb = %d\n", code_val_lsb);
+		rc = imx072_i2c_write_b_af(code_val_msb, code_val_lsb);
+		if (rc < 0) {
+			pr_err("imx072_move_focus failed writing i2c\n");
+			return rc;
+			}
+		imx072_ctrl->curr_lens_pos = next_lens_position;
+		usleep(imx072_sw_damping_time_wait*100);
+	}
+	if (imx072_ctrl->curr_lens_pos != dest_lens_position) {
+		code_val_msb = ((dest_lens_position & 0x03F0) >> 4);
+		code_val_lsb = ((dest_lens_position & 0x000F) << 4);
+		CDBG("position value = %d\n", dest_lens_position);
+		CDBG("movefocus vcm_msb = %d\n", code_val_msb);
+		CDBG("movefocus vcm_lsb = %d\n", code_val_lsb);
+		rc = imx072_i2c_write_b_af(code_val_msb, code_val_lsb);
+		if (rc < 0) {
+			pr_err("imx072_move_focus failed writing i2c\n");
+			return rc;
+			}
+		usleep(imx072_sw_damping_time_wait * 100);
+	}
+	imx072_ctrl->curr_lens_pos = dest_lens_position;
+	imx072_ctrl->curr_step_pos = dest_step_position;
+	return rc;
+
+}
+
+static int32_t imx072_init_focus(void)
+{
+	uint8_t i;
+	int32_t rc = 0;
+
+	imx072_step_position_table[0] = imx072_af_initial_code;
+	for (i = 1; i <= IMX072_TOTAL_STEPS_NEAR_TO_FAR; i++) {
+		if (i <= imx072_nl_region_boundary1)
+			imx072_step_position_table[i] =
+				imx072_step_position_table[i-1]
+				+ imx072_nl_region_code_per_step1;
+		else
+			imx072_step_position_table[i] =
+				imx072_step_position_table[i-1]
+				+ imx072_l_region_code_per_step;
+
+		if (imx072_step_position_table[i] > 1023)
+			imx072_step_position_table[i] = 1023;
+	}
+	imx072_ctrl->curr_lens_pos = 0;
+
+	return rc;
+}
+
+static int32_t imx072_set_default_focus(void)
+{
+	int32_t rc = 0;
+	uint8_t code_val_msb, code_val_lsb;
+	int16_t dest_lens_position = 0;
+
+	CDBG("%s Index = [%d]\n", __func__, 0);
+	if (imx072_ctrl->curr_step_pos != 0)
+		rc = imx072_move_focus(MOVE_FAR,
+		imx072_ctrl->curr_step_pos);
+	else {
+		dest_lens_position = imx072_af_initial_code;
+		code_val_msb = ((dest_lens_position & 0x03F0) >> 4);
+		code_val_lsb = ((dest_lens_position & 0x000F) << 4);
+
+		CDBG("position value = %d\n", dest_lens_position);
+		CDBG("movefocus vcm_msb = %d\n", code_val_msb);
+		CDBG("movefocus vcm_lsb = %d\n", code_val_lsb);
+		rc = imx072_i2c_write_b_af(code_val_msb, code_val_lsb);
+		if (rc < 0) {
+			pr_err("imx072_set_default_focus failed writing i2c\n");
+			return rc;
+		}
+
+		imx072_ctrl->curr_lens_pos = dest_lens_position;
+		imx072_ctrl->curr_step_pos = 0;
+
+	}
+	usleep(5000);
+	return rc;
+}
+
+static int32_t imx072_af_power_down(void)
+{
+	int32_t rc = 0;
+	int32_t i = 0;
+	int16_t dest_lens_position = imx072_af_initial_code;
+
+	if (imx072_ctrl->curr_lens_pos != 0) {
+		rc = imx072_set_default_focus();
+		CDBG("%s after imx072_set_default_focus\n", __func__);
+		msleep(40);
+		/*to avoid the sound during the power off.
+		brings the actuator to mechanical infinity gradually.*/
+		for (i = 0; i < IMX072_TOTAL_STEPS_NEAR_TO_FAR; i++) {
+			dest_lens_position = dest_lens_position -
+				(imx072_af_initial_code /
+					IMX072_TOTAL_STEPS_NEAR_TO_FAR);
+			CDBG("position value = %d\n", dest_lens_position);
+			rc = imx072_i2c_write_b_af(
+				((dest_lens_position & 0x03F0) >> 4),
+				((dest_lens_position & 0x000F) << 4));
+			CDBG("count = %d\n", i);
+			msleep(20);
+			if (rc < 0) {
+				pr_err("imx072_set_default_focus failed writing i2c\n");
+				return rc;
+			}
+		}
+		rc = imx072_i2c_write_b_af(0x00, 00);
+		msleep(40);
+	}
+	rc = imx072_i2c_write_b_af(0x80, 00);
+	return rc;
+}
+
+static int32_t imx072_power_down(void)
+{
+	int32_t rc = 0;
+
+	rc = imx072_af_power_down();
+	return rc;
+}
+
+static int imx072_probe_init_done(const struct msm_camera_sensor_info *data)
+{
+	pr_err("probe done\n");
+	gpio_free(data->sensor_reset);
+	return 0;
+}
+
+static int imx072_probe_init_sensor(
+	const struct msm_camera_sensor_info *data)
+{
+	int32_t rc = 0;
+	uint16_t chipid = 0;
+
+	CDBG("%s: %d\n", __func__, __LINE__);
+	rc = gpio_request(data->sensor_reset, "imx072");
+	CDBG(" imx072_probe_init_sensor\n");
+	if (!rc) {
+		pr_err("sensor_reset = %d\n", rc);
+		gpio_direction_output(data->sensor_reset, 0);
+		msleep(50);
+		gpio_set_value_cansleep(data->sensor_reset, 1);
+		msleep(20);
+	} else {
+		goto init_probe_done;
+	}
+
+	CDBG(" imx072_probe_init_sensor is called\n");
+	rc = imx072_i2c_read(0x0, &chipid, 2);
+	CDBG("ID: %d\n", chipid);
+	/* 4. Compare sensor ID to IMX072 ID: */
+	if (chipid != 0x0045) {
+		rc = -ENODEV;
+		pr_err("imx072_probe_init_sensor chip id doesnot match\n");
+		goto init_probe_fail;
+	}
+	goto init_probe_done;
+init_probe_fail:
+	pr_err(" imx072_probe_init_sensor fails\n");
+	gpio_set_value_cansleep(data->sensor_reset, 0);
+	imx072_probe_init_done(data);
+init_probe_done:
+	pr_err(" imx072_probe_init_sensor finishes\n");
+	return rc;
+}
+
+int imx072_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc = 0;
+
+	CDBG("%s: %d\n", __func__, __LINE__);
+	imx072_ctrl = kzalloc(sizeof(struct imx072_ctrl_t), GFP_KERNEL);
+	if (!imx072_ctrl) {
+		pr_err("imx072_init failed!\n");
+		rc = -ENOMEM;
+		goto init_done;
+	}
+	imx072_ctrl->fps_divider = 1 * 0x00000400;
+	imx072_ctrl->pict_fps_divider = 1 * 0x00000400;
+	imx072_ctrl->set_test = TEST_OFF;
+	imx072_ctrl->cam_mode = MODE_INVALID;
+
+	if (data)
+		imx072_ctrl->sensordata = data;
+	if (rc < 0) {
+		pr_err("Calling imx072_sensor_open_init fail1\n");
+		return rc;
+	}
+	CDBG("%s: %d\n", __func__, __LINE__);
+	/* enable mclk first */
+	msm_camio_clk_rate_set(IMX072_MASTER_CLK_RATE);
+	rc = imx072_probe_init_sensor(data);
+	if (rc < 0)
+		goto init_fail;
+
+	imx072_init_focus();
+	imx072_ctrl->fps = 30*Q8;
+	if (rc < 0) {
+		gpio_set_value_cansleep(data->sensor_reset, 0);
+		goto init_fail;
+	} else
+		goto init_done;
+init_fail:
+	pr_err("init_fail\n");
+	imx072_probe_init_done(data);
+init_done:
+	pr_err("init_done\n");
+	return rc;
+}
+
+static int imx072_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&imx072_wait_queue);
+	return 0;
+}
+
+static const struct i2c_device_id imx072_i2c_id[] = {
+	{"imx072", 0},
+	{ }
+};
+
+static int imx072_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int rc = 0;
+	CDBG("imx072_probe called!\n");
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	imx072_sensorw = kzalloc(sizeof(struct imx072_work_t),
+			GFP_KERNEL);
+	if (!imx072_sensorw) {
+		pr_err("kzalloc failed.\n");
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, imx072_sensorw);
+	imx072_init_client(client);
+	imx072_client = client;
+
+	msleep(50);
+
+	CDBG("imx072_probe successed! rc = %d\n", rc);
+	return 0;
+
+probe_failure:
+	pr_err("imx072_probe failed! rc = %d\n", rc);
+	return rc;
+}
+
+static int imx072_send_wb_info(struct wb_info_cfg *wb)
+{
+	return 0;
+
+}
+
+static int __exit imx072_remove(struct i2c_client *client)
+{
+	struct imx072_work_t_t *sensorw = i2c_get_clientdata(client);
+	free_irq(client->irq, sensorw);
+	imx072_client = NULL;
+	kfree(sensorw);
+	return 0;
+}
+
+static struct i2c_driver imx072_i2c_driver = {
+	.id_table = imx072_i2c_id,
+	.probe  = imx072_i2c_probe,
+	.remove = __exit_p(imx072_i2c_remove),
+	.driver = {
+		.name = "imx072",
+	},
+};
+
+int imx072_sensor_config(void __user *argp)
+{
+	struct sensor_cfg_data cdata;
+	long   rc = 0;
+	if (copy_from_user(&cdata,
+		(void *)argp,
+		sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+	mutex_lock(&imx072_mut);
+	CDBG("imx072_sensor_config: cfgtype = %d\n",
+		 cdata.cfgtype);
+	switch (cdata.cfgtype) {
+	case CFG_GET_PICT_FPS:
+		imx072_get_pict_fps(
+			cdata.cfg.gfps.prevfps,
+			&(cdata.cfg.gfps.pictfps));
+
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+	case CFG_GET_PREV_L_PF:
+		cdata.cfg.prevl_pf =
+		imx072_get_prev_lines_pf();
+
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+	case CFG_GET_PREV_P_PL:
+		cdata.cfg.prevp_pl =
+			imx072_get_prev_pixels_pl();
+
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+	case CFG_GET_PICT_L_PF:
+		cdata.cfg.pictl_pf =
+			imx072_get_pict_lines_pf();
+
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+	case CFG_GET_PICT_P_PL:
+		cdata.cfg.pictp_pl =
+			imx072_get_pict_pixels_pl();
+
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+	case CFG_GET_PICT_MAX_EXP_LC:
+		cdata.cfg.pict_max_exp_lc =
+			imx072_get_pict_max_exp_lc();
+
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+	case CFG_SET_FPS:
+	case CFG_SET_PICT_FPS:
+		rc = imx072_set_fps(&(cdata.cfg.fps));
+		break;
+	case CFG_SET_EXP_GAIN:
+		rc = imx072_write_exp_gain(
+			cdata.cfg.exp_gain.gain,
+			cdata.cfg.exp_gain.line);
+		break;
+	case CFG_SET_PICT_EXP_GAIN:
+		rc = imx072_set_pict_exp_gain(
+			cdata.cfg.exp_gain.gain,
+			cdata.cfg.exp_gain.line);
+		break;
+	case CFG_SET_MODE:
+		rc = imx072_set_sensor_mode(cdata.mode, cdata.rs);
+		break;
+	case CFG_PWR_DOWN:
+		rc = imx072_power_down();
+		break;
+	case CFG_MOVE_FOCUS:
+		rc = imx072_move_focus(cdata.cfg.focus.dir,
+				cdata.cfg.focus.steps);
+		break;
+	case CFG_SET_DEFAULT_FOCUS:
+		imx072_set_default_focus();
+		break;
+	case CFG_GET_AF_MAX_STEPS:
+		cdata.max_steps = IMX072_TOTAL_STEPS_NEAR_TO_FAR;
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+	case CFG_SET_EFFECT:
+		break;
+	case CFG_SEND_WB_INFO:
+		rc = imx072_send_wb_info(
+			&(cdata.cfg.wb_info));
+	break;
+	case CFG_SENSOR_INIT:
+		rc = imx072_mode_init(cdata.mode,
+				cdata.cfg.init_info);
+	break;
+	case CFG_SET_LENS_SHADING:
+		break;
+	default:
+		rc = -EFAULT;
+		break;
+	}
+
+	mutex_unlock(&imx072_mut);
+
+	return rc;
+}
+
+static int imx072_sensor_release(void)
+{
+	int rc = -EBADF;
+	mutex_lock(&imx072_mut);
+	imx072_power_down();
+	gpio_set_value_cansleep(imx072_ctrl->sensordata->sensor_reset, 0);
+	msleep(20);
+	gpio_free(imx072_ctrl->sensordata->sensor_reset);
+	kfree(imx072_ctrl);
+	imx072_ctrl = NULL;
+	pr_err("imx072_release completed\n");
+	mutex_unlock(&imx072_mut);
+
+	return rc;
+}
+
+static int imx072_sensor_probe(const struct msm_camera_sensor_info *info,
+		struct msm_sensor_ctrl *s)
+{
+	int rc = 0;
+	rc = i2c_add_driver(&imx072_i2c_driver);
+	if (rc < 0 || imx072_client == NULL) {
+		rc = -ENOTSUPP;
+		pr_err("I2C add driver failed");
+		goto probe_fail;
+	}
+	msm_camio_clk_rate_set(IMX072_MASTER_CLK_RATE);
+	rc = imx072_probe_init_sensor(info);
+	if (rc < 0)
+		goto probe_fail;
+	s->s_init = imx072_sensor_open_init;
+	s->s_release = imx072_sensor_release;
+	s->s_config  = imx072_sensor_config;
+	s->s_mount_angle = info->sensor_platform_info->mount_angle;
+
+	gpio_set_value_cansleep(info->sensor_reset, 0);
+	imx072_probe_init_done(info);
+	pr_info("imx072_sensor_probe : SUCCESS\n");
+	return rc;
+
+probe_fail:
+	pr_err("imx072_sensor_probe: SENSOR PROBE FAILS!\n");
+	return rc;
+}
+
+static int __imx072_probe(struct platform_device *pdev)
+{
+	return msm_camera_drv_start(pdev, imx072_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = __imx072_probe,
+	.driver = {
+		.name = "msm_camera_imx072",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init imx072_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(imx072_init);
+void imx072_exit(void)
+{
+	i2c_del_driver(&imx072_i2c_driver);
+}
+MODULE_DESCRIPTION("Aptina 8 MP Bayer sensor driver");
+MODULE_LICENSE("GPL v2");
+
+#ifdef CONFIG_DEBUG_FS
+static bool streaming = 1;
+
+static int cam_debug_stream_set(void *data, u64 val)
+{
+	int rc = 0;
+
+	if (val) {
+		imx072_start_stream();
+		streaming = 1;
+	} else {
+		imx072_stop_stream();
+		streaming = 0;
+	}
+
+	return rc;
+}
+
+static int cam_debug_stream_get(void *data, u64 *val)
+{
+	*val = streaming;
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(cam_stream, cam_debug_stream_get,
+			cam_debug_stream_set, "%llu\n");
+
+
+
+static int imx072_set_af_codestep(void *data, u64 val)
+{
+	imx072_l_region_code_per_step = val;
+	imx072_init_focus();
+	return 0;
+}
+
+static int imx072_get_af_codestep(void *data, u64 *val)
+{
+	*val = imx072_l_region_code_per_step;
+	return 0;
+}
+
+static uint16_t imx072_linear_total_step = IMX072_TOTAL_STEPS_NEAR_TO_FAR;
+static int imx072_set_linear_total_step(void *data, u64 val)
+{
+	imx072_linear_total_step = val;
+	return 0;
+}
+
+static int imx072_af_linearity_test(void *data, u64 *val)
+{
+	int i = 0;
+
+	imx072_set_default_focus();
+	msleep(3000);
+	for (i = 0; i < imx072_linear_total_step; i++) {
+		imx072_move_focus(MOVE_NEAR, 1);
+		CDBG("moved to index =[%d]\n", i);
+		msleep(1000);
+	}
+
+	for (i = 0; i < imx072_linear_total_step; i++) {
+		imx072_move_focus(MOVE_FAR, 1);
+		CDBG("moved to index =[%d]\n", i);
+		msleep(1000);
+	}
+	return 0;
+}
+
+static uint16_t imx072_step_val = IMX072_TOTAL_STEPS_NEAR_TO_FAR;
+static uint8_t imx072_step_dir = MOVE_NEAR;
+static int imx072_af_step_config(void *data, u64 val)
+{
+	imx072_step_val = val & 0xFFFF;
+	imx072_step_dir = (val >> 16) & 0x1;
+	return 0;
+}
+
+static int imx072_af_step(void *data, u64 *val)
+{
+	int i = 0;
+	int dir = MOVE_NEAR;
+	imx072_set_default_focus();
+	msleep(3000);
+	if (imx072_step_dir == 1)
+		dir = MOVE_FAR;
+
+	for (i = 0; i < imx072_step_val; i += 4) {
+		imx072_move_focus(dir, 4);
+		msleep(1000);
+	}
+	imx072_set_default_focus();
+	msleep(3000);
+	return 0;
+}
+
+static int imx072_af_set_resolution(void *data, u64 val)
+{
+	imx072_init_focus();
+	return 0;
+}
+
+static int imx072_af_get_resolution(void *data, u64 *val)
+{
+	*val = 0xFF;
+	return 0;
+}
+
+
+
+DEFINE_SIMPLE_ATTRIBUTE(af_codeperstep, imx072_get_af_codestep,
+			imx072_set_af_codestep, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(af_linear, imx072_af_linearity_test,
+			imx072_set_linear_total_step, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(af_step, imx072_af_step,
+			imx072_af_step_config, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(af_step_res, imx072_af_get_resolution,
+			imx072_af_set_resolution, "%llu\n");
+
+static int cam_debug_init(void)
+{
+	struct dentry *cam_dir;
+	debugfs_base = debugfs_create_dir("sensor", NULL);
+	if (!debugfs_base)
+		return -ENOMEM;
+
+	cam_dir = debugfs_create_dir("imx072", debugfs_base);
+	if (!cam_dir)
+		return -ENOMEM;
+
+	if (!debugfs_create_file("stream", S_IRUGO | S_IWUSR, cam_dir,
+							 NULL, &cam_stream))
+		return -ENOMEM;
+
+	if (!debugfs_create_file("af_codeperstep", S_IRUGO | S_IWUSR, cam_dir,
+							 NULL, &af_codeperstep))
+		return -ENOMEM;
+	if (!debugfs_create_file("af_linear", S_IRUGO | S_IWUSR, cam_dir,
+							 NULL, &af_linear))
+		return -ENOMEM;
+	if (!debugfs_create_file("af_step", S_IRUGO | S_IWUSR, cam_dir,
+							 NULL, &af_step))
+		return -ENOMEM;
+
+	if (!debugfs_create_file("af_step_res", S_IRUGO | S_IWUSR, cam_dir,
+							 NULL, &af_step_res))
+		return -ENOMEM;
+
+	return 0;
+}
+#endif
diff --git a/drivers/media/video/msm/imx072.h b/drivers/media/video/msm/imx072.h
new file mode 100644
index 0000000..e3d279f
--- /dev/null
+++ b/drivers/media/video/msm/imx072.h
@@ -0,0 +1,79 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#ifndef IMX072_H
+#define IMX072_H
+#include <linux/types.h>
+#include <mach/board.h>
+extern struct imx072_reg imx072_regs;
+
+struct imx072_i2c_reg_conf {
+	unsigned short waddr;
+	unsigned short wdata;
+};
+
+struct imx072_i2c_conf_array {
+	struct imx072_i2c_reg_conf *conf;
+	unsigned short size;
+};
+
+enum imx072_test_mode_t {
+	TEST_OFF,
+	TEST_1,
+	TEST_2,
+	TEST_3
+};
+
+enum imx072_resolution_t {
+	QTR_2D_SIZE,
+	FULL_2D_SIZE,
+	QTR_3D_SIZE,
+	FULL_3D_SIZE,
+	INVALID_SIZE
+};
+enum imx072_setting {
+	RES_PREVIEW,
+	RES_CAPTURE,
+	RES_3D_PREVIEW,
+	RES_3D_CAPTURE
+};
+enum imx072_cam_mode_t {
+	MODE_2D_RIGHT,
+	MODE_2D_LEFT,
+	MODE_3D,
+	MODE_INVALID
+};
+enum imx072_reg_update {
+	/* Sensor egisters that need to be updated during initialization */
+	REG_INIT,
+	/* Sensor egisters that needs periodic I2C writes */
+	UPDATE_PERIODIC,
+	/* All the sensor Registers will be updated */
+	UPDATE_ALL,
+	/* Not valid update */
+	UPDATE_INVALID
+};
+
+enum imx072_reg_mode {
+	IMX072_FRAME_LENGTH_LINES_HI = 0,
+	IMX072_FRAME_LENGTH_LINES_LO,
+	IMX072_LINE_LENGTH_PCK_HI,
+	IMX072_LINE_LENGTH_PCK_LO,
+};
+
+struct imx072_reg {
+	const struct imx072_i2c_reg_conf *rec_settings;
+	const unsigned short rec_size;
+	const struct imx072_i2c_conf_array *conf_array;
+};
+#endif /* IMX072_H */
diff --git a/drivers/media/video/msm/imx072_reg.c b/drivers/media/video/msm/imx072_reg.c
new file mode 100644
index 0000000..ea75548
--- /dev/null
+++ b/drivers/media/video/msm/imx072_reg.c
@@ -0,0 +1,153 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include "imx072.h"
+
+struct imx072_i2c_reg_conf imx072_prev_settings[] = {
+	{0x0340, 0x03},/*frame_length*/
+	{0x0341, 0xF7},/*frame_length*/
+	{0x0342, 0x0A},/*line_length*/
+	{0x0343, 0xE0},/*line_length*/
+	{0x0344, 0x00},/*x_addr_start*/
+	{0x0345, 0x00},/*x_addr_start*/
+	{0x0346, 0x00},/*y_addr_start*/
+	{0x0347, 0x00},/*y_addr_start*/
+	{0x0348, 0x0A},/*x_addr_end*/
+	{0x0349, 0x2F},/*x_addr_end*/
+	{0x034A, 0x07},/*y_addr_end*/
+	{0x034B, 0xA7},/*y_addr_end*/
+	{0x034C, 0x05},/*x_out_size*/
+	{0x034D, 0x18},/*x_out_size*/
+	{0x034E, 0x03},/*y_out_size*/
+	{0x034F, 0xD4},/*y_out_size*/
+	{0x0381, 0x01},/*x_even_inc*/
+	{0x0383, 0x03},/*x_odd_inc*/
+	{0x0385, 0x01},/*y_even_inc*/
+	{0x0387, 0x03},/*y_odd_inc*/
+	{0x3016, 0x06},/*VMODEADD*/
+	{0x3017, 0x40},
+	{0x3069, 0x24},
+	{0x306A, 0x00},
+	{0x306B, 0xCB},
+	{0x306C, 0x07},
+	{0x30E8, 0x86},
+	{0x3304, 0x03},
+	{0x3305, 0x02},
+	{0x3306, 0x0A},
+	{0x3307, 0x02},
+	{0x3308, 0x11},
+	{0x3309, 0x04},
+	{0x330A, 0x05},
+	{0x330B, 0x04},
+	{0x330C, 0x05},
+	{0x330D, 0x04},
+	{0x330E, 0x01},
+	{0x3301, 0x80},
+};
+
+struct imx072_i2c_reg_conf imx072_snap_settings[] = {
+	{0x0340, 0x07},/*frame_length*/
+	{0x0341, 0xEE},/*frame_length*/
+	{0x0342, 0x0A},/*line_length*/
+	{0x0343, 0xE0},/*line_length*/
+	{0x0344, 0x00},/*x_addr_start*/
+	{0x0345, 0x00},/*x_addr_start*/
+	{0x0346, 0x00},/*y_addr_start*/
+	{0x0347, 0x00},/*y_addr_start*/
+	{0x0348, 0x0A},/*x_addr_end*/
+	{0x0349, 0x2F},/*x_addr_end*/
+	{0x034A, 0x07},/*y_addr_end*/
+	{0x034B, 0xA7},/*y_addr_end*/
+	{0x034C, 0x0A},/*x_out_size*/
+	{0x034D, 0x30},/*x_out_size*/
+	{0x034E, 0x07},/*y_out_size*/
+	{0x034F, 0xA8},/*y_out_size*/
+	{0x0381, 0x01},/*x_even_inc*/
+	{0x0383, 0x01},/*x_odd_inc*/
+	{0x0385, 0x01},/*y_even_inc*/
+	{0x0387, 0x01},/*y_odd_inc*/
+	{0x3016, 0x06},/*VMODEADD*/
+	{0x3017, 0x40},
+	{0x3069, 0x24},
+	{0x306A, 0x00},
+	{0x306B, 0xCB},
+	{0x306C, 0x07},
+	{0x30E8, 0x06},
+	{0x3304, 0x05},
+	{0x3305, 0x04},
+	{0x3306, 0x15},
+	{0x3307, 0x02},
+	{0x3308, 0x11},
+	{0x3309, 0x07},
+	{0x330A, 0x05},
+	{0x330B, 0x04},
+	{0x330C, 0x05},
+	{0x330D, 0x04},
+	{0x330E, 0x01},
+	{0x3301, 0x00},
+};
+
+struct imx072_i2c_reg_conf imx072_recommend_settings[] = {
+	{0x0307, 0x12},
+	{0x302B, 0x4B},
+	{0x0101, 0x03},
+	{0x300A, 0x80},
+	{0x3014, 0x08},
+	{0x3015, 0x37},
+	{0x3017, 0x40},
+	{0x301C, 0x01},
+	{0x3031, 0x28},
+	{0x3040, 0x00},
+	{0x3041, 0x60},
+	{0x3051, 0x24},
+	{0x3053, 0x34},
+	{0x3055, 0x3B},
+	{0x3057, 0xC0},
+	{0x3060, 0x30},
+	{0x3065, 0x00},
+	{0x30AA, 0x88},
+	{0x30AB, 0x1C},
+	{0x30B0, 0x32},
+	{0x30B2, 0x83},
+	{0x30D3, 0x04},
+	{0x310E, 0xDD},
+	{0x31A4, 0xD8},
+	{0x31A6, 0x17},
+	{0x31AC, 0xCF},
+	{0x31AE, 0xF1},
+	{0x31B4, 0xD8},
+	{0x31B6, 0x17},
+	{0x3304, 0x05},
+	{0x3305, 0x04},
+	{0x3306, 0x15},
+	{0x3307, 0x02},
+	{0x3308, 0x11},
+	{0x3309, 0x07},
+	{0x330A, 0x05},
+	{0x330B, 0x04},
+	{0x330C, 0x05},
+	{0x330D, 0x04},
+	{0x330E, 0x01},
+	{0x30d8, 0x20},
+};
+
+struct imx072_i2c_conf_array imx072_confs[] = {
+	{&imx072_prev_settings[0], ARRAY_SIZE(imx072_prev_settings)},
+	{&imx072_snap_settings[0], ARRAY_SIZE(imx072_snap_settings)},
+};
+
+struct imx072_reg imx072_regs = {
+	.rec_settings = &imx072_recommend_settings[0],
+	.rec_size = ARRAY_SIZE(imx072_recommend_settings),
+	.conf_array = &imx072_confs[0],
+};
diff --git a/drivers/media/video/msm/imx074.c b/drivers/media/video/msm/imx074.c
new file mode 100644
index 0000000..636b402
--- /dev/null
+++ b/drivers/media/video/msm/imx074.c
@@ -0,0 +1,1414 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <media/msm_camera.h>
+#include <mach/gpio.h>
+#include <mach/camera.h>
+#include <asm/mach-types.h>
+#include "imx074.h"
+
+/*SENSOR REGISTER DEFINES*/
+#define	IMX074_EEPROM_SLAVE_ADDR			0x52
+#define REG_GROUPED_PARAMETER_HOLD			0x0104
+#define GROUPED_PARAMETER_HOLD_OFF			0x00
+#define GROUPED_PARAMETER_HOLD				0x01
+#define REG_MODE_SELECT					0x100
+#define MODE_SELECT_STANDBY_MODE			0x00
+#define MODE_SELECT_STREAM				0x01
+/* Integration Time */
+#define REG_COARSE_INTEGRATION_TIME_HI			0x0202
+#define REG_COARSE_INTEGRATION_TIME_LO			0x0203
+/* Gain */
+#define REG_ANALOGUE_GAIN_CODE_GLOBAL_HI		0x0204
+#define REG_ANALOGUE_GAIN_CODE_GLOBAL_LO		0x0205
+/* PLL registers */
+#define REG_PLL_MULTIPLIER				0x0307
+#define REG_PRE_PLL_CLK_DIV				0x0305
+#define REG_PLSTATIM					0x302b
+#define REG_3024					0x3024
+#define REG_IMAGE_ORIENTATION				0x0101
+#define REG_VNDMY_ABLMGSHLMT				0x300a
+#define REG_Y_OPBADDR_START_DI				0x3014
+#define REG_3015					0x3015
+#define REG_301C					0x301C
+#define REG_302C					0x302C
+#define REG_3031					0x3031
+#define REG_3041					0x3041
+#define REG_3051					0x3051
+#define REG_3053					0x3053
+#define REG_3057					0x3057
+#define REG_305C					0x305C
+#define REG_305D					0x305D
+#define REG_3060					0x3060
+#define REG_3065					0x3065
+#define REG_30AA					0x30AA
+#define REG_30AB					0x30AB
+#define REG_30B0					0x30B0
+#define REG_30B2					0x30B2
+#define REG_30D3					0x30D3
+#define REG_3106					0x3106
+#define REG_310C					0x310C
+#define REG_3304					0x3304
+#define REG_3305					0x3305
+#define REG_3306					0x3306
+#define REG_3307					0x3307
+#define REG_3308					0x3308
+#define REG_3309					0x3309
+#define REG_330A					0x330A
+#define REG_330B					0x330B
+#define REG_330C					0x330C
+#define REG_330D					0x330D
+#define REG_330F					0x330F
+#define REG_3381					0x3381
+
+/* mode setting */
+#define REG_FRAME_LENGTH_LINES_HI			0x0340
+#define REG_FRAME_LENGTH_LINES_LO			0x0341
+#define REG_YADDR_START					0x0347
+#define REG_YAAAR_END					0x034b
+#define REG_X_OUTPUT_SIZE_MSB				0x034c
+#define REG_X_OUTPUT_SIZE_LSB				0x034d
+#define REG_Y_OUTPUT_SIZE_MSB				0x034e
+#define REG_Y_OUTPUT_SIZE_LSB				0x034f
+#define REG_X_EVEN_INC					0x0381
+#define REG_X_ODD_INC					0x0383
+#define REG_Y_EVEN_INC					0x0385
+#define REG_Y_ODD_INC					0x0387
+#define REG_HMODEADD					0x3001
+#define REG_VMODEADD					0x3016
+#define REG_VAPPLINE_START				0x3069
+#define REG_VAPPLINE_END				0x306b
+#define REG_SHUTTER					0x3086
+#define REG_HADDAVE					0x30e8
+#define REG_LANESEL					0x3301
+/* Test Pattern */
+#define REG_TEST_PATTERN_MODE				0x0601
+
+#define REG_LINE_LENGTH_PCK_HI				0x0342
+#define REG_LINE_LENGTH_PCK_LO				0x0343
+/*..... TYPE DECLARATIONS.....*/
+#define	IMX074_OFFSET					3
+#define	IMX074_DEFAULT_MASTER_CLK_RATE			24000000
+/* Full	Size */
+#define	IMX074_FULL_SIZE_WIDTH				4208
+#define	IMX074_FULL_SIZE_HEIGHT				3120
+#define	IMX074_FULL_SIZE_DUMMY_PIXELS			0
+#define	IMX074_FULL_SIZE_DUMMY_LINES			0
+/* Quarter Size	*/
+#define	IMX074_QTR_SIZE_WIDTH				2104
+#define	IMX074_QTR_SIZE_HEIGHT				1560
+#define	IMX074_QTR_SIZE_DUMMY_PIXELS			0
+#define	IMX074_QTR_SIZE_DUMMY_LINES			0
+/* Blanking as measured	on the scope */
+/* Full	Size */
+#define	IMX074_HRZ_FULL_BLK_PIXELS			264
+#define	IMX074_VER_FULL_BLK_LINES			96
+/* Quarter Size	*/
+#define	IMX074_HRZ_QTR_BLK_PIXELS			2368
+#define	IMX074_VER_QTR_BLK_LINES			21
+#define	Q8						0x100
+#define	Q10						0x400
+#define	IMX074_AF_I2C_SLAVE_ID				0x72
+#define	IMX074_STEPS_NEAR_TO_CLOSEST_INF		52
+#define	IMX074_TOTAL_STEPS_NEAR_TO_FAR			52
+static uint32_t imx074_l_region_code_per_step = 2;
+
+struct imx074_work_t {
+	struct work_struct work;
+};
+
+static struct imx074_work_t *imx074_sensorw;
+static struct i2c_client *imx074_client;
+
+struct imx074_ctrl_t {
+	const struct msm_camera_sensor_info *sensordata;
+	uint32_t sensormode;
+	uint32_t fps_divider;/* init to 1 * 0x00000400 */
+	uint32_t pict_fps_divider;/* init to 1 * 0x00000400 */
+	uint16_t fps;
+	int16_t curr_lens_pos;
+	uint16_t curr_step_pos;
+	uint16_t my_reg_gain;
+	uint32_t my_reg_line_count;
+	uint16_t total_lines_per_frame;
+	enum imx074_resolution_t prev_res;
+	enum imx074_resolution_t pict_res;
+	enum imx074_resolution_t curr_res;
+	enum imx074_test_mode_t set_test;
+	unsigned short imgaddr;
+};
+static uint8_t imx074_delay_msecs_stdby = 5;
+static uint16_t imx074_delay_msecs_stream = 5;
+static int32_t config_csi;
+
+static struct imx074_ctrl_t *imx074_ctrl;
+static DECLARE_WAIT_QUEUE_HEAD(imx074_wait_queue);
+DEFINE_MUTEX(imx074_mut);
+
+/*=============================================================*/
+
+static int imx074_i2c_rxdata(unsigned short saddr,
+	unsigned char *rxdata, int length)
+{
+	struct i2c_msg msgs[] = {
+		{
+			.addr  = saddr,
+			.flags = 0,
+			.len   = 2,
+			.buf   = rxdata,
+		},
+		{
+			.addr  = saddr,
+			.flags = I2C_M_RD,
+			.len   = 2,
+			.buf   = rxdata,
+		},
+	};
+	if (i2c_transfer(imx074_client->adapter, msgs, 2) < 0) {
+		CDBG("imx074_i2c_rxdata failed!\n");
+		return -EIO;
+	}
+	return 0;
+}
+static int32_t imx074_i2c_txdata(unsigned short saddr,
+				unsigned char *txdata, int length)
+{
+	struct i2c_msg msg[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = length,
+			.buf = txdata,
+		 },
+	};
+	if (i2c_transfer(imx074_client->adapter, msg, 1) < 0) {
+		CDBG("imx074_i2c_txdata faild 0x%x\n", imx074_client->addr);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+
+static int32_t imx074_i2c_read(unsigned short raddr,
+	unsigned short *rdata, int rlen)
+{
+	int32_t rc = 0;
+	unsigned char buf[2];
+	if (!rdata)
+		return -EIO;
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (raddr & 0xFF00) >> 8;
+	buf[1] = (raddr & 0x00FF);
+	rc = imx074_i2c_rxdata(imx074_client->addr, buf, rlen);
+	if (rc < 0) {
+		CDBG("imx074_i2c_read 0x%x failed!\n", raddr);
+		return rc;
+	}
+	*rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]);
+	return rc;
+}
+
+static int imx074_af_i2c_rxdata_b(unsigned short saddr,
+	unsigned char *rxdata, int length)
+{
+	struct i2c_msg msgs[] = {
+		{
+		.addr  = saddr,
+		.flags = 0,
+		.len   = 1,
+		.buf   = rxdata,
+		},
+		{
+		.addr  = saddr,
+		.flags = I2C_M_RD,
+		.len   = 1,
+		.buf   = rxdata,
+		},
+	};
+
+	if (i2c_transfer(imx074_client->adapter, msgs, 2) < 0) {
+		CDBG("imx074_i2c_rxdata_b failed!\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t imx074_i2c_read_w_eeprom(unsigned short raddr,
+	unsigned short *rdata)
+{
+	int32_t rc;
+	unsigned char buf;
+	if (!rdata)
+		return -EIO;
+	/* Read 2 bytes in sequence */
+	buf = (raddr & 0x00FF);
+	rc = imx074_af_i2c_rxdata_b(IMX074_EEPROM_SLAVE_ADDR, &buf, 1);
+	if (rc < 0) {
+		CDBG("imx074_i2c_read_eeprom 0x%x failed!\n", raddr);
+		return rc;
+	}
+	*rdata = buf<<8;
+
+	/* Read Second byte of data */
+	buf = (raddr & 0x00FF) + 1;
+	rc = imx074_af_i2c_rxdata_b(IMX074_EEPROM_SLAVE_ADDR, &buf, 1);
+	if (rc < 0) {
+		CDBG("imx074_i2c_read_eeprom 0x%x failed!\n", raddr);
+		return rc;
+	}
+	*rdata |= buf;
+	return rc;
+}
+
+static int32_t imx074_i2c_write_b_sensor(unsigned short waddr, uint8_t bdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[3];
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = bdata;
+	CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata);
+	rc = imx074_i2c_txdata(imx074_client->addr, buf, 3);
+	if (rc < 0) {
+		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+			waddr, bdata);
+	}
+	return rc;
+}
+static int16_t imx074_i2c_write_b_af(unsigned short saddr,
+	unsigned short baddr, unsigned short bdata)
+{
+	int32_t rc;
+	unsigned char buf[2];
+	memset(buf, 0, sizeof(buf));
+	buf[0] = baddr;
+	buf[1] = bdata;
+	rc = imx074_i2c_txdata(saddr, buf, 2);
+	if (rc < 0)
+		CDBG("AFi2c_write failed, saddr = 0x%x addr = 0x%x, val =0x%x!",
+			saddr, baddr, bdata);
+	return rc;
+}
+
+static int32_t imx074_i2c_write_w_table(struct imx074_i2c_reg_conf const
+					 *reg_conf_tbl, int num)
+{
+	int i;
+	int32_t rc = -EIO;
+	for (i = 0; i < num; i++) {
+		rc = imx074_i2c_write_b_sensor(reg_conf_tbl->waddr,
+			reg_conf_tbl->wdata);
+		if (rc < 0)
+			break;
+		reg_conf_tbl++;
+	}
+	return rc;
+}
+static int16_t imx074_af_init(void)
+{
+	int32_t rc;
+	/* Initialize waveform */
+	rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x01, 0xA9);
+	rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x02, 0xD2);
+	rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x03, 0x0C);
+	rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x04, 0x14);
+	rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x05, 0xB6);
+	rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x06, 0x4F);
+	return rc;
+}
+
+static void imx074_get_pict_fps(uint16_t fps, uint16_t *pfps)
+{
+	/* input fps is preview fps in Q8 format */
+	uint16_t preview_frame_length_lines, snapshot_frame_length_lines;
+	uint32_t divider, d1;
+	uint32_t pclk_mult;/*Q10 */
+	/* Total frame_length_lines and line_length_pck for preview */
+	preview_frame_length_lines = IMX074_QTR_SIZE_HEIGHT +
+		IMX074_VER_QTR_BLK_LINES;
+	/* Total frame_length_lines and line_length_pck for snapshot */
+	snapshot_frame_length_lines = IMX074_FULL_SIZE_HEIGHT +
+		IMX074_VER_FULL_BLK_LINES;
+	d1 = preview_frame_length_lines * 0x00010000 /
+		snapshot_frame_length_lines;
+	pclk_mult =
+		(uint32_t) ((imx074_regs.reg_pat[RES_CAPTURE].pll_multiplier *
+		0x00010000) /
+		(imx074_regs.reg_pat[RES_PREVIEW].pll_multiplier));
+	divider = d1 * pclk_mult / 0x00010000;
+	*pfps = (uint16_t) (fps * divider / 0x00010000);
+}
+
+static uint16_t imx074_get_prev_lines_pf(void)
+{
+	if (imx074_ctrl->prev_res == QTR_SIZE)
+		return IMX074_QTR_SIZE_HEIGHT + IMX074_VER_QTR_BLK_LINES;
+	else
+		return IMX074_FULL_SIZE_HEIGHT + IMX074_VER_FULL_BLK_LINES;
+
+}
+
+static uint16_t imx074_get_prev_pixels_pl(void)
+{
+	if (imx074_ctrl->prev_res == QTR_SIZE)
+		return IMX074_QTR_SIZE_WIDTH + IMX074_HRZ_QTR_BLK_PIXELS;
+	else
+		return IMX074_FULL_SIZE_WIDTH + IMX074_HRZ_FULL_BLK_PIXELS;
+}
+
+static uint16_t imx074_get_pict_lines_pf(void)
+{
+		if (imx074_ctrl->pict_res == QTR_SIZE)
+			return IMX074_QTR_SIZE_HEIGHT +
+				IMX074_VER_QTR_BLK_LINES;
+		else
+			return IMX074_FULL_SIZE_HEIGHT +
+				IMX074_VER_FULL_BLK_LINES;
+}
+
+static uint16_t imx074_get_pict_pixels_pl(void)
+{
+	if (imx074_ctrl->pict_res == QTR_SIZE)
+		return IMX074_QTR_SIZE_WIDTH +
+			IMX074_HRZ_QTR_BLK_PIXELS;
+	else
+		return IMX074_FULL_SIZE_WIDTH +
+			IMX074_HRZ_FULL_BLK_PIXELS;
+}
+
+static uint32_t imx074_get_pict_max_exp_lc(void)
+{
+	if (imx074_ctrl->pict_res == QTR_SIZE)
+		return (IMX074_QTR_SIZE_HEIGHT +
+			IMX074_VER_QTR_BLK_LINES)*24;
+	else
+		return (IMX074_FULL_SIZE_HEIGHT +
+			IMX074_VER_FULL_BLK_LINES)*24;
+}
+
+static int32_t imx074_set_fps(struct fps_cfg	*fps)
+{
+	uint16_t total_lines_per_frame;
+	int32_t rc = 0;
+	imx074_ctrl->fps_divider = fps->fps_div;
+	imx074_ctrl->pict_fps_divider = fps->pict_fps_div;
+	if (imx074_ctrl->curr_res  == QTR_SIZE) {
+		total_lines_per_frame = (uint16_t)(((IMX074_QTR_SIZE_HEIGHT +
+			IMX074_VER_QTR_BLK_LINES) *
+			imx074_ctrl->fps_divider) / 0x400);
+	} else {
+		total_lines_per_frame = (uint16_t)(((IMX074_FULL_SIZE_HEIGHT +
+			IMX074_VER_FULL_BLK_LINES) *
+			imx074_ctrl->pict_fps_divider) / 0x400);
+	}
+	if (imx074_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_HI,
+		((total_lines_per_frame & 0xFF00) >> 8)) < 0)
+		return rc;
+	if (imx074_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_LO,
+		(total_lines_per_frame & 0x00FF)) < 0)
+		return rc;
+	return rc;
+}
+
+static int32_t imx074_write_exp_gain(uint16_t gain, uint32_t line)
+{
+	static uint16_t max_legal_gain = 0x00E0;
+	uint8_t gain_msb, gain_lsb;
+	uint8_t intg_time_msb, intg_time_lsb;
+	uint8_t frame_length_line_msb, frame_length_line_lsb;
+	uint16_t frame_length_lines;
+	int32_t rc = -1;
+
+	CDBG("imx074_write_exp_gain : gain = %d line = %d", gain, line);
+	if (imx074_ctrl->curr_res  == QTR_SIZE) {
+		frame_length_lines = IMX074_QTR_SIZE_HEIGHT +
+			IMX074_VER_QTR_BLK_LINES;
+		frame_length_lines = frame_length_lines *
+			imx074_ctrl->fps_divider / 0x400;
+	} else {
+		frame_length_lines = IMX074_FULL_SIZE_HEIGHT +
+			IMX074_VER_FULL_BLK_LINES;
+		frame_length_lines = frame_length_lines *
+			imx074_ctrl->pict_fps_divider / 0x400;
+	}
+	if (line > (frame_length_lines - IMX074_OFFSET))
+		frame_length_lines = line + IMX074_OFFSET;
+
+	CDBG("imx074 setting line = %d\n", line);
+
+
+	CDBG("imx074 setting frame_length_lines = %d\n",
+					frame_length_lines);
+
+	if (gain > max_legal_gain)
+		/* range: 0 to 224 */
+		gain = max_legal_gain;
+
+	/* update gain registers */
+	gain_msb = (uint8_t) ((gain & 0xFF00) >> 8);
+	gain_lsb = (uint8_t) (gain & 0x00FF);
+
+	frame_length_line_msb = (uint8_t) ((frame_length_lines & 0xFF00) >> 8);
+	frame_length_line_lsb = (uint8_t) (frame_length_lines & 0x00FF);
+
+	/* update line count registers */
+	intg_time_msb = (uint8_t) ((line & 0xFF00) >> 8);
+	intg_time_lsb = (uint8_t) (line & 0x00FF);
+
+	rc = imx074_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
+					GROUPED_PARAMETER_HOLD);
+	if (rc < 0)
+		return rc;
+	CDBG("imx074 setting REG_ANALOGUE_GAIN_CODE_GLOBAL_HI = 0x%X\n",
+					gain_msb);
+	rc = imx074_i2c_write_b_sensor(REG_ANALOGUE_GAIN_CODE_GLOBAL_HI,
+					gain_msb);
+	if (rc < 0)
+		return rc;
+	CDBG("imx074 setting REG_ANALOGUE_GAIN_CODE_GLOBAL_LO = 0x%X\n",
+					gain_lsb);
+	rc = imx074_i2c_write_b_sensor(REG_ANALOGUE_GAIN_CODE_GLOBAL_LO,
+					gain_lsb);
+	if (rc < 0)
+		return rc;
+
+	CDBG("imx074 setting REG_FRAME_LENGTH_LINES_HI = 0x%X\n",
+					frame_length_line_msb);
+	rc = imx074_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_HI,
+			frame_length_line_msb);
+	if (rc < 0)
+		return rc;
+
+	CDBG("imx074 setting REG_FRAME_LENGTH_LINES_LO = 0x%X\n",
+			frame_length_line_lsb);
+	rc = imx074_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_LO,
+			frame_length_line_lsb);
+	if (rc < 0)
+		return rc;
+
+	CDBG("imx074 setting REG_COARSE_INTEGRATION_TIME_HI = 0x%X\n",
+					intg_time_msb);
+	rc = imx074_i2c_write_b_sensor(REG_COARSE_INTEGRATION_TIME_HI,
+					intg_time_msb);
+	if (rc < 0)
+		return rc;
+
+	CDBG("imx074 setting REG_COARSE_INTEGRATION_TIME_LO = 0x%X\n",
+					intg_time_lsb);
+	rc = imx074_i2c_write_b_sensor(REG_COARSE_INTEGRATION_TIME_LO,
+					intg_time_lsb);
+	if (rc < 0)
+		return rc;
+
+	rc = imx074_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
+					GROUPED_PARAMETER_HOLD_OFF);
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+
+static int32_t imx074_set_pict_exp_gain(uint16_t gain, uint32_t line)
+{
+	int32_t rc = 0;
+	rc = imx074_write_exp_gain(gain, line);
+	return rc;
+}
+
+static int32_t imx074_move_focus(int direction,
+	int32_t num_steps)
+{
+	int32_t step_direction, dest_step_position, bit_mask;
+	int32_t rc = 0;
+
+	if (num_steps == 0)
+		return rc;
+
+	if (direction == MOVE_NEAR) {
+		step_direction = 1;
+		bit_mask = 0x80;
+	} else if (direction == MOVE_FAR) {
+		step_direction = -1;
+		bit_mask = 0x00;
+	} else {
+		CDBG("imx074_move_focus: Illegal focus direction");
+		return -EINVAL;
+	}
+	dest_step_position = imx074_ctrl->curr_step_pos +
+		(step_direction * num_steps);
+	if (dest_step_position < 0)
+		dest_step_position = 0;
+	else if (dest_step_position > IMX074_TOTAL_STEPS_NEAR_TO_FAR)
+		dest_step_position = IMX074_TOTAL_STEPS_NEAR_TO_FAR;
+	rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x00,
+		((num_steps * imx074_l_region_code_per_step) | bit_mask));
+	CDBG("%s: Index: %d\n", __func__, dest_step_position);
+	imx074_ctrl->curr_step_pos = dest_step_position;
+	return rc;
+}
+
+
+static int32_t imx074_set_default_focus(uint8_t af_step)
+{
+	int32_t rc;
+	/* Initialize to infinity */
+	rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x00, 0x7F);
+	rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x00, 0x7F);
+	imx074_ctrl->curr_step_pos = 0;
+	return rc;
+}
+static int32_t imx074_test(enum imx074_test_mode_t mo)
+{
+	int32_t rc = 0;
+	if (mo == TEST_OFF)
+		return rc;
+	else {
+		/* Set mo to 2 inorder to enable test pattern*/
+		if (imx074_i2c_write_b_sensor(REG_TEST_PATTERN_MODE,
+			(uint8_t) mo) < 0) {
+			return rc;
+		}
+	}
+	return rc;
+}
+static int32_t imx074_sensor_setting(int update_type, int rt)
+{
+	int32_t rc = 0;
+	struct msm_camera_csi_params imx074_csi_params;
+	switch (update_type) {
+	case REG_INIT:
+		if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+			struct imx074_i2c_reg_conf init_tbl[] = {
+				{REG_PRE_PLL_CLK_DIV,
+					imx074_regs.reg_pat_init[0].
+					pre_pll_clk_div},
+				{REG_PLSTATIM,
+					imx074_regs.reg_pat_init[0].
+					plstatim},
+				{REG_3024,
+					imx074_regs.reg_pat_init[0].
+					reg_3024},
+				{REG_IMAGE_ORIENTATION,
+					imx074_regs.reg_pat_init[0].
+					image_orientation},
+				{REG_VNDMY_ABLMGSHLMT,
+					imx074_regs.reg_pat_init[0].
+					vndmy_ablmgshlmt},
+				{REG_Y_OPBADDR_START_DI,
+					imx074_regs.reg_pat_init[0].
+					y_opbaddr_start_di},
+				{REG_3015,
+					imx074_regs.reg_pat_init[0].
+					reg_0x3015},
+				{REG_301C,
+					imx074_regs.reg_pat_init[0].
+					reg_0x301c},
+				{REG_302C,
+					imx074_regs.reg_pat_init[0].
+					reg_0x302c},
+				{REG_3031,
+					imx074_regs.reg_pat_init[0].reg_0x3031},
+				{REG_3041,
+					imx074_regs.reg_pat_init[0].reg_0x3041},
+				{REG_3051,
+					imx074_regs.reg_pat_init[0].reg_0x3051},
+				{REG_3053,
+					imx074_regs.reg_pat_init[0].reg_0x3053},
+				{REG_3057,
+					imx074_regs.reg_pat_init[0].reg_0x3057},
+				{REG_305C,
+					imx074_regs.reg_pat_init[0].reg_0x305c},
+				{REG_305D,
+					imx074_regs.reg_pat_init[0].reg_0x305d},
+				{REG_3060,
+					imx074_regs.reg_pat_init[0].reg_0x3060},
+				{REG_3065,
+					imx074_regs.reg_pat_init[0].reg_0x3065},
+				{REG_30AA,
+					imx074_regs.reg_pat_init[0].reg_0x30aa},
+				{REG_30AB,
+					imx074_regs.reg_pat_init[0].reg_0x30ab},
+				{REG_30B0,
+					imx074_regs.reg_pat_init[0].reg_0x30b0},
+				{REG_30B2,
+					imx074_regs.reg_pat_init[0].reg_0x30b2},
+				{REG_30D3,
+					imx074_regs.reg_pat_init[0].reg_0x30d3},
+				{REG_3106,
+					imx074_regs.reg_pat_init[0].reg_0x3106},
+				{REG_310C,
+					imx074_regs.reg_pat_init[0].reg_0x310c},
+				{REG_3304,
+					imx074_regs.reg_pat_init[0].reg_0x3304},
+				{REG_3305,
+					imx074_regs.reg_pat_init[0].reg_0x3305},
+				{REG_3306,
+					imx074_regs.reg_pat_init[0].reg_0x3306},
+				{REG_3307,
+					imx074_regs.reg_pat_init[0].reg_0x3307},
+				{REG_3308,
+					imx074_regs.reg_pat_init[0].reg_0x3308},
+				{REG_3309,
+					imx074_regs.reg_pat_init[0].reg_0x3309},
+				{REG_330A,
+					imx074_regs.reg_pat_init[0].reg_0x330a},
+				{REG_330B,
+					imx074_regs.reg_pat_init[0].reg_0x330b},
+				{REG_330C,
+					imx074_regs.reg_pat_init[0].reg_0x330c},
+				{REG_330D,
+					imx074_regs.reg_pat_init[0].reg_0x330d},
+				{REG_330F,
+					imx074_regs.reg_pat_init[0].reg_0x330f},
+				{REG_3381,
+					imx074_regs.reg_pat_init[0].reg_0x3381},
+			};
+			struct imx074_i2c_reg_conf init_mode_tbl[] = {
+				{REG_GROUPED_PARAMETER_HOLD,
+					GROUPED_PARAMETER_HOLD},
+				{REG_PLL_MULTIPLIER,
+					imx074_regs.reg_pat[rt].
+					pll_multiplier},
+				{REG_FRAME_LENGTH_LINES_HI,
+					imx074_regs.reg_pat[rt].
+					frame_length_lines_hi},
+				{REG_FRAME_LENGTH_LINES_LO,
+					imx074_regs.reg_pat[rt].
+					frame_length_lines_lo},
+				{REG_YADDR_START ,
+					imx074_regs.reg_pat[rt].
+					y_addr_start},
+				{REG_YAAAR_END,
+					imx074_regs.reg_pat[rt].
+					y_add_end},
+				{REG_X_OUTPUT_SIZE_MSB,
+					imx074_regs.reg_pat[rt].
+					x_output_size_msb},
+				{REG_X_OUTPUT_SIZE_LSB,
+					imx074_regs.reg_pat[rt].
+					x_output_size_lsb},
+				{REG_Y_OUTPUT_SIZE_MSB,
+					imx074_regs.reg_pat[rt].
+					y_output_size_msb},
+				{REG_Y_OUTPUT_SIZE_LSB ,
+					imx074_regs.reg_pat[rt].
+					y_output_size_lsb},
+				{REG_X_EVEN_INC,
+					imx074_regs.reg_pat[rt].
+					x_even_inc},
+				{REG_X_ODD_INC,
+					imx074_regs.reg_pat[rt].
+					x_odd_inc},
+				{REG_Y_EVEN_INC,
+					imx074_regs.reg_pat[rt].
+					y_even_inc},
+				{REG_Y_ODD_INC,
+					imx074_regs.reg_pat[rt].
+					y_odd_inc},
+				{REG_HMODEADD,
+					imx074_regs.reg_pat[rt].
+					hmodeadd},
+				{REG_VMODEADD,
+					imx074_regs.reg_pat[rt].
+					vmodeadd},
+				{REG_VAPPLINE_START,
+					imx074_regs.reg_pat[rt].
+					vapplinepos_start},
+				{REG_VAPPLINE_END,
+					imx074_regs.reg_pat[rt].
+					vapplinepos_end},
+				{REG_SHUTTER,
+					imx074_regs.reg_pat[rt].
+					shutter},
+				{REG_HADDAVE,
+					imx074_regs.reg_pat[rt].
+					haddave},
+				{REG_LANESEL,
+					imx074_regs.reg_pat[rt].
+					lanesel},
+				{REG_GROUPED_PARAMETER_HOLD,
+					GROUPED_PARAMETER_HOLD_OFF},
+
+			};
+			/* reset fps_divider */
+			imx074_ctrl->fps = 30 * Q8;
+			imx074_ctrl->fps_divider = 1 * 0x400;
+			/* stop streaming */
+			rc = imx074_i2c_write_b_sensor(REG_MODE_SELECT,
+				MODE_SELECT_STANDBY_MODE);
+			if (rc < 0)
+				return rc;
+			msleep(imx074_delay_msecs_stdby);
+			rc = imx074_i2c_write_w_table(&init_tbl[0],
+				ARRAY_SIZE(init_tbl));
+			if (rc < 0)
+				return rc;
+			rc = imx074_i2c_write_w_table(&init_mode_tbl[0],
+				ARRAY_SIZE(init_mode_tbl));
+			if (rc < 0)
+				return rc;
+			rc = imx074_test(imx074_ctrl->set_test);
+			return rc;
+		}
+		break;
+	case UPDATE_PERIODIC:
+		if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+			struct imx074_i2c_reg_conf mode_tbl[] = {
+				{REG_GROUPED_PARAMETER_HOLD,
+					GROUPED_PARAMETER_HOLD},
+				{REG_PLL_MULTIPLIER,
+					imx074_regs.reg_pat[rt].
+					pll_multiplier},
+				{REG_FRAME_LENGTH_LINES_HI,
+					imx074_regs.reg_pat[rt].
+					frame_length_lines_hi},
+				{REG_FRAME_LENGTH_LINES_LO,
+					imx074_regs.reg_pat[rt].
+					frame_length_lines_lo},
+				{REG_YADDR_START ,
+					imx074_regs.reg_pat[rt].
+					y_addr_start},
+				{REG_YAAAR_END,
+					imx074_regs.reg_pat[rt].
+					y_add_end},
+				{REG_X_OUTPUT_SIZE_MSB,
+					imx074_regs.reg_pat[rt].
+					x_output_size_msb},
+				{REG_X_OUTPUT_SIZE_LSB,
+					imx074_regs.reg_pat[rt].
+					x_output_size_lsb},
+				{REG_Y_OUTPUT_SIZE_MSB,
+					imx074_regs.reg_pat[rt].
+					y_output_size_msb},
+				{REG_Y_OUTPUT_SIZE_LSB ,
+					imx074_regs.reg_pat[rt].
+					y_output_size_lsb},
+				{REG_X_EVEN_INC,
+					imx074_regs.reg_pat[rt].
+					x_even_inc},
+				{REG_X_ODD_INC,
+					imx074_regs.reg_pat[rt].
+					x_odd_inc},
+				{REG_Y_EVEN_INC,
+					imx074_regs.reg_pat[rt].
+					y_even_inc},
+				{REG_Y_ODD_INC,
+					imx074_regs.reg_pat[rt].
+					y_odd_inc},
+				{REG_HMODEADD,
+					imx074_regs.reg_pat[rt].
+					hmodeadd},
+				{REG_VMODEADD,
+					imx074_regs.reg_pat[rt].
+					vmodeadd},
+				{REG_VAPPLINE_START,
+					imx074_regs.reg_pat[rt].
+					vapplinepos_start},
+				{REG_VAPPLINE_END,
+					imx074_regs.reg_pat[rt].
+					vapplinepos_end},
+				{REG_SHUTTER,
+					imx074_regs.reg_pat[rt].
+					shutter},
+				{REG_HADDAVE,
+					imx074_regs.reg_pat[rt].
+					haddave},
+				{REG_LANESEL,
+					imx074_regs.reg_pat[rt].
+					lanesel},
+				{REG_GROUPED_PARAMETER_HOLD,
+					GROUPED_PARAMETER_HOLD_OFF},
+			};
+
+			/* stop streaming */
+			rc = imx074_i2c_write_b_sensor(REG_MODE_SELECT,
+				MODE_SELECT_STANDBY_MODE);
+			msleep(imx074_delay_msecs_stdby);
+			if (config_csi == 0) {
+				imx074_csi_params.lane_cnt = 4;
+				imx074_csi_params.data_format = CSI_10BIT;
+				imx074_csi_params.lane_assign = 0xe4;
+				imx074_csi_params.dpcm_scheme = 0;
+				imx074_csi_params.settle_cnt = 0x14;
+				rc = msm_camio_csi_config(&imx074_csi_params);
+				/*imx074_delay_msecs_stdby*/
+				msleep(imx074_delay_msecs_stream);
+				config_csi = 1;
+			}
+			rc = imx074_i2c_write_w_table(&mode_tbl[0],
+				ARRAY_SIZE(mode_tbl));
+			if (rc < 0)
+				return rc;
+			rc = imx074_i2c_write_b_sensor(REG_MODE_SELECT,
+				MODE_SELECT_STREAM);
+			if (rc < 0)
+				return rc;
+			msleep(imx074_delay_msecs_stream);
+		}
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+
+static int32_t imx074_video_config(int mode)
+{
+
+	int32_t	rc = 0;
+	int	rt;
+	/* change sensor resolution	if needed */
+	if (imx074_ctrl->prev_res == QTR_SIZE) {
+		rt = RES_PREVIEW;
+	} else {
+		rt = RES_CAPTURE;
+	}
+	if (imx074_sensor_setting(UPDATE_PERIODIC, rt) < 0)
+		return rc;
+	imx074_ctrl->curr_res = imx074_ctrl->prev_res;
+	imx074_ctrl->sensormode = mode;
+	return rc;
+}
+
+static int32_t imx074_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+	int rt = RES_PREVIEW; /* TODO: Used without initialization, guessing. */
+	/* change sensor resolution if needed */
+	if (imx074_ctrl->curr_res != imx074_ctrl->pict_res) {
+		if (imx074_ctrl->pict_res == QTR_SIZE) {
+			rt = RES_PREVIEW;
+		} else {
+			rt = RES_CAPTURE;
+		}
+	}
+	if (imx074_sensor_setting(UPDATE_PERIODIC, rt) < 0)
+		return rc;
+	imx074_ctrl->curr_res = imx074_ctrl->pict_res;
+	imx074_ctrl->sensormode = mode;
+	return rc;
+}
+static int32_t imx074_raw_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+	int rt = RES_PREVIEW; /* TODO: Used without initialization, guessing. */
+	/* change sensor resolution if needed */
+	if (imx074_ctrl->curr_res != imx074_ctrl->pict_res) {
+		if (imx074_ctrl->pict_res == QTR_SIZE) {
+			rt = RES_PREVIEW;
+		} else {
+			rt = RES_CAPTURE;
+		}
+	}
+	if (imx074_sensor_setting(UPDATE_PERIODIC, rt) < 0)
+		return rc;
+	imx074_ctrl->curr_res = imx074_ctrl->pict_res;
+	imx074_ctrl->sensormode = mode;
+	return rc;
+}
+static int32_t imx074_set_sensor_mode(int mode,
+	int res)
+{
+	int32_t rc = 0;
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		rc = imx074_video_config(mode);
+		break;
+	case SENSOR_SNAPSHOT_MODE:
+		rc = imx074_snapshot_config(mode);
+		break;
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		rc = imx074_raw_snapshot_config(mode);
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+static int32_t imx074_power_down(void)
+{
+	imx074_i2c_write_b_sensor(REG_MODE_SELECT,
+		MODE_SELECT_STANDBY_MODE);
+	msleep(imx074_delay_msecs_stdby);
+	return 0;
+}
+static int imx074_probe_init_done(const struct msm_camera_sensor_info *data)
+{
+	gpio_set_value_cansleep(data->sensor_reset, 0);
+	gpio_direction_input(data->sensor_reset);
+	gpio_free(data->sensor_reset);
+	return 0;
+}
+
+static int imx074_read_eeprom_data(struct sensor_cfg_data *cfg)
+{
+	int32_t rc = 0;
+	uint16_t eepromdata = 0;
+	uint8_t addr = 0;
+
+	addr = 0x10;
+	rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
+	if (rc < 0) {
+		CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
+		return rc;
+	}
+	cfg->cfg.calib_info.r_over_g = eepromdata;
+
+	addr = 0x12;
+	rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
+	if (rc < 0) {
+		CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
+		return rc;
+	}
+	cfg->cfg.calib_info.b_over_g = eepromdata;
+
+	addr = 0x14;
+	rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
+	if (rc < 0) {
+		CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
+		return rc;
+	}
+	cfg->cfg.calib_info.gr_over_gb = eepromdata;
+
+	addr = 0x1A;
+	rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
+	if (rc < 0) {
+		CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
+		return rc;
+	}
+	cfg->cfg.calib_info.macro_2_inf = eepromdata;
+
+	addr = 0x1C;
+	rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
+	if (rc < 0) {
+		CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
+		return rc;
+	}
+	cfg->cfg.calib_info.inf_2_macro = eepromdata;
+
+	addr = 0x1E;
+	rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
+	if (rc < 0) {
+		CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
+		return rc;
+	}
+	cfg->cfg.calib_info.stroke_amt = eepromdata;
+
+	addr = 0x20;
+	rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
+	if (rc < 0) {
+		CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
+		return rc;
+	}
+	cfg->cfg.calib_info.af_pos_1m = eepromdata;
+
+	addr = 0x22;
+	rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
+	if (rc < 0) {
+		CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
+		return rc;
+	}
+	cfg->cfg.calib_info.af_pos_inf = eepromdata;
+
+	return rc;
+}
+
+static int imx074_probe_init_sensor(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc = 0;
+	unsigned short chipidl, chipidh;
+	CDBG("%s: %d\n", __func__, __LINE__);
+	rc = gpio_request(data->sensor_reset, "imx074");
+	CDBG(" imx074_probe_init_sensor \n");
+	if (!rc) {
+		CDBG("sensor_reset = %d\n", rc);
+		gpio_direction_output(data->sensor_reset, 0);
+		usleep_range(5000, 6000);
+		gpio_set_value_cansleep(data->sensor_reset, 1);
+		usleep_range(5000, 6000);
+	} else {
+		CDBG("gpio reset fail");
+		goto init_probe_done;
+	}
+	CDBG("imx074_probe_init_sensor is called\n");
+	/* 3. Read sensor Model ID: */
+	rc = imx074_i2c_read(0x0000, &chipidh, 1);
+	if (rc < 0) {
+		CDBG("Model read failed\n");
+		goto init_probe_fail;
+	}
+	rc = imx074_i2c_read(0x0001, &chipidl, 1);
+	if (rc < 0) {
+		CDBG("Model read failed\n");
+		goto init_probe_fail;
+	}
+	CDBG("imx074 model_id = 0x%x  0x%x\n", chipidh, chipidl);
+	/* 4. Compare sensor ID to IMX074 ID: */
+	if (chipidh != 0x00 || chipidl != 0x74) {
+		rc = -ENODEV;
+		CDBG("imx074_probe_init_sensor fail chip id doesnot match\n");
+		goto init_probe_fail;
+	}
+	goto init_probe_done;
+init_probe_fail:
+	CDBG("imx074_probe_init_sensor fails\n");
+	imx074_probe_init_done(data);
+init_probe_done:
+	CDBG(" imx074_probe_init_sensor finishes\n");
+	return rc;
+	}
+static int32_t imx074_poweron_af(void)
+{
+	int32_t rc = 0;
+	CDBG("imx074 enable AF actuator, gpio = %d\n",
+			imx074_ctrl->sensordata->vcm_pwd);
+	rc = gpio_request(imx074_ctrl->sensordata->vcm_pwd, "imx074");
+	if (!rc) {
+		gpio_direction_output(imx074_ctrl->sensordata->vcm_pwd, 1);
+		msleep(20);
+		rc = imx074_af_init();
+		if (rc < 0)
+			CDBG("imx074 AF initialisation failed\n");
+	} else {
+		CDBG("%s: AF PowerON gpio_request failed %d\n", __func__, rc);
+	 }
+	return rc;
+}
+static void imx074_poweroff_af(void)
+{
+	gpio_set_value_cansleep(imx074_ctrl->sensordata->vcm_pwd, 0);
+	gpio_free(imx074_ctrl->sensordata->vcm_pwd);
+}
+/* camsensor_iu060f_imx074_reset */
+int imx074_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc = 0;
+	CDBG("%s: %d\n", __func__, __LINE__);
+	CDBG("Calling imx074_sensor_open_init\n");
+	imx074_ctrl = kzalloc(sizeof(struct imx074_ctrl_t), GFP_KERNEL);
+	if (!imx074_ctrl) {
+		CDBG("imx074_init failed!\n");
+		rc = -ENOMEM;
+		goto init_done;
+	}
+	imx074_ctrl->fps_divider = 1 * 0x00000400;
+	imx074_ctrl->pict_fps_divider = 1 * 0x00000400;
+	imx074_ctrl->fps = 30 * Q8;
+	imx074_ctrl->set_test = TEST_OFF;
+	imx074_ctrl->prev_res = QTR_SIZE;
+	imx074_ctrl->pict_res = FULL_SIZE;
+	imx074_ctrl->curr_res = INVALID_SIZE;
+	config_csi = 0;
+
+	if (data)
+		imx074_ctrl->sensordata = data;
+
+	/* enable mclk first */
+	msm_camio_clk_rate_set(IMX074_DEFAULT_MASTER_CLK_RATE);
+	usleep_range(1000, 2000);
+	rc = imx074_probe_init_sensor(data);
+	if (rc < 0) {
+		CDBG("Calling imx074_sensor_open_init fail\n");
+		goto probe_fail;
+	}
+
+	rc = imx074_sensor_setting(REG_INIT, RES_PREVIEW);
+	if (rc < 0) {
+		CDBG("imx074_sensor_setting failed\n");
+		goto init_fail;
+	}
+	if (machine_is_msm8x60_fluid())
+		rc = imx074_poweron_af();
+	else
+		rc = imx074_af_init();
+	if (rc < 0) {
+		CDBG("AF initialisation failed\n");
+		goto init_fail;
+	} else
+		goto init_done;
+probe_fail:
+	CDBG(" imx074_sensor_open_init probe fail\n");
+	kfree(imx074_ctrl);
+	return rc;
+init_fail:
+	CDBG(" imx074_sensor_open_init fail\n");
+	imx074_probe_init_done(data);
+	kfree(imx074_ctrl);
+init_done:
+	CDBG("imx074_sensor_open_init done\n");
+	return rc;
+}
+static int imx074_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&imx074_wait_queue);
+	return 0;
+}
+
+static const struct i2c_device_id imx074_i2c_id[] = {
+	{"imx074", 0},
+	{ }
+};
+
+static int imx074_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int rc = 0;
+	CDBG("imx074_probe called!\n");
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		CDBG("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	imx074_sensorw = kzalloc(sizeof(struct imx074_work_t), GFP_KERNEL);
+	if (!imx074_sensorw) {
+		CDBG("kzalloc failed.\n");
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, imx074_sensorw);
+	imx074_init_client(client);
+	imx074_client = client;
+
+
+	CDBG("imx074_probe successed! rc = %d\n", rc);
+	return 0;
+
+probe_failure:
+	CDBG("imx074_probe failed! rc = %d\n", rc);
+	return rc;
+}
+
+static int __exit imx074_remove(struct i2c_client *client)
+{
+	struct imx074_work_t_t *sensorw = i2c_get_clientdata(client);
+	free_irq(client->irq, sensorw);
+	imx074_client = NULL;
+	kfree(sensorw);
+	return 0;
+}
+
+static struct i2c_driver imx074_i2c_driver = {
+	.id_table = imx074_i2c_id,
+	.probe  = imx074_i2c_probe,
+	.remove = __exit_p(imx074_i2c_remove),
+	.driver = {
+		.name = "imx074",
+	},
+};
+
+int imx074_sensor_config(void __user *argp)
+{
+	struct sensor_cfg_data cdata;
+	long   rc = 0;
+	if (copy_from_user(&cdata,
+		(void *)argp,
+		sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+	mutex_lock(&imx074_mut);
+	CDBG("imx074_sensor_config: cfgtype = %d\n",
+	cdata.cfgtype);
+	switch (cdata.cfgtype) {
+	case CFG_GET_PICT_FPS:
+		imx074_get_pict_fps(
+			cdata.cfg.gfps.prevfps,
+			&(cdata.cfg.gfps.pictfps));
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+			break;
+	case CFG_GET_PREV_L_PF:
+		cdata.cfg.prevl_pf =
+			imx074_get_prev_lines_pf();
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+			break;
+	case CFG_GET_PREV_P_PL:
+		cdata.cfg.prevp_pl =
+			imx074_get_prev_pixels_pl();
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+			break;
+
+	case CFG_GET_PICT_L_PF:
+		cdata.cfg.pictl_pf =
+			imx074_get_pict_lines_pf();
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+			break;
+	case CFG_GET_PICT_P_PL:
+		cdata.cfg.pictp_pl =
+			imx074_get_pict_pixels_pl();
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+			break;
+	case CFG_GET_PICT_MAX_EXP_LC:
+		cdata.cfg.pict_max_exp_lc =
+			imx074_get_pict_max_exp_lc();
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+			break;
+	case CFG_SET_FPS:
+	case CFG_SET_PICT_FPS:
+		rc = imx074_set_fps(&(cdata.cfg.fps));
+		break;
+	case CFG_SET_EXP_GAIN:
+		rc =
+			imx074_write_exp_gain(
+			cdata.cfg.exp_gain.gain,
+			cdata.cfg.exp_gain.line);
+			break;
+	case CFG_SET_PICT_EXP_GAIN:
+		rc =
+			imx074_set_pict_exp_gain(
+			cdata.cfg.exp_gain.gain,
+			cdata.cfg.exp_gain.line);
+			break;
+	case CFG_SET_MODE:
+		rc = imx074_set_sensor_mode(cdata.mode,
+			cdata.rs);
+			break;
+	case CFG_PWR_DOWN:
+		rc = imx074_power_down();
+			break;
+	case CFG_GET_CALIB_DATA:
+		rc = imx074_read_eeprom_data(&cdata);
+		if (rc < 0)
+			break;
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(cdata)))
+			rc = -EFAULT;
+		break;
+	case CFG_MOVE_FOCUS:
+		rc =
+			imx074_move_focus(
+			cdata.cfg.focus.dir,
+			cdata.cfg.focus.steps);
+			break;
+	case CFG_SET_DEFAULT_FOCUS:
+		rc =
+			imx074_set_default_focus(
+			cdata.cfg.focus.steps);
+			break;
+	case CFG_GET_AF_MAX_STEPS:
+		cdata.max_steps = IMX074_STEPS_NEAR_TO_CLOSEST_INF;
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+			break;
+	case CFG_SET_EFFECT:
+	default:
+		rc = -EFAULT;
+		break;
+	}
+
+	mutex_unlock(&imx074_mut);
+
+	return rc;
+}
+static int imx074_sensor_release(void)
+{
+	int rc = -EBADF;
+	mutex_lock(&imx074_mut);
+	if (machine_is_msm8x60_fluid())
+		imx074_poweroff_af();
+	imx074_power_down();
+	gpio_set_value_cansleep(imx074_ctrl->sensordata->sensor_reset, 0);
+	msleep(5);
+	gpio_direction_input(imx074_ctrl->sensordata->sensor_reset);
+	gpio_free(imx074_ctrl->sensordata->sensor_reset);
+	kfree(imx074_ctrl);
+	imx074_ctrl = NULL;
+	CDBG("imx074_release completed\n");
+	mutex_unlock(&imx074_mut);
+
+	return rc;
+}
+
+static int imx074_sensor_probe(const struct msm_camera_sensor_info *info,
+		struct msm_sensor_ctrl *s)
+{
+	int rc = 0;
+	rc = i2c_add_driver(&imx074_i2c_driver);
+	if (rc < 0 || imx074_client == NULL) {
+		rc = -ENOTSUPP;
+		goto probe_fail;
+	}
+	msm_camio_clk_rate_set(IMX074_DEFAULT_MASTER_CLK_RATE);
+	rc = imx074_probe_init_sensor(info);
+	if (rc < 0)
+		goto probe_fail;
+	s->s_init = imx074_sensor_open_init;
+	s->s_release = imx074_sensor_release;
+	s->s_config  = imx074_sensor_config;
+	s->s_mount_angle = info->sensor_platform_info->mount_angle;
+	imx074_probe_init_done(info);
+	return rc;
+
+probe_fail:
+	CDBG("imx074_sensor_probe: SENSOR PROBE FAILS!\n");
+	i2c_del_driver(&imx074_i2c_driver);
+	return rc;
+}
+
+static int __imx074_probe(struct platform_device *pdev)
+{
+
+	return msm_camera_drv_start(pdev, imx074_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = __imx074_probe,
+	.driver = {
+		.name = "msm_camera_imx074",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init imx074_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(imx074_init);
+
+MODULE_DESCRIPTION("Sony 13 MP Bayer sensor driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/media/video/msm/imx074.h b/drivers/media/video/msm/imx074.h
new file mode 100644
index 0000000..8be0fb7
--- /dev/null
+++ b/drivers/media/video/msm/imx074.h
@@ -0,0 +1,118 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef IMX074_H
+#define IMX074_H
+#include <linux/types.h>
+#include <mach/board.h>
+extern struct imx074_reg imx074_regs;
+struct reg_struct_init {
+    /* PLL setting */
+	uint8_t pre_pll_clk_div; /* 0x0305 */
+	uint8_t plstatim; /* 0x302b */
+	uint8_t reg_3024; /*ox3024*/
+	uint8_t image_orientation;  /* 0x0101*/
+	uint8_t vndmy_ablmgshlmt; /*0x300a*/
+	uint8_t y_opbaddr_start_di; /*0x3014*/
+	uint8_t reg_0x3015; /*0x3015*/
+	uint8_t reg_0x301c; /*0x301c*/
+	uint8_t reg_0x302c; /*0x302c*/
+	uint8_t reg_0x3031; /*0x3031*/
+	uint8_t reg_0x3041; /* 0x3041 */
+	uint8_t reg_0x3051; /* 0x3051 */
+	uint8_t reg_0x3053; /* 0x3053 */
+	uint8_t reg_0x3057; /* 0x3057 */
+	uint8_t reg_0x305c; /* 0x305c */
+	uint8_t reg_0x305d; /* 0x305d */
+	uint8_t reg_0x3060; /* 0x3060 */
+	uint8_t reg_0x3065; /* 0x3065 */
+	uint8_t reg_0x30aa; /* 0x30aa */
+	uint8_t reg_0x30ab;
+	uint8_t reg_0x30b0;
+	uint8_t reg_0x30b2;
+	uint8_t reg_0x30d3;
+	uint8_t reg_0x3106;
+	uint8_t reg_0x310c;
+	uint8_t reg_0x3304;
+	uint8_t reg_0x3305;
+	uint8_t reg_0x3306;
+	uint8_t reg_0x3307;
+	uint8_t reg_0x3308;
+	uint8_t reg_0x3309;
+	uint8_t reg_0x330a;
+	uint8_t reg_0x330b;
+	uint8_t reg_0x330c;
+	uint8_t reg_0x330d;
+	uint8_t reg_0x330f;
+	uint8_t reg_0x3381;
+};
+
+struct reg_struct {
+	uint8_t pll_multiplier; /* 0x0307 */
+	uint8_t frame_length_lines_hi; /* 0x0340*/
+	uint8_t frame_length_lines_lo; /* 0x0341*/
+	uint8_t y_addr_start;  /* 0x347 */
+	uint8_t y_add_end;  /* 0x034b */
+	uint8_t x_output_size_msb;  /* 0x034c */
+	uint8_t x_output_size_lsb;  /* 0x034d */
+	uint8_t y_output_size_msb; /* 0x034e */
+	uint8_t y_output_size_lsb; /* 0x034f */
+	uint8_t x_even_inc;  /* 0x0381 */
+	uint8_t x_odd_inc; /* 0x0383 */
+	uint8_t y_even_inc;  /* 0x0385 */
+	uint8_t y_odd_inc; /* 0x0387 */
+	uint8_t hmodeadd;   /* 0x3001 */
+	uint8_t vmodeadd;   /* 0x3016 */
+	uint8_t vapplinepos_start;/*ox3069*/
+	uint8_t vapplinepos_end;/*306b*/
+	uint8_t shutter;	/* 0x3086 */
+	uint8_t haddave;	/* 0x30e8 */
+	uint8_t lanesel;    /* 0x3301 */
+};
+
+struct imx074_i2c_reg_conf {
+	unsigned short waddr;
+	unsigned short wdata;
+};
+
+enum imx074_test_mode_t {
+	TEST_OFF,
+	TEST_1,
+	TEST_2,
+	TEST_3
+};
+
+enum imx074_resolution_t {
+	QTR_SIZE,
+	FULL_SIZE,
+	INVALID_SIZE
+};
+enum imx074_setting {
+	RES_PREVIEW,
+	RES_CAPTURE
+};
+enum mt9p012_reg_update {
+	/* Sensor egisters that need to be updated during initialization */
+	REG_INIT,
+	/* Sensor egisters that needs periodic I2C writes */
+	UPDATE_PERIODIC,
+	/* All the sensor Registers will be updated */
+	UPDATE_ALL,
+	/* Not valid update */
+	UPDATE_INVALID
+};
+
+struct imx074_reg {
+	const struct reg_struct_init  *reg_pat_init;
+	const struct reg_struct  *reg_pat;
+};
+#endif /* IMX074_H */
diff --git a/drivers/media/video/msm/imx074_reg.c b/drivers/media/video/msm/imx074_reg.c
new file mode 100644
index 0000000..ccc9b2f
--- /dev/null
+++ b/drivers/media/video/msm/imx074_reg.c
@@ -0,0 +1,111 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include "imx074.h"
+const struct reg_struct_init imx074_reg_init[1] = {
+	{
+		/* PLL setting */
+		0x02,	/* pll_divider 0x0305 */
+		0x4B,	/* plstatim 0x302b */
+		0x03,	/* reg_3024 */
+		0x00,	/* image_orientation 0x0101 */
+		0x80,	/* vndmy_ablmgshlmt 0x300a*/
+		0x08,	/* y_opbaddr_start_di 3014*/
+		0x37,	/* 0x3015*/
+		0x01,	/* 0x301c*/
+		0x05,	/* 0x302c*/
+		0x26,	/* 0x3031*/
+		0x60,	/* 0x3041*/
+		0x24,	/* 0x3051 CLK DIV*/
+		0x34,	/* 0x3053*/
+		0xc0,	/* 0x3057*/
+		0x09,	/* 0x305c*/
+		0x07,	/* 0x305d */
+		0x30,	/* 0x3060 */
+		0x00,	/* 0x3065 */
+		0x08,	/* 0x30aa */
+		0x1c,	/* 0x30ab */
+		0x32,	/* 0x30b0 */
+		0x83,	/* 0x30b2 */
+		0x04,	/* 0x30d3 */
+		0x78,	/* 0x3106 */
+		0x82,	/* 0x310c */
+		0x05,	/* 0x3304 */
+		0x04,	/* 0x3305 */
+		0x11,	/* 0x3306 */
+		0x02,	/* 0x3307 */
+		0x0c,	/* 0x3308 */
+		0x06,	/* 0x3309 */
+		0x08,	/* 0x330a */
+		0x04,	/* 0x330b */
+		0x08,	/* 0x330c */
+		0x06,	/* 0x330d */
+		0x01,	/* 0x330f */
+		0x00,	/* 0x3381 */
+
+	}
+};
+
+/* Preview / Snapshot register settings	*/
+const struct reg_struct	imx074_reg_pat[2] = {
+	/*preview*/
+	{
+		0x2D, /*pll_multiplier*/
+		0x06, /*frame_length_lines_hi 0x0340*/
+		0x2D, /* frame_length_lines_lo 0x0341*/
+		0x00, /* y_addr_start 0x347 */
+		0x2F, /* y_add_end 0x034b */
+		0x08, /* x_output_size_msb0x034c */
+		0x38, /* x_output_size_lsb0x034d */
+		0x06, /*  y_output_size_msb0x034e */
+		0x18, /*  y_output_size_lsb0x034f */
+		0x01, /* x_even_inc 0x0381 */
+		0x03, /* x_odd_inc 0x0383 */
+		0x01, /* y_even_inc 0x0385 */
+		0x03, /* y_odd_inc 0x0387 */
+		0x80, /* hmodeadd0x3001 */
+		0x16, /* vmodeadd0x3016 */
+		0x24, /* vapplinepos_startox3069*/
+		0x53, /* vapplinepos_end306b*/
+		0x00,/*  shutter 0x3086 */
+		0x80, /* haddave 0x30e8 */
+		0x83, /* lanesel 0x3301 */
+	},
+
+	/*snapshot*/
+	{
+		0x26, /*pll_multiplier*/
+		0x0C, /* frame_length_lines_hi 0x0340*/
+		0x90, /* frame_length_lines_lo 0x0341*/
+		0x00, /* y_addr_start 0x347 */
+		0x2F, /* y_add_end 0x034b */
+		0x10, /* x_output_size_msb0x034c */
+		0x70, /* x_output_size_lsb0x034d */
+		0x0c, /* y_output_size_msb0x034e */
+		0x30, /* y_output_size_lsb0x034f */
+		0x01, /* x_even_inc 0x0381 */
+		0x01, /* x_odd_inc 0x0383 */
+		0x01, /* y_even_inc 0x0385 */
+		0x01, /* y_odd_inc 0x0387 */
+		0x00, /* hmodeadd0x3001 */
+		0x06, /* vmodeadd0x3016 */
+		0x24, /* vapplinepos_startox3069*/
+		0x53, /* vapplinepos_end306b*/
+		0x00, /* shutter 0x3086 */
+		0x00, /* haddave 0x30e8 */
+		0x03, /* lanesel 0x3301 */
+	}
+};
+struct imx074_reg imx074_regs = {
+	.reg_pat_init = &imx074_reg_init[0],
+	.reg_pat = &imx074_reg_pat[0],
+};
diff --git a/drivers/media/video/msm/imx074_v4l2.c b/drivers/media/video/msm/imx074_v4l2.c
new file mode 100644
index 0000000..18a653d
--- /dev/null
+++ b/drivers/media/video/msm/imx074_v4l2.c
@@ -0,0 +1,1476 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <media/msm_camera.h>
+#include <media/v4l2-subdev.h>
+#include <mach/gpio.h>
+#include <mach/camera.h>
+#include <asm/mach-types.h>
+#include "imx074.h"
+#include "msm.h"
+
+/*SENSOR REGISTER DEFINES*/
+#define	IMX074_EEPROM_SLAVE_ADDR			0x52
+#define REG_GROUPED_PARAMETER_HOLD			0x0104
+#define GROUPED_PARAMETER_HOLD_OFF			0x00
+#define GROUPED_PARAMETER_HOLD				0x01
+#define REG_MODE_SELECT					0x100
+#define MODE_SELECT_STANDBY_MODE			0x00
+#define MODE_SELECT_STREAM				0x01
+/* Integration Time */
+#define REG_COARSE_INTEGRATION_TIME_HI			0x0202
+#define REG_COARSE_INTEGRATION_TIME_LO			0x0203
+/* Gain */
+#define REG_ANALOGUE_GAIN_CODE_GLOBAL_HI		0x0204
+#define REG_ANALOGUE_GAIN_CODE_GLOBAL_LO		0x0205
+/* PLL registers */
+#define REG_PLL_MULTIPLIER				0x0307
+#define REG_PRE_PLL_CLK_DIV				0x0305
+#define REG_PLSTATIM					0x302b
+#define REG_3024					0x3024
+#define REG_IMAGE_ORIENTATION				0x0101
+#define REG_VNDMY_ABLMGSHLMT				0x300a
+#define REG_Y_OPBADDR_START_DI				0x3014
+#define REG_3015					0x3015
+#define REG_301C					0x301C
+#define REG_302C					0x302C
+#define REG_3031					0x3031
+#define REG_3041					0x3041
+#define REG_3051					0x3051
+#define REG_3053					0x3053
+#define REG_3057					0x3057
+#define REG_305C					0x305C
+#define REG_305D					0x305D
+#define REG_3060					0x3060
+#define REG_3065					0x3065
+#define REG_30AA					0x30AA
+#define REG_30AB					0x30AB
+#define REG_30B0					0x30B0
+#define REG_30B2					0x30B2
+#define REG_30D3					0x30D3
+#define REG_3106					0x3106
+#define REG_310C					0x310C
+#define REG_3304					0x3304
+#define REG_3305					0x3305
+#define REG_3306					0x3306
+#define REG_3307					0x3307
+#define REG_3308					0x3308
+#define REG_3309					0x3309
+#define REG_330A					0x330A
+#define REG_330B					0x330B
+#define REG_330C					0x330C
+#define REG_330D					0x330D
+#define REG_330F					0x330F
+#define REG_3381					0x3381
+
+/* mode setting */
+#define REG_FRAME_LENGTH_LINES_HI			0x0340
+#define REG_FRAME_LENGTH_LINES_LO			0x0341
+#define REG_YADDR_START					0x0347
+#define REG_YAAAR_END					0x034b
+#define REG_X_OUTPUT_SIZE_MSB				0x034c
+#define REG_X_OUTPUT_SIZE_LSB				0x034d
+#define REG_Y_OUTPUT_SIZE_MSB				0x034e
+#define REG_Y_OUTPUT_SIZE_LSB				0x034f
+#define REG_X_EVEN_INC					0x0381
+#define REG_X_ODD_INC					0x0383
+#define REG_Y_EVEN_INC					0x0385
+#define REG_Y_ODD_INC					0x0387
+#define REG_HMODEADD					0x3001
+#define REG_VMODEADD					0x3016
+#define REG_VAPPLINE_START				0x3069
+#define REG_VAPPLINE_END				0x306b
+#define REG_SHUTTER					0x3086
+#define REG_HADDAVE					0x30e8
+#define REG_LANESEL					0x3301
+/* Test Pattern */
+#define REG_TEST_PATTERN_MODE				0x0601
+
+#define REG_LINE_LENGTH_PCK_HI				0x0342
+#define REG_LINE_LENGTH_PCK_LO				0x0343
+/*..... TYPE DECLARATIONS.....*/
+#define	IMX074_OFFSET					3
+#define	IMX074_DEFAULT_MASTER_CLK_RATE			24000000
+/* Full	Size */
+#define	IMX074_FULL_SIZE_WIDTH				4208
+#define	IMX074_FULL_SIZE_HEIGHT				3120
+#define	IMX074_FULL_SIZE_DUMMY_PIXELS			0
+#define	IMX074_FULL_SIZE_DUMMY_LINES			0
+/* Quarter Size	*/
+#define	IMX074_QTR_SIZE_WIDTH				2104
+#define	IMX074_QTR_SIZE_HEIGHT				1560
+#define	IMX074_QTR_SIZE_DUMMY_PIXELS			0
+#define	IMX074_QTR_SIZE_DUMMY_LINES			0
+/* Blanking as measured	on the scope */
+/* Full	Size */
+#define	IMX074_HRZ_FULL_BLK_PIXELS			264
+#define	IMX074_VER_FULL_BLK_LINES			96
+/* Quarter Size	*/
+#define	IMX074_HRZ_QTR_BLK_PIXELS			2368
+#define	IMX074_VER_QTR_BLK_LINES			21
+#define	Q8						0x100
+#define	Q10						0x400
+#define	IMX074_AF_I2C_SLAVE_ID				0x72
+#define	IMX074_STEPS_NEAR_TO_CLOSEST_INF		52
+#define	IMX074_TOTAL_STEPS_NEAR_TO_FAR			52
+static uint32_t imx074_l_region_code_per_step = 2;
+
+struct imx074_work_t {
+	struct work_struct work;
+};
+
+static struct imx074_work_t *imx074_sensorw;
+static struct i2c_client *imx074_client;
+
+struct imx074_ctrl_t {
+	const struct msm_camera_sensor_info *sensordata;
+	uint32_t sensormode;
+	uint32_t fps_divider;/* init to 1 * 0x00000400 */
+	uint32_t pict_fps_divider;/* init to 1 * 0x00000400 */
+	uint16_t fps;
+	int16_t curr_lens_pos;
+	uint16_t curr_step_pos;
+	uint16_t my_reg_gain;
+	uint32_t my_reg_line_count;
+	uint16_t total_lines_per_frame;
+	enum imx074_resolution_t prev_res;
+	enum imx074_resolution_t pict_res;
+	enum imx074_resolution_t curr_res;
+	enum imx074_test_mode_t set_test;
+	unsigned short imgaddr;
+
+	struct v4l2_subdev *sensor_dev;
+	struct imx074_format *fmt;
+};
+static uint8_t imx074_delay_msecs_stdby = 5;
+static uint16_t imx074_delay_msecs_stream = 5;
+static int32_t config_csi;
+
+static struct imx074_ctrl_t *imx074_ctrl;
+static DECLARE_WAIT_QUEUE_HEAD(imx074_wait_queue);
+DEFINE_MUTEX(imx074_mut);
+
+struct imx074_format {
+	enum v4l2_mbus_pixelcode code;
+	enum v4l2_colorspace colorspace;
+	u16 fmt;
+	u16 order;
+};
+/*=============================================================*/
+
+static int imx074_i2c_rxdata(unsigned short saddr,
+	unsigned char *rxdata, int length)
+{
+	struct i2c_msg msgs[] = {
+		{
+			.addr  = saddr,
+			.flags = 0,
+			.len   = 2,
+			.buf   = rxdata,
+		},
+		{
+			.addr  = saddr,
+			.flags = I2C_M_RD,
+			.len   = 2,
+			.buf   = rxdata,
+		},
+	};
+	if (i2c_transfer(imx074_client->adapter, msgs, 2) < 0) {
+		CDBG("imx074_i2c_rxdata failed!\n");
+		return -EIO;
+	}
+	return 0;
+}
+static int32_t imx074_i2c_txdata(unsigned short saddr,
+				unsigned char *txdata, int length)
+{
+	struct i2c_msg msg[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = length,
+			.buf = txdata,
+		 },
+	};
+	if (i2c_transfer(imx074_client->adapter, msg, 1) < 0) {
+		CDBG("imx074_i2c_txdata faild 0x%x\n", imx074_client->addr);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+
+static int32_t imx074_i2c_read(unsigned short raddr,
+	unsigned short *rdata, int rlen)
+{
+	int32_t rc = 0;
+	unsigned char buf[2];
+	if (!rdata)
+		return -EIO;
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (raddr & 0xFF00) >> 8;
+	buf[1] = (raddr & 0x00FF);
+	rc = imx074_i2c_rxdata(imx074_client->addr, buf, rlen);
+	if (rc < 0) {
+		CDBG("imx074_i2c_read 0x%x failed!\n", raddr);
+		return rc;
+	}
+	*rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]);
+	return rc;
+}
+
+static int imx074_af_i2c_rxdata_b(unsigned short saddr,
+	unsigned char *rxdata, int length)
+{
+	struct i2c_msg msgs[] = {
+		{
+		.addr  = saddr,
+		.flags = 0,
+		.len   = 1,
+		.buf   = rxdata,
+		},
+		{
+		.addr  = saddr,
+		.flags = I2C_M_RD,
+		.len   = 1,
+		.buf   = rxdata,
+		},
+	};
+
+	if (i2c_transfer(imx074_client->adapter, msgs, 2) < 0) {
+		CDBG("imx074_i2c_rxdata_b failed!\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t imx074_i2c_read_w_eeprom(unsigned short raddr,
+	unsigned short *rdata)
+{
+	int32_t rc;
+	unsigned char buf;
+	if (!rdata)
+		return -EIO;
+	/* Read 2 bytes in sequence */
+	buf = (raddr & 0x00FF);
+	rc = imx074_af_i2c_rxdata_b(IMX074_EEPROM_SLAVE_ADDR, &buf, 1);
+	if (rc < 0) {
+		CDBG("imx074_i2c_read_eeprom 0x%x failed!\n", raddr);
+		return rc;
+	}
+	*rdata = buf<<8;
+
+	/* Read Second byte of data */
+	buf = (raddr & 0x00FF) + 1;
+	rc = imx074_af_i2c_rxdata_b(IMX074_EEPROM_SLAVE_ADDR, &buf, 1);
+	if (rc < 0) {
+		CDBG("imx074_i2c_read_eeprom 0x%x failed!\n", raddr);
+		return rc;
+	}
+	*rdata |= buf;
+	return rc;
+}
+
+static int32_t imx074_i2c_write_b_sensor(unsigned short waddr, uint8_t bdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[3];
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = bdata;
+	CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata);
+	rc = imx074_i2c_txdata(imx074_client->addr, buf, 3);
+	if (rc < 0) {
+		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+			waddr, bdata);
+	}
+	return rc;
+}
+static int16_t imx074_i2c_write_b_af(unsigned short saddr,
+	unsigned short baddr, unsigned short bdata)
+{
+	int32_t rc;
+	unsigned char buf[2];
+	memset(buf, 0, sizeof(buf));
+	buf[0] = baddr;
+	buf[1] = bdata;
+	rc = imx074_i2c_txdata(saddr, buf, 2);
+	if (rc < 0)
+		CDBG("AFi2c_write failed, saddr = 0x%x addr = 0x%x, val =0x%x!",
+			saddr, baddr, bdata);
+	return rc;
+}
+
+static int32_t imx074_i2c_write_w_table(struct imx074_i2c_reg_conf const
+					 *reg_conf_tbl, int num)
+{
+	int i;
+	int32_t rc = -EIO;
+	for (i = 0; i < num; i++) {
+		rc = imx074_i2c_write_b_sensor(reg_conf_tbl->waddr,
+			reg_conf_tbl->wdata);
+		if (rc < 0)
+			break;
+		reg_conf_tbl++;
+	}
+	return rc;
+}
+static int16_t imx074_af_init(void)
+{
+	int32_t rc;
+	/* Initialize waveform */
+	rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x01, 0xA9);
+	rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x02, 0xD2);
+	rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x03, 0x0C);
+	rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x04, 0x14);
+	rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x05, 0xB6);
+	rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x06, 0x4F);
+	return rc;
+}
+
+static void imx074_get_pict_fps(uint16_t fps, uint16_t *pfps)
+{
+	/* input fps is preview fps in Q8 format */
+	uint16_t preview_frame_length_lines, snapshot_frame_length_lines;
+	uint32_t divider, d1;
+	uint32_t pclk_mult;/*Q10 */
+	/* Total frame_length_lines and line_length_pck for preview */
+	preview_frame_length_lines = IMX074_QTR_SIZE_HEIGHT +
+		IMX074_VER_QTR_BLK_LINES;
+	/* Total frame_length_lines and line_length_pck for snapshot */
+	snapshot_frame_length_lines = IMX074_FULL_SIZE_HEIGHT +
+		IMX074_VER_FULL_BLK_LINES;
+	d1 = preview_frame_length_lines * 0x00010000 /
+		snapshot_frame_length_lines;
+	pclk_mult =
+		(uint32_t) ((imx074_regs.reg_pat[RES_CAPTURE].pll_multiplier *
+		0x00010000) /
+		(imx074_regs.reg_pat[RES_PREVIEW].pll_multiplier));
+	divider = d1 * pclk_mult / 0x00010000;
+	*pfps = (uint16_t) (fps * divider / 0x00010000);
+}
+
+static uint16_t imx074_get_prev_lines_pf(void)
+{
+	if (imx074_ctrl->prev_res == QTR_SIZE)
+		return IMX074_QTR_SIZE_HEIGHT + IMX074_VER_QTR_BLK_LINES;
+	else
+		return IMX074_FULL_SIZE_HEIGHT + IMX074_VER_FULL_BLK_LINES;
+
+}
+
+static uint16_t imx074_get_prev_pixels_pl(void)
+{
+	if (imx074_ctrl->prev_res == QTR_SIZE)
+		return IMX074_QTR_SIZE_WIDTH + IMX074_HRZ_QTR_BLK_PIXELS;
+	else
+		return IMX074_FULL_SIZE_WIDTH + IMX074_HRZ_FULL_BLK_PIXELS;
+}
+
+static uint16_t imx074_get_pict_lines_pf(void)
+{
+		if (imx074_ctrl->pict_res == QTR_SIZE)
+			return IMX074_QTR_SIZE_HEIGHT +
+				IMX074_VER_QTR_BLK_LINES;
+		else
+			return IMX074_FULL_SIZE_HEIGHT +
+				IMX074_VER_FULL_BLK_LINES;
+}
+
+static uint16_t imx074_get_pict_pixels_pl(void)
+{
+	if (imx074_ctrl->pict_res == QTR_SIZE)
+		return IMX074_QTR_SIZE_WIDTH +
+			IMX074_HRZ_QTR_BLK_PIXELS;
+	else
+		return IMX074_FULL_SIZE_WIDTH +
+			IMX074_HRZ_FULL_BLK_PIXELS;
+}
+
+static uint32_t imx074_get_pict_max_exp_lc(void)
+{
+	if (imx074_ctrl->pict_res == QTR_SIZE)
+		return (IMX074_QTR_SIZE_HEIGHT +
+			IMX074_VER_QTR_BLK_LINES)*24;
+	else
+		return (IMX074_FULL_SIZE_HEIGHT +
+			IMX074_VER_FULL_BLK_LINES)*24;
+}
+
+static int32_t imx074_set_fps(struct fps_cfg	*fps)
+{
+	uint16_t total_lines_per_frame;
+	int32_t rc = 0;
+	imx074_ctrl->fps_divider = fps->fps_div;
+	imx074_ctrl->pict_fps_divider = fps->pict_fps_div;
+	total_lines_per_frame = (uint16_t)(((IMX074_QTR_SIZE_HEIGHT +
+		IMX074_VER_QTR_BLK_LINES) * imx074_ctrl->fps_divider) / 0x400);
+	if (imx074_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_HI,
+		((total_lines_per_frame & 0xFF00) >> 8)) < 0)
+		return rc;
+	if (imx074_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_LO,
+		(total_lines_per_frame & 0x00FF)) < 0)
+		return rc;
+	return rc;
+}
+
+static int32_t imx074_write_exp_gain(uint16_t gain, uint32_t line)
+{
+	static uint16_t max_legal_gain = 0x00E0;
+	uint8_t gain_msb, gain_lsb;
+	uint8_t intg_time_msb, intg_time_lsb;
+	uint8_t frame_length_line_msb, frame_length_line_lsb;
+	uint16_t frame_length_lines;
+	int32_t rc = -1;
+	CDBG("imx074_write_exp_gain : gain = %d line = %d", gain, line);
+	if (imx074_ctrl->curr_res  == QTR_SIZE) {
+		frame_length_lines = IMX074_QTR_SIZE_HEIGHT +
+			IMX074_VER_QTR_BLK_LINES;
+		frame_length_lines = frame_length_lines *
+			imx074_ctrl->fps_divider / 0x400;
+	} else {
+		frame_length_lines = IMX074_FULL_SIZE_HEIGHT +
+			IMX074_VER_FULL_BLK_LINES;
+		frame_length_lines = frame_length_lines *
+			imx074_ctrl->pict_fps_divider / 0x400;
+	}
+	if (line > (frame_length_lines - IMX074_OFFSET))
+		frame_length_lines = line + IMX074_OFFSET;
+
+	CDBG("imx074 setting line = %d\n", line);
+
+
+	CDBG("imx074 setting frame_length_lines = %d\n",
+					frame_length_lines);
+
+	if (gain > max_legal_gain)
+		/* range: 0 to 224 */
+		gain = max_legal_gain;
+
+	/* update gain registers */
+	gain_msb = (uint8_t) ((gain & 0xFF00) >> 8);
+	gain_lsb = (uint8_t) (gain & 0x00FF);
+
+	frame_length_line_msb = (uint8_t) ((frame_length_lines & 0xFF00) >> 8);
+	frame_length_line_lsb = (uint8_t) (frame_length_lines & 0x00FF);
+
+	/* update line count registers */
+	intg_time_msb = (uint8_t) ((line & 0xFF00) >> 8);
+	intg_time_lsb = (uint8_t) (line & 0x00FF);
+
+	rc = imx074_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
+					GROUPED_PARAMETER_HOLD);
+	if (rc < 0)
+		return rc;
+	CDBG("imx074 setting REG_ANALOGUE_GAIN_CODE_GLOBAL_HI = 0x%X\n",
+					gain_msb);
+	rc = imx074_i2c_write_b_sensor(REG_ANALOGUE_GAIN_CODE_GLOBAL_HI,
+					gain_msb);
+	if (rc < 0)
+		return rc;
+	CDBG("imx074 setting REG_ANALOGUE_GAIN_CODE_GLOBAL_LO = 0x%X\n",
+					gain_lsb);
+	rc = imx074_i2c_write_b_sensor(REG_ANALOGUE_GAIN_CODE_GLOBAL_LO,
+					gain_lsb);
+	if (rc < 0)
+		return rc;
+
+	CDBG("imx074 setting REG_FRAME_LENGTH_LINES_HI = 0x%X\n",
+					frame_length_line_msb);
+	rc = imx074_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_HI,
+			frame_length_line_msb);
+	if (rc < 0)
+		return rc;
+
+	CDBG("imx074 setting REG_FRAME_LENGTH_LINES_LO = 0x%X\n",
+			frame_length_line_lsb);
+	rc = imx074_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_LO,
+			frame_length_line_lsb);
+	if (rc < 0)
+		return rc;
+
+	CDBG("imx074 setting REG_COARSE_INTEGRATION_TIME_HI = 0x%X\n",
+					intg_time_msb);
+	rc = imx074_i2c_write_b_sensor(REG_COARSE_INTEGRATION_TIME_HI,
+					intg_time_msb);
+	if (rc < 0)
+		return rc;
+
+	CDBG("imx074 setting REG_COARSE_INTEGRATION_TIME_LO = 0x%X\n",
+					intg_time_lsb);
+	rc = imx074_i2c_write_b_sensor(REG_COARSE_INTEGRATION_TIME_LO,
+					intg_time_lsb);
+	if (rc < 0)
+		return rc;
+
+	rc = imx074_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
+					GROUPED_PARAMETER_HOLD_OFF);
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+
+static int32_t imx074_set_pict_exp_gain(uint16_t gain, uint32_t line)
+{
+	int32_t rc = 0;
+	rc = imx074_write_exp_gain(gain, line);
+	return rc;
+}
+
+static int32_t imx074_move_focus(int direction,
+	int32_t num_steps)
+{
+	int32_t step_direction, dest_step_position, bit_mask;
+	int32_t rc = 0;
+
+	if (num_steps == 0)
+		return rc;
+
+	if (direction == MOVE_NEAR) {
+		step_direction = 1;
+		bit_mask = 0x80;
+	} else if (direction == MOVE_FAR) {
+		step_direction = -1;
+		bit_mask = 0x00;
+	} else {
+		CDBG("imx074_move_focus: Illegal focus direction");
+		return -EINVAL;
+	}
+	dest_step_position = imx074_ctrl->curr_step_pos +
+		(step_direction * num_steps);
+	if (dest_step_position < 0)
+		dest_step_position = 0;
+	else if (dest_step_position > IMX074_TOTAL_STEPS_NEAR_TO_FAR)
+		dest_step_position = IMX074_TOTAL_STEPS_NEAR_TO_FAR;
+	rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x00,
+		((num_steps * imx074_l_region_code_per_step) | bit_mask));
+	CDBG("%s: Index: %d\n", __func__, dest_step_position);
+	imx074_ctrl->curr_step_pos = dest_step_position;
+	return rc;
+}
+
+
+static int32_t imx074_set_default_focus(uint8_t af_step)
+{
+	int32_t rc;
+	/* Initialize to infinity */
+	rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x00, 0x7F);
+	rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x00, 0x7F);
+	imx074_ctrl->curr_step_pos = 0;
+	return rc;
+}
+static int32_t imx074_test(enum imx074_test_mode_t mo)
+{
+	int32_t rc = 0;
+	if (mo == TEST_OFF)
+		return rc;
+	else {
+		/* Set mo to 2 inorder to enable test pattern*/
+		if (imx074_i2c_write_b_sensor(REG_TEST_PATTERN_MODE,
+			(uint8_t) mo) < 0) {
+			return rc;
+		}
+	}
+	return rc;
+}
+static int32_t imx074_sensor_setting(int update_type, int rt)
+{
+	int32_t rc = 0;
+	struct msm_camera_csid_params imx074_csid_params;
+	struct msm_camera_csiphy_params imx074_csiphy_params;
+	switch (update_type) {
+	case REG_INIT:
+		if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+			struct imx074_i2c_reg_conf init_tbl[] = {
+				{REG_PRE_PLL_CLK_DIV,
+					imx074_regs.reg_pat_init[0].
+					pre_pll_clk_div},
+				{REG_PLSTATIM,
+					imx074_regs.reg_pat_init[0].
+					plstatim},
+				{REG_3024,
+					imx074_regs.reg_pat_init[0].
+					reg_3024},
+				{REG_IMAGE_ORIENTATION,
+					imx074_regs.reg_pat_init[0].
+					image_orientation},
+				{REG_VNDMY_ABLMGSHLMT,
+					imx074_regs.reg_pat_init[0].
+					vndmy_ablmgshlmt},
+				{REG_Y_OPBADDR_START_DI,
+					imx074_regs.reg_pat_init[0].
+					y_opbaddr_start_di},
+				{REG_3015,
+					imx074_regs.reg_pat_init[0].
+					reg_0x3015},
+				{REG_301C,
+					imx074_regs.reg_pat_init[0].
+					reg_0x301c},
+				{REG_302C,
+					imx074_regs.reg_pat_init[0].
+					reg_0x302c},
+				{REG_3031,
+					imx074_regs.reg_pat_init[0].reg_0x3031},
+				{REG_3041,
+					imx074_regs.reg_pat_init[0].reg_0x3041},
+				{REG_3051,
+					imx074_regs.reg_pat_init[0].reg_0x3051},
+				{REG_3053,
+					imx074_regs.reg_pat_init[0].reg_0x3053},
+				{REG_3057,
+					imx074_regs.reg_pat_init[0].reg_0x3057},
+				{REG_305C,
+					imx074_regs.reg_pat_init[0].reg_0x305c},
+				{REG_305D,
+					imx074_regs.reg_pat_init[0].reg_0x305d},
+				{REG_3060,
+					imx074_regs.reg_pat_init[0].reg_0x3060},
+				{REG_3065,
+					imx074_regs.reg_pat_init[0].reg_0x3065},
+				{REG_30AA,
+					imx074_regs.reg_pat_init[0].reg_0x30aa},
+				{REG_30AB,
+					imx074_regs.reg_pat_init[0].reg_0x30ab},
+				{REG_30B0,
+					imx074_regs.reg_pat_init[0].reg_0x30b0},
+				{REG_30B2,
+					imx074_regs.reg_pat_init[0].reg_0x30b2},
+				{REG_30D3,
+					imx074_regs.reg_pat_init[0].reg_0x30d3},
+				{REG_3106,
+					imx074_regs.reg_pat_init[0].reg_0x3106},
+				{REG_310C,
+					imx074_regs.reg_pat_init[0].reg_0x310c},
+				{REG_3304,
+					imx074_regs.reg_pat_init[0].reg_0x3304},
+				{REG_3305,
+					imx074_regs.reg_pat_init[0].reg_0x3305},
+				{REG_3306,
+					imx074_regs.reg_pat_init[0].reg_0x3306},
+				{REG_3307,
+					imx074_regs.reg_pat_init[0].reg_0x3307},
+				{REG_3308,
+					imx074_regs.reg_pat_init[0].reg_0x3308},
+				{REG_3309,
+					imx074_regs.reg_pat_init[0].reg_0x3309},
+				{REG_330A,
+					imx074_regs.reg_pat_init[0].reg_0x330a},
+				{REG_330B,
+					imx074_regs.reg_pat_init[0].reg_0x330b},
+				{REG_330C,
+					imx074_regs.reg_pat_init[0].reg_0x330c},
+				{REG_330D,
+					imx074_regs.reg_pat_init[0].reg_0x330d},
+				{REG_330F,
+					imx074_regs.reg_pat_init[0].reg_0x330f},
+				{REG_3381,
+					imx074_regs.reg_pat_init[0].reg_0x3381},
+			};
+			struct imx074_i2c_reg_conf init_mode_tbl[] = {
+				{REG_GROUPED_PARAMETER_HOLD,
+					GROUPED_PARAMETER_HOLD},
+				{REG_PLL_MULTIPLIER,
+					imx074_regs.reg_pat[rt].
+					pll_multiplier},
+				{REG_FRAME_LENGTH_LINES_HI,
+					imx074_regs.reg_pat[rt].
+					frame_length_lines_hi},
+				{REG_FRAME_LENGTH_LINES_LO,
+					imx074_regs.reg_pat[rt].
+					frame_length_lines_lo},
+				{REG_YADDR_START ,
+					imx074_regs.reg_pat[rt].
+					y_addr_start},
+				{REG_YAAAR_END,
+					imx074_regs.reg_pat[rt].
+					y_add_end},
+				{REG_X_OUTPUT_SIZE_MSB,
+					imx074_regs.reg_pat[rt].
+					x_output_size_msb},
+				{REG_X_OUTPUT_SIZE_LSB,
+					imx074_regs.reg_pat[rt].
+					x_output_size_lsb},
+				{REG_Y_OUTPUT_SIZE_MSB,
+					imx074_regs.reg_pat[rt].
+					y_output_size_msb},
+				{REG_Y_OUTPUT_SIZE_LSB ,
+					imx074_regs.reg_pat[rt].
+					y_output_size_lsb},
+				{REG_X_EVEN_INC,
+					imx074_regs.reg_pat[rt].
+					x_even_inc},
+				{REG_X_ODD_INC,
+					imx074_regs.reg_pat[rt].
+					x_odd_inc},
+				{REG_Y_EVEN_INC,
+					imx074_regs.reg_pat[rt].
+					y_even_inc},
+				{REG_Y_ODD_INC,
+					imx074_regs.reg_pat[rt].
+					y_odd_inc},
+				{REG_HMODEADD,
+					imx074_regs.reg_pat[rt].
+					hmodeadd},
+				{REG_VMODEADD,
+					imx074_regs.reg_pat[rt].
+					vmodeadd},
+				{REG_VAPPLINE_START,
+					imx074_regs.reg_pat[rt].
+					vapplinepos_start},
+				{REG_VAPPLINE_END,
+					imx074_regs.reg_pat[rt].
+					vapplinepos_end},
+				{REG_SHUTTER,
+					imx074_regs.reg_pat[rt].
+					shutter},
+				{REG_HADDAVE,
+					imx074_regs.reg_pat[rt].
+					haddave},
+				{REG_LANESEL,
+					imx074_regs.reg_pat[rt].
+					lanesel},
+				{REG_GROUPED_PARAMETER_HOLD,
+					GROUPED_PARAMETER_HOLD_OFF},
+
+			};
+			/* reset fps_divider */
+			imx074_ctrl->fps = 30 * Q8;
+			imx074_ctrl->fps_divider = 1 * 0x400;
+			/* stop streaming */
+			rc = imx074_i2c_write_b_sensor(REG_MODE_SELECT,
+				MODE_SELECT_STANDBY_MODE);
+			if (rc < 0)
+				return rc;
+			msleep(imx074_delay_msecs_stdby);
+			rc = imx074_i2c_write_w_table(&init_tbl[0],
+				ARRAY_SIZE(init_tbl));
+			if (rc < 0)
+				return rc;
+			rc = imx074_i2c_write_w_table(&init_mode_tbl[0],
+				ARRAY_SIZE(init_mode_tbl));
+			if (rc < 0)
+				return rc;
+			rc = imx074_test(imx074_ctrl->set_test);
+			return rc;
+		}
+		break;
+	case UPDATE_PERIODIC:
+		if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+			struct imx074_i2c_reg_conf mode_tbl[] = {
+				{REG_GROUPED_PARAMETER_HOLD,
+					GROUPED_PARAMETER_HOLD},
+				{REG_PLL_MULTIPLIER,
+					imx074_regs.reg_pat[rt].
+					pll_multiplier},
+				{REG_FRAME_LENGTH_LINES_HI,
+					imx074_regs.reg_pat[rt].
+					frame_length_lines_hi},
+				{REG_FRAME_LENGTH_LINES_LO,
+					imx074_regs.reg_pat[rt].
+					frame_length_lines_lo},
+				{REG_YADDR_START ,
+					imx074_regs.reg_pat[rt].
+					y_addr_start},
+				{REG_YAAAR_END,
+					imx074_regs.reg_pat[rt].
+					y_add_end},
+				{REG_X_OUTPUT_SIZE_MSB,
+					imx074_regs.reg_pat[rt].
+					x_output_size_msb},
+				{REG_X_OUTPUT_SIZE_LSB,
+					imx074_regs.reg_pat[rt].
+					x_output_size_lsb},
+				{REG_Y_OUTPUT_SIZE_MSB,
+					imx074_regs.reg_pat[rt].
+					y_output_size_msb},
+				{REG_Y_OUTPUT_SIZE_LSB ,
+					imx074_regs.reg_pat[rt].
+					y_output_size_lsb},
+				{REG_X_EVEN_INC,
+					imx074_regs.reg_pat[rt].
+					x_even_inc},
+				{REG_X_ODD_INC,
+					imx074_regs.reg_pat[rt].
+					x_odd_inc},
+				{REG_Y_EVEN_INC,
+					imx074_regs.reg_pat[rt].
+					y_even_inc},
+				{REG_Y_ODD_INC,
+					imx074_regs.reg_pat[rt].
+					y_odd_inc},
+				{REG_HMODEADD,
+					imx074_regs.reg_pat[rt].
+					hmodeadd},
+				{REG_VMODEADD,
+					imx074_regs.reg_pat[rt].
+					vmodeadd},
+				{REG_VAPPLINE_START,
+					imx074_regs.reg_pat[rt].
+					vapplinepos_start},
+				{REG_VAPPLINE_END,
+					imx074_regs.reg_pat[rt].
+					vapplinepos_end},
+				{REG_SHUTTER,
+					imx074_regs.reg_pat[rt].
+					shutter},
+				{REG_HADDAVE,
+					imx074_regs.reg_pat[rt].
+					haddave},
+				{REG_LANESEL,
+					imx074_regs.reg_pat[rt].
+					lanesel},
+				{REG_GROUPED_PARAMETER_HOLD,
+					GROUPED_PARAMETER_HOLD_OFF},
+			};
+
+			/* stop streaming */
+			rc = imx074_i2c_write_b_sensor(REG_MODE_SELECT,
+				MODE_SELECT_STANDBY_MODE);
+			msleep(imx074_delay_msecs_stdby);
+			rc = imx074_i2c_write_w_table(&mode_tbl[0],
+				ARRAY_SIZE(mode_tbl));
+			if (config_csi == 0) {
+				struct msm_camera_csid_vc_cfg imx074_vccfg[] = {
+					{0, CSI_RAW10, CSI_DECODE_10BIT},
+					{1, CSI_EMBED_DATA, CSI_DECODE_8BIT},
+				};
+				imx074_csid_params.lane_cnt = 4;
+				imx074_csid_params.lane_assign = 0xe4;
+				imx074_csid_params.lut_params.num_cid =
+					ARRAY_SIZE(imx074_vccfg);
+				imx074_csid_params.lut_params.vc_cfg =
+					&imx074_vccfg[0];
+				imx074_csiphy_params.lane_cnt = 4;
+				imx074_csiphy_params.settle_cnt = 0x1B;
+				rc = msm_camio_csid_config(&imx074_csid_params);
+				v4l2_subdev_notify(imx074_ctrl->sensor_dev,
+						NOTIFY_CID_CHANGE, NULL);
+				mb();
+				rc = msm_camio_csiphy_config
+					(&imx074_csiphy_params);
+				mb();
+				/*imx074_delay_msecs_stdby*/
+				msleep(imx074_delay_msecs_stream);
+				config_csi = 1;
+			}
+			if (rc < 0)
+				return rc;
+			rc = imx074_i2c_write_b_sensor(REG_MODE_SELECT,
+				MODE_SELECT_STREAM);
+			if (rc < 0)
+				return rc;
+			msleep(imx074_delay_msecs_stream);
+		}
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+
+static int32_t imx074_video_config(int mode)
+{
+
+	int32_t	rc = 0;
+	int	rt;
+	/* change sensor resolution	if needed */
+	if (imx074_ctrl->prev_res == QTR_SIZE)
+		rt = RES_PREVIEW;
+	else
+		rt = RES_CAPTURE;
+
+	if (imx074_sensor_setting(UPDATE_PERIODIC, rt) < 0)
+		return rc;
+	imx074_ctrl->curr_res = imx074_ctrl->prev_res;
+	imx074_ctrl->sensormode = mode;
+	return rc;
+}
+
+static int32_t imx074_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+	int rt = RES_PREVIEW; /* TODO: Used without initialization, guessing. */
+	/* change sensor resolution if needed */
+	if (imx074_ctrl->curr_res != imx074_ctrl->pict_res) {
+		if (imx074_ctrl->pict_res == QTR_SIZE)
+			rt = RES_PREVIEW;
+		else
+			rt = RES_CAPTURE;
+	}
+	if (imx074_sensor_setting(UPDATE_PERIODIC, rt) < 0)
+		return rc;
+	imx074_ctrl->curr_res = imx074_ctrl->pict_res;
+	imx074_ctrl->sensormode = mode;
+	return rc;
+}
+static int32_t imx074_raw_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+	int rt = RES_PREVIEW; /* TODO: Used without initialization, guessing. */
+	/* change sensor resolution if needed */
+	if (imx074_ctrl->curr_res != imx074_ctrl->pict_res) {
+		if (imx074_ctrl->pict_res == QTR_SIZE)
+			rt = RES_PREVIEW;
+		else
+			rt = RES_CAPTURE;
+	}
+	if (imx074_sensor_setting(UPDATE_PERIODIC, rt) < 0)
+		return rc;
+	imx074_ctrl->curr_res = imx074_ctrl->pict_res;
+	imx074_ctrl->sensormode = mode;
+	return rc;
+}
+static int32_t imx074_set_sensor_mode(int mode,
+	int res)
+{
+	int32_t rc = 0;
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		rc = imx074_video_config(mode);
+		break;
+	case SENSOR_SNAPSHOT_MODE:
+		rc = imx074_snapshot_config(mode);
+		break;
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		rc = imx074_raw_snapshot_config(mode);
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+static int32_t imx074_power_down(void)
+{
+	imx074_i2c_write_b_sensor(REG_MODE_SELECT,
+		MODE_SELECT_STANDBY_MODE);
+	msleep(imx074_delay_msecs_stdby);
+	return 0;
+}
+static int imx074_probe_init_done(const struct msm_camera_sensor_info *data)
+{
+	gpio_set_value_cansleep(data->sensor_reset, 0);
+	gpio_direction_input(data->sensor_reset);
+	gpio_free(data->sensor_reset);
+	return 0;
+}
+
+static int imx074_read_eeprom_data(struct sensor_cfg_data *cfg)
+{
+	int32_t rc = 0;
+	uint16_t eepromdata = 0;
+	uint8_t addr = 0;
+
+	addr = 0x10;
+	rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
+	if (rc < 0) {
+		CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
+		return rc;
+	}
+	cfg->cfg.calib_info.r_over_g = eepromdata;
+
+	addr = 0x12;
+	rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
+	if (rc < 0) {
+		CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
+		return rc;
+	}
+	cfg->cfg.calib_info.b_over_g = eepromdata;
+
+	addr = 0x14;
+	rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
+	if (rc < 0) {
+		CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
+		return rc;
+	}
+	cfg->cfg.calib_info.gr_over_gb = eepromdata;
+
+	addr = 0x1A;
+	rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
+	if (rc < 0) {
+		CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
+		return rc;
+	}
+	cfg->cfg.calib_info.macro_2_inf = eepromdata;
+
+	addr = 0x1C;
+	rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
+	if (rc < 0) {
+		CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
+		return rc;
+	}
+	cfg->cfg.calib_info.inf_2_macro = eepromdata;
+
+	addr = 0x1E;
+	rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
+	if (rc < 0) {
+		CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
+		return rc;
+	}
+	cfg->cfg.calib_info.stroke_amt = eepromdata;
+
+	addr = 0x20;
+	rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
+	if (rc < 0) {
+		CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
+		return rc;
+	}
+	cfg->cfg.calib_info.af_pos_1m = eepromdata;
+
+	addr = 0x22;
+	rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
+	if (rc < 0) {
+		CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
+		return rc;
+	}
+	cfg->cfg.calib_info.af_pos_inf = eepromdata;
+
+	return rc;
+}
+
+static int imx074_probe_init_sensor(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc = 0;
+	unsigned short chipidl, chipidh;
+	CDBG("%s: %d\n", __func__, __LINE__);
+	rc = gpio_request(data->sensor_reset, "imx074");
+	CDBG("imx074_probe_init_sensor\n");
+	if (!rc) {
+		CDBG("sensor_reset = %d\n", rc);
+		gpio_direction_output(data->sensor_reset, 0);
+		usleep_range(5000, 6000);
+		gpio_set_value_cansleep(data->sensor_reset, 1);
+		usleep_range(5000, 6000);
+	} else {
+		CDBG("gpio reset fail");
+		goto init_probe_done;
+	}
+	CDBG("imx074_probe_init_sensor is called\n");
+	/* 3. Read sensor Model ID: */
+	rc = imx074_i2c_read(0x0000, &chipidh, 1);
+	if (rc < 0) {
+		CDBG("Model read failed\n");
+		goto init_probe_fail;
+	}
+	rc = imx074_i2c_read(0x0001, &chipidl, 1);
+	if (rc < 0) {
+		CDBG("Model read failed\n");
+		goto init_probe_fail;
+	}
+	CDBG("imx074 model_id = 0x%x  0x%x\n", chipidh, chipidl);
+	/* 4. Compare sensor ID to IMX074 ID: */
+	if (chipidh != 0x00 || chipidl != 0x74) {
+		rc = -ENODEV;
+		CDBG("imx074_probe_init_sensor fail chip id doesnot match\n");
+		goto init_probe_fail;
+	}
+	goto init_probe_done;
+init_probe_fail:
+	CDBG("imx074_probe_init_sensor fails\n");
+	imx074_probe_init_done(data);
+init_probe_done:
+	CDBG(" imx074_probe_init_sensor finishes\n");
+	return rc;
+	}
+static int32_t imx074_poweron_af(void)
+{
+	int32_t rc = 0;
+	CDBG("imx074 enable AF actuator, gpio = %d\n",
+			imx074_ctrl->sensordata->vcm_pwd);
+	rc = gpio_request(imx074_ctrl->sensordata->vcm_pwd, "imx074");
+	if (!rc) {
+		gpio_direction_output(imx074_ctrl->sensordata->vcm_pwd, 1);
+		msleep(20);
+		rc = imx074_af_init();
+		if (rc < 0)
+			CDBG("imx074 AF initialisation failed\n");
+	} else {
+		CDBG("%s: AF PowerON gpio_request failed %d\n", __func__, rc);
+	 }
+	return rc;
+}
+static void imx074_poweroff_af(void)
+{
+	gpio_set_value_cansleep(imx074_ctrl->sensordata->vcm_pwd, 0);
+	gpio_free(imx074_ctrl->sensordata->vcm_pwd);
+}
+/* camsensor_iu060f_imx074_reset */
+int imx074_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc = 0;
+	CDBG("%s: %d\n", __func__, __LINE__);
+	CDBG("Calling imx074_sensor_open_init\n");
+	imx074_ctrl->fps_divider = 1 * 0x00000400;
+	imx074_ctrl->pict_fps_divider = 1 * 0x00000400;
+	imx074_ctrl->fps = 30 * Q8;
+	imx074_ctrl->set_test = TEST_OFF;
+	imx074_ctrl->prev_res = QTR_SIZE;
+	imx074_ctrl->pict_res = FULL_SIZE;
+	imx074_ctrl->curr_res = INVALID_SIZE;
+	config_csi = 0;
+
+	if (data)
+		imx074_ctrl->sensordata = data;
+
+	/* enable mclk first */
+	msm_camio_clk_rate_set(IMX074_DEFAULT_MASTER_CLK_RATE);
+	usleep_range(1000, 2000);
+	rc = imx074_probe_init_sensor(data);
+	if (rc < 0) {
+		CDBG("Calling imx074_sensor_open_init fail\n");
+		goto probe_fail;
+	}
+
+	rc = imx074_sensor_setting(REG_INIT, RES_PREVIEW);
+	if (rc < 0) {
+		CDBG("imx074_sensor_setting failed\n");
+		goto init_fail;
+	}
+	if (machine_is_msm8x60_fluid())
+		rc = imx074_poweron_af();
+	else
+		rc = imx074_af_init();
+	if (rc < 0) {
+		CDBG("AF initialisation failed\n");
+		goto init_fail;
+	} else
+		goto init_done;
+probe_fail:
+	CDBG(" imx074_sensor_open_init probe fail\n");
+	kfree(imx074_ctrl);
+	return rc;
+init_fail:
+	CDBG(" imx074_sensor_open_init fail\n");
+	imx074_probe_init_done(data);
+	kfree(imx074_ctrl);
+init_done:
+	CDBG("imx074_sensor_open_init done\n");
+	return rc;
+}
+static int imx074_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&imx074_wait_queue);
+	return 0;
+}
+
+static const struct i2c_device_id imx074_i2c_id[] = {
+	{"imx074", 0},
+	{ }
+};
+
+static int imx074_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int rc = 0;
+	CDBG("imx074_probe called!\n");
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		CDBG("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	imx074_sensorw = kzalloc(sizeof(struct imx074_work_t), GFP_KERNEL);
+	if (!imx074_sensorw) {
+		CDBG("kzalloc failed.\n");
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, imx074_sensorw);
+	imx074_init_client(client);
+	imx074_client = client;
+
+
+	CDBG("imx074_probe successed! rc = %d\n", rc);
+	return 0;
+
+probe_failure:
+	CDBG("imx074_probe failed! rc = %d\n", rc);
+	return rc;
+}
+
+static int __exit imx074_remove(struct i2c_client *client)
+{
+	struct imx074_work_t_t *sensorw = i2c_get_clientdata(client);
+	free_irq(client->irq, sensorw);
+	imx074_client = NULL;
+	kfree(sensorw);
+	return 0;
+}
+
+static struct i2c_driver imx074_i2c_driver = {
+	.id_table = imx074_i2c_id,
+	.probe  = imx074_i2c_probe,
+	.remove = __exit_p(imx074_i2c_remove),
+	.driver = {
+		.name = "imx074",
+	},
+};
+
+int imx074_sensor_config(void __user *argp)
+{
+	struct sensor_cfg_data cdata;
+	long   rc = 0;
+	if (copy_from_user(&cdata,
+		(void *)argp,
+		sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+	mutex_lock(&imx074_mut);
+	CDBG("imx074_sensor_config: cfgtype = %d\n",
+	cdata.cfgtype);
+	switch (cdata.cfgtype) {
+	case CFG_GET_PICT_FPS:
+		imx074_get_pict_fps(
+			cdata.cfg.gfps.prevfps,
+			&(cdata.cfg.gfps.pictfps));
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+			break;
+	case CFG_GET_PREV_L_PF:
+		cdata.cfg.prevl_pf =
+			imx074_get_prev_lines_pf();
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+			break;
+	case CFG_GET_PREV_P_PL:
+		cdata.cfg.prevp_pl =
+			imx074_get_prev_pixels_pl();
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+			break;
+
+	case CFG_GET_PICT_L_PF:
+		cdata.cfg.pictl_pf =
+			imx074_get_pict_lines_pf();
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+			break;
+	case CFG_GET_PICT_P_PL:
+		cdata.cfg.pictp_pl =
+			imx074_get_pict_pixels_pl();
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+			break;
+	case CFG_GET_PICT_MAX_EXP_LC:
+		cdata.cfg.pict_max_exp_lc =
+			imx074_get_pict_max_exp_lc();
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+			break;
+	case CFG_SET_FPS:
+	case CFG_SET_PICT_FPS:
+		rc = imx074_set_fps(&(cdata.cfg.fps));
+		break;
+	case CFG_SET_EXP_GAIN:
+		rc =
+			imx074_write_exp_gain(
+			cdata.cfg.exp_gain.gain,
+			cdata.cfg.exp_gain.line);
+			break;
+	case CFG_SET_PICT_EXP_GAIN:
+		rc =
+			imx074_set_pict_exp_gain(
+			cdata.cfg.exp_gain.gain,
+			cdata.cfg.exp_gain.line);
+			break;
+	case CFG_SET_MODE:
+		rc = imx074_set_sensor_mode(cdata.mode,
+			cdata.rs);
+			break;
+	case CFG_PWR_DOWN:
+		rc = imx074_power_down();
+			break;
+	case CFG_GET_CALIB_DATA:
+		rc = imx074_read_eeprom_data(&cdata);
+		if (rc < 0)
+			break;
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(cdata)))
+			rc = -EFAULT;
+		break;
+	case CFG_MOVE_FOCUS:
+		rc =
+			imx074_move_focus(
+			cdata.cfg.focus.dir,
+			cdata.cfg.focus.steps);
+			break;
+	case CFG_SET_DEFAULT_FOCUS:
+		rc =
+			imx074_set_default_focus(
+			cdata.cfg.focus.steps);
+			break;
+	case CFG_GET_AF_MAX_STEPS:
+		cdata.max_steps = IMX074_STEPS_NEAR_TO_CLOSEST_INF;
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+			break;
+	case CFG_SET_EFFECT:
+	default:
+		rc = -EFAULT;
+		break;
+	}
+
+	mutex_unlock(&imx074_mut);
+
+	return rc;
+}
+static int imx074_sensor_release(void)
+{
+	int rc = -EBADF;
+	mutex_lock(&imx074_mut);
+	if (machine_is_msm8x60_fluid())
+		imx074_poweroff_af();
+	imx074_power_down();
+	gpio_set_value_cansleep(imx074_ctrl->sensordata->sensor_reset, 0);
+	usleep_range(5000, 6000);
+	gpio_direction_input(imx074_ctrl->sensordata->sensor_reset);
+	gpio_free(imx074_ctrl->sensordata->sensor_reset);
+	CDBG("imx074_release completed\n");
+	mutex_unlock(&imx074_mut);
+
+	return rc;
+}
+
+static int imx074_sensor_probe(const struct msm_camera_sensor_info *info,
+		struct msm_sensor_ctrl *s)
+{
+	int rc = 0;
+	rc = i2c_add_driver(&imx074_i2c_driver);
+	if (rc < 0 || imx074_client == NULL) {
+		rc = -ENOTSUPP;
+		goto probe_fail;
+	}
+	msm_camio_clk_rate_set(IMX074_DEFAULT_MASTER_CLK_RATE);
+	rc = imx074_probe_init_sensor(info);
+	if (rc < 0)
+		goto probe_fail;
+	s->s_init = imx074_sensor_open_init;
+	s->s_release = imx074_sensor_release;
+	s->s_config  = imx074_sensor_config;
+	s->s_mount_angle = info->sensor_platform_info->mount_angle;
+	imx074_probe_init_done(info);
+	return rc;
+
+probe_fail:
+	CDBG("imx074_sensor_probe: SENSOR PROBE FAILS!\n");
+	i2c_del_driver(&imx074_i2c_driver);
+	return rc;
+}
+
+static struct imx074_format imx074_subdev_info[] = {
+	{
+	.code   = V4L2_MBUS_FMT_SBGGR10_1X10,
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	.fmt    = 1,
+	.order    = 0,
+	},
+	/* more can be supported, to be added later */
+};
+
+static int imx074_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+			   enum v4l2_mbus_pixelcode *code)
+{
+	printk(KERN_DEBUG "Index is %d\n", index);
+	if ((unsigned int)index >= ARRAY_SIZE(imx074_subdev_info))
+		return -EINVAL;
+
+	*code = imx074_subdev_info[index].code;
+	return 0;
+}
+
+static struct v4l2_subdev_core_ops imx074_subdev_core_ops;
+static struct v4l2_subdev_video_ops imx074_subdev_video_ops = {
+	.enum_mbus_fmt = imx074_enum_fmt,
+};
+
+static struct v4l2_subdev_ops imx074_subdev_ops = {
+	.core = &imx074_subdev_core_ops,
+	.video  = &imx074_subdev_video_ops,
+};
+
+
+static int imx074_sensor_probe_cb(const struct msm_camera_sensor_info *info,
+	struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s)
+{
+	int rc = 0;
+	rc = imx074_sensor_probe(info, s);
+	if (rc < 0)
+		return rc;
+
+	imx074_ctrl = kzalloc(sizeof(struct imx074_ctrl_t), GFP_KERNEL);
+	if (!imx074_ctrl) {
+		CDBG("imx074_sensor_probe failed!\n");
+		return -ENOMEM;
+	}
+
+	/* probe is successful, init a v4l2 subdevice */
+	printk(KERN_DEBUG "going into v4l2_i2c_subdev_init\n");
+	if (sdev) {
+		v4l2_i2c_subdev_init(sdev, imx074_client,
+						&imx074_subdev_ops);
+		imx074_ctrl->sensor_dev = sdev;
+	}
+	return rc;
+}
+
+static int __imx074_probe(struct platform_device *pdev)
+{
+	return msm_sensor_register(pdev, imx074_sensor_probe_cb);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = __imx074_probe,
+	.driver = {
+		.name = "msm_camera_imx074",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init imx074_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(imx074_init);
+
+MODULE_DESCRIPTION("Sony 13 MP Bayer sensor driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
new file mode 100644
index 0000000..da28403
--- /dev/null
+++ b/drivers/media/video/msm/msm.c
@@ -0,0 +1,2080 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/spinlock.h>
+#include <linux/proc_fs.h>
+#include "msm.h"
+
+
+#define MSM_MAX_CAMERA_SENSORS 5
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+#define D(fmt, args...) pr_debug("msm: " fmt, ##args)
+#else
+#define D(fmt, args...) do {} while (0)
+#endif
+
+static unsigned msm_camera_v4l2_nr = -1;
+static struct msm_cam_server_dev g_server_dev;
+static struct class *msm_class;
+static dev_t msm_devno;
+static int vnode_count;
+
+module_param(msm_camera_v4l2_nr, uint, 0644);
+MODULE_PARM_DESC(msm_camera_v4l2_nr, "videoX start number, -1 is autodetect");
+
+static int msm_setup_v4l2_event_queue(struct v4l2_fh *eventHandle,
+				  struct video_device *pvdev);
+
+static void msm_queue_init(struct msm_device_queue *queue, const char *name)
+{
+	D("%s\n", __func__);
+	spin_lock_init(&queue->lock);
+	queue->len = 0;
+	queue->max = 0;
+	queue->name = name;
+	INIT_LIST_HEAD(&queue->list);
+	init_waitqueue_head(&queue->wait);
+}
+
+static void msm_enqueue(struct msm_device_queue *queue,
+			struct list_head *entry)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&queue->lock, flags);
+	queue->len++;
+	if (queue->len > queue->max) {
+		queue->max = queue->len;
+		pr_info("%s: queue %s new max is %d\n", __func__,
+			queue->name, queue->max);
+	}
+	list_add_tail(entry, &queue->list);
+	wake_up(&queue->wait);
+	D("%s: woke up %s\n", __func__, queue->name);
+	spin_unlock_irqrestore(&queue->lock, flags);
+}
+
+/* callback function from all subdevices of a msm_cam_v4l2_device */
+static void msm_cam_v4l2_subdev_notify(struct v4l2_subdev *sd,
+				    unsigned int notification, void *arg)
+{
+	struct msm_cam_v4l2_device *pcam;
+
+	if (sd == NULL)
+		return;
+
+	pcam = to_pcam(sd->v4l2_dev);
+
+	if (pcam == NULL)
+		return;
+
+	/* forward to media controller for any changes*/
+	if (pcam->mctl.mctl_notify) {
+		pcam->mctl.mctl_notify(&pcam->mctl, notification, arg);
+	}
+}
+
+static int msm_ctrl_cmd_done(void __user *arg)
+{
+	void __user *uptr;
+	struct msm_queue_cmd *qcmd;
+	struct msm_ctrl_cmd *command = &g_server_dev.ctrl;
+
+	D("%s\n", __func__);
+
+	if (copy_from_user(command, arg,
+			sizeof(struct msm_ctrl_cmd)))
+		return -EINVAL;
+
+	qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
+	atomic_set(&qcmd->on_heap, 0);
+	uptr = command->value;
+	qcmd->command = command;
+
+	if (command->length > 0) {
+		command->value = g_server_dev.ctrl_data;
+		if (command->length > sizeof(g_server_dev.ctrl_data)) {
+			pr_err("%s: user data %d is too big (max %d)\n",
+				__func__, command->length,
+				sizeof(g_server_dev.ctrl_data));
+			return -EINVAL;
+		}
+		if (copy_from_user(command->value, uptr, command->length))
+			return -EINVAL;
+	}
+
+	msm_enqueue(&g_server_dev.ctrl_q, &qcmd->list_control);
+	return 0;
+}
+
+/* send control command to config and wait for results*/
+static int msm_server_control(struct msm_cam_server_dev *server_dev,
+				struct msm_ctrl_cmd *out)
+{
+	int rc = 0;
+	void *value;
+	struct msm_queue_cmd *rcmd;
+	struct msm_ctrl_cmd *ctrlcmd;
+	struct msm_device_queue *queue =  &server_dev->ctrl_q;
+
+	struct v4l2_event v4l2_evt;
+	struct msm_isp_stats_event_ctrl *isp_event;
+	D("%s\n", __func__);
+
+	v4l2_evt.type = V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_V4L2;
+
+	/* setup event object to transfer the command; */
+	isp_event = (struct msm_isp_stats_event_ctrl *)v4l2_evt.u.data;
+	isp_event->resptype = MSM_CAM_RESP_V4L2;
+	isp_event->isp_data.ctrl = *out;
+
+	/* now send command to config thread in usersspace,
+	 * and wait for results */
+	v4l2_event_queue(server_dev->server_command_queue.pvdev,
+					  &v4l2_evt);
+
+	D("%s v4l2_event_queue: type = 0x%x\n", __func__, v4l2_evt.type);
+
+	/* wait for config return status */
+	D("Waiting for config status\n");
+	rc = wait_event_interruptible_timeout(queue->wait,
+		!list_empty_careful(&queue->list),
+		out->timeout_ms);
+	D("Waiting is over for config status\n");
+	if (list_empty_careful(&queue->list)) {
+		if (!rc)
+			rc = -ETIMEDOUT;
+		if (rc < 0) {
+			pr_err("%s: wait_event error %d\n", __func__, rc);
+			return rc;
+		}
+	}
+
+	rcmd = msm_dequeue(queue, list_control);
+	BUG_ON(!rcmd);
+	D("%s Finished servicing ioctl\n", __func__);
+
+	ctrlcmd = (struct msm_ctrl_cmd *)(rcmd->command);
+	value = out->value;
+	if (ctrlcmd->length > 0)
+		memcpy(value, ctrlcmd->value, ctrlcmd->length);
+
+	memcpy(out, ctrlcmd, sizeof(struct msm_ctrl_cmd));
+	out->value = value;
+
+	free_qcmd(rcmd);
+	D("%s: rc %d\n", __func__, rc);
+	/* rc is the time elapsed. */
+	if (rc >= 0) {
+		/* TODO: Refactor msm_ctrl_cmd::status field */
+		if (out->status == 0)
+			rc = -1;
+		else if (out->status == 1)
+			rc = 0;
+		else
+			rc = -EINVAL;
+	}
+	return rc;
+}
+
+/*send open command to server*/
+static int msm_send_open_server(void)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd ctrlcmd;
+	D("%s\n", __func__);
+	ctrlcmd.type	   = MSM_V4L2_OPEN;
+	ctrlcmd.timeout_ms = 10000;
+	ctrlcmd.length	 = 0;
+	ctrlcmd.value    = NULL;
+
+	/* send command to config thread in usersspace, and get return value */
+	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+
+	return rc;
+}
+
+static int msm_send_close_server(void)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd ctrlcmd;
+	D("%s\n", __func__);
+	ctrlcmd.type	   = MSM_V4L2_CLOSE;
+	ctrlcmd.timeout_ms = 10000;
+	ctrlcmd.length	 = 0;
+	ctrlcmd.value    = NULL;
+
+	/* send command to config thread in usersspace, and get return value */
+	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+
+	return rc;
+}
+
+static int msm_server_set_fmt(struct msm_cam_v4l2_device *pcam, int idx,
+				 struct v4l2_format *pfmt)
+{
+	int rc = 0;
+	int i = 0;
+	struct v4l2_pix_format *pix = &pfmt->fmt.pix;
+	struct msm_ctrl_cmd ctrlcmd;
+
+	D("%s: %d, %d, 0x%x\n", __func__,
+		pfmt->fmt.pix.width, pfmt->fmt.pix.height,
+		pfmt->fmt.pix.pixelformat);
+
+	if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		D("%s, Attention! Wrong buf-type %d\n", __func__, pfmt->type);
+
+	for (i = 0; i < pcam->num_fmts; i++)
+		if (pcam->usr_fmts[i].fourcc == pix->pixelformat)
+			break;
+	if (i == pcam->num_fmts) {
+		pr_err("%s: User requested pixelformat %x not supported\n",
+						__func__, pix->pixelformat);
+		return -EINVAL;
+	}
+
+	ctrlcmd.type       = MSM_V4L2_VID_CAP_TYPE;
+	ctrlcmd.length     = MSM_V4L2_DIMENSION_SIZE;
+	ctrlcmd.value      = (void *)pfmt->fmt.pix.priv;
+	ctrlcmd.timeout_ms = 10000;
+
+	/* send command to config thread in usersspace, and get return value */
+	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+
+	if (rc >= 0) {
+		pcam->dev_inst[idx]->vid_fmt.fmt.pix.width    = pix->width;
+		pcam->dev_inst[idx]->vid_fmt.fmt.pix.height   = pix->height;
+		pcam->dev_inst[idx]->vid_fmt.fmt.pix.field    = pix->field;
+		pcam->dev_inst[idx]->vid_fmt.fmt.pix.pixelformat =
+							pix->pixelformat;
+		pcam->dev_inst[idx]->vid_fmt.fmt.pix.bytesperline =
+							pix->bytesperline;
+		pcam->dev_inst[idx]->vid_bufq.field   = pix->field;
+		pcam->dev_inst[idx]->sensor_pxlcode
+					= pcam->usr_fmts[i].pxlcode;
+		D("%s:inst=0x%x,idx=%d,width=%d,heigth=%d\n",
+			 __func__, (u32)pcam->dev_inst[idx], idx,
+			 pcam->dev_inst[idx]->vid_fmt.fmt.pix.width,
+			 pcam->dev_inst[idx]->vid_fmt.fmt.pix.height);
+	}
+
+	return rc;
+}
+
+static int msm_server_streamon(struct msm_cam_v4l2_device *pcam, int idx)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd ctrlcmd;
+	D("%s\n", __func__);
+	ctrlcmd.type	   = MSM_V4L2_STREAM_ON;
+	ctrlcmd.timeout_ms = 10000;
+	ctrlcmd.length	 = 0;
+	ctrlcmd.value    = NULL;
+	ctrlcmd.stream_type = pcam->dev_inst[idx]->image_mode;
+	ctrlcmd.vnode_id = pcam->vnode_id;
+
+
+	/* send command to config thread in usersspace, and get return value */
+	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+
+	return rc;
+}
+
+static int msm_server_streamoff(struct msm_cam_v4l2_device *pcam, int idx)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd ctrlcmd;
+
+	D("%s, pcam = 0x%x\n", __func__, (u32)pcam);
+	ctrlcmd.type	   = MSM_V4L2_STREAM_OFF;
+	ctrlcmd.timeout_ms = 10000;
+	ctrlcmd.length	 = 0;
+	ctrlcmd.value    = NULL;
+	ctrlcmd.stream_type = pcam->dev_inst[idx]->image_mode;
+	ctrlcmd.vnode_id = pcam->vnode_id;
+
+	/* send command to config thread in usersspace, and get return value */
+	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+
+	return rc;
+}
+
+static int msm_server_proc_ctrl_cmd(struct msm_cam_v4l2_device *pcam,
+				 struct v4l2_control *ctrl, int is_set_cmd)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd ctrlcmd, *tmp_cmd;
+	uint8_t *ctrl_data = NULL;
+	void __user *uptr_cmd;
+	void __user *uptr_value;
+	uint32_t cmd_len = sizeof(struct msm_ctrl_cmd);
+	uint32_t value_len;
+
+	tmp_cmd = (struct msm_ctrl_cmd *)ctrl->value;
+	uptr_cmd = (void __user *)ctrl->value;
+	uptr_value = (void __user *)tmp_cmd->value;
+	value_len = tmp_cmd->length;
+
+	D("%s: cmd type = %d, up1=0x%x, ulen1=%d, up2=0x%x, ulen2=%d\n",
+		__func__, tmp_cmd->type, (uint32_t)uptr_cmd, cmd_len,
+		(uint32_t)uptr_value, tmp_cmd->length);
+
+	ctrl_data = kzalloc(value_len+cmd_len, GFP_KERNEL);
+	if (ctrl_data == 0) {
+		pr_err("%s could not allocate memory\n", __func__);
+		rc = -ENOMEM;
+		goto end;
+	}
+	tmp_cmd = (struct msm_ctrl_cmd *)ctrl_data;
+	if (copy_from_user((void *)ctrl_data, uptr_cmd,
+					cmd_len)) {
+		pr_err("%s: copy_from_user failed.\n", __func__);
+		rc = -EINVAL;
+		goto end;
+	}
+	tmp_cmd->value = (void *)(ctrl_data+cmd_len);
+	if (uptr_value && tmp_cmd->length > 0) {
+		if (copy_from_user((void *)tmp_cmd->value, uptr_value,
+						value_len)) {
+			pr_err("%s: copy_from_user failed, size=%d\n",
+				__func__, value_len);
+			rc = -EINVAL;
+			goto end;
+		}
+	} else
+	tmp_cmd->value = NULL;
+
+	ctrlcmd.type = MSM_V4L2_SET_CTRL_CMD;
+	ctrlcmd.length = cmd_len + value_len;
+	ctrlcmd.value = (void *)ctrl_data;
+	ctrlcmd.timeout_ms = 1000;
+	ctrlcmd.vnode_id = pcam->vnode_id;
+	/* send command to config thread in usersspace, and get return value */
+	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+	pr_err("%s: msm_server_control rc=%d\n", __func__, rc);
+	if (rc == 0) {
+		if (uptr_value && tmp_cmd->length > 0 &&
+			copy_to_user((void __user *)uptr_value,
+				(void *)(ctrl_data+cmd_len), tmp_cmd->length)) {
+			pr_err("%s: copy_to_user failed, size=%d\n",
+				__func__, tmp_cmd->length);
+			rc = -EINVAL;
+			goto end;
+		}
+		tmp_cmd->value = uptr_value;
+		if (copy_to_user((void __user *)uptr_cmd,
+			(void *)tmp_cmd, cmd_len)) {
+			pr_err("%s: copy_to_user failed in cpy, size=%d\n",
+				__func__, cmd_len);
+			rc = -EINVAL;
+			goto end;
+		}
+	}
+end:
+	pr_err("%s: END, type = %d, vaddr = 0x%x, vlen = %d, status = %d, rc = %d\n",
+		__func__, tmp_cmd->type, (uint32_t)tmp_cmd->value,
+		tmp_cmd->length, tmp_cmd->status, rc);
+	kfree(ctrl_data);
+	return rc;
+}
+
+static int msm_server_s_ctrl(struct msm_cam_v4l2_device *pcam,
+				 struct v4l2_control *ctrl)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd ctrlcmd;
+	uint8_t ctrl_data[max_control_command_size];
+
+	WARN_ON(ctrl == NULL);
+
+	if (ctrl && ctrl->id == MSM_V4L2_PID_CTRL_CMD)
+		return msm_server_proc_ctrl_cmd(pcam, ctrl, 1);
+
+	memset(ctrl_data, 0, sizeof(ctrl_data));
+
+	ctrlcmd.type = MSM_V4L2_SET_CTRL;
+	ctrlcmd.length = sizeof(struct v4l2_control);
+	ctrlcmd.value = (void *)ctrl_data;
+	memcpy(ctrlcmd.value, ctrl, ctrlcmd.length);
+	ctrlcmd.timeout_ms = 1000;
+	ctrlcmd.vnode_id = pcam->vnode_id;
+
+	/* send command to config thread in usersspace, and get return value */
+	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+
+	return rc;
+}
+
+static int msm_server_g_ctrl(struct msm_cam_v4l2_device *pcam,
+				 struct v4l2_control *ctrl)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd ctrlcmd;
+	uint8_t ctrl_data[max_control_command_size];
+
+	WARN_ON(ctrl == NULL);
+	if (ctrl && ctrl->id == MSM_V4L2_PID_CTRL_CMD)
+		return msm_server_proc_ctrl_cmd(pcam, ctrl, 0);
+
+	memset(ctrl_data, 0, sizeof(ctrl_data));
+
+	ctrlcmd.type = MSM_V4L2_GET_CTRL;
+	ctrlcmd.length = sizeof(struct v4l2_control);
+	ctrlcmd.value = (void *)ctrl_data;
+	memcpy(ctrlcmd.value, ctrl, ctrlcmd.length);
+	ctrlcmd.timeout_ms = 1000;
+
+	/* send command to config thread in usersspace, and get return value */
+	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+
+	ctrl->value = ((struct v4l2_control *)ctrlcmd.value)->value;
+
+	return rc;
+}
+
+static int msm_server_q_ctrl(struct msm_cam_v4l2_device *pcam,
+			struct v4l2_queryctrl *queryctrl)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd ctrlcmd;
+	uint8_t ctrl_data[max_control_command_size];
+
+	WARN_ON(queryctrl == NULL);
+	memset(ctrl_data, 0, sizeof(ctrl_data));
+
+	ctrlcmd.type = MSM_V4L2_QUERY_CTRL;
+	ctrlcmd.length = sizeof(struct v4l2_queryctrl);
+	ctrlcmd.value = (void *)ctrl_data;
+	memcpy(ctrlcmd.value, queryctrl, ctrlcmd.length);
+	ctrlcmd.timeout_ms = 1000;
+
+	/* send command to config thread in userspace, and get return value */
+	rc = msm_server_control(&g_server_dev, &ctrlcmd);
+	D("%s: rc = %d\n", __func__, rc);
+
+	if (rc >= 0)
+		memcpy(queryctrl, ctrlcmd.value, sizeof(struct v4l2_queryctrl));
+
+	return rc;
+}
+
+static int msm_server_get_fmt(struct msm_cam_v4l2_device *pcam,
+		 int idx, struct v4l2_format *pfmt)
+{
+	struct v4l2_pix_format *pix = &pfmt->fmt.pix;
+
+	pix->width	  = pcam->dev_inst[idx]->vid_fmt.fmt.pix.width;
+	pix->height	 = pcam->dev_inst[idx]->vid_fmt.fmt.pix.height;
+	pix->field	  = pcam->dev_inst[idx]->vid_fmt.fmt.pix.field;
+	pix->pixelformat = pcam->dev_inst[idx]->vid_fmt.fmt.pix.pixelformat;
+	pix->bytesperline = pcam->dev_inst[idx]->vid_fmt.fmt.pix.bytesperline;
+	pix->colorspace	 = pcam->dev_inst[idx]->vid_fmt.fmt.pix.colorspace;
+	if (pix->bytesperline < 0)
+		return pix->bytesperline;
+
+	pix->sizeimage	  = pix->height * pix->bytesperline;
+
+	return 0;
+}
+
+static int msm_server_try_fmt(struct msm_cam_v4l2_device *pcam,
+				 struct v4l2_format *pfmt)
+{
+	int rc = 0;
+	int i = 0;
+	struct v4l2_pix_format *pix = &pfmt->fmt.pix;
+	struct v4l2_mbus_framefmt sensor_fmt;
+
+	D("%s: 0x%x\n", __func__, pix->pixelformat);
+
+	if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		pr_err("%s: pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE!\n",
+							__func__);
+		return -EINVAL;
+	}
+
+	/* check if the format is supported by this host-sensor combo */
+	for (i = 0; i < pcam->num_fmts; i++) {
+		D("%s: usr_fmts.fourcc: 0x%x\n", __func__,
+			pcam->usr_fmts[i].fourcc);
+		if (pcam->usr_fmts[i].fourcc == pix->pixelformat)
+			break;
+	}
+
+	if (i == pcam->num_fmts) {
+		pr_err("%s: Format %x not found\n", __func__, pix->pixelformat);
+		return -EINVAL;
+	}
+
+	sensor_fmt.width  = pix->width;
+	sensor_fmt.height = pix->height;
+	sensor_fmt.field  = pix->field;
+	sensor_fmt.colorspace = pix->colorspace;
+	sensor_fmt.code   = pcam->usr_fmts[i].pxlcode;
+
+	pix->width	= sensor_fmt.width;
+	pix->height   = sensor_fmt.height;
+	pix->field	= sensor_fmt.field;
+	pix->colorspace   = sensor_fmt.colorspace;
+
+	return rc;
+}
+
+/*
+ *
+ * implementation of v4l2_ioctl_ops
+ *
+ */
+static int msm_camera_v4l2_querycap(struct file *f, void *pctx,
+				struct v4l2_capability *pcaps)
+{
+	struct msm_cam_v4l2_device *pcam  = video_drvdata(f);
+
+	D("%s\n", __func__);
+	WARN_ON(pctx != f->private_data);
+
+	/* some other day, some other time */
+	/*cap->version = LINUX_VERSION_CODE; */
+	strlcpy(pcaps->driver, pcam->pdev->name, sizeof(pcaps->driver));
+	pcaps->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+	return 0;
+}
+
+static int msm_camera_v4l2_queryctrl(struct file *f, void *pctx,
+				struct v4l2_queryctrl *pqctrl)
+{
+	int rc = 0;
+	struct msm_cam_v4l2_device *pcam  = video_drvdata(f);
+
+	D("%s\n", __func__);
+	WARN_ON(pctx != f->private_data);
+
+	mutex_lock(&pcam->vid_lock);
+	rc = msm_server_q_ctrl(pcam, pqctrl);
+	mutex_unlock(&pcam->vid_lock);
+	return rc;
+}
+
+static int msm_camera_v4l2_g_ctrl(struct file *f, void *pctx,
+					struct v4l2_control *c)
+{
+	int rc = 0;
+	struct msm_cam_v4l2_device *pcam  = video_drvdata(f);
+
+	D("%s\n", __func__);
+	WARN_ON(pctx != f->private_data);
+
+	mutex_lock(&pcam->vid_lock);
+	rc = msm_server_g_ctrl(pcam, c);
+	mutex_unlock(&pcam->vid_lock);
+
+	return rc;
+}
+
+static int msm_camera_v4l2_s_ctrl(struct file *f, void *pctx,
+					struct v4l2_control *ctrl)
+{
+	int rc = 0;
+	struct msm_cam_v4l2_device *pcam  = video_drvdata(f);
+
+	D("%s\n", __func__);
+	WARN_ON(pctx != f->private_data);
+	mutex_lock(&pcam->vid_lock);
+	if (ctrl->id == MSM_V4L2_PID_CAM_MODE)
+		pcam->op_mode = ctrl->value;
+	rc = msm_server_s_ctrl(pcam, ctrl);
+	mutex_unlock(&pcam->vid_lock);
+
+	return rc;
+}
+
+static int msm_camera_v4l2_reqbufs(struct file *f, void *pctx,
+				struct v4l2_requestbuffers *pb)
+{
+	int rc = 0;
+	int i = 0;
+	/*struct msm_cam_v4l2_device *pcam  = video_drvdata(f);*/
+	struct msm_cam_v4l2_dev_inst *pcam_inst  = f->private_data;
+
+	D("%s\n", __func__);
+	WARN_ON(pctx != f->private_data);
+
+	if (!pb->count) {
+		if (pcam_inst->vid_bufq.streaming)
+			videobuf_stop(&pcam_inst->vid_bufq);
+		else
+			videobuf_queue_cancel(&pcam_inst->vid_bufq);
+
+		/* free the queue: function name is ambiguous it frees all
+		types of buffers (mmap or userptr - it doesn't matter) */
+		rc = videobuf_mmap_free(&pcam_inst->vid_bufq);
+	} else {
+		rc = videobuf_reqbufs(&pcam_inst->vid_bufq, pb);
+		if (rc < 0)
+			return rc;
+		/* Now initialize the local msm_frame_buffer structure */
+		for (i = 0; i < pb->count; i++) {
+			struct msm_frame_buffer *buf = container_of(
+						pcam_inst->vid_bufq.bufs[i],
+						struct msm_frame_buffer,
+						vidbuf);
+			buf->inuse = 0;
+			INIT_LIST_HEAD(&buf->vidbuf.queue);
+		}
+	}
+	pcam_inst->buf_count = pb->count;
+	return rc;
+}
+
+static int msm_camera_v4l2_querybuf(struct file *f, void *pctx,
+					struct v4l2_buffer *pb)
+{
+	/* get the video device */
+	struct msm_cam_v4l2_dev_inst *pcam_inst  = f->private_data;
+
+	D("%s\n", __func__);
+	WARN_ON(pctx != f->private_data);
+
+	return videobuf_querybuf(&pcam_inst->vid_bufq, pb);
+}
+
+static int msm_camera_v4l2_qbuf(struct file *f, void *pctx,
+					struct v4l2_buffer *pb)
+{
+	int rc = 0;
+	/* get the camera device */
+	struct msm_cam_v4l2_dev_inst *pcam_inst  = f->private_data;
+
+	D("%s\n", __func__);
+	WARN_ON(pctx != f->private_data);
+
+	rc = videobuf_qbuf(&pcam_inst->vid_bufq, pb);
+	D("%s, videobuf_qbuf returns %d\n", __func__, rc);
+
+	return rc;
+}
+
+static int msm_camera_v4l2_dqbuf(struct file *f, void *pctx,
+					struct v4l2_buffer *pb)
+{
+	int rc = 0;
+	/* get the camera device */
+	struct msm_cam_v4l2_dev_inst *pcam_inst  = f->private_data;
+
+	D("%s\n", __func__);
+	WARN_ON(pctx != f->private_data);
+
+	rc = videobuf_dqbuf(&pcam_inst->vid_bufq, pb, f->f_flags & O_NONBLOCK);
+	D("%s, videobuf_dqbuf returns %d\n", __func__, rc);
+
+	return rc;
+}
+
+static int msm_camera_v4l2_streamon(struct file *f, void *pctx,
+					enum v4l2_buf_type i)
+{
+	int rc = 0;
+	struct videobuf_buffer *buf;
+	int cnt = 0;
+	/* get the camera device */
+	struct msm_cam_v4l2_device *pcam  = video_drvdata(f);
+	struct msm_cam_v4l2_dev_inst *pcam_inst  = f->private_data;
+
+	D("%s\n", __func__);
+	WARN_ON(pctx != f->private_data);
+
+	D("%s Calling videobuf_streamon", __func__);
+	/* if HW streaming on is successful, start buffer streaming */
+	rc = videobuf_streamon(&pcam_inst->vid_bufq);
+	D("%s, videobuf_streamon returns %d\n", __func__, rc);
+
+	mutex_lock(&pcam->vid_lock);
+	/* turn HW (VFE/sensor) streaming */
+	rc = msm_server_streamon(pcam, pcam_inst->my_index);
+	mutex_unlock(&pcam->vid_lock);
+	D("%s rc = %d\n", __func__, rc);
+	if (rc < 0) {
+		pr_err("%s: hw failed to start streaming\n", __func__);
+		return rc;
+	}
+
+	list_for_each_entry(buf, &pcam_inst->vid_bufq.stream, stream) {
+		D("%s index %d, state %d\n", __func__, cnt, buf->state);
+		cnt++;
+	}
+
+	return rc;
+}
+
+static int msm_camera_v4l2_streamoff(struct file *f, void *pctx,
+					enum v4l2_buf_type i)
+{
+	int rc = 0;
+	/* get the camera device */
+	struct msm_cam_v4l2_device *pcam  = video_drvdata(f);
+	struct msm_cam_v4l2_dev_inst *pcam_inst  = f->private_data;
+
+	D("%s\n", __func__);
+	WARN_ON(pctx != f->private_data);
+
+	/* first turn of HW (VFE/sensor) streaming so that buffers are
+	  not in use when we free the buffers */
+	mutex_lock(&pcam->vid_lock);
+	rc = msm_server_streamoff(pcam, pcam_inst->my_index);
+	mutex_unlock(&pcam->vid_lock);
+	if (rc < 0)
+		pr_err("%s: hw failed to stop streaming\n", __func__);
+
+	/* stop buffer streaming */
+	rc = videobuf_streamoff(&pcam_inst->vid_bufq);
+	D("%s, videobuf_streamoff returns %d\n", __func__, rc);
+
+	return rc;
+}
+
+static int msm_camera_v4l2_enum_fmt_cap(struct file *f, void *pctx,
+					struct v4l2_fmtdesc *pfmtdesc)
+{
+	/* get the video device */
+	struct msm_cam_v4l2_device *pcam  = video_drvdata(f);
+	const struct msm_isp_color_fmt *isp_fmt;
+
+	D("%s\n", __func__);
+	WARN_ON(pctx != f->private_data);
+
+	if (pfmtdesc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (pfmtdesc->index >= pcam->num_fmts)
+		return -EINVAL;
+
+	isp_fmt = &pcam->usr_fmts[pfmtdesc->index];
+
+	if (isp_fmt->name)
+		strlcpy(pfmtdesc->description, isp_fmt->name,
+						sizeof(pfmtdesc->description));
+
+	pfmtdesc->pixelformat = isp_fmt->fourcc;
+
+	D("%s: [%d] 0x%x, %s\n", __func__, pfmtdesc->index,
+		isp_fmt->fourcc, isp_fmt->name);
+	return 0;
+}
+
+static int msm_camera_v4l2_g_fmt_cap(struct file *f,
+		void *pctx, struct v4l2_format *pfmt)
+{
+	int rc = 0;
+	/* get the video device */
+	struct msm_cam_v4l2_device *pcam  = video_drvdata(f);
+	struct msm_cam_v4l2_dev_inst *pcam_inst  = f->private_data;
+
+	D("%s\n", __func__);
+	WARN_ON(pctx != f->private_data);
+
+	if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	rc = msm_server_get_fmt(pcam, pcam_inst->my_index, pfmt);
+
+	D("%s: current_fmt->fourcc: 0x%08x, rc = %d\n", __func__,
+				pfmt->fmt.pix.pixelformat, rc);
+	return rc;
+}
+
+/* This function will readjust the format parameters based in HW
+  capabilities. Called by s_fmt_cap
+*/
+static int msm_camera_v4l2_try_fmt_cap(struct file *f, void *pctx,
+					struct v4l2_format *pfmt)
+{
+	int rc = 0;
+	/* get the video device */
+	struct msm_cam_v4l2_device *pcam  = video_drvdata(f);
+
+	D("%s\n", __func__);
+	WARN_ON(pctx != f->private_data);
+
+	rc = msm_server_try_fmt(pcam, pfmt);
+	if (rc)
+		pr_err("Format %x not found, rc = %d\n",
+				pfmt->fmt.pix.pixelformat, rc);
+
+	return rc;
+}
+
+/* This function will reconfig the v4l2 driver and HW device, it should be
+   called after the streaming is stopped.
+*/
+static int msm_camera_v4l2_s_fmt_cap(struct file *f, void *pctx,
+					struct v4l2_format *pfmt)
+{
+	int rc;
+	void __user *uptr;
+	/* get the video device */
+	struct msm_cam_v4l2_device *pcam  = video_drvdata(f);
+	struct msm_cam_v4l2_dev_inst *pcam_inst  = f->private_data;
+
+	D("%s\n", __func__);
+	D("%s, inst=0x%x,idx=%d,priv = 0x%p\n",
+		__func__, (u32)pcam_inst, pcam_inst->my_index,
+		(void *)pfmt->fmt.pix.priv);
+	WARN_ON(pctx != f->private_data);
+
+	uptr = (void __user *)pfmt->fmt.pix.priv;
+	pfmt->fmt.pix.priv = (__u32)kzalloc(MSM_V4L2_DIMENSION_SIZE,
+							GFP_KERNEL);
+
+	if (!pfmt->fmt.pix.priv) {
+		pr_err("%s could not allocate memory\n", __func__);
+		return -ENOMEM;
+	}
+	D("%s Copying priv data:n", __func__);
+	if (copy_from_user((void *)pfmt->fmt.pix.priv, uptr,
+					MSM_V4L2_DIMENSION_SIZE)) {
+		pr_err("%s: copy_from_user failed.\n", __func__);
+		kfree((void *)pfmt->fmt.pix.priv);
+		return -EINVAL;
+	}
+	D("%s Done Copying priv data\n", __func__);
+
+	mutex_lock(&pcam->vid_lock);
+
+	rc = msm_server_set_fmt(pcam, pcam_inst->my_index, pfmt);
+	if (rc < 0) {
+		pr_err("%s: msm_server_set_fmt Error: %d\n",
+				__func__, rc);
+		goto done;
+	}
+
+	if (copy_to_user(uptr, (const void *)pfmt->fmt.pix.priv,
+					MSM_V4L2_DIMENSION_SIZE)) {
+		pr_err("%s: copy_to_user failed\n", __func__);
+		rc = -EINVAL;
+	}
+
+done:
+	kfree((void *)pfmt->fmt.pix.priv);
+	pfmt->fmt.pix.priv = (__u32)uptr;
+
+	mutex_unlock(&pcam->vid_lock);
+
+	return rc;
+}
+
+static int msm_camera_v4l2_g_jpegcomp(struct file *f, void *pctx,
+				struct v4l2_jpegcompression *pcomp)
+{
+	int rc = -EINVAL;
+
+	D("%s\n", __func__);
+	WARN_ON(pctx != f->private_data);
+
+	return rc;
+}
+
+static int msm_camera_v4l2_s_jpegcomp(struct file *f, void *pctx,
+				struct v4l2_jpegcompression *pcomp)
+{
+	int rc = -EINVAL;
+
+	D("%s\n", __func__);
+	WARN_ON(pctx != f->private_data);
+
+	return rc;
+}
+
+
+static int msm_camera_v4l2_g_crop(struct file *f, void *pctx,
+					struct v4l2_crop *a)
+{
+	int rc = -EINVAL;
+
+	D("%s\n", __func__);
+	WARN_ON(pctx != f->private_data);
+
+	return rc;
+}
+
+static int msm_camera_v4l2_s_crop(struct file *f, void *pctx,
+					struct v4l2_crop *a)
+{
+	int rc = -EINVAL;
+
+	D("%s\n", __func__);
+	WARN_ON(pctx != f->private_data);
+
+	return rc;
+}
+
+/* Stream type-dependent parameter ioctls */
+static int msm_camera_v4l2_g_parm(struct file *f, void *pctx,
+				struct v4l2_streamparm *a)
+{
+	int rc = -EINVAL;
+	return rc;
+}
+static int msm_vidbuf_get_path(u32 extendedmode)
+{
+	switch (extendedmode) {
+	case MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL:
+		return OUTPUT_TYPE_T;
+	case MSM_V4L2_EXT_CAPTURE_MODE_MAIN:
+		return OUTPUT_TYPE_S;
+	case MSM_V4L2_EXT_CAPTURE_MODE_VIDEO:
+		return OUTPUT_TYPE_V;
+	case MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT:
+	case MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW:
+	default:
+		return OUTPUT_TYPE_P;
+	}
+}
+
+static int msm_camera_v4l2_s_parm(struct file *f, void *pctx,
+				struct v4l2_streamparm *a)
+{
+	int rc = 0;
+	struct msm_cam_v4l2_dev_inst *pcam_inst  = f->private_data;
+	pcam_inst->image_mode = a->parm.capture.extendedmode;
+	pcam_inst->pcam->dev_inst_map[pcam_inst->image_mode] = pcam_inst;
+	pcam_inst->path = msm_vidbuf_get_path(pcam_inst->image_mode);
+	D("%spath=%d,rc=%d\n", __func__,
+		pcam_inst->path, rc);
+	return rc;
+}
+
+static int msm_camera_v4l2_subscribe_event(struct v4l2_fh *fh,
+			struct v4l2_event_subscription *sub)
+{
+	int rc = 0;
+
+	D("%s\n", __func__);
+	D("fh = 0x%x\n", (u32)fh);
+
+	/* handle special case where user wants to subscribe to all
+	the events */
+	D("sub->type = 0x%x\n", sub->type);
+
+	if (sub->type == V4L2_EVENT_ALL) {
+		/*sub->type = MSM_ISP_EVENT_START;*/
+		sub->type = V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_CTRL;
+
+		D("sub->type start = 0x%x\n", sub->type);
+		do {
+			rc = v4l2_event_subscribe(fh, sub);
+			if (rc < 0) {
+				D("%s: failed for evtType = 0x%x, rc = %d\n",
+						__func__, sub->type, rc);
+			/* unsubscribe all events here and return */
+			sub->type = V4L2_EVENT_ALL;
+			v4l2_event_unsubscribe(fh, sub);
+			return rc;
+			} else
+				D("%s: subscribed evtType = 0x%x, rc = %d\n",
+						__func__, sub->type, rc);
+			sub->type++;
+			D("sub->type while = 0x%x\n", sub->type);
+		} while (sub->type !=
+			V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_MAX);
+	} else {
+		D("sub->type not V4L2_EVENT_ALL = 0x%x\n", sub->type);
+		rc = v4l2_event_subscribe(fh, sub);
+		if (rc < 0)
+			D("%s: failed for evtType = 0x%x, rc = %d\n",
+						__func__, sub->type, rc);
+	}
+
+	D("%s: rc = %d\n", __func__, rc);
+	return rc;
+}
+
+static int msm_camera_v4l2_unsubscribe_event(struct v4l2_fh *fh,
+			struct v4l2_event_subscription *sub)
+{
+	int rc = 0;
+
+	D("%s\n", __func__);
+	D("fh = 0x%x\n", (u32)fh);
+
+	rc = v4l2_event_unsubscribe(fh, sub);
+
+	D("%s: rc = %d\n", __func__, rc);
+	return rc;
+}
+
+/* v4l2_ioctl_ops */
+static const struct v4l2_ioctl_ops g_msm_ioctl_ops = {
+	.vidioc_querycap = msm_camera_v4l2_querycap,
+
+	.vidioc_s_crop = msm_camera_v4l2_s_crop,
+	.vidioc_g_crop = msm_camera_v4l2_g_crop,
+
+	.vidioc_queryctrl = msm_camera_v4l2_queryctrl,
+	.vidioc_g_ctrl = msm_camera_v4l2_g_ctrl,
+	.vidioc_s_ctrl = msm_camera_v4l2_s_ctrl,
+
+	.vidioc_reqbufs = msm_camera_v4l2_reqbufs,
+	.vidioc_querybuf = msm_camera_v4l2_querybuf,
+	.vidioc_qbuf = msm_camera_v4l2_qbuf,
+	.vidioc_dqbuf = msm_camera_v4l2_dqbuf,
+
+	.vidioc_streamon = msm_camera_v4l2_streamon,
+	.vidioc_streamoff = msm_camera_v4l2_streamoff,
+
+	/* format ioctls */
+	.vidioc_enum_fmt_vid_cap = msm_camera_v4l2_enum_fmt_cap,
+	.vidioc_try_fmt_vid_cap = msm_camera_v4l2_try_fmt_cap,
+	.vidioc_g_fmt_vid_cap = msm_camera_v4l2_g_fmt_cap,
+	.vidioc_s_fmt_vid_cap = msm_camera_v4l2_s_fmt_cap,
+
+	.vidioc_g_jpegcomp = msm_camera_v4l2_g_jpegcomp,
+	.vidioc_s_jpegcomp = msm_camera_v4l2_s_jpegcomp,
+
+	/* Stream type-dependent parameter ioctls */
+	.vidioc_g_parm =  msm_camera_v4l2_g_parm,
+	.vidioc_s_parm =  msm_camera_v4l2_s_parm,
+
+	/* event subscribe/unsubscribe */
+	.vidioc_subscribe_event = msm_camera_v4l2_subscribe_event,
+	.vidioc_unsubscribe_event = msm_camera_v4l2_unsubscribe_event,
+};
+
+/* open an active camera session to manage the streaming logic */
+static int msm_cam_server_open_session(struct msm_cam_server_dev *ps,
+	struct msm_cam_v4l2_device *pcam)
+{
+	int rc = 0;
+	D("%s\n", __func__);
+
+	if (!ps || !pcam) {
+		pr_err("%s NULL pointer passed in!\n", __func__);
+		return rc;
+	}
+
+	/* book keeping this camera session*/
+	ps->pcam_active = pcam;
+	atomic_inc(&ps->number_pcam_active);
+
+	D("config pcam = 0x%p\n", ps->pcam_active);
+
+	/* initialization the media controller module*/
+	msm_mctl_init_module(pcam);
+
+	/*yyan: for single VFE msms (8660, 8960v1), just populate the session
+	with our VFE devices that registered*/
+	pcam->mctl.sensor_sdev = &(pcam->sensor_sdev);
+
+	pcam->mctl.isp_sdev = ps->isp_subdev[0];
+	pcam->mctl.ispif_fns = &ps->ispif_fns;
+
+
+	/*yyan: 8960 bring up - no VPE and flash; populate later*/
+	pcam->mctl.vpe_sdev = NULL;
+	pcam->mctl.flash_sdev = NULL;
+
+	return rc;
+
+}
+
+/* close an active camera session to server */
+static int msm_cam_server_close_session(struct msm_cam_server_dev *ps,
+	struct msm_cam_v4l2_device *pcam)
+{
+	int rc = 0;
+	D("%s\n", __func__);
+
+	if (!ps || !pcam) {
+		D("%s NULL pointer passed in!\n", __func__);
+		return rc;
+	}
+
+
+	atomic_dec(&ps->number_pcam_active);
+	ps->pcam_active = NULL;
+
+	return rc;
+}
+/* v4l2_file_operations */
+static int msm_open(struct file *f)
+{
+	int i;
+	int rc = -EINVAL;
+	/*struct msm_isp_ops *p_isp = 0;*/
+	/* get the video device */
+	struct msm_cam_v4l2_device *pcam  = video_drvdata(f);
+	struct msm_cam_v4l2_dev_inst *pcam_inst;
+
+	D("%s\n", __func__);
+
+	if (!pcam) {
+		pr_err("%s NULL pointer passed in!\n", __func__);
+		return rc;
+	}
+	mutex_lock(&pcam->vid_lock);
+	for (i = 0; i < MSM_DEV_INST_MAX; i++) {
+		if (pcam->dev_inst[i] == NULL) {
+			mutex_unlock(&pcam->vid_lock);
+			break;
+		}
+	}
+	/* if no instance is available, return error */
+	if (i == MSM_DEV_INST_MAX) {
+		mutex_unlock(&pcam->vid_lock);
+		return rc;
+	}
+	pcam_inst = kzalloc(sizeof(struct msm_cam_v4l2_dev_inst), GFP_KERNEL);
+	if (!pcam_inst) {
+		mutex_unlock(&pcam->vid_lock);
+		return rc;
+	}
+	pcam_inst->sensor_pxlcode = pcam->usr_fmts[0].pxlcode;
+	pcam_inst->my_index = i;
+	pcam_inst->pcam = pcam;
+	pcam->dev_inst[i] = pcam_inst;
+
+	D("%s for %s\n", __func__, pcam->pdev->name);
+	pcam->use_count++;
+	if (pcam->use_count == 1) {
+
+		rc = msm_cam_server_open_session(&g_server_dev, pcam);
+		if (rc < 0) {
+			pr_err("%s: cam_server_open_session failed %d\n",
+			__func__, rc);
+			mutex_unlock(&pcam->vid_lock);
+			return rc;
+		}
+
+		/* Should be set to sensor ops if any but right now its OK!! */
+		if (!pcam->mctl.mctl_open) {
+			D("%s: media contoller is not inited\n",
+				 __func__);
+			mutex_unlock(&pcam->vid_lock);
+			return -ENODEV;
+		}
+
+		/* Now we really have to activate the camera */
+		D("%s: call mctl_open\n", __func__);
+		rc = pcam->mctl.mctl_open(&(pcam->mctl), MSM_APPS_ID_V4L2);
+
+		if (rc < 0) {
+			mutex_unlock(&pcam->vid_lock);
+			pr_err("%s: HW open failed rc = 0x%x\n",  __func__, rc);
+			return rc;
+		}
+		pcam->mctl.sync.pcam_sync = pcam;
+
+		/* Register isp subdev */
+		rc = v4l2_device_register_subdev(&pcam->v4l2_dev,
+					&pcam->mctl.isp_sdev->sd);
+		if (rc < 0) {
+			mutex_unlock(&pcam->vid_lock);
+			pr_err("%s: v4l2_device_register_subdev failed rc = %d\n",
+				__func__, rc);
+			return rc;
+		}
+	}
+
+	/* Initialize the video queue */
+	rc = pcam->mctl.mctl_vidbuf_init(pcam_inst, &pcam_inst->vid_bufq);
+	if (rc < 0) {
+		mutex_unlock(&pcam->vid_lock);
+		return rc;
+	}
+
+
+	f->private_data = pcam_inst;
+
+	D("f->private_data = 0x%x, pcam = 0x%x\n",
+		(u32)f->private_data, (u32)pcam_inst);
+
+
+	if (pcam->use_count == 1) {
+		rc = msm_send_open_server();
+		if (rc < 0) {
+			mutex_unlock(&pcam->vid_lock);
+			pr_err("%s failed\n", __func__);
+			return rc;
+		}
+	}
+	mutex_unlock(&pcam->vid_lock);
+	/* rc = msm_cam_server_open_session(g_server_dev, pcam);*/
+	return rc;
+}
+
+static int msm_mmap(struct file *f, struct vm_area_struct *vma)
+{
+	int rc = 0;
+	struct msm_cam_v4l2_dev_inst *pcam_inst  = f->private_data;
+
+	D("mmap called, vma=0x%08lx\n", (unsigned long)vma);
+
+	rc = videobuf_mmap_mapper(&pcam_inst->vid_bufq, vma);
+
+	D("vma start=0x%08lx, size=%ld, ret=%d\n",
+		(unsigned long)vma->vm_start,
+		(unsigned long)vma->vm_end - (unsigned long)vma->vm_start,
+		rc);
+
+	return rc;
+}
+
+static int msm_close(struct file *f)
+{
+	int rc = 0;
+	struct msm_cam_v4l2_device *pcam  = video_drvdata(f);
+	struct msm_cam_v4l2_dev_inst *pcam_inst  = f->private_data;
+
+	D("%s\n", __func__);
+	if (!pcam) {
+		pr_err("%s NULL pointer of camera device!\n", __func__);
+		return -EINVAL;
+	}
+
+
+	mutex_lock(&pcam->vid_lock);
+	pcam->use_count--;
+	pcam->dev_inst_map[pcam_inst->image_mode] = NULL;
+	videobuf_stop(&pcam_inst->vid_bufq);
+	/* free the queue: function name is ambiguous it frees all
+	types of buffers (mmap or userptr - it doesn't matter) */
+	rc = videobuf_mmap_free(&pcam_inst->vid_bufq);
+	if (rc  < 0)
+		pr_err("%s: unable to free buffers\n", __func__);
+	pcam->dev_inst[pcam_inst->my_index] = NULL;
+	kfree(pcam_inst);
+	f->private_data = NULL;
+
+	if (pcam->use_count == 0) {
+		if (pcam->mctl.mctl_release) {
+			rc = pcam->mctl.mctl_release(&(pcam->mctl));
+			if (rc < 0)
+				pr_err("mctl_release fails %d\n", rc);
+		}
+
+		v4l2_device_unregister_subdev(&pcam->mctl.isp_sdev->sd);
+
+		rc = msm_cam_server_close_session(&g_server_dev, pcam);
+		if (rc < 0)
+			pr_err("msm_cam_server_close_session fails %d\n", rc);
+
+		rc = msm_send_close_server();
+		if (rc < 0)
+			pr_err("msm_send_close_server failed %d\n", rc);
+
+		dma_release_declared_memory(&pcam->pdev->dev);
+	}
+	mutex_unlock(&pcam->vid_lock);
+	return rc;
+}
+
+static unsigned int msm_poll(struct file *f, struct poll_table_struct *wait)
+{
+	int rc = 0;
+	struct msm_cam_v4l2_device *pcam  = video_drvdata(f);
+	struct msm_cam_v4l2_dev_inst *pcam_inst  = f->private_data;
+
+	D("%s\n", __func__);
+	if (!pcam) {
+		pr_err("%s NULL pointer of camera device!\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!pcam_inst->vid_bufq.streaming) {
+		D("%s vid_bufq.streaming is off, inst=0x%x\n",
+			__func__, (u32)pcam_inst);
+		return -EINVAL;
+	}
+
+	rc |= videobuf_poll_stream(f, &pcam_inst->vid_bufq, wait);
+	D("%s returns, rc  = 0x%x\n", __func__, rc);
+
+	return rc;
+}
+
+static unsigned int msm_poll_server(struct file *fp,
+					struct poll_table_struct *wait)
+{
+	int rc = 0;
+
+	D("%s\n", __func__);
+	poll_wait(fp,
+		 &g_server_dev.server_command_queue.eventHandle.events->wait,
+		 wait);
+	if (v4l2_event_pending(&g_server_dev.server_command_queue.eventHandle))
+		rc |= POLLPRI;
+
+	return rc;
+}
+static long msm_ioctl_server(struct file *fp, unsigned int cmd,
+	unsigned long arg)
+{
+	int rc = -EINVAL;
+	struct v4l2_event ev;
+	struct msm_camera_info temp_cam_info;
+	struct msm_cam_config_dev_info temp_config_info;
+	struct v4l2_event_subscription temp_sub;
+	int i;
+
+	D("%s: cmd %d\n", __func__, _IOC_NR(cmd));
+
+	switch (cmd) {
+	case MSM_CAM_IOCTL_GET_CAMERA_INFO:
+		if (copy_from_user(&temp_cam_info, (void __user *)arg,
+					  sizeof(struct msm_camera_info))) {
+			rc = -EINVAL;
+			return rc;
+		}
+		for (i = 0; i < g_server_dev.camera_info.num_cameras; i++) {
+			if (copy_to_user((void __user *)
+			temp_cam_info.video_dev_name[i],
+			 g_server_dev.camera_info.video_dev_name[i],
+			strlen(g_server_dev.camera_info.video_dev_name[i]))) {
+				rc = -EINVAL;
+				return rc;
+			}
+			temp_cam_info.has_3d_support[i] =
+				g_server_dev.camera_info.has_3d_support[i];
+			temp_cam_info.is_internal_cam[i] =
+				g_server_dev.camera_info.is_internal_cam[i];
+			temp_cam_info.s_mount_angle[i] =
+				g_server_dev.camera_info.s_mount_angle[i];
+			temp_cam_info.sensor_type[i] =
+				g_server_dev.camera_info.sensor_type[i];
+
+		}
+		temp_cam_info.num_cameras =
+			g_server_dev.camera_info.num_cameras;
+		if (copy_to_user((void __user *)arg,
+							  &temp_cam_info,
+				sizeof(struct msm_camera_info))) {
+			rc = -EINVAL;
+			return rc;
+		}
+		rc = 0;
+		break;
+
+	case MSM_CAM_IOCTL_GET_CONFIG_INFO:
+		if (copy_from_user(&temp_config_info, (void __user *)arg,
+				  sizeof(struct msm_cam_config_dev_info))) {
+			rc = -EINVAL;
+			return rc;
+		}
+		for (i = 0;
+		 i < g_server_dev.config_info.num_config_nodes; i++) {
+			if (copy_to_user(
+			(void __user *)temp_config_info.config_dev_name[i],
+			g_server_dev.config_info.config_dev_name[i],
+			strlen(g_server_dev.config_info.config_dev_name[i]))) {
+				rc = -EINVAL;
+				return rc;
+			}
+		}
+		temp_config_info.num_config_nodes =
+			g_server_dev.config_info.num_config_nodes;
+		if (copy_to_user((void __user *)arg,
+							  &temp_config_info,
+				sizeof(struct msm_cam_config_dev_info))) {
+			rc = -EINVAL;
+			return rc;
+		}
+		rc = 0;
+		break;
+
+	case VIDIOC_SUBSCRIBE_EVENT:
+		if (copy_from_user(&temp_sub, (void __user *)arg,
+				  sizeof(struct v4l2_event_subscription))) {
+			rc = -EINVAL;
+			return rc;
+		}
+		rc = msm_camera_v4l2_subscribe_event
+			(&g_server_dev.server_command_queue.eventHandle,
+			 &temp_sub);
+		if (rc < 0)
+			return rc;
+
+		break;
+
+	case VIDIOC_DQEVENT: {
+		void __user *u_ctrl_value = NULL;
+		struct msm_isp_stats_event_ctrl *u_isp_event;
+		struct msm_isp_stats_event_ctrl *k_isp_event;
+
+		/* Make a copy of control value and event data pointer */
+		D("%s: VIDIOC_DQEVENT\n", __func__);
+		if (copy_from_user(&ev, (void __user *)arg,
+				sizeof(struct v4l2_event)))
+			break;
+		u_isp_event = (struct msm_isp_stats_event_ctrl *)ev.u.data;
+		u_ctrl_value = u_isp_event->isp_data.ctrl.value;
+
+		rc = v4l2_event_dequeue(
+			&g_server_dev.server_command_queue.eventHandle,
+			 &ev, fp->f_flags & O_NONBLOCK);
+		if (rc < 0) {
+			pr_err("no pending events?");
+			break;
+		}
+
+		k_isp_event = (struct msm_isp_stats_event_ctrl *)ev.u.data;
+		if (ev.type == V4L2_EVENT_PRIVATE_START+MSM_CAM_RESP_V4L2 &&
+				k_isp_event->isp_data.ctrl.length > 0) {
+			void *k_ctrl_value = k_isp_event->isp_data.ctrl.value;
+			if (copy_to_user(u_ctrl_value, k_ctrl_value,
+				u_isp_event->isp_data.ctrl.length)) {
+				rc = -EINVAL;
+				break;
+			}
+		}
+		k_isp_event->isp_data.ctrl.value = u_ctrl_value;
+
+		if (copy_to_user((void __user *)arg, &ev,
+				sizeof(struct v4l2_event))) {
+			rc = -EINVAL;
+			break;
+		}
+		}
+
+		break;
+
+	case MSM_CAM_IOCTL_CTRL_CMD_DONE:
+		D("%s: MSM_CAM_IOCTL_CTRL_CMD_DONE\n", __func__);
+		rc = msm_ctrl_cmd_done((void __user *)arg);
+		break;
+
+	default:
+		break;
+	}
+	return rc;
+}
+
+static int msm_open_server(struct inode *inode, struct file *fp)
+{
+	int rc;
+	D("%s: open %s\n", __func__, fp->f_path.dentry->d_name.name);
+
+	rc = nonseekable_open(inode, fp);
+	if (rc < 0) {
+		pr_err("%s: nonseekable_open error %d\n", __func__, rc);
+		return rc;
+	}
+	g_server_dev.use_count++;
+	if (g_server_dev.use_count == 1)
+		msm_queue_init(&g_server_dev.ctrl_q, "control");
+
+	return rc;
+}
+
+static unsigned int msm_poll_config(struct file *fp,
+					struct poll_table_struct *wait)
+{
+	int rc = 0;
+	struct msm_cam_config_dev *config = fp->private_data;
+	if (config == NULL)
+		return -EINVAL;
+
+	D("%s\n", __func__);
+
+	poll_wait(fp,
+	&config->config_stat_event_queue.eventHandle.events->wait, wait);
+	if (v4l2_event_pending(&config->config_stat_event_queue.eventHandle))
+		rc |= POLLPRI;
+	return rc;
+}
+
+static long msm_ioctl_config(struct file *fp, unsigned int cmd,
+	unsigned long arg)
+{
+
+	int rc = 0;
+	struct v4l2_event ev;
+	struct msm_cam_config_dev *config_cam = fp->private_data;
+	struct v4l2_event_subscription temp_sub;
+
+	D("%s: cmd %d\n", __func__, _IOC_NR(cmd));
+
+	switch (cmd) {
+		/* memory management shall be handeld here*/
+	case MSM_CAM_IOCTL_REGISTER_PMEM:
+		   return msm_register_pmem(
+			&config_cam->p_mctl->sync.pmem_stats,
+			(void __user *)arg);
+		   break;
+
+	case MSM_CAM_IOCTL_UNREGISTER_PMEM:
+		   return msm_pmem_table_del(
+			&config_cam->p_mctl->sync.pmem_stats,
+			(void __user *)arg);
+		   break;
+	case VIDIOC_SUBSCRIBE_EVENT:
+			if (copy_from_user(&temp_sub,
+			(void __user *)arg,
+			sizeof(struct v4l2_event_subscription))) {
+				rc = -EINVAL;
+				return rc;
+			}
+			rc = msm_camera_v4l2_subscribe_event
+			(&config_cam->config_stat_event_queue.eventHandle,
+				 &temp_sub);
+			if (rc < 0)
+				return rc;
+
+			break;
+
+	case VIDIOC_UNSUBSCRIBE_EVENT:
+		if (copy_from_user(&temp_sub, (void __user *)arg,
+			  sizeof(struct v4l2_event_subscription))) {
+			rc = -EINVAL;
+			return rc;
+		}
+		rc = msm_camera_v4l2_unsubscribe_event
+			(&config_cam->config_stat_event_queue.eventHandle,
+			 &temp_sub);
+		if (rc < 0)
+			return rc;
+
+		break;
+
+	case VIDIOC_DQEVENT: {
+		void __user *u_msg_value = NULL;
+		struct msm_isp_stats_event_ctrl *u_isp_event;
+		struct msm_isp_stats_event_ctrl *k_isp_event;
+
+		/* Make a copy of control value and event data pointer */
+		D("%s: VIDIOC_DQEVENT\n", __func__);
+		if (copy_from_user(&ev, (void __user *)arg,
+				sizeof(struct v4l2_event)))
+			break;
+		u_isp_event = (struct msm_isp_stats_event_ctrl *)ev.u.data;
+		u_msg_value = u_isp_event->isp_data.isp_msg.data;
+
+		rc = v4l2_event_dequeue(
+		&config_cam->config_stat_event_queue.eventHandle,
+			 &ev, fp->f_flags & O_NONBLOCK);
+		if (rc < 0) {
+			pr_err("no pending events?");
+			break;
+		}
+
+		k_isp_event = (struct msm_isp_stats_event_ctrl *)ev.u.data;
+		if (ev.type ==
+			V4L2_EVENT_PRIVATE_START+MSM_CAM_RESP_STAT_EVT_MSG &&
+			k_isp_event->isp_data.isp_msg.len > 0) {
+			void *k_msg_value = k_isp_event->isp_data.isp_msg.data;
+			if (copy_to_user(u_msg_value, k_msg_value,
+				k_isp_event->isp_data.isp_msg.len)) {
+				rc = -EINVAL;
+				break;
+			}
+			kfree(k_msg_value);
+		}
+		k_isp_event->isp_data.isp_msg.data = u_msg_value;
+
+		if (copy_to_user((void __user *)arg, &ev,
+				sizeof(struct v4l2_event))) {
+			rc = -EINVAL;
+			break;
+		}
+		}
+
+		break;
+
+	default:{
+		/* For the rest of config command, forward to media controller*/
+		struct msm_cam_media_controller *p_mctl = config_cam->p_mctl;
+		if (p_mctl && p_mctl->mctl_cmd) {
+			rc = config_cam->p_mctl->mctl_cmd(p_mctl, cmd, arg);
+		} else {
+			rc = -EINVAL;
+			pr_err("%s: media controller is null\n", __func__);
+		}
+
+		break;
+	} /* end of default*/
+	} /* end of switch*/
+	return rc;
+}
+
+static int msm_open_config(struct inode *inode, struct file *fp)
+{
+	int rc;
+
+	struct msm_cam_config_dev *config_cam =
+	container_of(inode->i_cdev, struct msm_cam_config_dev, config_cdev);
+
+	D("%s: open %s\n", __func__, fp->f_path.dentry->d_name.name);
+
+	rc = nonseekable_open(inode, fp);
+	if (rc < 0) {
+		pr_err("%s: nonseekable_open error %d\n", __func__, rc);
+		return rc;
+	}
+	config_cam->use_count++;
+
+	/*config_cam->isp_subdev = g_server_dev.pcam_active->mctl.isp_sdev;*/
+	/* assume there is only one active camera possible*/
+	config_cam->p_mctl = &g_server_dev.pcam_active->mctl;
+
+	INIT_HLIST_HEAD(&config_cam->p_mctl->sync.pmem_stats);
+	spin_lock_init(&config_cam->p_mctl->sync.pmem_stats_spinlock);
+
+	config_cam->p_mctl->config_device = config_cam;
+	fp->private_data = config_cam;
+	return rc;
+}
+
+static struct v4l2_file_operations g_msm_fops = {
+	.owner   = THIS_MODULE,
+	.open	= msm_open,
+	.poll	= msm_poll,
+	.mmap	= msm_mmap,
+	.release = msm_close,
+	.ioctl   = video_ioctl2,
+};
+
+/* Init a config node for ISP control,
+   which will create a config device (/dev/config0/ and plug in
+   ISP's operation "v4l2_ioctl_ops*"
+*/
+static const struct file_operations msm_fops_server = {
+	.owner = THIS_MODULE,
+	.open  = msm_open_server,
+	.poll  = msm_poll_server,
+	.unlocked_ioctl = msm_ioctl_server,
+};
+
+static const struct file_operations msm_fops_config = {
+	.owner = THIS_MODULE,
+	.open  = msm_open_config,
+	.poll  = msm_poll_config,
+	.unlocked_ioctl = msm_ioctl_config,
+};
+
+static int msm_setup_v4l2_event_queue(struct v4l2_fh *eventHandle,
+				  struct video_device *pvdev)
+{
+	int rc = 0;
+	/* v4l2_fh support */
+	spin_lock_init(&pvdev->fh_lock);
+	INIT_LIST_HEAD(&pvdev->fh_list);
+
+	rc = v4l2_fh_init(eventHandle, pvdev);
+	if (rc < 0)
+		return rc;
+
+	rc = v4l2_event_init(eventHandle);
+	if (rc < 0)
+		return rc;
+
+	/* queue of max size 30 */
+	rc = v4l2_event_alloc(eventHandle, 30);
+	if (rc < 0)
+		return rc;
+
+	v4l2_fh_add(eventHandle);
+	return rc;
+
+}
+
+static int msm_setup_config_dev(int node, char *device_name)
+{
+	int rc = -ENODEV;
+	struct device *device_config;
+	int dev_num = node;
+	dev_t devno;
+	struct msm_cam_config_dev *config_cam;
+
+	config_cam = kzalloc(sizeof(*config_cam), GFP_KERNEL);
+	if (!config_cam) {
+		pr_err("%s: could not allocate memory for msm_cam_config_device\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	D("%s\n", __func__);
+
+	devno = MKDEV(MAJOR(msm_devno), dev_num+1);
+	device_config = device_create(msm_class, NULL, devno, NULL,
+				    "%s%d", device_name, dev_num);
+
+	if (IS_ERR(device_config)) {
+		rc = PTR_ERR(device_config);
+		pr_err("%s: error creating device: %d\n", __func__, rc);
+		return rc;
+	}
+
+	cdev_init(&config_cam->config_cdev,
+			   &msm_fops_config);
+	config_cam->config_cdev.owner = THIS_MODULE;
+
+	rc = cdev_add(&config_cam->config_cdev, devno, 1);
+	if (rc < 0) {
+		pr_err("%s: error adding cdev: %d\n", __func__, rc);
+		device_destroy(msm_class, devno);
+		return rc;
+	}
+	g_server_dev.config_info.config_dev_name[dev_num]
+		= dev_name(device_config);
+	D("%s Connected config device %s\n", __func__,
+		g_server_dev.config_info.config_dev_name[dev_num]);
+
+	config_cam->config_stat_event_queue.pvdev = video_device_alloc();
+	if (config_cam->config_stat_event_queue.pvdev == NULL) {
+		pr_err("%s: video_device_alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	rc = msm_setup_v4l2_event_queue(
+		&config_cam->config_stat_event_queue.eventHandle,
+		config_cam->config_stat_event_queue.pvdev);
+	if (rc < 0)
+		pr_err("%s failed to initialize event queue\n", __func__);
+
+	return rc;
+}
+
+static int msm_setup_server_dev(int node, char *device_name)
+{
+	int rc = -ENODEV;
+	struct device *device_server;
+	int dev_num = node;
+	dev_t devno;
+
+	D("%s\n", __func__);
+
+	devno = MKDEV(MAJOR(msm_devno), dev_num);
+	device_server = device_create(msm_class, NULL,
+			devno, NULL, "%s", device_name);
+
+	if (IS_ERR(device_server)) {
+		rc = PTR_ERR(device_server);
+		pr_err("%s: error creating device: %d\n", __func__, rc);
+		return rc;
+	}
+
+	cdev_init(&g_server_dev.server_cdev, &msm_fops_server);
+	g_server_dev.server_cdev.owner = THIS_MODULE;
+
+	rc = cdev_add(&g_server_dev.server_cdev, devno, 1);
+	if (rc < 0) {
+		pr_err("%s: error adding cdev: %d\n", __func__, rc);
+		device_destroy(msm_class, devno);
+		return rc;
+	}
+
+	g_server_dev.pcam_active = NULL;
+	g_server_dev.camera_info.num_cameras = 0;
+	atomic_set(&g_server_dev.number_pcam_active, 0);
+	g_server_dev.ispif_fns.ispif_config = NULL;
+
+	/*initialize fake video device and event queue*/
+
+	g_server_dev.server_command_queue.pvdev = video_device_alloc();
+	if (g_server_dev.server_command_queue.pvdev == NULL) {
+		pr_err("%s: video_device_alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+	rc = msm_setup_v4l2_event_queue(
+		&g_server_dev.server_command_queue.eventHandle,
+		g_server_dev.server_command_queue.pvdev);
+	if (rc < 0)
+		pr_err("%s failed to initialize event queue\n", __func__);
+
+	return rc;
+}
+
+static int msm_cam_dev_init(struct msm_cam_v4l2_device *pcam)
+{
+	int rc = -ENOMEM;
+	struct video_device *pvdev = NULL;
+	D("%s\n", __func__);
+
+	/* first register the v4l2 device */
+	pcam->v4l2_dev.dev = &pcam->pdev->dev;
+	rc = v4l2_device_register(pcam->v4l2_dev.dev, &pcam->v4l2_dev);
+	if (rc < 0)
+		return -EINVAL;
+	else
+		pcam->v4l2_dev.notify = msm_cam_v4l2_subdev_notify;
+
+
+	/* now setup video device */
+	pvdev = video_device_alloc();
+	if (pvdev == NULL) {
+		pr_err("%s: video_device_alloc failed\n", __func__);
+		return rc;
+	}
+
+	/* init video device's driver interface */
+	D("sensor name = %s, sizeof(pvdev->name)=%d\n",
+		pcam->pdev->name, sizeof(pvdev->name));
+
+	/* device info - strlcpy is safer than strncpy but
+	   only if architecture supports*/
+	strlcpy(pvdev->name, pcam->pdev->name, sizeof(pvdev->name));
+
+	pvdev->release   = video_device_release;
+	pvdev->fops	  = &g_msm_fops;
+	pvdev->ioctl_ops = &g_msm_ioctl_ops;
+	pvdev->minor	 = -1;
+	pvdev->vfl_type  = 1;
+
+	/* register v4l2 video device to kernel as /dev/videoXX */
+	D("video_register_device\n");
+	rc = video_register_device(pvdev,
+				   VFL_TYPE_GRABBER,
+				   msm_camera_v4l2_nr);
+	if (rc) {
+		pr_err("%s: video_register_device failed\n", __func__);
+		goto reg_fail;
+	}
+	D("%s: video device registered as /dev/video%d\n",
+		__func__, pvdev->num);
+
+	/* connect pcam and video dev to each other */
+	pcam->pvdev	= pvdev;
+	video_set_drvdata(pcam->pvdev, pcam);
+
+	/* If isp HW registeration is successful, then create event queue to
+	   receievent event froms HW
+	 */
+	/* yyan: no global - each sensor will create a new vidoe node! */
+	/* g_pmsm_camera_v4l2_dev = pmsm_camera_v4l2_dev; */
+	/* g_pmsm_camera_v4l2_dev->pvdev = pvdev; */
+
+	return rc ;
+
+reg_fail:
+	video_device_release(pvdev);
+	v4l2_device_unregister(&pcam->v4l2_dev);
+	pcam->v4l2_dev.dev = NULL;
+	return rc;
+}
+
+static int msm_sync_destroy(struct msm_sync *sync)
+{
+	if (sync)
+		wake_lock_destroy(&sync->wake_lock);
+	return 0;
+}
+static int msm_sync_init(struct msm_sync *sync,
+	struct platform_device *pdev, struct msm_sensor_ctrl *sctrl)
+{
+	int rc = 0;
+
+	sync->sdata = pdev->dev.platform_data;
+
+	wake_lock_init(&sync->wake_lock, WAKE_LOCK_IDLE, "msm_camera");
+
+	sync->pdev = pdev;
+	sync->sctrl = *sctrl;
+	sync->opencnt = 0;
+	mutex_init(&sync->lock);
+	D("%s: initialized %s\n", __func__, sync->sdata->sensor_name);
+	return rc;
+}
+
+int msm_ispif_register(struct msm_ispif_fns *ispif)
+{
+	int rc = -EINVAL;
+	if (ispif != NULL) {
+		/*save ispif into server dev*/
+		g_server_dev.ispif_fns.ispif_config = ispif->ispif_config;
+		g_server_dev.ispif_fns.ispif_start_intf_transfer
+			= ispif->ispif_start_intf_transfer;
+		rc = 0;
+	}
+	return rc;
+}
+EXPORT_SYMBOL(msm_ispif_register);
+
+/* register a msm sensor into the msm device, which will probe the
+   sensor HW. if the HW exist then create a video device (/dev/videoX/)
+   to represent this sensor */
+int msm_sensor_register(struct platform_device *pdev,
+		int (*sensor_probe)(const struct msm_camera_sensor_info *,
+			struct v4l2_subdev *, struct msm_sensor_ctrl *))
+{
+
+	int rc = -EINVAL;
+	struct msm_camera_sensor_info *sdata = pdev->dev.platform_data;
+	struct msm_cam_v4l2_device *pcam;
+	struct v4l2_subdev *sdev;
+	struct msm_sensor_ctrl sctrl;
+
+	D("%s for %s\n", __func__, pdev->name);
+
+	/* allocate the memory for the camera device first */
+	pcam = kzalloc(sizeof(*pcam), GFP_KERNEL);
+	if (!pcam) {
+		pr_err("%s: could not allocate memory for msm_cam_v4l2_device\n",
+			__func__);
+		return -ENOMEM;
+	} else{
+		sdev = &(pcam->sensor_sdev);
+		snprintf(sdev->name, sizeof(sdev->name), "%s", pdev->name);
+	}
+
+	/* come sensor probe logic */
+	rc = msm_camio_probe_on(pdev);
+	if (rc < 0) {
+		kzfree(pcam);
+		return rc;
+	}
+
+	rc = sensor_probe(sdata, sdev, &sctrl);
+
+	msm_camio_probe_off(pdev);
+	if (rc < 0) {
+		pr_err("%s: failed to detect %s\n",
+			__func__,
+		sdata->sensor_name);
+		kzfree(pcam);
+		return rc;
+	}
+
+	/* if the probe is successfull, allocat the camera driver object
+	   for this sensor */
+
+	pcam->sync = kzalloc(sizeof(struct msm_sync), GFP_ATOMIC);
+	if (!pcam->sync) {
+		pr_err("%s: could not allocate memory for msm_sync object\n",
+			__func__);
+		kzfree(pcam);
+		return -ENOMEM;
+	}
+
+	/* setup a manager object*/
+	rc = msm_sync_init(pcam->sync, pdev, &sctrl);
+	if (rc < 0)
+		goto failure;
+	D("%s: pcam =0x%p\n", __func__, pcam);
+	D("%s: pcam->sync =0x%p\n", __func__, pcam->sync);
+
+	(pcam->sync)->pcam_sync = pcam;
+	/* bind the driver device to the sensor device */
+	pcam->pdev = pdev;
+	pcam->sctrl = sctrl;
+
+	/* init the user count and lock*/
+	pcam->use_count = 0;
+	mutex_init(&pcam->vid_lock);
+
+	/* Initialize the formats supported */
+	rc  = msm_mctl_init_user_formats(pcam);
+	if (rc < 0)
+		goto failure;
+
+	/* now initialize the camera device object */
+	rc  = msm_cam_dev_init(pcam);
+	if (rc < 0)
+		goto failure;
+
+	g_server_dev.camera_info.video_dev_name
+	[g_server_dev.camera_info.num_cameras]
+	= video_device_node_name(pcam->pvdev);
+	D("%s Connected video device %s\n", __func__,
+	  g_server_dev.camera_info.video_dev_name
+		[g_server_dev.camera_info.num_cameras]);
+	g_server_dev.camera_info.num_cameras++;
+
+	D("%s done, rc = %d\n", __func__, rc);
+	D("%s number of sensors connected is %d\n", __func__,
+			g_server_dev.camera_info.num_cameras);
+/*
+	if (g_server_dev.camera_info.num_cameras == 1) {
+		rc = add_axi_qos();
+		if (rc < 0)
+			goto failure;
+	}
+*/
+	/* register the subdevice, must be done for callbacks */
+	rc = v4l2_device_register_subdev(&pcam->v4l2_dev, sdev);
+	pcam->vnode_id = vnode_count++;
+	return rc;
+
+failure:
+	/* mutex_destroy not needed at this moment as the associated
+	implemenation of mutex_init is not consuming resources */
+	msm_sync_destroy(pcam->sync);
+	pcam->pdev = NULL;
+	kzfree(pcam->sync);
+	kzfree(pcam);
+	return rc;
+}
+EXPORT_SYMBOL(msm_sensor_register);
+
+static int __init msm_camera_init(void)
+{
+	int rc = 0, i;
+	/*for now just create a config 0 node
+	  put logic here later to know how many configs to create*/
+	g_server_dev.config_info.num_config_nodes = 1;
+
+	rc = msm_isp_init_module(g_server_dev.config_info.num_config_nodes);
+	if (rc < 0) {
+		pr_err("Failed to initialize isp\n");
+		return rc;
+	}
+
+	if (!msm_class) {
+		rc = alloc_chrdev_region(&msm_devno, 0,
+		g_server_dev.config_info.num_config_nodes+1, "msm_camera");
+		if (rc < 0) {
+			pr_err("%s: failed to allocate chrdev: %d\n", __func__,
+			rc);
+			return rc;
+		}
+
+		msm_class = class_create(THIS_MODULE, "msm_camera");
+		if (IS_ERR(msm_class)) {
+			rc = PTR_ERR(msm_class);
+			pr_err("%s: create device class failed: %d\n",
+			__func__, rc);
+			return rc;
+		}
+	}
+
+	D("creating server and config nodes\n");
+	rc = msm_setup_server_dev(0, "video_msm");
+	if (rc < 0) {
+		pr_err("%s: failed to create server dev: %d\n", __func__,
+		rc);
+		return rc;
+	}
+
+	for (i = 0; i < g_server_dev.config_info.num_config_nodes; i++) {
+		rc = msm_setup_config_dev(i, "config");
+		if (rc < 0) {
+			pr_err("%s:failed to create config dev: %d\n",
+			 __func__, rc);
+			return rc;
+		}
+	}
+
+	msm_isp_register(&g_server_dev);
+	return rc;
+}
+
+static void __exit msm_camera_exit(void)
+{
+	msm_isp_unregister(&g_server_dev);
+}
+
+module_init(msm_camera_init);
+module_exit(msm_camera_exit);
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
new file mode 100644
index 0000000..0049cc1
--- /dev/null
+++ b/drivers/media/video/msm/msm.h
@@ -0,0 +1,372 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _MSM_H
+#define _MSM_H
+
+#ifdef __KERNEL__
+
+/* Header files */
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <linux/pm_qos_params.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-mediabus.h>
+#include <media/videobuf-dma-contig.h>
+#include <media/videobuf-msm-mem.h>
+#include <mach/camera.h>
+
+#define MSM_V4L2_DIMENSION_SIZE 96
+
+#define ERR_USER_COPY(to) pr_err("%s(%d): copy %s user\n", \
+				__func__, __LINE__, ((to) ? "to" : "from"))
+#define ERR_COPY_FROM_USER() ERR_USER_COPY(0)
+#define ERR_COPY_TO_USER() ERR_USER_COPY(1)
+
+/* msm queue management APIs*/
+
+#define msm_dequeue(queue, member) ({	   \
+	unsigned long flags;		  \
+	struct msm_device_queue *__q = (queue);	 \
+	struct msm_queue_cmd *qcmd = 0;	   \
+	spin_lock_irqsave(&__q->lock, flags);	 \
+	if (!list_empty(&__q->list)) {		\
+		__q->len--;		 \
+		qcmd = list_first_entry(&__q->list,   \
+		struct msm_queue_cmd, member);  \
+		list_del_init(&qcmd->member);	 \
+	}			 \
+	spin_unlock_irqrestore(&__q->lock, flags);  \
+	qcmd;			 \
+})
+
+#define msm_queue_drain(queue, member) do {	 \
+	unsigned long flags;		  \
+	struct msm_device_queue *__q = (queue);	 \
+	struct msm_queue_cmd *qcmd;	   \
+	spin_lock_irqsave(&__q->lock, flags);	 \
+	while (!list_empty(&__q->list)) {	 \
+		qcmd = list_first_entry(&__q->list,   \
+			struct msm_queue_cmd, member);	\
+			list_del_init(&qcmd->member);	 \
+			free_qcmd(qcmd);		\
+	 };			  \
+	spin_unlock_irqrestore(&__q->lock, flags);	\
+} while (0)
+
+static inline void free_qcmd(struct msm_queue_cmd *qcmd)
+{
+	if (!qcmd || !atomic_read(&qcmd->on_heap))
+		return;
+	if (!atomic_sub_return(1, &qcmd->on_heap))
+		kfree(qcmd);
+}
+
+/* message id for v4l2_subdev_notify*/
+enum msm_camera_v4l2_subdev_notify {
+	NOTIFY_CID_CHANGE, /* arg = msm_camera_csid_params */
+	NOTIFY_VFE_MSG_EVT, /* arg = msm_vfe_resp */
+	NOTIFY_INVALID
+};
+
+enum isp_vfe_cmd_id {
+	/*
+	*Important! Command_ID are arranged in order.
+	*Don't change!*/
+	ISP_VFE_CMD_ID_STREAM_ON,
+	ISP_VFE_CMD_ID_STREAM_OFF,
+	ISP_VFE_CMD_ID_FRAME_BUF_RELEASE
+};
+
+struct msm_cam_v4l2_device;
+struct msm_cam_v4l2_dev_inst;
+
+/* buffer for one video frame */
+struct msm_frame_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer    vidbuf;
+	enum v4l2_mbus_pixelcode  pxlcode;
+	int                       inuse;
+	int                       active;
+};
+
+struct msm_isp_color_fmt {
+	char *name;
+	int depth;
+	int bitsperpxl;
+	u32 fourcc;
+	enum v4l2_mbus_pixelcode pxlcode;
+	enum v4l2_colorspace colorspace;
+};
+
+enum ispif_op_id {
+	/*
+	*Important! Command_ID are arranged in order.
+	*Don't change!*/
+	ISPIF_ENABLE,
+	ISPIF_DISABLE,
+	ISPIF_RESET,
+	ISPIF_CONFIG
+};
+
+struct msm_ispif_ops {
+
+	int (*ispif_op)(struct msm_ispif_ops *p_ispif,
+		enum ispif_op_id ispif_op_id_used, unsigned long arg);
+};
+
+struct msm_ispif_fns {
+	int (*ispif_config)(struct msm_ispif_params *ispif_params,
+						 uint8_t num_of_intf);
+	int (*ispif_start_intf_transfer)
+		(struct msm_ispif_params *ispif_params);
+};
+
+extern int msm_ispif_init_module(struct msm_ispif_ops *p_ispif);
+
+/*"Media Controller" represents a camera steaming session, which consists
+   of a "sensor" device and an "isp" device (such as VFE, if needed),
+   connected via an "IO" device, (such as IPIF on 8960, or none on 8660)
+   plus other extra sub devices such as VPE and flash
+*/
+
+struct msm_cam_media_controller {
+
+	int (*mctl_open)(struct msm_cam_media_controller *p_mctl,
+					 const char *const apps_id);
+	int (*mctl_cb)(void);
+	int (*mctl_notify)(struct msm_cam_media_controller *p_mctl,
+			unsigned int notification, void *arg);
+	int (*mctl_cmd)(struct msm_cam_media_controller *p_mctl,
+					unsigned int cmd, unsigned long arg);
+	int (*mctl_release)(struct msm_cam_media_controller *p_mctl);
+	int (*mctl_vidbuf_init)(struct msm_cam_v4l2_dev_inst *pcam,
+						struct videobuf_queue *);
+	int (*mctl_ufmt_init)(struct msm_cam_media_controller *p_mctl);
+
+	struct v4l2_device v4l2_dev;
+	struct v4l2_fh  eventHandle; /* event queue to export events */
+	/* most-frequently accessed manager object*/
+	struct msm_sync sync;
+
+
+	/* the following reflect the HW topology information*/
+	/*mandatory*/
+	struct v4l2_subdev *sensor_sdev; /* sensor sub device */
+	struct v4l2_subdev mctl_sdev;   /*  media control sub device */
+	struct platform_device *plat_dev;
+	/*optional*/
+	struct msm_isp_ops *isp_sdev;    /* isp sub device : camif/VFE */
+	struct v4l2_subdev *vpe_sdev;    /* vpe sub device : VPE */
+	struct v4l2_subdev *flash_sdev;    /* vpe sub device : VPE */
+	struct msm_cam_config_dev *config_device;
+	struct msm_ispif_fns *ispif_fns;
+
+	struct pm_qos_request_list pm_qos_req_list;
+};
+
+/* abstract camera device represents a VFE and connected sensor */
+struct msm_isp_ops {
+	char *config_dev_name;
+
+	/*int (*isp_init)(struct msm_cam_v4l2_device *pcam);*/
+	int (*isp_open)(struct v4l2_subdev *sd, struct msm_sync *sync);
+	int (*isp_config)(struct msm_cam_media_controller *pmctl,
+		 unsigned int cmd, unsigned long arg);
+	int (*isp_enqueue)(struct msm_cam_media_controller *pcam,
+		struct msm_vfe_resp *data,
+		enum msm_queue qtype);
+	int (*isp_notify)(struct v4l2_subdev *sd, void *arg);
+
+	void (*isp_release)(struct msm_sync *psync);
+
+	/* vfe subdevice */
+	struct v4l2_subdev sd;
+};
+
+struct msm_isp_buf_info {
+	int type;
+	unsigned long buffer;
+	int fd;
+};
+#define MSM_DEV_INST_MAX                    16
+struct msm_cam_v4l2_dev_inst {
+	struct videobuf_queue vid_bufq;
+	spinlock_t vb_irqlock;
+	struct v4l2_format vid_fmt;
+	/* senssor pixel code*/
+	enum v4l2_mbus_pixelcode sensor_pxlcode;
+	struct msm_cam_v4l2_device *pcam;
+	int my_index;
+	int image_mode;
+	int path;
+	int buf_count;
+};
+#define MSM_MAX_IMG_MODE                5
+/* abstract camera device for each sensor successfully probed*/
+struct msm_cam_v4l2_device {
+	/* standard device interfaces */
+	/* parent of video device to trace back */
+	struct device dev;
+	/* sensor's platform device*/
+	struct platform_device *pdev;
+	/* V4l2 device */
+	struct v4l2_device v4l2_dev;
+	/* will be registered as /dev/video*/
+	struct video_device *pvdev;
+	int use_count;
+	/* will be used to init/release HW */
+	struct msm_cam_media_controller mctl;
+	/* sensor subdevice */
+	struct v4l2_subdev sensor_sdev;
+	struct msm_sensor_ctrl sctrl;
+
+	/* parent device */
+	struct device *parent_dev;
+
+	struct mutex vid_lock;
+	/* v4l2 format support */
+	struct msm_isp_color_fmt *usr_fmts;
+	int num_fmts;
+	/* preview or snapshot */
+	u32 mode;
+	u32 memsize;
+
+	int op_mode;
+	int vnode_id;
+	struct msm_cam_v4l2_dev_inst *dev_inst[MSM_DEV_INST_MAX];
+	struct msm_cam_v4l2_dev_inst *dev_inst_map[MSM_MAX_IMG_MODE];
+	/* native config device */
+	struct cdev cdev;
+
+	/* most-frequently accessed manager object*/
+	struct msm_sync *sync;
+
+	/* The message queue is used by the control thread to send commands
+	 * to the config thread, and also by the HW to send messages to the
+	 * config thread.  Thus it is the only queue that is accessed from
+	 * both interrupt and process context.
+	 */
+	/* struct msm_device_queue event_q; */
+
+	/* This queue used by the config thread to send responses back to the
+	 * control thread.  It is accessed only from a process context.
+	 * TO BE REMOVED
+	 */
+	struct msm_device_queue ctrl_q;
+
+	struct mutex lock;
+	uint8_t ctrl_data[max_control_command_size];
+	struct msm_ctrl_cmd ctrl;
+};
+static inline struct msm_cam_v4l2_device *to_pcam(
+	struct v4l2_device *v4l2_dev)
+{
+	return container_of(v4l2_dev, struct msm_cam_v4l2_device, v4l2_dev);
+}
+
+/*pseudo v4l2 device and v4l2 event queue
+  for server and config cdevs*/
+struct v4l2_queue_util {
+	struct video_device *pvdev;
+	struct v4l2_fh  eventHandle;
+};
+
+/* abstract config device for all sensor successfully probed*/
+struct msm_cam_config_dev {
+	struct cdev config_cdev;
+	struct v4l2_queue_util config_stat_event_queue;
+	int use_count;
+	/*struct msm_isp_ops* isp_subdev;*/
+	struct msm_cam_media_controller *p_mctl;
+};
+
+/* abstract camera server device for all sensor successfully probed*/
+struct msm_cam_server_dev {
+
+	/* config node device*/
+	struct cdev server_cdev;
+	/* info of sensors successfully probed*/
+	struct msm_camera_info camera_info;
+	/* info of configs successfully created*/
+	struct msm_cam_config_dev_info config_info;
+	/* active working camera device - only one allowed at this time*/
+	struct msm_cam_v4l2_device *pcam_active;
+	/* number of camera devices opened*/
+	atomic_t number_pcam_active;
+	struct v4l2_queue_util server_command_queue;
+	/* This queue used by the config thread to send responses back to the
+	 * control thread.  It is accessed only from a process context.
+	 */
+	struct msm_device_queue ctrl_q;
+	uint8_t ctrl_data[max_control_command_size];
+	struct msm_ctrl_cmd ctrl;
+	int use_count;
+    /* all the registered ISP subdevice*/
+	struct msm_isp_ops *isp_subdev[MSM_MAX_CAMERA_CONFIGS];
+	struct msm_ispif_fns ispif_fns;
+
+};
+
+/* camera server related functions */
+
+
+/* ISP related functions */
+void msm_isp_vfe_dev_init(struct v4l2_subdev *vd);
+/*
+int msm_isp_register(struct msm_cam_v4l2_device *pcam);
+*/
+int msm_isp_register(struct msm_cam_server_dev *psvr);
+void msm_isp_unregister(struct msm_cam_server_dev *psvr);
+int msm_ispif_register(struct msm_ispif_fns *ispif);
+int msm_sensor_register(struct platform_device *pdev,
+	int (*sensor_probe)(const struct msm_camera_sensor_info *,
+	struct v4l2_subdev *, struct msm_sensor_ctrl *));
+int msm_isp_init_module(int g_num_config_nodes);
+
+int msm_mctl_init_module(struct msm_cam_v4l2_device *pcam);
+int msm_mctl_init_user_formats(struct msm_cam_v4l2_device *pcam);
+int msm_mctl_buf_done(struct msm_cam_media_controller *pmctl,
+			int msg_type, uint32_t y_phy);
+/*Memory(PMEM) functions*/
+int msm_register_pmem(struct hlist_head *ptype, void __user *arg);
+int msm_pmem_table_del(struct hlist_head *ptype, void __user *arg);
+uint8_t msm_pmem_region_lookup(struct hlist_head *ptype,
+	int pmem_type, struct msm_pmem_region *reg, uint8_t maxcount);
+uint8_t msm_pmem_region_lookup_2(struct hlist_head *ptype,
+					int pmem_type,
+					struct msm_pmem_region *reg,
+					uint8_t maxcount);
+uint8_t msm_pmem_region_lookup_3(struct msm_cam_v4l2_device *pcam, int idx,
+						struct msm_pmem_region *reg,
+						int mem_type);
+unsigned long msm_pmem_stats_vtop_lookup(
+				struct msm_sync *sync,
+				unsigned long buffer,
+				int fd);
+unsigned long msm_pmem_stats_ptov_lookup(struct msm_sync *sync,
+						unsigned long addr, int *fd);
+
+int msm_vfe_subdev_init(struct v4l2_subdev *sd, void *data,
+					struct platform_device *pdev);
+void msm_vfe_subdev_release(struct platform_device *pdev);
+
+int msm_isp_subdev_ioctl(struct v4l2_subdev *sd,
+	struct msm_vfe_cfg_cmd *cfgcmd, void *data);
+#endif /* __KERNEL__ */
+
+#endif /* _MSM_H */
diff --git a/drivers/media/video/msm/msm_axi_qos.c b/drivers/media/video/msm/msm_axi_qos.c
new file mode 100644
index 0000000..3969547
--- /dev/null
+++ b/drivers/media/video/msm/msm_axi_qos.c
@@ -0,0 +1,47 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/clk.h>
+#include <mach/camera.h>
+#define MSM_AXI_QOS_NAME "msm_camera"
+
+static struct clk *ebi1_clk;
+
+int add_axi_qos(void)
+{
+	ebi1_clk = clk_get(NULL, "ebi1_vfe_clk");
+	if (IS_ERR(ebi1_clk))
+		ebi1_clk = NULL;
+	else
+		clk_enable(ebi1_clk);
+
+	return 0;
+}
+
+int update_axi_qos(uint32_t rate)
+{
+	if (!ebi1_clk)
+		return 0;
+
+	return clk_set_rate(ebi1_clk, rate * 1000);
+}
+
+void release_axi_qos(void)
+{
+	if (!ebi1_clk)
+		return;
+
+	clk_disable(ebi1_clk);
+	clk_put(ebi1_clk);
+	ebi1_clk = NULL;
+}
diff --git a/drivers/media/video/msm/msm_camera.c b/drivers/media/video/msm/msm_camera.c
new file mode 100644
index 0000000..3fddb8e
--- /dev/null
+++ b/drivers/media/video/msm/msm_camera.c
@@ -0,0 +1,4049 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+//FIXME: most allocations need not be GFP_ATOMIC
+/* FIXME: management of mutexes */
+/* FIXME: msm_pmem_region_lookup return values */
+/* FIXME: way too many copy to/from user */
+/* FIXME: does region->active mean free */
+/* FIXME: check limits on command lenghts passed from userspace */
+/* FIXME: __msm_release: which queues should we flush when opencnt != 0 */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <mach/board.h>
+
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/android_pmem.h>
+#include <linux/poll.h>
+#include <media/msm_camera.h>
+#include <mach/camera.h>
+#include <linux/syscalls.h>
+#include <linux/hrtimer.h>
+DEFINE_MUTEX(ctrl_cmd_lock);
+
+#define CAMERA_STOP_VIDEO 58
+spinlock_t pp_prev_spinlock;
+spinlock_t pp_stereocam_spinlock;
+spinlock_t st_frame_spinlock;
+
+#define ERR_USER_COPY(to) pr_err("%s(%d): copy %s user\n", \
+				__func__, __LINE__, ((to) ? "to" : "from"))
+#define ERR_COPY_FROM_USER() ERR_USER_COPY(0)
+#define ERR_COPY_TO_USER() ERR_USER_COPY(1)
+#define MAX_PMEM_CFG_BUFFERS 10
+
+static struct class *msm_class;
+static dev_t msm_devno;
+static LIST_HEAD(msm_sensors);
+struct  msm_control_device *g_v4l2_control_device;
+int g_v4l2_opencnt;
+static int camera_node;
+static enum msm_camera_type camera_type[MSM_MAX_CAMERA_SENSORS];
+static uint32_t sensor_mount_angle[MSM_MAX_CAMERA_SENSORS];
+
+static const char *vfe_config_cmd[] = {
+	"CMD_GENERAL",  /* 0 */
+	"CMD_AXI_CFG_OUT1",
+	"CMD_AXI_CFG_SNAP_O1_AND_O2",
+	"CMD_AXI_CFG_OUT2",
+	"CMD_PICT_T_AXI_CFG",
+	"CMD_PICT_M_AXI_CFG",  /* 5 */
+	"CMD_RAW_PICT_AXI_CFG",
+	"CMD_FRAME_BUF_RELEASE",
+	"CMD_PREV_BUF_CFG",
+	"CMD_SNAP_BUF_RELEASE",
+	"CMD_SNAP_BUF_CFG",  /* 10 */
+	"CMD_STATS_DISABLE",
+	"CMD_STATS_AEC_AWB_ENABLE",
+	"CMD_STATS_AF_ENABLE",
+	"CMD_STATS_AEC_ENABLE",
+	"CMD_STATS_AWB_ENABLE",  /* 15 */
+	"CMD_STATS_ENABLE",
+	"CMD_STATS_AXI_CFG",
+	"CMD_STATS_AEC_AXI_CFG",
+	"CMD_STATS_AF_AXI_CFG",
+	"CMD_STATS_AWB_AXI_CFG",  /* 20 */
+	"CMD_STATS_RS_AXI_CFG",
+	"CMD_STATS_CS_AXI_CFG",
+	"CMD_STATS_IHIST_AXI_CFG",
+	"CMD_STATS_SKIN_AXI_CFG",
+	"CMD_STATS_BUF_RELEASE",  /* 25 */
+	"CMD_STATS_AEC_BUF_RELEASE",
+	"CMD_STATS_AF_BUF_RELEASE",
+	"CMD_STATS_AWB_BUF_RELEASE",
+	"CMD_STATS_RS_BUF_RELEASE",
+	"CMD_STATS_CS_BUF_RELEASE",  /* 30 */
+	"CMD_STATS_IHIST_BUF_RELEASE",
+	"CMD_STATS_SKIN_BUF_RELEASE",
+	"UPDATE_STATS_INVALID",
+	"CMD_AXI_CFG_SNAP_GEMINI",
+	"CMD_AXI_CFG_SNAP",  /* 35 */
+	"CMD_AXI_CFG_PREVIEW",
+	"CMD_AXI_CFG_VIDEO",
+	"CMD_STATS_IHIST_ENABLE",
+	"CMD_STATS_RS_ENABLE",
+	"CMD_STATS_CS_ENABLE",  /* 40 */
+	"CMD_VPE",
+	"CMD_AXI_CFG_VPE",
+	"CMD_AXI_CFG_SNAP_VPE",
+	"CMD_AXI_CFG_SNAP_THUMB_VPE",
+};
+#define __CONTAINS(r, v, l, field) ({				\
+	typeof(r) __r = r;					\
+	typeof(v) __v = v;					\
+	typeof(v) __e = __v + l;				\
+	int res = __v >= __r->field &&				\
+		__e <= __r->field + __r->len;			\
+	res;							\
+})
+
+#define CONTAINS(r1, r2, field) ({				\
+	typeof(r2) __r2 = r2;					\
+	__CONTAINS(r1, __r2->field, __r2->len, field);		\
+})
+
+#define IN_RANGE(r, v, field) ({				\
+	typeof(r) __r = r;					\
+	typeof(v) __vv = v;					\
+	int res = ((__vv >= __r->field) &&			\
+		(__vv < (__r->field + __r->len)));		\
+	res;							\
+})
+
+#define OVERLAPS(r1, r2, field) ({				\
+	typeof(r1) __r1 = r1;					\
+	typeof(r2) __r2 = r2;					\
+	typeof(__r2->field) __v = __r2->field;			\
+	typeof(__v) __e = __v + __r2->len - 1;			\
+	int res = (IN_RANGE(__r1, __v, field) ||		\
+		   IN_RANGE(__r1, __e, field));                 \
+	res;							\
+})
+
+static inline void free_qcmd(struct msm_queue_cmd *qcmd)
+{
+	if (!qcmd || !atomic_read(&qcmd->on_heap))
+		return;
+	if (!atomic_sub_return(1, &qcmd->on_heap))
+		kfree(qcmd);
+}
+
+static void msm_region_init(struct msm_sync *sync)
+{
+	INIT_HLIST_HEAD(&sync->pmem_frames);
+	INIT_HLIST_HEAD(&sync->pmem_stats);
+	spin_lock_init(&sync->pmem_frame_spinlock);
+	spin_lock_init(&sync->pmem_stats_spinlock);
+}
+
+static void msm_queue_init(struct msm_device_queue *queue, const char *name)
+{
+	spin_lock_init(&queue->lock);
+	queue->len = 0;
+	queue->max = 0;
+	queue->name = name;
+	INIT_LIST_HEAD(&queue->list);
+	init_waitqueue_head(&queue->wait);
+}
+
+static void msm_enqueue(struct msm_device_queue *queue,
+		struct list_head *entry)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&queue->lock, flags);
+	queue->len++;
+	if (queue->len > queue->max) {
+		queue->max = queue->len;
+		CDBG("%s: queue %s new max is %d\n", __func__,
+			queue->name, queue->max);
+	}
+	list_add_tail(entry, &queue->list);
+	wake_up(&queue->wait);
+	CDBG("%s: woke up %s\n", __func__, queue->name);
+	spin_unlock_irqrestore(&queue->lock, flags);
+}
+
+static void msm_enqueue_vpe(struct msm_device_queue *queue,
+		struct list_head *entry)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&queue->lock, flags);
+	queue->len++;
+	if (queue->len > queue->max) {
+		queue->max = queue->len;
+		CDBG("%s: queue %s new max is %d\n", __func__,
+			queue->name, queue->max);
+	}
+	list_add_tail(entry, &queue->list);
+    CDBG("%s: woke up %s\n", __func__, queue->name);
+	spin_unlock_irqrestore(&queue->lock, flags);
+}
+
+#define msm_dequeue(queue, member) ({				\
+	unsigned long flags;					\
+	struct msm_device_queue *__q = (queue);			\
+	struct msm_queue_cmd *qcmd = 0;				\
+	spin_lock_irqsave(&__q->lock, flags);			\
+	if (!list_empty(&__q->list)) {				\
+		__q->len--;					\
+		qcmd = list_first_entry(&__q->list,		\
+				struct msm_queue_cmd, member);	\
+		if ((qcmd) && (&qcmd->member) && (&qcmd->member.next))	\
+			list_del_init(&qcmd->member);			\
+	}							\
+	spin_unlock_irqrestore(&__q->lock, flags);	\
+	qcmd;							\
+})
+
+#define msm_delete_entry(queue, member, q_cmd) ({		\
+	unsigned long flags;					\
+	struct msm_device_queue *__q = (queue);			\
+	struct msm_queue_cmd *qcmd = 0;				\
+	spin_lock_irqsave(&__q->lock, flags);			\
+	if (!list_empty(&__q->list)) {				\
+		list_for_each_entry(qcmd, &__q->list, member)	\
+		if (qcmd == q_cmd) {				\
+			__q->len--;				\
+			list_del_init(&qcmd->member);		\
+			CDBG("msm_delete_entry, match found\n");\
+			kfree(q_cmd);				\
+			q_cmd = NULL;				\
+			break;					\
+		}						\
+	}							\
+	spin_unlock_irqrestore(&__q->lock, flags);		\
+	q_cmd;		\
+})
+
+#define msm_queue_drain(queue, member) do {			\
+	unsigned long flags;					\
+	struct msm_device_queue *__q = (queue);			\
+	struct msm_queue_cmd *qcmd;				\
+	spin_lock_irqsave(&__q->lock, flags);			\
+	while (!list_empty(&__q->list)) {			\
+		__q->len--;					\
+		qcmd = list_first_entry(&__q->list,		\
+			struct msm_queue_cmd, member);		\
+		if (qcmd) {					\
+			if ((&qcmd->member) && (&qcmd->member.next))	\
+				list_del_init(&qcmd->member);		\
+			free_qcmd(qcmd);				\
+		}							\
+	}							\
+	spin_unlock_irqrestore(&__q->lock, flags);		\
+} while (0)
+
+static int check_overlap(struct hlist_head *ptype,
+			unsigned long paddr,
+			unsigned long len)
+{
+	struct msm_pmem_region *region;
+	struct msm_pmem_region t = { .paddr = paddr, .len = len };
+	struct hlist_node *node;
+
+	hlist_for_each_entry(region, node, ptype, list) {
+		if (CONTAINS(region, &t, paddr) ||
+				CONTAINS(&t, region, paddr) ||
+				OVERLAPS(region, &t, paddr)) {
+			CDBG(" region (PHYS %p len %ld)"
+				" clashes with registered region"
+				" (paddr %p len %ld)\n",
+				(void *)t.paddr, t.len,
+				(void *)region->paddr, region->len);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int check_pmem_info(struct msm_pmem_info *info, int len)
+{
+	if (info->offset < len &&
+	    info->offset + info->len <= len &&
+	    info->y_off < len &&
+	    info->cbcr_off < len)
+		return 0;
+
+	pr_err("%s: check failed: off %d len %d y %d cbcr %d (total len %d)\n",
+		__func__,
+		info->offset,
+		info->len,
+		info->y_off,
+		info->cbcr_off,
+		len);
+	return -EINVAL;
+}
+static int msm_pmem_table_add(struct hlist_head *ptype,
+	struct msm_pmem_info *info, spinlock_t* pmem_spinlock,
+	struct msm_sync *sync)
+{
+	struct file *file;
+	unsigned long paddr;
+	unsigned long kvstart;
+	unsigned long len;
+	int rc;
+	struct msm_pmem_region *region;
+	unsigned long flags;
+
+
+	rc = get_pmem_file(info->fd, &paddr, &kvstart, &len, &file);
+	if (rc < 0) {
+		pr_err("%s: get_pmem_file fd %d error %d\n",
+			__func__,
+			info->fd, rc);
+		return rc;
+	}
+
+	if (!info->len)
+		info->len = len;
+
+	rc = check_pmem_info(info, len);
+	if (rc < 0)
+		return rc;
+
+	paddr += info->offset;
+	len = info->len;
+
+	spin_lock_irqsave(pmem_spinlock, flags);
+	if (check_overlap(ptype, paddr, len) < 0) {
+		spin_unlock_irqrestore(pmem_spinlock, flags);
+		return -EINVAL;
+	}
+	spin_unlock_irqrestore(pmem_spinlock, flags);
+
+
+	region = kmalloc(sizeof(struct msm_pmem_region), GFP_KERNEL);
+	if (!region)
+		return -ENOMEM;
+
+	spin_lock_irqsave(pmem_spinlock, flags);
+	INIT_HLIST_NODE(&region->list);
+
+	region->paddr = paddr;
+	region->len = len;
+	region->file = file;
+	memcpy(&region->info, info, sizeof(region->info));
+
+	hlist_add_head(&(region->list), ptype);
+	spin_unlock_irqrestore(pmem_spinlock, flags);
+	CDBG("%s: type %d, paddr 0x%lx, vaddr 0x%lx\n",
+		__func__, info->type, paddr, (unsigned long)info->vaddr);
+
+	return 0;
+}
+
+/* return of 0 means failure */
+static uint8_t msm_pmem_region_lookup(struct hlist_head *ptype,
+	int pmem_type, struct msm_pmem_region *reg, uint8_t maxcount,
+	spinlock_t *pmem_spinlock)
+{
+	struct msm_pmem_region *region;
+	struct msm_pmem_region *regptr;
+	struct hlist_node *node, *n;
+	unsigned long flags = 0;
+
+	uint8_t rc = 0;
+
+	regptr = reg;
+	spin_lock_irqsave(pmem_spinlock, flags);
+	hlist_for_each_entry_safe(region, node, n, ptype, list) {
+		if (region->info.type == pmem_type && region->info.active) {
+			*regptr = *region;
+			rc += 1;
+			if (rc >= maxcount)
+				break;
+			regptr++;
+		}
+	}
+	spin_unlock_irqrestore(pmem_spinlock, flags);
+	/* After lookup failure, dump all the list entries...*/
+	if (rc == 0) {
+		pr_err("%s: pmem_type = %d\n", __func__, pmem_type);
+		hlist_for_each_entry_safe(region, node, n, ptype, list) {
+			pr_err("listed region->info.type = %d, active = %d",
+				region->info.type, region->info.active);
+		}
+
+	}
+	return rc;
+}
+
+static uint8_t msm_pmem_region_lookup_2(struct hlist_head *ptype,
+					int pmem_type,
+					struct msm_pmem_region *reg,
+					uint8_t maxcount,
+					spinlock_t *pmem_spinlock)
+{
+	struct msm_pmem_region *region;
+	struct msm_pmem_region *regptr;
+	struct hlist_node *node, *n;
+	uint8_t rc = 0;
+	unsigned long flags = 0;
+	regptr = reg;
+	spin_lock_irqsave(pmem_spinlock, flags);
+	hlist_for_each_entry_safe(region, node, n, ptype, list) {
+		CDBG("%s:info.type=%d, pmem_type = %d,"
+						"info.active = %d\n",
+		__func__, region->info.type, pmem_type, region->info.active);
+
+		if (region->info.type == pmem_type && region->info.active) {
+			CDBG("%s:info.type=%d, pmem_type = %d,"
+							"info.active = %d,\n",
+				__func__, region->info.type, pmem_type,
+				region->info.active);
+			*regptr = *region;
+			region->info.type = MSM_PMEM_VIDEO;
+			rc += 1;
+			if (rc >= maxcount)
+				break;
+			regptr++;
+		}
+	}
+	spin_unlock_irqrestore(pmem_spinlock, flags);
+	return rc;
+}
+
+static int msm_pmem_frame_ptov_lookup(struct msm_sync *sync,
+		unsigned long pyaddr,
+		unsigned long pcbcraddr,
+		struct msm_pmem_info *pmem_info,
+		int clear_active)
+{
+	struct msm_pmem_region *region;
+	struct hlist_node *node, *n;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&sync->pmem_frame_spinlock, flags);
+	hlist_for_each_entry_safe(region, node, n, &sync->pmem_frames, list) {
+		if (pyaddr == (region->paddr + region->info.y_off) &&
+				pcbcraddr == (region->paddr +
+						region->info.cbcr_off) &&
+				region->info.active) {
+			/* offset since we could pass vaddr inside
+			 * a registerd pmem buffer
+			 */
+			memcpy(pmem_info, &region->info, sizeof(*pmem_info));
+			if (clear_active)
+				region->info.active = 0;
+			spin_unlock_irqrestore(&sync->pmem_frame_spinlock,
+				flags);
+			return 0;
+		}
+	}
+	/* After lookup failure, dump all the list entries... */
+	pr_err("%s, for pyaddr 0x%lx, pcbcraddr 0x%lx\n",
+			__func__, pyaddr, pcbcraddr);
+	hlist_for_each_entry_safe(region, node, n, &sync->pmem_frames, list) {
+		pr_err("listed pyaddr 0x%lx, pcbcraddr 0x%lx, active = %d",
+				(region->paddr + region->info.y_off),
+				(region->paddr + region->info.cbcr_off),
+				region->info.active);
+	}
+
+	spin_unlock_irqrestore(&sync->pmem_frame_spinlock, flags);
+	return -EINVAL;
+}
+
+static int msm_pmem_frame_ptov_lookup2(struct msm_sync *sync,
+		unsigned long pyaddr,
+		struct msm_pmem_info *pmem_info,
+		int clear_active)
+{
+	struct msm_pmem_region *region;
+	struct hlist_node *node, *n;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&sync->pmem_frame_spinlock, flags);
+	hlist_for_each_entry_safe(region, node, n, &sync->pmem_frames, list) {
+		if (pyaddr == (region->paddr + region->info.y_off) &&
+				region->info.active) {
+			/* offset since we could pass vaddr inside
+			 * a registerd pmem buffer
+			 */
+			memcpy(pmem_info, &region->info, sizeof(*pmem_info));
+			if (clear_active)
+				region->info.active = 0;
+			spin_unlock_irqrestore(&sync->pmem_frame_spinlock,
+				flags);
+			return 0;
+		}
+	}
+
+	spin_unlock_irqrestore(&sync->pmem_frame_spinlock, flags);
+	return -EINVAL;
+}
+
+static unsigned long msm_pmem_stats_ptov_lookup(struct msm_sync *sync,
+		unsigned long addr, int *fd)
+{
+	struct msm_pmem_region *region;
+	struct hlist_node *node, *n;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&sync->pmem_stats_spinlock, flags);
+	hlist_for_each_entry_safe(region, node, n, &sync->pmem_stats, list) {
+		if (addr == region->paddr && region->info.active) {
+			/* offset since we could pass vaddr inside a
+			 * registered pmem buffer */
+			*fd = region->info.fd;
+			region->info.active = 0;
+			spin_unlock_irqrestore(&sync->pmem_stats_spinlock,
+				flags);
+			return (unsigned long)(region->info.vaddr);
+		}
+	}
+	/* After lookup failure, dump all the list entries... */
+	pr_err("%s, lookup failure, for paddr 0x%lx\n",
+			__func__, addr);
+	hlist_for_each_entry_safe(region, node, n, &sync->pmem_stats, list) {
+		pr_err("listed paddr 0x%lx, active = %d",
+				region->paddr,
+				region->info.active);
+	}
+	spin_unlock_irqrestore(&sync->pmem_stats_spinlock, flags);
+
+	return 0;
+}
+
+static unsigned long msm_pmem_frame_vtop_lookup(struct msm_sync *sync,
+		unsigned long buffer,
+		uint32_t yoff, uint32_t cbcroff, int fd, int change_flag)
+{
+	struct msm_pmem_region *region;
+	struct hlist_node *node, *n;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&sync->pmem_frame_spinlock, flags);
+	hlist_for_each_entry_safe(region,
+		node, n, &sync->pmem_frames, list) {
+		if (((unsigned long)(region->info.vaddr) == buffer) &&
+				(region->info.y_off == yoff) &&
+				(region->info.cbcr_off == cbcroff) &&
+				(region->info.fd == fd) &&
+				(region->info.active == 0)) {
+			if (change_flag)
+				region->info.active = 1;
+			spin_unlock_irqrestore(&sync->pmem_frame_spinlock,
+				flags);
+			return region->paddr;
+		}
+	}
+	/* After lookup failure, dump all the list entries... */
+	pr_err("%s, failed for vaddr 0x%lx, yoff %d cbcroff %d\n",
+			__func__, buffer, yoff, cbcroff);
+	hlist_for_each_entry_safe(region, node, n, &sync->pmem_frames, list) {
+		pr_err("listed vaddr 0x%p, cbcroff %d, active = %d",
+				(region->info.vaddr),
+				(region->info.cbcr_off),
+				region->info.active);
+	}
+
+	spin_unlock_irqrestore(&sync->pmem_frame_spinlock, flags);
+
+	return 0;
+}
+
+static unsigned long msm_pmem_stats_vtop_lookup(
+		struct msm_sync *sync,
+		unsigned long buffer,
+		int fd)
+{
+	struct msm_pmem_region *region;
+	struct hlist_node *node, *n;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&sync->pmem_stats_spinlock, flags);
+	hlist_for_each_entry_safe(region, node, n, &sync->pmem_stats, list) {
+		if (((unsigned long)(region->info.vaddr) == buffer) &&
+				(region->info.fd == fd) &&
+				region->info.active == 0) {
+			region->info.active = 1;
+			spin_unlock_irqrestore(&sync->pmem_stats_spinlock,
+				flags);
+			return region->paddr;
+		}
+	}
+	/* After lookup failure, dump all the list entries... */
+	pr_err("%s,look up error for vaddr %ld\n",
+			__func__, buffer);
+	hlist_for_each_entry_safe(region, node, n, &sync->pmem_stats, list) {
+		pr_err("listed vaddr 0x%p, active = %d",
+				region->info.vaddr,
+				region->info.active);
+	}
+	spin_unlock_irqrestore(&sync->pmem_stats_spinlock, flags);
+
+	return 0;
+}
+
+static int __msm_pmem_table_del(struct msm_sync *sync,
+		struct msm_pmem_info *pinfo)
+{
+	int rc = 0;
+	struct msm_pmem_region *region;
+	struct hlist_node *node, *n;
+	unsigned long flags = 0;
+
+	switch (pinfo->type) {
+	case MSM_PMEM_PREVIEW:
+	case MSM_PMEM_THUMBNAIL:
+	case MSM_PMEM_MAINIMG:
+	case MSM_PMEM_RAW_MAINIMG:
+	case MSM_PMEM_C2D:
+	case MSM_PMEM_MAINIMG_VPE:
+	case MSM_PMEM_THUMBNAIL_VPE:
+		spin_lock_irqsave(&sync->pmem_frame_spinlock, flags);
+		hlist_for_each_entry_safe(region, node, n,
+			&sync->pmem_frames, list) {
+
+			if (pinfo->type == region->info.type &&
+					pinfo->vaddr == region->info.vaddr &&
+					pinfo->fd == region->info.fd) {
+				hlist_del(node);
+				put_pmem_file(region->file);
+				kfree(region);
+				CDBG("%s: type %d, vaddr  0x%p\n",
+					__func__, pinfo->type, pinfo->vaddr);
+			}
+		}
+		spin_unlock_irqrestore(&sync->pmem_frame_spinlock, flags);
+		break;
+
+	case MSM_PMEM_VIDEO:
+	case MSM_PMEM_VIDEO_VPE:
+		spin_lock_irqsave(&sync->pmem_frame_spinlock, flags);
+		hlist_for_each_entry_safe(region, node, n,
+			&sync->pmem_frames, list) {
+
+			if (((region->info.type == MSM_PMEM_VIDEO) ||
+				(region->info.type == MSM_PMEM_VIDEO_VPE)) &&
+				pinfo->vaddr == region->info.vaddr &&
+				pinfo->fd == region->info.fd) {
+				hlist_del(node);
+				put_pmem_file(region->file);
+				kfree(region);
+				CDBG("%s: type %d, vaddr  0x%p\n",
+					__func__, pinfo->type, pinfo->vaddr);
+			}
+		}
+		spin_unlock_irqrestore(&sync->pmem_frame_spinlock, flags);
+		break;
+
+	case MSM_PMEM_AEC_AWB:
+	case MSM_PMEM_AF:
+		spin_lock_irqsave(&sync->pmem_stats_spinlock, flags);
+		hlist_for_each_entry_safe(region, node, n,
+			&sync->pmem_stats, list) {
+
+			if (pinfo->type == region->info.type &&
+					pinfo->vaddr == region->info.vaddr &&
+					pinfo->fd == region->info.fd) {
+				hlist_del(node);
+				put_pmem_file(region->file);
+				kfree(region);
+				CDBG("%s: type %d, vaddr  0x%p\n",
+					__func__, pinfo->type, pinfo->vaddr);
+			}
+		}
+		spin_unlock_irqrestore(&sync->pmem_stats_spinlock, flags);
+		break;
+
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+static int msm_pmem_table_del(struct msm_sync *sync, void __user *arg)
+{
+	struct msm_pmem_info info;
+
+	if (copy_from_user(&info, arg, sizeof(info))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	return __msm_pmem_table_del(sync, &info);
+}
+
+static int __msm_get_frame(struct msm_sync *sync,
+		struct msm_frame *frame)
+{
+	int rc = 0;
+
+	struct msm_pmem_info pmem_info;
+	struct msm_queue_cmd *qcmd = NULL;
+	struct msm_vfe_resp *vdata;
+	struct msm_vfe_phy_info *pphy;
+
+	qcmd = msm_dequeue(&sync->frame_q, list_frame);
+
+	if (!qcmd) {
+		pr_err("%s: no preview frame.\n", __func__);
+		return -EAGAIN;
+	}
+
+	if ((!qcmd->command) && (qcmd->error_code & MSM_CAMERA_ERR_MASK)) {
+		frame->error_code = qcmd->error_code;
+		pr_err("%s: fake frame with camera error code = %d\n",
+			__func__, frame->error_code);
+		goto err;
+	}
+
+	vdata = (struct msm_vfe_resp *)(qcmd->command);
+	pphy = &vdata->phy;
+
+	rc = msm_pmem_frame_ptov_lookup(sync,
+			pphy->y_phy,
+			pphy->cbcr_phy,
+			&pmem_info,
+			1); /* Clear the active flag */
+
+	if (rc < 0) {
+		pr_err("%s: cannot get frame, invalid lookup address "
+			"y %x cbcr %x\n",
+			__func__,
+			pphy->y_phy,
+			pphy->cbcr_phy);
+		goto err;
+	}
+
+	frame->ts = qcmd->ts;
+	frame->buffer = (unsigned long)pmem_info.vaddr;
+	frame->y_off = pmem_info.y_off;
+	frame->cbcr_off = pmem_info.cbcr_off;
+	frame->fd = pmem_info.fd;
+	frame->path = vdata->phy.output_id;
+	frame->frame_id = vdata->phy.frame_id;
+
+	CDBG("%s: y %x, cbcr %x, qcmd %x, virt_addr %x\n",
+		__func__,
+		pphy->y_phy, pphy->cbcr_phy, (int) qcmd, (int) frame->buffer);
+
+err:
+	free_qcmd(qcmd);
+	return rc;
+}
+
+static int msm_get_frame(struct msm_sync *sync, void __user *arg)
+{
+	int rc = 0;
+	struct msm_frame frame;
+
+	if (copy_from_user(&frame,
+				arg,
+				sizeof(struct msm_frame))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	rc = __msm_get_frame(sync, &frame);
+	if (rc < 0)
+		return rc;
+
+	mutex_lock(&sync->lock);
+	if (sync->croplen && (!sync->stereocam_enabled)) {
+		if (frame.croplen != sync->croplen) {
+			pr_err("%s: invalid frame croplen %d,"
+				"expecting %d\n",
+				__func__,
+				frame.croplen,
+				sync->croplen);
+			mutex_unlock(&sync->lock);
+			return -EINVAL;
+		}
+
+		if (copy_to_user((void *)frame.cropinfo,
+				sync->cropinfo,
+				sync->croplen)) {
+			ERR_COPY_TO_USER();
+			mutex_unlock(&sync->lock);
+			return -EFAULT;
+		}
+	}
+
+	if (sync->fdroiinfo.info) {
+		if (copy_to_user((void *)frame.roi_info.info,
+			sync->fdroiinfo.info,
+			sync->fdroiinfo.info_len)) {
+			ERR_COPY_TO_USER();
+			mutex_unlock(&sync->lock);
+			return -EFAULT;
+		}
+	}
+
+	if (sync->stereocam_enabled) {
+		frame.stcam_conv_value = sync->stcam_conv_value;
+		frame.stcam_quality_ind = sync->stcam_quality_ind;
+	}
+
+	if (copy_to_user((void *)arg,
+				&frame, sizeof(struct msm_frame))) {
+		ERR_COPY_TO_USER();
+		rc = -EFAULT;
+	}
+
+	mutex_unlock(&sync->lock);
+	CDBG("%s: got frame\n", __func__);
+
+	return rc;
+}
+
+static int msm_enable_vfe(struct msm_sync *sync, void __user *arg)
+{
+	int rc = -EIO;
+	struct camera_enable_cmd cfg;
+
+	if (copy_from_user(&cfg,
+			arg,
+			sizeof(struct camera_enable_cmd))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	if (sync->vfefn.vfe_enable)
+		rc = sync->vfefn.vfe_enable(&cfg);
+
+	return rc;
+}
+
+static int msm_disable_vfe(struct msm_sync *sync, void __user *arg)
+{
+	int rc = -EIO;
+	struct camera_enable_cmd cfg;
+
+	if (copy_from_user(&cfg,
+			arg,
+			sizeof(struct camera_enable_cmd))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	if (sync->vfefn.vfe_disable)
+		rc = sync->vfefn.vfe_disable(&cfg, NULL);
+
+	return rc;
+}
+
+static struct msm_queue_cmd *__msm_control(struct msm_sync *sync,
+		struct msm_device_queue *queue,
+		struct msm_queue_cmd *qcmd,
+		int timeout)
+{
+	int rc;
+
+	CDBG("Inside __msm_control\n");
+	if (sync->event_q.len <= 100 && sync->frame_q.len <= 100) {
+		/* wake up config thread */
+		msm_enqueue(&sync->event_q, &qcmd->list_config);
+	} else {
+		pr_err("%s, Error Queue limit exceeded e_q = %d, f_q = %d\n",
+			__func__, sync->event_q.len, sync->frame_q.len);
+		free_qcmd(qcmd);
+		return NULL;
+	}
+	if (!queue)
+		return NULL;
+
+	/* wait for config status */
+	CDBG("Waiting for config status \n");
+	rc = wait_event_interruptible_timeout(
+			queue->wait,
+			!list_empty_careful(&queue->list),
+			timeout);
+	CDBG("Waiting over for config status\n");
+	if (list_empty_careful(&queue->list)) {
+		if (!rc) {
+			rc = -ETIMEDOUT;
+			pr_err("%s: wait_event error %d\n", __func__, rc);
+			return ERR_PTR(rc);
+		} else if (rc < 0) {
+			pr_err("%s: wait_event error %d\n", __func__, rc);
+			if (msm_delete_entry(&sync->event_q,
+				list_config, qcmd)) {
+				sync->ignore_qcmd = true;
+				sync->ignore_qcmd_type =
+					(int16_t)((struct msm_ctrl_cmd *)
+					(qcmd->command))->type;
+			}
+			return ERR_PTR(rc);
+		}
+	}
+	qcmd = msm_dequeue(queue, list_control);
+	BUG_ON(!qcmd);
+	CDBG("__msm_control done \n");
+	return qcmd;
+}
+
+static struct msm_queue_cmd *__msm_control_nb(struct msm_sync *sync,
+					struct msm_queue_cmd *qcmd_to_copy)
+{
+	/* Since this is a non-blocking command, we cannot use qcmd_to_copy and
+	 * its data, since they are on the stack.  We replicate them on the heap
+	 * and mark them on_heap so that they get freed when the config thread
+	 * dequeues them.
+	 */
+
+	struct msm_ctrl_cmd *udata;
+	struct msm_ctrl_cmd *udata_to_copy = qcmd_to_copy->command;
+
+	struct msm_queue_cmd *qcmd =
+			kmalloc(sizeof(*qcmd_to_copy) +
+				sizeof(*udata_to_copy) +
+				udata_to_copy->length,
+				GFP_KERNEL);
+	if (!qcmd) {
+		pr_err("%s: out of memory\n", __func__);
+		return ERR_PTR(-ENOMEM);
+	}
+	*qcmd = *qcmd_to_copy;
+	udata = qcmd->command = qcmd + 1;
+	memcpy(udata, udata_to_copy, sizeof(*udata));
+	udata->value = udata + 1;
+	memcpy(udata->value, udata_to_copy->value, udata_to_copy->length);
+
+	atomic_set(&qcmd->on_heap, 1);
+
+	/* qcmd_resp will be set to NULL */
+	return __msm_control(sync, NULL, qcmd, 0);
+}
+
+static int msm_control(struct msm_control_device *ctrl_pmsm,
+			int block,
+			void __user *arg)
+{
+	int rc = 0;
+
+	struct msm_sync *sync = ctrl_pmsm->pmsm->sync;
+	void __user *uptr;
+	struct msm_ctrl_cmd udata_resp;
+	struct msm_queue_cmd *qcmd_resp = NULL;
+	uint8_t data[max_control_command_size];
+	struct msm_ctrl_cmd *udata;
+	struct msm_queue_cmd *qcmd =
+		kmalloc(sizeof(struct msm_queue_cmd) +
+			sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
+	if (!qcmd) {
+		pr_err("%s: out of memory\n", __func__);
+		return -ENOMEM;
+	}
+	udata = (struct msm_ctrl_cmd *)(qcmd + 1);
+	atomic_set(&(qcmd->on_heap), 1);
+	CDBG("Inside msm_control\n");
+	if (copy_from_user(udata, arg, sizeof(struct msm_ctrl_cmd))) {
+		ERR_COPY_FROM_USER();
+		rc = -EFAULT;
+		goto end;
+	}
+
+	uptr = udata->value;
+	udata->value = data;
+	qcmd->type = MSM_CAM_Q_CTRL;
+	qcmd->command = udata;
+
+	if (udata->length) {
+		if (udata->length > sizeof(data)) {
+			pr_err("%s: user data too large (%d, max is %d)\n",
+					__func__,
+					udata->length,
+					sizeof(data));
+			rc = -EIO;
+			goto end;
+		}
+		if (copy_from_user(udata->value, uptr, udata->length)) {
+			ERR_COPY_FROM_USER();
+			rc = -EFAULT;
+			goto end;
+		}
+	}
+
+	if (unlikely(!block)) {
+		qcmd_resp = __msm_control_nb(sync, qcmd);
+		goto end;
+	}
+
+	qcmd_resp = __msm_control(sync,
+				  &ctrl_pmsm->ctrl_q,
+				  qcmd, msecs_to_jiffies(10000));
+
+	/* ownership of qcmd will be transfered to event queue */
+	qcmd = NULL;
+
+	if (!qcmd_resp || IS_ERR(qcmd_resp)) {
+		/* Do not free qcmd_resp here.  If the config thread read it,
+		 * then it has already been freed, and we timed out because
+		 * we did not receive a MSM_CAM_IOCTL_CTRL_CMD_DONE.  If the
+		 * config thread itself is blocked and not dequeueing commands,
+		 * then it will either eventually unblock and process them,
+		 * or when it is killed, qcmd will be freed in
+		 * msm_release_config.
+		 */
+		rc = PTR_ERR(qcmd_resp);
+		qcmd_resp = NULL;
+		goto end;
+	}
+
+	if (qcmd_resp->command) {
+		udata_resp = *(struct msm_ctrl_cmd *)qcmd_resp->command;
+		if (udata_resp.length > 0) {
+			if (copy_to_user(uptr,
+					 udata_resp.value,
+					 udata_resp.length)) {
+				ERR_COPY_TO_USER();
+				rc = -EFAULT;
+				goto end;
+			}
+		}
+		udata_resp.value = uptr;
+
+		if (copy_to_user((void *)arg, &udata_resp,
+				sizeof(struct msm_ctrl_cmd))) {
+			ERR_COPY_TO_USER();
+			rc = -EFAULT;
+			goto end;
+		}
+	}
+
+end:
+	free_qcmd(qcmd);
+	CDBG("%s: done rc = %d\n", __func__, rc);
+	return rc;
+}
+
+/* Divert frames for post-processing by delivering them to the config thread;
+ * when post-processing is done, it will return the frame to the frame thread.
+ */
+static int msm_divert_frame(struct msm_sync *sync,
+		struct msm_vfe_resp *data,
+		struct msm_stats_event_ctrl *se)
+{
+	struct msm_pmem_info pinfo;
+	struct msm_postproc buf;
+	int rc;
+
+	CDBG("%s: Frame PP sync->pp_mask %d\n", __func__, sync->pp_mask);
+
+	if (!(sync->pp_mask & PP_PREV)  && !(sync->pp_mask & PP_SNAP)) {
+		pr_err("%s: diverting frame, not in PP_PREV or PP_SNAP!\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	rc = msm_pmem_frame_ptov_lookup(sync, data->phy.y_phy,
+			data->phy.cbcr_phy, &pinfo,
+			0); /* do not clear the active flag */
+
+	if (rc < 0) {
+		pr_err("%s: msm_pmem_frame_ptov_lookup failed\n", __func__);
+		return rc;
+	}
+
+	buf.fmain.buffer = (unsigned long)pinfo.vaddr;
+	buf.fmain.y_off = pinfo.y_off;
+	buf.fmain.cbcr_off = pinfo.cbcr_off;
+	buf.fmain.fd = pinfo.fd;
+
+	CDBG("%s: buf 0x%x fd %d\n", __func__, (unsigned int)buf.fmain.buffer,
+		 buf.fmain.fd);
+	if (copy_to_user((void *)(se->stats_event.data),
+			&(buf.fmain), sizeof(struct msm_frame))) {
+		ERR_COPY_TO_USER();
+		return -EFAULT;
+	}
+	return 0;
+}
+
+/* Divert stereo frames for post-processing by delivering
+ * them to the config thread.
+ */
+static int msm_divert_st_frame(struct msm_sync *sync,
+	struct msm_vfe_resp *data, struct msm_stats_event_ctrl *se, int path)
+{
+	struct msm_pmem_info pinfo;
+	struct msm_st_frame buf;
+	struct video_crop_t *crop = NULL;
+	int rc = 0;
+
+	if (se->stats_event.msg_id == OUTPUT_TYPE_ST_L) {
+		buf.type = OUTPUT_TYPE_ST_L;
+	} else if (se->stats_event.msg_id == OUTPUT_TYPE_ST_R) {
+		buf.type = OUTPUT_TYPE_ST_R;
+	} else {
+		if (se->resptype == MSM_CAM_RESP_STEREO_OP_1) {
+			rc = msm_pmem_frame_ptov_lookup(sync, data->phy.y_phy,
+					data->phy.cbcr_phy, &pinfo,
+					1);  /* do clear the active flag */
+			buf.buf_info.path = path;
+		} else if (se->resptype == MSM_CAM_RESP_STEREO_OP_2) {
+			rc = msm_pmem_frame_ptov_lookup(sync, data->phy.y_phy,
+					data->phy.cbcr_phy, &pinfo,
+					0); /* do not clear the active flag */
+			buf.buf_info.path = path;
+		} else
+			CDBG("%s: Invalid resptype = %d\n", __func__,
+				se->resptype);
+
+		if (rc < 0) {
+			CDBG("%s: msm_pmem_frame_ptov_lookup failed\n",
+				__func__);
+			return rc;
+		}
+
+		buf.type = OUTPUT_TYPE_ST_D;
+
+		if (sync->cropinfo != NULL) {
+			crop = sync->cropinfo;
+			switch (path) {
+			case OUTPUT_TYPE_P:
+			case OUTPUT_TYPE_T: {
+				buf.L.stCropInfo.in_w = crop->in1_w;
+				buf.L.stCropInfo.in_h = crop->in1_h;
+				buf.L.stCropInfo.out_w = crop->out1_w;
+				buf.L.stCropInfo.out_h = crop->out1_h;
+				buf.R.stCropInfo = buf.L.stCropInfo;
+				break;
+			}
+
+			case OUTPUT_TYPE_V:
+			case OUTPUT_TYPE_S: {
+				buf.L.stCropInfo.in_w = crop->in2_w;
+				buf.L.stCropInfo.in_h = crop->in2_h;
+				buf.L.stCropInfo.out_w = crop->out2_w;
+				buf.L.stCropInfo.out_h = crop->out2_h;
+				buf.R.stCropInfo = buf.L.stCropInfo;
+				break;
+			}
+			default: {
+				pr_warning("%s: invalid frame path %d\n",
+					__func__, path);
+				break;
+			}
+			}
+		} else {
+			buf.L.stCropInfo.in_w = 0;
+			buf.L.stCropInfo.in_h = 0;
+			buf.L.stCropInfo.out_w = 0;
+			buf.L.stCropInfo.out_h = 0;
+			buf.R.stCropInfo = buf.L.stCropInfo;
+		}
+
+		/* hardcode for now. */
+		if ((path == OUTPUT_TYPE_S) || (path == OUTPUT_TYPE_T))
+			buf.packing = sync->sctrl.s_snap_packing;
+		else
+			buf.packing = sync->sctrl.s_video_packing;
+
+		buf.buf_info.buffer = (unsigned long)pinfo.vaddr;
+		buf.buf_info.phy_offset = pinfo.offset;
+		buf.buf_info.y_off = pinfo.y_off;
+		buf.buf_info.cbcr_off = pinfo.cbcr_off;
+		buf.buf_info.fd = pinfo.fd;
+
+		CDBG("%s: buf 0x%x fd %d\n", __func__,
+			(unsigned int)buf.buf_info.buffer, buf.buf_info.fd);
+	}
+
+	if (copy_to_user((void *)(se->stats_event.data),
+			&buf, sizeof(struct msm_st_frame))) {
+		ERR_COPY_TO_USER();
+		return -EFAULT;
+	}
+	return 0;
+}
+
+static int msm_get_stats(struct msm_sync *sync, void __user *arg)
+{
+	int rc = 0;
+
+	struct msm_stats_event_ctrl se;
+
+	struct msm_queue_cmd *qcmd = NULL;
+	struct msm_ctrl_cmd  *ctrl = NULL;
+	struct msm_vfe_resp  *data = NULL;
+	struct msm_vpe_resp  *vpe_data = NULL;
+	struct msm_stats_buf stats;
+
+	if (copy_from_user(&se, arg,
+			sizeof(struct msm_stats_event_ctrl))) {
+		ERR_COPY_FROM_USER();
+		pr_err("%s, ERR_COPY_FROM_USER\n", __func__);
+		return -EFAULT;
+	}
+
+	rc = 0;
+
+	qcmd = msm_dequeue(&sync->event_q, list_config);
+	if (!qcmd) {
+		/* Should be associated with wait_event
+			error -512 from __msm_control*/
+		pr_err("%s, qcmd is Null\n", __func__);
+		rc = -ETIMEDOUT;
+		return rc;
+	}
+
+	CDBG("%s: received from DSP %d\n", __func__, qcmd->type);
+
+	switch (qcmd->type) {
+	case MSM_CAM_Q_VPE_MSG:
+		/* Complete VPE response. */
+		vpe_data = (struct msm_vpe_resp *)(qcmd->command);
+		se.resptype = MSM_CAM_RESP_STEREO_OP_2;
+		se.stats_event.type   = vpe_data->evt_msg.type;
+		se.stats_event.msg_id = vpe_data->evt_msg.msg_id;
+		se.stats_event.len    = vpe_data->evt_msg.len;
+
+		if (vpe_data->type == VPE_MSG_OUTPUT_ST_L) {
+			CDBG("%s: Change msg_id to OUTPUT_TYPE_ST_L\n",
+				__func__);
+			se.stats_event.msg_id = OUTPUT_TYPE_ST_L;
+			rc = msm_divert_st_frame(sync, data, &se,
+				OUTPUT_TYPE_V);
+		} else if (vpe_data->type == VPE_MSG_OUTPUT_ST_R) {
+			CDBG("%s: Change msg_id to OUTPUT_TYPE_ST_R\n",
+				__func__);
+			se.stats_event.msg_id = OUTPUT_TYPE_ST_R;
+			rc = msm_divert_st_frame(sync, data, &se,
+				OUTPUT_TYPE_V);
+		} else {
+			pr_warning("%s: invalid vpe_data->type = %d\n",
+				__func__, vpe_data->type);
+		}
+		break;
+
+	case MSM_CAM_Q_VFE_EVT:
+	case MSM_CAM_Q_VFE_MSG:
+		data = (struct msm_vfe_resp *)(qcmd->command);
+
+		/* adsp event and message */
+		se.resptype = MSM_CAM_RESP_STAT_EVT_MSG;
+
+		/* 0 - msg from aDSP, 1 - event from mARM */
+		se.stats_event.type   = data->evt_msg.type;
+		se.stats_event.msg_id = data->evt_msg.msg_id;
+		se.stats_event.len    = data->evt_msg.len;
+		se.stats_event.frame_id = data->evt_msg.frame_id;
+
+		CDBG("%s: qcmd->type %d length %d msd_id %d\n", __func__,
+			qcmd->type,
+			se.stats_event.len,
+			se.stats_event.msg_id);
+
+		if (data->type == VFE_MSG_COMMON) {
+			stats.status_bits = data->stats_msg.status_bits;
+			if (data->stats_msg.aec_buff) {
+				stats.aec.buff =
+				msm_pmem_stats_ptov_lookup(sync,
+						data->stats_msg.aec_buff,
+						&(stats.aec.fd));
+				if (!stats.aec.buff) {
+					pr_err("%s: msm_pmem_stats_ptov_lookup error\n",
+						__func__);
+					rc = -EINVAL;
+					goto failure;
+				}
+
+			} else {
+				stats.aec.buff = 0;
+			}
+			if (data->stats_msg.awb_buff) {
+				stats.awb.buff =
+				msm_pmem_stats_ptov_lookup(sync,
+						data->stats_msg.awb_buff,
+						&(stats.awb.fd));
+				if (!stats.awb.buff) {
+					pr_err("%s: msm_pmem_stats_ptov_lookup error\n",
+						__func__);
+					rc = -EINVAL;
+					goto failure;
+				}
+
+			} else {
+				stats.awb.buff = 0;
+			}
+			if (data->stats_msg.af_buff) {
+				stats.af.buff =
+				msm_pmem_stats_ptov_lookup(sync,
+						data->stats_msg.af_buff,
+						&(stats.af.fd));
+				if (!stats.af.buff) {
+					pr_err("%s: msm_pmem_stats_ptov_lookup error\n",
+						__func__);
+					rc = -EINVAL;
+					goto failure;
+				}
+
+			} else {
+				stats.af.buff = 0;
+			}
+			if (data->stats_msg.ihist_buff) {
+				stats.ihist.buff =
+				msm_pmem_stats_ptov_lookup(sync,
+						data->stats_msg.ihist_buff,
+						&(stats.ihist.fd));
+				if (!stats.ihist.buff) {
+					pr_err("%s: msm_pmem_stats_ptov_lookup error\n",
+						__func__);
+					rc = -EINVAL;
+					goto failure;
+				}
+
+			} else {
+				stats.ihist.buff = 0;
+			}
+
+			if (data->stats_msg.rs_buff) {
+				stats.rs.buff =
+				msm_pmem_stats_ptov_lookup(sync,
+						data->stats_msg.rs_buff,
+						&(stats.rs.fd));
+				if (!stats.rs.buff) {
+					pr_err("%s: msm_pmem_stats_ptov_lookup error\n",
+						__func__);
+					rc = -EINVAL;
+					goto failure;
+				}
+
+			} else {
+				stats.rs.buff = 0;
+			}
+
+			if (data->stats_msg.cs_buff) {
+				stats.cs.buff =
+				msm_pmem_stats_ptov_lookup(sync,
+						data->stats_msg.cs_buff,
+						&(stats.cs.fd));
+				if (!stats.cs.buff) {
+					pr_err("%s: msm_pmem_stats_ptov_lookup error\n",
+						__func__);
+					rc = -EINVAL;
+					goto failure;
+				}
+			} else {
+				stats.cs.buff = 0;
+			}
+
+			se.stats_event.frame_id = data->phy.frame_id;
+			if (copy_to_user((void *)(se.stats_event.data),
+					&stats,
+					sizeof(struct msm_stats_buf))) {
+				ERR_COPY_TO_USER();
+				rc = -EFAULT;
+				goto failure;
+			}
+		} else if ((data->type >= VFE_MSG_STATS_AEC) &&
+			(data->type <=  VFE_MSG_STATS_WE)) {
+			/* the check above includes all stats type. */
+			stats.buffer =
+				msm_pmem_stats_ptov_lookup(sync,
+						data->phy.sbuf_phy,
+						&(stats.fd));
+			if (!stats.buffer) {
+					pr_err("%s: msm_pmem_stats_ptov_lookup error\n",
+						__func__);
+					rc = -EINVAL;
+					goto failure;
+			}
+			se.stats_event.frame_id = data->phy.frame_id;
+			if (copy_to_user((void *)(se.stats_event.data),
+					&stats,
+					sizeof(struct msm_stats_buf))) {
+				ERR_COPY_TO_USER();
+				rc = -EFAULT;
+				goto failure;
+			}
+		} else if ((data->evt_msg.len > 0) &&
+				(data->type == VFE_MSG_GENERAL)) {
+			if (copy_to_user((void *)(se.stats_event.data),
+					data->evt_msg.data,
+					data->evt_msg.len)) {
+				ERR_COPY_TO_USER();
+				rc = -EFAULT;
+				goto failure;
+			}
+		} else {
+			if (sync->stereocam_enabled) {
+				if (data->type == VFE_MSG_OUTPUT_P) {
+					CDBG("%s: Preview mark as st op 1\n",
+						__func__);
+					se.resptype = MSM_CAM_RESP_STEREO_OP_1;
+					rc = msm_divert_st_frame(sync, data,
+						&se, OUTPUT_TYPE_P);
+					break;
+				} else if (data->type == VFE_MSG_OUTPUT_V) {
+					CDBG("%s: Video mark as st op 2\n",
+						__func__);
+					se.resptype = MSM_CAM_RESP_STEREO_OP_2;
+					rc = msm_divert_st_frame(sync, data,
+						&se, OUTPUT_TYPE_V);
+					break;
+				} else if (data->type == VFE_MSG_OUTPUT_S) {
+					CDBG("%s: Main img mark as st op 2\n",
+						__func__);
+					se.resptype = MSM_CAM_RESP_STEREO_OP_2;
+					rc = msm_divert_st_frame(sync, data,
+						&se, OUTPUT_TYPE_S);
+					break;
+				} else if (data->type == VFE_MSG_OUTPUT_T) {
+					CDBG("%s: Thumb img mark as st op 2\n",
+						__func__);
+					se.resptype = MSM_CAM_RESP_STEREO_OP_2;
+					rc = msm_divert_st_frame(sync, data,
+						&se, OUTPUT_TYPE_T);
+					break;
+				} else
+					CDBG("%s: VFE_MSG Fall Through\n",
+						__func__);
+			}
+			if ((sync->pp_frame_avail == 1) &&
+				(sync->pp_mask & PP_PREV) &&
+				(data->type == VFE_MSG_OUTPUT_P)) {
+					CDBG("%s:%d:preiew PP\n",
+					__func__, __LINE__);
+					se.stats_event.frame_id =
+							data->phy.frame_id;
+					rc = msm_divert_frame(sync, data, &se);
+					sync->pp_frame_avail = 0;
+			} else {
+				if ((sync->pp_mask & PP_PREV) &&
+					(data->type == VFE_MSG_OUTPUT_P)) {
+					se.stats_event.frame_id =
+							data->phy.frame_id;
+					free_qcmd(qcmd);
+					return 0;
+				} else
+					CDBG("%s:indication type is %d\n",
+						__func__, data->type);
+			}
+			if (sync->pp_mask & PP_SNAP)
+				if (data->type == VFE_MSG_OUTPUT_S ||
+					data->type == VFE_MSG_OUTPUT_T)
+					rc = msm_divert_frame(sync, data, &se);
+		}
+		break;
+
+	case MSM_CAM_Q_CTRL:
+		/* control command from control thread */
+		ctrl = (struct msm_ctrl_cmd *)(qcmd->command);
+
+		CDBG("%s: qcmd->type %d length %d\n", __func__,
+			qcmd->type, ctrl->length);
+
+		if (ctrl->length > 0) {
+			if (copy_to_user((void *)(se.ctrl_cmd.value),
+						ctrl->value,
+						ctrl->length)) {
+				ERR_COPY_TO_USER();
+				rc = -EFAULT;
+				goto failure;
+			}
+		}
+
+		se.resptype = MSM_CAM_RESP_CTRL;
+
+		/* what to control */
+		se.ctrl_cmd.type = ctrl->type;
+		se.ctrl_cmd.length = ctrl->length;
+		se.ctrl_cmd.resp_fd = ctrl->resp_fd;
+		break;
+
+	case MSM_CAM_Q_V4L2_REQ:
+		/* control command from v4l2 client */
+		ctrl = (struct msm_ctrl_cmd *)(qcmd->command);
+		if (ctrl->length > 0) {
+			if (copy_to_user((void *)(se.ctrl_cmd.value),
+					ctrl->value, ctrl->length)) {
+				ERR_COPY_TO_USER();
+				rc = -EFAULT;
+				goto failure;
+			}
+		}
+
+		/* 2 tells config thread this is v4l2 request */
+		se.resptype = MSM_CAM_RESP_V4L2;
+
+		/* what to control */
+		se.ctrl_cmd.type   = ctrl->type;
+		se.ctrl_cmd.length = ctrl->length;
+		break;
+
+	default:
+		rc = -EFAULT;
+		goto failure;
+	} /* switch qcmd->type */
+	if (copy_to_user((void *)arg, &se, sizeof(se))) {
+		ERR_COPY_TO_USER();
+		rc = -EFAULT;
+		goto failure;
+	}
+
+failure:
+	free_qcmd(qcmd);
+
+	CDBG("%s: %d\n", __func__, rc);
+	return rc;
+}
+
+static int msm_ctrl_cmd_done(struct msm_control_device *ctrl_pmsm,
+		void __user *arg)
+{
+	void __user *uptr;
+	struct msm_queue_cmd *qcmd = &ctrl_pmsm->qcmd;
+	struct msm_ctrl_cmd *command = &ctrl_pmsm->ctrl;
+
+	if (copy_from_user(command, arg, sizeof(*command))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	atomic_set(&qcmd->on_heap, 0);
+	qcmd->command = command;
+	uptr = command->value;
+
+	if (command->length > 0) {
+		command->value = ctrl_pmsm->ctrl_data;
+		if (command->length > sizeof(ctrl_pmsm->ctrl_data)) {
+			pr_err("%s: user data %d is too big (max %d)\n",
+				__func__, command->length,
+				sizeof(ctrl_pmsm->ctrl_data));
+			return -EINVAL;
+		}
+
+		if (copy_from_user(command->value,
+					uptr,
+					command->length)) {
+			ERR_COPY_FROM_USER();
+			return -EFAULT;
+		}
+	} else
+		command->value = NULL;
+
+	/* Ignore the command if the ctrl cmd has
+	   return back due to signaling */
+	/* Should be associated with wait_event
+	   error -512 from __msm_control*/
+	if (ctrl_pmsm->pmsm->sync->ignore_qcmd == true &&
+	   ctrl_pmsm->pmsm->sync->ignore_qcmd_type == (int16_t)command->type) {
+		ctrl_pmsm->pmsm->sync->ignore_qcmd = false;
+		ctrl_pmsm->pmsm->sync->ignore_qcmd_type = -1;
+	} else /* wake up control thread */
+		msm_enqueue(&ctrl_pmsm->ctrl_q, &qcmd->list_control);
+
+	return 0;
+}
+
+static int msm_config_vpe(struct msm_sync *sync, void __user *arg)
+{
+	struct msm_vpe_cfg_cmd cfgcmd;
+	if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+	CDBG("%s: cmd_type %s\n", __func__, vfe_config_cmd[cfgcmd.cmd_type]);
+	switch (cfgcmd.cmd_type) {
+	case CMD_VPE:
+		return sync->vpefn.vpe_config(&cfgcmd, NULL);
+	default:
+		pr_err("%s: unknown command type %d\n",
+			__func__, cfgcmd.cmd_type);
+	}
+	return -EINVAL;
+}
+
+static int msm_config_vfe(struct msm_sync *sync, void __user *arg)
+{
+	struct msm_vfe_cfg_cmd cfgcmd;
+	struct msm_pmem_region region[8];
+	struct axidata axi_data;
+
+	if (!sync->vfefn.vfe_config) {
+		pr_err("%s: no vfe_config!\n", __func__);
+		return -EIO;
+	}
+
+	if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	memset(&axi_data, 0, sizeof(axi_data));
+	CDBG("%s: cmd_type %s\n", __func__, vfe_config_cmd[cfgcmd.cmd_type]);
+	switch (cfgcmd.cmd_type) {
+	case CMD_STATS_ENABLE:
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+				MSM_PMEM_AEC_AWB, &region[0],
+				NUM_STAT_OUTPUT_BUFFERS,
+				&sync->pmem_stats_spinlock);
+		axi_data.bufnum2 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+				MSM_PMEM_AF, &region[axi_data.bufnum1],
+				NUM_STAT_OUTPUT_BUFFERS,
+				&sync->pmem_stats_spinlock);
+		if (!axi_data.bufnum1 || !axi_data.bufnum2) {
+			pr_err("%s: pmem region lookup error\n", __func__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+		return sync->vfefn.vfe_config(&cfgcmd, &axi_data);
+	case CMD_STATS_AF_ENABLE:
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+				MSM_PMEM_AF, &region[0],
+				NUM_STAT_OUTPUT_BUFFERS,
+				&sync->pmem_stats_spinlock);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+		return sync->vfefn.vfe_config(&cfgcmd, &axi_data);
+	case CMD_STATS_AEC_AWB_ENABLE:
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+				MSM_PMEM_AEC_AWB, &region[0],
+				NUM_STAT_OUTPUT_BUFFERS,
+				&sync->pmem_stats_spinlock);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+		return sync->vfefn.vfe_config(&cfgcmd, &axi_data);
+	case CMD_STATS_AEC_ENABLE:
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+			MSM_PMEM_AEC, &region[0],
+			NUM_STAT_OUTPUT_BUFFERS,
+			&sync->pmem_stats_spinlock);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+		return sync->vfefn.vfe_config(&cfgcmd, &axi_data);
+	case CMD_STATS_AWB_ENABLE:
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+			MSM_PMEM_AWB, &region[0],
+			NUM_STAT_OUTPUT_BUFFERS,
+			&sync->pmem_stats_spinlock);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+		return sync->vfefn.vfe_config(&cfgcmd, &axi_data);
+
+
+	case CMD_STATS_IHIST_ENABLE:
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+			MSM_PMEM_IHIST, &region[0],
+			NUM_STAT_OUTPUT_BUFFERS,
+			&sync->pmem_stats_spinlock);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+		return sync->vfefn.vfe_config(&cfgcmd, &axi_data);
+
+	case CMD_STATS_RS_ENABLE:
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+			MSM_PMEM_RS, &region[0],
+			NUM_STAT_OUTPUT_BUFFERS,
+			&sync->pmem_stats_spinlock);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+		return sync->vfefn.vfe_config(&cfgcmd, &axi_data);
+
+	case CMD_STATS_CS_ENABLE:
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+			MSM_PMEM_CS, &region[0],
+			NUM_STAT_OUTPUT_BUFFERS,
+			&sync->pmem_stats_spinlock);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+		return sync->vfefn.vfe_config(&cfgcmd, &axi_data);
+
+	case CMD_GENERAL:
+	case CMD_STATS_DISABLE:
+		return sync->vfefn.vfe_config(&cfgcmd, NULL);
+	default:
+		pr_err("%s: unknown command type %d\n",
+			__func__, cfgcmd.cmd_type);
+	}
+
+	return -EINVAL;
+}
+static int msm_vpe_frame_cfg(struct msm_sync *sync,
+				void *cfgcmdin)
+{
+	int rc = -EIO;
+	struct axidata axi_data;
+	void *data = &axi_data;
+	struct msm_pmem_region region[8];
+	int pmem_type;
+
+	struct msm_vpe_cfg_cmd *cfgcmd;
+	cfgcmd = (struct msm_vpe_cfg_cmd *)cfgcmdin;
+
+	memset(&axi_data, 0, sizeof(axi_data));
+	CDBG("In vpe_frame_cfg cfgcmd->cmd_type = %s\n",
+		vfe_config_cmd[cfgcmd->cmd_type]);
+	switch (cfgcmd->cmd_type) {
+	case CMD_AXI_CFG_VPE:
+		pmem_type = MSM_PMEM_VIDEO_VPE;
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup_2(&sync->pmem_frames, pmem_type,
+				&region[0], 8, &sync->pmem_frame_spinlock);
+		CDBG("axi_data.bufnum1 = %d\n", axi_data.bufnum1);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		pmem_type = MSM_PMEM_VIDEO;
+		break;
+	case CMD_AXI_CFG_SNAP_THUMB_VPE:
+		CDBG("%s: CMD_AXI_CFG_SNAP_THUMB_VPE", __func__);
+		pmem_type = MSM_PMEM_THUMBNAIL_VPE;
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_frames, pmem_type,
+			&region[0], 8, &sync->pmem_frame_spinlock);
+		if (!axi_data.bufnum1) {
+			pr_err("%s: THUMBNAIL_VPE pmem region lookup error\n",
+				__func__);
+			return -EINVAL;
+		}
+		break;
+	case CMD_AXI_CFG_SNAP_VPE:
+		CDBG("%s: CMD_AXI_CFG_SNAP_VPE", __func__);
+		pmem_type = MSM_PMEM_MAINIMG_VPE;
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_frames, pmem_type,
+				&region[0], 8, &sync->pmem_frame_spinlock);
+		if (!axi_data.bufnum1) {
+			pr_err("%s: MAINIMG_VPE pmem region lookup error\n",
+				__func__);
+			return -EINVAL;
+		}
+		break;
+	default:
+		pr_err("%s: unknown command type %d\n",
+			__func__, cfgcmd->cmd_type);
+		break;
+	}
+	axi_data.region = &region[0];
+	CDBG("out vpe_frame_cfg cfgcmd->cmd_type = %s\n",
+		vfe_config_cmd[cfgcmd->cmd_type]);
+	/* send the AXI configuration command to driver */
+	if (sync->vpefn.vpe_config)
+		rc = sync->vpefn.vpe_config(cfgcmd, data);
+	return rc;
+}
+
+static int msm_frame_axi_cfg(struct msm_sync *sync,
+		struct msm_vfe_cfg_cmd *cfgcmd)
+{
+	int rc = -EIO;
+	struct axidata axi_data;
+	void *data = &axi_data;
+	struct msm_pmem_region region[MAX_PMEM_CFG_BUFFERS];
+	int pmem_type;
+
+	memset(&axi_data, 0, sizeof(axi_data));
+
+	switch (cfgcmd->cmd_type) {
+
+	case CMD_AXI_CFG_PREVIEW:
+		pmem_type = MSM_PMEM_PREVIEW;
+		axi_data.bufnum2 =
+			msm_pmem_region_lookup(&sync->pmem_frames, pmem_type,
+				&region[0], MAX_PMEM_CFG_BUFFERS,
+				&sync->pmem_frame_spinlock);
+		if (!axi_data.bufnum2) {
+			pr_err("%s %d: pmem region lookup error (empty %d)\n",
+				__func__, __LINE__,
+				hlist_empty(&sync->pmem_frames));
+			return -EINVAL;
+		}
+		break;
+
+	case CMD_AXI_CFG_VIDEO:
+		pmem_type = MSM_PMEM_PREVIEW;
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_frames, pmem_type,
+				&region[0], MAX_PMEM_CFG_BUFFERS,
+				&sync->pmem_frame_spinlock);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+
+		pmem_type = MSM_PMEM_VIDEO;
+		axi_data.bufnum2 =
+			msm_pmem_region_lookup(&sync->pmem_frames, pmem_type,
+				&region[axi_data.bufnum1],
+				(MAX_PMEM_CFG_BUFFERS-(axi_data.bufnum1)),
+				&sync->pmem_frame_spinlock);
+		if (!axi_data.bufnum2) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		break;
+
+	case CMD_AXI_CFG_SNAP:
+		CDBG("%s, CMD_AXI_CFG_SNAP, type=%d\n", __func__,
+			cfgcmd->cmd_type);
+		pmem_type = MSM_PMEM_THUMBNAIL;
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_frames, pmem_type,
+				&region[0], MAX_PMEM_CFG_BUFFERS,
+				&sync->pmem_frame_spinlock);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+
+		pmem_type = MSM_PMEM_MAINIMG;
+		axi_data.bufnum2 =
+			msm_pmem_region_lookup(&sync->pmem_frames, pmem_type,
+				&region[axi_data.bufnum1],
+				(MAX_PMEM_CFG_BUFFERS-(axi_data.bufnum1)),
+				 &sync->pmem_frame_spinlock);
+		if (!axi_data.bufnum2) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		break;
+
+	case CMD_AXI_CFG_ZSL:
+		CDBG("%s, CMD_AXI_CFG_ZSL, type = %d\n", __func__,
+			cfgcmd->cmd_type);
+		pmem_type = MSM_PMEM_PREVIEW;
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_frames, pmem_type,
+				&region[0], MAX_PMEM_CFG_BUFFERS,
+				&sync->pmem_frame_spinlock);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+
+		pmem_type = MSM_PMEM_THUMBNAIL;
+		axi_data.bufnum2 =
+			msm_pmem_region_lookup(&sync->pmem_frames, pmem_type,
+				&region[axi_data.bufnum1],
+				(MAX_PMEM_CFG_BUFFERS-(axi_data.bufnum1)),
+				 &sync->pmem_frame_spinlock);
+		if (!axi_data.bufnum2) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+
+		pmem_type = MSM_PMEM_MAINIMG;
+		axi_data.bufnum3 =
+			msm_pmem_region_lookup(&sync->pmem_frames, pmem_type,
+				&region[axi_data.bufnum1 + axi_data.bufnum2],
+				(MAX_PMEM_CFG_BUFFERS - axi_data.bufnum1 -
+				axi_data.bufnum2), &sync->pmem_frame_spinlock);
+		if (!axi_data.bufnum3) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		break;
+
+	case CMD_RAW_PICT_AXI_CFG:
+		pmem_type = MSM_PMEM_RAW_MAINIMG;
+		axi_data.bufnum2 =
+			msm_pmem_region_lookup(&sync->pmem_frames, pmem_type,
+				&region[0], MAX_PMEM_CFG_BUFFERS,
+				&sync->pmem_frame_spinlock);
+		if (!axi_data.bufnum2) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		break;
+
+	case CMD_GENERAL:
+		data = NULL;
+		break;
+
+	default:
+		pr_err("%s: unknown command type %d\n",
+			__func__, cfgcmd->cmd_type);
+		return -EINVAL;
+	}
+
+	axi_data.region = &region[0];
+
+	/* send the AXI configuration command to driver */
+	if (sync->vfefn.vfe_config)
+		rc = sync->vfefn.vfe_config(cfgcmd, data);
+
+	return rc;
+}
+
+static int msm_get_sensor_info(struct msm_sync *sync, void __user *arg)
+{
+	int rc = 0;
+	struct msm_camsensor_info info;
+	struct msm_camera_sensor_info *sdata;
+
+	if (copy_from_user(&info,
+			arg,
+			sizeof(struct msm_camsensor_info))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	sdata = sync->pdev->dev.platform_data;
+	if (sync->sctrl.s_camera_type == BACK_CAMERA_3D)
+		info.support_3d = true;
+	else
+		info.support_3d = false;
+	memcpy(&info.name[0],
+		sdata->sensor_name,
+		MAX_SENSOR_NAME);
+	info.flash_enabled = sdata->flash_data->flash_type !=
+		MSM_CAMERA_FLASH_NONE;
+
+	/* copy back to user space */
+	if (copy_to_user((void *)arg,
+			&info,
+			sizeof(struct msm_camsensor_info))) {
+		ERR_COPY_TO_USER();
+		rc = -EFAULT;
+	}
+
+	return rc;
+}
+
+static int msm_get_camera_info(void __user *arg)
+{
+	int rc = 0;
+	int i = 0;
+	struct msm_camera_info info;
+
+	if (copy_from_user(&info, arg, sizeof(struct msm_camera_info))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	CDBG("%s: camera_node %d\n", __func__, camera_node);
+	info.num_cameras = camera_node;
+
+	for (i = 0; i < camera_node; i++) {
+		info.has_3d_support[i] = 0;
+		info.is_internal_cam[i] = 0;
+		info.s_mount_angle[i] = sensor_mount_angle[i];
+		switch (camera_type[i]) {
+		case FRONT_CAMERA_2D:
+			info.is_internal_cam[i] = 1;
+			break;
+		case BACK_CAMERA_3D:
+			info.has_3d_support[i] = 1;
+			break;
+		case BACK_CAMERA_2D:
+		default:
+			break;
+		}
+	}
+	/* copy back to user space */
+	if (copy_to_user((void *)arg, &info, sizeof(struct msm_camera_info))) {
+		ERR_COPY_TO_USER();
+		rc = -EFAULT;
+	}
+	return rc;
+}
+
+static int __msm_put_frame_buf(struct msm_sync *sync,
+		struct msm_frame *pb)
+{
+	unsigned long pphy;
+	struct msm_vfe_cfg_cmd cfgcmd;
+
+	int rc = -EIO;
+
+	/* Change the active flag. */
+	pphy = msm_pmem_frame_vtop_lookup(sync,
+		pb->buffer,
+		pb->y_off, pb->cbcr_off, pb->fd, 1);
+
+	if (pphy != 0) {
+		CDBG("%s: rel: vaddr %lx, paddr %lx\n",
+			__func__,
+			pb->buffer, pphy);
+		cfgcmd.cmd_type = CMD_FRAME_BUF_RELEASE;
+		cfgcmd.value    = (void *)pb;
+		if (sync->vfefn.vfe_config)
+			rc = sync->vfefn.vfe_config(&cfgcmd, &pphy);
+	} else {
+		pr_err("%s: msm_pmem_frame_vtop_lookup failed\n",
+			__func__);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+static int __msm_put_pic_buf(struct msm_sync *sync,
+		struct msm_frame *pb)
+{
+	unsigned long pphy;
+	struct msm_vfe_cfg_cmd cfgcmd;
+
+	int rc = -EIO;
+
+	pphy = msm_pmem_frame_vtop_lookup(sync,
+		pb->buffer,
+		pb->y_off, pb->cbcr_off, pb->fd, 1);
+
+	if (pphy != 0) {
+		CDBG("%s: rel: vaddr %lx, paddr %lx\n",
+			__func__,
+			pb->buffer, pphy);
+		cfgcmd.cmd_type = CMD_SNAP_BUF_RELEASE;
+		cfgcmd.value    = (void *)pb;
+		if (sync->vfefn.vfe_config)
+			rc = sync->vfefn.vfe_config(&cfgcmd, &pphy);
+	} else {
+		pr_err("%s: msm_pmem_frame_vtop_lookup failed\n",
+			__func__);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+
+static int msm_put_frame_buffer(struct msm_sync *sync, void __user *arg)
+{
+	struct msm_frame buf_t;
+
+	if (copy_from_user(&buf_t,
+				arg,
+				sizeof(struct msm_frame))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	return __msm_put_frame_buf(sync, &buf_t);
+}
+
+
+static int msm_put_pic_buffer(struct msm_sync *sync, void __user *arg)
+{
+	struct msm_frame buf_t;
+
+	if (copy_from_user(&buf_t,
+				arg,
+				sizeof(struct msm_frame))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	return __msm_put_pic_buf(sync, &buf_t);
+}
+
+static int __msm_register_pmem(struct msm_sync *sync,
+		struct msm_pmem_info *pinfo)
+{
+	int rc = 0;
+
+	switch (pinfo->type) {
+	case MSM_PMEM_VIDEO:
+	case MSM_PMEM_PREVIEW:
+	case MSM_PMEM_THUMBNAIL:
+	case MSM_PMEM_MAINIMG:
+	case MSM_PMEM_RAW_MAINIMG:
+	case MSM_PMEM_VIDEO_VPE:
+	case MSM_PMEM_C2D:
+	case MSM_PMEM_MAINIMG_VPE:
+	case MSM_PMEM_THUMBNAIL_VPE:
+		rc = msm_pmem_table_add(&sync->pmem_frames, pinfo,
+			&sync->pmem_frame_spinlock, sync);
+		break;
+
+	case MSM_PMEM_AEC_AWB:
+	case MSM_PMEM_AF:
+	case MSM_PMEM_AEC:
+	case MSM_PMEM_AWB:
+	case MSM_PMEM_RS:
+	case MSM_PMEM_CS:
+	case MSM_PMEM_IHIST:
+	case MSM_PMEM_SKIN:
+
+		rc = msm_pmem_table_add(&sync->pmem_stats, pinfo,
+			 &sync->pmem_stats_spinlock, sync);
+		break;
+
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+static int msm_register_pmem(struct msm_sync *sync, void __user *arg)
+{
+	struct msm_pmem_info info;
+
+	if (copy_from_user(&info, arg, sizeof(info))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	return __msm_register_pmem(sync, &info);
+}
+
+static int msm_stats_axi_cfg(struct msm_sync *sync,
+		struct msm_vfe_cfg_cmd *cfgcmd)
+{
+	int rc = -EIO;
+	struct axidata axi_data;
+	void *data = &axi_data;
+
+	struct msm_pmem_region region[3];
+	int pmem_type = MSM_PMEM_MAX;
+
+	memset(&axi_data, 0, sizeof(axi_data));
+
+	switch (cfgcmd->cmd_type) {
+	case CMD_STATS_AXI_CFG:
+		pmem_type = MSM_PMEM_AEC_AWB;
+		break;
+	case CMD_STATS_AF_AXI_CFG:
+		pmem_type = MSM_PMEM_AF;
+		break;
+	case CMD_GENERAL:
+		data = NULL;
+		break;
+	default:
+		pr_err("%s: unknown command type %d\n",
+			__func__, cfgcmd->cmd_type);
+		return -EINVAL;
+	}
+
+	if (cfgcmd->cmd_type != CMD_GENERAL) {
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats, pmem_type,
+				&region[0], NUM_STAT_OUTPUT_BUFFERS,
+				&sync->pmem_stats_spinlock);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+	axi_data.region = &region[0];
+	}
+
+	/* send the AEC/AWB STATS configuration command to driver */
+	if (sync->vfefn.vfe_config)
+		rc = sync->vfefn.vfe_config(cfgcmd, &axi_data);
+
+	return rc;
+}
+
+static int msm_put_stats_buffer(struct msm_sync *sync, void __user *arg)
+{
+	int rc = -EIO;
+
+	struct msm_stats_buf buf;
+	unsigned long pphy;
+	struct msm_vfe_cfg_cmd cfgcmd;
+
+	if (copy_from_user(&buf, arg,
+				sizeof(struct msm_stats_buf))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	CDBG("%s\n", __func__);
+	pphy = msm_pmem_stats_vtop_lookup(sync, buf.buffer, buf.fd);
+
+	if (pphy != 0) {
+		if (buf.type == STAT_AEAW)
+			cfgcmd.cmd_type = CMD_STATS_BUF_RELEASE;
+		else if (buf.type == STAT_AF)
+			cfgcmd.cmd_type = CMD_STATS_AF_BUF_RELEASE;
+		else if (buf.type == STAT_AEC)
+			cfgcmd.cmd_type = CMD_STATS_AEC_BUF_RELEASE;
+		else if (buf.type == STAT_AWB)
+			cfgcmd.cmd_type = CMD_STATS_AWB_BUF_RELEASE;
+		else if (buf.type == STAT_IHIST)
+			cfgcmd.cmd_type = CMD_STATS_IHIST_BUF_RELEASE;
+		else if (buf.type == STAT_RS)
+			cfgcmd.cmd_type = CMD_STATS_RS_BUF_RELEASE;
+		else if (buf.type == STAT_CS)
+			cfgcmd.cmd_type = CMD_STATS_CS_BUF_RELEASE;
+
+		else {
+			pr_err("%s: invalid buf type %d\n",
+				__func__,
+				buf.type);
+			rc = -EINVAL;
+			goto put_done;
+		}
+
+		cfgcmd.value = (void *)&buf;
+
+		if (sync->vfefn.vfe_config) {
+			rc = sync->vfefn.vfe_config(&cfgcmd, &pphy);
+			if (rc < 0)
+				pr_err("%s: vfe_config error %d\n",
+					__func__, rc);
+		} else
+			pr_err("%s: vfe_config is NULL\n", __func__);
+	} else {
+		pr_err("%s: NULL physical address\n", __func__);
+		rc = -EINVAL;
+	}
+
+put_done:
+	return rc;
+}
+
+static int msm_axi_config(struct msm_sync *sync, void __user *arg)
+{
+	struct msm_vfe_cfg_cmd cfgcmd;
+
+	if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	switch (cfgcmd.cmd_type) {
+	case CMD_AXI_CFG_VIDEO:
+	case CMD_AXI_CFG_PREVIEW:
+	case CMD_AXI_CFG_SNAP:
+	case CMD_RAW_PICT_AXI_CFG:
+	case CMD_AXI_CFG_ZSL:
+		CDBG("%s, cfgcmd.cmd_type = %d\n", __func__, cfgcmd.cmd_type);
+		return msm_frame_axi_cfg(sync, &cfgcmd);
+
+	case CMD_AXI_CFG_VPE:
+	case CMD_AXI_CFG_SNAP_VPE:
+	case CMD_AXI_CFG_SNAP_THUMB_VPE:
+		return msm_vpe_frame_cfg(sync, (void *)&cfgcmd);
+
+	case CMD_STATS_AXI_CFG:
+	case CMD_STATS_AF_AXI_CFG:
+		return msm_stats_axi_cfg(sync, &cfgcmd);
+
+	default:
+		pr_err("%s: unknown command type %d\n",
+			__func__,
+			cfgcmd.cmd_type);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int __msm_get_pic(struct msm_sync *sync,
+		struct msm_frame *frame)
+{
+
+	int rc = 0;
+	struct msm_queue_cmd *qcmd = NULL;
+	struct msm_vfe_resp *vdata;
+	struct msm_vfe_phy_info *pphy;
+	struct msm_pmem_info pmem_info;
+	struct msm_frame *pframe;
+
+	qcmd = msm_dequeue(&sync->pict_q, list_pict);
+
+	if (!qcmd) {
+		pr_err("%s: no pic frame.\n", __func__);
+		return -EAGAIN;
+	}
+
+	if (MSM_CAM_Q_PP_MSG != qcmd->type) {
+		vdata = (struct msm_vfe_resp *)(qcmd->command);
+		pphy = &vdata->phy;
+
+		rc = msm_pmem_frame_ptov_lookup2(sync,
+				pphy->y_phy,
+				&pmem_info,
+				1); /* mark pic frame in use */
+
+		if (rc < 0) {
+			pr_err("%s: cannot get pic frame, invalid lookup"
+				" address y %x cbcr %x\n",
+				__func__, pphy->y_phy, pphy->cbcr_phy);
+			goto err;
+		}
+
+		frame->ts = qcmd->ts;
+		frame->buffer = (unsigned long)pmem_info.vaddr;
+		frame->y_off = pmem_info.y_off;
+		frame->cbcr_off = pmem_info.cbcr_off;
+		frame->fd = pmem_info.fd;
+		if (sync->stereocam_enabled &&
+			sync->stereo_state != STEREO_RAW_SNAP_STARTED) {
+			if (pmem_info.type == MSM_PMEM_THUMBNAIL_VPE)
+				frame->path = OUTPUT_TYPE_T;
+			else
+				frame->path = OUTPUT_TYPE_S;
+		} else
+			frame->path = vdata->phy.output_id;
+
+		CDBG("%s: y %x, cbcr %x, qcmd %x, virt_addr %x\n",
+			__func__, pphy->y_phy,
+			pphy->cbcr_phy, (int) qcmd, (int) frame->buffer);
+	} else { /* PP */
+		pframe = (struct msm_frame *)(qcmd->command);
+		frame->ts = qcmd->ts;
+		frame->buffer = pframe->buffer;
+		frame->y_off = pframe->y_off;
+		frame->cbcr_off = pframe->cbcr_off;
+		frame->fd = pframe->fd;
+		frame->path = pframe->path;
+		CDBG("%s: PP y_off %x, cbcr_off %x, path %d vaddr 0x%x\n",
+			__func__, frame->y_off, frame->cbcr_off, frame->path,
+			(int) frame->buffer);
+	}
+
+err:
+	free_qcmd(qcmd);
+
+	return rc;
+}
+
+static int msm_get_pic(struct msm_sync *sync, void __user *arg)
+{
+	int rc = 0;
+	struct msm_frame frame;
+
+	if (copy_from_user(&frame,
+				arg,
+				sizeof(struct msm_frame))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	rc = __msm_get_pic(sync, &frame);
+	if (rc < 0)
+		return rc;
+
+	if (sync->croplen && (!sync->stereocam_enabled)) {
+		if (frame.croplen != sync->croplen) {
+			pr_err("%s: invalid frame croplen %d,"
+				"expecting %d\n",
+				__func__,
+				frame.croplen,
+				sync->croplen);
+			return -EINVAL;
+		}
+
+		if (copy_to_user((void *)frame.cropinfo,
+				sync->cropinfo,
+				sync->croplen)) {
+			ERR_COPY_TO_USER();
+			return -EFAULT;
+		}
+	}
+	CDBG("%s: copy snapshot frame to user\n", __func__);
+	if (copy_to_user((void *)arg,
+				&frame, sizeof(struct msm_frame))) {
+		ERR_COPY_TO_USER();
+		rc = -EFAULT;
+	}
+
+	CDBG("%s: got pic frame\n", __func__);
+
+	return rc;
+}
+
+static int msm_set_crop(struct msm_sync *sync, void __user *arg)
+{
+	struct crop_info crop;
+
+	mutex_lock(&sync->lock);
+	if (copy_from_user(&crop,
+				arg,
+				sizeof(struct crop_info))) {
+		ERR_COPY_FROM_USER();
+		mutex_unlock(&sync->lock);
+		return -EFAULT;
+	}
+
+	if (crop.len != CROP_LEN) {
+		mutex_unlock(&sync->lock);
+		return -EINVAL;
+	}
+
+	if (!sync->croplen) {
+		sync->cropinfo = kmalloc(crop.len, GFP_KERNEL);
+		if (!sync->cropinfo) {
+			mutex_unlock(&sync->lock);
+			return -ENOMEM;
+		}
+	}
+
+	if (copy_from_user(sync->cropinfo,
+				crop.info,
+				crop.len)) {
+		ERR_COPY_FROM_USER();
+		sync->croplen = 0;
+		kfree(sync->cropinfo);
+		mutex_unlock(&sync->lock);
+		return -EFAULT;
+	}
+
+	sync->croplen = crop.len;
+
+	mutex_unlock(&sync->lock);
+	return 0;
+}
+
+static int msm_error_config(struct msm_sync *sync, void __user *arg)
+{
+	struct msm_queue_cmd *qcmd =
+		kmalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
+
+	qcmd->command = NULL;
+
+	if (qcmd)
+		atomic_set(&(qcmd->on_heap), 1);
+
+	if (copy_from_user(&(qcmd->error_code), arg, sizeof(uint32_t))) {
+		ERR_COPY_FROM_USER();
+		free_qcmd(qcmd);
+		return -EFAULT;
+	}
+
+	pr_err("%s: Enqueue Fake Frame with error code = %d\n", __func__,
+		qcmd->error_code);
+	msm_enqueue(&sync->frame_q, &qcmd->list_frame);
+	return 0;
+}
+
+static int msm_set_fd_roi(struct msm_sync *sync, void __user *arg)
+{
+	struct fd_roi_info fd_roi;
+
+	mutex_lock(&sync->lock);
+	if (copy_from_user(&fd_roi,
+			arg,
+			sizeof(struct fd_roi_info))) {
+		ERR_COPY_FROM_USER();
+		mutex_unlock(&sync->lock);
+		return -EFAULT;
+	}
+	if (fd_roi.info_len <= 0) {
+		mutex_unlock(&sync->lock);
+		return -EFAULT;
+	}
+
+	if (!sync->fdroiinfo.info) {
+		sync->fdroiinfo.info = kmalloc(fd_roi.info_len, GFP_KERNEL);
+		if (!sync->fdroiinfo.info) {
+			mutex_unlock(&sync->lock);
+			return -ENOMEM;
+		}
+		sync->fdroiinfo.info_len = fd_roi.info_len;
+	} else if (sync->fdroiinfo.info_len < fd_roi.info_len) {
+		mutex_unlock(&sync->lock);
+		return -EINVAL;
+    }
+
+	if (copy_from_user(sync->fdroiinfo.info,
+			fd_roi.info,
+			fd_roi.info_len)) {
+		ERR_COPY_FROM_USER();
+		kfree(sync->fdroiinfo.info);
+		sync->fdroiinfo.info = NULL;
+		mutex_unlock(&sync->lock);
+		return -EFAULT;
+	}
+	mutex_unlock(&sync->lock);
+	return 0;
+}
+
+static int msm_pp_grab(struct msm_sync *sync, void __user *arg)
+{
+	uint32_t enable;
+	if (copy_from_user(&enable, arg, sizeof(enable))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	} else {
+		enable &= PP_MASK;
+		if (enable & (enable - 1)) {
+			pr_err("%s: error: more than one PP request!\n",
+				__func__);
+			return -EINVAL;
+		}
+		if (sync->pp_mask) {
+			if (enable) {
+				pr_err("%s: postproc %x is already enabled\n",
+					__func__, sync->pp_mask & enable);
+				return -EINVAL;
+			} else {
+				sync->pp_mask &= enable;
+				CDBG("%s: sync->pp_mask %d enable %d\n",
+					__func__, sync->pp_mask, enable);
+				return 0;
+			}
+		}
+
+		CDBG("%s: sync->pp_mask %d enable %d\n", __func__,
+			sync->pp_mask, enable);
+		sync->pp_mask |= enable;
+	}
+
+	return 0;
+}
+
+static int msm_put_st_frame(struct msm_sync *sync, void __user *arg)
+{
+	unsigned long flags;
+	unsigned long st_pphy;
+	if (sync->stereocam_enabled) {
+		/* Make stereo frame ready for VPE. */
+		struct msm_st_frame stereo_frame_half;
+
+		if (copy_from_user(&stereo_frame_half, arg,
+			sizeof(stereo_frame_half))) {
+			ERR_COPY_FROM_USER();
+			return -EFAULT;
+		}
+
+		if (stereo_frame_half.type == OUTPUT_TYPE_ST_L) {
+			struct msm_vfe_resp *vfe_rp;
+			struct msm_queue_cmd *qcmd;
+
+			spin_lock_irqsave(&pp_stereocam_spinlock, flags);
+			if (!sync->pp_stereocam) {
+				pr_warning("%s: no stereo frame to deliver!\n",
+					__func__);
+				spin_unlock_irqrestore(&pp_stereocam_spinlock,
+					flags);
+				return -EINVAL;
+			}
+			CDBG("%s: delivering left frame to VPE\n", __func__);
+
+			qcmd = sync->pp_stereocam;
+			sync->pp_stereocam = NULL;
+			spin_unlock_irqrestore(&pp_stereocam_spinlock, flags);
+
+			vfe_rp = (struct msm_vfe_resp *)qcmd->command;
+
+			CDBG("%s: Left Py = 0x%x y_off = %d cbcr_off = %d\n",
+				__func__, vfe_rp->phy.y_phy,
+				stereo_frame_half.L.buf_y_off,
+				stereo_frame_half.L.buf_cbcr_off);
+
+			sync->vpefn.vpe_cfg_offset(stereo_frame_half.packing,
+			vfe_rp->phy.y_phy + stereo_frame_half.L.buf_y_off,
+			vfe_rp->phy.y_phy + stereo_frame_half.L.buf_cbcr_off,
+			&(qcmd->ts), OUTPUT_TYPE_ST_L, stereo_frame_half.L,
+			stereo_frame_half.frame_id);
+
+			free_qcmd(qcmd);
+		} else if (stereo_frame_half.type == OUTPUT_TYPE_ST_R) {
+			CDBG("%s: delivering right frame to VPE\n", __func__);
+			spin_lock_irqsave(&st_frame_spinlock, flags);
+
+			sync->stcam_conv_value =
+				stereo_frame_half.buf_info.stcam_conv_value;
+			sync->stcam_quality_ind =
+				stereo_frame_half.buf_info.stcam_quality_ind;
+
+			st_pphy = msm_pmem_frame_vtop_lookup(sync,
+				stereo_frame_half.buf_info.buffer,
+				stereo_frame_half.buf_info.y_off,
+				stereo_frame_half.buf_info.cbcr_off,
+				stereo_frame_half.buf_info.fd,
+				0); /* Do not change the active flag. */
+
+			sync->vpefn.vpe_cfg_offset(stereo_frame_half.packing,
+				st_pphy + stereo_frame_half.R.buf_y_off,
+				st_pphy + stereo_frame_half.R.buf_cbcr_off,
+				NULL, OUTPUT_TYPE_ST_R, stereo_frame_half.R,
+				stereo_frame_half.frame_id);
+
+			spin_unlock_irqrestore(&st_frame_spinlock, flags);
+		} else {
+			CDBG("%s: Invalid Msg\n", __func__);
+		}
+	}
+
+	return 0;
+}
+
+static struct msm_queue_cmd *msm_get_pp_qcmd(struct msm_frame* frame)
+{
+	struct msm_queue_cmd *qcmd =
+		kmalloc(sizeof(struct msm_queue_cmd) +
+			sizeof(struct msm_frame), GFP_ATOMIC);
+	qcmd->command = (struct msm_frame *)(qcmd + 1);
+
+	qcmd->type = MSM_CAM_Q_PP_MSG;
+
+	ktime_get_ts(&(qcmd->ts));
+	memcpy(qcmd->command, frame, sizeof(struct msm_frame));
+	atomic_set(&(qcmd->on_heap), 1);
+	return qcmd;
+}
+
+static int msm_pp_release(struct msm_sync *sync, void __user *arg)
+{
+	unsigned long flags;
+
+	if (!sync->pp_mask) {
+		pr_warning("%s: pp not in progress for\n", __func__);
+		return -EINVAL;
+	}
+	if (sync->pp_mask & PP_PREV) {
+
+
+		spin_lock_irqsave(&pp_prev_spinlock, flags);
+		if (!sync->pp_prev) {
+			pr_err("%s: no preview frame to deliver!\n",
+				__func__);
+			spin_unlock_irqrestore(&pp_prev_spinlock,
+				flags);
+			return -EINVAL;
+		}
+		CDBG("%s: delivering pp_prev\n", __func__);
+
+			if (sync->frame_q.len <= 100 &&
+				sync->event_q.len <= 100) {
+					msm_enqueue(&sync->frame_q,
+						&sync->pp_prev->list_frame);
+			} else {
+				pr_err("%s, Error Queue limit exceeded f_q=%d,\
+					e_q = %d\n",
+					__func__, sync->frame_q.len,
+					sync->event_q.len);
+				free_qcmd(sync->pp_prev);
+				goto done;
+			}
+
+			sync->pp_prev = NULL;
+			spin_unlock_irqrestore(&pp_prev_spinlock, flags);
+		goto done;
+	}
+
+	if ((sync->pp_mask & PP_SNAP) ||
+		(sync->pp_mask & PP_RAW_SNAP)) {
+		struct msm_frame frame;
+		struct msm_queue_cmd *qcmd;
+
+		if (copy_from_user(&frame,
+			arg,
+			sizeof(struct msm_frame))) {
+			ERR_COPY_FROM_USER();
+			return -EFAULT;
+		}
+		qcmd = msm_get_pp_qcmd(&frame);
+		if (!qcmd) {
+			pr_err("%s: no snapshot to deliver!\n", __func__);
+			return -EINVAL;
+		}
+		CDBG("%s: delivering pp snap\n", __func__);
+		msm_enqueue(&sync->pict_q, &qcmd->list_pict);
+	}
+
+done:
+	return 0;
+}
+
+static long msm_ioctl_common(struct msm_cam_device *pmsm,
+		unsigned int cmd,
+		void __user *argp)
+{
+	switch (cmd) {
+	case MSM_CAM_IOCTL_REGISTER_PMEM:
+		CDBG("%s cmd = MSM_CAM_IOCTL_REGISTER_PMEM\n", __func__);
+		return msm_register_pmem(pmsm->sync, argp);
+	case MSM_CAM_IOCTL_UNREGISTER_PMEM:
+		CDBG("%s cmd = MSM_CAM_IOCTL_UNREGISTER_PMEM\n", __func__);
+		return msm_pmem_table_del(pmsm->sync, argp);
+	case MSM_CAM_IOCTL_RELEASE_FRAME_BUFFER:
+		CDBG("%s cmd = MSM_CAM_IOCTL_RELEASE_FRAME_BUFFER\n", __func__);
+		return msm_put_frame_buffer(pmsm->sync, argp);
+		break;
+	default:
+		CDBG("%s cmd invalid\n", __func__);
+		return -EINVAL;
+	}
+}
+
+static long msm_ioctl_config(struct file *filep, unsigned int cmd,
+	unsigned long arg)
+{
+	int rc = -EINVAL;
+	void __user *argp = (void __user *)arg;
+	struct msm_cam_device *pmsm = filep->private_data;
+
+	CDBG("%s: cmd %d\n", __func__, _IOC_NR(cmd));
+
+	switch (cmd) {
+	case MSM_CAM_IOCTL_GET_SENSOR_INFO:
+		rc = msm_get_sensor_info(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_CONFIG_VFE:
+		/* Coming from config thread for update */
+		rc = msm_config_vfe(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_CONFIG_VPE:
+		/* Coming from config thread for update */
+		rc = msm_config_vpe(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_GET_STATS:
+		/* Coming from config thread wait
+		 * for vfe statistics and control requests */
+		rc = msm_get_stats(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_ENABLE_VFE:
+		/* This request comes from control thread:
+		 * enable either QCAMTASK or VFETASK */
+		rc = msm_enable_vfe(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_DISABLE_VFE:
+		/* This request comes from control thread:
+		 * disable either QCAMTASK or VFETASK */
+		rc = msm_disable_vfe(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_VFE_APPS_RESET:
+		msm_camio_vfe_blk_reset();
+		rc = 0;
+		break;
+
+	case MSM_CAM_IOCTL_RELEASE_STATS_BUFFER:
+		rc = msm_put_stats_buffer(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_AXI_CONFIG:
+	case MSM_CAM_IOCTL_AXI_VPE_CONFIG:
+		rc = msm_axi_config(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_SET_CROP:
+		rc = msm_set_crop(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_SET_FD_ROI:
+		rc = msm_set_fd_roi(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_PICT_PP:
+		/* Grab one preview frame or one snapshot
+		 * frame.
+		 */
+		rc = msm_pp_grab(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_PICT_PP_DONE:
+		/* Release the preview of snapshot frame
+		 * that was grabbed.
+		 */
+		rc = msm_pp_release(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_PUT_ST_FRAME:
+		/* Release the left or right frame
+		 * that was sent for stereo processing.
+		 */
+		rc = msm_put_st_frame(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_SENSOR_IO_CFG:
+		rc = pmsm->sync->sctrl.s_config(argp);
+		break;
+
+	case MSM_CAM_IOCTL_FLASH_LED_CFG: {
+		uint32_t led_state;
+		if (copy_from_user(&led_state, argp, sizeof(led_state))) {
+			ERR_COPY_FROM_USER();
+			rc = -EFAULT;
+		} else
+			rc = msm_camera_flash_set_led_state(pmsm->sync->
+					sdata->flash_data, led_state);
+		break;
+	}
+
+	case MSM_CAM_IOCTL_STROBE_FLASH_CFG: {
+		uint32_t flash_type;
+		if (copy_from_user(&flash_type, argp, sizeof(flash_type))) {
+			pr_err("msm_strobe_flash_init failed");
+			ERR_COPY_FROM_USER();
+			rc = -EFAULT;
+		} else {
+			CDBG("msm_strobe_flash_init enter");
+			rc = msm_strobe_flash_init(pmsm->sync, flash_type);
+		}
+		break;
+	}
+
+	case MSM_CAM_IOCTL_STROBE_FLASH_RELEASE:
+		if (pmsm->sync->sdata->strobe_flash_data) {
+			rc = pmsm->sync->sfctrl.strobe_flash_release(
+				pmsm->sync->sdata->strobe_flash_data, 0);
+		}
+		break;
+
+	case MSM_CAM_IOCTL_STROBE_FLASH_CHARGE: {
+		uint32_t charge_en;
+		if (copy_from_user(&charge_en, argp, sizeof(charge_en))) {
+			ERR_COPY_FROM_USER();
+			rc = -EFAULT;
+		} else
+			rc = pmsm->sync->sfctrl.strobe_flash_charge(
+			pmsm->sync->sdata->strobe_flash_data->flash_charge,
+			charge_en, pmsm->sync->sdata->strobe_flash_data->
+				flash_recharge_duration);
+		break;
+	}
+
+	case MSM_CAM_IOCTL_FLASH_CTRL: {
+		struct flash_ctrl_data flash_info;
+		if (copy_from_user(&flash_info, argp, sizeof(flash_info))) {
+			ERR_COPY_FROM_USER();
+			rc = -EFAULT;
+		} else
+			rc = msm_flash_ctrl(pmsm->sync->sdata, &flash_info);
+
+		break;
+	}
+
+	case MSM_CAM_IOCTL_ERROR_CONFIG:
+		rc = msm_error_config(pmsm->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_ABORT_CAPTURE: {
+		unsigned long flags = 0;
+		CDBG("get_pic:MSM_CAM_IOCTL_ABORT_CAPTURE\n");
+		spin_lock_irqsave(&pmsm->sync->abort_pict_lock, flags);
+		pmsm->sync->get_pic_abort = 1;
+		spin_unlock_irqrestore(&pmsm->sync->abort_pict_lock, flags);
+		wake_up(&(pmsm->sync->pict_q.wait));
+		rc = 0;
+		break;
+	}
+
+	default:
+		rc = msm_ioctl_common(pmsm, cmd, argp);
+		break;
+	}
+
+	CDBG("%s: cmd %d DONE\n", __func__, _IOC_NR(cmd));
+	return rc;
+}
+
+static int msm_unblock_poll_frame(struct msm_sync *);
+
+static long msm_ioctl_frame(struct file *filep, unsigned int cmd,
+	unsigned long arg)
+{
+	int rc = -EINVAL;
+	void __user *argp = (void __user *)arg;
+	struct msm_cam_device *pmsm = filep->private_data;
+
+
+	switch (cmd) {
+	case MSM_CAM_IOCTL_GETFRAME:
+		/* Coming from frame thread to get frame
+		 * after SELECT is done */
+		rc = msm_get_frame(pmsm->sync, argp);
+		break;
+	case MSM_CAM_IOCTL_RELEASE_FRAME_BUFFER:
+		rc = msm_put_frame_buffer(pmsm->sync, argp);
+		break;
+	case MSM_CAM_IOCTL_UNBLOCK_POLL_FRAME:
+		rc = msm_unblock_poll_frame(pmsm->sync);
+		break;
+	default:
+		break;
+	}
+
+	return rc;
+}
+
+static int msm_unblock_poll_pic(struct msm_sync *sync);
+static long msm_ioctl_pic(struct file *filep, unsigned int cmd,
+	unsigned long arg)
+{
+	int rc = -EINVAL;
+	void __user *argp = (void __user *)arg;
+	struct msm_cam_device *pmsm = filep->private_data;
+
+
+	switch (cmd) {
+	case MSM_CAM_IOCTL_GET_PICTURE:
+		rc = msm_get_pic(pmsm->sync, argp);
+		break;
+	case MSM_CAM_IOCTL_RELEASE_PIC_BUFFER:
+		rc = msm_put_pic_buffer(pmsm->sync, argp);
+		break;
+	case MSM_CAM_IOCTL_UNBLOCK_POLL_PIC_FRAME:
+		rc = msm_unblock_poll_pic(pmsm->sync);
+		break;
+	default:
+		break;
+	}
+
+	return rc;
+}
+
+
+static long msm_ioctl_control(struct file *filep, unsigned int cmd,
+	unsigned long arg)
+{
+	int rc = -EINVAL;
+	void __user *argp = (void __user *)arg;
+	struct msm_control_device *ctrl_pmsm = filep->private_data;
+	struct msm_cam_device *pmsm = ctrl_pmsm->pmsm;
+
+	switch (cmd) {
+	case MSM_CAM_IOCTL_CTRL_COMMAND:
+		/* Coming from control thread, may need to wait for
+		 * command status */
+		CDBG("calling msm_control kernel msm_ioctl_control\n");
+		mutex_lock(&ctrl_cmd_lock);
+		rc = msm_control(ctrl_pmsm, 1, argp);
+		mutex_unlock(&ctrl_cmd_lock);
+		break;
+	case MSM_CAM_IOCTL_CTRL_COMMAND_2:
+		/* Sends a message, returns immediately */
+		rc = msm_control(ctrl_pmsm, 0, argp);
+		break;
+	case MSM_CAM_IOCTL_CTRL_CMD_DONE:
+		/* Config thread calls the control thread to notify it
+		 * of the result of a MSM_CAM_IOCTL_CTRL_COMMAND.
+		 */
+		rc = msm_ctrl_cmd_done(ctrl_pmsm, argp);
+		break;
+	case MSM_CAM_IOCTL_GET_SENSOR_INFO:
+		rc = msm_get_sensor_info(pmsm->sync, argp);
+		break;
+	case MSM_CAM_IOCTL_GET_CAMERA_INFO:
+		rc = msm_get_camera_info(argp);
+		break;
+	default:
+		rc = msm_ioctl_common(pmsm, cmd, argp);
+		break;
+	}
+
+	return rc;
+}
+
+static int __msm_release(struct msm_sync *sync)
+{
+	struct msm_pmem_region *region;
+	struct hlist_node *hnode;
+	struct hlist_node *n;
+
+	mutex_lock(&sync->lock);
+	if (sync->opencnt)
+		sync->opencnt--;
+	pr_info("%s, open count =%d\n", __func__, sync->opencnt);
+	if (!sync->opencnt) {
+		/* need to clean up system resource */
+		pr_info("%s, release VFE\n", __func__);
+		if (sync->core_powered_on) {
+			if (sync->vfefn.vfe_release)
+				sync->vfefn.vfe_release(sync->pdev);
+			/*sensor release */
+			pr_info("%s, release Sensor\n", __func__);
+			sync->sctrl.s_release();
+			CDBG("%s, msm_camio_sensor_clk_off\n", __func__);
+			msm_camio_sensor_clk_off(sync->pdev);
+			if (sync->sfctrl.strobe_flash_release) {
+				CDBG("%s, strobe_flash_release\n", __func__);
+				sync->sfctrl.strobe_flash_release(
+				sync->sdata->strobe_flash_data, 1);
+			}
+		}
+		kfree(sync->cropinfo);
+		sync->cropinfo = NULL;
+		sync->croplen = 0;
+		CDBG("%s, free frame pmem region\n", __func__);
+		hlist_for_each_entry_safe(region, hnode, n,
+				&sync->pmem_frames, list) {
+			hlist_del(hnode);
+			put_pmem_file(region->file);
+			kfree(region);
+		}
+		CDBG("%s, free stats pmem region\n", __func__);
+		hlist_for_each_entry_safe(region, hnode, n,
+				&sync->pmem_stats, list) {
+			hlist_del(hnode);
+			put_pmem_file(region->file);
+			kfree(region);
+		}
+		msm_queue_drain(&sync->pict_q, list_pict);
+		msm_queue_drain(&sync->event_q, list_config);
+
+		wake_unlock(&sync->wake_lock);
+		sync->apps_id = NULL;
+		sync->core_powered_on = 0;
+	}
+	mutex_unlock(&sync->lock);
+
+	return 0;
+}
+
+static int msm_release_config(struct inode *node, struct file *filep)
+{
+	int rc;
+	struct msm_cam_device *pmsm = filep->private_data;
+	pr_info("%s: %s\n", __func__, filep->f_path.dentry->d_name.name);
+	rc = __msm_release(pmsm->sync);
+	if (!rc) {
+		msm_queue_drain(&pmsm->sync->event_q, list_config);
+		atomic_set(&pmsm->opened, 0);
+	}
+	return rc;
+}
+
+static int msm_release_control(struct inode *node, struct file *filep)
+{
+	int rc;
+	struct msm_control_device *ctrl_pmsm = filep->private_data;
+	struct msm_cam_device *pmsm = ctrl_pmsm->pmsm;
+	pr_info("%s: %s\n", __func__, filep->f_path.dentry->d_name.name);
+	g_v4l2_opencnt--;
+	mutex_lock(&pmsm->sync->lock);
+	if (pmsm->sync->core_powered_on && pmsm->sync->vfefn.vfe_stop) {
+		pr_info("%s, stop vfe if active\n", __func__);
+		pmsm->sync->vfefn.vfe_stop();
+	}
+	mutex_unlock(&pmsm->sync->lock);
+	rc = __msm_release(pmsm->sync);
+	if (!rc) {
+		msm_queue_drain(&ctrl_pmsm->ctrl_q, list_control);
+		kfree(ctrl_pmsm);
+	}
+	return rc;
+}
+
+static int msm_release_frame(struct inode *node, struct file *filep)
+{
+	int rc;
+	struct msm_cam_device *pmsm = filep->private_data;
+	pr_info("%s: %s\n", __func__, filep->f_path.dentry->d_name.name);
+	rc = __msm_release(pmsm->sync);
+	if (!rc) {
+		msm_queue_drain(&pmsm->sync->frame_q, list_frame);
+		atomic_set(&pmsm->opened, 0);
+	}
+	return rc;
+}
+
+
+static int msm_release_pic(struct inode *node, struct file *filep)
+{
+	int rc;
+	struct msm_cam_device *pmsm = filep->private_data;
+	CDBG("%s: %s\n", __func__, filep->f_path.dentry->d_name.name);
+	rc = __msm_release(pmsm->sync);
+	if (!rc) {
+		msm_queue_drain(&pmsm->sync->pict_q, list_pict);
+		atomic_set(&pmsm->opened, 0);
+	}
+	return rc;
+}
+
+static int msm_unblock_poll_pic(struct msm_sync *sync)
+{
+	unsigned long flags;
+	CDBG("%s\n", __func__);
+	spin_lock_irqsave(&sync->pict_q.lock, flags);
+	sync->unblock_poll_pic_frame = 1;
+	wake_up(&sync->pict_q.wait);
+	spin_unlock_irqrestore(&sync->pict_q.lock, flags);
+	return 0;
+}
+
+static int msm_unblock_poll_frame(struct msm_sync *sync)
+{
+	unsigned long flags;
+	CDBG("%s\n", __func__);
+	spin_lock_irqsave(&sync->frame_q.lock, flags);
+	sync->unblock_poll_frame = 1;
+	wake_up(&sync->frame_q.wait);
+	spin_unlock_irqrestore(&sync->frame_q.lock, flags);
+	return 0;
+}
+
+static unsigned int __msm_poll_frame(struct msm_sync *sync,
+		struct file *filep,
+		struct poll_table_struct *pll_table)
+{
+	int rc = 0;
+	unsigned long flags;
+
+	poll_wait(filep, &sync->frame_q.wait, pll_table);
+
+	spin_lock_irqsave(&sync->frame_q.lock, flags);
+	if (!list_empty_careful(&sync->frame_q.list))
+		/* frame ready */
+		rc = POLLIN | POLLRDNORM;
+	if (sync->unblock_poll_frame) {
+		CDBG("%s: sync->unblock_poll_frame is true\n", __func__);
+		rc |= POLLPRI;
+		sync->unblock_poll_frame = 0;
+	}
+	spin_unlock_irqrestore(&sync->frame_q.lock, flags);
+
+	return rc;
+}
+
+static unsigned int __msm_poll_pic(struct msm_sync *sync,
+		struct file *filep,
+		struct poll_table_struct *pll_table)
+{
+	int rc = 0;
+	unsigned long flags;
+
+	poll_wait(filep, &sync->pict_q.wait , pll_table);
+	spin_lock_irqsave(&sync->abort_pict_lock, flags);
+	if (sync->get_pic_abort == 1) {
+		/* TODO: need to pass an error case */
+		sync->get_pic_abort = 0;
+	}
+	spin_unlock_irqrestore(&sync->abort_pict_lock, flags);
+
+	spin_lock_irqsave(&sync->pict_q.lock, flags);
+	if (!list_empty_careful(&sync->pict_q.list))
+		/* frame ready */
+		rc = POLLIN | POLLRDNORM;
+	if (sync->unblock_poll_pic_frame) {
+		CDBG("%s: sync->unblock_poll_pic_frame is true\n", __func__);
+		rc |= POLLPRI;
+		sync->unblock_poll_pic_frame = 0;
+	}
+	spin_unlock_irqrestore(&sync->pict_q.lock, flags);
+
+	return rc;
+}
+
+static unsigned int msm_poll_frame(struct file *filep,
+	struct poll_table_struct *pll_table)
+{
+	struct msm_cam_device *pmsm = filep->private_data;
+	return __msm_poll_frame(pmsm->sync, filep, pll_table);
+}
+
+static unsigned int msm_poll_pic(struct file *filep,
+	struct poll_table_struct *pll_table)
+{
+	struct msm_cam_device *pmsm = filep->private_data;
+	return __msm_poll_pic(pmsm->sync, filep, pll_table);
+}
+
+static unsigned int __msm_poll_config(struct msm_sync *sync,
+		struct file *filep,
+		struct poll_table_struct *pll_table)
+{
+	int rc = 0;
+	unsigned long flags;
+
+	poll_wait(filep, &sync->event_q.wait, pll_table);
+
+	spin_lock_irqsave(&sync->event_q.lock, flags);
+	if (!list_empty_careful(&sync->event_q.list))
+		/* event ready */
+		rc = POLLIN | POLLRDNORM;
+	spin_unlock_irqrestore(&sync->event_q.lock, flags);
+
+	return rc;
+}
+
+static unsigned int msm_poll_config(struct file *filep,
+	struct poll_table_struct *pll_table)
+{
+	struct msm_cam_device *pmsm = filep->private_data;
+	return __msm_poll_config(pmsm->sync, filep, pll_table);
+}
+
+/*
+ * This function executes in interrupt context.
+ */
+
+static void *msm_vfe_sync_alloc(int size,
+			void *syncdata __attribute__((unused)),
+			gfp_t gfp)
+{
+	struct msm_queue_cmd *qcmd =
+		kzalloc(sizeof(struct msm_queue_cmd) + size, gfp);
+	if (qcmd) {
+		atomic_set(&qcmd->on_heap, 1);
+		return qcmd + 1;
+	}
+	return NULL;
+}
+
+static void *msm_vpe_sync_alloc(int size,
+			void *syncdata __attribute__((unused)),
+			gfp_t gfp)
+{
+	struct msm_queue_cmd *qcmd =
+		kzalloc(sizeof(struct msm_queue_cmd) + size, gfp);
+	if (qcmd) {
+		atomic_set(&qcmd->on_heap, 1);
+		return qcmd + 1;
+	}
+	return NULL;
+}
+
+static void msm_vfe_sync_free(void *ptr)
+{
+	if (ptr) {
+		struct msm_queue_cmd *qcmd =
+			(struct msm_queue_cmd *)ptr;
+		qcmd--;
+		if (atomic_read(&qcmd->on_heap))
+			kfree(qcmd);
+	}
+}
+
+static void msm_vpe_sync_free(void *ptr)
+{
+	if (ptr) {
+		struct msm_queue_cmd *qcmd =
+			(struct msm_queue_cmd *)ptr;
+		qcmd--;
+		if (atomic_read(&qcmd->on_heap))
+			kfree(qcmd);
+	}
+}
+
+/*
+ * This function executes in interrupt context.
+ */
+
+static void msm_vfe_sync(struct msm_vfe_resp *vdata,
+		enum msm_queue qtype, void *syncdata,
+		gfp_t gfp)
+{
+	struct msm_queue_cmd *qcmd = NULL;
+	struct msm_sync *sync = (struct msm_sync *)syncdata;
+	unsigned long flags;
+
+	if (!sync) {
+		pr_err("%s: no context in dsp callback.\n", __func__);
+		return;
+	}
+
+	qcmd = ((struct msm_queue_cmd *)vdata) - 1;
+	qcmd->type = qtype;
+	qcmd->command = vdata;
+
+	ktime_get_ts(&(qcmd->ts));
+
+	if (qtype != MSM_CAM_Q_VFE_MSG)
+		goto vfe_for_config;
+
+	CDBG("%s: vdata->type %d\n", __func__, vdata->type);
+
+	switch (vdata->type) {
+	case VFE_MSG_OUTPUT_P:
+		if (sync->pp_mask & PP_PREV) {
+			CDBG("%s: PP_PREV in progress: phy_y %x phy_cbcr %x\n",
+				__func__,
+				vdata->phy.y_phy,
+				vdata->phy.cbcr_phy);
+			spin_lock_irqsave(&pp_prev_spinlock, flags);
+			if (sync->pp_prev)
+				CDBG("%s: overwriting pp_prev!\n",
+					__func__);
+			CDBG("%s: sending preview to config\n", __func__);
+			sync->pp_prev = qcmd;
+			spin_unlock_irqrestore(&pp_prev_spinlock, flags);
+			sync->pp_frame_avail = 1;
+			if (atomic_read(&qcmd->on_heap))
+				atomic_add(1, &qcmd->on_heap);
+			break;
+		}
+		CDBG("%s: msm_enqueue frame_q\n", __func__);
+		if (sync->stereocam_enabled)
+			CDBG("%s: Enqueue VFE_MSG_OUTPUT_P to event_q for "
+				"stereo processing\n", __func__);
+		else {
+			if (sync->frame_q.len <= 100 &&
+				sync->event_q.len <= 100) {
+				if (atomic_read(&qcmd->on_heap))
+					atomic_add(1, &qcmd->on_heap);
+				msm_enqueue(&sync->frame_q, &qcmd->list_frame);
+			} else {
+				pr_err("%s, Error Queue limit exceeded "
+					"f_q = %d, e_q = %d\n",	__func__,
+					sync->frame_q.len, sync->event_q.len);
+				free_qcmd(qcmd);
+				return;
+			}
+		}
+		break;
+
+	case VFE_MSG_OUTPUT_T:
+		if (sync->stereocam_enabled) {
+			spin_lock_irqsave(&pp_stereocam_spinlock, flags);
+
+			/* if out1/2 is currently in progress, save the qcmd
+			and issue only ionce the 1st one completes the 3D
+			pipeline */
+			if (STEREO_SNAP_BUFFER1_PROCESSING ==
+				sync->stereo_state) {
+				sync->pp_stereocam2 = qcmd;
+				spin_unlock_irqrestore(&pp_stereocam_spinlock,
+					flags);
+				if (atomic_read(&qcmd->on_heap))
+					atomic_add(1, &qcmd->on_heap);
+				CDBG("%s: snapshot stereo in progress\n",
+					__func__);
+				return;
+			}
+
+			if (sync->pp_stereocam)
+				CDBG("%s: overwriting pp_stereocam!\n",
+					__func__);
+
+			CDBG("%s: sending stereo frame to config\n", __func__);
+			sync->pp_stereocam = qcmd;
+			sync->stereo_state =
+				STEREO_SNAP_BUFFER1_PROCESSING;
+
+			spin_unlock_irqrestore(&pp_stereocam_spinlock, flags);
+
+			/* Increament on_heap by one because the same qcmd will
+			be used for VPE in msm_pp_release. */
+			if (atomic_read(&qcmd->on_heap))
+				atomic_add(1, &qcmd->on_heap);
+			CDBG("%s: Enqueue VFE_MSG_OUTPUT_T to event_q for "
+				"stereo processing.\n", __func__);
+			break;
+		}
+		if (sync->pp_mask & PP_SNAP) {
+			CDBG("%s: pp sending thumbnail to config\n",
+				__func__);
+		} else {
+			msm_enqueue(&sync->pict_q, &qcmd->list_pict);
+			return;
+		}
+
+	case VFE_MSG_OUTPUT_S:
+		if (sync->stereocam_enabled &&
+			sync->stereo_state != STEREO_RAW_SNAP_STARTED) {
+			spin_lock_irqsave(&pp_stereocam_spinlock, flags);
+
+			/* if out1/2 is currently in progress, save the qcmd
+			and issue only once the 1st one completes the 3D
+			pipeline */
+			if (STEREO_SNAP_BUFFER1_PROCESSING ==
+				sync->stereo_state) {
+				sync->pp_stereocam2 = qcmd;
+				spin_unlock_irqrestore(&pp_stereocam_spinlock,
+					flags);
+				if (atomic_read(&qcmd->on_heap))
+					atomic_add(1, &qcmd->on_heap);
+				CDBG("%s: snapshot stereo in progress\n",
+					__func__);
+				return;
+			}
+			if (sync->pp_stereocam)
+				CDBG("%s: overwriting pp_stereocam!\n",
+					__func__);
+
+			CDBG("%s: sending stereo frame to config\n", __func__);
+			sync->pp_stereocam = qcmd;
+			sync->stereo_state =
+				STEREO_SNAP_BUFFER1_PROCESSING;
+
+			spin_unlock_irqrestore(&pp_stereocam_spinlock, flags);
+
+			/* Increament on_heap by one because the same qcmd will
+			be used for VPE in msm_pp_release. */
+			if (atomic_read(&qcmd->on_heap))
+				atomic_add(1, &qcmd->on_heap);
+			CDBG("%s: Enqueue VFE_MSG_OUTPUT_S to event_q for "
+				"stereo processing.\n", __func__);
+			break;
+		}
+		if (sync->pp_mask & PP_SNAP) {
+			CDBG("%s: pp sending main image to config\n",
+				__func__);
+		} else {
+			CDBG("%s: enqueue to picture queue\n", __func__);
+			msm_enqueue(&sync->pict_q, &qcmd->list_pict);
+			return;
+		}
+		break;
+
+	case VFE_MSG_OUTPUT_V:
+		if (sync->stereocam_enabled) {
+			spin_lock_irqsave(&pp_stereocam_spinlock, flags);
+
+			if (sync->pp_stereocam)
+				CDBG("%s: overwriting pp_stereocam!\n",
+					__func__);
+
+			CDBG("%s: sending stereo frame to config\n", __func__);
+			sync->pp_stereocam = qcmd;
+
+			spin_unlock_irqrestore(&pp_stereocam_spinlock, flags);
+
+			/* Increament on_heap by one because the same qcmd will
+			be used for VPE in msm_pp_release. */
+			if (atomic_read(&qcmd->on_heap))
+				atomic_add(1, &qcmd->on_heap);
+			CDBG("%s: Enqueue VFE_MSG_OUTPUT_V to event_q for "
+				"stereo processing.\n", __func__);
+			break;
+		}
+		if (sync->vpefn.vpe_cfg_update) {
+			CDBG("dis_en = %d\n", *sync->vpefn.dis);
+			if (*(sync->vpefn.dis)) {
+				memset(&(vdata->vpe_bf), 0,
+					sizeof(vdata->vpe_bf));
+
+				if (sync->cropinfo != NULL)
+					vdata->vpe_bf.vpe_crop =
+				*(struct video_crop_t *)(sync->cropinfo);
+
+				vdata->vpe_bf.y_phy = vdata->phy.y_phy;
+				vdata->vpe_bf.cbcr_phy = vdata->phy.cbcr_phy;
+				vdata->vpe_bf.ts = (qcmd->ts);
+				vdata->vpe_bf.frame_id = vdata->phy.frame_id;
+				qcmd->command = vdata;
+				msm_enqueue_vpe(&sync->vpe_q,
+					&qcmd->list_vpe_frame);
+				return;
+			} else if (sync->vpefn.vpe_cfg_update(sync->cropinfo)) {
+				CDBG("%s: msm_enqueue video frame to vpe time "
+					"= %ld\n", __func__, qcmd->ts.tv_nsec);
+
+				sync->vpefn.send_frame_to_vpe(
+					vdata->phy.y_phy,
+					vdata->phy.cbcr_phy,
+					&(qcmd->ts), OUTPUT_TYPE_V);
+
+				free_qcmd(qcmd);
+				return;
+			} else {
+				CDBG("%s: msm_enqueue video frame_q\n",
+					__func__);
+				if (sync->liveshot_enabled) {
+					CDBG("%s: msm_enqueue liveshot\n",
+						__func__);
+					vdata->phy.output_id |= OUTPUT_TYPE_L;
+					sync->liveshot_enabled = false;
+				}
+				if (sync->frame_q.len <= 100 &&
+					sync->event_q.len <= 100) {
+						msm_enqueue(&sync->frame_q,
+							&qcmd->list_frame);
+				} else {
+					pr_err("%s, Error Queue limit exceeded\
+						f_q = %d, e_q = %d\n",
+						__func__, sync->frame_q.len,
+						sync->event_q.len);
+					free_qcmd(qcmd);
+				}
+
+				return;
+			}
+		} else {
+			CDBG("%s: msm_enqueue video frame_q\n",	__func__);
+			if (sync->frame_q.len <= 100 &&
+				sync->event_q.len <= 100) {
+				msm_enqueue(&sync->frame_q, &qcmd->list_frame);
+			} else {
+				pr_err("%s, Error Queue limit exceeded\
+					f_q = %d, e_q = %d\n",
+					__func__, sync->frame_q.len,
+					sync->event_q.len);
+				free_qcmd(qcmd);
+			}
+
+			return;
+		}
+
+	case VFE_MSG_SNAPSHOT:
+		if (sync->pp_mask & (PP_SNAP | PP_RAW_SNAP)) {
+			CDBG("%s: PP_SNAP in progress: pp_mask %x\n",
+				__func__, sync->pp_mask);
+		} else {
+			if (atomic_read(&qcmd->on_heap))
+				atomic_add(1, &qcmd->on_heap);
+			CDBG("%s: VFE_MSG_SNAPSHOT store\n",
+				__func__);
+			if (sync->stereocam_enabled &&
+				sync->stereo_state != STEREO_RAW_SNAP_STARTED) {
+				sync->pp_stereosnap = qcmd;
+				return;
+			}
+		}
+		break;
+
+	case VFE_MSG_COMMON:
+		CDBG("%s: qtype %d, comp stats, enqueue event_q.\n",
+			__func__, vdata->type);
+		break;
+
+	case VFE_MSG_GENERAL:
+		CDBG("%s: qtype %d, general msg, enqueue event_q.\n",
+			__func__, vdata->type);
+		break;
+
+	default:
+		CDBG("%s: qtype %d not handled\n", __func__, vdata->type);
+		/* fall through, send to config. */
+	}
+
+vfe_for_config:
+	CDBG("%s: msm_enqueue event_q\n", __func__);
+	if (sync->frame_q.len <= 100 && sync->event_q.len <= 100) {
+		msm_enqueue(&sync->event_q, &qcmd->list_config);
+	} else {
+		pr_err("%s, Error Queue limit exceeded f_q = %d, e_q = %d\n",
+			__func__, sync->frame_q.len, sync->event_q.len);
+		free_qcmd(qcmd);
+	}
+
+}
+
+static void msm_vpe_sync(struct msm_vpe_resp *vdata,
+	enum msm_queue qtype, void *syncdata, void *ts, gfp_t gfp)
+{
+	struct msm_queue_cmd *qcmd = NULL;
+	unsigned long flags;
+
+	struct msm_sync *sync = (struct msm_sync *)syncdata;
+	if (!sync) {
+		pr_err("%s: no context in dsp callback.\n", __func__);
+		return;
+	}
+
+	qcmd = ((struct msm_queue_cmd *)vdata) - 1;
+	qcmd->type = qtype;
+	qcmd->command = vdata;
+	qcmd->ts = *((struct timespec *)ts);
+
+	if (qtype != MSM_CAM_Q_VPE_MSG) {
+		pr_err("%s: Invalid qcmd type = %d.\n", __func__, qcmd->type);
+		free_qcmd(qcmd);
+		return;
+	}
+
+	CDBG("%s: vdata->type %d\n", __func__, vdata->type);
+	switch (vdata->type) {
+	case VPE_MSG_OUTPUT_V:
+		if (sync->liveshot_enabled) {
+			CDBG("%s: msm_enqueue liveshot %d\n", __func__,
+				sync->liveshot_enabled);
+			vdata->phy.output_id |= OUTPUT_TYPE_L;
+			sync->liveshot_enabled = false;
+		}
+		if (sync->frame_q.len <= 100 && sync->event_q.len <= 100) {
+			CDBG("%s: enqueue to frame_q from VPE\n", __func__);
+			msm_enqueue(&sync->frame_q, &qcmd->list_frame);
+		} else {
+			pr_err("%s, Error Queue limit exceeded f_q = %d, "
+				"e_q = %d\n", __func__, sync->frame_q.len,
+				sync->event_q.len);
+			free_qcmd(qcmd);
+		}
+		return;
+
+	case VPE_MSG_OUTPUT_ST_L:
+		CDBG("%s: enqueue left frame done msg to event_q from VPE\n",
+			__func__);
+		msm_enqueue(&sync->event_q, &qcmd->list_config);
+		return;
+
+	case VPE_MSG_OUTPUT_ST_R:
+		spin_lock_irqsave(&pp_stereocam_spinlock, flags);
+		CDBG("%s: received VPE_MSG_OUTPUT_ST_R state %d\n", __func__,
+			sync->stereo_state);
+
+		if (STEREO_SNAP_BUFFER1_PROCESSING == sync->stereo_state) {
+			msm_enqueue(&sync->pict_q, &qcmd->list_pict);
+			qcmd = sync->pp_stereocam2;
+			sync->pp_stereocam = sync->pp_stereocam2;
+			sync->pp_stereocam2 = NULL;
+			msm_enqueue(&sync->event_q, &qcmd->list_config);
+			sync->stereo_state =
+				STEREO_SNAP_BUFFER2_PROCESSING;
+		} else if (STEREO_SNAP_BUFFER2_PROCESSING ==
+				sync->stereo_state) {
+			sync->stereo_state = STEREO_SNAP_IDLE;
+			/* Send snapshot DONE */
+			msm_enqueue(&sync->pict_q, &qcmd->list_pict);
+			qcmd = sync->pp_stereosnap;
+			sync->pp_stereosnap = NULL;
+			CDBG("%s: send SNAPSHOT_DONE message\n", __func__);
+			msm_enqueue(&sync->event_q, &qcmd->list_config);
+		} else {
+			if (atomic_read(&qcmd->on_heap))
+				atomic_add(1, &qcmd->on_heap);
+			msm_enqueue(&sync->event_q, &qcmd->list_config);
+			if (sync->stereo_state == STEREO_VIDEO_ACTIVE) {
+				CDBG("%s: st frame to frame_q from VPE\n",
+					__func__);
+				msm_enqueue(&sync->frame_q, &qcmd->list_frame);
+			}
+		}
+		spin_unlock_irqrestore(&pp_stereocam_spinlock, flags);
+		return;
+
+	default:
+		pr_err("%s: qtype %d not handled\n", __func__, vdata->type);
+	}
+	pr_err("%s: Should not come here. Error.\n", __func__);
+}
+
+static struct msm_vpe_callback msm_vpe_s = {
+	.vpe_resp = msm_vpe_sync,
+	.vpe_alloc = msm_vpe_sync_alloc,
+	.vpe_free = msm_vpe_sync_free,
+};
+
+static struct msm_vfe_callback msm_vfe_s = {
+	.vfe_resp = msm_vfe_sync,
+	.vfe_alloc = msm_vfe_sync_alloc,
+	.vfe_free = msm_vfe_sync_free,
+};
+
+static int __msm_open(struct msm_cam_device *pmsm, const char *const apps_id,
+			int is_controlnode)
+{
+	int rc = 0;
+	struct msm_sync *sync = pmsm->sync;
+
+	mutex_lock(&sync->lock);
+	if (sync->apps_id && strcmp(sync->apps_id, apps_id)
+				&& (!strcmp(MSM_APPS_ID_V4L2, apps_id))) {
+		pr_err("%s(%s): sensor %s is already opened for %s\n",
+			__func__,
+			apps_id,
+			sync->sdata->sensor_name,
+			sync->apps_id);
+		rc = -EBUSY;
+		goto msm_open_done;
+	}
+
+	sync->apps_id = apps_id;
+
+	if (!sync->core_powered_on && !is_controlnode) {
+		wake_lock(&sync->wake_lock);
+
+		msm_camvfe_fn_init(&sync->vfefn, sync);
+		if (sync->vfefn.vfe_init) {
+			sync->pp_frame_avail = 0;
+			sync->get_pic_abort = 0;
+			rc = msm_camio_sensor_clk_on(sync->pdev);
+			if (rc < 0) {
+				pr_err("%s: setting sensor clocks failed: %d\n",
+					__func__, rc);
+				goto msm_open_err;
+			}
+			rc = sync->sctrl.s_init(sync->sdata);
+			if (rc < 0) {
+				pr_err("%s: sensor init failed: %d\n",
+					__func__, rc);
+				msm_camio_sensor_clk_off(sync->pdev);
+				goto msm_open_err;
+			}
+			rc = sync->vfefn.vfe_init(&msm_vfe_s,
+				sync->pdev);
+			if (rc < 0) {
+				pr_err("%s: vfe_init failed at %d\n",
+					__func__, rc);
+				sync->sctrl.s_release();
+				msm_camio_sensor_clk_off(sync->pdev);
+				goto msm_open_err;
+			}
+		} else {
+			pr_err("%s: no sensor init func\n", __func__);
+			rc = -ENODEV;
+			goto msm_open_err;
+		}
+		msm_camvpe_fn_init(&sync->vpefn, sync);
+
+		spin_lock_init(&sync->abort_pict_lock);
+		spin_lock_init(&pp_prev_spinlock);
+		spin_lock_init(&pp_stereocam_spinlock);
+		spin_lock_init(&st_frame_spinlock);
+		if (rc >= 0) {
+			msm_region_init(sync);
+			if (sync->vpefn.vpe_reg)
+				sync->vpefn.vpe_reg(&msm_vpe_s);
+			sync->unblock_poll_frame = 0;
+			sync->unblock_poll_pic_frame = 0;
+		}
+		sync->core_powered_on = 1;
+	}
+	sync->opencnt++;
+
+msm_open_done:
+	mutex_unlock(&sync->lock);
+	return rc;
+
+msm_open_err:
+	atomic_set(&pmsm->opened, 0);
+	mutex_unlock(&sync->lock);
+	return rc;
+}
+
+static int msm_open_common(struct inode *inode, struct file *filep,
+			int once, int is_controlnode)
+{
+	int rc;
+	struct msm_cam_device *pmsm =
+		container_of(inode->i_cdev, struct msm_cam_device, cdev);
+
+	CDBG("%s: open %s\n", __func__, filep->f_path.dentry->d_name.name);
+
+	if (atomic_cmpxchg(&pmsm->opened, 0, 1) && once) {
+		pr_err("%s: %s is already opened.\n",
+			__func__,
+			filep->f_path.dentry->d_name.name);
+		return -EBUSY;
+	}
+
+	rc = nonseekable_open(inode, filep);
+	if (rc < 0) {
+		pr_err("%s: nonseekable_open error %d\n", __func__, rc);
+		return rc;
+	}
+
+	rc = __msm_open(pmsm, MSM_APPS_ID_PROP, is_controlnode);
+	if (rc < 0)
+		return rc;
+	filep->private_data = pmsm;
+	CDBG("%s: rc %d\n", __func__, rc);
+	return rc;
+}
+
+static int msm_open(struct inode *inode, struct file *filep)
+{
+	return msm_open_common(inode, filep, 1, 0);
+}
+
+static int msm_open_control(struct inode *inode, struct file *filep)
+{
+	int rc;
+
+	struct msm_control_device *ctrl_pmsm =
+		kmalloc(sizeof(struct msm_control_device), GFP_KERNEL);
+	if (!ctrl_pmsm)
+		return -ENOMEM;
+
+	rc = msm_open_common(inode, filep, 0, 1);
+	if (rc < 0) {
+		kfree(ctrl_pmsm);
+		return rc;
+	}
+	ctrl_pmsm->pmsm = filep->private_data;
+	filep->private_data = ctrl_pmsm;
+
+	msm_queue_init(&ctrl_pmsm->ctrl_q, "control");
+
+	if (!g_v4l2_opencnt)
+		g_v4l2_control_device = ctrl_pmsm;
+	g_v4l2_opencnt++;
+	CDBG("%s: rc %d\n", __func__, rc);
+	return rc;
+}
+
+static const struct file_operations msm_fops_config = {
+	.owner = THIS_MODULE,
+	.open = msm_open,
+	.unlocked_ioctl = msm_ioctl_config,
+	.release = msm_release_config,
+	.poll = msm_poll_config,
+};
+
+static const struct file_operations msm_fops_control = {
+	.owner = THIS_MODULE,
+	.open = msm_open_control,
+	.unlocked_ioctl = msm_ioctl_control,
+	.release = msm_release_control,
+};
+
+static const struct file_operations msm_fops_frame = {
+	.owner = THIS_MODULE,
+	.open = msm_open,
+	.unlocked_ioctl = msm_ioctl_frame,
+	.release = msm_release_frame,
+	.poll = msm_poll_frame,
+};
+
+static const struct file_operations msm_fops_pic = {
+	.owner = THIS_MODULE,
+	.open = msm_open,
+	.unlocked_ioctl = msm_ioctl_pic,
+	.release = msm_release_pic,
+	.poll = msm_poll_pic,
+};
+
+static int msm_setup_cdev(struct msm_cam_device *msm,
+			int node,
+			dev_t devno,
+			const char *suffix,
+			const struct file_operations *fops)
+{
+	int rc = -ENODEV;
+
+	struct device *device =
+		device_create(msm_class, NULL,
+			devno, NULL,
+			"%s%d", suffix, node);
+
+	if (IS_ERR(device)) {
+		rc = PTR_ERR(device);
+		pr_err("%s: error creating device: %d\n", __func__, rc);
+		return rc;
+	}
+
+	cdev_init(&msm->cdev, fops);
+	msm->cdev.owner = THIS_MODULE;
+
+	rc = cdev_add(&msm->cdev, devno, 1);
+	if (rc < 0) {
+		pr_err("%s: error adding cdev: %d\n", __func__, rc);
+		device_destroy(msm_class, devno);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int msm_tear_down_cdev(struct msm_cam_device *msm, dev_t devno)
+{
+	cdev_del(&msm->cdev);
+	device_destroy(msm_class, devno);
+	return 0;
+}
+
+static int msm_sync_init(struct msm_sync *sync,
+		struct platform_device *pdev,
+		int (*sensor_probe)(const struct msm_camera_sensor_info *,
+				struct msm_sensor_ctrl *))
+{
+	int rc = 0;
+	struct msm_sensor_ctrl sctrl;
+	sync->sdata = pdev->dev.platform_data;
+
+	msm_queue_init(&sync->event_q, "event");
+	msm_queue_init(&sync->frame_q, "frame");
+	msm_queue_init(&sync->pict_q, "pict");
+	msm_queue_init(&sync->vpe_q, "vpe");
+
+	wake_lock_init(&sync->wake_lock, WAKE_LOCK_IDLE, "msm_camera");
+
+	rc = msm_camio_probe_on(pdev);
+	if (rc < 0) {
+		wake_lock_destroy(&sync->wake_lock);
+		return rc;
+	}
+	rc = sensor_probe(sync->sdata, &sctrl);
+	if (rc >= 0) {
+		sync->pdev = pdev;
+		sync->sctrl = sctrl;
+	}
+	msm_camio_probe_off(pdev);
+	if (rc < 0) {
+		pr_err("%s: failed to initialize %s\n",
+			__func__,
+			sync->sdata->sensor_name);
+		wake_lock_destroy(&sync->wake_lock);
+		return rc;
+	}
+
+	sync->opencnt = 0;
+	sync->core_powered_on = 0;
+	sync->ignore_qcmd = false;
+	sync->ignore_qcmd_type = -1;
+	mutex_init(&sync->lock);
+	if (sync->sdata->strobe_flash_data) {
+		sync->sdata->strobe_flash_data->state = 0;
+		spin_lock_init(&sync->sdata->strobe_flash_data->spin_lock);
+	}
+	CDBG("%s: initialized %s\n", __func__, sync->sdata->sensor_name);
+	return rc;
+}
+
+static int msm_sync_destroy(struct msm_sync *sync)
+{
+	wake_lock_destroy(&sync->wake_lock);
+	return 0;
+}
+
+static int msm_device_init(struct msm_cam_device *pmsm,
+		struct msm_sync *sync,
+		int node)
+{
+	int dev_num = 4 * node;
+	int rc = msm_setup_cdev(pmsm, node,
+		MKDEV(MAJOR(msm_devno), dev_num),
+		"control", &msm_fops_control);
+	if (rc < 0) {
+		pr_err("%s: error creating control node: %d\n", __func__, rc);
+		return rc;
+	}
+
+	rc = msm_setup_cdev(pmsm + 1, node,
+		MKDEV(MAJOR(msm_devno), dev_num + 1),
+		"config", &msm_fops_config);
+	if (rc < 0) {
+		pr_err("%s: error creating config node: %d\n", __func__, rc);
+		msm_tear_down_cdev(pmsm, MKDEV(MAJOR(msm_devno),
+				dev_num));
+		return rc;
+	}
+
+	rc = msm_setup_cdev(pmsm + 2, node,
+		MKDEV(MAJOR(msm_devno), dev_num + 2),
+		"frame", &msm_fops_frame);
+	if (rc < 0) {
+		pr_err("%s: error creating frame node: %d\n", __func__, rc);
+		msm_tear_down_cdev(pmsm,
+			MKDEV(MAJOR(msm_devno), dev_num));
+		msm_tear_down_cdev(pmsm + 1,
+			MKDEV(MAJOR(msm_devno), dev_num + 1));
+		return rc;
+	}
+
+	rc = msm_setup_cdev(pmsm + 3, node,
+		MKDEV(MAJOR(msm_devno), dev_num + 3),
+		"pic", &msm_fops_pic);
+	if (rc < 0) {
+		pr_err("%s: error creating pic node: %d\n", __func__, rc);
+		msm_tear_down_cdev(pmsm,
+			MKDEV(MAJOR(msm_devno), dev_num));
+		msm_tear_down_cdev(pmsm + 1,
+			MKDEV(MAJOR(msm_devno), dev_num + 1));
+		msm_tear_down_cdev(pmsm + 2,
+			MKDEV(MAJOR(msm_devno), dev_num + 2));
+		return rc;
+	}
+
+
+	atomic_set(&pmsm[0].opened, 0);
+	atomic_set(&pmsm[1].opened, 0);
+	atomic_set(&pmsm[2].opened, 0);
+	atomic_set(&pmsm[3].opened, 0);
+
+	pmsm[0].sync = sync;
+	pmsm[1].sync = sync;
+	pmsm[2].sync = sync;
+	pmsm[3].sync = sync;
+
+	return rc;
+}
+
+int msm_camera_drv_start(struct platform_device *dev,
+		int (*sensor_probe)(const struct msm_camera_sensor_info *,
+			struct msm_sensor_ctrl *))
+{
+	struct msm_cam_device *pmsm = NULL;
+	struct msm_sync *sync;
+	int rc = -ENODEV;
+
+	if (camera_node >= MSM_MAX_CAMERA_SENSORS) {
+		pr_err("%s: too many camera sensors\n", __func__);
+		return rc;
+	}
+
+	if (!msm_class) {
+		/* There are three device nodes per sensor */
+		rc = alloc_chrdev_region(&msm_devno, 0,
+				4 * MSM_MAX_CAMERA_SENSORS,
+				"msm_camera");
+		if (rc < 0) {
+			pr_err("%s: failed to allocate chrdev: %d\n", __func__,
+				rc);
+			return rc;
+		}
+
+		msm_class = class_create(THIS_MODULE, "msm_camera");
+		if (IS_ERR(msm_class)) {
+			rc = PTR_ERR(msm_class);
+			pr_err("%s: create device class failed: %d\n",
+				__func__, rc);
+			return rc;
+		}
+	}
+
+	pmsm = kzalloc(sizeof(struct msm_cam_device) * 4 +
+			sizeof(struct msm_sync), GFP_ATOMIC);
+	if (!pmsm)
+		return -ENOMEM;
+	sync = (struct msm_sync *)(pmsm + 4);
+
+	rc = msm_sync_init(sync, dev, sensor_probe);
+	if (rc < 0) {
+		kfree(pmsm);
+		return rc;
+	}
+
+	CDBG("%s: setting camera node %d\n", __func__, camera_node);
+	rc = msm_device_init(pmsm, sync, camera_node);
+	if (rc < 0) {
+		msm_sync_destroy(sync);
+		kfree(pmsm);
+		return rc;
+	}
+
+	camera_type[camera_node] = sync->sctrl.s_camera_type;
+	sensor_mount_angle[camera_node] = sync->sctrl.s_mount_angle;
+	camera_node++;
+
+	list_add(&sync->list, &msm_sensors);
+	return rc;
+}
+EXPORT_SYMBOL(msm_camera_drv_start);
diff --git a/drivers/media/video/msm/msm_gemini_common.h b/drivers/media/video/msm/msm_gemini_common.h
new file mode 100644
index 0000000..0ddedc5
--- /dev/null
+++ b/drivers/media/video/msm/msm_gemini_common.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef MSM_GEMINI_COMMON_H
+#define MSM_GEMINI_COMMON_H
+
+#define MSM_GEMINI_DEBUG
+#ifdef MSM_GEMINI_DEBUG
+#define GMN_DBG(fmt, args...) pr_debug(fmt, ##args)
+#else
+#define GMN_DBG(fmt, args...) do { } while (0)
+#endif
+
+#define GMN_PR_ERR   pr_err
+
+enum GEMINI_MODE {
+	GEMINI_MODE_DISABLE,
+	GEMINI_MODE_OFFLINE,
+	GEMINI_MODE_REALTIME,
+	GEMINI_MODE_REALTIME_ROTATION
+};
+
+enum GEMINI_ROTATION {
+	GEMINI_ROTATION_0,
+	GEMINI_ROTATION_90,
+	GEMINI_ROTATION_180,
+	GEMINI_ROTATION_270
+};
+
+#endif /* MSM_GEMINI_COMMON_H */
diff --git a/drivers/media/video/msm/msm_gemini_core.c b/drivers/media/video/msm/msm_gemini_core.c
new file mode 100644
index 0000000..58c2e7c
--- /dev/null
+++ b/drivers/media/video/msm/msm_gemini_core.c
@@ -0,0 +1,249 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include "msm_gemini_hw.h"
+#include "msm_gemini_core.h"
+#include "msm_gemini_platform.h"
+#include "msm_gemini_common.h"
+
+static struct msm_gemini_hw_pingpong fe_pingpong_buf;
+static struct msm_gemini_hw_pingpong we_pingpong_buf;
+static int we_pingpong_index;
+static int reset_done_ack;
+static spinlock_t reset_lock;
+static wait_queue_head_t reset_wait;
+
+int msm_gemini_core_reset(uint8_t op_mode, void *base, int size)
+{
+	unsigned long flags;
+	int rc = 0;
+	int tm = 500; /*500ms*/
+	memset(&fe_pingpong_buf, 0, sizeof(fe_pingpong_buf));
+	fe_pingpong_buf.is_fe = 1;
+	we_pingpong_index = 0;
+	memset(&we_pingpong_buf, 0, sizeof(we_pingpong_buf));
+	spin_lock_irqsave(&reset_lock, flags);
+	reset_done_ack = 0;
+	msm_gemini_hw_reset(base, size);
+	spin_unlock_irqrestore(&reset_lock, flags);
+	rc = wait_event_interruptible_timeout(
+			reset_wait,
+			reset_done_ack,
+			msecs_to_jiffies(tm));
+
+	if (!reset_done_ack) {
+		GMN_DBG("%s: reset ACK failed %d", __func__, rc);
+		return -EBUSY;
+	}
+
+	GMN_DBG("%s: reset_done_ack rc %d", __func__, rc);
+	spin_lock_irqsave(&reset_lock, flags);
+	reset_done_ack = 0;
+	spin_unlock_irqrestore(&reset_lock, flags);
+
+	if (op_mode == MSM_GEMINI_MODE_REALTIME_ENCODE) {
+		/* Nothing needed for fe buffer cfg, config we only */
+		msm_gemini_hw_we_buffer_cfg(1);
+	} else {
+		/* Nothing needed for fe buffer cfg, config we only */
+		msm_gemini_hw_we_buffer_cfg(0);
+	}
+
+	/* @todo wait for reset done irq */
+
+	return 0;
+}
+
+void msm_gemini_core_release(int release_buf)
+{
+	int i = 0;
+	for (i = 0; i < 2; i++) {
+		if (we_pingpong_buf.buf_status[i] && release_buf)
+			msm_gemini_platform_p2v(we_pingpong_buf.buf[i].file);
+		we_pingpong_buf.buf_status[i] = 0;
+	}
+}
+
+void msm_gemini_core_init(void)
+{
+	init_waitqueue_head(&reset_wait);
+	spin_lock_init(&reset_lock);
+}
+
+int msm_gemini_core_fe_start(void)
+{
+	msm_gemini_hw_fe_start();
+	return 0;
+}
+
+/* fetch engine */
+int msm_gemini_core_fe_buf_update(struct msm_gemini_core_buf *buf)
+{
+	GMN_DBG("%s:%d] 0x%08x %d 0x%08x %d\n", __func__, __LINE__,
+		(int) buf->y_buffer_addr, buf->y_len,
+		(int) buf->cbcr_buffer_addr, buf->cbcr_len);
+	return msm_gemini_hw_pingpong_update(&fe_pingpong_buf, buf);
+}
+
+void *msm_gemini_core_fe_pingpong_irq(int gemini_irq_status, void *context)
+{
+	return msm_gemini_hw_pingpong_irq(&fe_pingpong_buf);
+}
+
+/* write engine */
+int msm_gemini_core_we_buf_update(struct msm_gemini_core_buf *buf)
+{
+	int rc;
+	GMN_DBG("%s:%d] 0x%08x 0x%08x %d\n", __func__, __LINE__,
+		(int) buf->y_buffer_addr, (int) buf->cbcr_buffer_addr,
+		buf->y_len);
+	we_pingpong_buf.buf_status[we_pingpong_index] = 0;
+	we_pingpong_index = (we_pingpong_index + 1)%2;
+	rc = msm_gemini_hw_pingpong_update(&we_pingpong_buf, buf);
+	return 0;
+}
+
+int msm_gemini_core_we_buf_reset(struct msm_gemini_hw_buf *buf)
+{
+	int i = 0;
+	for (i = 0; i < 2; i++) {
+		if (we_pingpong_buf.buf[i].y_buffer_addr
+					== buf->y_buffer_addr)
+			we_pingpong_buf.buf_status[i] = 0;
+	}
+	return 0;
+}
+
+void *msm_gemini_core_we_pingpong_irq(int gemini_irq_status, void *context)
+{
+	GMN_DBG("%s:%d]\n", __func__, __LINE__);
+
+	return msm_gemini_hw_pingpong_irq(&we_pingpong_buf);
+}
+
+void *msm_gemini_core_framedone_irq(int gemini_irq_status, void *context)
+{
+	struct msm_gemini_hw_buf *buf_p;
+
+	GMN_DBG("%s:%d]\n", __func__, __LINE__);
+
+	buf_p = msm_gemini_hw_pingpong_active_buffer(&we_pingpong_buf);
+	if (buf_p) {
+		buf_p->framedone_len = msm_gemini_hw_encode_output_size();
+		GMN_DBG("%s:%d] framedone_len %d\n", __func__, __LINE__,
+			buf_p->framedone_len);
+	}
+
+	return buf_p;
+}
+
+void *msm_gemini_core_reset_ack_irq(int gemini_irq_status, void *context)
+{
+	/* @todo return the status back to msm_gemini_core_reset */
+	GMN_DBG("%s:%d]\n", __func__, __LINE__);
+	return NULL;
+}
+
+void *msm_gemini_core_err_irq(int gemini_irq_status, void *context)
+{
+	GMN_PR_ERR("%s:%d]\n", __func__, gemini_irq_status);
+	return NULL;
+}
+
+static int (*msm_gemini_irq_handler) (int, void *, void *);
+
+irqreturn_t msm_gemini_core_irq(int irq_num, void *context)
+{
+	void *data = NULL;
+	unsigned long flags;
+	int gemini_irq_status;
+
+	GMN_DBG("%s:%d] irq_num = %d\n", __func__, __LINE__, irq_num);
+
+	spin_lock_irqsave(&reset_lock, flags);
+	reset_done_ack = 1;
+	spin_unlock_irqrestore(&reset_lock, flags);
+	gemini_irq_status = msm_gemini_hw_irq_get_status();
+
+	GMN_DBG("%s:%d] gemini_irq_status = %0x\n", __func__, __LINE__,
+		gemini_irq_status);
+
+	/*For reset and framedone IRQs, clear all bits*/
+	if (gemini_irq_status & 0x400) {
+		wake_up(&reset_wait);
+		msm_gemini_hw_irq_clear(HWIO_JPEG_IRQ_CLEAR_RMSK,
+			JPEG_IRQ_CLEAR_ALL);
+	} else if (gemini_irq_status & 0x1) {
+		msm_gemini_hw_irq_clear(HWIO_JPEG_IRQ_CLEAR_RMSK,
+			JPEG_IRQ_CLEAR_ALL);
+	} else {
+		msm_gemini_hw_irq_clear(HWIO_JPEG_IRQ_CLEAR_RMSK,
+			gemini_irq_status);
+	}
+
+	if (msm_gemini_hw_irq_is_frame_done(gemini_irq_status)) {
+		data = msm_gemini_core_framedone_irq(gemini_irq_status,
+			context);
+		if (msm_gemini_irq_handler)
+			msm_gemini_irq_handler(
+				MSM_GEMINI_HW_MASK_COMP_FRAMEDONE,
+				context, data);
+	}
+
+	if (msm_gemini_hw_irq_is_fe_pingpong(gemini_irq_status)) {
+		data = msm_gemini_core_fe_pingpong_irq(gemini_irq_status,
+			context);
+		if (msm_gemini_irq_handler)
+			msm_gemini_irq_handler(MSM_GEMINI_HW_MASK_COMP_FE,
+				context, data);
+	}
+
+	if (msm_gemini_hw_irq_is_we_pingpong(gemini_irq_status) &&
+	    !msm_gemini_hw_irq_is_frame_done(gemini_irq_status)) {
+		data = msm_gemini_core_we_pingpong_irq(gemini_irq_status,
+			context);
+		if (msm_gemini_irq_handler)
+			msm_gemini_irq_handler(MSM_GEMINI_HW_MASK_COMP_WE,
+				context, data);
+	}
+
+	if (msm_gemini_hw_irq_is_reset_ack(gemini_irq_status)) {
+		data = msm_gemini_core_reset_ack_irq(gemini_irq_status,
+			context);
+		if (msm_gemini_irq_handler)
+			msm_gemini_irq_handler(
+				MSM_GEMINI_HW_MASK_COMP_RESET_ACK,
+				context, data);
+	}
+
+	/* Unexpected/unintended HW interrupt */
+	if (msm_gemini_hw_irq_is_err(gemini_irq_status)) {
+		data = msm_gemini_core_err_irq(gemini_irq_status, context);
+		if (msm_gemini_irq_handler)
+			msm_gemini_irq_handler(MSM_GEMINI_HW_MASK_COMP_ERR,
+				context, data);
+	}
+
+	return IRQ_HANDLED;
+}
+
+void msm_gemini_core_irq_install(int (*irq_handler) (int, void *, void *))
+{
+	msm_gemini_irq_handler = irq_handler;
+}
+
+void msm_gemini_core_irq_remove(void)
+{
+	msm_gemini_irq_handler = NULL;
+}
diff --git a/drivers/media/video/msm/msm_gemini_core.h b/drivers/media/video/msm/msm_gemini_core.h
new file mode 100644
index 0000000..f240505
--- /dev/null
+++ b/drivers/media/video/msm/msm_gemini_core.h
@@ -0,0 +1,35 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef MSM_GEMINI_CORE_H
+#define MSM_GEMINI_CORE_H
+
+#include <linux/interrupt.h>
+#include "msm_gemini_hw.h"
+
+#define msm_gemini_core_buf msm_gemini_hw_buf
+
+irqreturn_t msm_gemini_core_irq(int irq_num, void *context);
+
+void msm_gemini_core_irq_install(int (*irq_handler) (int, void *, void *));
+void msm_gemini_core_irq_remove(void);
+
+int msm_gemini_core_fe_buf_update(struct msm_gemini_core_buf *buf);
+int msm_gemini_core_we_buf_update(struct msm_gemini_core_buf *buf);
+int msm_gemini_core_we_buf_reset(struct msm_gemini_hw_buf *buf);
+
+int msm_gemini_core_reset(uint8_t op_mode, void *base, int size);
+int msm_gemini_core_fe_start(void);
+
+void msm_gemini_core_release(int);
+void msm_gemini_core_init(void);
+#endif /* MSM_GEMINI_CORE_H */
diff --git a/drivers/media/video/msm/msm_gemini_dev.c b/drivers/media/video/msm/msm_gemini_dev.c
new file mode 100644
index 0000000..1156bb0
--- /dev/null
+++ b/drivers/media/video/msm/msm_gemini_dev.c
@@ -0,0 +1,208 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <mach/board.h>
+
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+
+#include <media/msm_gemini.h>
+#include "msm_gemini_sync.h"
+#include "msm_gemini_common.h"
+
+#define MSM_GEMINI_NAME "gemini"
+
+static int msm_gemini_open(struct inode *inode, struct file *filp)
+{
+	int rc;
+
+	struct msm_gemini_device *pgmn_dev = container_of(inode->i_cdev,
+		struct msm_gemini_device, cdev);
+	filp->private_data = pgmn_dev;
+
+	GMN_DBG("%s:%d]\n", __func__, __LINE__);
+
+	rc = __msm_gemini_open(pgmn_dev);
+
+	GMN_DBG(KERN_INFO "%s:%d] %s open_count = %d\n", __func__, __LINE__,
+		filp->f_path.dentry->d_name.name, pgmn_dev->open_count);
+
+	return rc;
+}
+
+static int msm_gemini_release(struct inode *inode, struct file *filp)
+{
+	int rc;
+
+	struct msm_gemini_device *pgmn_dev = filp->private_data;
+
+	GMN_DBG(KERN_INFO "%s:%d]\n", __func__, __LINE__);
+
+	rc = __msm_gemini_release(pgmn_dev);
+
+	GMN_DBG(KERN_INFO "%s:%d] %s open_count = %d\n", __func__, __LINE__,
+		filp->f_path.dentry->d_name.name, pgmn_dev->open_count);
+	return rc;
+}
+
+static long msm_gemini_ioctl(struct file *filp, unsigned int cmd,
+	unsigned long arg)
+{
+	int rc;
+	struct msm_gemini_device *pgmn_dev = filp->private_data;
+
+	GMN_DBG(KERN_INFO "%s:%d] cmd = %d\n", __func__, __LINE__,
+		_IOC_NR(cmd));
+
+	rc = __msm_gemini_ioctl(pgmn_dev, cmd, arg);
+
+	GMN_DBG("%s:%d]\n", __func__, __LINE__);
+	return rc;
+}
+
+static const struct file_operations msm_gemini_fops = {
+	.owner	  = THIS_MODULE,
+	.open	   = msm_gemini_open,
+	.release	= msm_gemini_release,
+	.unlocked_ioctl = msm_gemini_ioctl,
+};
+
+static struct class *msm_gemini_class;
+static dev_t msm_gemini_devno;
+static struct msm_gemini_device *msm_gemini_device_p;
+
+static int msm_gemini_init(struct platform_device *pdev)
+{
+	int rc = -1;
+	struct device *dev;
+
+	GMN_DBG("%s:%d]\n", __func__, __LINE__);
+
+	msm_gemini_device_p = __msm_gemini_init(pdev);
+	if (msm_gemini_device_p == NULL) {
+		GMN_PR_ERR("%s: initialization failed\n", __func__);
+		goto fail;
+	}
+
+	rc = alloc_chrdev_region(&msm_gemini_devno, 0, 1, MSM_GEMINI_NAME);
+	if (rc < 0) {
+		GMN_PR_ERR("%s: failed to allocate chrdev\n", __func__);
+		goto fail_1;
+	}
+
+	if (!msm_gemini_class) {
+		msm_gemini_class = class_create(THIS_MODULE, MSM_GEMINI_NAME);
+		if (IS_ERR(msm_gemini_class)) {
+			rc = PTR_ERR(msm_gemini_class);
+			GMN_PR_ERR("%s: create device class failed\n",
+				__func__);
+			goto fail_2;
+		}
+	}
+
+	dev = device_create(msm_gemini_class, NULL,
+		MKDEV(MAJOR(msm_gemini_devno), MINOR(msm_gemini_devno)), NULL,
+		"%s%d", MSM_GEMINI_NAME, 0);
+
+	if (IS_ERR(dev)) {
+		GMN_PR_ERR("%s: error creating device\n", __func__);
+		rc = -ENODEV;
+		goto fail_3;
+	}
+
+	cdev_init(&msm_gemini_device_p->cdev, &msm_gemini_fops);
+	msm_gemini_device_p->cdev.owner = THIS_MODULE;
+	msm_gemini_device_p->cdev.ops   =
+		(const struct file_operations *) &msm_gemini_fops;
+	rc = cdev_add(&msm_gemini_device_p->cdev, msm_gemini_devno, 1);
+	if (rc < 0) {
+		GMN_PR_ERR("%s: error adding cdev\n", __func__);
+		rc = -ENODEV;
+		goto fail_4;
+	}
+
+	GMN_DBG("%s %s: success\n", __func__, MSM_GEMINI_NAME);
+
+	return rc;
+
+fail_4:
+	device_destroy(msm_gemini_class, msm_gemini_devno);
+
+fail_3:
+	class_destroy(msm_gemini_class);
+
+fail_2:
+	unregister_chrdev_region(msm_gemini_devno, 1);
+
+fail_1:
+	__msm_gemini_exit(msm_gemini_device_p);
+
+fail:
+	return rc;
+}
+
+static void msm_gemini_exit(void)
+{
+	cdev_del(&msm_gemini_device_p->cdev);
+	device_destroy(msm_gemini_class, msm_gemini_devno);
+	class_destroy(msm_gemini_class);
+	unregister_chrdev_region(msm_gemini_devno, 1);
+
+	__msm_gemini_exit(msm_gemini_device_p);
+}
+
+static int __msm_gemini_probe(struct platform_device *pdev)
+{
+	int rc;
+	rc = msm_gemini_init(pdev);
+	return rc;
+}
+
+static int __msm_gemini_remove(struct platform_device *pdev)
+{
+	msm_gemini_exit();
+	return 0;
+}
+
+static struct platform_driver msm_gemini_driver = {
+	.probe  = __msm_gemini_probe,
+	.remove = __msm_gemini_remove,
+	.driver = {
+		.name = "msm_gemini",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_gemini_driver_init(void)
+{
+	int rc;
+	rc = platform_driver_register(&msm_gemini_driver);
+	return rc;
+}
+
+static void __exit msm_gemini_driver_exit(void)
+{
+	platform_driver_unregister(&msm_gemini_driver);
+}
+
+MODULE_DESCRIPTION("msm gemini jpeg driver");
+MODULE_VERSION("msm gemini 0.1");
+
+module_init(msm_gemini_driver_init);
+module_exit(msm_gemini_driver_exit);
+
diff --git a/drivers/media/video/msm/msm_gemini_hw.c b/drivers/media/video/msm/msm_gemini_hw.c
new file mode 100644
index 0000000..ba8f353
--- /dev/null
+++ b/drivers/media/video/msm/msm_gemini_hw.c
@@ -0,0 +1,525 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include "msm_gemini_hw.h"
+#include "msm_gemini_common.h"
+
+#include <linux/io.h>
+
+static void *gemini_region_base;
+static uint32_t gemini_region_size;
+
+int msm_gemini_hw_pingpong_update(struct msm_gemini_hw_pingpong *pingpong_hw,
+	struct msm_gemini_hw_buf *buf)
+{
+	int buf_free_index = -1;
+
+	if (!pingpong_hw->buf_status[0]) {
+		buf_free_index = 0;
+	} else if (!pingpong_hw->buf_status[1]) {
+		buf_free_index = 1;
+	} else {
+		GMN_PR_ERR("%s:%d: pingpong buffer busy\n", __func__, __LINE__);
+		return -1;
+	}
+
+	pingpong_hw->buf[buf_free_index] = *buf;
+	pingpong_hw->buf_status[buf_free_index] = 1;
+
+	if (pingpong_hw->is_fe) {
+		/* it is fe */
+		msm_gemini_hw_fe_buffer_update(
+			&pingpong_hw->buf[buf_free_index], buf_free_index);
+	} else {
+		/* it is we */
+		msm_gemini_hw_we_buffer_update(
+			&pingpong_hw->buf[buf_free_index], buf_free_index);
+	}
+	return 0;
+}
+
+void *msm_gemini_hw_pingpong_irq(struct msm_gemini_hw_pingpong *pingpong_hw)
+{
+	struct msm_gemini_hw_buf *buf_p = NULL;
+
+	if (pingpong_hw->buf_status[pingpong_hw->buf_active_index]) {
+		buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index];
+		pingpong_hw->buf_status[pingpong_hw->buf_active_index] = 0;
+	}
+
+	pingpong_hw->buf_active_index = !pingpong_hw->buf_active_index;
+
+	return (void *) buf_p;
+}
+
+void *msm_gemini_hw_pingpong_active_buffer(
+	struct msm_gemini_hw_pingpong *pingpong_hw)
+{
+	struct msm_gemini_hw_buf *buf_p = NULL;
+
+	if (pingpong_hw->buf_status[pingpong_hw->buf_active_index])
+		buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index];
+
+	return (void *) buf_p;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_irq_get_status[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_GEMINI_HW_CMD_TYPE_READ, 1, HWIO_JPEG_IRQ_STATUS_ADDR,
+		HWIO_JPEG_IRQ_STATUS_RMSK, {0} },
+};
+
+int msm_gemini_hw_irq_get_status(void)
+{
+	uint32_t n_irq_status = 0;
+	rmb();
+	n_irq_status = msm_gemini_hw_read(&hw_cmd_irq_get_status[0]);
+	rmb();
+	return n_irq_status;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_encode_output_size[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_GEMINI_HW_CMD_TYPE_READ, 1,
+		HWIO_JPEG_STATUS_ENCODE_OUTPUT_SIZE_ADDR,
+		HWIO_JPEG_STATUS_ENCODE_OUTPUT_SIZE_RMSK, {0} },
+};
+
+long msm_gemini_hw_encode_output_size(void)
+{
+	uint32_t encode_output_size = 0;
+
+	encode_output_size = msm_gemini_hw_read(&hw_cmd_encode_output_size[0]);
+
+	return encode_output_size;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_irq_clear[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_IRQ_CLEAR_ADDR,
+		HWIO_JPEG_IRQ_CLEAR_RMSK, {JPEG_IRQ_CLEAR_ALL} },
+};
+
+void msm_gemini_hw_irq_clear(uint32_t mask, uint32_t data)
+{
+	GMN_DBG("%s:%d] mask %0x data %0x", __func__, __LINE__, mask, data);
+	hw_cmd_irq_clear[0].mask = mask;
+	hw_cmd_irq_clear[0].data = data;
+	msm_gemini_hw_write(&hw_cmd_irq_clear[0]);
+}
+
+struct msm_gemini_hw_cmd hw_cmd_fe_ping_update[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_BUFFER_CFG_ADDR,
+		HWIO_JPEG_FE_BUFFER_CFG_RMSK, {0} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_Y_PING_ADDR_ADDR,
+		HWIO_JPEG_FE_Y_PING_ADDR_RMSK, {0} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CBCR_PING_ADDR_ADDR,
+		HWIO_JPEG_FE_CBCR_PING_ADDR_RMSK, {0} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CMD_ADDR,
+		HWIO_JPEG_FE_CMD_RMSK, {JPEG_FE_CMD_BUFFERRELOAD} },
+};
+
+struct msm_gemini_hw_cmd hw_cmd_fe_pong_update[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_BUFFER_CFG_ADDR,
+		HWIO_JPEG_FE_BUFFER_CFG_RMSK, {0} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_Y_PONG_ADDR_ADDR,
+		HWIO_JPEG_FE_Y_PONG_ADDR_RMSK, {0} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CBCR_PONG_ADDR_ADDR,
+		HWIO_JPEG_FE_CBCR_PONG_ADDR_RMSK, {0} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CMD_ADDR,
+		HWIO_JPEG_FE_CMD_RMSK, {JPEG_FE_CMD_BUFFERRELOAD} },
+};
+
+void msm_gemini_hw_fe_buffer_update(struct msm_gemini_hw_buf *p_input,
+	uint8_t pingpong_index)
+{
+	uint32_t n_reg_val = 0;
+
+	struct msm_gemini_hw_cmd *hw_cmd_p;
+
+	if (pingpong_index == 0) {
+		hw_cmd_p = &hw_cmd_fe_ping_update[0];
+		n_reg_val = ((((p_input->num_of_mcu_rows - 1) <<
+			HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_SHFT) &
+			HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_BMSK) |
+			(((p_input->num_of_mcu_rows - 1) <<
+			HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_SHFT) &
+			HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_BMSK));
+		hw_cmd_p->data = n_reg_val;
+		msm_gemini_hw_write(hw_cmd_p++);
+
+		n_reg_val = ((p_input->y_buffer_addr <<
+			HWIO_JPEG_FE_Y_PING_ADDR_FE_Y_PING_START_ADDR_SHFT) &
+			HWIO_JPEG_FE_Y_PING_ADDR_FE_Y_PING_START_ADDR_BMSK);
+		hw_cmd_p->data = n_reg_val;
+		msm_gemini_hw_write(hw_cmd_p++);
+
+		n_reg_val = ((p_input->cbcr_buffer_addr<<
+		HWIO_JPEG_FE_CBCR_PING_ADDR_FE_CBCR_PING_START_ADDR_SHFT) &
+		HWIO_JPEG_FE_CBCR_PING_ADDR_FE_CBCR_PING_START_ADDR_BMSK);
+		hw_cmd_p->data = n_reg_val;
+		msm_gemini_hw_write(hw_cmd_p++);
+
+		msm_gemini_hw_write(hw_cmd_p);
+	} else if (pingpong_index == 1) {
+		hw_cmd_p = &hw_cmd_fe_pong_update[0];
+		n_reg_val = ((((p_input->num_of_mcu_rows - 1) <<
+			HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_SHFT) &
+			HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_BMSK) |
+			(((p_input->num_of_mcu_rows - 1) <<
+			HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_SHFT) &
+			HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_BMSK));
+		hw_cmd_p->data = n_reg_val;
+		msm_gemini_hw_write(hw_cmd_p++);
+
+		n_reg_val = ((p_input->y_buffer_addr <<
+			HWIO_JPEG_FE_Y_PONG_ADDR_FE_Y_PONG_START_ADDR_SHFT) &
+			HWIO_JPEG_FE_Y_PONG_ADDR_FE_Y_PONG_START_ADDR_BMSK);
+		hw_cmd_p->data = n_reg_val;
+		msm_gemini_hw_write(hw_cmd_p++);
+
+		n_reg_val = ((p_input->cbcr_buffer_addr<<
+		HWIO_JPEG_FE_CBCR_PONG_ADDR_FE_CBCR_PONG_START_ADDR_SHFT) &
+		HWIO_JPEG_FE_CBCR_PONG_ADDR_FE_CBCR_PONG_START_ADDR_BMSK);
+		hw_cmd_p->data = n_reg_val;
+		msm_gemini_hw_write(hw_cmd_p++);
+
+		msm_gemini_hw_write(hw_cmd_p);
+	} else {
+		/* shall not get to here */
+	}
+
+	return;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_fe_start[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CMD_ADDR,
+		HWIO_JPEG_FE_CMD_RMSK, {JPEG_OFFLINE_CMD_START} },
+};
+
+void msm_gemini_hw_fe_start(void)
+{
+	msm_gemini_hw_write(&hw_cmd_fe_start[0]);
+
+	return;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_we_buffer_cfg[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_THRESHOLD_ADDR,
+		HWIO_JPEG_WE_Y_THRESHOLD_RMSK, {0} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_UB_CFG_ADDR,
+		HWIO_JPEG_WE_Y_UB_CFG_RMSK, {JPEG_WE_YUB_ENCODE} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_CBCR_THRESHOLD_ADDR,
+		HWIO_JPEG_WE_CBCR_THRESHOLD_RMSK, {0} },
+};
+
+/* first dimension is WE_ASSERT_STALL_TH and WE_DEASSERT_STALL_TH
+   second dimension is for offline and real-time settings
+ */
+static const uint32_t GEMINI_WE_Y_THRESHOLD[2][2] = {
+	{ 0x00000190, 0x000001ff },
+	{ 0x0000016a, 0x000001ff }
+};
+
+/* first dimension is WE_ASSERT_STALL_TH and WE_DEASSERT_STALL_TH
+   second dimension is for offline and real-time settings
+ */
+static const uint32_t GEMINI_WE_CBCR_THRESHOLD[2][2] = {
+	{ 0x00000190, 0x000001ff },
+	{ 0x0000016a, 0x000001ff }
+};
+
+void msm_gemini_hw_we_buffer_cfg(uint8_t is_realtime)
+{
+	uint32_t              n_reg_val = 0;
+
+	struct msm_gemini_hw_cmd *hw_cmd_p = &hw_cmd_we_buffer_cfg[0];
+
+	n_reg_val = (((GEMINI_WE_Y_THRESHOLD[1][is_realtime] <<
+		HWIO_JPEG_WE_Y_THRESHOLD_WE_DEASSERT_STALL_TH_SHFT) &
+		HWIO_JPEG_WE_Y_THRESHOLD_WE_DEASSERT_STALL_TH_BMSK) |
+		((GEMINI_WE_Y_THRESHOLD[0][is_realtime] <<
+		HWIO_JPEG_WE_Y_THRESHOLD_WE_ASSERT_STALL_TH_SHFT) &
+		HWIO_JPEG_WE_Y_THRESHOLD_WE_ASSERT_STALL_TH_BMSK));
+	hw_cmd_p->data = n_reg_val;
+	msm_gemini_hw_write(hw_cmd_p++);
+
+	msm_gemini_hw_write(hw_cmd_p++);
+
+	/* @todo maybe not for realtime? */
+	n_reg_val = (((GEMINI_WE_CBCR_THRESHOLD[1][is_realtime] <<
+		HWIO_JPEG_WE_CBCR_THRESHOLD_WE_DEASSERT_STALL_TH_SHFT) &
+		HWIO_JPEG_WE_CBCR_THRESHOLD_WE_DEASSERT_STALL_TH_BMSK) |
+		((GEMINI_WE_CBCR_THRESHOLD[0][is_realtime] <<
+		HWIO_JPEG_WE_CBCR_THRESHOLD_WE_ASSERT_STALL_TH_SHFT) &
+		HWIO_JPEG_WE_CBCR_THRESHOLD_WE_ASSERT_STALL_TH_BMSK));
+	hw_cmd_p->data = n_reg_val;
+	msm_gemini_hw_write(hw_cmd_p);
+
+	return;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_we_ping_update[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_PING_BUFFER_CFG_ADDR,
+		HWIO_JPEG_WE_Y_PING_BUFFER_CFG_RMSK, {0} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_PING_ADDR_ADDR,
+		HWIO_JPEG_WE_Y_PING_ADDR_RMSK, {0} },
+};
+
+struct msm_gemini_hw_cmd hw_cmd_we_pong_update[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_ADDR,
+		HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_RMSK, {0} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_PONG_ADDR_ADDR,
+		HWIO_JPEG_WE_Y_PONG_ADDR_RMSK, {0} },
+};
+
+void msm_gemini_hw_we_buffer_update(struct msm_gemini_hw_buf *p_input,
+	uint8_t pingpong_index)
+{
+	uint32_t n_reg_val = 0;
+
+	struct msm_gemini_hw_cmd *hw_cmd_p;
+
+	if (pingpong_index == 0) {
+		hw_cmd_p = &hw_cmd_we_ping_update[0];
+
+		n_reg_val = ((p_input->y_len <<
+			HWIO_JPEG_WE_Y_PING_BUFFER_CFG_WE_BUFFER_LENGTH_SHFT) &
+			HWIO_JPEG_WE_Y_PING_BUFFER_CFG_WE_BUFFER_LENGTH_BMSK);
+		hw_cmd_p->data = n_reg_val;
+		msm_gemini_hw_write(hw_cmd_p++);
+
+		n_reg_val = p_input->y_buffer_addr;
+		hw_cmd_p->data = n_reg_val;
+		msm_gemini_hw_write(hw_cmd_p++);
+	} else if (pingpong_index == 1) {
+		hw_cmd_p = &hw_cmd_we_pong_update[0];
+
+		n_reg_val = ((p_input->y_len <<
+			HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_WE_BUFFER_LENGTH_SHFT) &
+			HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_WE_BUFFER_LENGTH_BMSK);
+		hw_cmd_p->data = n_reg_val;
+		msm_gemini_hw_write(hw_cmd_p++);
+
+		n_reg_val = p_input->y_buffer_addr;
+		hw_cmd_p->data = n_reg_val;
+		msm_gemini_hw_write(hw_cmd_p++);
+	} else {
+		/* shall not get to here */
+	}
+
+	return;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_reset[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_IRQ_MASK_ADDR,
+		HWIO_JPEG_IRQ_MASK_RMSK, {JPEG_IRQ_DISABLE_ALL} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_IRQ_CLEAR_ADDR,
+		HWIO_JPEG_IRQ_MASK_RMSK, {JPEG_IRQ_CLEAR_ALL} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_IRQ_MASK_ADDR,
+		HWIO_JPEG_IRQ_MASK_RMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_RESET_CMD_ADDR,
+		HWIO_JPEG_RESET_CMD_RMSK, {JPEG_RESET_DEFAULT} },
+};
+
+void msm_gemini_hw_init(void *base, int size)
+{
+	gemini_region_base = base;
+	gemini_region_size = size;
+}
+
+void msm_gemini_hw_reset(void *base, int size)
+{
+	struct msm_gemini_hw_cmd *hw_cmd_p;
+
+	hw_cmd_p = &hw_cmd_reset[0];
+
+	wmb();
+	msm_gemini_hw_write(hw_cmd_p++);
+	msm_gemini_hw_write(hw_cmd_p++);
+	msm_gemini_hw_write(hw_cmd_p++);
+	msm_gemini_hw_write(hw_cmd_p);
+	wmb();
+
+	return;
+}
+
+uint32_t msm_gemini_hw_read(struct msm_gemini_hw_cmd *hw_cmd_p)
+{
+	uint32_t *paddr;
+	uint32_t data;
+
+	paddr = gemini_region_base + hw_cmd_p->offset;
+
+	data = readl(paddr);
+	data &= hw_cmd_p->mask;
+
+	GMN_DBG("%s:%d] type-%d n-%d offset-0x%4x mask-0x%8x data-0x%8x\n",
+		__func__, __LINE__, hw_cmd_p->type, hw_cmd_p->n,
+		hw_cmd_p->offset, hw_cmd_p->mask, data);
+	return data;
+}
+
+void msm_gemini_hw_write(struct msm_gemini_hw_cmd *hw_cmd_p)
+{
+	uint32_t *paddr;
+	uint32_t old_data, new_data;
+
+	/* type, repeat n times, offset, mask, data or pdata */
+	GMN_DBG("%s:%d] type-%d n-%d offset-0x%4x mask-0x%8x data-0x%8x\n",
+		__func__, __LINE__, hw_cmd_p->type, hw_cmd_p->n,
+		hw_cmd_p->offset, hw_cmd_p->mask, hw_cmd_p->data);
+
+	paddr = gemini_region_base + hw_cmd_p->offset;
+
+	if (hw_cmd_p->mask == 0xffffffff) {
+		old_data = 0;
+	} else {
+		old_data = readl(paddr);
+		old_data &= ~hw_cmd_p->mask;
+	}
+
+	new_data = hw_cmd_p->data & hw_cmd_p->mask;
+	new_data |= old_data;
+	writel(new_data, paddr);
+}
+
+int msm_gemini_hw_wait(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us)
+{
+	int tm = hw_cmd_p->n;
+	uint32_t data;
+	uint32_t wait_data = hw_cmd_p->data & hw_cmd_p->mask;
+
+	data = msm_gemini_hw_read(hw_cmd_p);
+	if (data != wait_data) {
+		while (tm) {
+			udelay(m_us);
+			data = msm_gemini_hw_read(hw_cmd_p);
+			if (data == wait_data)
+				break;
+			tm--;
+		}
+	}
+	hw_cmd_p->data = data;
+	return tm;
+}
+
+void msm_gemini_hw_delay(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us)
+{
+	int tm = hw_cmd_p->n;
+	while (tm) {
+		udelay(m_us);
+		tm--;
+	}
+}
+
+int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds)
+{
+	int is_copy_to_user = -1;
+	uint32_t data;
+
+	while (m_cmds--) {
+		if (hw_cmd_p->offset > gemini_region_size) {
+			GMN_PR_ERR("%s:%d] %d exceed hw region %d\n", __func__,
+				__LINE__, hw_cmd_p->offset, gemini_region_size);
+			return -EFAULT;
+		}
+
+		switch (hw_cmd_p->type) {
+		case MSM_GEMINI_HW_CMD_TYPE_READ:
+			hw_cmd_p->data = msm_gemini_hw_read(hw_cmd_p);
+			is_copy_to_user = 1;
+			break;
+
+		case MSM_GEMINI_HW_CMD_TYPE_WRITE:
+			msm_gemini_hw_write(hw_cmd_p);
+			break;
+
+		case MSM_GEMINI_HW_CMD_TYPE_WRITE_OR:
+			data = msm_gemini_hw_read(hw_cmd_p);
+			hw_cmd_p->data = (hw_cmd_p->data & hw_cmd_p->mask) |
+				data;
+			msm_gemini_hw_write(hw_cmd_p);
+			break;
+
+		case MSM_GEMINI_HW_CMD_TYPE_UWAIT:
+			msm_gemini_hw_wait(hw_cmd_p, 1);
+			break;
+
+		case MSM_GEMINI_HW_CMD_TYPE_MWAIT:
+			msm_gemini_hw_wait(hw_cmd_p, 1000);
+			break;
+
+		case MSM_GEMINI_HW_CMD_TYPE_UDELAY:
+			msm_gemini_hw_delay(hw_cmd_p, 1);
+			break;
+
+		case MSM_GEMINI_HW_CMD_TYPE_MDELAY:
+			msm_gemini_hw_delay(hw_cmd_p, 1000);
+			break;
+
+		default:
+			GMN_PR_ERR("wrong hw command type\n");
+			break;
+		}
+
+		hw_cmd_p++;
+	}
+	return is_copy_to_user;
+}
+
+void msm_gemini_hw_region_dump(int size)
+{
+	uint32_t *p;
+	uint8_t *p8;
+
+	if (size > gemini_region_size)
+		GMN_PR_ERR("%s:%d] wrong region dump size\n",
+			__func__, __LINE__);
+
+	p = (uint32_t *) gemini_region_base;
+	while (size >= 16) {
+		GMN_DBG("0x%08X] %08X %08X %08X %08X\n",
+			gemini_region_size - size,
+			readl(p), readl(p+1), readl(p+2), readl(p+3));
+		p += 4;
+		size -= 16;
+	}
+
+	if (size > 0) {
+		uint32_t d;
+		GMN_DBG("0x%08X] ", gemini_region_size - size);
+		while (size >= 4) {
+			GMN_DBG("%08X ", readl(p++));
+			size -= 4;
+		}
+
+		d = readl(p);
+		p8 = (uint8_t *) &d;
+		while (size) {
+			GMN_DBG("%02X", *p8++);
+			size--;
+		}
+
+		GMN_DBG("\n");
+	}
+}
+
diff --git a/drivers/media/video/msm/msm_gemini_hw.h b/drivers/media/video/msm/msm_gemini_hw.h
new file mode 100644
index 0000000..ee1eac3
--- /dev/null
+++ b/drivers/media/video/msm/msm_gemini_hw.h
@@ -0,0 +1,101 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef MSM_GEMINI_HW_H
+#define MSM_GEMINI_HW_H
+
+#include <media/msm_gemini.h>
+#include "msm_gemini_hw_reg.h"
+
+struct msm_gemini_hw_buf {
+	struct msm_gemini_buf vbuf;
+	struct file  *file;
+	uint32_t framedone_len;
+	uint32_t y_buffer_addr;
+	uint32_t y_len;
+	uint32_t cbcr_buffer_addr;
+	uint32_t cbcr_len;
+	uint32_t num_of_mcu_rows;
+};
+
+struct msm_gemini_hw_pingpong {
+	uint8_t is_fe; /* 1: fe; 0: we */
+	struct  msm_gemini_hw_buf buf[2];
+	int     buf_status[2];
+	int     buf_active_index;
+};
+
+int msm_gemini_hw_pingpong_update(struct msm_gemini_hw_pingpong *pingpong_hw,
+	struct msm_gemini_hw_buf *buf);
+void *msm_gemini_hw_pingpong_irq(struct msm_gemini_hw_pingpong *pingpong_hw);
+void *msm_gemini_hw_pingpong_active_buffer(struct msm_gemini_hw_pingpong
+	*pingpong_hw);
+
+void msm_gemini_hw_irq_clear(uint32_t, uint32_t);
+int msm_gemini_hw_irq_get_status(void);
+long msm_gemini_hw_encode_output_size(void);
+#define MSM_GEMINI_HW_MASK_COMP_FRAMEDONE \
+		MSM_GEMINI_HW_IRQ_STATUS_FRAMEDONE_MASK
+#define MSM_GEMINI_HW_MASK_COMP_FE \
+		MSM_GEMINI_HW_IRQ_STATUS_FE_RD_DONE_MASK
+#define MSM_GEMINI_HW_MASK_COMP_WE \
+		(MSM_GEMINI_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK | \
+		 MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK)
+#define MSM_GEMINI_HW_MASK_COMP_RESET_ACK \
+		MSM_GEMINI_HW_IRQ_STATUS_RESET_ACK_MASK
+#define MSM_GEMINI_HW_MASK_COMP_ERR \
+		(MSM_GEMINI_HW_IRQ_STATUS_FE_RTOVF_MASK | \
+		MSM_GEMINI_HW_IRQ_STATUS_FE_VFE_OVERFLOW_MASK | \
+		MSM_GEMINI_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_MASK | \
+		MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_MASK | \
+		MSM_GEMINI_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_MASK | \
+		MSM_GEMINI_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_MASK | \
+		MSM_GEMINI_HW_IRQ_STATUS_BUS_ERROR_MASK | \
+		MSM_GEMINI_HW_IRQ_STATUS_VIOLATION_MASK)
+
+#define msm_gemini_hw_irq_is_frame_done(gemini_irq_status) \
+	(gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_FRAMEDONE)
+#define msm_gemini_hw_irq_is_fe_pingpong(gemini_irq_status) \
+	(gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_FE)
+#define msm_gemini_hw_irq_is_we_pingpong(gemini_irq_status) \
+	(gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_WE)
+#define msm_gemini_hw_irq_is_reset_ack(gemini_irq_status) \
+	(gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_RESET_ACK)
+#define msm_gemini_hw_irq_is_err(gemini_irq_status) \
+	(gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_ERR)
+
+void msm_gemini_hw_fe_buffer_update(struct msm_gemini_hw_buf *p_input,
+	uint8_t pingpong_index);
+void msm_gemini_hw_we_buffer_update(struct msm_gemini_hw_buf *p_input,
+	uint8_t pingpong_index);
+
+void msm_gemini_hw_we_buffer_cfg(uint8_t is_realtime);
+
+void msm_gemini_hw_fe_start(void);
+void msm_gemini_hw_clk_cfg(void);
+
+void msm_gemini_hw_reset(void *base, int size);
+void msm_gemini_hw_irq_cfg(void);
+void msm_gemini_hw_init(void *base, int size);
+
+uint32_t msm_gemini_hw_read(struct msm_gemini_hw_cmd *hw_cmd_p);
+void msm_gemini_hw_write(struct msm_gemini_hw_cmd *hw_cmd_p);
+int msm_gemini_hw_wait(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us);
+void msm_gemini_hw_delay(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us);
+int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds);
+void msm_gemini_hw_region_dump(int size);
+
+#define MSM_GEMINI_PIPELINE_CLK_128MHZ 128 /* 8MP  128MHz */
+#define MSM_GEMINI_PIPELINE_CLK_140MHZ 140 /* 9MP  140MHz */
+#define MSM_GEMINI_PIPELINE_CLK_200MHZ 153 /* 12MP 153MHz */
+
+#endif /* MSM_GEMINI_HW_H */
diff --git a/drivers/media/video/msm/msm_gemini_hw_reg.h b/drivers/media/video/msm/msm_gemini_hw_reg.h
new file mode 100644
index 0000000..4bddfbb
--- /dev/null
+++ b/drivers/media/video/msm/msm_gemini_hw_reg.h
@@ -0,0 +1,176 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef MSM_GEMINI_HW_REG_H
+#define MSM_GEMINI_HW_REG_H
+
+#define GEMINI_REG_BASE 0
+
+#define MSM_GEMINI_HW_IRQ_MASK_ADDR 0x00000014
+#define MSM_GEMINI_HW_IRQ_MASK_RMSK 0xffffffff
+#define MSM_GEMINI_HW_IRQ_MASK_SHFT 0
+#define MSM_GEMINI_HW_IRQ_DISABLE 0
+#define MSM_GEMINI_HW_IRQ_ENABLE 0xffffffff
+
+#define MSM_GEMINI_HW_IRQ_CLEAR_ADDR 0x00000018
+#define MSM_GEMINI_HW_IRQ_CLEAR_RMSK 0xffffffff
+#define MSM_GEMINI_HW_IRQ_CLEAR_SHFT 0
+#define MSM_GEMINI_HW_IRQ_CLEAR  0xffffffff
+
+#define MSM_GEMINI_HW_IRQ_STATUS_FRAMEDONE_MASK 0x00000001
+#define MSM_GEMINI_HW_IRQ_STATUS_FRAMEDONE_SHIFT 0x00000000
+
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_RD_DONE_MASK 0x00000002
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_RD_DONE_SHIFT 0x00000001
+
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_RTOVF_MASK 0x00000004
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_RTOVF_SHIFT 0x00000002
+
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_VFE_OVERFLOW_MASK 0x00000008
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_VFE_OVERFLOW_SHIFT 0x00000003
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK 0x00000010
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_Y_PINGPONG_SHIFT 0x00000004
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK 0x00000020
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_PINGPONG_SHIFT 0x00000005
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_MASK 0x00000040
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_SHIFT 0x00000006
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_MASK 0x00000080
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_SHIFT 0x00000007
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_MASK 0x00000100
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_SHIFT 0x00000008
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_MASK 0x00000200
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_SHIFT 0x00000009
+
+#define MSM_GEMINI_HW_IRQ_STATUS_RESET_ACK_MASK 0x00000400
+#define MSM_GEMINI_HW_IRQ_STATUS_RESET_ACK_SHIFT 0x0000000a
+
+#define MSM_GEMINI_HW_IRQ_STATUS_BUS_ERROR_MASK 0x00000800
+#define MSM_GEMINI_HW_IRQ_STATUS_BUS_ERROR_SHIFT 0x0000000b
+
+#define MSM_GEMINI_HW_IRQ_STATUS_VIOLATION_MASK 0x00001000
+#define MSM_GEMINI_HW_IRQ_STATUS_VIOLATION_SHIFT 0x0000000c
+
+#define JPEG_BUS_CMD_HALT_REQ 0x00000001
+
+#define JPEG_REALTIME_CMD_STOP_FB 0x00000000
+#define JPEG_REALTIME_CMD_STOP_IM 0x00000003
+#define JPEG_REALTIME_CMD_START 0x00000001
+
+#define JPEG_OFFLINE_CMD_START 0x00000003
+
+#define JPEG_DMI_CFG_DISABLE 0x00000000
+#define JPEG_DMI_ADDR_START 0x00000000
+
+#define JPEG_FE_CMD_BUFFERRELOAD 0x00000001
+
+#define JPEG_WE_YUB_ENCODE 0x01ff0000
+
+#define JPEG_RESET_DEFAULT 0x0004ffff /* cfff? */
+
+#define JPEG_IRQ_DISABLE_ALL 0x00000000
+#define JPEG_IRQ_CLEAR_ALL 0xffffffff
+#define JPEG_IRQ_ALLSOURCES_ENABLE 0xffffffff
+
+#define HWIO_JPEG_FE_BUFFER_CFG_ADDR (GEMINI_REG_BASE + 0x00000080)
+#define HWIO_JPEG_FE_BUFFER_CFG_RMSK 0x1fff1fff
+
+#define HWIO_JPEG_FE_Y_PING_ADDR_ADDR (GEMINI_REG_BASE + 0x00000084)
+#define HWIO_JPEG_FE_Y_PING_ADDR_RMSK 0xffffffff
+
+#define HWIO_JPEG_FE_Y_PONG_ADDR_ADDR (GEMINI_REG_BASE + 0x00000088)
+#define HWIO_JPEG_FE_Y_PONG_ADDR_RMSK 0xffffffff
+
+#define HWIO_JPEG_FE_CBCR_PING_ADDR_ADDR (GEMINI_REG_BASE + 0x0000008c)
+#define HWIO_JPEG_FE_CBCR_PING_ADDR_RMSK 0xffffffff
+
+#define HWIO_JPEG_FE_CBCR_PONG_ADDR_ADDR (GEMINI_REG_BASE + 0x00000090)
+#define HWIO_JPEG_FE_CBCR_PONG_ADDR_RMSK 0xffffffff
+
+#define HWIO_JPEG_FE_CMD_ADDR (GEMINI_REG_BASE + 0x00000094)
+#define HWIO_JPEG_FE_CMD_RMSK 0x3
+
+#define HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_BMSK 0x1fff0000
+#define HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_SHFT 0x10
+#define HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_BMSK 0x1fff
+#define HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_SHFT 0
+
+#define HWIO_JPEG_FE_Y_PING_ADDR_FE_Y_PING_START_ADDR_BMSK 0xffffffff
+#define HWIO_JPEG_FE_Y_PING_ADDR_FE_Y_PING_START_ADDR_SHFT 0
+
+#define HWIO_JPEG_FE_CBCR_PING_ADDR_FE_CBCR_PING_START_ADDR_BMSK 0xffffffff
+#define HWIO_JPEG_FE_CBCR_PING_ADDR_FE_CBCR_PING_START_ADDR_SHFT 0
+
+#define HWIO_JPEG_FE_Y_PONG_ADDR_FE_Y_PONG_START_ADDR_BMSK 0xffffffff
+#define HWIO_JPEG_FE_Y_PONG_ADDR_FE_Y_PONG_START_ADDR_SHFT 0
+
+#define HWIO_JPEG_FE_CBCR_PONG_ADDR_FE_CBCR_PONG_START_ADDR_BMSK 0xffffffff
+#define HWIO_JPEG_FE_CBCR_PONG_ADDR_FE_CBCR_PONG_START_ADDR_SHFT 0
+
+#define HWIO_JPEG_WE_Y_THRESHOLD_ADDR (GEMINI_REG_BASE + 0x000000c0)
+#define HWIO_JPEG_WE_Y_THRESHOLD_RMSK 0x1ff01ff
+
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_ADDR (GEMINI_REG_BASE      + 0x000000c4)
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_RMSK 0x1ff01ff
+
+#define HWIO_JPEG_WE_Y_UB_CFG_ADDR (GEMINI_REG_BASE + 0x000000e8)
+#define HWIO_JPEG_WE_Y_UB_CFG_RMSK 0x1ff01ff
+
+#define HWIO_JPEG_WE_Y_THRESHOLD_WE_DEASSERT_STALL_TH_BMSK 0x1ff0000
+#define HWIO_JPEG_WE_Y_THRESHOLD_WE_DEASSERT_STALL_TH_SHFT 0x10
+#define HWIO_JPEG_WE_Y_THRESHOLD_WE_ASSERT_STALL_TH_BMSK 0x1ff
+#define HWIO_JPEG_WE_Y_THRESHOLD_WE_ASSERT_STALL_TH_SHFT 0
+
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_WE_DEASSERT_STALL_TH_BMSK 0x1ff0000
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_WE_DEASSERT_STALL_TH_SHFT 0x10
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_WE_ASSERT_STALL_TH_BMSK 0x1ff
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_WE_ASSERT_STALL_TH_SHFT 0
+
+#define HWIO_JPEG_WE_Y_PING_BUFFER_CFG_ADDR (GEMINI_REG_BASE + 0x000000c8)
+#define HWIO_JPEG_WE_Y_PING_BUFFER_CFG_RMSK 0x7fffff
+
+#define HWIO_JPEG_WE_Y_PING_ADDR_ADDR (GEMINI_REG_BASE + 0x000000d8)
+#define HWIO_JPEG_WE_Y_PING_ADDR_RMSK 0xfffffff8
+
+#define HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_ADDR (GEMINI_REG_BASE + 0x000000cc)
+#define HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_RMSK 0x7fffff
+
+#define HWIO_JPEG_WE_Y_PONG_ADDR_ADDR (GEMINI_REG_BASE + 0x000000dc)
+#define HWIO_JPEG_WE_Y_PONG_ADDR_RMSK 0xfffffff8
+
+#define HWIO_JPEG_WE_Y_PING_BUFFER_CFG_WE_BUFFER_LENGTH_BMSK 0x7fffff
+#define HWIO_JPEG_WE_Y_PING_BUFFER_CFG_WE_BUFFER_LENGTH_SHFT 0
+
+#define HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_WE_BUFFER_LENGTH_BMSK 0x7fffff
+#define HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_WE_BUFFER_LENGTH_SHFT 0
+
+#define HWIO_JPEG_IRQ_MASK_ADDR (GEMINI_REG_BASE + 0x00000014)
+#define HWIO_JPEG_IRQ_MASK_RMSK 0xffffffff
+
+#define HWIO_JPEG_IRQ_CLEAR_ADDR (GEMINI_REG_BASE + 0x00000018)
+#define HWIO_JPEG_IRQ_CLEAR_RMSK 0xffffffff
+
+#define HWIO_JPEG_RESET_CMD_ADDR (GEMINI_REG_BASE + 0x00000004)
+#define HWIO_JPEG_RESET_CMD_RMSK 0xe004ffff
+
+#define HWIO_JPEG_IRQ_STATUS_ADDR (GEMINI_REG_BASE + 0x0000001c)
+#define HWIO_JPEG_IRQ_STATUS_RMSK 0xffffffff
+
+#define HWIO_JPEG_STATUS_ENCODE_OUTPUT_SIZE_ADDR (GEMINI_REG_BASE + 0x00000034)
+#define HWIO_JPEG_STATUS_ENCODE_OUTPUT_SIZE_RMSK 0xffffff
+
+#endif /* MSM_GEMINI_HW_REG_H */
diff --git a/drivers/media/video/msm/msm_gemini_platform.c b/drivers/media/video/msm/msm_gemini_platform.c
new file mode 100644
index 0000000..140d5d0
--- /dev/null
+++ b/drivers/media/video/msm/msm_gemini_platform.c
@@ -0,0 +1,154 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/pm_qos_params.h>
+#include <linux/clk.h>
+#include <mach/clk.h>
+#include <linux/io.h>
+#include <linux/android_pmem.h>
+#include <mach/msm_reqs.h>
+#include <mach/camera.h>
+
+#include "msm_gemini_platform.h"
+#include "msm_gemini_common.h"
+#include "msm_gemini_hw.h"
+
+#ifdef CONFIG_MSM_NPA_SYSTEM_BUS
+/* NPA Flow ID */
+#define MSM_SYSTEM_BUS_RATE	MSM_AXI_FLOW_JPEG_12MP
+#else
+/* AXI rate in KHz */
+#define MSM_SYSTEM_BUS_RATE	160000
+#endif
+
+void msm_gemini_platform_p2v(struct file  *file)
+{
+#ifdef CONFIG_ANDROID_PMEM
+	put_pmem_file(file);
+#endif
+}
+
+uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file_p)
+{
+	unsigned long paddr;
+	unsigned long size;
+	int rc;
+
+#ifdef CONFIG_ANDROID_PMEM
+	unsigned long kvstart;
+	rc = get_pmem_file(fd, &paddr, &kvstart, &size, file_p);
+#else
+	rc = 0;
+	paddr = 0;
+	size = 0;
+#endif
+	if (rc < 0) {
+		GMN_PR_ERR("%s: get_pmem_file fd %d error %d\n", __func__, fd,
+			rc);
+		return 0;
+	}
+
+	/* validate user input */
+	if (len > size) {
+		GMN_PR_ERR("%s: invalid offset + len\n", __func__);
+		return 0;
+	}
+
+	return paddr;
+}
+
+int msm_gemini_platform_init(struct platform_device *pdev,
+	struct resource **mem,
+	void **base,
+	int *irq,
+	irqreturn_t (*handler) (int, void *),
+	void *context)
+{
+	int rc = -1;
+	int gemini_irq;
+	struct resource *gemini_mem, *gemini_io, *gemini_irq_res;
+	void *gemini_base;
+
+	gemini_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!gemini_mem) {
+		GMN_PR_ERR("%s: no mem resource?\n", __func__);
+		return -ENODEV;
+	}
+
+	gemini_irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!gemini_irq_res) {
+		GMN_PR_ERR("no irq resource?\n");
+		return -ENODEV;
+	}
+	gemini_irq = gemini_irq_res->start;
+
+	gemini_io = request_mem_region(gemini_mem->start,
+		resource_size(gemini_mem), pdev->name);
+	if (!gemini_io) {
+		GMN_PR_ERR("%s: region already claimed\n", __func__);
+		return -EBUSY;
+	}
+
+	gemini_base = ioremap(gemini_mem->start, resource_size(gemini_mem));
+	if (!gemini_base) {
+		rc = -ENOMEM;
+		GMN_PR_ERR("%s: ioremap failed\n", __func__);
+		goto fail1;
+	}
+
+	rc = msm_camio_jpeg_clk_enable();
+	if (rc) {
+		GMN_PR_ERR("%s: clk failed rc = %d\n", __func__, rc);
+		goto fail2;
+	}
+
+	msm_gemini_hw_init(gemini_base, resource_size(gemini_mem));
+	rc = request_irq(gemini_irq, handler, IRQF_TRIGGER_RISING, "gemini",
+		context);
+	if (rc) {
+		GMN_PR_ERR("%s: request_irq failed, %d\n", __func__,
+			gemini_irq);
+		goto fail3;
+	}
+
+	*mem  = gemini_mem;
+	*base = gemini_base;
+	*irq  = gemini_irq;
+	GMN_DBG("%s:%d] success\n", __func__, __LINE__);
+
+	return rc;
+
+fail3:
+	msm_camio_jpeg_clk_disable();
+fail2:
+	iounmap(gemini_base);
+fail1:
+	release_mem_region(gemini_mem->start, resource_size(gemini_mem));
+	GMN_DBG("%s:%d] fail\n", __func__, __LINE__);
+	return rc;
+}
+
+int msm_gemini_platform_release(struct resource *mem, void *base, int irq,
+	void *context)
+{
+	int result;
+
+	free_irq(irq, context);
+	result = msm_camio_jpeg_clk_disable();
+	iounmap(base);
+	release_mem_region(mem->start, resource_size(mem));
+
+	GMN_DBG("%s:%d] success\n", __func__, __LINE__);
+	return result;
+}
+
diff --git a/drivers/media/video/msm/msm_gemini_platform.h b/drivers/media/video/msm/msm_gemini_platform.h
new file mode 100644
index 0000000..49b1db6
--- /dev/null
+++ b/drivers/media/video/msm/msm_gemini_platform.h
@@ -0,0 +1,34 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef MSM_GEMINI_PLATFORM_H
+#define MSM_GEMINI_PLATFORM_H
+
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+void msm_gemini_platform_p2v(struct file  *file);
+uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file);
+
+int msm_gemini_platform_clk_enable(void);
+int msm_gemini_platform_clk_disable(void);
+
+int msm_gemini_platform_init(struct platform_device *pdev,
+	struct resource **mem,
+	void **base,
+	int *irq,
+	irqreturn_t (*handler) (int, void *),
+	void *context);
+int msm_gemini_platform_release(struct resource *mem, void *base, int irq,
+	void *context);
+
+#endif /* MSM_GEMINI_PLATFORM_H */
diff --git a/drivers/media/video/msm/msm_gemini_sync.c b/drivers/media/video/msm/msm_gemini_sync.c
new file mode 100644
index 0000000..2ad0467
--- /dev/null
+++ b/drivers/media/video/msm/msm_gemini_sync.c
@@ -0,0 +1,839 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <media/msm_gemini.h>
+#include "msm_gemini_sync.h"
+#include "msm_gemini_core.h"
+#include "msm_gemini_platform.h"
+#include "msm_gemini_common.h"
+
+static int release_buf;
+
+/*************** queue helper ****************/
+inline void msm_gemini_q_init(char const *name, struct msm_gemini_q *q_p)
+{
+	GMN_DBG("%s:%d] %s\n", __func__, __LINE__, name);
+	q_p->name = name;
+	spin_lock_init(&q_p->lck);
+	INIT_LIST_HEAD(&q_p->q);
+	init_waitqueue_head(&q_p->wait);
+	q_p->unblck = 0;
+}
+
+inline void *msm_gemini_q_out(struct msm_gemini_q *q_p)
+{
+	unsigned long flags;
+	struct msm_gemini_q_entry *q_entry_p = NULL;
+	void *data = NULL;
+
+	GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+	spin_lock_irqsave(&q_p->lck, flags);
+	if (!list_empty(&q_p->q)) {
+		q_entry_p = list_first_entry(&q_p->q, struct msm_gemini_q_entry,
+			list);
+		list_del_init(&q_entry_p->list);
+	}
+	spin_unlock_irqrestore(&q_p->lck, flags);
+
+	if (q_entry_p) {
+		data = q_entry_p->data;
+		kfree(q_entry_p);
+	} else {
+		GMN_DBG("%s:%d] %s no entry\n", __func__, __LINE__,
+			q_p->name);
+	}
+
+	return data;
+}
+
+inline int msm_gemini_q_in(struct msm_gemini_q *q_p, void *data)
+{
+	unsigned long flags;
+
+	struct msm_gemini_q_entry *q_entry_p;
+
+	GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+
+	q_entry_p = kmalloc(sizeof(struct msm_gemini_q_entry), GFP_ATOMIC);
+	if (!q_entry_p) {
+		GMN_PR_ERR("%s: no mem\n", __func__);
+		return -1;
+	}
+	q_entry_p->data = data;
+
+	spin_lock_irqsave(&q_p->lck, flags);
+	list_add_tail(&q_entry_p->list, &q_p->q);
+	spin_unlock_irqrestore(&q_p->lck, flags);
+
+	return 0;
+}
+
+inline int msm_gemini_q_in_buf(struct msm_gemini_q *q_p,
+	struct msm_gemini_core_buf *buf)
+{
+	struct msm_gemini_core_buf *buf_p;
+
+	GMN_DBG("%s:%d]\n", __func__, __LINE__);
+	buf_p = kmalloc(sizeof(struct msm_gemini_core_buf), GFP_ATOMIC);
+	if (!buf_p) {
+		GMN_PR_ERR("%s: no mem\n", __func__);
+		return -1;
+	}
+
+	memcpy(buf_p, buf, sizeof(struct msm_gemini_core_buf));
+
+	msm_gemini_q_in(q_p, buf_p);
+	return 0;
+}
+
+inline int msm_gemini_q_wait(struct msm_gemini_q *q_p)
+{
+	int tm = MAX_SCHEDULE_TIMEOUT; /* 500ms */
+	int rc;
+
+	GMN_DBG("%s:%d] %s wait\n", __func__, __LINE__, q_p->name);
+	rc = wait_event_interruptible_timeout(q_p->wait,
+		(!list_empty_careful(&q_p->q) || q_p->unblck),
+		msecs_to_jiffies(tm));
+	GMN_DBG("%s:%d] %s wait done\n", __func__, __LINE__, q_p->name);
+	if (list_empty_careful(&q_p->q)) {
+		if (rc == 0) {
+			rc = -ETIMEDOUT;
+			GMN_PR_ERR("%s:%d] %s timeout\n", __func__, __LINE__,
+				q_p->name);
+		} else if (q_p->unblck) {
+			GMN_DBG("%s:%d] %s unblock is true\n", __func__,
+				__LINE__, q_p->name);
+			q_p->unblck = 0;
+			rc = -ECANCELED;
+		} else if (rc < 0) {
+			GMN_PR_ERR("%s:%d] %s rc %d\n", __func__, __LINE__,
+				q_p->name, rc);
+		}
+	}
+	return rc;
+}
+
+inline int msm_gemini_q_wakeup(struct msm_gemini_q *q_p)
+{
+	GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+	wake_up(&q_p->wait);
+	return 0;
+}
+
+inline int msm_gemini_q_unblock(struct msm_gemini_q *q_p)
+{
+	GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+	q_p->unblck = 1;
+	wake_up(&q_p->wait);
+	return 0;
+}
+
+inline void msm_gemini_outbuf_q_cleanup(struct msm_gemini_q *q_p)
+{
+	struct msm_gemini_core_buf *buf_p;
+	GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+	do {
+		buf_p = msm_gemini_q_out(q_p);
+		if (buf_p) {
+			msm_gemini_platform_p2v(buf_p->file);
+			GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+			kfree(buf_p);
+		}
+	} while (buf_p);
+	q_p->unblck = 0;
+}
+
+inline void msm_gemini_q_cleanup(struct msm_gemini_q *q_p)
+{
+	void *data;
+	GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+	do {
+		data = msm_gemini_q_out(q_p);
+		if (data) {
+			GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+			kfree(data);
+		}
+	} while (data);
+	q_p->unblck = 0;
+}
+
+/*************** event queue ****************/
+
+int msm_gemini_framedone_irq(struct msm_gemini_device *pgmn_dev,
+	struct msm_gemini_core_buf *buf_in)
+{
+	int rc = 0;
+
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+	if (buf_in) {
+		buf_in->vbuf.framedone_len = buf_in->framedone_len;
+		buf_in->vbuf.type = MSM_GEMINI_EVT_FRAMEDONE;
+		GMN_DBG("%s:%d] 0x%08x %d framedone_len %d\n",
+			__func__, __LINE__,
+			(int) buf_in->y_buffer_addr, buf_in->y_len,
+			buf_in->vbuf.framedone_len);
+		rc = msm_gemini_q_in_buf(&pgmn_dev->evt_q, buf_in);
+	} else {
+		GMN_PR_ERR("%s:%d] no output return buffer\n",
+			__func__, __LINE__);
+		rc = -1;
+	}
+
+	if (buf_in)
+		rc = msm_gemini_q_wakeup(&pgmn_dev->evt_q);
+
+	return rc;
+}
+
+int msm_gemini_evt_get(struct msm_gemini_device *pgmn_dev,
+	void __user *to)
+{
+	struct msm_gemini_core_buf *buf_p;
+	struct msm_gemini_ctrl_cmd ctrl_cmd;
+
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+	msm_gemini_q_wait(&pgmn_dev->evt_q);
+	buf_p = msm_gemini_q_out(&pgmn_dev->evt_q);
+
+	if (!buf_p) {
+		GMN_DBG("%s:%d] no buffer\n", __func__, __LINE__);
+		return -EAGAIN;
+	}
+
+	ctrl_cmd.type = buf_p->vbuf.type;
+	kfree(buf_p);
+
+	GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+		(int) ctrl_cmd.value, ctrl_cmd.len);
+
+	if (copy_to_user(to, &ctrl_cmd, sizeof(ctrl_cmd))) {
+		GMN_PR_ERR("%s:%d]\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+int msm_gemini_evt_get_unblock(struct msm_gemini_device *pgmn_dev)
+{
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	msm_gemini_q_unblock(&pgmn_dev->evt_q);
+	return 0;
+}
+
+void msm_gemini_reset_ack_irq(struct msm_gemini_device *pgmn_dev)
+{
+	GMN_DBG("%s:%d]\n", __func__, __LINE__);
+}
+
+void msm_gemini_err_irq(struct msm_gemini_device *pgmn_dev,
+	int event)
+{
+	int rc = 0;
+	struct msm_gemini_core_buf buf;
+
+	GMN_PR_ERR("%s:%d] error: %d\n", __func__, __LINE__, event);
+
+	buf.vbuf.type = MSM_GEMINI_EVT_ERR;
+	rc = msm_gemini_q_in_buf(&pgmn_dev->evt_q, &buf);
+	if (!rc)
+		rc = msm_gemini_q_wakeup(&pgmn_dev->evt_q);
+
+	if (!rc)
+		GMN_PR_ERR("%s:%d] err err\n", __func__, __LINE__);
+
+	return;
+}
+
+/*************** output queue ****************/
+
+int msm_gemini_we_pingpong_irq(struct msm_gemini_device *pgmn_dev,
+	struct msm_gemini_core_buf *buf_in)
+{
+	int rc = 0;
+	struct msm_gemini_core_buf *buf_out;
+
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	if (buf_in) {
+		GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+			(int) buf_in->y_buffer_addr, buf_in->y_len);
+		rc = msm_gemini_q_in_buf(&pgmn_dev->output_rtn_q, buf_in);
+	} else {
+		GMN_DBG("%s:%d] no output return buffer\n", __func__,
+			__LINE__);
+		rc = -1;
+	}
+
+	buf_out = msm_gemini_q_out(&pgmn_dev->output_buf_q);
+
+	if (buf_out) {
+		rc = msm_gemini_core_we_buf_update(buf_out);
+		kfree(buf_out);
+	} else {
+		msm_gemini_core_we_buf_reset(buf_in);
+		GMN_DBG("%s:%d] no output buffer\n", __func__, __LINE__);
+		rc = -2;
+	}
+
+	if (buf_in)
+		rc = msm_gemini_q_wakeup(&pgmn_dev->output_rtn_q);
+
+	return rc;
+}
+
+int msm_gemini_output_get(struct msm_gemini_device *pgmn_dev, void __user *to)
+{
+	struct msm_gemini_core_buf *buf_p;
+	struct msm_gemini_buf buf_cmd;
+
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+	msm_gemini_q_wait(&pgmn_dev->output_rtn_q);
+	buf_p = msm_gemini_q_out(&pgmn_dev->output_rtn_q);
+
+	if (!buf_p) {
+		GMN_DBG("%s:%d] no output buffer return\n",
+			__func__, __LINE__);
+		return -EAGAIN;
+	}
+
+	buf_cmd = buf_p->vbuf;
+	msm_gemini_platform_p2v(buf_p->file);
+	kfree(buf_p);
+
+	GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+		(int) buf_cmd.vaddr, buf_cmd.y_len);
+
+	if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) {
+		GMN_PR_ERR("%s:%d]", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+int msm_gemini_output_get_unblock(struct msm_gemini_device *pgmn_dev)
+{
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	msm_gemini_q_unblock(&pgmn_dev->output_rtn_q);
+	return 0;
+}
+
+int msm_gemini_output_buf_enqueue(struct msm_gemini_device *pgmn_dev,
+	void __user *arg)
+{
+	struct msm_gemini_buf buf_cmd;
+	struct msm_gemini_core_buf *buf_p;
+
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_gemini_buf))) {
+		GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	buf_p = kmalloc(sizeof(struct msm_gemini_core_buf), GFP_ATOMIC);
+	if (!buf_p) {
+		GMN_PR_ERR("%s:%d] no mem\n", __func__, __LINE__);
+		return -1;
+	}
+
+	GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, (int) buf_cmd.vaddr,
+		buf_cmd.y_len);
+
+	buf_p->y_buffer_addr = msm_gemini_platform_v2p(buf_cmd.fd,
+		buf_cmd.y_len, &buf_p->file);
+	if (!buf_p->y_buffer_addr) {
+		GMN_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
+		kfree(buf_p);
+		return -1;
+	}
+	buf_p->y_len = buf_cmd.y_len;
+	buf_p->vbuf = buf_cmd;
+
+	msm_gemini_q_in(&pgmn_dev->output_buf_q, buf_p);
+	return 0;
+}
+
+/*************** input queue ****************/
+
+int msm_gemini_fe_pingpong_irq(struct msm_gemini_device *pgmn_dev,
+	struct msm_gemini_core_buf *buf_in)
+{
+	struct msm_gemini_core_buf *buf_out;
+	int rc = 0;
+
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	if (buf_in) {
+		GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+			(int) buf_in->y_buffer_addr, buf_in->y_len);
+		rc = msm_gemini_q_in_buf(&pgmn_dev->input_rtn_q, buf_in);
+	} else {
+		GMN_DBG("%s:%d] no input return buffer\n", __func__,
+			__LINE__);
+		rc = -1;
+	}
+
+	buf_out = msm_gemini_q_out(&pgmn_dev->input_buf_q);
+
+	if (buf_out) {
+		rc = msm_gemini_core_fe_buf_update(buf_out);
+		kfree(buf_out);
+		msm_gemini_core_fe_start();
+	} else {
+		GMN_DBG("%s:%d] no input buffer\n", __func__, __LINE__);
+		rc = -2;
+	}
+
+	if (buf_in)
+		rc = msm_gemini_q_wakeup(&pgmn_dev->input_rtn_q);
+
+	return rc;
+}
+
+int msm_gemini_input_get(struct msm_gemini_device *pgmn_dev, void __user * to)
+{
+	struct msm_gemini_core_buf *buf_p;
+	struct msm_gemini_buf buf_cmd;
+
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	msm_gemini_q_wait(&pgmn_dev->input_rtn_q);
+	buf_p = msm_gemini_q_out(&pgmn_dev->input_rtn_q);
+
+	if (!buf_p) {
+		GMN_DBG("%s:%d] no input buffer return\n",
+			__func__, __LINE__);
+		return -EAGAIN;
+	}
+
+	buf_cmd = buf_p->vbuf;
+	msm_gemini_platform_p2v(buf_p->file);
+	kfree(buf_p);
+
+	GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+		(int) buf_cmd.vaddr, buf_cmd.y_len);
+
+	if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) {
+		GMN_PR_ERR("%s:%d]\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+int msm_gemini_input_get_unblock(struct msm_gemini_device *pgmn_dev)
+{
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	msm_gemini_q_unblock(&pgmn_dev->input_rtn_q);
+	return 0;
+}
+
+int msm_gemini_input_buf_enqueue(struct msm_gemini_device *pgmn_dev,
+	void __user *arg)
+{
+	struct msm_gemini_core_buf *buf_p;
+	struct msm_gemini_buf buf_cmd;
+
+	if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_gemini_buf))) {
+		GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	buf_p = kmalloc(sizeof(struct msm_gemini_core_buf), GFP_ATOMIC);
+	if (!buf_p) {
+		GMN_PR_ERR("%s:%d] no mem\n", __func__, __LINE__);
+		return -1;
+	}
+
+	GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+		(int) buf_cmd.vaddr, buf_cmd.y_len);
+
+	buf_p->y_buffer_addr    = msm_gemini_platform_v2p(buf_cmd.fd,
+		buf_cmd.y_len + buf_cmd.cbcr_len, &buf_p->file)
+		+ buf_cmd.offset;
+	buf_p->y_len          = buf_cmd.y_len;
+
+	buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + buf_cmd.y_len;
+	buf_p->cbcr_len       = buf_cmd.cbcr_len;
+
+	buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows;
+
+	if (!buf_p->y_buffer_addr || !buf_p->cbcr_buffer_addr) {
+		GMN_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
+		kfree(buf_p);
+		return -1;
+	}
+	buf_p->vbuf           = buf_cmd;
+
+	msm_gemini_q_in(&pgmn_dev->input_buf_q, buf_p);
+
+	return 0;
+}
+
+int msm_gemini_irq(int event, void *context, void *data)
+{
+	struct msm_gemini_device *pgmn_dev =
+		(struct msm_gemini_device *) context;
+
+	switch (event) {
+	case MSM_GEMINI_HW_MASK_COMP_FRAMEDONE:
+		msm_gemini_framedone_irq(pgmn_dev, data);
+		msm_gemini_we_pingpong_irq(pgmn_dev, data);
+		break;
+
+	case MSM_GEMINI_HW_MASK_COMP_FE:
+		msm_gemini_fe_pingpong_irq(pgmn_dev, data);
+		break;
+
+	case MSM_GEMINI_HW_MASK_COMP_WE:
+		msm_gemini_we_pingpong_irq(pgmn_dev, data);
+		break;
+
+	case MSM_GEMINI_HW_MASK_COMP_RESET_ACK:
+		msm_gemini_reset_ack_irq(pgmn_dev);
+		break;
+
+	case MSM_GEMINI_HW_MASK_COMP_ERR:
+	default:
+		msm_gemini_err_irq(pgmn_dev, event);
+		break;
+	}
+
+	return 0;
+}
+
+int __msm_gemini_open(struct msm_gemini_device *pgmn_dev)
+{
+	int rc;
+
+	mutex_lock(&pgmn_dev->lock);
+	if (pgmn_dev->open_count) {
+		/* only open once */
+		GMN_PR_ERR("%s:%d] busy\n", __func__, __LINE__);
+		mutex_unlock(&pgmn_dev->lock);
+		return -EBUSY;
+	}
+	pgmn_dev->open_count++;
+	mutex_unlock(&pgmn_dev->lock);
+
+	msm_gemini_core_irq_install(msm_gemini_irq);
+	rc = msm_gemini_platform_init(pgmn_dev->pdev,
+		&pgmn_dev->mem, &pgmn_dev->base,
+		&pgmn_dev->irq, msm_gemini_core_irq, pgmn_dev);
+	if (rc) {
+		GMN_PR_ERR("%s:%d] platform_init fail %d\n", __func__,
+			__LINE__, rc);
+		return rc;
+	}
+
+	GMN_DBG("%s:%d] platform resources - mem %p, base %p, irq %d\n",
+		__func__, __LINE__,
+		pgmn_dev->mem, pgmn_dev->base, pgmn_dev->irq);
+
+	msm_gemini_q_cleanup(&pgmn_dev->evt_q);
+	msm_gemini_q_cleanup(&pgmn_dev->output_rtn_q);
+	msm_gemini_outbuf_q_cleanup(&pgmn_dev->output_buf_q);
+	msm_gemini_q_cleanup(&pgmn_dev->input_rtn_q);
+	msm_gemini_q_cleanup(&pgmn_dev->input_buf_q);
+	msm_gemini_core_init();
+
+	GMN_DBG("%s:%d] success\n", __func__, __LINE__);
+	return rc;
+}
+
+int __msm_gemini_release(struct msm_gemini_device *pgmn_dev)
+{
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	mutex_lock(&pgmn_dev->lock);
+	if (!pgmn_dev->open_count) {
+		GMN_PR_ERR(KERN_ERR "%s: not opened\n", __func__);
+		mutex_unlock(&pgmn_dev->lock);
+		return -EINVAL;
+	}
+	pgmn_dev->open_count--;
+	mutex_unlock(&pgmn_dev->lock);
+
+	msm_gemini_core_release(release_buf);
+	msm_gemini_q_cleanup(&pgmn_dev->evt_q);
+	msm_gemini_q_cleanup(&pgmn_dev->output_rtn_q);
+	msm_gemini_outbuf_q_cleanup(&pgmn_dev->output_buf_q);
+	msm_gemini_q_cleanup(&pgmn_dev->input_rtn_q);
+	msm_gemini_outbuf_q_cleanup(&pgmn_dev->input_buf_q);
+
+	if (pgmn_dev->open_count)
+		GMN_PR_ERR(KERN_ERR "%s: multiple opens\n", __func__);
+
+	msm_gemini_platform_release(pgmn_dev->mem, pgmn_dev->base,
+		pgmn_dev->irq, pgmn_dev);
+
+	return 0;
+}
+
+int msm_gemini_ioctl_hw_cmd(struct msm_gemini_device *pgmn_dev,
+	void * __user arg)
+{
+	struct msm_gemini_hw_cmd hw_cmd;
+	int is_copy_to_user;
+
+	if (copy_from_user(&hw_cmd, arg, sizeof(struct msm_gemini_hw_cmd))) {
+		GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	is_copy_to_user = msm_gemini_hw_exec_cmds(&hw_cmd, 1);
+	GMN_DBG("%s:%d] type %d, n %d, offset %d, mask %x, data %x, pdata %x\n",
+		__func__, __LINE__, hw_cmd.type, hw_cmd.n, hw_cmd.offset,
+		hw_cmd.mask, hw_cmd.data, (int) hw_cmd.pdata);
+
+	if (is_copy_to_user >= 0) {
+		if (copy_to_user(arg, &hw_cmd, sizeof(hw_cmd))) {
+			GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+
+int msm_gemini_ioctl_hw_cmds(struct msm_gemini_device *pgmn_dev,
+	void * __user arg)
+{
+	int is_copy_to_user;
+	int len;
+	uint32_t m;
+	struct msm_gemini_hw_cmds *hw_cmds_p;
+	struct msm_gemini_hw_cmd *hw_cmd_p;
+
+	if (copy_from_user(&m, arg, sizeof(m))) {
+		GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	len = sizeof(struct msm_gemini_hw_cmds) +
+		sizeof(struct msm_gemini_hw_cmd) * (m - 1);
+	hw_cmds_p = kmalloc(len, GFP_KERNEL);
+	if (!hw_cmds_p) {
+		GMN_PR_ERR("%s:%d] no mem %d\n", __func__, __LINE__, len);
+		return -EFAULT;
+	}
+
+	if (copy_from_user(hw_cmds_p, arg, len)) {
+		GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		kfree(hw_cmds_p);
+		return -EFAULT;
+	}
+
+	hw_cmd_p = (struct msm_gemini_hw_cmd *) &(hw_cmds_p->hw_cmd);
+
+	is_copy_to_user = msm_gemini_hw_exec_cmds(hw_cmd_p, m);
+
+	if (is_copy_to_user >= 0) {
+		if (copy_to_user(arg, hw_cmds_p, len)) {
+			GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+			kfree(hw_cmds_p);
+			return -EFAULT;
+		}
+	}
+	kfree(hw_cmds_p);
+	return 0;
+}
+
+int msm_gemini_start(struct msm_gemini_device *pgmn_dev, void * __user arg)
+{
+	struct msm_gemini_core_buf *buf_out;
+	struct msm_gemini_core_buf *buf_out_free[2] = {NULL, NULL};
+	int i, rc;
+
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+	release_buf = 1;
+	for (i = 0; i < 2; i++) {
+		buf_out = msm_gemini_q_out(&pgmn_dev->input_buf_q);
+
+		if (buf_out) {
+			msm_gemini_core_fe_buf_update(buf_out);
+			kfree(buf_out);
+		} else {
+			GMN_DBG("%s:%d] no input buffer\n", __func__, __LINE__);
+			break;
+		}
+	}
+
+	for (i = 0; i < 2; i++) {
+		buf_out_free[i] = msm_gemini_q_out(&pgmn_dev->output_buf_q);
+
+		if (buf_out_free[i]) {
+			msm_gemini_core_we_buf_update(buf_out_free[i]);
+		} else if (i == 1) {
+			/* set the pong to same address as ping */
+			buf_out_free[0]->y_len >>= 1;
+			buf_out_free[0]->y_buffer_addr +=
+				buf_out_free[0]->y_len;
+			msm_gemini_core_we_buf_update(buf_out_free[0]);
+			/* since ping and pong are same buf release only once*/
+			release_buf = 0;
+		} else {
+			GMN_DBG("%s:%d] no output buffer\n",
+			__func__, __LINE__);
+			break;
+		}
+	}
+
+	for (i = 0; i < 2; i++)
+		kfree(buf_out_free[i]);
+
+	rc = msm_gemini_ioctl_hw_cmds(pgmn_dev, arg);
+	GMN_DBG("%s:%d]\n", __func__, __LINE__);
+	return rc;
+}
+
+int msm_gemini_ioctl_reset(struct msm_gemini_device *pgmn_dev,
+	void * __user arg)
+{
+	int rc;
+	struct msm_gemini_ctrl_cmd ctrl_cmd;
+
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	if (copy_from_user(&ctrl_cmd, arg, sizeof(ctrl_cmd))) {
+		GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	pgmn_dev->op_mode = ctrl_cmd.type;
+
+	rc = msm_gemini_core_reset(pgmn_dev->op_mode, pgmn_dev->base,
+		resource_size(pgmn_dev->mem));
+	return rc;
+}
+
+int msm_gemini_ioctl_test_dump_region(struct msm_gemini_device *pgmn_dev,
+	unsigned long arg)
+{
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	msm_gemini_hw_region_dump(arg);
+	return 0;
+}
+
+long __msm_gemini_ioctl(struct msm_gemini_device *pgmn_dev,
+	unsigned int cmd, unsigned long arg)
+{
+	int rc = 0;
+	switch (cmd) {
+	case MSM_GMN_IOCTL_GET_HW_VERSION:
+		GMN_DBG("%s:%d] VERSION 1\n", __func__, __LINE__);
+		rc = msm_gemini_ioctl_hw_cmd(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_GMN_IOCTL_RESET:
+		rc = msm_gemini_ioctl_reset(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_GMN_IOCTL_STOP:
+		rc = msm_gemini_ioctl_hw_cmds(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_GMN_IOCTL_START:
+		rc = msm_gemini_start(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_GMN_IOCTL_INPUT_BUF_ENQUEUE:
+		rc = msm_gemini_input_buf_enqueue(pgmn_dev,
+			(void __user *) arg);
+		break;
+
+	case MSM_GMN_IOCTL_INPUT_GET:
+		rc = msm_gemini_input_get(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_GMN_IOCTL_INPUT_GET_UNBLOCK:
+		rc = msm_gemini_input_get_unblock(pgmn_dev);
+		break;
+
+	case MSM_GMN_IOCTL_OUTPUT_BUF_ENQUEUE:
+		rc = msm_gemini_output_buf_enqueue(pgmn_dev,
+			(void __user *) arg);
+		break;
+
+	case MSM_GMN_IOCTL_OUTPUT_GET:
+		rc = msm_gemini_output_get(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_GMN_IOCTL_OUTPUT_GET_UNBLOCK:
+		rc = msm_gemini_output_get_unblock(pgmn_dev);
+		break;
+
+	case MSM_GMN_IOCTL_EVT_GET:
+		rc = msm_gemini_evt_get(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_GMN_IOCTL_EVT_GET_UNBLOCK:
+		rc = msm_gemini_evt_get_unblock(pgmn_dev);
+		break;
+
+	case MSM_GMN_IOCTL_HW_CMD:
+		rc = msm_gemini_ioctl_hw_cmd(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_GMN_IOCTL_HW_CMDS:
+		rc = msm_gemini_ioctl_hw_cmds(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_GMN_IOCTL_TEST_DUMP_REGION:
+		rc = msm_gemini_ioctl_test_dump_region(pgmn_dev, arg);
+		break;
+
+	default:
+		GMN_PR_ERR(KERN_INFO "%s:%d] cmd = %d not supported\n",
+			__func__, __LINE__, _IOC_NR(cmd));
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+struct msm_gemini_device *__msm_gemini_init(struct platform_device *pdev)
+{
+	struct msm_gemini_device *pgmn_dev;
+
+	pgmn_dev = kzalloc(sizeof(struct msm_gemini_device), GFP_ATOMIC);
+	if (!pgmn_dev) {
+		GMN_PR_ERR("%s:%d]no mem\n", __func__, __LINE__);
+		return NULL;
+	}
+
+	mutex_init(&pgmn_dev->lock);
+
+	pgmn_dev->pdev = pdev;
+
+	msm_gemini_q_init("evt_q", &pgmn_dev->evt_q);
+	msm_gemini_q_init("output_rtn_q", &pgmn_dev->output_rtn_q);
+	msm_gemini_q_init("output_buf_q", &pgmn_dev->output_buf_q);
+	msm_gemini_q_init("input_rtn_q", &pgmn_dev->input_rtn_q);
+	msm_gemini_q_init("input_buf_q", &pgmn_dev->input_buf_q);
+
+	return pgmn_dev;
+}
+
+int __msm_gemini_exit(struct msm_gemini_device *pgmn_dev)
+{
+	mutex_destroy(&pgmn_dev->lock);
+	kfree(pgmn_dev);
+	return 0;
+}
+
diff --git a/drivers/media/video/msm/msm_gemini_sync.h b/drivers/media/video/msm/msm_gemini_sync.h
new file mode 100644
index 0000000..6c69a92
--- /dev/null
+++ b/drivers/media/video/msm/msm_gemini_sync.h
@@ -0,0 +1,77 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef MSM_GEMINI_SYNC_H
+#define MSM_GEMINI_SYNC_H
+
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include "msm_gemini_core.h"
+
+struct msm_gemini_q {
+	char const	*name;
+	struct list_head  q;
+	spinlock_t	lck;
+	wait_queue_head_t wait;
+	int	       unblck;
+};
+
+struct msm_gemini_q_entry {
+	struct list_head list;
+	void   *data;
+};
+
+struct msm_gemini_device {
+	struct platform_device *pdev;
+	struct resource        *mem;
+	int                     irq;
+	void                   *base;
+
+	struct device *device;
+	struct cdev   cdev;
+	struct mutex  lock;
+	char	  open_count;
+	uint8_t       op_mode;
+
+	/* event queue including frame done & err indications
+	 */
+	struct msm_gemini_q evt_q;
+
+	/* output return queue
+	 */
+	struct msm_gemini_q output_rtn_q;
+
+	/* output buf queue
+	 */
+	struct msm_gemini_q output_buf_q;
+
+	/* input return queue
+	 */
+	struct msm_gemini_q input_rtn_q;
+
+	/* input buf queue
+	 */
+	struct msm_gemini_q input_buf_q;
+};
+
+int __msm_gemini_open(struct msm_gemini_device *pgmn_dev);
+int __msm_gemini_release(struct msm_gemini_device *pgmn_dev);
+
+long __msm_gemini_ioctl(struct msm_gemini_device *pgmn_dev,
+	unsigned int cmd, unsigned long arg);
+
+struct msm_gemini_device *__msm_gemini_init(struct platform_device *pdev);
+int __msm_gemini_exit(struct msm_gemini_device *pgmn_dev);
+
+#endif /* MSM_GEMINI_SYNC_H */
diff --git a/drivers/media/video/msm/msm_io7x.c b/drivers/media/video/msm/msm_io7x.c
new file mode 100644
index 0000000..1befec6
--- /dev/null
+++ b/drivers/media/video/msm/msm_io7x.c
@@ -0,0 +1,318 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/camera.h>
+#include <mach/clk.h>
+
+#define CAMIF_CFG_RMSK 0x1fffff
+#define CAM_SEL_BMSK 0x2
+#define CAM_PCLK_SRC_SEL_BMSK 0x60000
+#define CAM_PCLK_INVERT_BMSK 0x80000
+#define CAM_PAD_REG_SW_RESET_BMSK 0x100000
+
+#define EXT_CAM_HSYNC_POL_SEL_BMSK 0x10000
+#define EXT_CAM_VSYNC_POL_SEL_BMSK 0x8000
+#define MDDI_CLK_CHICKEN_BIT_BMSK  0x80
+
+#define CAM_SEL_SHFT 0x1
+#define CAM_PCLK_SRC_SEL_SHFT 0x11
+#define CAM_PCLK_INVERT_SHFT 0x13
+#define CAM_PAD_REG_SW_RESET_SHFT 0x14
+
+#define EXT_CAM_HSYNC_POL_SEL_SHFT 0x10
+#define EXT_CAM_VSYNC_POL_SEL_SHFT 0xF
+#define MDDI_CLK_CHICKEN_BIT_SHFT  0x7
+#define APPS_RESET_OFFSET 0x00000210
+
+static struct clk *camio_vfe_mdc_clk;
+static struct clk *camio_mdc_clk;
+static struct clk *camio_vfe_clk;
+
+static struct msm_camera_io_ext camio_ext;
+static struct resource *appio, *mdcio;
+void __iomem *appbase, *mdcbase;
+
+static struct resource *appio, *mdcio;
+void __iomem *appbase, *mdcbase;
+
+int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
+{
+	int rc = -1;
+	struct clk *clk = NULL;
+
+	switch (clktype) {
+	case CAMIO_VFE_MDC_CLK:
+		clk = camio_vfe_mdc_clk = clk_get(NULL, "vfe_mdc_clk");
+		break;
+
+	case CAMIO_MDC_CLK:
+		clk = camio_mdc_clk = clk_get(NULL, "mdc_clk");
+		break;
+
+	case CAMIO_VFE_CLK:
+		clk = camio_vfe_clk = clk_get(NULL, "vfe_clk");
+		break;
+
+	default:
+		break;
+	}
+
+	if (!IS_ERR(clk)) {
+		clk_enable(clk);
+		rc = 0;
+	}
+
+	return rc;
+}
+
+int msm_camio_clk_disable(enum msm_camio_clk_type clktype)
+{
+	int rc = -1;
+	struct clk *clk = NULL;
+
+	switch (clktype) {
+	case CAMIO_VFE_MDC_CLK:
+		clk = camio_vfe_mdc_clk;
+		break;
+
+	case CAMIO_MDC_CLK:
+		clk = camio_mdc_clk;
+		break;
+
+	case CAMIO_VFE_CLK:
+		clk = camio_vfe_clk;
+		break;
+
+	default:
+		break;
+	}
+
+	if (!IS_ERR(clk)) {
+		clk_disable(clk);
+		clk_put(clk);
+		rc = 0;
+	}
+
+	return rc;
+}
+
+void msm_camio_clk_rate_set(int rate)
+{
+	struct clk *clk = camio_vfe_clk;
+
+	if (clk != ERR_PTR(-ENOENT))
+		clk_set_rate(clk, rate);
+}
+
+int msm_camio_enable(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+	camio_ext = camdev->ioext;
+
+	appio = request_mem_region(camio_ext.appphy,
+		camio_ext.appsz, pdev->name);
+	if (!appio) {
+		rc = -EBUSY;
+		goto enable_fail;
+	}
+
+	appbase = ioremap(camio_ext.appphy,
+		camio_ext.appsz);
+	if (!appbase) {
+		rc = -ENOMEM;
+		goto apps_no_mem;
+	}
+
+	msm_camio_clk_enable(CAMIO_VFE_CLK);
+	msm_camio_clk_enable(CAMIO_MDC_CLK);
+	return 0;
+apps_no_mem:
+	release_mem_region(camio_ext.appphy, camio_ext.appsz);
+enable_fail:
+	return rc;
+}
+
+int msm_camio_sensor_clk_on(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	int32_t rc = 0;
+	camio_ext = camdev->ioext;
+	mdcio = request_mem_region(camio_ext.mdcphy,
+		camio_ext.mdcsz, pdev->name);
+	if (!mdcio)
+		rc = -EBUSY;
+	mdcbase = ioremap(camio_ext.mdcphy,
+		camio_ext.mdcsz);
+	if (!mdcbase) {
+		rc = -EINVAL;
+		goto mdc_no_mem;
+	}
+	camdev->camera_gpio_on();
+	return msm_camio_clk_enable(CAMIO_VFE_MDC_CLK);
+
+mdc_no_mem:
+	release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz);
+	return rc;
+}
+
+int msm_camio_sensor_clk_off(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	camdev->camera_gpio_off();
+	iounmap(mdcbase);
+	release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz);
+	return msm_camio_clk_disable(CAMIO_VFE_MDC_CLK);
+}
+
+void msm_camio_disable(struct platform_device *pdev)
+{
+	iounmap(appbase);
+	release_mem_region(camio_ext.appphy, camio_ext.appsz);
+	msm_camio_clk_disable(CAMIO_VFE_CLK);
+	msm_camio_clk_disable(CAMIO_MDC_CLK);
+}
+
+void msm_disable_io_gpio_clk(struct platform_device *pdev)
+{
+	return;
+}
+
+void msm_camio_camif_pad_reg_reset(void)
+{
+	uint32_t reg;
+	uint32_t mask, value;
+
+	/* select CLKRGM_VFE_SRC_CAM_VFE_SRC:  internal source */
+	msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_INTERNAL);
+
+	reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+
+	mask = CAM_SEL_BMSK |
+		CAM_PCLK_SRC_SEL_BMSK |
+		CAM_PCLK_INVERT_BMSK;
+
+	value = 1 << CAM_SEL_SHFT |
+		3 << CAM_PCLK_SRC_SEL_SHFT |
+		0 << CAM_PCLK_INVERT_SHFT;
+
+	writel((reg & (~mask)) | (value & mask), mdcbase);
+	msleep(10);
+
+	reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+	mask = CAM_PAD_REG_SW_RESET_BMSK;
+	value = 1 << CAM_PAD_REG_SW_RESET_SHFT;
+	writel((reg & (~mask)) | (value & mask), mdcbase);
+	msleep(10);
+
+	reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+	mask = CAM_PAD_REG_SW_RESET_BMSK;
+	value = 0 << CAM_PAD_REG_SW_RESET_SHFT;
+	writel((reg & (~mask)) | (value & mask), mdcbase);
+	msleep(10);
+
+	msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_EXTERNAL);
+	msleep(10);
+}
+
+void msm_camio_vfe_blk_reset(void)
+{
+	uint32_t val;
+
+	/* do apps reset */
+	val = readl(appbase + 0x00000210);
+	val |= 0x1;
+	writel(val, appbase + 0x00000210);
+	mdelay(10);
+
+	val = readl(appbase + 0x00000210);
+	val &= ~0x1;
+	writel(val, appbase + 0x00000210);
+	mdelay(10);
+
+	/* do axi reset */
+	val = readl(appbase + 0x00000208);
+	val |= 0x1;
+	writel(val, appbase + 0x00000208);
+	mdelay(10);
+
+	val = readl(appbase + 0x00000208);
+	val &= ~0x1;
+	writel(val, appbase + 0x00000208);
+	mdelay(10);
+}
+
+void msm_camio_camif_pad_reg_reset_2(void)
+{
+	uint32_t reg;
+	uint32_t mask, value;
+
+	reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+	mask = CAM_PAD_REG_SW_RESET_BMSK;
+	value = 1 << CAM_PAD_REG_SW_RESET_SHFT;
+	writel((reg & (~mask)) | (value & mask), mdcbase);
+	mdelay(10);
+
+	reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+	mask = CAM_PAD_REG_SW_RESET_BMSK;
+	value = 0 << CAM_PAD_REG_SW_RESET_SHFT;
+	writel((reg & (~mask)) | (value & mask), mdcbase);
+	mdelay(10);
+}
+
+void msm_camio_clk_sel(enum msm_camio_clk_src_type srctype)
+{
+	struct clk *clk = NULL;
+
+	clk = camio_vfe_clk;
+
+	if (clk != NULL && clk != ERR_PTR(-ENOENT)) {
+		switch (srctype) {
+		case MSM_CAMIO_CLK_SRC_INTERNAL:
+			clk_set_flags(clk, 0x00000100 << 1);
+			break;
+
+		case MSM_CAMIO_CLK_SRC_EXTERNAL:
+			clk_set_flags(clk, 0x00000100);
+			break;
+
+		default:
+			break;
+		}
+	}
+}
+
+int msm_camio_probe_on(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	camdev->camera_gpio_on();
+	return msm_camio_clk_enable(CAMIO_VFE_CLK);
+}
+
+int msm_camio_probe_off(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	camdev->camera_gpio_off();
+	return msm_camio_clk_disable(CAMIO_VFE_CLK);
+}
diff --git a/drivers/media/video/msm/msm_io8x.c b/drivers/media/video/msm/msm_io8x.c
new file mode 100644
index 0000000..6bc92b0
--- /dev/null
+++ b/drivers/media/video/msm/msm_io8x.c
@@ -0,0 +1,331 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/camera.h>
+#include <mach/clk.h>
+
+#define CAMIF_CFG_RMSK 0x1fffff
+#define CAM_SEL_BMSK 0x2
+#define CAM_PCLK_SRC_SEL_BMSK 0x60000
+#define CAM_PCLK_INVERT_BMSK 0x80000
+#define CAM_PAD_REG_SW_RESET_BMSK 0x100000
+
+#define EXT_CAM_HSYNC_POL_SEL_BMSK 0x10000
+#define EXT_CAM_VSYNC_POL_SEL_BMSK 0x8000
+#define MDDI_CLK_CHICKEN_BIT_BMSK  0x80
+
+#define CAM_SEL_SHFT 0x1
+#define CAM_PCLK_SRC_SEL_SHFT 0x11
+#define CAM_PCLK_INVERT_SHFT 0x13
+#define CAM_PAD_REG_SW_RESET_SHFT 0x14
+
+#define EXT_CAM_HSYNC_POL_SEL_SHFT 0x10
+#define EXT_CAM_VSYNC_POL_SEL_SHFT 0xF
+#define MDDI_CLK_CHICKEN_BIT_SHFT  0x7
+#define APPS_RESET_OFFSET 0x00000214
+
+static struct clk *camio_vfe_mdc_clk;
+static struct clk *camio_mdc_clk;
+static struct clk *camio_vfe_clk;
+static struct clk *camio_vfe_axi_clk;
+static struct msm_camera_io_ext camio_ext;
+static struct resource *appio, *mdcio;
+
+void __iomem *appbase, *mdcbase;
+
+
+int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
+{
+	int rc = 0;
+	struct clk *clk = NULL;
+
+	switch (clktype) {
+	case CAMIO_VFE_MDC_CLK:
+		camio_vfe_mdc_clk = clk = clk_get(NULL, "vfe_mdc_clk");
+		break;
+
+	case CAMIO_MDC_CLK:
+		camio_mdc_clk = clk = clk_get(NULL, "mdc_clk");
+		break;
+
+	case CAMIO_VFE_CLK:
+		camio_vfe_clk = clk = clk_get(NULL, "vfe_clk");
+		break;
+
+	case CAMIO_VFE_AXI_CLK:
+		camio_vfe_axi_clk = clk = clk_get(NULL, "vfe_axi_clk");
+		break;
+
+	default:
+		break;
+	}
+
+	if (!IS_ERR(clk))
+		clk_enable(clk);
+	else
+		rc = -1;
+
+	return rc;
+}
+
+int msm_camio_clk_disable(enum msm_camio_clk_type clktype)
+{
+	int rc = 0;
+	struct clk *clk = NULL;
+
+	switch (clktype) {
+	case CAMIO_VFE_MDC_CLK:
+		clk = camio_vfe_mdc_clk;
+		break;
+
+	case CAMIO_MDC_CLK:
+		clk = camio_mdc_clk;
+		break;
+
+	case CAMIO_VFE_CLK:
+		clk = camio_vfe_clk;
+		break;
+
+	case CAMIO_VFE_AXI_CLK:
+		clk = camio_vfe_axi_clk;
+		break;
+
+	default:
+		break;
+	}
+
+	if (!IS_ERR(clk)) {
+		clk_disable(clk);
+		clk_put(clk);
+	} else
+		rc = -1;
+
+	return rc;
+}
+
+void msm_camio_clk_rate_set(int rate)
+{
+	struct clk *clk = camio_vfe_mdc_clk;
+
+	/* TODO: check return */
+	clk_set_rate(clk, rate);
+}
+
+int msm_camio_enable(struct platform_device *pdev)
+{
+	int rc = 0;
+
+	appio = request_mem_region(camio_ext.appphy,
+		camio_ext.appsz, pdev->name);
+	if (!appio) {
+		rc = -EBUSY;
+		goto enable_fail;
+	}
+
+	appbase = ioremap(camio_ext.appphy, camio_ext.appsz);
+	if (!appbase) {
+		rc = -ENOMEM;
+		goto apps_no_mem;
+	}
+	msm_camio_clk_enable(CAMIO_MDC_CLK);
+	msm_camio_clk_enable(CAMIO_VFE_AXI_CLK);
+	return 0;
+
+apps_no_mem:
+	release_mem_region(camio_ext.appphy, camio_ext.appsz);
+enable_fail:
+	return rc;
+}
+
+void msm_camio_disable(struct platform_device *pdev)
+{
+	iounmap(appbase);
+	release_mem_region(camio_ext.appphy, camio_ext.appsz);
+	msm_camio_clk_disable(CAMIO_MDC_CLK);
+	msm_camio_clk_disable(CAMIO_VFE_AXI_CLK);
+}
+
+int msm_camio_sensor_clk_on(struct platform_device *pdev)
+{
+
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	int32_t rc = 0;
+	camio_ext = camdev->ioext;
+
+	mdcio = request_mem_region(camio_ext.mdcphy,
+		camio_ext.mdcsz, pdev->name);
+	if (!mdcio)
+		rc = -EBUSY;
+	mdcbase = ioremap(camio_ext.mdcphy,
+		camio_ext.mdcsz);
+	if (!mdcbase)
+		goto mdc_no_mem;
+	camdev->camera_gpio_on();
+
+	msm_camio_clk_enable(CAMIO_VFE_CLK);
+	msm_camio_clk_enable(CAMIO_VFE_MDC_CLK);
+	return rc;
+
+
+mdc_no_mem:
+	release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz);
+	return -EINVAL;
+}
+
+int msm_camio_sensor_clk_off(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	camdev->camera_gpio_off();
+	iounmap(mdcbase);
+	release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz);
+	msm_camio_clk_disable(CAMIO_VFE_CLK);
+	return msm_camio_clk_disable(CAMIO_VFE_MDC_CLK);
+
+}
+
+void msm_disable_io_gpio_clk(struct platform_device *pdev)
+{
+	return;
+}
+
+void msm_camio_camif_pad_reg_reset(void)
+{
+	uint32_t reg;
+	uint32_t mask, value;
+
+	/* select CLKRGM_VFE_SRC_CAM_VFE_SRC:  internal source */
+	msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_INTERNAL);
+
+	reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+
+	mask = CAM_SEL_BMSK |
+		CAM_PCLK_SRC_SEL_BMSK |
+		CAM_PCLK_INVERT_BMSK |
+		EXT_CAM_HSYNC_POL_SEL_BMSK |
+	    EXT_CAM_VSYNC_POL_SEL_BMSK | MDDI_CLK_CHICKEN_BIT_BMSK;
+
+	value = 1 << CAM_SEL_SHFT |
+		3 << CAM_PCLK_SRC_SEL_SHFT |
+		0 << CAM_PCLK_INVERT_SHFT |
+		0 << EXT_CAM_HSYNC_POL_SEL_SHFT |
+	    0 << EXT_CAM_VSYNC_POL_SEL_SHFT | 0 << MDDI_CLK_CHICKEN_BIT_SHFT;
+	writel((reg & (~mask)) | (value & mask), mdcbase);
+	msleep(10);
+
+	reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+	mask = CAM_PAD_REG_SW_RESET_BMSK;
+	value = 1 << CAM_PAD_REG_SW_RESET_SHFT;
+	writel((reg & (~mask)) | (value & mask), mdcbase);
+	msleep(10);
+
+	reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+	mask = CAM_PAD_REG_SW_RESET_BMSK;
+	value = 0 << CAM_PAD_REG_SW_RESET_SHFT;
+	writel((reg & (~mask)) | (value & mask), mdcbase);
+	msleep(10);
+
+	msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_EXTERNAL);
+
+	msleep(10);
+
+	/* todo: check return */
+	if (camio_vfe_clk)
+		clk_set_rate(camio_vfe_clk, 96000000);
+}
+
+void msm_camio_vfe_blk_reset(void)
+{
+	uint32_t val;
+
+	val = readl(appbase + APPS_RESET_OFFSET);
+	val |= 0x1;
+	writel(val, appbase + APPS_RESET_OFFSET);
+	mdelay(10);
+
+	val = readl(appbase + APPS_RESET_OFFSET);
+	val &= ~0x1;
+	writel(val, appbase + APPS_RESET_OFFSET);
+	mdelay(10);
+}
+
+void msm_camio_camif_pad_reg_reset_2(void)
+{
+	uint32_t reg;
+	uint32_t mask, value;
+
+	reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+	mask = CAM_PAD_REG_SW_RESET_BMSK;
+	value = 1 << CAM_PAD_REG_SW_RESET_SHFT;
+	writel((reg & (~mask)) | (value & mask), mdcbase);
+	mdelay(10);
+
+	reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+	mask = CAM_PAD_REG_SW_RESET_BMSK;
+	value = 0 << CAM_PAD_REG_SW_RESET_SHFT;
+	writel((reg & (~mask)) | (value & mask), mdcbase);
+	mdelay(10);
+}
+
+void msm_camio_clk_sel(enum msm_camio_clk_src_type srctype)
+{
+	struct clk *clk = NULL;
+
+	clk = camio_vfe_clk;
+
+	if (clk != NULL) {
+		switch (srctype) {
+		case MSM_CAMIO_CLK_SRC_INTERNAL:
+			clk_set_flags(clk, 0x00000100 << 1);
+			break;
+
+		case MSM_CAMIO_CLK_SRC_EXTERNAL:
+			clk_set_flags(clk, 0x00000100);
+			break;
+
+		default:
+			break;
+		}
+	}
+}
+
+void msm_camio_clk_axi_rate_set(int rate)
+{
+	struct clk *clk = camio_vfe_axi_clk;
+	/* todo: check return */
+	clk_set_rate(clk, rate);
+}
+
+int msm_camio_probe_on(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+	camdev->camera_gpio_on();
+	return msm_camio_clk_enable(CAMIO_VFE_MDC_CLK);
+}
+
+int msm_camio_probe_off(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+	camdev->camera_gpio_off();
+	return msm_camio_clk_disable(CAMIO_VFE_MDC_CLK);
+}
diff --git a/drivers/media/video/msm/msm_io_7x27a.c b/drivers/media/video/msm/msm_io_7x27a.c
new file mode 100644
index 0000000..c70cfca
--- /dev/null
+++ b/drivers/media/video/msm/msm_io_7x27a.c
@@ -0,0 +1,612 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/pm_qos_params.h>
+#include <mach/board.h>
+#include <mach/camera.h>
+#include <mach/camera.h>
+#include <mach/clk.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+
+
+/* MIPI	CSI controller registers */
+#define	MIPI_PHY_CONTROL		0x00000000
+#define	MIPI_PROTOCOL_CONTROL		0x00000004
+#define	MIPI_INTERRUPT_STATUS		0x00000008
+#define	MIPI_INTERRUPT_MASK		0x0000000C
+#define	MIPI_CAMERA_CNTL		0x00000024
+#define	MIPI_CALIBRATION_CONTROL	0x00000018
+#define	MIPI_PHY_D0_CONTROL2		0x00000038
+#define	MIPI_PHY_D1_CONTROL2		0x0000003C
+#define	MIPI_PHY_D2_CONTROL2		0x00000040
+#define	MIPI_PHY_D3_CONTROL2		0x00000044
+#define	MIPI_PHY_CL_CONTROL		0x00000048
+#define	MIPI_PHY_D0_CONTROL		0x00000034
+#define	MIPI_PHY_D1_CONTROL		0x00000020
+#define	MIPI_PHY_D2_CONTROL		0x0000002C
+#define	MIPI_PHY_D3_CONTROL		0x00000030
+#define	MIPI_PWR_CNTL			0x00000054
+
+/*
+ * MIPI_PROTOCOL_CONTROL register bits to enable/disable the features of
+ * CSI Rx Block
+ */
+
+/* DPCM scheme */
+#define	MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT			0x1e
+/* SW_RST to issue a SW reset to the CSI core */
+#define	MIPI_PROTOCOL_CONTROL_SW_RST_BMSK			0x8000000
+/* To Capture Long packet Header Info in MIPI_PROTOCOL_STATUS register */
+#define	MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK	0x200000
+/* Data format for unpacking purpose */
+#define	MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT			0x13
+/* Enable decoding of payload based on data type filed of packet hdr */
+#define	MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK			0x00000
+/* Enable error correction on packet headers */
+#define	MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK			0x20000
+
+/*
+ * MIPI_CALIBRATION_CONTROL register contains control info for
+ * calibration impledence controller
+*/
+
+/* Enable bit for calibration pad */
+#define	MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT		0x16
+/* With SWCAL_STRENGTH_OVERRIDE_EN, SW_CAL_EN and MANUAL_OVERRIDE_EN
+ * the hardware calibration circuitry associated with CAL_SW_HW_MODE
+ * is bypassed
+*/
+#define	MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT	0x15
+/* To indicate the Calibration process is in the control of HW/SW */
+#define	MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT		0x14
+/* When this is set the strength value of the data and clk lane impedence
+ * termination is updated with MANUAL_STRENGTH settings and calibration
+ * sensing logic is idle.
+*/
+#define	MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT	0x7
+
+/* Data lane0 control */
+/* T-hs Settle count value  for Rx */
+#define	MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT			0x18
+/* Rx termination control */
+#define	MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT			0x10
+/* LP Rx enable */
+#define	MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT			0x4
+/*
+ * Enable for error in sync sequence
+ * 1 - one bit error in sync seq
+ * 0 - requires all 8 bit correct seq
+*/
+#define	MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT			0x3
+
+/* Comments are same as D0 */
+#define	MIPI_PHY_D1_CONTROL2_SETTLE_COUNT_SHFT			0x18
+#define	MIPI_PHY_D1_CONTROL2_HS_TERM_IMP_SHFT			0x10
+#define	MIPI_PHY_D1_CONTROL2_LP_REC_EN_SHFT			0x4
+#define	MIPI_PHY_D1_CONTROL2_ERR_SOT_HS_EN_SHFT			0x3
+
+/* Comments are same as D0 */
+#define	MIPI_PHY_D2_CONTROL2_SETTLE_COUNT_SHFT			0x18
+#define	MIPI_PHY_D2_CONTROL2_HS_TERM_IMP_SHFT			0x10
+#define	MIPI_PHY_D2_CONTROL2_LP_REC_EN_SHFT			0x4
+#define	MIPI_PHY_D2_CONTROL2_ERR_SOT_HS_EN_SHFT			0x3
+
+/* Comments are same as D0 */
+#define	MIPI_PHY_D3_CONTROL2_SETTLE_COUNT_SHFT			0x18
+#define	MIPI_PHY_D3_CONTROL2_HS_TERM_IMP_SHFT			0x10
+#define	MIPI_PHY_D3_CONTROL2_LP_REC_EN_SHFT			0x4
+#define	MIPI_PHY_D3_CONTROL2_ERR_SOT_HS_EN_SHFT			0x3
+
+/* PHY_CL_CTRL programs the parameters of clk lane of CSIRXPHY */
+/* HS Rx termination control */
+#define	MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT			0x18
+/* Start signal for T-hs delay */
+#define	MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT			0x2
+
+/* PHY DATA lane 0 control */
+/*
+ * HS RX equalizer strength control
+ * 00 - 0db 01 - 3db 10 - 5db 11 - 7db
+*/
+#define	MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT			0x1c
+
+/* PHY DATA lane 1 control */
+/* Shutdown signal for MIPI clk phy line */
+#define	MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT		0x9
+/* Shutdown signal for MIPI data phy line */
+#define	MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT	0x8
+
+#define MSM_AXI_QOS_PREVIEW 200000
+#define MSM_AXI_QOS_SNAPSHOT 200000
+#define MSM_AXI_QOS_RECORDING 200000
+
+#define MIPI_PWR_CNTL_ENA	0x07
+#define MIPI_PWR_CNTL_DIS	0x0
+
+static struct clk *camio_cam_clk;
+static struct clk *camio_vfe_clk;
+static struct clk *camio_csi_src_clk;
+static struct clk *camio_csi0_vfe_clk;
+static struct clk *camio_csi1_vfe_clk;
+static struct clk *camio_csi0_clk;
+static struct clk *camio_csi1_clk;
+static struct clk *camio_csi0_pclk;
+static struct clk *camio_csi1_pclk;
+
+static struct msm_camera_io_ext camio_ext;
+static struct msm_camera_io_clk camio_clk;
+static struct platform_device *camio_dev;
+void __iomem *csibase;
+void __iomem *appbase;
+
+
+
+void msm_io_w(u32 data, void __iomem *addr)
+{
+	CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+	writel((data), (addr));
+}
+
+u32 msm_io_r(void __iomem *addr)
+{
+	uint32_t data = readl(addr);
+	CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+	return data;
+}
+
+void msm_camio_vfe_clk_rate_set(int rate)
+{
+	struct clk *clk = camio_vfe_clk;
+	if (rate > clk_get_rate(clk))
+		clk_set_rate(clk, rate);
+}
+
+int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
+{
+	int rc = 0;
+	struct clk *clk = NULL;
+
+	switch (clktype) {
+	case CAMIO_CAM_MCLK_CLK:
+		clk = clk_get(NULL, "cam_m_clk");
+		camio_cam_clk = clk;
+		msm_camio_clk_rate_set_2(clk, camio_clk.mclk_clk_rate);
+		break;
+	case CAMIO_VFE_CLK:
+		clk = clk_get(NULL, "vfe_clk");
+		camio_vfe_clk = clk;
+		msm_camio_clk_rate_set_2(clk, camio_clk.vfe_clk_rate);
+		break;
+	case CAMIO_CSI0_VFE_CLK:
+		clk = clk_get(&camio_dev->dev, "csi_vfe_clk");
+		camio_csi0_vfe_clk = clk;
+		break;
+	case CAMIO_CSI1_VFE_CLK:
+		clk = clk_get(NULL, "csi_vfe_clk");
+		camio_csi1_vfe_clk = clk;
+		break;
+	case CAMIO_CSI_SRC_CLK:
+		clk = clk_get(NULL, "csi_src_clk");
+		camio_csi_src_clk = clk;
+		break;
+	case CAMIO_CSI0_CLK:
+		clk = clk_get(&camio_dev->dev, "csi_clk");
+		camio_csi0_clk = clk;
+		msm_camio_clk_rate_set_2(clk, 400000000);
+		break;
+	case CAMIO_CSI1_CLK:
+		clk = clk_get(NULL, "csi_clk");
+		camio_csi1_clk = clk;
+		break;
+	case CAMIO_CSI0_PCLK:
+		clk = clk_get(&camio_dev->dev, "csi_pclk");
+		camio_csi0_pclk = clk;
+		break;
+	case CAMIO_CSI1_PCLK:
+		clk = clk_get(NULL, "csi_pclk");
+		camio_csi1_pclk = clk;
+		break;
+	default:
+		break;
+	}
+
+	if (!IS_ERR(clk))
+		clk_enable(clk);
+	else
+		rc = -1;
+	return rc;
+}
+
+int msm_camio_clk_disable(enum msm_camio_clk_type clktype)
+{
+	int rc = 0;
+	struct clk *clk = NULL;
+
+	switch (clktype) {
+	case CAMIO_CAM_MCLK_CLK:
+		clk = camio_cam_clk;
+		break;
+	case CAMIO_VFE_CLK:
+		clk = camio_vfe_clk;
+		break;
+	case CAMIO_CSI_SRC_CLK:
+		clk = camio_csi_src_clk;
+		break;
+	case CAMIO_CSI0_VFE_CLK:
+		clk = camio_csi0_vfe_clk;
+		break;
+	case CAMIO_CSI1_VFE_CLK:
+		clk = camio_csi1_vfe_clk;
+		break;
+	case CAMIO_CSI0_CLK:
+		clk = camio_csi0_clk;
+		break;
+	case CAMIO_CSI1_CLK:
+		clk = camio_csi1_clk;
+		break;
+	case CAMIO_CSI0_PCLK:
+		clk = camio_csi0_pclk;
+		break;
+	case CAMIO_CSI1_PCLK:
+		clk = camio_csi1_pclk;
+		break;
+	default:
+		break;
+	}
+
+	if (!IS_ERR(clk)) {
+		clk_disable(clk);
+		clk_put(clk);
+	} else
+		rc = -1;
+	return rc;
+}
+
+void msm_camio_clk_rate_set(int rate)
+{
+	struct clk *clk = camio_cam_clk;
+	clk_set_rate(clk, rate);
+}
+
+void msm_camio_clk_rate_set_2(struct clk *clk, int rate)
+{
+	clk_set_rate(clk, rate);
+}
+
+void msm_camio_clk_set_min_rate(struct clk *clk, int rate)
+{
+	clk_set_min_rate(clk, rate);
+}
+
+static irqreturn_t msm_io_csi_irq(int irq_num, void *data)
+{
+	uint32_t irq;
+
+	irq = msm_io_r(csibase + MIPI_INTERRUPT_STATUS);
+	CDBG("%s MIPI_INTERRUPT_STATUS = 0x%x\n", __func__, irq);
+	msm_io_w(irq, csibase + MIPI_INTERRUPT_STATUS);
+
+	/* TODO: Needs to send this info to upper layers */
+	if ((irq >> 19) & 0x1)
+		pr_info("Unsupported packet format is received\n");
+	return IRQ_HANDLED;
+}
+
+int msm_camio_enable(struct platform_device *pdev)
+{
+	int rc = 0;
+	const struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	uint32_t val;
+
+	camio_dev = pdev;
+	camio_ext = camdev->ioext;
+	camio_clk = camdev->ioclk;
+
+	msm_camio_clk_enable(CAMIO_VFE_CLK);
+	msm_camio_clk_enable(CAMIO_CSI0_VFE_CLK);
+	msm_camio_clk_enable(CAMIO_CSI1_VFE_CLK);
+	msm_camio_clk_enable(CAMIO_CSI0_CLK);
+	msm_camio_clk_enable(CAMIO_CSI1_CLK);
+	msm_camio_clk_enable(CAMIO_CSI0_PCLK);
+	msm_camio_clk_enable(CAMIO_CSI1_PCLK);
+
+	csibase = ioremap(camio_ext.csiphy, camio_ext.csisz);
+	if (!csibase) {
+		rc = -ENOMEM;
+		goto csi_busy;
+	}
+	rc = request_irq(camio_ext.csiirq, msm_io_csi_irq,
+				IRQF_TRIGGER_RISING, "csi", 0);
+	if (rc < 0)
+		goto csi_irq_fail;
+
+	msleep(20);
+	val = (20 <<
+		MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) |
+		(0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) |
+		(0x0 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) |
+		(0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT);
+	CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D2_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D3_CONTROL2);
+
+	val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) |
+		(0x0 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT);
+	CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_PHY_CL_CONTROL);
+
+	appbase = ioremap(camio_ext.appphy,
+		camio_ext.appsz);
+	if (!appbase) {
+		rc = -ENOMEM;
+		goto csi_irq_fail;
+	}
+	return 0;
+
+csi_irq_fail:
+	iounmap(csibase);
+csi_busy:
+	msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
+	msm_camio_clk_disable(CAMIO_VFE_CLK);
+	msm_camio_clk_disable(CAMIO_CSI0_VFE_CLK);
+	msm_camio_clk_disable(CAMIO_CSI1_VFE_CLK);
+	msm_camio_clk_disable(CAMIO_CSI0_CLK);
+	msm_camio_clk_disable(CAMIO_CSI1_CLK);
+	msm_camio_clk_disable(CAMIO_CSI0_PCLK);
+	msm_camio_clk_disable(CAMIO_CSI1_PCLK);
+	camdev->camera_gpio_off();
+	return rc;
+}
+
+void msm_camio_disable(struct platform_device *pdev)
+{
+	uint32_t val;
+
+	val = (20 <<
+		MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) |
+		(0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) |
+		(0x0 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) |
+		(0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT);
+	CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D2_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D3_CONTROL2);
+
+	val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) |
+		(0x0 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT);
+	CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_PHY_CL_CONTROL);
+	msleep(20);
+
+	free_irq(camio_ext.csiirq, 0);
+	iounmap(csibase);
+	iounmap(appbase);
+	CDBG("disable clocks\n");
+
+	msm_camio_clk_disable(CAMIO_VFE_CLK);
+	msm_camio_clk_disable(CAMIO_CSI0_CLK);
+	msm_camio_clk_disable(CAMIO_CSI1_CLK);
+	msm_camio_clk_disable(CAMIO_CSI0_VFE_CLK);
+	msm_camio_clk_disable(CAMIO_CSI1_VFE_CLK);
+	msm_camio_clk_disable(CAMIO_CSI0_PCLK);
+	msm_camio_clk_disable(CAMIO_CSI1_PCLK);
+}
+
+int msm_camio_sensor_clk_on(struct platform_device *pdev)
+{
+	int rc = 0;
+	const struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	camio_dev = pdev;
+	camio_ext = camdev->ioext;
+	camio_clk = camdev->ioclk;
+
+	rc = camdev->camera_gpio_on();
+	if (rc < 0)
+		return rc;
+	return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
+}
+
+int msm_camio_sensor_clk_off(struct platform_device *pdev)
+{
+	const struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	camdev->camera_gpio_off();
+	return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
+
+}
+
+void msm_camio_vfe_blk_reset(void)
+{
+	uint32_t val;
+
+	/* do apps reset */
+	val = readl_relaxed(appbase + 0x00000210);
+	val |= 0x1;
+	writel_relaxed(val, appbase + 0x00000210);
+	usleep_range(10000, 11000);
+
+	val = readl_relaxed(appbase + 0x00000210);
+	val &= ~0x1;
+	writel_relaxed(val, appbase + 0x00000210);
+	usleep_range(10000, 11000);
+
+	/* do axi reset */
+	val = readl_relaxed(appbase + 0x00000208);
+	val |= 0x1;
+	writel_relaxed(val, appbase + 0x00000208);
+	usleep_range(10000, 11000);
+
+	val = readl_relaxed(appbase + 0x00000208);
+	val &= ~0x1;
+	writel_relaxed(val, appbase + 0x00000208);
+	mb();
+	usleep_range(10000, 11000);
+	return;
+}
+
+int msm_camio_probe_on(struct platform_device *pdev)
+{
+	int rc = 0;
+	const struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	camio_dev = pdev;
+	camio_ext = camdev->ioext;
+	camio_clk = camdev->ioclk;
+
+	msm_camio_clk_enable(CAMIO_CSI0_PCLK);
+	msm_camio_clk_enable(CAMIO_CSI1_PCLK);
+
+	rc = camdev->camera_gpio_on();
+	if (rc < 0)
+		return rc;
+	return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
+}
+
+int msm_camio_probe_off(struct platform_device *pdev)
+{
+	const struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	camdev->camera_gpio_off();
+
+	csibase = ioremap(camdev->ioext.csiphy, camdev->ioext.csisz);
+	if (!csibase) {
+		pr_err("ioremap failed for CSIBASE\n");
+		goto ioremap_fail;
+	}
+	msm_io_w(MIPI_PWR_CNTL_DIS, csibase + MIPI_PWR_CNTL);
+	iounmap(csibase);
+ioremap_fail:
+	msm_camio_clk_disable(CAMIO_CSI0_PCLK);
+	msm_camio_clk_disable(CAMIO_CSI1_PCLK);
+	return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
+}
+
+int msm_camio_csi_config(struct msm_camera_csi_params *csi_params)
+{
+	int rc = 0;
+	uint32_t val = 0;
+
+	CDBG("msm_camio_csi_config\n");
+
+	/* Enable error correction for DATA lane. Applies to all data lanes */
+	msm_io_w(0x4, csibase + MIPI_PHY_CONTROL);
+
+	msm_io_w(MIPI_PROTOCOL_CONTROL_SW_RST_BMSK,
+		csibase + MIPI_PROTOCOL_CONTROL);
+
+	val = MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK |
+		MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK |
+		MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK;
+	val |= (uint32_t)(csi_params->data_format) <<
+		MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT;
+	val |= csi_params->dpcm_scheme <<
+		MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT;
+	CDBG("%s MIPI_PROTOCOL_CONTROL val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_PROTOCOL_CONTROL);
+
+	val = (0x1 << MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT) |
+		(0x1 <<
+		MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT) |
+		(0x1 << MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT) |
+		(0x1 << MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT);
+	CDBG("%s MIPI_CALIBRATION_CONTROL val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_CALIBRATION_CONTROL);
+
+	val = (csi_params->settle_cnt <<
+		MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) |
+		(0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) |
+		(0x1 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) |
+		(0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT);
+	CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D2_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D3_CONTROL2);
+
+
+	val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) |
+		(0x1 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT);
+	CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_PHY_CL_CONTROL);
+
+	val = 0 << MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT;
+	msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL);
+
+	val = (0x1 << MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT) |
+		(0x1 << MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT);
+	CDBG("%s MIPI_PHY_D1_CONTROL val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL);
+
+	msm_io_w(0x00000000, csibase + MIPI_PHY_D2_CONTROL);
+	msm_io_w(0x00000000, csibase + MIPI_PHY_D3_CONTROL);
+
+	/* program number of lanes and lane mapping */
+	switch (csi_params->lane_cnt) {
+	case 1:
+		msm_io_w(csi_params->lane_assign << 8 | 0x4,
+			csibase + MIPI_CAMERA_CNTL);
+		break;
+	case 2:
+		msm_io_w(csi_params->lane_assign << 8 | 0x5,
+			csibase + MIPI_CAMERA_CNTL);
+		break;
+	case 3:
+		msm_io_w(csi_params->lane_assign << 8 | 0x6,
+			csibase + MIPI_CAMERA_CNTL);
+		break;
+	case 4:
+		msm_io_w(csi_params->lane_assign << 8 | 0x7,
+			csibase + MIPI_CAMERA_CNTL);
+		break;
+	}
+
+	msm_io_w(0xFFFFF3FF, csibase + MIPI_INTERRUPT_MASK);
+	/*clear IRQ bits - write 1 clears the status*/
+	msm_io_w(0xFFFFF3FF, csibase + MIPI_INTERRUPT_STATUS);
+
+	return rc;
+}
+
+void msm_camio_set_perf_lvl(enum msm_bus_perf_setting perf_setting)
+{
+	switch (perf_setting) {
+	case S_INIT:
+		add_axi_qos();
+		break;
+	case S_PREVIEW:
+		update_axi_qos(MSM_AXI_QOS_PREVIEW);
+		break;
+	case S_VIDEO:
+		update_axi_qos(MSM_AXI_QOS_RECORDING);
+		break;
+	case S_CAPTURE:
+		update_axi_qos(MSM_AXI_QOS_SNAPSHOT);
+		break;
+	case S_DEFAULT:
+		update_axi_qos(PM_QOS_DEFAULT_VALUE);
+		break;
+	case S_EXIT:
+		release_axi_qos();
+		break;
+	default:
+		CDBG("%s: INVALID CASE\n", __func__);
+	}
+}
diff --git a/drivers/media/video/msm/msm_io_8960.c b/drivers/media/video/msm/msm_io_8960.c
new file mode 100644
index 0000000..eb29d08
--- /dev/null
+++ b/drivers/media/video/msm/msm_io_8960.c
@@ -0,0 +1,1359 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/regulator/consumer.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/camera.h>
+#include <mach/vreg.h>
+#include <mach/camera.h>
+#include <mach/clk.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include "msm_ispif.h"
+
+#define DBG_CSID 0
+#define DBG_CSIPHY 0
+
+/* MIPI	CSI	PHY registers */
+#define MIPI_CSIPHY_LNn_CFG1_ADDR                0x0
+#define MIPI_CSIPHY_LNn_CFG2_ADDR                0x4
+#define MIPI_CSIPHY_LNn_CFG3_ADDR                0x8
+#define MIPI_CSIPHY_LNn_CFG4_ADDR                0xC
+#define MIPI_CSIPHY_LNn_CFG5_ADDR                0x10
+#define MIPI_CSIPHY_LNCK_CFG1_ADDR               0x100
+#define MIPI_CSIPHY_LNCK_CFG2_ADDR               0x104
+#define MIPI_CSIPHY_LNCK_CFG3_ADDR               0x108
+#define MIPI_CSIPHY_LNCK_CFG4_ADDR               0x10C
+#define MIPI_CSIPHY_LNCK_CFG5_ADDR               0x110
+#define MIPI_CSIPHY_LNCK_MISC1_ADDR              0x128
+#define MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR        0x1E0
+#define MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR           0x1E8
+#define MIPI_CSIPHY_GLBL_PWR_CFG_ADDR           0x0144
+#define MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR      0x0180
+#define MIPI_CSIPHY_INTERRUPT_STATUS1_ADDR      0x0184
+#define MIPI_CSIPHY_INTERRUPT_STATUS2_ADDR      0x0188
+#define MIPI_CSIPHY_INTERRUPT_STATUS3_ADDR      0x018C
+#define MIPI_CSIPHY_INTERRUPT_STATUS4_ADDR      0x0190
+#define MIPI_CSIPHY_INTERRUPT_MASK0_ADDR        0x01A0
+#define MIPI_CSIPHY_INTERRUPT_MASK1_ADDR        0x01A4
+#define MIPI_CSIPHY_INTERRUPT_MASK2_ADDR        0x01A8
+#define MIPI_CSIPHY_INTERRUPT_MASK3_ADDR        0x01AC
+#define MIPI_CSIPHY_INTERRUPT_MASK4_ADDR        0x01B0
+#define MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR       0x01C0
+#define MIPI_CSIPHY_INTERRUPT_CLEAR1_ADDR       0x01C4
+#define MIPI_CSIPHY_INTERRUPT_CLEAR2_ADDR       0x01C8
+#define MIPI_CSIPHY_INTERRUPT_CLEAR3_ADDR       0x01CC
+#define MIPI_CSIPHY_INTERRUPT_CLEAR4_ADDR       0x01D0
+
+/* MIPI	CSID registers */
+#define CSID_CORE_CTRL_ADDR                     0x4
+#define CSID_RST_CMD_ADDR                       0x8
+#define CSID_CID_LUT_VC_0_ADDR                  0xc
+#define CSID_CID_LUT_VC_1_ADDR                  0x10
+#define CSID_CID_LUT_VC_2_ADDR                  0x14
+#define CSID_CID_LUT_VC_3_ADDR                  0x18
+#define CSID_CID_n_CFG_ADDR                     0x1C
+#define CSID_IRQ_CLEAR_CMD_ADDR                 0x5c
+#define CSID_IRQ_MASK_ADDR                      0x60
+#define CSID_IRQ_STATUS_ADDR                    0x64
+#define CSID_CAPTURED_UNMAPPED_LONG_PKT_HDR_ADDR    0x68
+#define CSID_CAPTURED_MMAPPED_LONG_PKT_HDR_ADDR     0x6c
+#define CSID_CAPTURED_SHORT_PKT_ADDR                0x70
+#define CSID_CAPTURED_LONG_PKT_HDR_ADDR             0x74
+#define CSID_CAPTURED_LONG_PKT_FTR_ADDR             0x78
+#define CSID_PIF_MISR_DL0_ADDR                      0x7C
+#define CSID_PIF_MISR_DL1_ADDR                      0x80
+#define CSID_PIF_MISR_DL2_ADDR                      0x84
+#define CSID_PIF_MISR_DL3_ADDR                      0x88
+#define CSID_STATS_TOTAL_PKTS_RCVD_ADDR             0x8C
+#define CSID_STATS_ECC_ADDR                         0x90
+#define CSID_STATS_CRC_ADDR                         0x94
+#define CSID_TG_CTRL_ADDR                           0x9C
+#define CSID_TG_VC_CFG_ADDR                         0xA0
+#define CSID_TG_DT_n_CFG_0_ADDR                     0xA8
+#define CSID_TG_DT_n_CFG_1_ADDR                     0xAC
+#define CSID_TG_DT_n_CFG_2_ADDR                     0xB0
+#define CSID_TG_DT_n_CFG_3_ADDR                     0xD8
+
+/* Regulator Voltage and Current */
+
+#define CAM_VAF_MINUV                 2800000
+#define CAM_VAF_MAXUV                 2800000
+#define CAM_VDIG_MINUV                    1200000
+#define CAM_VDIG_MAXUV                    1200000
+#define CAM_VANA_MINUV                    2800000
+#define CAM_VANA_MAXUV                    2850000
+#define CAM_CSI_VDD_MINUV                  1200000
+#define CAM_CSI_VDD_MAXUV                  1200000
+
+#define CAM_VAF_LOAD_UA               300000
+#define CAM_VDIG_LOAD_UA                  105000
+#define CAM_VANA_LOAD_UA                  85600
+#define CAM_CSI_LOAD_UA                    20000
+
+static struct clk *camio_cam_clk;
+static struct clk *camio_vfe_clk;
+static struct clk *camio_csi_src_clk;
+static struct clk *camio_csi1_src_clk;
+static struct clk *camio_csi0_vfe_clk;
+static struct clk *camio_csi0_clk;
+static struct clk *camio_csi0_pclk;
+static struct clk *camio_csi_pix_clk;
+static struct clk *camio_csi_rdi_clk;
+static struct clk *camio_csiphy0_timer_clk;
+static struct clk *camio_csiphy1_timer_clk;
+static struct clk *camio_vfe_axi_clk;
+static struct clk *camio_vfe_pclk;
+static struct clk *camio_csi0_phy_clk;
+static struct clk *camio_csiphy_timer_src_clk;
+
+/*static struct clk *camio_vfe_pclk;*/
+static struct clk *camio_jpeg_clk;
+static struct clk *camio_jpeg_pclk;
+static struct clk *camio_vpe_clk;
+static struct clk *camio_vpe_pclk;
+static struct regulator *fs_vfe;
+static struct regulator *fs_ijpeg;
+static struct regulator *fs_vpe;
+static struct regulator *cam_vana;
+static struct regulator *cam_vio;
+static struct regulator *cam_vdig;
+static struct regulator *cam_vaf;
+static struct regulator *mipi_csi_vdd;
+
+static struct msm_camera_io_clk camio_clk;
+static struct platform_device *camio_dev;
+static struct resource *csidio, *csiphyio;
+static struct resource *csid_mem, *csiphy_mem;
+static struct resource *csid_irq, *csiphy_irq;
+void __iomem *csidbase, *csiphybase;
+
+static struct msm_bus_vectors cam_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors cam_preview_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1521190000,
+		.ib  = 1521190000,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors cam_video_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1521190000,
+		.ib  = 1521190000,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1521190000,
+		.ib  = 1521190000,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors cam_snapshot_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1521190000,
+		.ib  = 1521190000,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1521190000,
+		.ib  = 1521190000,
+	},
+};
+
+static struct msm_bus_paths cam_bus_client_config[] = {
+	{
+		ARRAY_SIZE(cam_init_vectors),
+		cam_init_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_preview_vectors),
+		cam_preview_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_video_vectors),
+		cam_video_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_snapshot_vectors),
+		cam_snapshot_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata cam_bus_client_pdata = {
+		cam_bus_client_config,
+		ARRAY_SIZE(cam_bus_client_config),
+		.name = "msm_camera",
+};
+
+
+void msm_io_w(u32 data, void __iomem *addr)
+{
+	CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+	writel_relaxed((data), (addr));
+}
+
+void msm_io_w_mb(u32 data, void __iomem *addr)
+{
+	CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+	wmb();
+	writel_relaxed((data), (addr));
+	wmb();
+}
+
+u32 msm_io_r(void __iomem *addr)
+{
+	uint32_t data = readl_relaxed(addr);
+	CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+	return data;
+}
+
+u32 msm_io_r_mb(void __iomem *addr)
+{
+	uint32_t data;
+	rmb();
+	data = readl_relaxed(addr);
+	rmb();
+	CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+	return data;
+}
+
+void msm_io_memcpy_toio(void __iomem *dest_addr,
+	void __iomem *src_addr, u32 len)
+{
+	int i;
+	u32 *d = (u32 *) dest_addr;
+	u32 *s = (u32 *) src_addr;
+	/* memcpy_toio does not work. Use writel_relaxed for now */
+	for (i = 0; i < len; i++)
+		writel_relaxed(*s++, d++);
+}
+
+void msm_io_dump(void __iomem *addr, int size)
+{
+	char line_str[128], *p_str;
+	int i;
+	u32 *p = (u32 *) addr;
+	u32 data;
+	CDBG("%s: %p %d\n", __func__, addr, size);
+	line_str[0] = '\0';
+	p_str = line_str;
+	for (i = 0; i < size/4; i++) {
+		if (i % 4 == 0) {
+			sprintf(p_str, "%08x: ", (u32) p);
+			p_str += 10;
+		}
+		data = readl_relaxed(p++);
+		sprintf(p_str, "%08x ", data);
+		p_str += 9;
+		if ((i + 1) % 4 == 0) {
+			CDBG("%s\n", line_str);
+			line_str[0] = '\0';
+			p_str = line_str;
+		}
+	}
+	if (line_str[0] != '\0')
+		CDBG("%s\n", line_str);
+}
+
+void msm_io_memcpy(void __iomem *dest_addr, void __iomem *src_addr, u32 len)
+{
+	CDBG("%s: %p %p %d\n", __func__, dest_addr, src_addr, len);
+	msm_io_memcpy_toio(dest_addr, src_addr, len / 4);
+	msm_io_dump(dest_addr, len);
+}
+
+static int msm_camera_vreg_enable(struct platform_device *pdev)
+{
+	if (mipi_csi_vdd == NULL) {
+		mipi_csi_vdd = regulator_get(&pdev->dev, "mipi_csi_vdd");
+		if (IS_ERR(mipi_csi_vdd)) {
+			CDBG("%s: VREG MIPI CSI VDD get failed\n", __func__);
+			mipi_csi_vdd = NULL;
+			return -ENODEV;
+		}
+		if (regulator_set_voltage(mipi_csi_vdd, CAM_CSI_VDD_MINUV,
+			CAM_CSI_VDD_MAXUV)) {
+			CDBG("%s: VREG MIPI CSI VDD set voltage failed\n",
+				__func__);
+			goto mipi_csi_vdd_put;
+		}
+		if (regulator_set_optimum_mode(mipi_csi_vdd,
+			CAM_CSI_LOAD_UA) < 0) {
+			CDBG("%s: VREG MIPI CSI set optimum mode failed\n",
+				__func__);
+			goto mipi_csi_vdd_release;
+		}
+		if (regulator_enable(mipi_csi_vdd)) {
+			CDBG("%s: VREG MIPI CSI VDD enable failed\n",
+				__func__);
+			goto mipi_csi_vdd_disable;
+		}
+	}
+	if (cam_vana == NULL) {
+		cam_vana = regulator_get(&pdev->dev, "cam_vana");
+		if (IS_ERR(cam_vana)) {
+			CDBG("%s: VREG CAM VANA get failed\n", __func__);
+			cam_vana = NULL;
+			goto mipi_csi_vdd_disable;
+		}
+		if (regulator_set_voltage(cam_vana, CAM_VANA_MINUV,
+			CAM_VANA_MAXUV)) {
+			CDBG("%s: VREG CAM VANA set voltage failed\n",
+				__func__);
+			goto cam_vana_put;
+		}
+		if (regulator_set_optimum_mode(cam_vana,
+			CAM_VANA_LOAD_UA) < 0) {
+			CDBG("%s: VREG CAM VANA set optimum mode failed\n",
+				__func__);
+			goto cam_vana_release;
+		}
+		if (regulator_enable(cam_vana)) {
+			CDBG("%s: VREG CAM VANA enable failed\n", __func__);
+			goto cam_vana_disable;
+		}
+	}
+	if (cam_vio == NULL) {
+		cam_vio = regulator_get(&pdev->dev, "cam_vio");
+		if (IS_ERR(cam_vio)) {
+			CDBG("%s: VREG VIO get failed\n", __func__);
+			cam_vio = NULL;
+			goto cam_vana_disable;
+		}
+		if (regulator_enable(cam_vio)) {
+			CDBG("%s: VREG VIO enable failed\n", __func__);
+			goto cam_vio_put;
+		}
+	}
+	if (cam_vdig == NULL) {
+		cam_vdig = regulator_get(&pdev->dev, "cam_vdig");
+		if (IS_ERR(cam_vdig)) {
+			CDBG("%s: VREG CAM VDIG get failed\n", __func__);
+			cam_vdig = NULL;
+			goto cam_vio_disable;
+		}
+		if (regulator_set_voltage(cam_vdig, CAM_VDIG_MINUV,
+			CAM_VDIG_MAXUV)) {
+			CDBG("%s: VREG CAM VDIG set voltage failed\n",
+				__func__);
+			goto cam_vdig_put;
+		}
+		if (regulator_set_optimum_mode(cam_vdig,
+			CAM_VDIG_LOAD_UA) < 0) {
+			CDBG("%s: VREG CAM VDIG set optimum mode failed\n",
+				__func__);
+			goto cam_vdig_release;
+		}
+		if (regulator_enable(cam_vdig)) {
+			CDBG("%s: VREG CAM VDIG enable failed\n", __func__);
+			goto cam_vdig_disable;
+		}
+	}
+	if (cam_vaf == NULL) {
+		cam_vaf = regulator_get(&pdev->dev, "cam_vaf");
+		if (IS_ERR(cam_vaf)) {
+			CDBG("%s: VREG CAM VAF get failed\n", __func__);
+			cam_vaf = NULL;
+			goto cam_vdig_disable;
+		}
+		if (regulator_set_voltage(cam_vaf, CAM_VAF_MINUV,
+			CAM_VAF_MAXUV)) {
+			CDBG("%s: VREG CAM VAF set voltage failed\n",
+				__func__);
+			goto cam_vaf_put;
+		}
+		if (regulator_set_optimum_mode(cam_vaf,
+			CAM_VAF_LOAD_UA) < 0) {
+			CDBG("%s: VREG CAM VAF set optimum mode failed\n",
+				__func__);
+			goto cam_vaf_release;
+		}
+		if (regulator_enable(cam_vaf)) {
+			CDBG("%s: VREG CAM VAF enable failed\n", __func__);
+			goto cam_vaf_disable;
+		}
+	}
+	if (fs_vfe == NULL) {
+		fs_vfe = regulator_get(&pdev->dev, "fs_vfe");
+		if (IS_ERR(fs_vfe)) {
+			CDBG("%s: Regulator FS_VFE get failed %ld\n", __func__,
+				PTR_ERR(fs_vfe));
+			fs_vfe = NULL;
+		} else if (regulator_enable(fs_vfe)) {
+			CDBG("%s: Regulator FS_VFE enable failed\n", __func__);
+			regulator_put(fs_vfe);
+		}
+	}
+	return 0;
+
+cam_vaf_disable:
+	regulator_set_optimum_mode(cam_vaf, 0);
+cam_vaf_release:
+	regulator_set_voltage(cam_vaf, 0, CAM_VAF_MAXUV);
+	regulator_disable(cam_vaf);
+cam_vaf_put:
+	regulator_put(cam_vaf);
+	cam_vaf = NULL;
+cam_vdig_disable:
+	regulator_set_optimum_mode(cam_vdig, 0);
+cam_vdig_release:
+	regulator_set_voltage(cam_vdig, 0, CAM_VDIG_MAXUV);
+	regulator_disable(cam_vdig);
+cam_vdig_put:
+	regulator_put(cam_vdig);
+	cam_vdig = NULL;
+cam_vio_disable:
+	regulator_disable(cam_vio);
+cam_vio_put:
+	regulator_put(cam_vio);
+	cam_vio = NULL;
+cam_vana_disable:
+	regulator_set_optimum_mode(cam_vana, 0);
+cam_vana_release:
+	regulator_set_voltage(cam_vana, 0, CAM_VANA_MAXUV);
+	regulator_disable(cam_vana);
+cam_vana_put:
+	regulator_put(cam_vana);
+	cam_vana = NULL;
+mipi_csi_vdd_disable:
+	regulator_set_optimum_mode(mipi_csi_vdd, 0);
+mipi_csi_vdd_release:
+	regulator_set_voltage(mipi_csi_vdd, 0, CAM_CSI_VDD_MAXUV);
+	regulator_disable(mipi_csi_vdd);
+
+mipi_csi_vdd_put:
+	regulator_put(mipi_csi_vdd);
+	mipi_csi_vdd = NULL;
+	return -ENODEV;
+}
+
+static void msm_camera_vreg_disable(void)
+{
+	if (mipi_csi_vdd) {
+		regulator_set_voltage(mipi_csi_vdd, 0, CAM_CSI_VDD_MAXUV);
+		regulator_set_optimum_mode(mipi_csi_vdd, 0);
+		regulator_disable(mipi_csi_vdd);
+		regulator_put(mipi_csi_vdd);
+		mipi_csi_vdd = NULL;
+	}
+
+	if (cam_vana) {
+		regulator_set_voltage(cam_vana, 0, CAM_VANA_MAXUV);
+		regulator_set_optimum_mode(cam_vana, 0);
+		regulator_disable(cam_vana);
+		regulator_put(cam_vana);
+		cam_vana = NULL;
+	}
+
+	if (cam_vio) {
+		regulator_disable(cam_vio);
+		regulator_put(cam_vio);
+		cam_vio = NULL;
+	}
+
+	if (cam_vdig) {
+		regulator_set_voltage(cam_vdig, 0, CAM_VDIG_MAXUV);
+		regulator_set_optimum_mode(cam_vdig, 0);
+		regulator_disable(cam_vdig);
+		regulator_put(cam_vdig);
+		cam_vdig = NULL;
+	}
+
+	if (cam_vaf) {
+		regulator_set_voltage(cam_vaf, 0, CAM_VAF_MAXUV);
+		regulator_set_optimum_mode(cam_vaf, 0);
+		regulator_disable(cam_vaf);
+		regulator_put(cam_vaf);
+		cam_vaf = NULL;
+	}
+
+	if (fs_vfe) {
+		regulator_disable(fs_vfe);
+		regulator_put(fs_vfe);
+		fs_vfe = NULL;
+	}
+}
+
+int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
+{
+	int rc = 0;
+	struct clk *clk = NULL;
+	struct msm_camera_sensor_info *sinfo = camio_dev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	uint8_t csid_core = camdev->csid_core;
+
+	switch (clktype) {
+	case CAMIO_CAM_MCLK_CLK:
+		camio_cam_clk =
+		clk = clk_get(&camio_dev->dev, "cam_clk");
+		msm_camio_clk_rate_set_2(clk, camio_clk.mclk_clk_rate);
+		break;
+
+	case CAMIO_VFE_CLK:
+		camio_vfe_clk =
+		clk = clk_get(NULL, "vfe_clk");
+		msm_camio_clk_rate_set_2(clk, camio_clk.vfe_clk_rate);
+		break;
+
+	case CAMIO_VFE_AXI_CLK:
+		camio_vfe_axi_clk =
+		clk = clk_get(NULL, "vfe_axi_clk");
+		break;
+
+	case CAMIO_VFE_PCLK:
+		camio_vfe_pclk =
+		clk = clk_get(NULL, "vfe_pclk");
+		break;
+
+	case CAMIO_CSI0_VFE_CLK:
+		camio_csi0_vfe_clk =
+		clk = clk_get(NULL, "csi_vfe_clk");
+		break;
+/*
+	case CAMIO_CSI1_VFE_CLK:
+		camio_csi1_vfe_clk =
+		clk = clk_get(&camio_dev->dev, "csi_vfe_clk");
+		break;
+*/
+	case CAMIO_CSI_SRC_CLK:
+		camio_csi_src_clk =
+		clk = clk_get(NULL, "csi_src_clk");
+		msm_camio_clk_rate_set_2(clk, 177780000);
+		break;
+
+	case CAMIO_CSI1_SRC_CLK:
+		camio_csi1_src_clk =
+		clk = clk_get(&camio_dev->dev, "csi_src_clk");
+		msm_camio_clk_rate_set_2(clk, 177780000);
+		break;
+
+	case CAMIO_CSI0_CLK:
+		camio_csi0_clk =
+		clk = clk_get(&camio_dev->dev, "csi_clk");
+		break;
+
+	case CAMIO_CSI0_PHY_CLK:
+		camio_csi0_phy_clk =
+		clk = clk_get(&camio_dev->dev, "csi_phy_clk");
+		break;
+
+	case CAMIO_CSI_PIX_CLK:
+		camio_csi_pix_clk =
+		clk = clk_get(NULL, "csi_pix_clk");
+		/* mux to select between csid0 and csid1 */
+		msm_camio_clk_rate_set_2(clk, csid_core);
+		break;
+
+	case CAMIO_CSI_RDI_CLK:
+		camio_csi_rdi_clk =
+		clk = clk_get(NULL, "csi_rdi_clk");
+		/* mux to select between csid0 and csid1 */
+		msm_camio_clk_rate_set_2(clk, csid_core);
+		break;
+
+	case CAMIO_CSIPHY0_TIMER_CLK:
+		camio_csiphy0_timer_clk =
+		clk = clk_get(NULL, "csi0phy_timer_clk");
+		break;
+
+	case CAMIO_CSIPHY1_TIMER_CLK:
+		camio_csiphy1_timer_clk =
+		clk = clk_get(NULL, "csi1phy_timer_clk");
+		break;
+
+	case CAMIO_CSIPHY_TIMER_SRC_CLK:
+		camio_csiphy_timer_src_clk =
+		clk = clk_get(NULL, "csiphy_timer_src_clk");
+		msm_camio_clk_rate_set_2(clk, 177780000);
+		break;
+
+	case CAMIO_CSI0_PCLK:
+		camio_csi0_pclk =
+		clk = clk_get(NULL, "csi_pclk");
+		break;
+
+	case CAMIO_JPEG_CLK:
+		camio_jpeg_clk =
+		clk = clk_get(NULL, "ijpeg_clk");
+		clk_set_min_rate(clk, 144000000);
+		break;
+
+	case CAMIO_JPEG_PCLK:
+		camio_jpeg_pclk =
+		clk = clk_get(NULL, "ijpeg_pclk");
+		break;
+
+	case CAMIO_VPE_CLK:
+		camio_vpe_clk =
+		clk = clk_get(NULL, "vpe_clk");
+		msm_camio_clk_set_min_rate(clk, 150000000);
+		break;
+
+	case CAMIO_VPE_PCLK:
+		camio_vpe_pclk =
+		clk = clk_get(NULL, "vpe_pclk");
+		break;
+
+	default:
+		break;
+	}
+
+	if (!IS_ERR(clk))
+		rc = clk_enable(clk);
+	else
+		rc = PTR_ERR(clk);
+
+	if (rc < 0)
+		pr_err("%s(%d) failed %d\n", __func__, clktype, rc);
+
+	return rc;
+}
+
+int msm_camio_clk_disable(enum msm_camio_clk_type clktype)
+{
+	int rc = 0;
+	struct clk *clk = NULL;
+
+	switch (clktype) {
+	case CAMIO_CAM_MCLK_CLK:
+		clk = camio_cam_clk;
+		break;
+
+	case CAMIO_VFE_CLK:
+		clk = camio_vfe_clk;
+		break;
+
+	case CAMIO_VFE_AXI_CLK:
+		clk = camio_vfe_axi_clk;
+		break;
+
+	case CAMIO_VFE_PCLK:
+		clk = camio_vfe_pclk;
+		break;
+
+	case CAMIO_CSI0_VFE_CLK:
+		clk = camio_csi0_vfe_clk;
+		break;
+
+	case CAMIO_CSI_SRC_CLK:
+		clk = camio_csi_src_clk;
+		break;
+
+	case CAMIO_CSI0_CLK:
+		clk = camio_csi0_clk;
+		break;
+
+	case CAMIO_CSI0_PHY_CLK:
+		clk = camio_csi0_phy_clk;
+		break;
+
+	case CAMIO_CSI_PIX_CLK:
+		clk = camio_csi_pix_clk;
+		break;
+
+	case CAMIO_CSI_RDI_CLK:
+		clk = camio_csi_rdi_clk;
+		break;
+
+	case CAMIO_CSIPHY0_TIMER_CLK:
+		clk = camio_csiphy0_timer_clk;
+		break;
+
+	case CAMIO_CSIPHY_TIMER_SRC_CLK:
+		clk = camio_csiphy_timer_src_clk;
+		break;
+
+	case CAMIO_CSI0_PCLK:
+		clk = camio_csi0_pclk;
+		break;
+
+	case CAMIO_JPEG_CLK:
+		clk = camio_jpeg_clk;
+		break;
+
+	case CAMIO_JPEG_PCLK:
+		clk = camio_jpeg_pclk;
+		break;
+
+	case CAMIO_VPE_CLK:
+		clk = camio_vpe_clk;
+		break;
+
+	case CAMIO_VPE_PCLK:
+		clk = camio_vpe_pclk;
+		break;
+
+	default:
+		break;
+	}
+
+	if (!IS_ERR(clk)) {
+		clk_disable(clk);
+		clk_put(clk);
+	} else
+		rc = PTR_ERR(clk);
+
+	if (rc < 0)
+		pr_err("%s(%d) failed %d\n", __func__, clktype, rc);
+
+	return rc;
+}
+
+void msm_camio_vfe_clk_rate_set(int rate)
+{
+	struct clk *clk = camio_vfe_clk;
+	if (rate > clk_get_rate(clk))
+		clk_set_rate(clk, rate);
+}
+
+void msm_camio_clk_rate_set(int rate)
+{
+	struct clk *clk = camio_cam_clk;
+	clk_set_rate(clk, rate);
+}
+
+void msm_camio_clk_rate_set_2(struct clk *clk, int rate)
+{
+	clk_set_rate(clk, rate);
+}
+
+void msm_camio_clk_set_min_rate(struct clk *clk, int rate)
+{
+	clk_set_min_rate(clk, rate);
+}
+
+#if DBG_CSID
+static irqreturn_t msm_io_csi_irq(int irq_num, void *data)
+{
+	uint32_t irq;
+	irq = msm_io_r(csidbase + CSID_IRQ_STATUS_ADDR);
+	CDBG("%s CSID_IRQ_STATUS_ADDR = 0x%x\n", __func__, irq);
+	msm_io_w(irq, csidbase + CSID_IRQ_CLEAR_CMD_ADDR);
+	irq = msm_io_r(csidbase + 0x7C);
+	CDBG("%s CSID_PIF_MISR_DL0 = 0x%x\n", __func__, irq);
+	irq = msm_io_r(csidbase + 0x80);
+	CDBG("%s CSID_PIF_MISR_DL1 = 0x%x\n", __func__, irq);
+	irq = msm_io_r(csidbase + 0x84);
+	CDBG("%s CSID_PIF_MISR_DL2 = 0x%x\n", __func__, irq);
+	irq = msm_io_r(csidbase + 0x88);
+	CDBG("%s CSID_PIF_MISR_DL3 = 0x%x\n", __func__, irq);
+	irq = msm_io_r(csidbase + 0x8C);
+	CDBG("%s PACKET Count = %d\n", __func__, irq);
+	return IRQ_HANDLED;
+}
+#endif
+/*
+void msm_io_read_interrupt(void)
+{
+	uint32_t irq;
+	irq = msm_io_r(csiphybase + MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR);
+	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS0 = 0x%x\n", __func__, irq);
+	irq = msm_io_r(csiphybase + MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR);
+	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS0 = 0x%x\n", __func__, irq);
+	irq = msm_io_r(csiphybase + MIPI_CSIPHY_INTERRUPT_STATUS1_ADDR);
+	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS1 = 0x%x\n", __func__, irq);
+	irq = msm_io_r(csiphybase + MIPI_CSIPHY_INTERRUPT_STATUS2_ADDR);
+	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS2 = 0x%x\n", __func__, irq);
+	irq = msm_io_r(csiphybase + MIPI_CSIPHY_INTERRUPT_STATUS3_ADDR);
+	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS3 = 0x%x\n", __func__, irq);
+	irq = msm_io_r(csiphybase + MIPI_CSIPHY_INTERRUPT_STATUS4_ADDR);
+	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS4 = 0x%x\n", __func__, irq);
+	msm_io_w(irq, csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR);
+	msm_io_w(irq, csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR1_ADDR);
+	msm_io_w(irq, csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR2_ADDR);
+	msm_io_w(irq, csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR3_ADDR);
+	msm_io_w(irq, csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR4_ADDR);
+	msm_io_w(0x1, csiphybase + 0x164);
+	msm_io_w(0x0, csiphybase + 0x164);
+	return;
+}
+*/
+#if DBG_CSIPHY
+static irqreturn_t msm_io_csiphy_irq(int irq_num, void *data)
+{
+	uint32_t irq;
+	irq = msm_io_r(csiphybase + MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR);
+	msm_io_w(irq, csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR);
+	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS0 = 0x%x\n", __func__, irq);
+	irq = msm_io_r(csiphybase + MIPI_CSIPHY_INTERRUPT_STATUS1_ADDR);
+	msm_io_w(irq, csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR1_ADDR);
+	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS1 = 0x%x\n", __func__, irq);
+	irq = msm_io_r(csiphybase + MIPI_CSIPHY_INTERRUPT_STATUS2_ADDR);
+	msm_io_w(irq, csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR2_ADDR);
+	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS2 = 0x%x\n", __func__, irq);
+	irq = msm_io_r(csiphybase + MIPI_CSIPHY_INTERRUPT_STATUS3_ADDR);
+	msm_io_w(irq, csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR3_ADDR);
+	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS3 = 0x%x\n", __func__, irq);
+	irq = msm_io_r(csiphybase + MIPI_CSIPHY_INTERRUPT_STATUS4_ADDR);
+	msm_io_w(irq, csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR4_ADDR);
+	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS4 = 0x%x\n", __func__, irq);
+	msm_io_w(0x1, csiphybase + 0x164);
+	msm_io_w(0x0, csiphybase + 0x164);
+	return IRQ_HANDLED;
+}
+#endif
+static int msm_camio_enable_all_clks(uint8_t csid_core)
+{
+	int rc = 0;
+
+	rc = msm_camio_clk_enable(CAMIO_CSI_SRC_CLK);
+	if (rc < 0)
+		goto csi_src_fail;
+	if (csid_core == 1) {
+		rc = msm_camio_clk_enable(CAMIO_CSI1_SRC_CLK);
+		if (rc < 0)
+			goto csi1_src_fail;
+	}
+	rc = msm_camio_clk_enable(CAMIO_CSI0_CLK);
+	if (rc < 0)
+		goto csi0_fail;
+	rc = msm_camio_clk_enable(CAMIO_CSI0_PHY_CLK);
+	if (rc < 0)
+		goto csi0_phy_fail;
+	rc = msm_camio_clk_enable(CAMIO_CSIPHY_TIMER_SRC_CLK);
+	if (rc < 0)
+		goto csiphy_timer_src_fail;
+	if (csid_core == 0) {
+		rc = msm_camio_clk_enable(CAMIO_CSIPHY0_TIMER_CLK);
+		if (rc < 0)
+			goto csiphy0_timer_fail;
+	} else if (csid_core == 1) {
+		rc = msm_camio_clk_enable(CAMIO_CSIPHY1_TIMER_CLK);
+		if (rc < 0)
+			goto csiphy1_timer_fail;
+	}
+	rc = msm_camio_clk_enable(CAMIO_CSI0_PCLK);
+	if (rc < 0)
+		goto csi0p_fail;
+
+	rc = msm_camio_clk_enable(CAMIO_VFE_CLK);
+	if (rc < 0)
+		goto vfe_fail;
+	rc = msm_camio_clk_enable(CAMIO_VFE_AXI_CLK);
+	if (rc < 0)
+		goto axi_fail;
+	rc = msm_camio_clk_enable(CAMIO_VFE_PCLK);
+	if (rc < 0)
+		goto vfep_fail;
+
+	rc = msm_camio_clk_enable(CAMIO_CSI0_VFE_CLK);
+	if (rc < 0)
+		goto csi0_vfe_fail;
+	rc = msm_camio_clk_enable(CAMIO_CSI_PIX_CLK);
+	if (rc < 0)
+		goto csi_pix_fail;
+	rc = msm_camio_clk_enable(CAMIO_CSI_RDI_CLK);
+	if (rc < 0)
+		goto csi_rdi_fail;
+	return rc;
+
+csi_rdi_fail:
+	msm_camio_clk_disable(CAMIO_CSI_PIX_CLK);
+csi_pix_fail:
+	msm_camio_clk_disable(CAMIO_CSI0_VFE_CLK);
+csi0_vfe_fail:
+	msm_camio_clk_disable(CAMIO_VFE_PCLK);
+vfep_fail:
+	msm_camio_clk_disable(CAMIO_VFE_AXI_CLK);
+axi_fail:
+	msm_camio_clk_disable(CAMIO_VFE_CLK);
+vfe_fail:
+	msm_camio_clk_disable(CAMIO_CSI0_PCLK);
+csi0p_fail:
+	msm_camio_clk_disable(CAMIO_CSIPHY0_TIMER_CLK);
+csiphy1_timer_fail:
+	msm_camio_clk_disable(CAMIO_CSIPHY1_TIMER_CLK);
+csiphy0_timer_fail:
+	msm_camio_clk_disable(CAMIO_CSIPHY_TIMER_SRC_CLK);
+csiphy_timer_src_fail:
+	msm_camio_clk_disable(CAMIO_CSI0_PHY_CLK);
+csi0_phy_fail:
+	msm_camio_clk_disable(CAMIO_CSI0_CLK);
+csi0_fail:
+	msm_camio_clk_disable(CAMIO_CSI1_SRC_CLK);
+csi1_src_fail:
+	msm_camio_clk_disable(CAMIO_CSI_SRC_CLK);
+csi_src_fail:
+	return rc;
+}
+
+static void msm_camio_disable_all_clks(uint8_t csid_core)
+{
+	msm_camio_clk_disable(CAMIO_CSI_RDI_CLK);
+	msm_camio_clk_disable(CAMIO_CSI_PIX_CLK);
+	msm_camio_clk_disable(CAMIO_CSI0_VFE_CLK);
+	msm_camio_clk_disable(CAMIO_VFE_PCLK);
+	msm_camio_clk_disable(CAMIO_VFE_AXI_CLK);
+	msm_camio_clk_disable(CAMIO_VFE_CLK);
+	msm_camio_clk_disable(CAMIO_CSI0_PCLK);
+	if (csid_core == 0)
+		msm_camio_clk_disable(CAMIO_CSIPHY0_TIMER_CLK);
+	else if (csid_core == 1)
+		msm_camio_clk_disable(CAMIO_CSIPHY1_TIMER_CLK);
+	msm_camio_clk_disable(CAMIO_CSIPHY_TIMER_SRC_CLK);
+	msm_camio_clk_disable(CAMIO_CSI0_PHY_CLK);
+	msm_camio_clk_disable(CAMIO_CSI0_CLK);
+	if (csid_core == 1)
+		msm_camio_clk_disable(CAMIO_CSI1_SRC_CLK);
+	msm_camio_clk_disable(CAMIO_CSI_SRC_CLK);
+}
+
+int msm_camio_jpeg_clk_disable(void)
+{
+	int rc = 0;
+	if (fs_ijpeg) {
+		rc = regulator_disable(fs_ijpeg);
+		if (rc < 0) {
+			CDBG("%s: Regulator disable failed %d\n", __func__, rc);
+			return rc;
+		}
+		regulator_put(fs_ijpeg);
+	}
+	rc = msm_camio_clk_disable(CAMIO_JPEG_PCLK);
+	if (rc < 0)
+		return rc;
+	rc = msm_camio_clk_disable(CAMIO_JPEG_CLK);
+	CDBG("%s: exit %d\n", __func__, rc);
+	return rc;
+}
+
+int msm_camio_jpeg_clk_enable(void)
+{
+	int rc = 0;
+	rc = msm_camio_clk_enable(CAMIO_JPEG_CLK);
+	if (rc < 0)
+		return rc;
+	rc = msm_camio_clk_enable(CAMIO_JPEG_PCLK);
+	if (rc < 0)
+		return rc;
+	fs_ijpeg = regulator_get(NULL, "fs_ijpeg");
+	if (IS_ERR(fs_ijpeg)) {
+		CDBG("%s: Regulator FS_IJPEG get failed %ld\n", __func__,
+			PTR_ERR(fs_ijpeg));
+		fs_ijpeg = NULL;
+	} else if (regulator_enable(fs_ijpeg)) {
+		CDBG("%s: Regulator FS_IJPEG enable failed\n", __func__);
+		regulator_put(fs_ijpeg);
+	}
+	CDBG("%s: exit %d\n", __func__, rc);
+	return rc;
+}
+
+int msm_camio_vpe_clk_disable(void)
+{
+	int rc = 0;
+	if (fs_vpe) {
+		regulator_disable(fs_vpe);
+		regulator_put(fs_vpe);
+	}
+
+	rc = msm_camio_clk_disable(CAMIO_VPE_CLK);
+	if (rc < 0)
+		return rc;
+	rc = msm_camio_clk_disable(CAMIO_VPE_PCLK);
+	return rc;
+}
+
+int msm_camio_vpe_clk_enable(uint32_t clk_rate)
+{
+	int rc = 0;
+	(void)clk_rate;
+	fs_vpe = regulator_get(NULL, "fs_vpe");
+	if (IS_ERR(fs_vpe)) {
+		CDBG("%s: Regulator FS_VPE get failed %ld\n", __func__,
+			PTR_ERR(fs_vpe));
+		fs_vpe = NULL;
+	} else if (regulator_enable(fs_vpe)) {
+		CDBG("%s: Regulator FS_VPE enable failed\n", __func__);
+		regulator_put(fs_vpe);
+	}
+
+	rc = msm_camio_clk_enable(CAMIO_VPE_CLK);
+	if (rc < 0)
+		return rc;
+	rc = msm_camio_clk_enable(CAMIO_VPE_PCLK);
+	return rc;
+}
+
+int msm_camio_enable(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	uint8_t csid_core = camdev->csid_core;
+	char csid[] = "csid0";
+	char csiphy[] = "csiphy0";
+	if (csid_core < 0 || csid_core > 2)
+		return -ENODEV;
+
+	csid[4] = '0' + csid_core;
+	csiphy[6] = '0' + csid_core;
+
+	camio_dev = pdev;
+	camio_clk = camdev->ioclk;
+
+	rc = msm_camio_enable_all_clks(csid_core);
+	if (rc < 0)
+		return rc;
+
+	csid_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, csid);
+	if (!csid_mem) {
+		pr_err("%s: no mem resource?\n", __func__);
+		return -ENODEV;
+	}
+	csid_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, csid);
+	if (!csid_irq) {
+		pr_err("%s: no irq resource?\n", __func__);
+		return -ENODEV;
+	}
+	csiphy_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, csiphy);
+	if (!csiphy_mem) {
+		pr_err("%s: no mem resource?\n", __func__);
+		return -ENODEV;
+	}
+	csiphy_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, csiphy);
+	if (!csiphy_irq) {
+		pr_err("%s: no irq resource?\n", __func__);
+		return -ENODEV;
+	}
+
+	csidio = request_mem_region(csid_mem->start,
+		resource_size(csid_mem), pdev->name);
+	if (!csidio) {
+		rc = -EBUSY;
+		goto common_fail;
+	}
+	csidbase = ioremap(csid_mem->start,
+		resource_size(csid_mem));
+	if (!csidbase) {
+		rc = -ENOMEM;
+		goto csi_busy;
+	}
+#if DBG_CSID
+	rc = request_irq(csid_irq->start, msm_io_csi_irq,
+		IRQF_TRIGGER_RISING, "csid", 0);
+	if (rc < 0)
+		goto csi_irq_fail;
+#endif
+	csiphyio = request_mem_region(csiphy_mem->start,
+		resource_size(csiphy_mem), pdev->name);
+	if (!csidio) {
+		rc = -EBUSY;
+		goto csi_irq_fail;
+	}
+	csiphybase = ioremap(csiphy_mem->start,
+		resource_size(csiphy_mem));
+	if (!csiphybase) {
+		rc = -ENOMEM;
+		goto csiphy_busy;
+	}
+#if DBG_CSIPHY
+	rc = request_irq(csiphy_irq->start, msm_io_csiphy_irq,
+		IRQF_TRIGGER_RISING, "csiphy", 0);
+	if (rc < 0)
+		goto csiphy_irq_fail;
+#endif
+	rc = msm_ispif_init(pdev);
+	if (rc < 0)
+		goto csiphy_irq_fail;
+	CDBG("camio enable done\n");
+	return 0;
+csiphy_irq_fail:
+	iounmap(csiphybase);
+csiphy_busy:
+	release_mem_region(csiphy_mem->start, resource_size(csiphy_mem));
+csi_irq_fail:
+	iounmap(csidbase);
+csi_busy:
+	release_mem_region(csid_mem->start, resource_size(csid_mem));
+common_fail:
+	msm_camio_disable_all_clks(csid_core);
+	msm_camera_vreg_disable();
+	camdev->camera_gpio_off();
+	return rc;
+}
+
+void msm_camio_disable(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	uint8_t csid_core = camdev->csid_core;
+#if DBG_CSIPHY
+	free_irq(csiphy_irq->start, 0);
+#endif
+	iounmap(csiphybase);
+	release_mem_region(csiphy_mem->start, resource_size(csiphy_mem));
+
+#if DBG_CSID
+	free_irq(csid_irq, 0);
+#endif
+	iounmap(csidbase);
+	release_mem_region(csid_mem->start, resource_size(csid_mem));
+
+	msm_camio_disable_all_clks(csid_core);
+	msm_ispif_release(pdev);
+}
+
+int msm_camio_sensor_clk_on(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	camio_dev = pdev;
+	camio_clk = camdev->ioclk;
+
+	msm_camera_vreg_enable(pdev);
+	msleep(20);
+	rc = camdev->camera_gpio_on();
+	if (rc < 0)
+		return rc;
+	return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
+}
+
+int msm_camio_sensor_clk_off(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	msm_camera_vreg_disable();
+	camdev->camera_gpio_off();
+	return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
+}
+
+void msm_camio_vfe_blk_reset(void)
+{
+	return;
+}
+
+int msm_camio_probe_on(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	camio_dev = pdev;
+	camio_clk = camdev->ioclk;
+
+	rc = camdev->camera_gpio_on();
+	if (rc < 0)
+		return rc;
+	msm_camera_vreg_enable(pdev);
+	return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
+}
+
+int msm_camio_probe_off(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	msm_camera_vreg_disable();
+	camdev->camera_gpio_off();
+	return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
+}
+
+int msm_camio_csid_cid_lut(struct msm_camera_csid_lut_params *csid_lut_params)
+{
+	int rc = 0, i = 0;
+	uint32_t val = 0;
+
+	for (i = 0; i < csid_lut_params->num_cid && i < 4; i++)	{
+		if (csid_lut_params->vc_cfg[i].dt < 0x12 ||
+			csid_lut_params->vc_cfg[i].dt > 0x37) {
+			CDBG("%s: unsupported data type 0x%x\n",
+				 __func__, csid_lut_params->vc_cfg[i].dt);
+			return rc;
+		}
+		val = msm_io_r(csidbase + CSID_CID_LUT_VC_0_ADDR +
+		(csid_lut_params->vc_cfg[i].cid >> 2) * 4)
+		& ~(0xFF << csid_lut_params->vc_cfg[i].cid * 8);
+		val |= csid_lut_params->vc_cfg[i].dt <<
+			csid_lut_params->vc_cfg[i].cid * 8;
+		msm_io_w(val, csidbase + CSID_CID_LUT_VC_0_ADDR +
+			(csid_lut_params->vc_cfg[i].cid >> 2) * 4);
+		val = csid_lut_params->vc_cfg[i].decode_format << 4 | 0x3;
+		msm_io_w(val, csidbase + CSID_CID_n_CFG_ADDR +
+			(csid_lut_params->vc_cfg[i].cid * 4));
+	}
+	return rc;
+}
+
+int msm_camio_csid_config(struct msm_camera_csid_params *csid_params)
+{
+	int rc = 0;
+	uint32_t val = 0;
+	val = csid_params->lane_cnt - 1;
+	val |= csid_params->lane_assign << 2;
+	val |= 0x1 << 10;
+	val |= 0x1 << 11;
+	val |= 0x1 << 12;
+	val |= 0x1 << 28;
+	msm_io_w(val, csidbase + CSID_CORE_CTRL_ADDR);
+
+	rc = msm_camio_csid_cid_lut(&csid_params->lut_params);
+	if (rc < 0)
+		return rc;
+
+	msm_io_w(0xFFFFFFFF, csidbase + CSID_IRQ_MASK_ADDR);
+	msm_io_w(0xFFFFFFFF, csidbase + CSID_IRQ_CLEAR_CMD_ADDR);
+
+	msleep(20);
+	return rc;
+}
+
+int msm_camio_csiphy_config(struct msm_camera_csiphy_params *csiphy_params)
+{
+	int rc = 0;
+	int i = 0;
+	uint32_t val = 0;
+	if (csiphy_params->lane_cnt < 1 || csiphy_params->lane_cnt > 4) {
+		CDBG("%s: unsupported lane cnt %d\n",
+			__func__, csiphy_params->lane_cnt);
+		return rc;
+	}
+
+	val = 0x3;
+	msm_io_w((((1 << csiphy_params->lane_cnt) - 1) << 2) | val,
+			 csiphybase + MIPI_CSIPHY_GLBL_PWR_CFG_ADDR);
+	msm_io_w(0x1, csiphybase + MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR);
+	msm_io_w(0x1, csiphybase + MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR);
+
+	for (i = 0; i < csiphy_params->lane_cnt; i++) {
+		msm_io_w(0x10, csiphybase + MIPI_CSIPHY_LNn_CFG1_ADDR + 0x40*i);
+		msm_io_w(0x5F, csiphybase + MIPI_CSIPHY_LNn_CFG2_ADDR + 0x40*i);
+		msm_io_w(csiphy_params->settle_cnt,
+			csiphybase + MIPI_CSIPHY_LNn_CFG3_ADDR + 0x40*i);
+		msm_io_w(0x00000052,
+			csiphybase + MIPI_CSIPHY_LNn_CFG5_ADDR + 0x40*i);
+	}
+
+	msm_io_w(0x00000000, csiphybase + MIPI_CSIPHY_LNCK_CFG1_ADDR);
+	msm_io_w(0x5F, csiphybase + MIPI_CSIPHY_LNCK_CFG2_ADDR);
+	msm_io_w(csiphy_params->settle_cnt,
+			 csiphybase + MIPI_CSIPHY_LNCK_CFG3_ADDR);
+	msm_io_w(0x5, csiphybase + MIPI_CSIPHY_LNCK_CFG4_ADDR);
+	msm_io_w(0x2, csiphybase + MIPI_CSIPHY_LNCK_CFG5_ADDR);
+	msm_io_w(0x0, csiphybase + 0x128);
+
+	for (i = 0; i <= csiphy_params->lane_cnt; i++) {
+		msm_io_w(0xFFFFFFFF,
+			csiphybase + MIPI_CSIPHY_INTERRUPT_MASK0_ADDR + 0x4*i);
+		msm_io_w(0xFFFFFFFF,
+			csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR + 0x4*i);
+	}
+	return rc;
+}
+
+void msm_camio_set_perf_lvl(enum msm_bus_perf_setting perf_setting)
+{
+	static uint32_t bus_perf_client;
+	int rc = 0;
+	switch (perf_setting) {
+	case S_INIT:
+		bus_perf_client =
+			msm_bus_scale_register_client(&cam_bus_client_pdata);
+		if (!bus_perf_client) {
+			CDBG("%s: Registration Failed!!!\n", __func__);
+			bus_perf_client = 0;
+			return;
+		}
+		CDBG("%s: S_INIT rc = %u\n", __func__, bus_perf_client);
+		break;
+	case S_EXIT:
+		if (bus_perf_client) {
+			CDBG("%s: S_EXIT\n", __func__);
+			msm_bus_scale_unregister_client(bus_perf_client);
+		} else
+			CDBG("%s: Bus Client NOT Registered!!!\n", __func__);
+		break;
+	case S_PREVIEW:
+		if (bus_perf_client) {
+			rc = msm_bus_scale_client_update_request(
+				bus_perf_client, 1);
+			CDBG("%s: S_PREVIEW rc = %d\n", __func__, rc);
+		} else
+			CDBG("%s: Bus Client NOT Registered!!!\n", __func__);
+		break;
+	case S_VIDEO:
+		if (bus_perf_client) {
+			rc = msm_bus_scale_client_update_request(
+				bus_perf_client, 2);
+			CDBG("%s: S_VIDEO rc = %d\n", __func__, rc);
+		} else
+			CDBG("%s: Bus Client NOT Registered!!!\n", __func__);
+		break;
+	case S_CAPTURE:
+		if (bus_perf_client) {
+			rc = msm_bus_scale_client_update_request(
+				bus_perf_client, 3);
+			CDBG("%s: S_CAPTURE rc = %d\n", __func__, rc);
+		} else
+			CDBG("%s: Bus Client NOT Registered!!!\n", __func__);
+		break;
+	case S_DEFAULT:
+		break;
+	default:
+		pr_warning("%s: INVALID CASE\n", __func__);
+	}
+}
diff --git a/drivers/media/video/msm/msm_io_8x60.c b/drivers/media/video/msm/msm_io_8x60.c
new file mode 100644
index 0000000..845777d
--- /dev/null
+++ b/drivers/media/video/msm/msm_io_8x60.c
@@ -0,0 +1,900 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/regulator/consumer.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/camera.h>
+#include <mach/vreg.h>
+#include <mach/camera.h>
+#include <mach/clk.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+
+
+/* MIPI	CSI	controller registers */
+#define	MIPI_PHY_CONTROL			0x00000000
+#define	MIPI_PROTOCOL_CONTROL		0x00000004
+#define	MIPI_INTERRUPT_STATUS		0x00000008
+#define	MIPI_INTERRUPT_MASK			0x0000000C
+#define	MIPI_CAMERA_CNTL			0x00000024
+#define	MIPI_CALIBRATION_CONTROL	0x00000018
+#define	MIPI_PHY_D0_CONTROL2		0x00000038
+#define	MIPI_PHY_D1_CONTROL2		0x0000003C
+#define	MIPI_PHY_D2_CONTROL2		0x00000040
+#define	MIPI_PHY_D3_CONTROL2		0x00000044
+#define	MIPI_PHY_CL_CONTROL			0x00000048
+#define	MIPI_PHY_D0_CONTROL			0x00000034
+#define	MIPI_PHY_D1_CONTROL			0x00000020
+#define	MIPI_PHY_D2_CONTROL			0x0000002C
+#define	MIPI_PHY_D3_CONTROL			0x00000030
+#define	MIPI_PROTOCOL_CONTROL_SW_RST_BMSK			0x8000000
+#define	MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK	0x200000
+#define	MIPI_PROTOCOL_CONTROL_DATA_FORMAT_BMSK			0x180000
+#define	MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK			0x40000
+#define	MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK			0x20000
+#define	MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT		0x16
+#define	MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT	0x15
+#define	MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT		0x14
+#define	MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT	0x7
+#define	MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT			0x13
+#define	MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT			0x1e
+#define	MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT			0x18
+#define	MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT			0x10
+#define	MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT				0x4
+#define	MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT			0x3
+#define	MIPI_PHY_D1_CONTROL2_SETTLE_COUNT_SHFT			0x18
+#define	MIPI_PHY_D1_CONTROL2_HS_TERM_IMP_SHFT			0x10
+#define	MIPI_PHY_D1_CONTROL2_LP_REC_EN_SHFT				0x4
+#define	MIPI_PHY_D1_CONTROL2_ERR_SOT_HS_EN_SHFT			0x3
+#define	MIPI_PHY_D2_CONTROL2_SETTLE_COUNT_SHFT			0x18
+#define	MIPI_PHY_D2_CONTROL2_HS_TERM_IMP_SHFT			0x10
+#define	MIPI_PHY_D2_CONTROL2_LP_REC_EN_SHFT				0x4
+#define	MIPI_PHY_D2_CONTROL2_ERR_SOT_HS_EN_SHFT			0x3
+#define	MIPI_PHY_D3_CONTROL2_SETTLE_COUNT_SHFT			0x18
+#define	MIPI_PHY_D3_CONTROL2_HS_TERM_IMP_SHFT			0x10
+#define	MIPI_PHY_D3_CONTROL2_LP_REC_EN_SHFT				0x4
+#define	MIPI_PHY_D3_CONTROL2_ERR_SOT_HS_EN_SHFT			0x3
+#define	MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT			0x18
+#define	MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT				0x2
+#define	MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT				0x1c
+#define	MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT		0x9
+#define	MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT	0x8
+
+static struct clk *camio_cam_clk;
+static struct clk *camio_vfe_clk;
+static struct clk *camio_csi_src_clk;
+static struct clk *camio_csi0_vfe_clk;
+static struct clk *camio_csi1_vfe_clk;
+static struct clk *camio_csi0_clk;
+static struct clk *camio_csi1_clk;
+static struct clk *camio_csi0_pclk;
+static struct clk *camio_csi1_pclk;
+static struct clk *camio_vfe_pclk;
+static struct clk *camio_jpeg_clk;
+static struct clk *camio_jpeg_pclk;
+static struct clk *camio_vpe_clk;
+static struct clk *camio_vpe_pclk;
+static struct regulator *fs_vfe;
+static struct regulator *fs_ijpeg;
+static struct regulator *fs_vpe;
+static struct regulator *ldo15;
+static struct regulator *lvs0;
+static struct regulator *ldo25;
+
+static struct msm_camera_io_ext camio_ext;
+static struct msm_camera_io_clk camio_clk;
+static struct platform_device *camio_dev;
+static struct resource *csiio;
+void __iomem *csibase;
+static int vpe_clk_rate;
+struct msm_bus_scale_pdata *cam_bus_scale_table;
+
+void msm_io_w(u32 data, void __iomem *addr)
+{
+	CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+	writel_relaxed((data), (addr));
+}
+
+void msm_io_w_mb(u32 data, void __iomem *addr)
+{
+	CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+	wmb();
+	writel_relaxed((data), (addr));
+	wmb();
+}
+
+u32 msm_io_r(void __iomem *addr)
+{
+	uint32_t data = readl_relaxed(addr);
+	CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+	return data;
+}
+
+u32 msm_io_r_mb(void __iomem *addr)
+{
+	uint32_t data;
+	rmb();
+	data = readl_relaxed(addr);
+	rmb();
+	CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+	return data;
+}
+
+void msm_io_memcpy_toio(void __iomem *dest_addr,
+	void __iomem *src_addr, u32 len)
+{
+	int i;
+	u32 *d = (u32 *) dest_addr;
+	u32 *s = (u32 *) src_addr;
+	/* memcpy_toio does not work. Use writel for now */
+	for (i = 0; i < len; i++)
+		writel_relaxed(*s++, d++);
+}
+
+void msm_io_dump(void __iomem *addr, int size)
+{
+	char line_str[128], *p_str;
+	int i;
+	u32 *p = (u32 *) addr;
+	u32 data;
+	CDBG("%s: %p %d\n", __func__, addr, size);
+	line_str[0] = '\0';
+	p_str = line_str;
+	for (i = 0; i < size/4; i++) {
+		if (i % 4 == 0) {
+			sprintf(p_str, "%08x: ", (u32) p);
+			p_str += 10;
+		}
+		data = readl_relaxed(p++);
+		sprintf(p_str, "%08x ", data);
+		p_str += 9;
+		if ((i + 1) % 4 == 0) {
+			CDBG("%s\n", line_str);
+			line_str[0] = '\0';
+			p_str = line_str;
+		}
+	}
+	if (line_str[0] != '\0')
+		CDBG("%s\n", line_str);
+}
+
+void msm_io_memcpy(void __iomem *dest_addr, void __iomem *src_addr, u32 len)
+{
+	CDBG("%s: %p %p %d\n", __func__, dest_addr, src_addr, len);
+	msm_io_memcpy_toio(dest_addr, src_addr, len / 4);
+	msm_io_dump(dest_addr, len);
+}
+
+static void msm_camera_vreg_enable(void)
+{
+	ldo15 = regulator_get(NULL, "8058_l15");
+	if (IS_ERR(ldo15)) {
+		pr_err("%s: VREG LDO15 get failed\n", __func__);
+		ldo15 = NULL;
+		return;
+	}
+	if (regulator_set_voltage(ldo15, 2850000, 2850000)) {
+		pr_err("%s: VREG LDO15 set voltage failed\n",  __func__);
+		goto ldo15_disable;
+	}
+	if (regulator_enable(ldo15)) {
+		pr_err("%s: VREG LDO15 enable failed\n", __func__);
+		goto ldo15_put;
+	}
+
+	lvs0 = regulator_get(NULL, "8058_lvs0");
+	if (IS_ERR(lvs0)) {
+		pr_err("%s: VREG LVS0 get failed\n", __func__);
+		lvs0 = NULL;
+		goto ldo15_disable;
+	}
+	if (regulator_enable(lvs0)) {
+		pr_err("%s: VREG LVS0 enable failed\n", __func__);
+		goto lvs0_put;
+	}
+
+	ldo25 = regulator_get(NULL, "8058_l25");
+	if (IS_ERR(ldo25)) {
+		pr_err("%s: VREG LDO25 get failed\n", __func__);
+		ldo25 = NULL;
+		goto lvs0_disable;
+	}
+	if (regulator_set_voltage(ldo25, 1200000, 1200000)) {
+		pr_err("%s: VREG LDO25 set voltage failed\n",  __func__);
+		goto ldo25_disable;
+	}
+	if (regulator_enable(ldo25)) {
+		pr_err("%s: VREG LDO25 enable failed\n", __func__);
+		goto ldo25_put;
+	}
+
+	fs_vfe = regulator_get(NULL, "fs_vfe");
+	if (IS_ERR(fs_vfe)) {
+		CDBG("%s: Regulator FS_VFE get failed %ld\n", __func__,
+			PTR_ERR(fs_vfe));
+		fs_vfe = NULL;
+	} else if (regulator_enable(fs_vfe)) {
+		CDBG("%s: Regulator FS_VFE enable failed\n", __func__);
+		regulator_put(fs_vfe);
+	}
+	return;
+
+ldo25_disable:
+	regulator_disable(ldo25);
+ldo25_put:
+	regulator_put(ldo25);
+lvs0_disable:
+	regulator_disable(lvs0);
+lvs0_put:
+	regulator_put(lvs0);
+ldo15_disable:
+	regulator_disable(ldo15);
+ldo15_put:
+	regulator_put(ldo15);
+}
+
+static void msm_camera_vreg_disable(void)
+{
+	if (ldo15) {
+		regulator_disable(ldo15);
+		regulator_put(ldo15);
+	}
+
+	if (lvs0) {
+		regulator_disable(lvs0);
+		regulator_put(lvs0);
+	}
+
+	if (ldo25) {
+		regulator_disable(ldo25);
+		regulator_put(ldo25);
+	}
+
+	if (fs_vfe) {
+		regulator_disable(fs_vfe);
+		regulator_put(fs_vfe);
+	}
+}
+
+int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
+{
+	int rc = 0;
+	struct clk *clk = NULL;
+
+	switch (clktype) {
+	case CAMIO_CAM_MCLK_CLK:
+		camio_cam_clk =
+		clk = clk_get(NULL, "cam_clk");
+		msm_camio_clk_rate_set_2(clk, camio_clk.mclk_clk_rate);
+		break;
+
+	case CAMIO_VFE_CLK:
+		camio_vfe_clk =
+		clk = clk_get(NULL, "vfe_clk");
+		msm_camio_clk_rate_set_2(clk, camio_clk.vfe_clk_rate);
+		break;
+
+	case CAMIO_CSI0_VFE_CLK:
+		camio_csi0_vfe_clk =
+		clk = clk_get(NULL, "csi_vfe_clk");
+		break;
+
+	case CAMIO_CSI1_VFE_CLK:
+		camio_csi1_vfe_clk =
+		clk = clk_get(&camio_dev->dev, "csi_vfe_clk");
+		break;
+
+	case CAMIO_CSI_SRC_CLK:
+		camio_csi_src_clk =
+		clk = clk_get(NULL, "csi_src_clk");
+		msm_camio_clk_rate_set_2(clk, 384000000);
+		break;
+
+	case CAMIO_CSI0_CLK:
+		camio_csi0_clk =
+		clk = clk_get(NULL, "csi_clk");
+		break;
+
+	case CAMIO_CSI1_CLK:
+		camio_csi1_clk =
+		clk = clk_get(&camio_dev->dev, "csi_clk");
+		break;
+
+	case CAMIO_VFE_PCLK:
+		camio_vfe_pclk =
+		clk = clk_get(NULL, "vfe_pclk");
+		break;
+
+	case CAMIO_CSI0_PCLK:
+		camio_csi0_pclk =
+		clk = clk_get(NULL, "csi_pclk");
+		break;
+
+	case CAMIO_CSI1_PCLK:
+		camio_csi1_pclk =
+		clk = clk_get(&camio_dev->dev, "csi_pclk");
+		break;
+
+	case CAMIO_JPEG_CLK:
+		camio_jpeg_clk =
+		clk = clk_get(NULL, "ijpeg_clk");
+		msm_camio_clk_rate_set_2(clk, 228571000);
+		break;
+
+	case CAMIO_JPEG_PCLK:
+		camio_jpeg_pclk =
+		clk = clk_get(NULL, "ijpeg_pclk");
+		break;
+
+	case CAMIO_VPE_CLK:
+		camio_vpe_clk =
+		clk = clk_get(NULL, "vpe_clk");
+		msm_camio_clk_set_min_rate(camio_vpe_clk, vpe_clk_rate);
+		break;
+
+	case CAMIO_VPE_PCLK:
+		camio_vpe_pclk =
+		clk = clk_get(NULL, "vpe_pclk");
+		break;
+
+	default:
+		break;
+	}
+
+	if (!IS_ERR(clk))
+		clk_enable(clk);
+	else
+		rc = -1;
+	return rc;
+}
+
+int msm_camio_clk_disable(enum msm_camio_clk_type clktype)
+{
+	int rc = 0;
+	struct clk *clk = NULL;
+
+	switch (clktype) {
+	case CAMIO_CAM_MCLK_CLK:
+		clk = camio_cam_clk;
+		break;
+
+	case CAMIO_VFE_CLK:
+		clk = camio_vfe_clk;
+		break;
+
+	case CAMIO_CSI_SRC_CLK:
+		clk = camio_csi_src_clk;
+		break;
+
+	case CAMIO_CSI0_VFE_CLK:
+		clk = camio_csi0_vfe_clk;
+		break;
+
+	case CAMIO_CSI1_VFE_CLK:
+		clk = camio_csi1_vfe_clk;
+		break;
+
+	case CAMIO_CSI0_CLK:
+		clk = camio_csi0_clk;
+		break;
+
+	case CAMIO_CSI1_CLK:
+		clk = camio_csi1_clk;
+		break;
+
+	case CAMIO_VFE_PCLK:
+		clk = camio_vfe_pclk;
+		break;
+
+	case CAMIO_CSI0_PCLK:
+		clk = camio_csi0_pclk;
+		break;
+
+	case CAMIO_CSI1_PCLK:
+		clk = camio_csi1_pclk;
+		break;
+
+	case CAMIO_JPEG_CLK:
+		clk = camio_jpeg_clk;
+		break;
+
+	case CAMIO_JPEG_PCLK:
+		clk = camio_jpeg_pclk;
+		break;
+
+	case CAMIO_VPE_CLK:
+		clk = camio_vpe_clk;
+		break;
+
+	case CAMIO_VPE_PCLK:
+		clk = camio_vpe_pclk;
+		break;
+
+	default:
+		break;
+	}
+
+	if (!IS_ERR(clk)) {
+		clk_disable(clk);
+		clk_put(clk);
+	} else
+		rc = -1;
+	return rc;
+}
+
+void msm_camio_vfe_clk_rate_set(int rate)
+{
+	struct clk *clk = camio_vfe_clk;
+	if (rate > clk_get_rate(clk))
+		clk_set_rate(clk, rate);
+}
+
+void msm_camio_clk_rate_set(int rate)
+{
+	struct clk *clk = camio_cam_clk;
+	clk_set_rate(clk, rate);
+}
+
+void msm_camio_clk_rate_set_2(struct clk *clk, int rate)
+{
+	clk_set_rate(clk, rate);
+}
+
+void msm_camio_clk_set_min_rate(struct clk *clk, int rate)
+{
+	clk_set_min_rate(clk, rate);
+}
+
+static irqreturn_t msm_io_csi_irq(int irq_num, void *data)
+{
+	uint32_t irq;
+	irq = msm_io_r(csibase + MIPI_INTERRUPT_STATUS);
+	CDBG("%s MIPI_INTERRUPT_STATUS = 0x%x\n", __func__, irq);
+	msm_io_w(irq, csibase + MIPI_INTERRUPT_STATUS);
+	return IRQ_HANDLED;
+}
+
+int msm_camio_jpeg_clk_disable(void)
+{
+	int rc = 0;
+	if (fs_ijpeg) {
+		rc = regulator_disable(fs_ijpeg);
+		if (rc < 0) {
+			CDBG("%s: Regulator disable failed %d\n", __func__, rc);
+			return rc;
+		}
+		regulator_put(fs_ijpeg);
+	}
+	rc = msm_camio_clk_disable(CAMIO_JPEG_PCLK);
+	if (rc < 0)
+		return rc;
+	rc = msm_camio_clk_disable(CAMIO_JPEG_CLK);
+	CDBG("%s: exit %d\n", __func__, rc);
+	return rc;
+}
+
+int msm_camio_jpeg_clk_enable(void)
+{
+	int rc = 0;
+	rc = msm_camio_clk_enable(CAMIO_JPEG_CLK);
+	if (rc < 0)
+		return rc;
+	rc = msm_camio_clk_enable(CAMIO_JPEG_PCLK);
+	if (rc < 0)
+		return rc;
+	fs_ijpeg = regulator_get(NULL, "fs_ijpeg");
+	if (IS_ERR(fs_ijpeg)) {
+		CDBG("%s: Regulator FS_IJPEG get failed %ld\n", __func__,
+			PTR_ERR(fs_ijpeg));
+		fs_ijpeg = NULL;
+	} else if (regulator_enable(fs_ijpeg)) {
+		CDBG("%s: Regulator FS_IJPEG enable failed\n", __func__);
+		regulator_put(fs_ijpeg);
+	}
+	CDBG("%s: exit %d\n", __func__, rc);
+	return rc;
+}
+
+int msm_camio_vpe_clk_disable(void)
+{
+	int rc = 0;
+	if (fs_vpe) {
+		regulator_disable(fs_vpe);
+		regulator_put(fs_vpe);
+	}
+
+	rc = msm_camio_clk_disable(CAMIO_VPE_CLK);
+	if (rc < 0)
+		return rc;
+	rc = msm_camio_clk_disable(CAMIO_VPE_PCLK);
+	return rc;
+}
+
+int msm_camio_vpe_clk_enable(uint32_t clk_rate)
+{
+	int rc = 0;
+	fs_vpe = regulator_get(NULL, "fs_vpe");
+	if (IS_ERR(fs_vpe)) {
+		CDBG("%s: Regulator FS_VPE get failed %ld\n", __func__,
+			PTR_ERR(fs_vpe));
+		fs_vpe = NULL;
+	} else if (regulator_enable(fs_vpe)) {
+		CDBG("%s: Regulator FS_VPE enable failed\n", __func__);
+		regulator_put(fs_vpe);
+	}
+
+	vpe_clk_rate = clk_rate;
+	rc = msm_camio_clk_enable(CAMIO_VPE_CLK);
+	if (rc < 0)
+		return rc;
+
+	rc = msm_camio_clk_enable(CAMIO_VPE_PCLK);
+	return rc;
+}
+
+int msm_camio_enable(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	uint32_t val;
+
+	camio_dev = pdev;
+	camio_ext = camdev->ioext;
+	camio_clk = camdev->ioclk;
+	cam_bus_scale_table = camdev->cam_bus_scale_table;
+
+	msm_camio_clk_enable(CAMIO_VFE_CLK);
+	msm_camio_clk_enable(CAMIO_CSI0_VFE_CLK);
+	msm_camio_clk_enable(CAMIO_CSI1_VFE_CLK);
+	msm_camio_clk_enable(CAMIO_CSI_SRC_CLK);
+	msm_camio_clk_enable(CAMIO_CSI0_CLK);
+	msm_camio_clk_enable(CAMIO_CSI1_CLK);
+	msm_camio_clk_enable(CAMIO_VFE_PCLK);
+	msm_camio_clk_enable(CAMIO_CSI0_PCLK);
+	msm_camio_clk_enable(CAMIO_CSI1_PCLK);
+
+	csiio = request_mem_region(camio_ext.csiphy,
+		camio_ext.csisz, pdev->name);
+	if (!csiio) {
+		rc = -EBUSY;
+		goto common_fail;
+	}
+	csibase = ioremap(camio_ext.csiphy,
+		camio_ext.csisz);
+	if (!csibase) {
+		rc = -ENOMEM;
+		goto csi_busy;
+	}
+	rc = request_irq(camio_ext.csiirq, msm_io_csi_irq,
+		IRQF_TRIGGER_RISING, "csi", 0);
+	if (rc < 0)
+		goto csi_irq_fail;
+
+	msleep(10);
+	val = (20 <<
+		MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) |
+		(0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) |
+		(0x0 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) |
+		(0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT);
+	CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D2_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D3_CONTROL2);
+
+	val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) |
+		(0x0 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT);
+	CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_PHY_CL_CONTROL);
+	return 0;
+
+csi_irq_fail:
+	iounmap(csibase);
+csi_busy:
+	release_mem_region(camio_ext.csiphy, camio_ext.csisz);
+common_fail:
+	msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
+	msm_camio_clk_disable(CAMIO_CSI0_VFE_CLK);
+	msm_camio_clk_disable(CAMIO_CSI0_CLK);
+	msm_camio_clk_disable(CAMIO_CSI1_VFE_CLK);
+	msm_camio_clk_disable(CAMIO_CSI1_CLK);
+	msm_camio_clk_disable(CAMIO_VFE_PCLK);
+	msm_camio_clk_disable(CAMIO_CSI0_PCLK);
+	msm_camio_clk_disable(CAMIO_CSI1_PCLK);
+	msm_camera_vreg_disable();
+	camdev->camera_gpio_off();
+	return rc;
+}
+
+void msm_camio_disable(struct platform_device *pdev)
+{
+	uint32_t val;
+	val = (0x0 << MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT) |
+		(0x0 <<
+		MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT) |
+		(0x0 << MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT) |
+		(0x0 << MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT);
+	CDBG("%s MIPI_CALIBRATION_CONTROL val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_CALIBRATION_CONTROL);
+
+	val = (20 <<
+		MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) |
+		(0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) |
+		(0x0 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) |
+		(0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT);
+	CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D2_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D3_CONTROL2);
+
+	val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) |
+		(0x0 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT);
+	CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_PHY_CL_CONTROL);
+	msleep(10);
+
+	val = msm_io_r(csibase + MIPI_PHY_D1_CONTROL);
+	val &= ~((0x1 << MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT) |
+	(0x1 << MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT));
+	CDBG("%s MIPI_PHY_D1_CONTROL val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL);
+	usleep_range(5000, 6000);
+	free_irq(camio_ext.csiirq, 0);
+	iounmap(csibase);
+	release_mem_region(camio_ext.csiphy, camio_ext.csisz);
+	CDBG("disable clocks\n");
+
+	msm_camio_clk_disable(CAMIO_CSI0_VFE_CLK);
+	msm_camio_clk_disable(CAMIO_CSI0_CLK);
+	msm_camio_clk_disable(CAMIO_CSI1_VFE_CLK);
+	msm_camio_clk_disable(CAMIO_CSI1_CLK);
+	msm_camio_clk_disable(CAMIO_VFE_PCLK);
+	msm_camio_clk_disable(CAMIO_CSI0_PCLK);
+	msm_camio_clk_disable(CAMIO_CSI1_PCLK);
+	msm_camio_clk_disable(CAMIO_CSI_SRC_CLK);
+	msm_camio_clk_disable(CAMIO_VFE_CLK);
+}
+
+int msm_camio_sensor_clk_on(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	camio_dev = pdev;
+	camio_ext = camdev->ioext;
+	camio_clk = camdev->ioclk;
+
+	msm_camera_vreg_enable();
+	msleep(10);
+	rc = camdev->camera_gpio_on();
+	if (rc < 0)
+		return rc;
+	return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
+}
+
+int msm_camio_sensor_clk_off(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	msm_camera_vreg_disable();
+	camdev->camera_gpio_off();
+	return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
+
+}
+
+void msm_camio_vfe_blk_reset(void)
+{
+	return;
+}
+
+int msm_camio_probe_on(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	camio_dev = pdev;
+	camio_ext = camdev->ioext;
+	camio_clk = camdev->ioclk;
+
+	rc = camdev->camera_gpio_on();
+	if (rc < 0)
+		return rc;
+	msm_camera_vreg_enable();
+	return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
+}
+
+int msm_camio_probe_off(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	msm_camera_vreg_disable();
+	camdev->camera_gpio_off();
+	return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
+}
+
+int msm_camio_csi_config(struct msm_camera_csi_params *csi_params)
+{
+	int rc = 0;
+	uint32_t val = 0;
+
+	CDBG("msm_camio_csi_config \n");
+
+	/* SOT_ECC_EN enable error correction for SYNC (data-lane) */
+	msm_io_w(0x4, csibase + MIPI_PHY_CONTROL);
+
+	/* SW_RST to the CSI core */
+	msm_io_w(MIPI_PROTOCOL_CONTROL_SW_RST_BMSK,
+		csibase + MIPI_PROTOCOL_CONTROL);
+
+	/* PROTOCOL CONTROL */
+	val = MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK |
+		MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK |
+		MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK;
+	val |= (uint32_t)(csi_params->data_format) <<
+		MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT;
+	val |= csi_params->dpcm_scheme <<
+		MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT;
+	CDBG("%s MIPI_PROTOCOL_CONTROL val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_PROTOCOL_CONTROL);
+
+	/* SW CAL EN */
+	val = (0x1 << MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT) |
+		(0x1 <<
+		MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT) |
+		(0x1 << MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT) |
+		(0x1 << MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT);
+	CDBG("%s MIPI_CALIBRATION_CONTROL val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_CALIBRATION_CONTROL);
+
+	/* settle_cnt is very sensitive to speed!
+	increase this value to run at higher speeds */
+	val = (csi_params->settle_cnt <<
+		MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) |
+		(0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) |
+		(0x1 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) |
+		(0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT);
+	CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D2_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D3_CONTROL2);
+
+
+	val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) |
+		(0x1 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT);
+	CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_PHY_CL_CONTROL);
+
+	val = 0 << MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT;
+	msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL);
+
+	val = (0x1 << MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT) |
+		(0x1 << MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT);
+	CDBG("%s MIPI_PHY_D1_CONTROL val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL);
+
+	msm_io_w(0x00000000, csibase + MIPI_PHY_D2_CONTROL);
+	msm_io_w(0x00000000, csibase + MIPI_PHY_D3_CONTROL);
+
+	/* halcyon only supports 1 or 2 lane */
+	switch (csi_params->lane_cnt) {
+	case 1:
+		msm_io_w(csi_params->lane_assign << 8 | 0x4,
+			csibase + MIPI_CAMERA_CNTL);
+		break;
+	case 2:
+		msm_io_w(csi_params->lane_assign << 8 | 0x5,
+			csibase + MIPI_CAMERA_CNTL);
+		break;
+	case 3:
+		msm_io_w(csi_params->lane_assign << 8 | 0x6,
+			csibase + MIPI_CAMERA_CNTL);
+		break;
+	case 4:
+		msm_io_w(csi_params->lane_assign << 8 | 0x7,
+			csibase + MIPI_CAMERA_CNTL);
+		break;
+	}
+
+	/* mask out ID_ERROR[19], DATA_CMM_ERR[11]
+	and CLK_CMM_ERR[10] - de-featured */
+	msm_io_w(0xFFF7F3FF, csibase + MIPI_INTERRUPT_MASK);
+	/*clear IRQ bits*/
+	msm_io_w(0xFFF7F3FF, csibase + MIPI_INTERRUPT_STATUS);
+
+	return rc;
+}
+
+void msm_camio_set_perf_lvl(enum msm_bus_perf_setting perf_setting)
+{
+	static uint32_t bus_perf_client;
+	int rc = 0;
+	switch (perf_setting) {
+	case S_INIT:
+		bus_perf_client =
+			msm_bus_scale_register_client(cam_bus_scale_table);
+		if (!bus_perf_client) {
+			pr_err("%s: Registration Failed!!!\n", __func__);
+			bus_perf_client = 0;
+			return;
+		}
+		CDBG("%s: S_INIT rc = %u\n", __func__, bus_perf_client);
+		break;
+	case S_EXIT:
+		if (bus_perf_client) {
+			CDBG("%s: S_EXIT\n", __func__);
+			msm_bus_scale_unregister_client(bus_perf_client);
+		} else
+			pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+		break;
+	case S_PREVIEW:
+		if (bus_perf_client) {
+			rc = msm_bus_scale_client_update_request(
+				bus_perf_client, 1);
+			CDBG("%s: S_PREVIEW rc = %d\n", __func__, rc);
+		} else
+			pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+		break;
+	case S_VIDEO:
+		if (bus_perf_client) {
+			rc = msm_bus_scale_client_update_request(
+				bus_perf_client, 2);
+			CDBG("%s: S_VIDEO rc = %d\n", __func__, rc);
+		} else
+			pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+		break;
+	case S_CAPTURE:
+		if (bus_perf_client) {
+			rc = msm_bus_scale_client_update_request(
+				bus_perf_client, 3);
+			CDBG("%s: S_CAPTURE rc = %d\n", __func__, rc);
+		} else
+			pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+		break;
+
+	case S_ZSL:
+		if (bus_perf_client) {
+			rc = msm_bus_scale_client_update_request(
+				bus_perf_client, 4);
+			CDBG("%s: S_ZSL rc = %d\n", __func__, rc);
+		} else
+			pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+		break;
+	case S_STEREO_VIDEO:
+		if (bus_perf_client) {
+			rc = msm_bus_scale_client_update_request(
+				bus_perf_client, 5);
+			CDBG("%s: S_STEREO_VIDEO rc = %d\n", __func__, rc);
+		} else
+			pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+		break;
+	case S_STEREO_CAPTURE:
+		if (bus_perf_client) {
+			rc = msm_bus_scale_client_update_request(
+				bus_perf_client, 6);
+			CDBG("%s: S_STEREO_VIDEO rc = %d\n", __func__, rc);
+		} else
+			pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+		break;
+	case S_DEFAULT:
+		break;
+	default:
+		pr_warning("%s: INVALID CASE\n", __func__);
+	}
+}
diff --git a/drivers/media/video/msm/msm_io_vfe31.c b/drivers/media/video/msm/msm_io_vfe31.c
new file mode 100644
index 0000000..6279b36
--- /dev/null
+++ b/drivers/media/video/msm/msm_io_vfe31.c
@@ -0,0 +1,924 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/pm_qos_params.h>
+#include <linux/regulator/consumer.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/camera.h>
+#include <mach/vreg.h>
+#include <mach/clk.h>
+
+#define CAMIF_CFG_RMSK             0x1fffff
+#define CAM_SEL_BMSK               0x2
+#define CAM_PCLK_SRC_SEL_BMSK      0x60000
+#define CAM_PCLK_INVERT_BMSK       0x80000
+#define CAM_PAD_REG_SW_RESET_BMSK  0x100000
+
+#define EXT_CAM_HSYNC_POL_SEL_BMSK 0x10000
+#define EXT_CAM_VSYNC_POL_SEL_BMSK 0x8000
+#define MDDI_CLK_CHICKEN_BIT_BMSK  0x80
+
+#define CAM_SEL_SHFT               0x1
+#define CAM_PCLK_SRC_SEL_SHFT      0x11
+#define CAM_PCLK_INVERT_SHFT       0x13
+#define CAM_PAD_REG_SW_RESET_SHFT  0x14
+
+#define EXT_CAM_HSYNC_POL_SEL_SHFT 0x10
+#define EXT_CAM_VSYNC_POL_SEL_SHFT 0xF
+#define MDDI_CLK_CHICKEN_BIT_SHFT  0x7
+
+/* MIPI	CSI	controller registers */
+#define	MIPI_PHY_CONTROL			0x00000000
+#define	MIPI_PROTOCOL_CONTROL		0x00000004
+#define	MIPI_INTERRUPT_STATUS		0x00000008
+#define	MIPI_INTERRUPT_MASK			0x0000000C
+#define	MIPI_CAMERA_CNTL			0x00000024
+#define	MIPI_CALIBRATION_CONTROL	0x00000018
+#define	MIPI_PHY_D0_CONTROL2		0x00000038
+#define	MIPI_PHY_D1_CONTROL2		0x0000003C
+#define	MIPI_PHY_D2_CONTROL2		0x00000040
+#define	MIPI_PHY_D3_CONTROL2		0x00000044
+#define	MIPI_PHY_CL_CONTROL			0x00000048
+#define	MIPI_PHY_D0_CONTROL			0x00000034
+#define	MIPI_PHY_D1_CONTROL			0x00000020
+#define	MIPI_PHY_D2_CONTROL			0x0000002C
+#define	MIPI_PHY_D3_CONTROL			0x00000030
+#define	MIPI_PROTOCOL_CONTROL_SW_RST_BMSK			0x8000000
+#define	MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK	0x200000
+#define	MIPI_PROTOCOL_CONTROL_DATA_FORMAT_BMSK			0x180000
+#define	MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK			0x40000
+#define	MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK			0x20000
+#define	MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT		0x16
+#define	MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT	0x15
+#define	MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT		0x14
+#define	MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT	0x7
+#define	MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT			0x13
+#define	MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT			0x1e
+#define	MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT			0x18
+#define	MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT			0x10
+#define	MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT				0x4
+#define	MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT			0x3
+#define	MIPI_PHY_D1_CONTROL2_SETTLE_COUNT_SHFT			0x18
+#define	MIPI_PHY_D1_CONTROL2_HS_TERM_IMP_SHFT			0x10
+#define	MIPI_PHY_D1_CONTROL2_LP_REC_EN_SHFT				0x4
+#define	MIPI_PHY_D1_CONTROL2_ERR_SOT_HS_EN_SHFT			0x3
+#define	MIPI_PHY_D2_CONTROL2_SETTLE_COUNT_SHFT			0x18
+#define	MIPI_PHY_D2_CONTROL2_HS_TERM_IMP_SHFT			0x10
+#define	MIPI_PHY_D2_CONTROL2_LP_REC_EN_SHFT				0x4
+#define	MIPI_PHY_D2_CONTROL2_ERR_SOT_HS_EN_SHFT			0x3
+#define	MIPI_PHY_D3_CONTROL2_SETTLE_COUNT_SHFT			0x18
+#define	MIPI_PHY_D3_CONTROL2_HS_TERM_IMP_SHFT			0x10
+#define	MIPI_PHY_D3_CONTROL2_LP_REC_EN_SHFT				0x4
+#define	MIPI_PHY_D3_CONTROL2_ERR_SOT_HS_EN_SHFT			0x3
+#define	MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT			0x18
+#define	MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT				0x2
+#define	MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT				0x1c
+#define	MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT		0x9
+#define	MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT	0x8
+
+#define	CAMIO_VFE_CLK_SNAP			122880000
+#define	CAMIO_VFE_CLK_PREV			122880000
+
+#ifdef CONFIG_MSM_NPA_SYSTEM_BUS
+/* NPA Flow IDs */
+#define MSM_AXI_QOS_PREVIEW     MSM_AXI_FLOW_CAMERA_PREVIEW_HIGH
+#define MSM_AXI_QOS_SNAPSHOT    MSM_AXI_FLOW_CAMERA_SNAPSHOT_12MP
+#define MSM_AXI_QOS_RECORDING   MSM_AXI_FLOW_CAMERA_RECORDING_720P
+#else
+/* AXI rates in KHz */
+#define MSM_AXI_QOS_PREVIEW     192000
+#define MSM_AXI_QOS_SNAPSHOT    192000
+#define MSM_AXI_QOS_RECORDING   192000
+#endif
+
+static struct clk *camio_vfe_mdc_clk;
+static struct clk *camio_mdc_clk;
+static struct clk *camio_vfe_clk;
+static struct clk *camio_vfe_camif_clk;
+static struct clk *camio_vfe_pbdg_clk;
+static struct clk *camio_cam_m_clk;
+static struct clk *camio_camif_pad_pbdg_clk;
+static struct clk *camio_csi_clk;
+static struct clk *camio_csi_pclk;
+static struct clk *camio_csi_vfe_clk;
+static struct clk *camio_jpeg_clk;
+static struct clk *camio_jpeg_pclk;
+static struct clk *camio_vpe_clk;
+static struct vreg *vreg_gp2;
+static struct vreg *vreg_lvsw1;
+static struct vreg *vreg_gp6;
+static struct vreg *vreg_gp16;
+static struct regulator *fs_vfe;
+static struct regulator *fs_vpe;
+static struct msm_camera_io_ext camio_ext;
+static struct msm_camera_io_clk camio_clk;
+static struct resource *camifpadio, *csiio;
+void __iomem *camifpadbase, *csibase;
+static uint32_t vpe_clk_rate;
+
+void msm_io_w(u32 data, void __iomem *addr)
+{
+	CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+	writel_relaxed((data), (addr));
+}
+
+void msm_io_w_mb(u32 data, void __iomem *addr)
+{
+	CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+	wmb();
+	writel_relaxed((data), (addr));
+	wmb();
+}
+
+u32 msm_io_r(void __iomem *addr)
+{
+	uint32_t data = readl_relaxed(addr);
+	CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+	return data;
+}
+
+u32 msm_io_r_mb(void __iomem *addr)
+{
+	uint32_t data;
+	rmb();
+	data = readl_relaxed(addr);
+	rmb();
+	CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+	return data;
+}
+
+void msm_io_memcpy_toio(void __iomem *dest_addr,
+	void __iomem *src_addr, u32 len)
+{
+	int i;
+	u32 *d = (u32 *) dest_addr;
+	u32 *s = (u32 *) src_addr;
+	/* memcpy_toio does not work. Use writel for now */
+	for (i = 0; i < len; i++)
+		writel_relaxed(*s++, d++);
+}
+
+void msm_io_dump(void __iomem *addr, int size)
+{
+	char line_str[128], *p_str;
+	int i;
+	u32 *p = (u32 *) addr;
+	u32 data;
+	CDBG("%s: %p %d\n", __func__, addr, size);
+	line_str[0] = '\0';
+	p_str = line_str;
+	for (i = 0; i < size/4; i++) {
+		if (i % 4 == 0) {
+			sprintf(p_str, "%08x: ", (u32) p);
+			p_str += 10;
+		}
+		data = readl_relaxed(p++);
+		sprintf(p_str, "%08x ", data);
+		p_str += 9;
+		if ((i + 1) % 4 == 0) {
+			CDBG("%s\n", line_str);
+			line_str[0] = '\0';
+			p_str = line_str;
+		}
+	}
+	if (line_str[0] != '\0')
+		CDBG("%s\n", line_str);
+}
+
+void msm_io_memcpy(void __iomem *dest_addr, void __iomem *src_addr, u32 len)
+{
+	CDBG("%s: %p %p %d\n", __func__, dest_addr, src_addr, len);
+	msm_io_memcpy_toio(dest_addr, src_addr, len / 4);
+	msm_io_dump(dest_addr, len);
+}
+
+static void msm_camera_vreg_enable(struct platform_device *pdev)
+{
+	vreg_gp2 = vreg_get(NULL, "gp2");
+	if (IS_ERR(vreg_gp2)) {
+		pr_err("%s: VREG GP2 get failed %ld\n", __func__,
+			PTR_ERR(vreg_gp2));
+		vreg_gp2 = NULL;
+		return;
+	}
+
+	if (vreg_set_level(vreg_gp2, 2600)) {
+		pr_err("%s: VREG GP2 set failed\n", __func__);
+		goto gp2_put;
+	}
+
+	if (vreg_enable(vreg_gp2)) {
+		pr_err("%s: VREG GP2 enable failed\n", __func__);
+		goto gp2_put;
+	}
+
+	vreg_lvsw1 = vreg_get(NULL, "lvsw1");
+	if (IS_ERR(vreg_lvsw1)) {
+		pr_err("%s: VREG LVSW1 get failed %ld\n", __func__,
+			PTR_ERR(vreg_lvsw1));
+		vreg_lvsw1 = NULL;
+		goto gp2_disable;
+		}
+	if (vreg_set_level(vreg_lvsw1, 1800)) {
+		pr_err("%s: VREG LVSW1 set failed\n", __func__);
+		goto lvsw1_put;
+	}
+	if (vreg_enable(vreg_lvsw1)) {
+		pr_err("%s: VREG LVSW1 enable failed\n", __func__);
+		goto lvsw1_put;
+	}
+
+	if (!strcmp(pdev->name, "msm_camera_sn12m0pz")) {
+		vreg_gp6 = vreg_get(NULL, "gp6");
+		if (IS_ERR(vreg_gp6)) {
+			pr_err("%s: VREG GP6 get failed %ld\n", __func__,
+				PTR_ERR(vreg_gp6));
+			vreg_gp6 = NULL;
+			goto lvsw1_disable;
+		}
+
+		if (vreg_set_level(vreg_gp6, 3050)) {
+			pr_err("%s: VREG GP6 set failed\n", __func__);
+			goto gp6_put;
+		}
+
+		if (vreg_enable(vreg_gp6)) {
+			pr_err("%s: VREG GP6 enable failed\n", __func__);
+			goto gp6_put;
+		}
+		vreg_gp16 = vreg_get(NULL, "gp16");
+		if (IS_ERR(vreg_gp16)) {
+			pr_err("%s: VREG GP16 get failed %ld\n", __func__,
+				PTR_ERR(vreg_gp16));
+			vreg_gp16 = NULL;
+			goto gp6_disable;
+		}
+
+		if (vreg_set_level(vreg_gp16, 1200)) {
+			pr_err("%s: VREG GP16 set failed\n", __func__);
+			goto gp16_put;
+		}
+
+		if (vreg_enable(vreg_gp16)) {
+			pr_err("%s: VREG GP16 enable failed\n", __func__);
+			goto gp16_put;
+		}
+	}
+
+	fs_vfe = regulator_get(NULL, "fs_vfe");
+	if (IS_ERR(fs_vfe)) {
+		pr_err("%s: Regulator FS_VFE get failed %ld\n", __func__,
+			PTR_ERR(fs_vfe));
+		fs_vfe = NULL;
+	} else if (regulator_enable(fs_vfe)) {
+		pr_err("%s: Regulator FS_VFE enable failed\n", __func__);
+		regulator_put(fs_vfe);
+	}
+
+	return;
+
+gp16_put:
+	vreg_put(vreg_gp16);
+	vreg_gp16 = NULL;
+gp6_disable:
+	 vreg_disable(vreg_gp6);
+gp6_put:
+	vreg_put(vreg_gp6);
+	vreg_gp6 = NULL;
+lvsw1_disable:
+	vreg_disable(vreg_lvsw1);
+lvsw1_put:
+	vreg_put(vreg_lvsw1);
+	vreg_lvsw1 = NULL;
+gp2_disable:
+	vreg_disable(vreg_gp2);
+gp2_put:
+	vreg_put(vreg_gp2);
+	vreg_gp2 = NULL;
+}
+
+static void msm_camera_vreg_disable(void)
+{
+	if (vreg_gp2) {
+		vreg_disable(vreg_gp2);
+		vreg_put(vreg_gp2);
+		vreg_gp2 = NULL;
+	}
+	if (vreg_lvsw1) {
+		vreg_disable(vreg_lvsw1);
+		vreg_put(vreg_lvsw1);
+		vreg_lvsw1 = NULL;
+	}
+	if (vreg_gp6) {
+		vreg_disable(vreg_gp6);
+		vreg_put(vreg_gp6);
+		vreg_gp6 = NULL;
+	}
+	if (vreg_gp16) {
+		vreg_disable(vreg_gp16);
+		vreg_put(vreg_gp16);
+		vreg_gp16 = NULL;
+	}
+	if (fs_vfe) {
+		regulator_disable(fs_vfe);
+		regulator_put(fs_vfe);
+	}
+}
+
+int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
+{
+	int rc = 0;
+	struct clk *clk = NULL;
+
+	switch (clktype) {
+	case CAMIO_VFE_MDC_CLK:
+		camio_vfe_mdc_clk =
+		clk = clk_get(NULL, "vfe_mdc_clk");
+		break;
+
+	case CAMIO_MDC_CLK:
+		camio_mdc_clk =
+		clk = clk_get(NULL, "mdc_clk");
+		break;
+
+	case CAMIO_VFE_CLK:
+		camio_vfe_clk =
+		clk = clk_get(NULL, "vfe_clk");
+		msm_camio_clk_rate_set_2(clk, camio_clk.vfe_clk_rate);
+		break;
+
+	case CAMIO_VFE_CAMIF_CLK:
+		camio_vfe_camif_clk =
+		clk = clk_get(NULL, "vfe_camif_clk");
+		break;
+
+	case CAMIO_VFE_PBDG_CLK:
+		camio_vfe_pbdg_clk =
+		clk = clk_get(NULL, "vfe_pclk");
+		break;
+
+	case CAMIO_CAM_MCLK_CLK:
+		camio_cam_m_clk =
+		clk = clk_get(NULL, "cam_m_clk");
+		msm_camio_clk_rate_set_2(clk, camio_clk.mclk_clk_rate);
+		break;
+
+	case CAMIO_CAMIF_PAD_PBDG_CLK:
+		camio_camif_pad_pbdg_clk =
+		clk = clk_get(NULL, "camif_pad_pclk");
+		break;
+
+	case CAMIO_CSI0_CLK:
+		camio_csi_clk =
+		clk = clk_get(NULL, "csi_clk");
+		msm_camio_clk_rate_set_2(clk, 153600000);
+		break;
+	case CAMIO_CSI0_VFE_CLK:
+		camio_csi_vfe_clk =
+		clk = clk_get(NULL, "csi_vfe_clk");
+		break;
+	case CAMIO_CSI0_PCLK:
+		camio_csi_pclk =
+		clk = clk_get(NULL, "csi_pclk");
+		break;
+
+	case CAMIO_JPEG_CLK:
+		camio_jpeg_clk =
+		clk = clk_get(NULL, "jpeg_clk");
+		clk_set_min_rate(clk, 144000000);
+		break;
+	case CAMIO_JPEG_PCLK:
+		camio_jpeg_pclk =
+		clk = clk_get(NULL, "jpeg_pclk");
+		break;
+	case CAMIO_VPE_CLK:
+		camio_vpe_clk =
+		clk = clk_get(NULL, "vpe_clk");
+		msm_camio_clk_set_min_rate(clk, vpe_clk_rate);
+		break;
+	default:
+		break;
+	}
+
+	if (!IS_ERR(clk))
+		clk_enable(clk);
+	else
+		rc = -1;
+	return rc;
+}
+
+int msm_camio_clk_disable(enum msm_camio_clk_type clktype)
+{
+	int rc = 0;
+	struct clk *clk = NULL;
+
+	switch (clktype) {
+	case CAMIO_VFE_MDC_CLK:
+		clk = camio_vfe_mdc_clk;
+		break;
+
+	case CAMIO_MDC_CLK:
+		clk = camio_mdc_clk;
+		break;
+
+	case CAMIO_VFE_CLK:
+		clk = camio_vfe_clk;
+		break;
+
+	case CAMIO_VFE_CAMIF_CLK:
+		clk = camio_vfe_camif_clk;
+		break;
+
+	case CAMIO_VFE_PBDG_CLK:
+		clk = camio_vfe_pbdg_clk;
+		break;
+
+	case CAMIO_CAM_MCLK_CLK:
+		clk = camio_cam_m_clk;
+		break;
+
+	case CAMIO_CAMIF_PAD_PBDG_CLK:
+		clk = camio_camif_pad_pbdg_clk;
+		break;
+	case CAMIO_CSI0_CLK:
+		clk = camio_csi_clk;
+		break;
+	case CAMIO_CSI0_VFE_CLK:
+		clk = camio_csi_vfe_clk;
+		break;
+	case CAMIO_CSI0_PCLK:
+		clk = camio_csi_pclk;
+		break;
+	case CAMIO_JPEG_CLK:
+		clk = camio_jpeg_clk;
+		break;
+	case CAMIO_JPEG_PCLK:
+		clk = camio_jpeg_pclk;
+		break;
+	case CAMIO_VPE_CLK:
+		clk = camio_vpe_clk;
+		break;
+	default:
+		break;
+	}
+
+	if (!IS_ERR(clk)) {
+		clk_disable(clk);
+		clk_put(clk);
+	} else
+		rc = -1;
+
+	return rc;
+}
+
+void msm_camio_clk_rate_set(int rate)
+{
+	struct clk *clk = camio_cam_m_clk;
+	clk_set_rate(clk, rate);
+}
+
+void msm_camio_vfe_clk_rate_set(int rate)
+{
+	struct clk *clk = camio_vfe_clk;
+	clk_set_rate(clk, rate);
+}
+
+void msm_camio_clk_rate_set_2(struct clk *clk, int rate)
+{
+	clk_set_rate(clk, rate);
+}
+
+void msm_camio_clk_set_min_rate(struct clk *clk, int rate)
+{
+	clk_set_min_rate(clk, rate);
+}
+
+static irqreturn_t msm_io_csi_irq(int irq_num, void *data)
+{
+	uint32_t irq;
+	irq = msm_io_r(csibase + MIPI_INTERRUPT_STATUS);
+	CDBG("%s MIPI_INTERRUPT_STATUS = 0x%x\n", __func__, irq);
+	msm_io_w(irq, csibase + MIPI_INTERRUPT_STATUS);
+	return IRQ_HANDLED;
+}
+
+int msm_camio_jpeg_clk_disable(void)
+{
+	msm_camio_clk_disable(CAMIO_JPEG_CLK);
+	msm_camio_clk_disable(CAMIO_JPEG_PCLK);
+	/* Need to add the code for remove PM QOS requirement */
+	return 0;
+}
+
+
+int msm_camio_jpeg_clk_enable(void)
+{
+	msm_camio_clk_enable(CAMIO_JPEG_CLK);
+	msm_camio_clk_enable(CAMIO_JPEG_PCLK);
+	return 0;
+}
+
+int msm_camio_vpe_clk_disable(void)
+{
+	msm_camio_clk_disable(CAMIO_VPE_CLK);
+
+	if (fs_vpe) {
+		regulator_disable(fs_vpe);
+		regulator_put(fs_vpe);
+	}
+
+	return 0;
+}
+
+int msm_camio_vpe_clk_enable(uint32_t clk_rate)
+{
+	fs_vpe = regulator_get(NULL, "fs_vpe");
+	if (IS_ERR(fs_vpe)) {
+		pr_err("%s: Regulator FS_VPE get failed %ld\n", __func__,
+			PTR_ERR(fs_vpe));
+		fs_vpe = NULL;
+	} else if (regulator_enable(fs_vpe)) {
+		pr_err("%s: Regulator FS_VPE enable failed\n", __func__);
+		regulator_put(fs_vpe);
+	}
+
+	vpe_clk_rate = clk_rate;
+	msm_camio_clk_enable(CAMIO_VPE_CLK);
+	return 0;
+}
+
+int msm_camio_enable(struct platform_device *pdev)
+{
+	int rc = 0;
+	uint32_t val;
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	msm_camio_clk_enable(CAMIO_VFE_PBDG_CLK);
+	if (!sinfo->csi_if)
+		msm_camio_clk_enable(CAMIO_VFE_CAMIF_CLK);
+	else {
+		msm_camio_clk_enable(CAMIO_VFE_CLK);
+		csiio = request_mem_region(camio_ext.csiphy,
+			camio_ext.csisz, pdev->name);
+		if (!csiio) {
+			rc = -EBUSY;
+			goto common_fail;
+		}
+		csibase = ioremap(camio_ext.csiphy,
+			camio_ext.csisz);
+		if (!csibase) {
+			rc = -ENOMEM;
+			goto csi_busy;
+		}
+		rc = request_irq(camio_ext.csiirq, msm_io_csi_irq,
+			IRQF_TRIGGER_RISING, "csi", 0);
+		if (rc < 0)
+			goto csi_irq_fail;
+		/* enable required clocks for CSI */
+		msm_camio_clk_enable(CAMIO_CSI0_PCLK);
+		msm_camio_clk_enable(CAMIO_CSI0_VFE_CLK);
+		msm_camio_clk_enable(CAMIO_CSI0_CLK);
+
+		msleep(10);
+		val = (20 <<
+			MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) |
+			(0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) |
+			(0x0 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) |
+			(0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT);
+		CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
+		msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2);
+		msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL2);
+		msm_io_w(val, csibase + MIPI_PHY_D2_CONTROL2);
+		msm_io_w(val, csibase + MIPI_PHY_D3_CONTROL2);
+
+		val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) |
+			(0x0 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT);
+		CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
+		msm_io_w(val, csibase + MIPI_PHY_CL_CONTROL);
+	}
+	return 0;
+csi_irq_fail:
+	iounmap(csibase);
+csi_busy:
+	release_mem_region(camio_ext.csiphy, camio_ext.csisz);
+common_fail:
+	msm_camio_clk_disable(CAMIO_VFE_PBDG_CLK);
+	msm_camio_clk_disable(CAMIO_VFE_CLK);
+	return rc;
+}
+
+void msm_camio_disable(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	uint32_t val;
+	if (!sinfo->csi_if) {
+		msm_camio_clk_disable(CAMIO_VFE_CAMIF_CLK);
+	} else {
+		val = (0x0 << MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT) |
+		(0x0<<MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT)|
+		(0x0 << MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT) |
+		(0x0 << MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT);
+		CDBG("%s MIPI_CALIBRATION_CONTROL val=0x%x\n", __func__, val);
+		msm_io_w(val, csibase + MIPI_CALIBRATION_CONTROL);
+
+		val = (20 <<
+			MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) |
+			(0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) |
+			(0x0 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) |
+			(0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT);
+		CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
+		msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2);
+		msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL2);
+		msm_io_w(val, csibase + MIPI_PHY_D2_CONTROL2);
+		msm_io_w(val, csibase + MIPI_PHY_D3_CONTROL2);
+		val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) |
+			(0x0 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT);
+		CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
+		msm_io_w(val, csibase + MIPI_PHY_CL_CONTROL);
+		msleep(10);
+		free_irq(camio_ext.csiirq, 0);
+		msm_camio_clk_disable(CAMIO_CSI0_PCLK);
+		msm_camio_clk_disable(CAMIO_CSI0_VFE_CLK);
+		msm_camio_clk_disable(CAMIO_CSI0_CLK);
+		msm_camio_clk_disable(CAMIO_VFE_CLK);
+		iounmap(csibase);
+		release_mem_region(camio_ext.csiphy, camio_ext.csisz);
+	}
+	msm_camio_clk_disable(CAMIO_VFE_PBDG_CLK);
+}
+
+void msm_camio_camif_pad_reg_reset(void)
+{
+	uint32_t reg;
+
+	msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_INTERNAL);
+	msleep(10);
+
+	reg = (msm_io_r(camifpadbase)) & CAMIF_CFG_RMSK;
+	reg |= 0x3;
+	msm_io_w(reg, camifpadbase);
+	msleep(10);
+
+	reg = (msm_io_r(camifpadbase)) & CAMIF_CFG_RMSK;
+	reg |= 0x10;
+	msm_io_w(reg, camifpadbase);
+	msleep(10);
+
+	reg = (msm_io_r(camifpadbase)) & CAMIF_CFG_RMSK;
+	/* Need to be uninverted*/
+	reg &= 0x03;
+	msm_io_w(reg, camifpadbase);
+	msleep(10);
+}
+
+void msm_camio_vfe_blk_reset(void)
+{
+	return;
+
+
+}
+
+void msm_camio_camif_pad_reg_reset_2(void)
+{
+	uint32_t reg;
+	uint32_t mask, value;
+	reg = (msm_io_r(camifpadbase)) & CAMIF_CFG_RMSK;
+	mask = CAM_PAD_REG_SW_RESET_BMSK;
+	value = 1 << CAM_PAD_REG_SW_RESET_SHFT;
+	msm_io_w((reg & (~mask)) | (value & mask), camifpadbase);
+	mdelay(10);
+	reg = (msm_io_r(camifpadbase)) & CAMIF_CFG_RMSK;
+	mask = CAM_PAD_REG_SW_RESET_BMSK;
+	value = 0 << CAM_PAD_REG_SW_RESET_SHFT;
+	msm_io_w((reg & (~mask)) | (value & mask), camifpadbase);
+	mdelay(10);
+}
+
+void msm_camio_clk_sel(enum msm_camio_clk_src_type srctype)
+{
+	struct clk *clk = NULL;
+
+	clk = camio_vfe_clk;
+
+	if (clk != NULL) {
+		switch (srctype) {
+		case MSM_CAMIO_CLK_SRC_INTERNAL:
+			clk_set_flags(clk, 0x00000100 << 1);
+			break;
+
+		case MSM_CAMIO_CLK_SRC_EXTERNAL:
+			clk_set_flags(clk, 0x00000100);
+			break;
+
+		default:
+			break;
+		}
+	}
+}
+int msm_camio_probe_on(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	camio_clk = camdev->ioclk;
+	camio_ext = camdev->ioext;
+	camdev->camera_gpio_on();
+	msm_camera_vreg_enable(pdev);
+	return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
+}
+
+int msm_camio_probe_off(struct platform_device *pdev)
+{
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	msm_camera_vreg_disable();
+	camdev->camera_gpio_off();
+	return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
+}
+
+int msm_camio_sensor_clk_on(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	camio_clk = camdev->ioclk;
+	camio_ext = camdev->ioext;
+	camdev->camera_gpio_on();
+	msm_camera_vreg_enable(pdev);
+	msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
+	msm_camio_clk_enable(CAMIO_CAMIF_PAD_PBDG_CLK);
+	if (!sinfo->csi_if) {
+		camifpadio = request_mem_region(camio_ext.camifpadphy,
+			camio_ext.camifpadsz, pdev->name);
+		msm_camio_clk_enable(CAMIO_VFE_CLK);
+		if (!camifpadio) {
+			rc = -EBUSY;
+			goto common_fail;
+		}
+		camifpadbase = ioremap(camio_ext.camifpadphy,
+			camio_ext.camifpadsz);
+		if (!camifpadbase) {
+			CDBG("msm_camio_sensor_clk_on fail\n");
+			rc = -ENOMEM;
+			goto parallel_busy;
+		}
+	}
+	return rc;
+parallel_busy:
+	release_mem_region(camio_ext.camifpadphy, camio_ext.camifpadsz);
+	goto common_fail;
+common_fail:
+	msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
+	msm_camio_clk_disable(CAMIO_VFE_CLK);
+	msm_camio_clk_disable(CAMIO_CAMIF_PAD_PBDG_CLK);
+	msm_camera_vreg_disable();
+	camdev->camera_gpio_off();
+	return rc;
+}
+
+int msm_camio_sensor_clk_off(struct platform_device *pdev)
+{
+	uint32_t rc = 0;
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	camdev->camera_gpio_off();
+	msm_camera_vreg_disable();
+	rc = msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
+	rc = msm_camio_clk_disable(CAMIO_CAMIF_PAD_PBDG_CLK);
+	if (!sinfo->csi_if) {
+		iounmap(camifpadbase);
+		release_mem_region(camio_ext.camifpadphy, camio_ext.camifpadsz);
+		rc = msm_camio_clk_disable(CAMIO_VFE_CLK);
+	}
+	return rc;
+}
+
+int msm_camio_csi_config(struct msm_camera_csi_params *csi_params)
+{
+	int rc = 0;
+	uint32_t val = 0;
+
+	CDBG("msm_camio_csi_config \n");
+
+	/* SOT_ECC_EN enable error correction for SYNC (data-lane) */
+	msm_io_w(0x4, csibase + MIPI_PHY_CONTROL);
+
+	/* SW_RST to the CSI core */
+	msm_io_w(MIPI_PROTOCOL_CONTROL_SW_RST_BMSK,
+		csibase + MIPI_PROTOCOL_CONTROL);
+
+	/* PROTOCOL CONTROL */
+	val = MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK |
+		MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK |
+		MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK;
+	val |= (uint32_t)(csi_params->data_format) <<
+		MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT;
+	val |= csi_params->dpcm_scheme <<
+		MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT;
+	CDBG("%s MIPI_PROTOCOL_CONTROL val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_PROTOCOL_CONTROL);
+
+	/* SW CAL EN */
+	val = (0x1 << MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT) |
+		(0x1 <<
+		MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT) |
+		(0x1 << MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT) |
+		(0x1 << MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT);
+	CDBG("%s MIPI_CALIBRATION_CONTROL val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_CALIBRATION_CONTROL);
+
+	/* settle_cnt is very sensitive to speed!
+	increase this value to run at higher speeds */
+	val = (csi_params->settle_cnt <<
+			MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) |
+		(0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) |
+		(0x1 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) |
+		(0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT);
+	CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D2_CONTROL2);
+	msm_io_w(val, csibase + MIPI_PHY_D3_CONTROL2);
+
+
+	val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) |
+		(0x1 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT);
+	CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_PHY_CL_CONTROL);
+
+	val = 0 << MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT;
+	msm_io_w(val, csibase + MIPI_PHY_D0_CONTROL);
+
+	val = (0x1 << MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT) |
+		(0x1 << MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT);
+	CDBG("%s MIPI_PHY_D1_CONTROL val=0x%x\n", __func__, val);
+	msm_io_w(val, csibase + MIPI_PHY_D1_CONTROL);
+
+	msm_io_w(0x00000000, csibase + MIPI_PHY_D2_CONTROL);
+	msm_io_w(0x00000000, csibase + MIPI_PHY_D3_CONTROL);
+
+	/* halcyon only supports 1 or 2 lane */
+	switch (csi_params->lane_cnt) {
+	case 1:
+		msm_io_w(csi_params->lane_assign << 8 | 0x4,
+			csibase + MIPI_CAMERA_CNTL);
+		break;
+	case 2:
+		msm_io_w(csi_params->lane_assign << 8 | 0x5,
+			csibase + MIPI_CAMERA_CNTL);
+		break;
+	case 3:
+		msm_io_w(csi_params->lane_assign << 8 | 0x6,
+			csibase + MIPI_CAMERA_CNTL);
+		break;
+	case 4:
+		msm_io_w(csi_params->lane_assign << 8 | 0x7,
+			csibase + MIPI_CAMERA_CNTL);
+		break;
+	}
+
+	/* mask out ID_ERROR[19], DATA_CMM_ERR[11]
+	and CLK_CMM_ERR[10] - de-featured */
+	msm_io_w(0xFFF7F3FF, csibase + MIPI_INTERRUPT_MASK);
+	/*clear IRQ bits*/
+	msm_io_w(0xFFF7F3FF, csibase + MIPI_INTERRUPT_STATUS);
+
+	return rc;
+}
+void msm_camio_set_perf_lvl(enum msm_bus_perf_setting perf_setting)
+{
+	switch (perf_setting) {
+	case S_INIT:
+		add_axi_qos();
+		break;
+	case S_PREVIEW:
+		update_axi_qos(MSM_AXI_QOS_PREVIEW);
+		break;
+	case S_VIDEO:
+		update_axi_qos(MSM_AXI_QOS_RECORDING);
+		break;
+	case S_CAPTURE:
+		update_axi_qos(MSM_AXI_QOS_SNAPSHOT);
+		break;
+	case S_DEFAULT:
+		update_axi_qos(PM_QOS_DEFAULT_VALUE);
+		break;
+	case S_EXIT:
+		release_axi_qos();
+		break;
+	default:
+		CDBG("%s: INVALID CASE\n", __func__);
+	}
+}
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
new file mode 100644
index 0000000..480c626
--- /dev/null
+++ b/drivers/media/video/msm/msm_isp.c
@@ -0,0 +1,814 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+#include <linux/android_pmem.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+
+#include "msm.h"
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+#define D(fmt, args...) pr_debug("msm_isp: " fmt, ##args)
+#else
+#define D(fmt, args...) do {} while (0)
+#endif
+#define ERR_USER_COPY(to) pr_err("%s(%d): copy %s user\n", \
+				__func__, __LINE__, ((to) ? "to" : "from"))
+#define ERR_COPY_FROM_USER() ERR_USER_COPY(0)
+#define ERR_COPY_TO_USER() ERR_USER_COPY(1)
+
+#define MSM_FRAME_AXI_MAX_BUF 16
+/* This will enqueue ISP events or signal buffer completion */
+static int msm_isp_enqueue(struct msm_cam_media_controller *pmctl,
+				struct msm_vfe_resp *data,
+				enum msm_queue qtype)
+{
+	struct v4l2_event v4l2_evt;
+
+	struct msm_stats_buf stats;
+	struct msm_isp_stats_event_ctrl *isp_event;
+	isp_event = (struct msm_isp_stats_event_ctrl *)v4l2_evt.u.data;
+	if (!data) {
+		pr_err("%s !!!!data = 0x%p\n", __func__, data);
+		return -EINVAL;
+	}
+
+	D("%s data->type = %d\n", __func__, data->type);
+
+	switch (qtype) {
+	case MSM_CAM_Q_VFE_EVT:
+	case MSM_CAM_Q_VFE_MSG:
+		/* adsp event and message */
+		v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
+					MSM_CAM_RESP_STAT_EVT_MSG;
+
+		isp_event->resptype = MSM_CAM_RESP_STAT_EVT_MSG;
+
+		/* 0 - msg from aDSP, 1 - event from mARM */
+		isp_event->isp_data.isp_msg.type   = data->evt_msg.type;
+		isp_event->isp_data.isp_msg.msg_id = data->evt_msg.msg_id;
+		isp_event->isp_data.isp_msg.len	= 0;
+
+		D("%s: qtype %d length %d msd_id %d\n", __func__,
+					qtype,
+					isp_event->isp_data.isp_msg.len,
+					isp_event->isp_data.isp_msg.msg_id);
+
+		if ((data->type >= VFE_MSG_STATS_AEC) &&
+			(data->type <=  VFE_MSG_STATS_WE)) {
+
+			D("%s data->phy.sbuf_phy = 0x%x\n", __func__,
+						data->phy.sbuf_phy);
+			stats.buffer = msm_pmem_stats_ptov_lookup(&pmctl->sync,
+							data->phy.sbuf_phy,
+							&(stats.fd));
+			if (!stats.buffer) {
+				pr_err("%s: msm_pmem_stats_ptov_lookup error\n",
+								__func__);
+				isp_event->isp_data.isp_msg.len = 0;
+			} else {
+				struct msm_stats_buf *stats_buf =
+					kmalloc(sizeof(struct msm_stats_buf),
+								GFP_ATOMIC);
+				if (!stats_buf) {
+					pr_err("%s: out of memory.\n",
+								__func__);
+					return -ENOMEM;
+				}
+
+				*stats_buf = stats;
+				isp_event->isp_data.isp_msg.len	=
+						sizeof(struct msm_stats_buf);
+				isp_event->isp_data.isp_msg.data = stats_buf;
+			}
+
+		} else if ((data->evt_msg.len > 0) &&
+				(data->type == VFE_MSG_GENERAL)) {
+			isp_event->isp_data.isp_msg.data =
+					kmalloc(data->evt_msg.len, GFP_ATOMIC);
+			if (!isp_event->isp_data.isp_msg.data) {
+				pr_err("%s: out of memory.\n", __func__);
+				return -ENOMEM;
+			}
+			memcpy(isp_event->isp_data.isp_msg.data,
+						data->evt_msg.data,
+						data->evt_msg.len);
+		} else if (data->type == VFE_MSG_OUTPUT_P ||
+			data->type == VFE_MSG_OUTPUT_V ||
+			data->type == VFE_MSG_OUTPUT_S ||
+			data->type == VFE_MSG_OUTPUT_T) {
+			msm_mctl_buf_done(pmctl, data->type,
+					(u32)data->phy.y_phy);
+		}
+		break;
+	default:
+		break;
+	}
+
+	/* now queue the event */
+	v4l2_event_queue(pmctl->config_device->config_stat_event_queue.pvdev,
+					  &v4l2_evt);
+	return 0;
+}
+
+/*
+ * This function executes in interrupt context.
+ */
+
+void *msm_isp_sync_alloc(int size,
+	  void *syncdata __attribute__((unused)),
+	  gfp_t gfp)
+{
+	struct msm_queue_cmd *qcmd =
+		kmalloc(sizeof(struct msm_queue_cmd) + size, gfp);
+
+	if (qcmd) {
+		atomic_set(&qcmd->on_heap, 1);
+		return qcmd + 1;
+	}
+	return NULL;
+}
+
+void msm_isp_sync_free(void *ptr)
+{
+	if (ptr) {
+		struct msm_queue_cmd *qcmd =
+			(struct msm_queue_cmd *)ptr;
+		qcmd--;
+		if (atomic_read(&qcmd->on_heap))
+			kfree(qcmd);
+	}
+}
+
+/*
+ * This function executes in interrupt context.
+ */
+static int msm_isp_notify(struct v4l2_subdev *sd, void *arg)
+{
+	int rc = -EINVAL;
+	struct msm_queue_cmd *qcmd = NULL;
+	struct msm_sync *sync =
+		(struct msm_sync *)v4l2_get_subdev_hostdata(sd);
+	struct msm_vfe_resp *vdata = (struct msm_vfe_resp *)arg;
+
+	if (!sync) {
+		pr_err("%s: no context in dsp callback.\n", __func__);
+		return rc;
+	}
+
+	qcmd = ((struct msm_queue_cmd *)vdata) - 1;
+	qcmd->type = MSM_CAM_Q_VFE_MSG;
+	qcmd->command = vdata;
+
+	D("%s: vdata->type %d\n", __func__, vdata->type);
+	switch (vdata->type) {
+	case VFE_MSG_STATS_AWB:
+		D("%s: qtype %d, AWB stats, enqueue event_q.\n",
+					__func__, vdata->type);
+		break;
+
+	case VFE_MSG_STATS_AEC:
+		D("%s: qtype %d, AEC stats, enqueue event_q.\n",
+					__func__, vdata->type);
+		break;
+
+	case VFE_MSG_STATS_IHIST:
+		D("%s: qtype %d, ihist stats, enqueue event_q.\n",
+					__func__, vdata->type);
+		break;
+
+	case VFE_MSG_STATS_RS:
+		D("%s: qtype %d, rs stats, enqueue event_q.\n",
+					__func__, vdata->type);
+		break;
+
+	case VFE_MSG_STATS_CS:
+		D("%s: qtype %d, cs stats, enqueue event_q.\n",
+					__func__, vdata->type);
+	break;
+
+	case VFE_MSG_GENERAL:
+		D("%s: qtype %d, general msg, enqueue event_q.\n",
+					__func__, vdata->type);
+		break;
+	default:
+		D("%s: qtype %d not handled\n", __func__, vdata->type);
+		/* fall through, send to config. */
+	}
+
+	D("%s: msm_enqueue event_q\n", __func__);
+	rc = msm_isp_enqueue(&sync->pcam_sync->mctl, vdata, MSM_CAM_Q_VFE_MSG);
+
+	msm_isp_sync_free(vdata);
+
+	return rc;
+}
+
+/* This function is called by open() function, so we need to init HW*/
+static int msm_isp_open(struct v4l2_subdev *sd, struct msm_sync *sync)
+{
+	/* init vfe and senor, register sync callbacks for init*/
+	int rc = 0;
+	D("%s\n", __func__);
+	if (!sync) {
+		pr_err("%s: param is NULL", __func__);
+		return -EINVAL;
+	}
+
+	rc = msm_vfe_subdev_init(sd, sync, sync->pdev);
+	if (rc < 0) {
+		pr_err("%s: vfe_init failed at %d\n",
+					__func__, rc);
+	}
+
+	return rc;
+}
+
+static void msm_isp_release(struct msm_sync *psync)
+{
+	D("%s\n", __func__);
+	msm_vfe_subdev_release(psync->pdev);
+}
+
+static int msm_config_vfe(struct v4l2_subdev *sd,
+		struct msm_sync *sync, void __user *arg)
+{
+	struct msm_vfe_cfg_cmd cfgcmd;
+	struct msm_pmem_region region[8];
+	struct axidata axi_data;
+
+	if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	memset(&axi_data, 0, sizeof(axi_data));
+	CDBG("%s: cmd_type %d\n", __func__, cfgcmd.cmd_type);
+	switch (cfgcmd.cmd_type) {
+	case CMD_STATS_AF_ENABLE:
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+					MSM_PMEM_AF, &region[0],
+					NUM_STAT_OUTPUT_BUFFERS);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+		return msm_isp_subdev_ioctl(sd, &cfgcmd,
+							&axi_data);
+	case CMD_STATS_AEC_ENABLE:
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+			MSM_PMEM_AEC, &region[0],
+			NUM_STAT_OUTPUT_BUFFERS);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+		return msm_isp_subdev_ioctl(sd, &cfgcmd,
+							&axi_data);
+	case CMD_STATS_AWB_ENABLE:
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+			MSM_PMEM_AWB, &region[0],
+			NUM_STAT_OUTPUT_BUFFERS);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+		return msm_isp_subdev_ioctl(sd, &cfgcmd,
+							&axi_data);
+	case CMD_STATS_IHIST_ENABLE:
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+			MSM_PMEM_IHIST, &region[0],
+			NUM_STAT_OUTPUT_BUFFERS);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+		return msm_isp_subdev_ioctl(sd, &cfgcmd,
+							&axi_data);
+	case CMD_STATS_RS_ENABLE:
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+			MSM_PMEM_RS, &region[0],
+			NUM_STAT_OUTPUT_BUFFERS);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+		return msm_isp_subdev_ioctl(sd, &cfgcmd,
+							&axi_data);
+	case CMD_STATS_CS_ENABLE:
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+			MSM_PMEM_CS, &region[0],
+			NUM_STAT_OUTPUT_BUFFERS);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+		return msm_isp_subdev_ioctl(sd, &cfgcmd,
+							&axi_data);
+	case CMD_GENERAL:
+	case CMD_STATS_DISABLE:
+		return msm_isp_subdev_ioctl(sd, &cfgcmd,
+							&axi_data);
+	default:
+		pr_err("%s: unknown command type %d\n",
+			__func__, cfgcmd.cmd_type);
+	}
+
+	return -EINVAL;
+}
+
+static int msm_vpe_frame_cfg(struct msm_sync *sync,
+				void *cfgcmdin)
+{
+	int rc = -EIO;
+	struct axidata axi_data;
+	void *data = &axi_data;
+	struct msm_pmem_region region[8];
+	int pmem_type;
+
+	struct msm_vpe_cfg_cmd *cfgcmd;
+	cfgcmd = (struct msm_vpe_cfg_cmd *)cfgcmdin;
+
+	memset(&axi_data, 0, sizeof(axi_data));
+	CDBG("In vpe_frame_cfg cfgcmd->cmd_type = %d\n",
+		cfgcmd->cmd_type);
+	switch (cfgcmd->cmd_type) {
+	case CMD_AXI_CFG_VPE:
+		pmem_type = MSM_PMEM_VIDEO_VPE;
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup_2(&sync->pmem_frames, pmem_type,
+								&region[0], 8);
+		CDBG("axi_data.bufnum1 = %d\n", axi_data.bufnum1);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		pmem_type = MSM_PMEM_VIDEO;
+		break;
+	default:
+		pr_err("%s: unknown command type %d\n",
+			__func__, cfgcmd->cmd_type);
+		break;
+	}
+	axi_data.region = &region[0];
+	CDBG("out vpe_frame_cfg cfgcmd->cmd_type = %d\n",
+		cfgcmd->cmd_type);
+	/* send the AXI configuration command to driver */
+	if (sync->vpefn.vpe_config)
+		rc = sync->vpefn.vpe_config(cfgcmd, data);
+	return rc;
+}
+
+static int msm_stats_axi_cfg(struct v4l2_subdev *sd,
+		struct msm_sync *sync, struct msm_vfe_cfg_cmd *cfgcmd)
+{
+	int rc = -EIO;
+	struct axidata axi_data;
+	void *data = &axi_data;
+	struct msm_pmem_region region[3];
+	int pmem_type = MSM_PMEM_MAX;
+
+	memset(&axi_data, 0, sizeof(axi_data));
+
+	switch (cfgcmd->cmd_type) {
+	case CMD_STATS_AXI_CFG:
+		pmem_type = MSM_PMEM_AEC_AWB;
+		break;
+	case CMD_STATS_AF_AXI_CFG:
+		pmem_type = MSM_PMEM_AF;
+		break;
+	case CMD_GENERAL:
+		data = NULL;
+		break;
+	default:
+		pr_err("%s: unknown command type %d\n",
+			__func__, cfgcmd->cmd_type);
+		return -EINVAL;
+	}
+
+	if (cfgcmd->cmd_type != CMD_GENERAL) {
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats, pmem_type,
+				&region[0], NUM_STAT_OUTPUT_BUFFERS);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+	}
+
+	/* send the AEC/AWB STATS configuration command to driver */
+	rc = msm_isp_subdev_ioctl(sd, cfgcmd, data);
+	return rc;
+}
+
+static int msm_frame_axi_cfg(struct v4l2_subdev *sd,
+	struct msm_sync *sync, struct msm_vfe_cfg_cmd *cfgcmd)
+{
+	int rc = -EIO;
+	struct axidata axi_data;
+	void *data = &axi_data;
+	struct msm_pmem_region region[MSM_FRAME_AXI_MAX_BUF];
+	int pmem_type;
+	int i = 0;
+	int idx = 0;
+	struct msm_cam_v4l2_device *pcam = sync->pcam_sync;
+	struct msm_cam_v4l2_dev_inst *pcam_inst;
+
+	memset(&axi_data, 0, sizeof(axi_data));
+
+	switch (cfgcmd->cmd_type) {
+
+	case CMD_AXI_CFG_PREVIEW:
+		pcam_inst =
+		pcam->dev_inst_map[MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW];
+		if (pcam_inst)
+			idx = pcam_inst->my_index;
+		else
+			return rc;
+		pmem_type = MSM_PMEM_PREVIEW;
+		axi_data.bufnum2 =
+			msm_pmem_region_lookup_3(sync->pcam_sync, idx,
+				&region[0], pmem_type);
+		if (!axi_data.bufnum2) {
+			pr_err("%s %d: pmem region 3 lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		D("%s __func__ axi_data.bufnum2 = %d\n", __func__,
+						axi_data.bufnum2);
+		break;
+
+	case CMD_AXI_CFG_VIDEO:
+		pcam_inst =
+		pcam->dev_inst_map[MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW];
+		if (pcam_inst)
+			idx = pcam_inst->my_index;
+		else
+			return rc;
+		pmem_type = MSM_PMEM_PREVIEW;
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup_3(sync->pcam_sync, idx,
+				&region[0], pmem_type);
+		D("%s bufnum1 = %d\n", __func__, axi_data.bufnum1);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+
+		pcam_inst
+		= pcam->dev_inst_map[MSM_V4L2_EXT_CAPTURE_MODE_VIDEO];
+		if (pcam_inst)
+			idx = pcam_inst->my_index;
+			pmem_type = MSM_PMEM_VIDEO;
+			axi_data.bufnum2 =
+			msm_pmem_region_lookup_3(sync->pcam_sync, idx,
+				&region[axi_data.bufnum1], pmem_type);
+		D("%s bufnum2 = %d\n", __func__, axi_data.bufnum2);
+		if (!axi_data.bufnum2) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		break;
+
+
+	case CMD_AXI_CFG_SNAP:
+		pcam_inst
+		= pcam->dev_inst_map[MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL];
+		if (pcam_inst)
+			idx = pcam_inst->my_index;
+		else
+			return rc;
+		pmem_type = MSM_PMEM_THUMBNAIL;
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup_3(sync->pcam_sync, idx,
+				&region[0], pmem_type);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+
+		pcam_inst
+		= pcam->dev_inst_map[MSM_V4L2_EXT_CAPTURE_MODE_MAIN];
+		if (pcam_inst)
+			idx = pcam_inst->my_index;
+		else
+			return rc;
+		pmem_type = MSM_PMEM_MAINIMG;
+		axi_data.bufnum2 =
+		msm_pmem_region_lookup_3(sync->pcam_sync, idx,
+				&region[axi_data.bufnum1], pmem_type);
+		if (!axi_data.bufnum2) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		break;
+
+	case CMD_RAW_PICT_AXI_CFG:
+		pcam_inst
+		= pcam->dev_inst_map[MSM_V4L2_EXT_CAPTURE_MODE_MAIN];
+		if (pcam_inst)
+			idx = pcam_inst->my_index;
+		else
+			return rc;
+		pmem_type = MSM_PMEM_RAW_MAINIMG;
+		axi_data.bufnum2 =
+			msm_pmem_region_lookup_3(sync->pcam_sync, idx,
+				&region[0], pmem_type);
+		if (!axi_data.bufnum2) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		break;
+
+	case CMD_GENERAL:
+		data = NULL;
+		break;
+
+	default:
+		pr_err("%s: unknown command type %d\n",
+			__func__, cfgcmd->cmd_type);
+		return -EINVAL;
+	}
+
+	axi_data.region = &region[0];
+	D("%s bufnum1 = %d, bufnum2 = %d\n", __func__,
+	  axi_data.bufnum1, axi_data.bufnum2);
+	for (i = 0; i < MSM_FRAME_AXI_MAX_BUF; i++) {
+		D("%s region %d paddr = 0x%p\n", __func__, i,
+					(void *)region[i].paddr);
+		D("%s region y_off = %d cbcr_off = %d\n", __func__,
+			region[i].info.y_off, region[i].info.cbcr_off);
+	}
+	/* send the AXI configuration command to driver */
+	rc = msm_isp_subdev_ioctl(sd, cfgcmd, data);
+	return rc;
+}
+
+static int msm_axi_config(struct v4l2_subdev *sd,
+			struct msm_sync *sync, void __user *arg)
+{
+	struct msm_vfe_cfg_cmd cfgcmd;
+
+	if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	switch (cfgcmd.cmd_type) {
+	case CMD_AXI_CFG_VIDEO:
+	case CMD_AXI_CFG_PREVIEW:
+	case CMD_AXI_CFG_SNAP:
+	case CMD_RAW_PICT_AXI_CFG:
+		return msm_frame_axi_cfg(sd, sync, &cfgcmd);
+	case CMD_AXI_CFG_VPE:
+		return 0;
+		return msm_vpe_frame_cfg(sync, (void *)&cfgcmd);
+
+	case CMD_STATS_AXI_CFG:
+	case CMD_STATS_AF_AXI_CFG:
+		return msm_stats_axi_cfg(sd, sync, &cfgcmd);
+
+	default:
+		pr_err("%s: unknown command type %d\n",
+			__func__,
+			cfgcmd.cmd_type);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int msm_set_crop(struct msm_sync *sync, void __user *arg)
+{
+	struct crop_info crop;
+
+	if (copy_from_user(&crop,
+				arg,
+				sizeof(struct crop_info))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	if (!sync->croplen) {
+		sync->cropinfo = kmalloc(crop.len, GFP_KERNEL);
+		if (!sync->cropinfo)
+			return -ENOMEM;
+	} else if (sync->croplen < crop.len)
+		return -EINVAL;
+
+	if (copy_from_user(sync->cropinfo,
+				crop.info,
+				crop.len)) {
+		ERR_COPY_FROM_USER();
+		kfree(sync->cropinfo);
+		return -EFAULT;
+	}
+
+	sync->croplen = crop.len;
+
+	return 0;
+}
+
+static int msm_put_stats_buffer(struct v4l2_subdev *sd,
+			struct msm_sync *sync, void __user *arg)
+{
+	int rc = -EIO;
+
+	struct msm_stats_buf buf;
+	unsigned long pphy;
+	struct msm_vfe_cfg_cmd cfgcmd;
+
+	if (copy_from_user(&buf, arg,
+				sizeof(struct msm_stats_buf))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	CDBG("%s\n", __func__);
+	pphy = msm_pmem_stats_vtop_lookup(sync, buf.buffer, buf.fd);
+
+	if (pphy != 0) {
+		if (buf.type == STAT_AF)
+			cfgcmd.cmd_type = CMD_STATS_AF_BUF_RELEASE;
+		else if (buf.type == STAT_AEC)
+			cfgcmd.cmd_type = CMD_STATS_AEC_BUF_RELEASE;
+		else if (buf.type == STAT_AWB)
+			cfgcmd.cmd_type = CMD_STATS_AWB_BUF_RELEASE;
+		else if (buf.type == STAT_IHIST)
+			cfgcmd.cmd_type = CMD_STATS_IHIST_BUF_RELEASE;
+		else if (buf.type == STAT_RS)
+			cfgcmd.cmd_type = CMD_STATS_RS_BUF_RELEASE;
+		else if (buf.type == STAT_CS)
+			cfgcmd.cmd_type = CMD_STATS_CS_BUF_RELEASE;
+
+		else {
+			pr_err("%s: invalid buf type %d\n",
+				__func__,
+				buf.type);
+			rc = -EINVAL;
+			goto put_done;
+		}
+
+		cfgcmd.value = (void *)&buf;
+
+		rc = msm_isp_subdev_ioctl(sd, &cfgcmd, &pphy);
+	} else {
+		pr_err("%s: NULL physical address\n", __func__);
+		rc = -EINVAL;
+	}
+
+put_done:
+	return rc;
+}
+
+/* config function simliar to origanl msm_ioctl_config*/
+static int msm_isp_config(struct msm_cam_media_controller *pmctl,
+			 unsigned int cmd, unsigned long arg)
+{
+
+	int rc = -EINVAL;
+	void __user *argp = (void __user *)arg;
+	struct v4l2_subdev *sd = &pmctl->isp_sdev->sd;
+
+	D("%s: cmd %d\n", __func__, _IOC_NR(cmd));
+	switch (cmd) {
+	case MSM_CAM_IOCTL_PICT_PP_DONE:
+		/* Release the preview of snapshot frame
+		 * that was grabbed.
+		 */
+		/*rc = msm_pp_release(pmsm->sync, arg);*/
+		break;
+
+	case MSM_CAM_IOCTL_CONFIG_VFE:
+		/* Coming from config thread for update */
+		rc = msm_config_vfe(sd, &pmctl->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_CONFIG_VPE:
+		/* Coming from config thread for update */
+		/*rc = msm_config_vpe(pmsm->sync, argp);*/
+		rc = 0;
+		break;
+
+	case MSM_CAM_IOCTL_AXI_CONFIG:
+	case MSM_CAM_IOCTL_AXI_VPE_CONFIG:
+		D("Received MSM_CAM_IOCTL_AXI_CONFIG\n");
+		rc = msm_axi_config(sd, &pmctl->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_SET_CROP:
+		rc = msm_set_crop(&pmctl->sync, argp);
+		break;
+
+	case MSM_CAM_IOCTL_RELEASE_STATS_BUFFER:
+		rc = msm_put_stats_buffer(sd, &pmctl->sync, argp);
+		break;
+
+	default:
+		break;
+	}
+
+	D("%s: cmd %d DONE\n", __func__, _IOC_NR(cmd));
+
+	return rc;
+}
+
+static struct msm_isp_ops isp_subdev[MSM_MAX_CAMERA_CONFIGS];
+
+/**/
+int msm_isp_init_module(int g_num_config_nodes)
+{
+	int i = 0;
+
+	for (i = 0; i < g_num_config_nodes; i++) {
+		isp_subdev[i].isp_open = msm_isp_open;
+		isp_subdev[i].isp_config = msm_isp_config;
+		isp_subdev[i].isp_release  = msm_isp_release;
+		isp_subdev[i].isp_enqueue = msm_isp_enqueue;
+		isp_subdev[i].isp_notify = msm_isp_notify;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(msm_isp_init_module);
+
+/*
+*/
+int msm_isp_register(struct msm_cam_server_dev *psvr)
+{
+	int i = 0;
+
+	D("%s\n", __func__);
+
+	BUG_ON(!psvr);
+
+	/* Initialize notify function for v4l2_dev */
+	for (i = 0; i < psvr->config_info.num_config_nodes; i++)
+		psvr->isp_subdev[i] = &(isp_subdev[i]);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_isp_register);
+
+/**/
+void msm_isp_unregister(struct msm_cam_server_dev *psvr)
+{
+	int i = 0;
+	for (i = 0; i < psvr->config_info.num_config_nodes; i++)
+		psvr->isp_subdev[i] = NULL;
+}
+
+int msm_isp_subdev_ioctl(struct v4l2_subdev *isp_subdev,
+	struct msm_vfe_cfg_cmd *cfgcmd, void *data)
+{
+	struct msm_camvfe_params vfe_params;
+	vfe_params.vfe_cfg = cfgcmd;
+	vfe_params.data = data;
+	return v4l2_subdev_call(isp_subdev, core, ioctl, 0, &vfe_params);
+}
diff --git a/drivers/media/video/msm/msm_ispif.c b/drivers/media/video/msm/msm_ispif.c
new file mode 100644
index 0000000..4611d06
--- /dev/null
+++ b/drivers/media/video/msm/msm_ispif.c
@@ -0,0 +1,397 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/regulator/consumer.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/camera.h>
+#include <mach/vreg.h>
+#include <mach/camera.h>
+#include <mach/clk.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include "msm_ispif.h"
+#include "msm.h"
+
+#define DBG_ISPIF 0
+/* ISPIF registers */
+
+#define ISPIF_RST_CMD_ADDR                        0X00
+#define ISPIF_INTF_CMD_ADDR                       0X04
+#define ISPIF_CTRL_ADDR                           0X08
+#define ISPIF_INPUT_SEL_ADDR                      0X0C
+#define ISPIF_PIX_INTF_CID_MASK_ADDR              0X10
+#define ISPIF_RDI_INTF_CID_MASK_ADDR              0X14
+#define ISPIF_PIX_1_INTF_CID_MASK_ADDR            0X38
+#define ISPIF_RDI_1_INTF_CID_MASK_ADDR            0X3C
+#define ISPIF_PIX_STATUS_ADDR                     0X24
+#define ISPIF_RDI_STATUS_ADDR                     0X28
+#define ISPIF_RDI_1_STATUS_ADDR                   0X64
+#define ISPIF_IRQ_MASK_ADDR                     0X0100
+#define ISPIF_IRQ_CLEAR_ADDR                    0X0104
+#define ISPIF_IRQ_STATUS_ADDR                   0X0108
+#define ISPIF_IRQ_MASK_1_ADDR                   0X010C
+#define ISPIF_IRQ_CLEAR_1_ADDR                  0X0110
+#define ISPIF_IRQ_STATUS_1_ADDR                 0X0114
+
+/*ISPIF RESET BITS*/
+
+#define VFE_CLK_DOMAIN_RST           31
+#define RDI_CLK_DOMAIN_RST           30
+#define PIX_CLK_DOMAIN_RST           29
+#define AHB_CLK_DOMAIN_RST           28
+#define RDI_1_CLK_DOMAIN_RST         27
+#define RDI_1_VFE_RST_STB            13
+#define RDI_1_CSID_RST_STB           12
+#define RDI_VFE_RST_STB              7
+#define RDI_CSID_RST_STB             6
+#define PIX_VFE_RST_STB              4
+#define PIX_CSID_RST_STB             3
+#define SW_REG_RST_STB               2
+#define MISC_LOGIC_RST_STB           1
+#define STROBED_RST_EN               0
+
+#define PIX_INTF_0_OVERFLOW_IRQ      12
+#define RAW_INTF_0_OVERFLOW_IRQ      25
+#define RAW_INTF_1_OVERFLOW_IRQ      25
+#define RESET_DONE_IRQ               27
+
+#define MAX_CID 15
+DEFINE_MUTEX(msm_ispif_mut);
+
+static struct resource *ispif_mem;
+static struct resource *ispif_irq;
+static struct resource *ispifio;
+void __iomem *ispifbase;
+static uint32_t global_intf_cmd_mask = 0xFFFFFFFF;
+#if DBG_ISPIF
+static inline void msm_ispif_read_irq_status(struct ispif_irq_status *out)
+{
+	uint32_t *temp;
+	memset(out, 0, sizeof(struct ispif_irq_status));
+	temp = (uint32_t *)(ispifbase + ISPIF_IRQ_STATUS_ADDR);
+	out->ispifIrqStatus0 = msm_io_r(temp);
+	pr_err("ispif_irq: Irq_status0 = 0x%x\n",
+		out->ispifIrqStatus0);
+	msm_io_w(out->ispifIrqStatus0, ispifbase + ISPIF_IRQ_CLEAR_ADDR);
+}
+
+static irqreturn_t msm_io_ispif_irq(int irq_num, void *data)
+{
+	struct ispif_irq_status irq;
+	msm_ispif_read_irq_status(&irq);
+	return IRQ_HANDLED;
+}
+#endif
+int msm_ispif_init(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_ispif_fns ispif_fns;
+
+	ispif_mem = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, "ispif");
+	if (!ispif_mem) {
+		pr_err("%s: no mem resource?\n", __func__);
+		return -ENODEV;
+	}
+	ispif_irq = platform_get_resource_byname(pdev,
+					IORESOURCE_IRQ, "ispif");
+	if (!ispif_irq) {
+		pr_err("%s: no irq resource?\n", __func__);
+		return -ENODEV;
+	}
+
+	ispifio  = request_mem_region(ispif_mem->start,
+		resource_size(ispif_mem), pdev->name);
+	if (!ispifio)
+		return -EBUSY;
+	ispifbase = ioremap(ispif_mem->start,
+		resource_size(ispif_mem));
+	if (!ispifbase) {
+		rc = -ENOMEM;
+		goto ispif_no_mem;
+	}
+#if DBG_ISPIF
+	rc = request_irq(ispif_irq->start, msm_io_ispif_irq,
+		IRQF_TRIGGER_RISING, "ispif", 0);
+	if (rc < 0)
+		goto ispif_irq_fail;
+#endif
+	global_intf_cmd_mask = 0xFFFFFFFF;
+	ispif_fns.ispif_config = msm_ispif_config;
+	ispif_fns.ispif_start_intf_transfer =
+		msm_ispif_start_intf_transfer;
+	rc = msm_ispif_register(&ispif_fns);
+	if (rc < 0)
+		goto ispif_irq_fail;
+
+	msm_ispif_reset();
+	return 0;
+
+ispif_irq_fail:
+	iounmap(ispifbase);
+ispif_no_mem:
+	release_mem_region(ispif_mem->start, resource_size(ispif_mem));
+	return rc;
+}
+
+void msm_ispif_release(struct platform_device *pdev)
+{
+	CDBG("%s, free_irq\n", __func__);
+#if DBG_ISPIF
+	free_irq(ispif_irq->start, 0);
+#endif
+	iounmap(ispifbase);
+	release_mem_region(ispif_mem->start, resource_size(ispif_mem));
+}
+
+void msm_ispif_intf_reset(uint8_t intftype)
+{
+	uint32_t data = 0x01 , data1 = 0x01;
+
+	msm_io_w(0x1<<STROBED_RST_EN, ispifbase + ISPIF_RST_CMD_ADDR);
+	switch (intftype) {
+	case PIX0:
+		data |= 0x1 << PIX_VFE_RST_STB;
+		msm_io_w(data, ispifbase + ISPIF_RST_CMD_ADDR);
+		usleep_range(11000, 12000);
+		data1 |= 0x1 << PIX_CSID_RST_STB;
+		msm_io_w(data1, ispifbase + ISPIF_RST_CMD_ADDR);
+		usleep_range(11000, 12000);
+		break;
+
+	case RDI0:
+		data |= 0x1 << RDI_VFE_RST_STB;
+		msm_io_w(data, ispifbase + ISPIF_RST_CMD_ADDR);
+		usleep_range(11000, 12000);
+		data1 |= 0x1 << RDI_CSID_RST_STB;
+		msm_io_w(data1, ispifbase + ISPIF_RST_CMD_ADDR);
+		usleep_range(11000, 12000);
+		break;
+
+	case RDI1:
+		data |= 0x1 << RDI_1_VFE_RST_STB;
+		msm_io_w(data, ispifbase + ISPIF_RST_CMD_ADDR);
+		usleep_range(11000, 12000);
+		data1 |= 0x1 << RDI_1_CSID_RST_STB;
+		msm_io_w(data1, ispifbase + ISPIF_RST_CMD_ADDR);
+		usleep_range(11000, 12000);
+		break;
+
+	default:
+		break;
+	}
+}
+
+void msm_ispif_swreg_misc_reset(void)
+{
+	uint32_t data = 0x01, data1 = 0x01;
+
+	data |= 0x1 << SW_REG_RST_STB;
+	msm_io_w(data, ispifbase + ISPIF_RST_CMD_ADDR);
+	usleep_range(11000, 12000);
+	data1 |= 0x1 << MISC_LOGIC_RST_STB;
+	msm_io_w(data1, ispifbase + ISPIF_RST_CMD_ADDR);
+	usleep_range(11000, 12000);
+}
+
+void msm_ispif_reset(void)
+{
+	msm_ispif_swreg_misc_reset();
+	msm_ispif_intf_reset(PIX0);
+	msm_ispif_intf_reset(RDI0);
+}
+
+void msm_ispif_sel_csid_core(uint8_t intftype, uint8_t csid)
+{
+	uint32_t data;
+	data = msm_io_r(ispifbase + ISPIF_INPUT_SEL_ADDR);
+	data |= csid<<(intftype*4);
+	msm_io_w(data, ispifbase + ISPIF_INPUT_SEL_ADDR);
+}
+
+static void
+msm_ispif_intf_cmd(uint8_t intftype, uint16_t cid_mask, uint8_t intf_cmd_mask)
+{
+	uint8_t vc = 0, val = 0;
+	while (cid_mask != 0) {
+		if ((cid_mask & 0xf) != 0x0) {
+			val = (intf_cmd_mask>>(vc*2)) & 0x3;
+			global_intf_cmd_mask &= ~((0x3 & ~val)
+				<<((vc*2)+(intftype*8)));
+			CDBG("intf cmd  0x%x\n", global_intf_cmd_mask);
+			msm_io_w(global_intf_cmd_mask,
+				ispifbase + ISPIF_INTF_CMD_ADDR);
+		}
+		vc++;
+		cid_mask >>= 4;
+	}
+}
+
+void msm_ispif_enable_intf_cids(uint8_t intftype, uint16_t cid_mask)
+{
+	uint32_t data;
+	mutex_lock(&msm_ispif_mut);
+	switch (intftype) {
+	case PIX0:
+		data = msm_io_r(ispifbase + ISPIF_PIX_INTF_CID_MASK_ADDR);
+		data |= cid_mask;
+		msm_io_w(data, ispifbase + ISPIF_PIX_INTF_CID_MASK_ADDR);
+		break;
+
+	case RDI0:
+		data = msm_io_r(ispifbase + ISPIF_RDI_INTF_CID_MASK_ADDR);
+		data |= cid_mask;
+		msm_io_w(data, ispifbase + ISPIF_RDI_INTF_CID_MASK_ADDR);
+		break;
+
+	case RDI1:
+		data = msm_io_r(ispifbase + ISPIF_RDI_1_INTF_CID_MASK_ADDR);
+		data |= cid_mask;
+		msm_io_w(data, ispifbase + ISPIF_RDI_1_INTF_CID_MASK_ADDR);
+		break;
+	}
+	mutex_unlock(&msm_ispif_mut);
+}
+
+int msm_ispif_abort_intf_transfer(struct msm_ispif_params *ispif_params)
+{
+	int rc = 0;
+	uint8_t intf_cmd_mask = 0xAA;
+
+	CDBG("abort stream request\n");
+	mutex_lock(&msm_ispif_mut);
+	msm_ispif_intf_cmd(ispif_params->intftype, ispif_params->cid_mask,
+		 intf_cmd_mask);
+	msm_ispif_intf_reset(ispif_params->intftype);
+	global_intf_cmd_mask |= 0xFF<<(ispif_params->intftype * 8);
+	mutex_unlock(&msm_ispif_mut);
+	return rc;
+}
+
+int msm_ispif_start_intf_transfer(struct msm_ispif_params *ispif_params)
+{
+	uint32_t data;
+	uint8_t intf_cmd_mask = 0x55;
+	int rc = 0;
+
+	CDBG("start stream request\n");
+	mutex_lock(&msm_ispif_mut);
+	switch (ispif_params->intftype) {
+	case PIX0:
+		data = msm_io_r(ispifbase + ISPIF_PIX_STATUS_ADDR);
+		if ((data & 0xf) != 0xf) {
+			CDBG("interface is busy\n");
+			mutex_unlock(&msm_ispif_mut);
+			return -EBUSY;
+		}
+		break;
+
+	case RDI0:
+		data  = msm_io_r(ispifbase + ISPIF_RDI_STATUS_ADDR);
+		break;
+
+	case RDI1:
+		data  = msm_io_r(ispifbase + ISPIF_RDI_1_STATUS_ADDR);
+		break;
+	}
+	msm_ispif_intf_cmd(ispif_params->intftype,
+		ispif_params->cid_mask, intf_cmd_mask);
+	mutex_unlock(&msm_ispif_mut);
+	return rc;
+}
+
+int msm_ispif_stop_intf_transfer(struct msm_ispif_params *ispif_params)
+{
+	int rc = 0;
+	uint8_t intf_cmd_mask = 0x00;
+	CDBG("stop stream request\n");
+	mutex_lock(&msm_ispif_mut);
+	msm_ispif_intf_cmd(ispif_params->intftype,
+		ispif_params->cid_mask, intf_cmd_mask);
+	switch (ispif_params->intftype) {
+	case PIX0:
+		while ((msm_io_r(ispifbase + ISPIF_PIX_STATUS_ADDR) & 0xf)
+			!= 0xf) {
+			CDBG("Wait for Idle\n");
+		}
+		break;
+
+	case RDI0:
+		while ((msm_io_r(ispifbase + ISPIF_RDI_STATUS_ADDR) & 0xf)
+			!= 0xf) {
+			CDBG("Wait for Idle\n");
+		}
+		break;
+	default:
+		break;
+	}
+	global_intf_cmd_mask |= 0xFF<<(ispif_params->intftype * 8);
+	mutex_unlock(&msm_ispif_mut);
+	return rc;
+}
+
+int msm_ispif_config(struct msm_ispif_params *ispif_params, uint8_t num_of_intf)
+{
+	uint32_t data, data1;
+	int rc = 0, i = 0;
+	CDBG("Enable interface\n");
+	data = msm_io_r(ispifbase + ISPIF_PIX_STATUS_ADDR);
+	data1 = msm_io_r(ispifbase + ISPIF_RDI_STATUS_ADDR);
+	if (((data & 0xf) != 0xf) || ((data1 & 0xf) != 0xf))
+		return -EBUSY;
+	msm_io_w(0x00000000, ispifbase + ISPIF_IRQ_MASK_ADDR);
+	for (i = 0; i < num_of_intf; i++) {
+		msm_ispif_sel_csid_core(ispif_params[i].intftype,
+			ispif_params[i].csid);
+		msm_ispif_enable_intf_cids(ispif_params[i].intftype,
+			ispif_params[i].cid_mask);
+	}
+	msm_io_w(0x0BFFFFFF, ispifbase + ISPIF_IRQ_MASK_ADDR);
+	msm_io_w(0x0BFFFFFF, ispifbase + ISPIF_IRQ_CLEAR_ADDR);
+	return rc;
+}
+
+void msm_ispif_vfe_get_cid(uint8_t intftype, char *cids, int *num)
+{
+	uint32_t data = 0;
+	int i = 0, j = 0;
+	switch (intftype) {
+	case PIX0:
+		data = msm_io_r(ispifbase +
+			ISPIF_PIX_INTF_CID_MASK_ADDR);
+		break;
+
+	case RDI0:
+		data = msm_io_r(ispifbase +
+			ISPIF_RDI_INTF_CID_MASK_ADDR);
+		break;
+
+	case RDI1:
+		data = msm_io_r(ispifbase +
+			ISPIF_RDI_1_INTF_CID_MASK_ADDR);
+		break;
+
+	default:
+		break;
+	}
+	for (i = 0; i <= MAX_CID; i++) {
+		if ((data & 0x1) == 0x1) {
+			cids[j++] = i;
+			(*num)++;
+		}
+		data >>= 1;
+	}
+}
diff --git a/drivers/media/video/msm/msm_ispif.h b/drivers/media/video/msm/msm_ispif.h
new file mode 100644
index 0000000..e5e0c23
--- /dev/null
+++ b/drivers/media/video/msm/msm_ispif.h
@@ -0,0 +1,49 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef MSM_ISPIF_H
+#define MSM_ISPIF_H
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/regulator/consumer.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/camera.h>
+#include <mach/vreg.h>
+#include <mach/camera.h>
+#include <mach/clk.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+
+
+struct ispif_irq_status {
+	uint32_t ispifIrqStatus0;
+	uint32_t ispifIrqStatus1;
+};
+
+int msm_ispif_init(struct platform_device *pdev);
+void msm_ispif_release(struct platform_device *pdev);
+void msm_ispif_intf_reset(uint8_t intftype);
+void msm_ispif_swreg_misc_reset(void);
+void msm_ispif_reset(void);
+void msm_ispif_sel_csid_core(uint8_t intftype, uint8_t csid);
+void msm_ispif_enable_intf_cids(uint8_t intftype, uint16_t cid_mask);
+int msm_ispif_start_intf_transfer(struct msm_ispif_params *ispif_params);
+int msm_ispif_stop_intf_transfer(struct msm_ispif_params *ispif_params);
+int msm_ispif_abort_intf_transfer(struct msm_ispif_params *ispif_params);
+int msm_ispif_config(struct msm_ispif_params *ispif_params, \
+	uint8_t num_of_intf);
+void msm_ispif_vfe_get_cid(uint8_t intftype, char *cids, int *num);
+
+#endif
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
new file mode 100644
index 0000000..35cb68a
--- /dev/null
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -0,0 +1,838 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+
+#include <linux/android_pmem.h>
+
+#include "msm.h"
+#include "msm_ispif.h"
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+#define D(fmt, args...) pr_debug("msm_mctl: " fmt, ##args)
+#else
+#define D(fmt, args...) do {} while (0)
+#endif
+
+#define MSM_V4L2_SWFI_LATENCY 3
+
+/* VFE required buffer number for streaming */
+static struct msm_isp_color_fmt msm_isp_formats[] = {
+	{
+	.name	   = "NV12YUV",
+	.depth	  = 12,
+	.bitsperpxl = 8,
+	.fourcc	 = V4L2_PIX_FMT_NV12,
+	.pxlcode	= V4L2_MBUS_FMT_YUYV8_2X8, /* YUV sensor */
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	},
+	{
+	.name	   = "NV21YUV",
+	.depth	  = 12,
+	.bitsperpxl = 8,
+	.fourcc	 = V4L2_PIX_FMT_NV21,
+	.pxlcode	= V4L2_MBUS_FMT_YUYV8_2X8, /* YUV sensor */
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	},
+	{
+	.name	   = "NV12BAYER",
+	.depth	  = 8,
+	.bitsperpxl = 8,
+	.fourcc	 = V4L2_PIX_FMT_NV12,
+	.pxlcode	= V4L2_MBUS_FMT_SBGGR10_1X10, /* Bayer sensor */
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	},
+	{
+	.name	   = "NV21BAYER",
+	.depth	  = 8,
+	.bitsperpxl = 8,
+	.fourcc	 = V4L2_PIX_FMT_NV21,
+	.pxlcode	= V4L2_MBUS_FMT_SBGGR10_1X10, /* Bayer sensor */
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	},
+	{
+	.name	   = "RAWBAYER",
+	.depth	  = 10,
+	.bitsperpxl = 10,
+	.fourcc	 = V4L2_PIX_FMT_SBGGR10,
+	.pxlcode	= V4L2_MBUS_FMT_SBGGR10_1X10, /* Bayer sensor */
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	},
+
+};
+/* master controller instance counter
+static atomic_t mctl_instance = ATOMIC_INIT(0);
+*/
+
+static int buffer_size(int width, int height, int pixelformat)
+{
+	int size;
+
+	switch (pixelformat) {
+	case V4L2_PIX_FMT_NV21:
+	case V4L2_PIX_FMT_NV12:
+		size = width * height * 3/2;
+		break;
+	case V4L2_PIX_FMT_SBGGR10:
+	case V4L2_PIX_FMT_SGBRG10:
+	case V4L2_PIX_FMT_SGRBG10:
+	case V4L2_PIX_FMT_SRGGB10:
+		size = width * height;
+		break;
+	default:
+		pr_err("%s: pixelformat %d not supported.\n",
+			__func__, pixelformat);
+		size = -EINVAL;
+	}
+
+	return size;
+}
+/*
+ *  Videobuf operations
+ */
+
+static void free_buffer(struct videobuf_queue *vq,
+			struct msm_frame_buffer *buf)
+{
+	struct videobuf_buffer *vb = &buf->vidbuf;
+
+	BUG_ON(in_interrupt());
+
+	D("%s (vb=0x%p) 0x%08lx %d\n", __func__,
+			vb, vb->baddr, vb->bsize);
+
+	/* This waits until this buffer is out of danger, i.e.,
+	 * until it is no longer in STATE_QUEUED or STATE_ACTIVE */
+	videobuf_waiton(vq, vb, 0, 0);
+	videobuf_pmem_contig_free(vq, vb);
+	vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+/* Setup # of buffers and size of each buffer for the videobuf_queue.
+   This is called when videobuf_reqbufs() is called, so this function
+   should tell how many buffer should be used and how big the size is.
+
+   The caller will allocate the real buffers, either in user space or
+   in kernel */
+static int msm_vidbuf_setup(struct videobuf_queue *vq, unsigned int *count,
+							unsigned int *size)
+{
+	/* get the video device */
+	struct msm_cam_v4l2_dev_inst *pcam_inst = vq->priv_data;
+	struct msm_cam_v4l2_device *pcam = NULL;
+
+	pcam = pcam_inst->pcam;
+
+	D("%s\n", __func__);
+	if (!pcam || !count || !size) {
+		pr_err("%s error : invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	D("%s, inst=0x%x,idx=%d, width = %d\n", __func__,
+		(u32)pcam_inst, pcam_inst->my_index,
+		pcam_inst->vid_fmt.fmt.pix.width);
+	D("%s, inst=0x%x,idx=%d, height = %d\n", __func__,
+		(u32)pcam_inst, pcam_inst->my_index,
+		pcam_inst->vid_fmt.fmt.pix.height);
+	*size = buffer_size(pcam_inst->vid_fmt.fmt.pix.width,
+				pcam_inst->vid_fmt.fmt.pix.height,
+				pcam_inst->vid_fmt.fmt.pix.pixelformat);
+	D("%s:inst=0x%x,idx=%d,count=%d, size=%d\n", __func__,
+		(u32)pcam_inst, pcam_inst->my_index, *count, *size);
+	return 0;
+}
+
+/* Prepare the buffer before it is put into the videobuf_queue for streaming.
+   This is called when videobuf_qbuf() is called, so this function should
+   setup the video buffer to receieve the VFE output. */
+static int msm_vidbuf_prepare(struct videobuf_queue *vq,
+	struct videobuf_buffer *vb, enum v4l2_field field)
+{
+	int rc = 0;
+	/*struct msm_cam_v4l2_device *pcam = vq->priv_data;*/
+	struct msm_cam_v4l2_dev_inst *pcam_inst = NULL;
+	struct msm_cam_v4l2_device *pcam = NULL;
+	struct msm_frame_buffer *buf = NULL;
+
+	D("%s\n", __func__);
+	if (!vb || !vq) {
+		pr_err("%s error : input is NULL\n", __func__);
+		return -EINVAL;
+	}
+	pcam_inst = vq->priv_data;
+	pcam = pcam_inst->pcam;
+	buf = container_of(vb, struct msm_frame_buffer, vidbuf);
+
+	if (!pcam || !buf) {
+		pr_err("%s error : pointer is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	D("%s (vb=0x%p) 0x%08lx %d\n", __func__,
+		vb, vb->baddr, vb->bsize);
+
+	/* by this time vid_fmt should be already set */
+	/* return error if it is not */
+	if ((pcam_inst->vid_fmt.fmt.pix.width == 0) ||
+		(pcam_inst->vid_fmt.fmt.pix.height == 0)) {
+		pr_err("%s error : pcam vid_fmt is not set\n", __func__);
+		return -EINVAL;
+	}
+
+	buf->inuse = 1;
+
+	D("buf->pxlcode=%d, pcam->sensor_pxlcode=%d, vb->width=%d,"
+		"pcam->vid_fmt.fmt.pix.width = %d, vb->height = %d,"
+		"pcam->vid_fmt.fmt.pix.height=%d, vb->field=%d, field=%d\n",
+		buf->pxlcode, pcam_inst->sensor_pxlcode, vb->width,
+		pcam_inst->vid_fmt.fmt.pix.width, vb->height,
+		pcam_inst->vid_fmt.fmt.pix.height, vb->field, field);
+
+	if (buf->pxlcode != pcam_inst->sensor_pxlcode ||
+		vb->width   != pcam_inst->vid_fmt.fmt.pix.width ||
+		vb->height	!= pcam_inst->vid_fmt.fmt.pix.height ||
+		vb->field   != field) {
+		buf->pxlcode  = pcam_inst->sensor_pxlcode;
+		vb->width = pcam_inst->vid_fmt.fmt.pix.width;
+		vb->height  = pcam_inst->vid_fmt.fmt.pix.height;
+		vb->field = field;
+		vb->state = VIDEOBUF_NEEDS_INIT;
+		D("VIDEOBUF_NEEDS_INIT\n");
+	}
+
+	vb->size = buffer_size(pcam_inst->vid_fmt.fmt.pix.width, vb->height,
+				pcam_inst->vid_fmt.fmt.pix.pixelformat);
+
+	D("vb->size=%lu, vb->bsize=%u, vb->baddr=0x%x\n",
+		vb->size, vb->bsize, (uint32_t)vb->baddr);
+
+	if (0 != vb->baddr && vb->bsize < vb->size) {
+		pr_err("Something wrong vb->size=%lu, vb->bsize=%u,\
+					vb->baddr=0x%x\n",
+					vb->size, vb->bsize,
+					(uint32_t)vb->baddr);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	if (vb->state == VIDEOBUF_NEEDS_INIT) {
+		rc = videobuf_iolock(vq, vb, NULL);
+		if (rc)
+			goto fail;
+		D("%s: setting buffer state to prepared\n", __func__);
+		vb->state = VIDEOBUF_PREPARED;
+	}
+
+	buf->inuse = 0;
+
+	/* finally if everything is oK, set the VIDEOBUF_PREPARED state*/
+	if (0 == rc)
+		vb->state = VIDEOBUF_PREPARED;
+	return rc;
+
+fail:
+	free_buffer(vq, buf);
+
+out:
+	buf->inuse = 0;
+	return rc;
+}
+
+/* Called under spin_lock_irqsave(q->irqlock, flags) in videobuf-core.c*/
+static void msm_vidbuf_queue(struct videobuf_queue *vq,
+				struct videobuf_buffer *vb)
+{
+	/*struct msm_cam_v4l2_device *pcam = vq->priv_data;*/
+	struct msm_cam_v4l2_dev_inst *pcam_inst = NULL;
+	struct msm_cam_v4l2_device *pcam = NULL;
+	unsigned long phyaddr = 0;
+	int rc;
+
+	D("%s\n", __func__);
+	if (!vb || !vq) {
+		pr_err("%s error : input is NULL\n", __func__);
+		return ;
+	}
+	pcam_inst = vq->priv_data;
+	pcam = pcam_inst->pcam;
+	if (!pcam) {
+		pr_err("%s error : pcam is NULL\n", __func__);
+		return;
+	}
+	D("%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, vb->baddr, vb->bsize);
+
+
+	vb->state = VIDEOBUF_QUEUED;
+	if (vq->streaming) {
+		struct msm_frame frame;
+		struct msm_vfe_cfg_cmd cfgcmd;
+		/* we are returning a buffer to the queue */
+		struct videobuf_contig_pmem *mem = vb->priv;
+		/* get the physcial address of the buffer */
+		phyaddr = (unsigned long) videobuf_to_pmem_contig(vb);
+
+		D("%s buffer type is %d\n", __func__, mem->buffer_type);
+		frame.path = pcam_inst->path;
+		frame.buffer = 0;
+		frame.y_off = mem->y_off;
+		frame.cbcr_off = mem->cbcr_off;
+
+		/* now release frame to vfe */
+		cfgcmd.cmd_type = CMD_FRAME_BUF_RELEASE;
+		cfgcmd.value    = (void *)&frame;
+		/* yyan: later change to mctl APIs*/
+		rc = msm_isp_subdev_ioctl(&pcam->mctl.isp_sdev->sd,
+			&cfgcmd, &phyaddr);
+	}
+}
+
+/* This will be called when streamingoff is called. */
+static void msm_vidbuf_release(struct videobuf_queue *vq,
+				struct videobuf_buffer *vb)
+{
+	struct msm_cam_v4l2_dev_inst *pcam_inst = vq->priv_data;
+	struct msm_cam_v4l2_device *pcam = pcam_inst->pcam;
+	struct msm_frame_buffer *buf = container_of(vb, struct msm_frame_buffer,
+									vidbuf);
+
+	D("%s\n", __func__);
+	if (!pcam || !vb || !vq) {
+		pr_err("%s error : input is NULL\n", __func__);
+		return ;
+	}
+#ifdef DEBUG
+	D("%s (vb=0x%p) 0x%08lx %d\n", __func__,
+		vb, vb->baddr, vb->bsize);
+
+	switch (vb->state) {
+	case VIDEOBUF_ACTIVE:
+		D("%s (active)\n", __func__);
+		break;
+	case VIDEOBUF_QUEUED:
+		D("%s (queued)\n", __func__);
+		break;
+	case VIDEOBUF_PREPARED:
+		D("%s (prepared)\n", __func__);
+		break;
+	default:
+		D("%s (unknown) state = %d\n", __func__, vb->state);
+		break;
+	}
+#endif
+
+	/* free the buffer */
+	free_buffer(vq, buf);
+}
+
+
+static struct videobuf_queue_ops msm_vidbuf_ops = {
+	.buf_setup  = msm_vidbuf_setup,
+	.buf_prepare  = msm_vidbuf_prepare,
+	.buf_queue  = msm_vidbuf_queue,
+	.buf_release  = msm_vidbuf_release,
+};
+
+
+
+/* prepare a video buffer queue for a vl42 device*/
+static int msm_vidbuf_init(struct msm_cam_v4l2_dev_inst *pcam_inst,
+						   struct videobuf_queue *q)
+{
+	int rc = 0;
+	struct resource *res;
+	struct platform_device *pdev = NULL;
+	struct msm_cam_v4l2_device *pcam = pcam_inst->pcam;
+	D("%s\n", __func__);
+	if (!pcam || !q) {
+		pr_err("%s error : input is NULL\n", __func__);
+		return -EINVAL;
+	} else
+		pdev = pcam->mctl.sync.pdev;
+
+	if (!pdev) {
+		pr_err("%s error : pdev is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (pcam->use_count == 1) {
+		/* first check if we have resources */
+		res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+		if (res) {
+			D("res->start = 0x%x\n", (u32)res->start);
+			D("res->size = 0x%x\n", (u32)resource_size(res));
+			D("res->end = 0x%x\n", (u32)res->end);
+			rc = dma_declare_coherent_memory(&pdev->dev, res->start,
+				res->start,
+				resource_size(res),
+				DMA_MEMORY_MAP |
+				DMA_MEMORY_EXCLUSIVE);
+			if (!rc) {
+				pr_err("%s: Unable to declare coherent memory.\n",
+				 __func__);
+				rc = -ENXIO;
+				return rc;
+			}
+
+			/*pcam->memsize = resource_size(res);*/
+			D("%s: found DMA capable resource\n", __func__);
+		} else {
+			pr_err("%s: no DMA capable resource\n", __func__);
+			return -ENOMEM;
+		}
+	}
+	spin_lock_init(&pcam_inst->vb_irqlock);
+
+	videobuf_queue_pmem_contig_init(q, &msm_vidbuf_ops, &pdev->dev,
+		&pcam_inst->vb_irqlock,
+		V4L2_BUF_TYPE_VIDEO_CAPTURE,
+		V4L2_FIELD_NONE,
+		sizeof(struct msm_frame_buffer), pcam_inst, NULL);
+
+
+	return 0;
+}
+
+/*
+ *  V4l2 subdevice operations
+ */
+static	int mctl_subdev_log_status(struct v4l2_subdev *sd)
+{
+	return -EINVAL;
+}
+
+static long mctl_subdev_ioctl(struct v4l2_subdev *sd,
+				 unsigned int cmd, void *arg)
+{
+	struct msm_cam_media_controller *pmctl = NULL;
+	if (!sd) {
+		pr_err("%s: param is NULL", __func__);
+		return -EINVAL;
+	} else
+		pmctl = (struct msm_cam_media_controller *)
+		v4l2_get_subdevdata(sd);
+
+
+	return -EINVAL;
+}
+
+
+static int mctl_subdev_g_mbus_fmt(struct v4l2_subdev *sd,
+					 struct v4l2_mbus_framefmt *mf)
+{
+	return -EINVAL;
+}
+
+static struct v4l2_subdev_core_ops mctl_subdev_core_ops = {
+	.log_status = mctl_subdev_log_status,
+	.ioctl = mctl_subdev_ioctl,
+};
+
+static struct v4l2_subdev_video_ops mctl_subdev_video_ops = {
+	.g_mbus_fmt = mctl_subdev_g_mbus_fmt,
+};
+
+static struct v4l2_subdev_ops mctl_subdev_ops = {
+	.core = &mctl_subdev_core_ops,
+	.video  = &mctl_subdev_video_ops,
+};
+
+static int msm_get_sensor_info(struct msm_sync *sync, void __user *arg)
+{
+	int rc = 0;
+	struct msm_camsensor_info info;
+	struct msm_camera_sensor_info *sdata;
+
+	if (copy_from_user(&info,
+			arg,
+			sizeof(struct msm_camsensor_info))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	sdata = sync->pdev->dev.platform_data;
+	D("%s: sensor_name %s\n", __func__, sdata->sensor_name);
+
+	memcpy(&info.name[0], sdata->sensor_name, MAX_SENSOR_NAME);
+	info.flash_enabled = sdata->flash_data->flash_type !=
+					MSM_CAMERA_FLASH_NONE;
+
+	/* copy back to user space */
+	if (copy_to_user((void *)arg,
+				&info,
+				sizeof(struct msm_camsensor_info))) {
+		ERR_COPY_TO_USER();
+		rc = -EFAULT;
+	}
+
+	return rc;
+}
+
+/* called by other subdev to notify any changes*/
+
+static int msm_mctl_notify(struct msm_cam_media_controller *p_mctl,
+			unsigned int notification, void *arg)
+{
+	int rc = -EINVAL;
+	struct msm_ispif_params ispif_params;
+	struct msm_camera_sensor_info *sinfo =
+			p_mctl->plat_dev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	uint8_t csid_core = camdev->csid_core;
+	switch (notification) {
+	case NOTIFY_CID_CHANGE:
+		/* reconfig the ISPIF*/
+		if (p_mctl->ispif_fns->ispif_config) {
+			ispif_params.intftype = PIX0;
+			ispif_params.cid_mask = 0x0001;
+			ispif_params.csid = csid_core;
+
+			rc = p_mctl->ispif_fns->ispif_config(&ispif_params, 1);
+			if (rc < 0)
+				return rc;
+			rc = p_mctl->ispif_fns->ispif_start_intf_transfer
+					(&ispif_params);
+			if (rc < 0)
+				return rc;
+			msleep(20);
+		}
+		break;
+	case NOTIFY_VFE_MSG_EVT:
+		if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_notify) {
+			rc = p_mctl->isp_sdev->isp_notify(
+				&p_mctl->isp_sdev->sd, arg);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return rc;
+}
+
+/* called by the server or the config nodes to handle user space
+  commands*/
+static int msm_mctl_cmd(struct msm_cam_media_controller *p_mctl,
+			unsigned int cmd, unsigned long arg)
+{
+	int rc = -EINVAL;
+	void __user *argp = (void __user *)arg;
+	if (!p_mctl) {
+		pr_err("%s: param is NULL", __func__);
+		return -EINVAL;
+	}
+	D("%s start cmd = %d\n", __func__, _IOC_NR(cmd));
+
+	/* ... call sensor, ISPIF or VEF subdev*/
+	switch (cmd) {
+		/* sensor config*/
+	case MSM_CAM_IOCTL_GET_SENSOR_INFO:
+			rc = msm_get_sensor_info(&p_mctl->sync, argp);
+			break;
+
+	case MSM_CAM_IOCTL_SENSOR_IO_CFG:
+			rc = p_mctl->sync.sctrl.s_config(argp);
+			break;
+
+	case MSM_CAM_IOCTL_FLASH_CTRL: {
+		struct flash_ctrl_data flash_info;
+		if (copy_from_user(&flash_info, argp, sizeof(flash_info))) {
+			ERR_COPY_FROM_USER();
+			rc = -EFAULT;
+		} else {
+			rc = msm_flash_ctrl(p_mctl->sync.sdata, &flash_info);
+		}
+		break;
+	}
+
+			/* ISFIF config*/
+
+	default:
+		/* ISP config*/
+		rc = p_mctl->isp_sdev->isp_config(p_mctl, cmd, arg);
+		break;
+	}
+	D("%s: !!! cmd = %d, rc = %d\n", __func__, _IOC_NR(cmd), rc);
+	return rc;
+}
+
+static int msm_sync_init(struct msm_sync *sync,
+	struct platform_device *pdev, struct msm_sensor_ctrl *sctrl)
+{
+	int rc = 0;
+	if (!sync) {
+		pr_err("%s: param is NULL", __func__);
+		return -EINVAL;
+	}
+
+	sync->sdata = pdev->dev.platform_data;
+
+	wake_lock_init(&sync->wake_lock, WAKE_LOCK_IDLE, "msm_camera");
+
+	sync->pdev = pdev;
+	sync->sctrl = *sctrl;
+	sync->opencnt = 0;
+	mutex_init(&sync->lock);
+	D("%s: initialized %s\n", __func__, sync->sdata->sensor_name);
+	return rc;
+}
+
+static int msm_mctl_open(struct msm_cam_media_controller *p_mctl,
+				 const char *const apps_id)
+{
+	int rc = 0;
+	struct msm_sync *sync = NULL;
+	D("%s\n", __func__);
+	if (!p_mctl) {
+		pr_err("%s: param is NULL", __func__);
+		return -EINVAL;
+	}
+
+	/* msm_sync_init() muct be called before*/
+	sync = &(p_mctl->sync);
+
+	mutex_lock(&sync->lock);
+	/* open sub devices - once only*/
+	if (!sync->opencnt) {
+		wake_lock(&sync->wake_lock);
+
+		/* turn on clock */
+		rc = msm_camio_sensor_clk_on(sync->pdev);
+		if (rc < 0) {
+			pr_err("%s: msm_camio_sensor_clk_on failed:%d\n",
+			 __func__, rc);
+			goto msm_open_done;
+		}
+
+		/* ISP first*/
+		if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_open)
+			rc = p_mctl->isp_sdev->isp_open(
+				&p_mctl->isp_sdev->sd, sync);
+
+		if (rc < 0) {
+			pr_err("%s: isp init failed: %d\n", __func__, rc);
+			goto msm_open_done;
+		}
+
+		/* then sensor - move sub dev later*/
+		if (sync->sctrl.s_init)
+			rc = sync->sctrl.s_init(sync->sdata);
+
+		if (rc < 0) {
+			pr_err("%s: isp init failed: %d\n", __func__, rc);
+			goto msm_open_done;
+		}
+
+		pm_qos_add_request(&p_mctl->pm_qos_req_list,
+					PM_QOS_CPU_DMA_LATENCY,
+					PM_QOS_DEFAULT_VALUE);
+		pm_qos_update_request(&p_mctl->pm_qos_req_list,
+					MSM_V4L2_SWFI_LATENCY);
+
+		sync->apps_id = apps_id;
+		sync->opencnt++;
+	}
+
+msm_open_done:
+	mutex_unlock(&sync->lock);
+	return rc;
+}
+
+static int msm_mctl_release(struct msm_cam_media_controller *p_mctl)
+{
+	struct msm_sync *sync = NULL;
+	int rc = 0;
+
+	sync = &(p_mctl->sync);
+
+	if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release)
+		p_mctl->isp_sdev->isp_release(&p_mctl->sync);
+
+	if (p_mctl->sync.sctrl.s_release)
+		p_mctl->sync.sctrl.s_release();
+
+	rc = msm_camio_sensor_clk_off(sync->pdev);
+	if (rc < 0)
+		pr_err("%s: msm_camio_sensor_clk_off failed:%d\n",
+			 __func__, rc);
+
+	pm_qos_update_request(&p_mctl->pm_qos_req_list,
+				PM_QOS_DEFAULT_VALUE);
+	pm_qos_remove_request(&p_mctl->pm_qos_req_list);
+
+	return rc;
+}
+
+int msm_mctl_init_user_formats(struct msm_cam_v4l2_device *pcam)
+{
+	struct v4l2_subdev *sd = &pcam->sensor_sdev;
+	enum v4l2_mbus_pixelcode pxlcode;
+	int numfmt_sensor = 0;
+	int numfmt = 0;
+	int rc = 0;
+	int i, j;
+
+	D("%s\n", __func__);
+	while (!v4l2_subdev_call(sd, video, enum_mbus_fmt, numfmt_sensor,
+								&pxlcode))
+		numfmt_sensor++;
+
+	D("%s, numfmt_sensor = %d\n", __func__, numfmt_sensor);
+	if (!numfmt_sensor)
+		return -ENXIO;
+
+	pcam->usr_fmts = vmalloc(numfmt_sensor * ARRAY_SIZE(msm_isp_formats) *
+				sizeof(struct msm_isp_color_fmt));
+	if (!pcam->usr_fmts)
+		return -ENOMEM;
+
+	/* from sensor to ISP.. fill the data structure */
+	for (i = 0; i < numfmt_sensor; i++) {
+		rc = v4l2_subdev_call(sd, video, enum_mbus_fmt, i, &pxlcode);
+		D("rc is  %d\n", rc);
+		if (rc < 0) {
+			vfree(pcam->usr_fmts);
+			return rc;
+		}
+
+		for (j = 0; j < ARRAY_SIZE(msm_isp_formats); j++) {
+			/* find the corresponding format */
+			if (pxlcode == msm_isp_formats[j].pxlcode) {
+				pcam->usr_fmts[numfmt] = msm_isp_formats[j];
+				D("pcam->usr_fmts=0x%x\n", (u32)pcam->usr_fmts);
+				D("format pxlcode 0x%x (0x%x) found\n",
+					  pcam->usr_fmts[numfmt].pxlcode,
+					  pcam->usr_fmts[numfmt].fourcc);
+				numfmt++;
+			}
+		}
+	}
+
+	pcam->num_fmts = numfmt;
+
+	if (numfmt == 0) {
+		pr_err("%s: No supported formats.\n", __func__);
+		vfree(pcam->usr_fmts);
+		return -EINVAL;
+	}
+
+	D("Found %d supported formats.\n", pcam->num_fmts);
+	/* set the default pxlcode, in any case, it will be set through
+	 * setfmt */
+	return 0;
+}
+
+/* this function plug in the implementation of a v4l2_subdev */
+int msm_mctl_init_module(struct msm_cam_v4l2_device *pcam)
+{
+
+	struct msm_cam_media_controller *pmctl = NULL;
+	D("%s\n", __func__);
+	if (!pcam) {
+		pr_err("%s: param is NULL", __func__);
+		return -EINVAL;
+	} else
+		pmctl = &pcam->mctl;
+
+	/* init module sync object*/
+	msm_sync_init(&pmctl->sync, pcam->pdev, &pcam->sctrl);
+
+	/* init module operations*/
+	pmctl->mctl_open = msm_mctl_open;
+	pmctl->mctl_cmd = msm_mctl_cmd;
+	pmctl->mctl_notify = msm_mctl_notify;
+	pmctl->mctl_vidbuf_init = msm_vidbuf_init;
+	pmctl->mctl_release = msm_mctl_release;
+
+	pmctl->plat_dev = pcam->pdev;
+	/* init sub device*/
+	v4l2_subdev_init(&(pmctl->mctl_sdev), &mctl_subdev_ops);
+	v4l2_set_subdevdata(&(pmctl->mctl_sdev), pmctl);
+
+	return 0;
+}
+static int msm_mctl_out_type_to_inst_index(struct msm_cam_v4l2_device *pcam,
+					int out_type)
+{
+	switch (out_type) {
+	case VFE_MSG_OUTPUT_P:
+		return pcam->dev_inst_map
+			[MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW]->my_index;
+	case VFE_MSG_OUTPUT_V:
+		return pcam->dev_inst_map
+			[MSM_V4L2_EXT_CAPTURE_MODE_VIDEO]->my_index;
+	case VFE_MSG_OUTPUT_S:
+		return pcam->dev_inst_map
+			[MSM_V4L2_EXT_CAPTURE_MODE_MAIN]->my_index;
+	case VFE_MSG_OUTPUT_T:
+		return pcam->dev_inst_map
+			[MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL]->my_index;
+	default:
+		return 0;
+	}
+	return 0;
+}
+
+int msm_mctl_buf_done(struct msm_cam_media_controller *pmctl,
+			int msg_type, uint32_t y_phy)
+{
+	struct videobuf_queue *q;
+	struct videobuf_buffer *buf = NULL;
+	uint32_t buf_phyaddr = 0;
+	int i, idx;
+	unsigned long flags = 0;
+
+	idx = msm_mctl_out_type_to_inst_index(pmctl->sync.pcam_sync, msg_type);
+	q = &(pmctl->sync.pcam_sync->dev_inst[idx]->vid_bufq);
+
+	D("q=0x%x\n", (u32)q);
+
+	/* find the videobuf which is done */
+	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+		if (NULL == q->bufs[i])
+			continue;
+		buf = q->bufs[i];
+		buf_phyaddr = videobuf_to_pmem_contig(buf);
+		D("buf_phyaddr=0x%x\n", (u32)buf_phyaddr);
+		D("data->phy.y_phy=0x%x\n",
+				y_phy);
+		D("buf = 0x%x\n", (u32)buf);
+		if (buf_phyaddr == y_phy) {
+			/* signal that buffer is done */
+			/* get the buf lock first */
+			spin_lock_irqsave(q->irqlock, flags);
+			buf->state = VIDEOBUF_DONE;
+			D("queuedequeue video_buffer 0x%x,"
+				"phyaddr = 0x%x\n",
+				(u32)buf, y_phy);
+
+			do_gettimeofday(&buf->ts);
+			buf->field_count++;
+			wake_up(&buf->done);
+			spin_unlock_irqrestore(q->irqlock, flags);
+			break;
+		}
+	}
+	return 0;
+}
diff --git a/drivers/media/video/msm/msm_mem.c b/drivers/media/video/msm/msm_mem.c
new file mode 100644
index 0000000..5232f7c
--- /dev/null
+++ b/drivers/media/video/msm/msm_mem.c
@@ -0,0 +1,403 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+
+#include <linux/android_pmem.h>
+
+#include "msm.h"
+#include "msm_vfe31.h"
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+#define D(fmt, args...) pr_debug("msm_isp: " fmt, ##args)
+#else
+#define D(fmt, args...) do {} while (0)
+#endif
+
+
+#define ERR_USER_COPY(to) pr_err("%s(%d): copy %s user\n", \
+				__func__, __LINE__, ((to) ? "to" : "from"))
+#define ERR_COPY_FROM_USER() ERR_USER_COPY(0)
+#define ERR_COPY_TO_USER() ERR_USER_COPY(1)
+
+
+#define PAD_TO_WORD(a)	  (((a) + 3) & ~3)
+
+#define __CONTAINS(r, v, l, field) ({			   \
+	typeof(r) __r = r;				  \
+	typeof(v) __v = v;				  \
+	typeof(v) __e = __v + l;				\
+	int res = __v >= __r->field &&			  \
+		__e <= __r->field + __r->len;		   \
+	res;							\
+})
+
+#define CONTAINS(r1, r2, field) ({			  \
+	typeof(r2) __r2 = r2;				   \
+	__CONTAINS(r1, __r2->field, __r2->len, field);	  \
+})
+
+#define IN_RANGE(r, v, field) ({				\
+	typeof(r) __r = r;				  \
+	typeof(v) __vv = v;				 \
+	int res = ((__vv >= __r->field) &&		  \
+		(__vv < (__r->field + __r->len)));	  \
+	res;							\
+})
+
+#define OVERLAPS(r1, r2, field) ({			  \
+	typeof(r1) __r1 = r1;				   \
+	typeof(r2) __r2 = r2;				   \
+	typeof(__r2->field) __v = __r2->field;		  \
+	typeof(__v) __e = __v + __r2->len - 1;		  \
+	int res = (IN_RANGE(__r1, __v, field) ||		\
+		IN_RANGE(__r1, __e, field));				 \
+	res;							\
+})
+
+static DEFINE_MUTEX(hlist_mut);
+
+#ifdef CONFIG_ANDROID_PMEM
+static int check_pmem_info(struct msm_pmem_info *info, int len)
+{
+	if (info->offset < len &&
+		info->offset + info->len <= len &&
+		info->y_off < len &&
+		info->cbcr_off < len)
+		return 0;
+
+	pr_err("%s: check failed: off %d len %d y %d cbcr %d (total len %d)\n",
+						__func__,
+						info->offset,
+						info->len,
+						info->y_off,
+						info->cbcr_off,
+						len);
+	return -EINVAL;
+}
+#endif
+
+static int check_overlap(struct hlist_head *ptype,
+				unsigned long paddr,
+				unsigned long len)
+{
+	struct msm_pmem_region *region;
+	struct msm_pmem_region t = { .paddr = paddr, .len = len };
+	struct hlist_node *node;
+
+	hlist_for_each_entry(region, node, ptype, list) {
+		if (CONTAINS(region, &t, paddr) ||
+			CONTAINS(&t, region, paddr) ||
+			OVERLAPS(region, &t, paddr)) {
+			CDBG(" region (PHYS %p len %ld)"
+				" clashes with registered region"
+				" (paddr %p len %ld)\n",
+				(void *)t.paddr, t.len,
+				(void *)region->paddr, region->len);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int msm_pmem_table_add(struct hlist_head *ptype,
+	struct msm_pmem_info *info)
+{
+	struct file *file;
+	unsigned long paddr;
+#ifdef CONFIG_ANDROID_PMEM
+	unsigned long kvstart;
+	int rc;
+#endif
+	unsigned long len;
+	struct msm_pmem_region *region;
+#ifdef CONFIG_ANDROID_PMEM
+	rc = get_pmem_file(info->fd, &paddr, &kvstart, &len, &file);
+	if (rc < 0) {
+		pr_err("%s: get_pmem_file fd %d error %d\n",
+						__func__,
+						info->fd, rc);
+		return rc;
+	}
+	if (!info->len)
+		info->len = len;
+
+	rc = check_pmem_info(info, len);
+	if (rc < 0)
+		return rc;
+#else
+	paddr = 0;
+	file = NULL;
+#endif
+	paddr += info->offset;
+	len = info->len;
+
+	if (check_overlap(ptype, paddr, len) < 0)
+		return -EINVAL;
+
+	CDBG("%s: type %d, active flag %d, paddr 0x%lx, vaddr 0x%lx\n",
+		__func__, info->type, info->active, paddr,
+		(unsigned long)info->vaddr);
+
+	region = kmalloc(sizeof(struct msm_pmem_region), GFP_KERNEL);
+	if (!region)
+		return -ENOMEM;
+
+	INIT_HLIST_NODE(&region->list);
+
+	region->paddr = paddr;
+	region->len = len;
+	region->file = file;
+	memcpy(&region->info, info, sizeof(region->info));
+	D("%s Adding region to list with type %d\n", __func__,
+						region->info.type);
+	D("%s pmem_stats address is 0x%p\n", __func__, ptype);
+	hlist_add_head(&(region->list), ptype);
+
+	return 0;
+}
+
+static int __msm_register_pmem(struct hlist_head *ptype,
+			struct msm_pmem_info *pinfo)
+{
+	int rc = 0;
+
+	switch (pinfo->type) {
+	case MSM_PMEM_AEC_AWB:
+	case MSM_PMEM_AF:
+	case MSM_PMEM_AEC:
+	case MSM_PMEM_AWB:
+	case MSM_PMEM_RS:
+	case MSM_PMEM_CS:
+	case MSM_PMEM_IHIST:
+	case MSM_PMEM_SKIN:
+		rc = msm_pmem_table_add(ptype, pinfo);
+		break;
+
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+static int __msm_pmem_table_del(struct hlist_head *ptype,
+			struct msm_pmem_info *pinfo)
+{
+	int rc = 0;
+	struct msm_pmem_region *region;
+	struct hlist_node *node, *n;
+
+	switch (pinfo->type) {
+	case MSM_PMEM_AEC_AWB:
+	case MSM_PMEM_AF:
+		hlist_for_each_entry_safe(region, node, n,
+				ptype, list) {
+
+			if (pinfo->type == region->info.type &&
+				pinfo->vaddr == region->info.vaddr &&
+				pinfo->fd == region->info.fd) {
+				hlist_del(node);
+#ifdef CONFIG_ANDROID_PMEM
+				put_pmem_file(region->file);
+#else
+
+#endif
+				kfree(region);
+			}
+		}
+		break;
+
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+/* return of 0 means failure */
+uint8_t msm_pmem_region_lookup(struct hlist_head *ptype,
+	int pmem_type, struct msm_pmem_region *reg, uint8_t maxcount)
+{
+	struct msm_pmem_region *region;
+	struct msm_pmem_region *regptr;
+	struct hlist_node *node, *n;
+
+	uint8_t rc = 0;
+	D("%s\n", __func__);
+	regptr = reg;
+	mutex_lock(&hlist_mut);
+	hlist_for_each_entry_safe(region, node, n, ptype, list) {
+		if (region->info.type == pmem_type && region->info.active) {
+			*regptr = *region;
+			rc += 1;
+			if (rc >= maxcount)
+				break;
+			regptr++;
+		}
+	}
+	D("%s finished, rc=%d\n", __func__, rc);
+	mutex_unlock(&hlist_mut);
+	return rc;
+}
+
+uint8_t msm_pmem_region_lookup_2(struct hlist_head *ptype,
+					int pmem_type,
+					struct msm_pmem_region *reg,
+					uint8_t maxcount)
+{
+	struct msm_pmem_region *region;
+	struct msm_pmem_region *regptr;
+	struct hlist_node *node, *n;
+	uint8_t rc = 0;
+	regptr = reg;
+	mutex_lock(&hlist_mut);
+	hlist_for_each_entry_safe(region, node, n, ptype, list) {
+		D("Mio: info.type=%d, pmem_type = %d,"
+						"info.active = %d\n",
+		region->info.type, pmem_type, region->info.active);
+
+		if (region->info.type == pmem_type && region->info.active) {
+			D("info.type=%d, pmem_type = %d,"
+							"info.active = %d,\n",
+				region->info.type, pmem_type,
+				region->info.active);
+			*regptr = *region;
+			region->info.type = MSM_PMEM_VIDEO;
+			rc += 1;
+			if (rc >= maxcount)
+				break;
+			regptr++;
+		}
+	}
+	mutex_unlock(&hlist_mut);
+	return rc;
+}
+
+uint8_t msm_pmem_region_lookup_3(struct msm_cam_v4l2_device *pcam, int idx,
+						struct msm_pmem_region *reg,
+						int mem_type)
+{
+	struct videobuf_contig_pmem *mem;
+	uint8_t rc = 0;
+	struct videobuf_queue *q = &pcam->dev_inst[idx]->vid_bufq;
+	struct videobuf_buffer *buf = NULL;
+
+	videobuf_queue_lock(q);
+	list_for_each_entry(buf, &q->stream, stream) {
+		mem = buf->priv;
+		reg->paddr = mem->phyaddr;
+		D("%s paddr for buf %d is 0x%p\n", __func__,
+						buf->i,
+						(void *)reg->paddr);
+		reg->len = sizeof(struct msm_pmem_info);
+		reg->file = NULL;
+		reg->info.len = mem->size;
+
+		reg->info.vaddr =
+			(void *)(buf->baddr);
+
+		reg->info.type = mem_type;
+
+		reg->info.offset = 0;
+		reg->info.y_off = mem->y_off;
+		reg->info.cbcr_off = PAD_TO_WORD(mem->cbcr_off);
+		D("%s y_off = %d, cbcr_off = %d\n", __func__,
+			reg->info.y_off, reg->info.cbcr_off);
+		rc += 1;
+		reg++;
+	}
+	videobuf_queue_unlock(q);
+
+	return rc;
+}
+
+unsigned long msm_pmem_stats_vtop_lookup(
+				struct msm_sync *sync,
+				unsigned long buffer,
+				int fd)
+{
+	struct msm_pmem_region *region;
+	struct hlist_node *node, *n;
+
+	hlist_for_each_entry_safe(region, node, n, &sync->pmem_stats, list) {
+		if (((unsigned long)(region->info.vaddr) == buffer) &&
+						(region->info.fd == fd) &&
+						region->info.active == 0) {
+			region->info.active = 1;
+			return region->paddr;
+		}
+	}
+
+	return 0;
+}
+
+unsigned long msm_pmem_stats_ptov_lookup(struct msm_sync *sync,
+						unsigned long addr, int *fd)
+{
+	struct msm_pmem_region *region;
+	struct hlist_node *node, *n;
+
+	hlist_for_each_entry_safe(region, node, n, &sync->pmem_stats, list) {
+		if (addr == region->paddr && region->info.active) {
+			/* offset since we could pass vaddr inside a
+			 * registered pmem buffer */
+			*fd = region->info.fd;
+			region->info.active = 0;
+			return (unsigned long)(region->info.vaddr);
+		}
+	}
+
+	return 0;
+}
+
+int msm_register_pmem(struct hlist_head *ptype, void __user *arg)
+{
+	struct msm_pmem_info info;
+
+	if (copy_from_user(&info, arg, sizeof(info))) {
+		ERR_COPY_FROM_USER();
+			return -EFAULT;
+	}
+
+	return __msm_register_pmem(ptype, &info);
+}
+EXPORT_SYMBOL(msm_register_pmem);
+
+int msm_pmem_table_del(struct hlist_head *ptype, void __user *arg)
+{
+	struct msm_pmem_info info;
+
+	if (copy_from_user(&info, arg, sizeof(info))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	return __msm_pmem_table_del(ptype, &info);
+}
+EXPORT_SYMBOL(msm_pmem_table_del);
diff --git a/drivers/media/video/msm/msm_sensor.c b/drivers/media/video/msm/msm_sensor.c
new file mode 100644
index 0000000..83fe643
--- /dev/null
+++ b/drivers/media/video/msm/msm_sensor.c
@@ -0,0 +1,814 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <mach/gpio.h>
+#include <mach/camera.h>
+#include <media/msm_camera.h>
+#include "msm_sensor.h"
+
+/*=============================================================*/
+
+int32_t msm_sensor_i2c_rxdata(struct msm_sensor_ctrl_t *s_ctrl,
+	unsigned char *rxdata, int length)
+{
+	uint16_t saddr = s_ctrl->msm_sensor_client->addr >> 1;
+	struct i2c_msg msgs[] = {
+		{
+			.addr  = saddr,
+			.flags = 0,
+			.len   = 2,
+			.buf   = rxdata,
+		},
+		{
+			.addr  = saddr,
+			.flags = I2C_M_RD,
+			.len   = length,
+			.buf   = rxdata,
+		},
+	};
+	if (i2c_transfer(s_ctrl->msm_sensor_client->adapter, msgs, 2) < 0) {
+		CDBG("msm_sensor_i2c_rxdata faild 0x%x\n", saddr);
+		return -EIO;
+	}
+	return 0;
+}
+
+int32_t msm_sensor_i2c_txdata(struct msm_sensor_ctrl_t *s_ctrl,
+				unsigned char *txdata, int length)
+{
+	uint16_t saddr = s_ctrl->msm_sensor_client->addr >> 1;
+	struct i2c_msg msg[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = length,
+			.buf = txdata,
+		 },
+	};
+	if (i2c_transfer(s_ctrl->msm_sensor_client->adapter, msg, 1) < 0) {
+		CDBG("msm_sensor_i2c_txdata faild 0x%x\n", saddr);
+		return -EIO;
+	}
+	return 0;
+}
+
+int32_t msm_sensor_i2c_waddr_write_b(struct msm_sensor_ctrl_t *s_ctrl,
+	uint16_t waddr, uint8_t bdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[3];
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = bdata;
+	CDBG("%s waddr = 0x%x, wdata = 0x%x\n", __func__, waddr, bdata);
+	rc = msm_sensor_i2c_txdata(s_ctrl, buf, 3);
+	if (rc < 0)
+		CDBG("%s fail\n", __func__);
+	return rc;
+}
+
+int32_t msm_sensor_i2c_waddr_write_w(struct msm_sensor_ctrl_t *s_ctrl,
+	uint16_t waddr, uint16_t wdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[4];
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = (wdata & 0xFF00) >> 8;
+	buf[3] = (wdata & 0x00FF);
+	CDBG("%s waddr = 0x%x, wdata = 0x%x\n", __func__, waddr, wdata);
+	rc = msm_sensor_i2c_txdata(s_ctrl, buf, 4);
+	if (rc < 0)
+		CDBG("%s fail\n", __func__);
+	return rc;
+}
+
+int32_t msm_sensor_i2c_waddr_write_b_tbl(struct msm_sensor_ctrl_t *s_ctrl,
+	struct msm_sensor_i2c_reg_conf const *reg_conf_tbl, uint8_t size)
+{
+	int i;
+	int32_t rc = -EIO;
+	for (i = 0; i < size; i++) {
+		rc = msm_sensor_i2c_waddr_write_b(
+			s_ctrl,
+			reg_conf_tbl->reg_addr,
+			reg_conf_tbl->reg_data);
+		if (rc < 0)
+			break;
+		reg_conf_tbl++;
+	}
+	return rc;
+}
+
+int32_t msm_sensor_i2c_waddr_write_w_tbl(struct msm_sensor_ctrl_t *s_ctrl,
+	struct msm_sensor_i2c_reg_conf const *reg_conf_tbl, uint8_t size)
+{
+	int i;
+	int32_t rc = -EIO;
+	for (i = 0; i < size; i++) {
+		rc = msm_sensor_i2c_waddr_write_w(
+			s_ctrl,
+			reg_conf_tbl->reg_addr,
+			reg_conf_tbl->reg_data);
+		if (rc < 0)
+			break;
+		reg_conf_tbl++;
+	}
+	return rc;
+}
+
+int32_t msm_sensor_i2c_waddr_read_w(struct msm_sensor_ctrl_t *s_ctrl,
+	uint16_t waddr, uint16_t *data)
+{
+	int32_t rc = 0;
+	unsigned char buf[2];
+	if (!data)
+		return -EIO;
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	rc = msm_sensor_i2c_rxdata(s_ctrl, buf, 2);
+	if (rc < 0) {
+		CDBG("%s fail\n", __func__);
+		return rc;
+	}
+	*data = (buf[0] << 8 | buf[1]);
+	CDBG("%s waddr = 0x%x val = 0x%x!\n", __func__,
+	waddr, *data);
+	return rc;
+}
+
+int msm_sensor_write_b_conf_array(struct msm_sensor_ctrl_t *s_ctrl,
+			struct msm_sensor_i2c_conf_array *array, uint16_t index)
+{
+	return msm_sensor_i2c_waddr_write_b_tbl(
+		s_ctrl, array[index].conf, array[index].size);
+}
+
+int msm_sensor_write_w_conf_array(struct msm_sensor_ctrl_t *s_ctrl,
+			struct msm_sensor_i2c_conf_array *array, uint16_t index)
+{
+	return msm_sensor_i2c_waddr_write_w_tbl(
+		s_ctrl, array[index].conf, array[index].size);
+}
+
+int msm_sensor_write_b_init_settings(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int rc = 0, i;
+	for (i = 0; i < s_ctrl->msm_sensor_reg.init_size; i++) {
+		rc = msm_sensor_write_b_conf_array(
+			s_ctrl, s_ctrl->msm_sensor_reg.init_settings, i);
+		msleep(s_ctrl->msm_sensor_reg.init_settings[i].delay);
+		if (rc < 0)
+			break;
+	}
+	return rc;
+}
+
+int msm_sensor_write_w_init_settings(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int rc = 0, i;
+	for (i = 0; i < s_ctrl->msm_sensor_reg.init_size; i++) {
+		rc = msm_sensor_write_w_conf_array(
+			s_ctrl, s_ctrl->msm_sensor_reg.init_settings, i);
+		msleep(s_ctrl->msm_sensor_reg.init_settings[i].delay);
+		if (rc < 0)
+			break;
+	}
+	return rc;
+}
+
+int msm_sensor_write_b_res_settings(struct msm_sensor_ctrl_t *s_ctrl,
+	uint16_t res)
+{
+	int rc = 0;
+	rc = msm_sensor_write_b_conf_array(
+		s_ctrl, s_ctrl->msm_sensor_reg.res_settings, res);
+	msleep(s_ctrl->msm_sensor_reg.res_settings[res].delay);
+	return rc;
+}
+
+int msm_sensor_write_w_res_settings(struct msm_sensor_ctrl_t *s_ctrl,
+	uint16_t res)
+{
+	int rc = 0;
+	rc = msm_sensor_write_w_conf_array(
+		s_ctrl, s_ctrl->msm_sensor_reg.res_settings, res);
+	msleep(s_ctrl->msm_sensor_reg.res_settings[res].delay);
+	return rc;
+}
+
+uint16_t msm_sensor_read_b_conf_wdata(struct msm_sensor_ctrl_t *s_ctrl,
+			enum msm_sensor_resolution_t res, int8_t array_addr)
+{
+	return
+	s_ctrl->msm_sensor_reg.res_settings[res].
+	conf[array_addr].reg_data << 8 |
+	s_ctrl->msm_sensor_reg.res_settings[res].
+	conf[array_addr+1].reg_data;
+}
+
+uint16_t msm_sensor_read_w_conf_wdata(struct msm_sensor_ctrl_t *s_ctrl,
+			enum msm_sensor_resolution_t res, int8_t array_addr)
+{
+	return
+	s_ctrl->msm_sensor_reg.res_settings[res].
+	conf[array_addr].reg_data;
+}
+
+void msm_sensor_start_stream(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	msm_sensor_i2c_waddr_write_b_tbl(s_ctrl,
+		s_ctrl->msm_sensor_reg.start_stream_conf,
+		s_ctrl->msm_sensor_reg.start_stream_conf_size);
+}
+
+void msm_sensor_stop_stream(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	msm_sensor_i2c_waddr_write_b_tbl(s_ctrl,
+		s_ctrl->msm_sensor_reg.stop_stream_conf,
+		s_ctrl->msm_sensor_reg.stop_stream_conf_size);
+}
+
+void msm_sensor_group_hold_on(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	msm_sensor_i2c_waddr_write_b_tbl(s_ctrl,
+		s_ctrl->msm_sensor_reg.group_hold_on_conf,
+		s_ctrl->msm_sensor_reg.group_hold_on_conf_size);
+}
+
+void msm_sensor_group_hold_off(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	msm_sensor_i2c_waddr_write_b_tbl(s_ctrl,
+		s_ctrl->msm_sensor_reg.group_hold_off_conf,
+		s_ctrl->msm_sensor_reg.group_hold_off_conf_size);
+}
+
+uint16_t msm_sensor_get_prev_lines_pf(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	return s_ctrl->prev_frame_length_lines;
+}
+
+uint16_t msm_sensor_get_prev_pixels_pl(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	return s_ctrl->prev_line_length_pck;
+}
+
+uint16_t msm_sensor_get_pict_lines_pf(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	return s_ctrl->snap_frame_length_lines;
+}
+
+uint16_t msm_sensor_get_pict_pixels_pl(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	return s_ctrl->snap_line_length_pck;
+}
+
+uint32_t msm_sensor_get_pict_max_exp_lc(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	return s_ctrl->snap_frame_length_lines  * 24;
+}
+
+void msm_sensor_get_pict_fps(struct msm_sensor_ctrl_t *s_ctrl,
+			uint16_t fps, uint16_t *pfps)
+{
+	uint32_t divider, d1, d2;
+	d1 = s_ctrl->prev_frame_length_lines * Q10 /
+		s_ctrl->snap_frame_length_lines;
+	d2 = s_ctrl->prev_line_length_pck * Q10 /
+		s_ctrl->snap_line_length_pck;
+	divider = d1 * d2 / Q10;
+	*pfps = (uint16_t) (fps * divider / Q10);
+}
+
+int32_t msm_sensor_set_fps(struct msm_sensor_ctrl_t *s_ctrl,
+						struct fps_cfg *fps)
+{
+	uint16_t total_lines_per_frame;
+	int32_t rc = 0;
+	s_ctrl->fps_divider = fps->fps_div;
+
+	total_lines_per_frame = (uint16_t)
+		((s_ctrl->prev_frame_length_lines) *
+		s_ctrl->fps_divider/Q10);
+
+	rc = msm_sensor_i2c_waddr_write_w(s_ctrl,
+				s_ctrl->frame_length_lines_addr,
+				total_lines_per_frame);
+	return rc;
+}
+
+int32_t msm_sensor_write_exp_gain1(struct msm_sensor_ctrl_t *s_ctrl,
+		uint16_t gain, uint32_t line)
+{
+	uint32_t fl_lines;
+	uint8_t offset;
+	fl_lines = s_ctrl->curr_frame_length_lines;
+	line = (line * s_ctrl->fps_divider) / Q10;
+	offset = s_ctrl->vert_offset;
+	if (line > (fl_lines - offset))
+		fl_lines = line + offset;
+
+	s_ctrl->func_tbl.sensor_group_hold_on(s_ctrl);
+	msm_sensor_i2c_waddr_write_w(s_ctrl,
+			s_ctrl->frame_length_lines_addr, fl_lines);
+	msm_sensor_i2c_waddr_write_w(s_ctrl,
+			s_ctrl->coarse_int_time_addr, line);
+	msm_sensor_i2c_waddr_write_w(s_ctrl, s_ctrl->global_gain_addr, gain);
+	s_ctrl->func_tbl.sensor_group_hold_off(s_ctrl);
+	return 0;
+}
+
+int32_t msm_sensor_write_exp_gain2(struct msm_sensor_ctrl_t *s_ctrl,
+		uint16_t gain, uint32_t line)
+{
+	uint32_t fl_lines, ll_pclk, ll_ratio;
+	uint8_t offset;
+	fl_lines = s_ctrl->curr_frame_length_lines;
+	ll_pclk = s_ctrl->curr_line_length_pck;
+	line = (line * s_ctrl->fps_divider) / Q10;
+	offset = s_ctrl->vert_offset;
+	if (line > (fl_lines - offset)) {
+		ll_ratio = (line * Q10) / (fl_lines - offset);
+		ll_pclk = ll_pclk * ll_ratio;
+		line = fl_lines - offset;
+	}
+
+	s_ctrl->func_tbl.sensor_group_hold_on(s_ctrl);
+	msm_sensor_i2c_waddr_write_w(s_ctrl,
+			s_ctrl->line_length_pck_addr, ll_pclk);
+	msm_sensor_i2c_waddr_write_w(s_ctrl,
+			s_ctrl->coarse_int_time_addr, line);
+	msm_sensor_i2c_waddr_write_w(s_ctrl, s_ctrl->global_gain_addr, gain);
+	s_ctrl->func_tbl.sensor_group_hold_off(s_ctrl);
+	return 0;
+}
+
+int32_t msm_sensor_set_sensor_mode_b(struct msm_sensor_ctrl_t *s_ctrl,
+	int mode, int res)
+{
+	int32_t rc = 0;
+
+	if (s_ctrl->curr_res != res) {
+		switch (mode) {
+		case SENSOR_PREVIEW_MODE:
+			s_ctrl->prev_res = res;
+			break;
+		case SENSOR_SNAPSHOT_MODE:
+		case SENSOR_RAW_SNAPSHOT_MODE:
+			s_ctrl->pict_res = res;
+			break;
+		default:
+			rc = -EINVAL;
+			break;
+		}
+		s_ctrl->curr_frame_length_lines =
+			msm_sensor_read_b_conf_wdata
+			(s_ctrl, res, s_ctrl->frame_length_lines_array_addr);
+		s_ctrl->curr_line_length_pck =
+			msm_sensor_read_b_conf_wdata
+			(s_ctrl, res, s_ctrl->line_length_pck_array_addr);
+
+		if (s_ctrl->func_tbl.sensor_setting
+			(s_ctrl, MSM_SENSOR_UPDATE_PERIODIC, res) < 0)
+			return rc;
+	}
+	s_ctrl->curr_res = res;
+	return rc;
+}
+
+int32_t msm_sensor_set_sensor_mode_w(struct msm_sensor_ctrl_t *s_ctrl,
+	int mode, int res)
+{
+	int32_t rc = 0;
+
+	if (s_ctrl->curr_res != res) {
+		switch (mode) {
+		case SENSOR_PREVIEW_MODE:
+			s_ctrl->prev_res = res;
+			break;
+		case SENSOR_SNAPSHOT_MODE:
+		case SENSOR_RAW_SNAPSHOT_MODE:
+			s_ctrl->pict_res = res;
+			break;
+		default:
+			rc = -EINVAL;
+			break;
+		}
+		s_ctrl->curr_frame_length_lines =
+			msm_sensor_read_w_conf_wdata
+			(s_ctrl, res, s_ctrl->frame_length_lines_array_addr);
+		s_ctrl->curr_line_length_pck =
+			msm_sensor_read_w_conf_wdata
+			(s_ctrl, res, s_ctrl->line_length_pck_array_addr);
+
+		if (s_ctrl->func_tbl.sensor_setting
+			(s_ctrl, MSM_SENSOR_UPDATE_PERIODIC, res) < 0)
+			return rc;
+	}
+	s_ctrl->curr_res = res;
+	return rc;
+}
+
+int32_t msm_sensor_mode_init_bdata(struct msm_sensor_ctrl_t *s_ctrl,
+			int mode, struct sensor_init_cfg *init_info)
+{
+	int32_t rc = 0;
+	CDBG("%s: %d\n", __func__, __LINE__);
+	if (mode != s_ctrl->cam_mode) {
+		if (init_info->prev_res >=
+			s_ctrl->msm_sensor_reg.num_conf ||
+			init_info->pict_res >=
+			s_ctrl->msm_sensor_reg.num_conf) {
+			CDBG("Resolution does not exist");
+			return -EINVAL;
+		}
+
+		s_ctrl->prev_res = init_info->prev_res;
+		s_ctrl->pict_res = init_info->pict_res;
+		s_ctrl->curr_res = MSM_SENSOR_INVALID_RES;
+		s_ctrl->cam_mode = mode;
+
+		s_ctrl->prev_frame_length_lines =
+			msm_sensor_read_b_conf_wdata(s_ctrl,
+				s_ctrl->prev_res,
+				s_ctrl->frame_length_lines_array_addr);
+		s_ctrl->prev_line_length_pck =
+			msm_sensor_read_b_conf_wdata(s_ctrl,
+				s_ctrl->prev_res,
+				s_ctrl->line_length_pck_array_addr);
+
+		s_ctrl->snap_frame_length_lines =
+			msm_sensor_read_b_conf_wdata(s_ctrl,
+				s_ctrl->pict_res,
+				s_ctrl->frame_length_lines_array_addr);
+
+		s_ctrl->snap_line_length_pck =
+			msm_sensor_read_b_conf_wdata(s_ctrl,
+				s_ctrl->pict_res,
+				s_ctrl->line_length_pck_array_addr);
+
+
+		rc = s_ctrl->func_tbl.sensor_setting(s_ctrl,
+			MSM_SENSOR_REG_INIT, s_ctrl->prev_res);
+	}
+	return rc;
+}
+
+int32_t msm_sensor_mode_init_wdata(struct msm_sensor_ctrl_t *s_ctrl,
+			int mode, struct sensor_init_cfg *init_info)
+{
+	int32_t rc = 0;
+	CDBG("%s: %d\n", __func__, __LINE__);
+	if (mode != s_ctrl->cam_mode) {
+		if (init_info->prev_res >=
+			s_ctrl->msm_sensor_reg.num_conf ||
+			init_info->pict_res >=
+			s_ctrl->msm_sensor_reg.num_conf) {
+			CDBG("Resolution does not exist");
+			return -EINVAL;
+		}
+
+		s_ctrl->prev_res = init_info->prev_res;
+		s_ctrl->pict_res = init_info->pict_res;
+		s_ctrl->curr_res = MSM_SENSOR_INVALID_RES;
+		s_ctrl->cam_mode = mode;
+
+		s_ctrl->prev_frame_length_lines =
+			msm_sensor_read_w_conf_wdata(s_ctrl,
+				s_ctrl->prev_res,
+				s_ctrl->frame_length_lines_array_addr);
+		s_ctrl->prev_line_length_pck =
+			msm_sensor_read_w_conf_wdata(s_ctrl,
+				s_ctrl->prev_res,
+				s_ctrl->line_length_pck_array_addr);
+
+		s_ctrl->snap_frame_length_lines =
+			msm_sensor_read_w_conf_wdata(s_ctrl,
+				s_ctrl->pict_res,
+				s_ctrl->frame_length_lines_array_addr);
+
+		s_ctrl->snap_line_length_pck =
+			msm_sensor_read_w_conf_wdata(s_ctrl,
+				s_ctrl->pict_res,
+				s_ctrl->line_length_pck_array_addr);
+
+
+		rc = s_ctrl->func_tbl.sensor_setting(s_ctrl,
+			MSM_SENSOR_REG_INIT, s_ctrl->prev_res);
+	}
+	return rc;
+}
+
+int32_t msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp)
+{
+	struct sensor_cfg_data cdata;
+	long   rc = 0;
+	if (copy_from_user(&cdata,
+		(void *)argp,
+		sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+	mutex_lock(s_ctrl->msm_sensor_mutex);
+	CDBG("msm_sensor_config: cfgtype = %d\n",
+	cdata.cfgtype);
+		switch (cdata.cfgtype) {
+		case CFG_GET_PICT_FPS:
+			s_ctrl->func_tbl.
+			sensor_get_pict_fps(
+				s_ctrl,
+				cdata.cfg.gfps.prevfps,
+				&(cdata.cfg.gfps.pictfps));
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PREV_L_PF:
+			cdata.cfg.prevl_pf =
+				s_ctrl->func_tbl.
+				sensor_get_prev_lines_pf
+				(s_ctrl);
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PREV_P_PL:
+			cdata.cfg.prevp_pl =
+				s_ctrl->func_tbl.
+				sensor_get_prev_pixels_pl
+				(s_ctrl);
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PICT_L_PF:
+			cdata.cfg.pictl_pf =
+				s_ctrl->func_tbl.
+				sensor_get_pict_lines_pf
+				(s_ctrl);
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PICT_P_PL:
+			cdata.cfg.pictp_pl =
+				s_ctrl->func_tbl.
+				sensor_get_pict_pixels_pl
+				(s_ctrl);
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PICT_MAX_EXP_LC:
+			cdata.cfg.pict_max_exp_lc =
+				s_ctrl->func_tbl.
+				sensor_get_pict_max_exp_lc
+				(s_ctrl);
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_SET_FPS:
+		case CFG_SET_PICT_FPS:
+			rc = s_ctrl->func_tbl.
+				sensor_set_fps(
+				s_ctrl,
+				&(cdata.cfg.fps));
+			break;
+
+		case CFG_SET_EXP_GAIN:
+			rc =
+				s_ctrl->func_tbl.
+				sensor_write_exp_gain(
+					s_ctrl,
+					cdata.cfg.exp_gain.gain,
+					cdata.cfg.exp_gain.line);
+			break;
+
+		case CFG_SET_PICT_EXP_GAIN:
+			rc =
+				s_ctrl->func_tbl.
+				sensor_write_exp_gain(
+					s_ctrl,
+					cdata.cfg.exp_gain.gain,
+					cdata.cfg.exp_gain.line);
+			break;
+
+		case CFG_SET_MODE:
+			rc = s_ctrl->func_tbl.
+				sensor_set_sensor_mode(
+					s_ctrl,
+					cdata.mode,
+					cdata.rs);
+			break;
+
+		case CFG_PWR_DOWN:
+			break;
+
+		case CFG_MOVE_FOCUS:
+			break;
+
+		case CFG_SET_DEFAULT_FOCUS:
+			break;
+
+		case CFG_GET_AF_MAX_STEPS:
+			cdata.max_steps = 32;
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_SET_EFFECT:
+			break;
+
+
+		case CFG_SEND_WB_INFO:
+			break;
+
+		case CFG_SENSOR_INIT:
+			rc = s_ctrl->func_tbl.
+				sensor_mode_init(
+				s_ctrl,
+				cdata.mode,
+				&(cdata.cfg.init_info));
+			break;
+
+		default:
+			rc = -EFAULT;
+			break;
+		}
+
+	mutex_unlock(s_ctrl->msm_sensor_mutex);
+
+	return rc;
+}
+
+int16_t msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int rc = 0;
+	uint16_t chipid = 0;
+	rc = msm_sensor_i2c_waddr_read_w(s_ctrl,
+			s_ctrl->sensor_id_addr, &chipid);
+	CDBG("msm_sensor id: %d\n", chipid);
+	if (chipid != s_ctrl->sensor_id) {
+		CDBG("msm_sensor_match_id chip id doesnot match\n");
+		return -ENODEV;
+	}
+	return rc;
+}
+
+int msm_sensor_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int rc = 0;
+	struct msm_sensor_ctrl_t *this_ctrl;
+	CDBG("%s_i2c_probe called\n", client->name);
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		CDBG("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	this_ctrl = (struct msm_sensor_ctrl_t *)(id->driver_data);
+	this_ctrl->msm_sensor_client = client;
+	return 0;
+
+probe_failure:
+	CDBG("%s_i2c_probe failed\n", client->name);
+	return rc;
+}
+
+int msm_sensor_probe(struct msm_sensor_ctrl_t *s_ctrl,
+		const struct msm_camera_sensor_info *info,
+		struct msm_sensor_ctrl *s)
+{
+	int rc = 0;
+	rc = i2c_add_driver(s_ctrl->msm_sensor_i2c_driver);
+	if (rc < 0 || s_ctrl->msm_sensor_client == NULL) {
+		rc = -ENOTSUPP;
+		CDBG("I2C add driver failed");
+		goto probe_fail;
+	}
+
+	rc = s_ctrl->func_tbl.sensor_power_up(info);
+	if (rc < 0)
+		goto probe_fail;
+	s->s_init = s_ctrl->func_tbl.sensor_open_init;
+	s->s_release = s_ctrl->func_tbl.sensor_release;
+	s->s_config  = s_ctrl->func_tbl.sensor_config;
+	s->s_camera_type = s_ctrl->camera_type;
+	s->s_mount_angle = 0;
+	s_ctrl->func_tbl.sensor_power_down(info);
+	return rc;
+probe_fail:
+	return rc;
+}
+
+int msm_sensor_v4l2_probe(struct msm_sensor_ctrl_t *s_ctrl,
+	const struct msm_camera_sensor_info *info,
+	struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s)
+{
+	int rc = 0;
+	rc = s_ctrl->func_tbl.sensor_probe(s_ctrl, info, s);
+	if (rc < 0)
+		return rc;
+
+	s_ctrl->sensor_v4l2_subdev = sdev;
+	v4l2_i2c_subdev_init(s_ctrl->sensor_v4l2_subdev,
+		s_ctrl->msm_sensor_client, s_ctrl->sensor_v4l2_subdev_ops);
+	s_ctrl->sensor_v4l2_subdev->dev_priv = (void *) s_ctrl;
+	return rc;
+}
+
+int msm_sensor_v4l2_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+			   enum v4l2_mbus_pixelcode *code)
+{
+	struct msm_sensor_ctrl_t *s_ctrl =
+		(struct msm_sensor_ctrl_t *) sd->dev_priv;
+	if ((unsigned int)index >= s_ctrl->sensor_v4l2_subdev_info_size)
+		return -EINVAL;
+
+	*code = s_ctrl->sensor_v4l2_subdev_info[index].code;
+	return 0;
+}
+
+static int msm_sensor_debugfs_stream_s(void *data, u64 val)
+{
+	struct msm_sensor_ctrl_t *s_ctrl = (struct msm_sensor_ctrl_t *) data;
+	if (val)
+		s_ctrl->func_tbl.sensor_start_stream(s_ctrl);
+	else
+		s_ctrl->func_tbl.sensor_stop_stream(s_ctrl);
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(sensor_debugfs_stream, NULL,
+			msm_sensor_debugfs_stream_s, "%llu\n");
+
+static int msm_sensor_debugfs_test_s(void *data, u64 val)
+{
+	CDBG("val: %llu\n", val);
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(sensor_debugfs_test, NULL,
+			msm_sensor_debugfs_test_s, "%llu\n");
+
+int msm_sensor_enable_debugfs(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	struct dentry *debugfs_base, *sensor_dir;
+	debugfs_base = debugfs_create_dir("msm_sensor", NULL);
+	if (!debugfs_base)
+		return -ENOMEM;
+
+	sensor_dir = debugfs_create_dir
+		(s_ctrl->sensordata->sensor_name, debugfs_base);
+	if (!sensor_dir)
+		return -ENOMEM;
+
+	if (!debugfs_create_file("stream", S_IRUGO | S_IWUSR, sensor_dir,
+			(void *) s_ctrl, &sensor_debugfs_stream))
+		return -ENOMEM;
+
+	if (!debugfs_create_file("test", S_IRUGO | S_IWUSR, sensor_dir,
+			(void *) s_ctrl, &sensor_debugfs_test))
+		return -ENOMEM;
+
+	return 0;
+}
diff --git a/drivers/media/video/msm/msm_sensor.h b/drivers/media/video/msm/msm_sensor.h
new file mode 100644
index 0000000..d8224ce
--- /dev/null
+++ b/drivers/media/video/msm/msm_sensor.h
@@ -0,0 +1,246 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/i2c.h>
+#include <linux/debugfs.h>
+#include <mach/camera.h>
+#include <media/msm_camera.h>
+#include <media/v4l2-subdev.h>
+#define Q8  0x00000100
+#define Q10 0x00000400
+
+enum msm_sensor_resolution_t {
+	MSM_SENSOR_RES_0,
+	MSM_SENSOR_RES_1,
+	MSM_SENSOR_RES_2,
+	MSM_SENSOR_RES_3,
+	MSM_SENSOR_RES_4,
+	MSM_SENSOR_RES_5,
+	MSM_SENSOR_RES_6,
+	MSM_SENSOR_RES_7,
+	MSM_SENSOR_INVALID_RES,
+};
+
+#define MSM_SENSOR_MCLK_8HZ 8000000
+#define MSM_SENSOR_MCLK_16HZ 16000000
+#define MSM_SENSOR_MCLK_24HZ 24000000
+
+enum msm_sensor_reg_update {
+	/* Sensor egisters that need to be updated during initialization */
+	MSM_SENSOR_REG_INIT,
+	/* Sensor egisters that needs periodic I2C writes */
+	MSM_SENSOR_UPDATE_PERIODIC,
+	/* All the sensor Registers will be updated */
+	MSM_SENSOR_UPDATE_ALL,
+	/* Not valid update */
+	MSM_SENSOR_UPDATE_INVALID
+};
+
+enum msm_sensor_cam_mode_t {
+	MSM_SENSOR_MODE_2D_RIGHT,
+	MSM_SENSOR_MODE_2D_LEFT,
+	MSM_SENSOR_MODE_3D,
+	MSM_SENSOR_MODE_INVALID
+};
+
+struct msm_sensor_i2c_reg_conf {
+	unsigned short reg_addr;
+	unsigned short reg_data;
+};
+
+struct msm_sensor_i2c_conf_array {
+	struct msm_sensor_i2c_reg_conf *conf;
+	unsigned short size;
+	unsigned short delay;
+};
+
+struct msm_sensor_reg_t {
+	struct msm_sensor_i2c_reg_conf *start_stream_conf;
+	uint8_t start_stream_conf_size;
+	struct msm_sensor_i2c_reg_conf *stop_stream_conf;
+	uint8_t stop_stream_conf_size;
+	struct msm_sensor_i2c_reg_conf *group_hold_on_conf;
+	uint8_t group_hold_on_conf_size;
+	struct msm_sensor_i2c_reg_conf *group_hold_off_conf;
+	uint8_t group_hold_off_conf_size;
+	struct msm_sensor_i2c_conf_array *init_settings;
+	uint8_t init_size;
+	struct msm_sensor_i2c_conf_array *res_settings;
+	uint8_t num_conf;
+};
+
+struct v4l2_subdev_info {
+	enum v4l2_mbus_pixelcode code;
+	enum v4l2_colorspace colorspace;
+	uint16_t fmt;
+	uint16_t order;
+};
+
+struct msm_sensor_ctrl_t {
+	const struct  msm_camera_sensor_info *sensordata;
+	struct i2c_client *msm_sensor_client;
+	struct i2c_driver *msm_sensor_i2c_driver;
+	struct msm_sensor_reg_t msm_sensor_reg;
+
+	uint16_t sensor_id_addr;
+	uint16_t sensor_id;
+	uint16_t frame_length_lines_addr;
+	uint16_t line_length_pck_addr;
+	uint16_t global_gain_addr;
+	uint16_t coarse_int_time_addr;
+
+	uint8_t frame_length_lines_array_addr;
+	uint8_t line_length_pck_array_addr;
+
+	uint16_t curr_line_length_pck;
+	uint16_t curr_frame_length_lines;
+	uint16_t prev_line_length_pck;
+	uint16_t prev_frame_length_lines;
+	uint16_t snap_line_length_pck;
+	uint16_t snap_frame_length_lines;
+	uint16_t vert_offset;
+
+	uint16_t fps;
+	uint32_t fps_divider;
+	enum msm_sensor_resolution_t prev_res;
+	enum msm_sensor_resolution_t pict_res;
+	enum msm_sensor_resolution_t curr_res;
+	enum msm_sensor_cam_mode_t cam_mode;
+	enum msm_camera_type camera_type;
+
+	struct mutex *msm_sensor_mutex;
+	bool config_csi_flag;
+	struct msm_camera_csi_params *csi_params;
+
+	/*To Do: Changing v4l2_subdev to a pointer according to yupeng*/
+	struct v4l2_subdev *sensor_v4l2_subdev;
+	struct v4l2_subdev_info *sensor_v4l2_subdev_info;
+	uint8_t sensor_v4l2_subdev_info_size;
+	struct v4l2_subdev_ops *sensor_v4l2_subdev_ops;
+
+	struct msm_sensor_fn_t {
+		void (*sensor_start_stream) (struct msm_sensor_ctrl_t *);
+		void (*sensor_stop_stream) (struct msm_sensor_ctrl_t *);
+		void (*sensor_group_hold_on) (struct msm_sensor_ctrl_t *);
+		void (*sensor_group_hold_off) (struct msm_sensor_ctrl_t *);
+
+		uint16_t (*sensor_get_prev_lines_pf)
+			(struct msm_sensor_ctrl_t *);
+		uint16_t (*sensor_get_prev_pixels_pl)
+			(struct msm_sensor_ctrl_t *);
+		uint16_t (*sensor_get_pict_lines_pf)
+			(struct msm_sensor_ctrl_t *);
+		uint16_t (*sensor_get_pict_pixels_pl)
+			(struct msm_sensor_ctrl_t *);
+		uint32_t (*sensor_get_pict_max_exp_lc)
+			(struct msm_sensor_ctrl_t *);
+		void (*sensor_get_pict_fps) (struct msm_sensor_ctrl_t *,
+				uint16_t, uint16_t *);
+		int32_t (*sensor_set_fps) (struct msm_sensor_ctrl_t *,
+				struct fps_cfg *);
+		int32_t (*sensor_write_exp_gain) (struct msm_sensor_ctrl_t *,
+				uint16_t, uint32_t);
+		int32_t (*sensor_setting) (struct msm_sensor_ctrl_t *,
+				int update_type, int rt);
+		int32_t (*sensor_set_sensor_mode)
+				(struct msm_sensor_ctrl_t *, int, int);
+		int32_t (*sensor_mode_init) (struct msm_sensor_ctrl_t *,
+			int, struct sensor_init_cfg *);
+		int (*sensor_config) (void __user *);
+		int (*sensor_open_init) (const struct msm_camera_sensor_info *);
+		int (*sensor_release) (void);
+		int (*sensor_power_down)
+			(const struct msm_camera_sensor_info *);
+		int (*sensor_power_up) (const struct msm_camera_sensor_info *);
+		int (*sensor_probe) (struct msm_sensor_ctrl_t *s_ctrl,
+				const struct msm_camera_sensor_info *info,
+				struct msm_sensor_ctrl *s);
+	} func_tbl;
+};
+
+int32_t msm_sensor_i2c_rxdata(struct msm_sensor_ctrl_t *s_ctrl,
+	unsigned char *rxdata, int length);
+
+int32_t msm_sensor_i2c_txdata(struct msm_sensor_ctrl_t *s_ctrl,
+	unsigned char *txdata, int length);
+
+int32_t msm_sensor_i2c_waddr_write_b(struct msm_sensor_ctrl_t *s_ctrl,
+	uint16_t waddr, uint8_t bdata);
+
+int32_t msm_sensor_i2c_waddr_write_w(struct msm_sensor_ctrl_t *s_ctrl,
+	uint16_t waddr, uint16_t wdata);
+
+int32_t msm_sensor_i2c_waddr_read_w(struct msm_sensor_ctrl_t *s_ctrl,
+	uint16_t waddr, uint16_t *data);
+
+int32_t msm_sensor_i2c_waddr_write_b_tbl(struct msm_sensor_ctrl_t *s_ctrl,
+	struct msm_sensor_i2c_reg_conf const *reg_conf_tbl, uint8_t size);
+
+int32_t msm_sensor_i2c_waddr_write_w_tbl(struct msm_sensor_ctrl_t *s_ctrl,
+	struct msm_sensor_i2c_reg_conf const *reg_conf_tbl, uint8_t size);
+
+void msm_sensor_start_stream(struct msm_sensor_ctrl_t *s_ctrl);
+void msm_sensor_stop_stream(struct msm_sensor_ctrl_t *s_ctrl);
+void msm_sensor_group_hold_on(struct msm_sensor_ctrl_t *s_ctrl);
+void msm_sensor_group_hold_off(struct msm_sensor_ctrl_t *s_ctrl);
+
+uint16_t msm_sensor_get_prev_lines_pf(struct msm_sensor_ctrl_t *s_ctrl);
+uint16_t msm_sensor_get_prev_pixels_pl(struct msm_sensor_ctrl_t *s_ctrl);
+uint16_t msm_sensor_get_pict_lines_pf(struct msm_sensor_ctrl_t *s_ctrl);
+uint16_t msm_sensor_get_pict_pixels_pl(struct msm_sensor_ctrl_t *s_ctrl);
+uint32_t msm_sensor_get_pict_max_exp_lc(struct msm_sensor_ctrl_t *s_ctrl);
+void msm_sensor_get_pict_fps(struct msm_sensor_ctrl_t *s_ctrl,
+			uint16_t fps, uint16_t *pfps);
+int32_t msm_sensor_set_fps(struct msm_sensor_ctrl_t *s_ctrl,
+			struct fps_cfg   *fps);
+int32_t msm_sensor_write_exp_gain1(struct msm_sensor_ctrl_t *s_ctrl,
+		uint16_t gain, uint32_t line);
+int32_t msm_sensor_write_exp_gain2(struct msm_sensor_ctrl_t *s_ctrl,
+		uint16_t gain, uint32_t line);
+int32_t msm_sensor_set_sensor_mode_b(struct msm_sensor_ctrl_t *s_ctrl,
+	int mode, int res);
+int32_t msm_sensor_set_sensor_mode_w(struct msm_sensor_ctrl_t *s_ctrl,
+	int mode, int res);
+int32_t msm_sensor_mode_init_bdata(struct msm_sensor_ctrl_t *s_ctrl,
+			int mode, struct sensor_init_cfg *init_info);
+int32_t msm_sensor_mode_init_wdata(struct msm_sensor_ctrl_t *s_ctrl,
+			int mode, struct sensor_init_cfg *init_info);
+int32_t msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl,
+			void __user *argp);
+int16_t msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl);
+uint16_t msm_sensor_read_b_conf_wdata(struct msm_sensor_ctrl_t *s_ctrl,
+			enum msm_sensor_resolution_t res, int8_t array_addr);
+uint16_t msm_sensor_read_w_conf_wdata(struct msm_sensor_ctrl_t *s_ctrl,
+			enum msm_sensor_resolution_t res, int8_t array_addr);
+
+int msm_sensor_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id);
+
+int msm_sensor_probe(struct msm_sensor_ctrl_t *s_ctrl,
+		const struct msm_camera_sensor_info *info,
+		struct msm_sensor_ctrl *s);
+
+int msm_sensor_v4l2_probe(struct msm_sensor_ctrl_t *s_ctrl,
+	const struct msm_camera_sensor_info *info,
+	struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s);
+
+int msm_sensor_v4l2_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+			enum v4l2_mbus_pixelcode *code);
+
+int msm_sensor_write_b_init_settings(struct msm_sensor_ctrl_t *s_ctrl);
+int msm_sensor_write_w_init_settings(struct msm_sensor_ctrl_t *s_ctrl);
+int msm_sensor_write_b_res_settings
+	(struct msm_sensor_ctrl_t *s_ctrl, uint16_t res);
+int msm_sensor_write_w_res_settings
+	(struct msm_sensor_ctrl_t *s_ctrl, uint16_t res);
+
+int msm_sensor_enable_debugfs(struct msm_sensor_ctrl_t *s_ctrl);
diff --git a/drivers/media/video/msm/msm_vfe31.c b/drivers/media/video/msm/msm_vfe31.c
new file mode 100644
index 0000000..aa35096
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe31.c
@@ -0,0 +1,3729 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <mach/irqs.h>
+#include <mach/camera.h>
+#include <mach/msm_reqs.h>
+#include <asm/atomic.h>
+
+#include "msm_vfe31.h"
+#include "msm_vpe1.h"
+
+atomic_t irq_cnt;
+
+#define CHECKED_COPY_FROM_USER(in) {					\
+	if (copy_from_user((in), (void __user *)cmd->value,		\
+			cmd->length)) {					\
+		rc = -EFAULT;						\
+		break;							\
+	}								\
+}
+
+static struct vfe31_ctrl_type *vfe31_ctrl;
+static struct msm_camera_io_clk camio_clk;
+static void *vfe_syncdata;
+static void vfe31_send_msg_no_payload(enum VFE31_MESSAGE_ID id);
+static void vfe31_reset_hist_cfg(void);
+
+struct vfe31_isr_queue_cmd {
+	struct list_head list;
+	uint32_t                           vfeInterruptStatus0;
+	uint32_t                           vfeInterruptStatus1;
+	uint32_t                           vfePingPongStatus;
+	struct vfe_frame_asf_info          vfeAsfFrameInfo;
+	struct vfe_frame_bpc_info          vfeBpcFrameInfo;
+	struct vfe_msg_camif_status        vfeCamifStatusLocal;
+};
+
+static struct vfe31_cmd_type vfe31_cmd[] = {
+/* 0*/	{V31_DUMMY_0},
+		{V31_SET_CLK},
+		{V31_RESET},
+		{V31_START},
+		{V31_TEST_GEN_START},
+/* 5*/	{V31_OPERATION_CFG, V31_OPERATION_CFG_LEN},
+		{V31_AXI_OUT_CFG, V31_AXI_OUT_LEN, V31_AXI_OUT_OFF, 0xFF},
+		{V31_CAMIF_CFG, V31_CAMIF_LEN, V31_CAMIF_OFF, 0xFF},
+		{V31_AXI_INPUT_CFG},
+		{V31_BLACK_LEVEL_CFG, V31_BLACK_LEVEL_LEN, V31_BLACK_LEVEL_OFF,
+		0xFF},
+/*10*/  {V31_ROLL_OFF_CFG, V31_ROLL_OFF_CFG_LEN, V31_ROLL_OFF_CFG_OFF,
+		0xFF},
+		{V31_DEMUX_CFG, V31_DEMUX_LEN, V31_DEMUX_OFF, 0xFF},
+		{V31_DEMOSAIC_0_CFG, V31_DEMOSAIC_0_LEN, V31_DEMOSAIC_0_OFF,
+		0xFF},
+		{V31_DEMOSAIC_1_CFG, V31_DEMOSAIC_1_LEN, V31_DEMOSAIC_1_OFF,
+		0xFF},
+		{V31_DEMOSAIC_2_CFG, V31_DEMOSAIC_2_LEN, V31_DEMOSAIC_2_OFF,
+		0xFF},
+/*15*/	{V31_FOV_CFG, V31_FOV_LEN, V31_FOV_OFF, 0xFF},
+		{V31_MAIN_SCALER_CFG, V31_MAIN_SCALER_LEN, V31_MAIN_SCALER_OFF,
+		0xFF},
+		{V31_WB_CFG, V31_WB_LEN, V31_WB_OFF, 0xFF},
+		{V31_COLOR_COR_CFG, V31_COLOR_COR_LEN, V31_COLOR_COR_OFF, 0xFF},
+		{V31_RGB_G_CFG, V31_RGB_G_LEN, V31_RGB_G_OFF, 0xFF},
+/*20*/	{V31_LA_CFG, V31_LA_LEN, V31_LA_OFF, 0xFF },
+		{V31_CHROMA_EN_CFG, V31_CHROMA_EN_LEN, V31_CHROMA_EN_OFF, 0xFF},
+		{V31_CHROMA_SUP_CFG, V31_CHROMA_SUP_LEN, V31_CHROMA_SUP_OFF,
+		0xFF},
+		{V31_MCE_CFG, V31_MCE_LEN, V31_MCE_OFF, 0xFF},
+		{V31_SK_ENHAN_CFG, V31_SCE_LEN, V31_SCE_OFF, 0xFF},
+/*25*/	{V31_ASF_CFG, V31_ASF_LEN, V31_ASF_OFF, 0xFF},
+		{V31_S2Y_CFG, V31_S2Y_LEN, V31_S2Y_OFF, 0xFF},
+		{V31_S2CbCr_CFG, V31_S2CbCr_LEN, V31_S2CbCr_OFF, 0xFF},
+		{V31_CHROMA_SUBS_CFG, V31_CHROMA_SUBS_LEN, V31_CHROMA_SUBS_OFF,
+		0xFF},
+		{V31_OUT_CLAMP_CFG, V31_OUT_CLAMP_LEN, V31_OUT_CLAMP_OFF,
+		0xFF},
+/*30*/	{V31_FRAME_SKIP_CFG, V31_FRAME_SKIP_LEN, V31_FRAME_SKIP_OFF,
+		0xFF},
+		{V31_DUMMY_1},
+		{V31_DUMMY_2},
+		{V31_DUMMY_3},
+		{V31_UPDATE},
+/*35*/	{V31_BL_LVL_UPDATE, V31_BLACK_LEVEL_LEN, V31_BLACK_LEVEL_OFF,
+		0xFF},
+		{V31_DEMUX_UPDATE, V31_DEMUX_LEN, V31_DEMUX_OFF, 0xFF},
+		{V31_DEMOSAIC_1_UPDATE, V31_DEMOSAIC_1_LEN, V31_DEMOSAIC_1_OFF,
+		0xFF},
+		{V31_DEMOSAIC_2_UPDATE, V31_DEMOSAIC_2_LEN, V31_DEMOSAIC_2_OFF,
+		0xFF},
+		{V31_FOV_UPDATE, V31_FOV_LEN, V31_FOV_OFF, 0xFF},
+/*40*/	{V31_MAIN_SCALER_UPDATE, V31_MAIN_SCALER_LEN, V31_MAIN_SCALER_OFF,
+		0xFF},
+		{V31_WB_UPDATE, V31_WB_LEN, V31_WB_OFF, 0xFF},
+		{V31_COLOR_COR_UPDATE, V31_COLOR_COR_LEN, V31_COLOR_COR_OFF,
+		0xFF},
+		{V31_RGB_G_UPDATE, V31_RGB_G_LEN, V31_CHROMA_EN_OFF, 0xFF},
+		{V31_LA_UPDATE, V31_LA_LEN, V31_LA_OFF, 0xFF },
+/*45*/	{V31_CHROMA_EN_UPDATE, V31_CHROMA_EN_LEN, V31_CHROMA_EN_OFF,
+		0xFF},
+		{V31_CHROMA_SUP_UPDATE, V31_CHROMA_SUP_LEN, V31_CHROMA_SUP_OFF,
+		0xFF},
+		{V31_MCE_UPDATE, V31_MCE_LEN, V31_MCE_OFF, 0xFF},
+		{V31_SK_ENHAN_UPDATE, V31_SCE_LEN, V31_SCE_OFF, 0xFF},
+		{V31_S2CbCr_UPDATE, V31_S2CbCr_LEN, V31_S2CbCr_OFF, 0xFF},
+/*50*/	{V31_S2Y_UPDATE, V31_S2Y_LEN, V31_S2Y_OFF, 0xFF},
+		{V31_ASF_UPDATE, V31_ASF_UPDATE_LEN, V31_ASF_OFF, 0xFF},
+		{V31_FRAME_SKIP_UPDATE},
+		{V31_CAMIF_FRAME_UPDATE},
+		{V31_STATS_AF_UPDATE, V31_STATS_AF_LEN, V31_STATS_AF_OFF},
+/*55*/	{V31_STATS_AE_UPDATE, V31_STATS_AE_LEN, V31_STATS_AE_OFF},
+		{V31_STATS_AWB_UPDATE, V31_STATS_AWB_LEN, V31_STATS_AWB_OFF},
+		{V31_STATS_RS_UPDATE, V31_STATS_RS_LEN, V31_STATS_RS_OFF},
+		{V31_STATS_CS_UPDATE, V31_STATS_CS_LEN, V31_STATS_CS_OFF},
+		{V31_STATS_SKIN_UPDATE},
+/*60*/	{V31_STATS_IHIST_UPDATE, V31_STATS_IHIST_LEN, V31_STATS_IHIST_OFF},
+		{V31_DUMMY_4},
+		{V31_EPOCH1_ACK},
+		{V31_EPOCH2_ACK},
+		{V31_START_RECORDING},
+/*65*/	{V31_STOP_RECORDING},
+		{V31_DUMMY_5},
+		{V31_DUMMY_6},
+		{V31_CAPTURE, V31_CAPTURE_LEN, 0xFF},
+		{V31_DUMMY_7},
+/*70*/	{V31_STOP},
+		{V31_GET_HW_VERSION},
+		{V31_GET_FRAME_SKIP_COUNTS},
+		{V31_OUTPUT1_BUFFER_ENQ},
+		{V31_OUTPUT2_BUFFER_ENQ},
+/*75*/	{V31_OUTPUT3_BUFFER_ENQ},
+		{V31_JPEG_OUT_BUF_ENQ},
+		{V31_RAW_OUT_BUF_ENQ},
+		{V31_RAW_IN_BUF_ENQ},
+		{V31_STATS_AF_ENQ},
+/*80*/	{V31_STATS_AE_ENQ},
+		{V31_STATS_AWB_ENQ},
+		{V31_STATS_RS_ENQ},
+		{V31_STATS_CS_ENQ},
+		{V31_STATS_SKIN_ENQ},
+/*85*/	{V31_STATS_IHIST_ENQ},
+		{V31_DUMMY_8},
+		{V31_JPEG_ENC_CFG},
+		{V31_DUMMY_9},
+		{V31_STATS_AF_START, V31_STATS_AF_LEN, V31_STATS_AF_OFF},
+/*90*/	{V31_STATS_AF_STOP},
+		{V31_STATS_AE_START, V31_STATS_AE_LEN, V31_STATS_AE_OFF},
+		{V31_STATS_AE_STOP},
+		{V31_STATS_AWB_START, V31_STATS_AWB_LEN, V31_STATS_AWB_OFF},
+		{V31_STATS_AWB_STOP},
+/*95*/	{V31_STATS_RS_START, V31_STATS_RS_LEN, V31_STATS_RS_OFF},
+		{V31_STATS_RS_STOP},
+		{V31_STATS_CS_START, V31_STATS_CS_LEN, V31_STATS_CS_OFF},
+		{V31_STATS_CS_STOP},
+		{V31_STATS_SKIN_START},
+/*100*/	{V31_STATS_SKIN_STOP},
+		{V31_STATS_IHIST_START,
+		V31_STATS_IHIST_LEN, V31_STATS_IHIST_OFF},
+		{V31_STATS_IHIST_STOP},
+		{V31_DUMMY_10},
+		{V31_SYNC_TIMER_SETTING, V31_SYNC_TIMER_LEN,
+			V31_SYNC_TIMER_OFF},
+/*105*/	{V31_ASYNC_TIMER_SETTING, V31_ASYNC_TIMER_LEN, V31_ASYNC_TIMER_OFF},
+		{V31_LIVESHOT},
+		{V31_ZSL, V31_CAPTURE_LEN, 0xFF},
+		{V31_STEREOCAM},
+		{V31_LA_SETUP},
+/*110*/	{V31_XBAR_CFG, V31_XBAR_CFG_LEN, V31_XBAR_CFG_OFF},
+/*111*/	{V31_EZTUNE_CFG, V31_EZTUNE_CFG_LEN, V31_EZTUNE_CFG_OFF},
+};
+
+uint32_t vfe31_AXI_WM_CFG[] = {
+	0x0000004C,
+	0x00000064,
+	0x0000007C,
+	0x00000094,
+	0x000000AC,
+	0x000000C4,
+	0x000000DC,
+};
+
+static const char *vfe31_general_cmd[] = {
+	"DUMMY_0",  /* 0 */
+	"SET_CLK",
+	"RESET",
+	"START",
+	"TEST_GEN_START",
+	"OPERATION_CFG",  /* 5 */
+	"AXI_OUT_CFG",
+	"CAMIF_CFG",
+	"AXI_INPUT_CFG",
+	"BLACK_LEVEL_CFG",
+	"ROLL_OFF_CFG",  /* 10 */
+	"DEMUX_CFG",
+	"DEMOSAIC_0_CFG",  /* general */
+	"DEMOSAIC_1_CFG",  /* ABF     */
+	"DEMOSAIC_2_CFG",  /* BPC     */
+	"FOV_CFG",  /* 15  */
+	"MAIN_SCALER_CFG",
+	"WB_CFG",
+	"COLOR_COR_CFG",
+	"RGB_G_CFG",
+	"LA_CFG",  /* 20 */
+	"CHROMA_EN_CFG",
+	"CHROMA_SUP_CFG",
+	"MCE_CFG",
+	"SK_ENHAN_CFG",
+	"ASF_CFG",  /* 25 */
+	"S2Y_CFG",
+	"S2CbCr_CFG",
+	"CHROMA_SUBS_CFG",
+	"OUT_CLAMP_CFG",
+	"FRAME_SKIP_CFG",  /* 30 */
+	"DUMMY_1",
+	"DUMMY_2",
+	"DUMMY_3",
+	"UPDATE",
+	"BL_LVL_UPDATE",  /* 35 */
+	"DEMUX_UPDATE",
+	"DEMOSAIC_1_UPDATE",  /* BPC */
+	"DEMOSAIC_2_UPDATE",  /* ABF */
+	"FOV_UPDATE",
+	"MAIN_SCALER_UPDATE",  /* 40 */
+	"WB_UPDATE",
+	"COLOR_COR_UPDATE",
+	"RGB_G_UPDATE",
+	"LA_UPDATE",
+	"CHROMA_EN_UPDATE",  /* 45 */
+	"CHROMA_SUP_UPDATE",
+	"MCE_UPDATE",
+	"SK_ENHAN_UPDATE",
+	"S2CbCr_UPDATE",
+	"S2Y_UPDATE",  /* 50 */
+	"ASF_UPDATE",
+	"FRAME_SKIP_UPDATE",
+	"CAMIF_FRAME_UPDATE",
+	"STATS_AF_UPDATE",
+	"STATS_AE_UPDATE",  /* 55 */
+	"STATS_AWB_UPDATE",
+	"STATS_RS_UPDATE",
+	"STATS_CS_UPDATE",
+	"STATS_SKIN_UPDATE",
+	"STATS_IHIST_UPDATE",  /* 60 */
+	"DUMMY_4",
+	"EPOCH1_ACK",
+	"EPOCH2_ACK",
+	"START_RECORDING",
+	"STOP_RECORDING",  /* 65 */
+	"DUMMY_5",
+	"DUMMY_6",
+	"CAPTURE",
+	"DUMMY_7",
+	"STOP",  /* 70 */
+	"GET_HW_VERSION",
+	"GET_FRAME_SKIP_COUNTS",
+	"OUTPUT1_BUFFER_ENQ",
+	"OUTPUT2_BUFFER_ENQ",
+	"OUTPUT3_BUFFER_ENQ",  /* 75 */
+	"JPEG_OUT_BUF_ENQ",
+	"RAW_OUT_BUF_ENQ",
+	"RAW_IN_BUF_ENQ",
+	"STATS_AF_ENQ",
+	"STATS_AE_ENQ",  /* 80 */
+	"STATS_AWB_ENQ",
+	"STATS_RS_ENQ",
+	"STATS_CS_ENQ",
+	"STATS_SKIN_ENQ",
+	"STATS_IHIST_ENQ",  /* 85 */
+	"DUMMY_8",
+	"JPEG_ENC_CFG",
+	"DUMMY_9",
+	"STATS_AF_START",
+	"STATS_AF_STOP",  /* 90 */
+	"STATS_AE_START",
+	"STATS_AE_STOP",
+	"STATS_AWB_START",
+	"STATS_AWB_STOP",
+	"STATS_RS_START",  /* 95 */
+	"STATS_RS_STOP",
+	"STATS_CS_START",
+	"STATS_CS_STOP",
+	"STATS_SKIN_START",
+	"STATS_SKIN_STOP",  /* 100 */
+	"STATS_IHIST_START",
+	"STATS_IHIST_STOP",
+	"DUMMY_10",
+	"SYNC_TIMER_SETTING",
+	"ASYNC_TIMER_SETTING",  /* 105 */
+	"V31_LIVESHOT",
+	"V31_ZSL",
+	"V31_STEREOCAM",
+	"V31_LA_SETUP",
+	"V31_XBAR_CFG",
+};
+
+static void vfe_addr_convert(struct msm_vfe_phy_info *pinfo,
+	enum vfe_resp_msg type, void *data, void **ext, int32_t *elen)
+{
+	uint8_t outid;
+	switch (type) {
+	case VFE_MSG_OUTPUT_T:
+	case VFE_MSG_OUTPUT_P:
+	case VFE_MSG_OUTPUT_S:
+	case VFE_MSG_OUTPUT_V:
+	{
+		pinfo->output_id =
+			((struct vfe_message *)data)->_u.msgOut.output_id;
+
+		switch (type) {
+		case VFE_MSG_OUTPUT_P:
+			outid = OUTPUT_TYPE_P;
+			break;
+		case VFE_MSG_OUTPUT_V:
+			outid = OUTPUT_TYPE_V;
+			break;
+		case VFE_MSG_OUTPUT_T:
+			outid = OUTPUT_TYPE_T;
+			break;
+		case VFE_MSG_OUTPUT_S:
+			outid = OUTPUT_TYPE_S;
+			break;
+		default:
+			outid = 0xff;
+			break;
+		}
+		pinfo->output_id = outid;
+		pinfo->y_phy =
+			((struct vfe_message *)data)->_u.msgOut.yBuffer;
+		pinfo->cbcr_phy =
+			((struct vfe_message *)data)->_u.msgOut.cbcrBuffer;
+
+		pinfo->frame_id =
+		((struct vfe_message *)data)->_u.msgOut.frameCounter;
+
+		((struct vfe_msg_output *)(vfe31_ctrl->extdata))->bpcInfo =
+		((struct vfe_message *)data)->_u.msgOut.bpcInfo;
+		((struct vfe_msg_output *)(vfe31_ctrl->extdata))->asfInfo =
+		((struct vfe_message *)data)->_u.msgOut.asfInfo;
+		((struct vfe_msg_output *)(vfe31_ctrl->extdata))->frameCounter =
+		((struct vfe_message *)data)->_u.msgOut.frameCounter;
+		*ext  = vfe31_ctrl->extdata;
+		*elen = vfe31_ctrl->extlen;
+	}
+		break;
+
+	default:
+		break;
+	} /* switch */
+}
+
+
+static void vfe31_proc_ops(enum VFE31_MESSAGE_ID id, void *msg, size_t len)
+{
+	struct msm_vfe_resp *rp;
+
+	rp = vfe31_ctrl->resp->vfe_alloc(sizeof(struct msm_vfe_resp),
+		vfe31_ctrl->syncdata, GFP_ATOMIC);
+	if (!rp) {
+		CDBG("rp: cannot allocate buffer\n");
+		return;
+	}
+	CDBG("vfe31_proc_ops, msgId = %d\n", id);
+	rp->evt_msg.type   = MSM_CAMERA_MSG;
+	rp->evt_msg.msg_id = id;
+	rp->evt_msg.len    = len;
+	rp->evt_msg.data   = msg;
+
+	switch (rp->evt_msg.msg_id) {
+	case MSG_ID_SNAPSHOT_DONE:
+		rp->type = VFE_MSG_SNAPSHOT;
+		break;
+
+	case MSG_ID_OUTPUT_P:
+		rp->type = VFE_MSG_OUTPUT_P;
+		vfe_addr_convert(&(rp->phy), VFE_MSG_OUTPUT_P,
+			rp->evt_msg.data, &(rp->extdata),
+			&(rp->extlen));
+		break;
+
+	case MSG_ID_OUTPUT_T:
+		rp->type = VFE_MSG_OUTPUT_T;
+		vfe_addr_convert(&(rp->phy), VFE_MSG_OUTPUT_T,
+			rp->evt_msg.data, &(rp->extdata),
+			&(rp->extlen));
+		break;
+
+	case MSG_ID_OUTPUT_S:
+		rp->type = VFE_MSG_OUTPUT_S;
+		vfe_addr_convert(&(rp->phy), VFE_MSG_OUTPUT_S,
+			rp->evt_msg.data, &(rp->extdata),
+			&(rp->extlen));
+		break;
+
+	case MSG_ID_OUTPUT_V:
+		rp->type = VFE_MSG_OUTPUT_V;
+		vfe_addr_convert(&(rp->phy), VFE_MSG_OUTPUT_V,
+			rp->evt_msg.data, &(rp->extdata),
+			&(rp->extlen));
+		break;
+
+	case MSG_ID_COMMON:
+		rp->type = VFE_MSG_COMMON;
+		rp->stats_msg.status_bits = ((struct vfe_message *)
+			rp->evt_msg.data)->_u.msgStats.status_bits;
+		rp->stats_msg.frame_id = ((struct vfe_message *)
+			rp->evt_msg.data)->_u.msgStats.frameCounter;
+
+		rp->stats_msg.aec_buff = ((struct vfe_message *)
+			rp->evt_msg.data)->_u.msgStats.buff.aec;
+		rp->stats_msg.awb_buff = ((struct vfe_message *)
+			rp->evt_msg.data)->_u.msgStats.buff.awb;
+		rp->stats_msg.af_buff = ((struct vfe_message *)
+			rp->evt_msg.data)->_u.msgStats.buff.af;
+		rp->stats_msg.ihist_buff = ((struct vfe_message *)
+			rp->evt_msg.data)->_u.msgStats.buff.ihist;
+		rp->stats_msg.rs_buff = ((struct vfe_message *)
+			rp->evt_msg.data)->_u.msgStats.buff.rs;
+		rp->stats_msg.cs_buff = ((struct vfe_message *)
+			rp->evt_msg.data)->_u.msgStats.buff.cs;
+		break;
+
+	case MSG_ID_SYNC_TIMER0_DONE:
+		rp->type = VFE_MSG_SYNC_TIMER0;
+		break;
+
+	case MSG_ID_SYNC_TIMER1_DONE:
+		rp->type = VFE_MSG_SYNC_TIMER1;
+		break;
+
+	case MSG_ID_SYNC_TIMER2_DONE:
+		rp->type = VFE_MSG_SYNC_TIMER2;
+		break;
+
+	default:
+		rp->type = VFE_MSG_GENERAL;
+		break;
+	}
+
+	/* save the frame id.*/
+	rp->evt_msg.frame_id = rp->phy.frame_id;
+
+	vfe31_ctrl->resp->vfe_resp(rp, MSM_CAM_Q_VFE_MSG, vfe31_ctrl->syncdata,
+		GFP_ATOMIC);
+}
+
+static void vfe_send_outmsg(uint8_t msgid, uint32_t pyaddr,
+	uint32_t pcbcraddr)
+{
+	struct vfe_message msg;
+	uint8_t outid;
+
+	msg._d = msgid;   /* now the output mode is redundnat. */
+	msg._u.msgOut.frameCounter = vfe31_ctrl->vfeFrameId;
+
+	switch (msgid) {
+	case MSG_ID_OUTPUT_P:
+		outid = OUTPUT_TYPE_P;
+		break;
+	case MSG_ID_OUTPUT_V:
+		outid = OUTPUT_TYPE_V;
+		break;
+	case MSG_ID_OUTPUT_T:
+		outid = OUTPUT_TYPE_T;
+		break;
+	case MSG_ID_OUTPUT_S:
+		outid = OUTPUT_TYPE_S;
+		break;
+	default:
+		outid = 0xff;  /* -1 for error condition.*/
+		break;
+	}
+	msg._u.msgOut.output_id   = msgid;
+	msg._u.msgOut.yBuffer     = pyaddr;
+	msg._u.msgOut.cbcrBuffer  = pcbcraddr;
+
+	vfe31_proc_ops(msgid, &msg, sizeof(struct vfe_message));
+	return;
+}
+static int vfe31_enable(struct camera_enable_cmd *enable)
+{
+	return 0;
+}
+
+static void vfe31_stop(void)
+{
+	atomic_set(&vfe31_ctrl->vstate, 0);
+	atomic_set(&vfe31_ctrl->stop_ack_pending, 1);
+
+	/* in either continuous or snapshot mode, stop command can be issued
+	 * at any time. stop camif immediately. */
+	msm_io_w_mb(CAMIF_COMMAND_STOP_IMMEDIATELY,
+		vfe31_ctrl->vfebase + VFE_CAMIF_COMMAND);
+
+	/* disable all interrupts.  */
+	msm_io_w(VFE_DISABLE_ALL_IRQS,
+		vfe31_ctrl->vfebase + VFE_IRQ_MASK_0);
+	msm_io_w(VFE_DISABLE_ALL_IRQS,
+		vfe31_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+	/* clear all pending interrupts*/
+	msm_io_w(VFE_CLEAR_ALL_IRQS,
+		vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+	msm_io_w(VFE_CLEAR_ALL_IRQS,
+		vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_io_w_mb(1,
+		vfe31_ctrl->vfebase + VFE_IRQ_CMD);
+
+	/* now enable only halt_irq & reset_irq */
+	msm_io_w(0xf0000000,          /* this is for async timer. */
+		vfe31_ctrl->vfebase + VFE_IRQ_MASK_0);
+	msm_io_w(VFE_IMASK_AXI_HALT,
+		vfe31_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+	/* then apply axi halt command. */
+	msm_io_w_mb(AXI_HALT,
+		vfe31_ctrl->vfebase + VFE_AXI_CMD);
+}
+
+static int vfe31_disable(struct camera_enable_cmd *enable,
+	struct platform_device *dev)
+{
+	msm_camio_set_perf_lvl(S_EXIT);
+	msm_camio_disable(dev);
+	return 0;
+}
+
+static int vfe31_add_free_buf2(struct vfe31_output_ch *outch,
+	uint32_t paddr, uint32_t y_off, uint32_t cbcr_off)
+{
+	struct vfe31_free_buf *free_buf = NULL;
+	unsigned long flags = 0;
+	free_buf = kmalloc(sizeof(struct vfe31_free_buf), GFP_KERNEL);
+	if (!free_buf)
+		return -ENOMEM;
+
+	spin_lock_irqsave(&outch->free_buf_lock, flags);
+	free_buf->paddr = paddr;
+	free_buf->y_off = y_off;
+	free_buf->cbcr_off = cbcr_off;
+	list_add_tail(&free_buf->node, &outch->free_buf_head);
+
+	CDBG("%s: free_buf paddr = 0x%x, y_off = %d, cbcr_off = %d\n",
+		__func__, free_buf->paddr, free_buf->y_off,
+		free_buf->cbcr_off);
+	spin_unlock_irqrestore(&outch->free_buf_lock, flags);
+	return 0;
+}
+
+#define vfe31_add_free_buf(outch, regptr) \
+	vfe31_add_free_buf2(outch, regptr->paddr, regptr->info.y_off,	\
+		regptr->info.cbcr_off)
+
+#define vfe31_free_buf_available(outch) \
+	(!list_empty(&outch.free_buf_head))
+
+static inline struct vfe31_free_buf *vfe31_get_free_buf(
+	struct vfe31_output_ch *outch)
+{
+	unsigned long flags = 0;
+	struct vfe31_free_buf *free_buf = NULL;
+	spin_lock_irqsave(&outch->free_buf_lock, flags);
+	if (!list_empty(&outch->free_buf_head)) {
+		free_buf = list_first_entry(&outch->free_buf_head,
+			struct vfe31_free_buf, node);
+		if (free_buf)
+			list_del_init(&free_buf->node);
+	}
+	spin_unlock_irqrestore(&outch->free_buf_lock, flags);
+	return free_buf;
+}
+
+static inline void vfe31_reset_free_buf_queue(
+	struct vfe31_output_ch *outch)
+{
+	unsigned long flags = 0;
+	struct vfe31_free_buf *free_buf = NULL;
+	spin_lock_irqsave(&outch->free_buf_lock, flags);
+	while (!list_empty(&outch->free_buf_head)) {
+		free_buf = list_first_entry(&outch->free_buf_head,
+			struct vfe31_free_buf, node);
+		if (free_buf) {
+			list_del_init(&free_buf->node);
+			kfree(free_buf);
+		}
+	}
+	spin_unlock_irqrestore(&outch->free_buf_lock, flags);
+}
+
+#define vfe31_init_free_buf_queue() do {	\
+	INIT_LIST_HEAD(&vfe31_ctrl->outpath.out0.free_buf_head);	\
+	INIT_LIST_HEAD(&vfe31_ctrl->outpath.out1.free_buf_head);	\
+	INIT_LIST_HEAD(&vfe31_ctrl->outpath.out2.free_buf_head);	\
+	spin_lock_init(&vfe31_ctrl->outpath.out0.free_buf_lock);	\
+	spin_lock_init(&vfe31_ctrl->outpath.out1.free_buf_lock);	\
+	spin_lock_init(&vfe31_ctrl->outpath.out2.free_buf_lock);	\
+} while (0)
+
+#define vfe31_reset_free_buf_queue_all() do {	\
+	vfe31_reset_free_buf_queue(&vfe31_ctrl->outpath.out0);	\
+	vfe31_reset_free_buf_queue(&vfe31_ctrl->outpath.out1);	\
+	vfe31_reset_free_buf_queue(&vfe31_ctrl->outpath.out2);	\
+} while (0)
+
+static int vfe31_config_axi(int mode, struct axidata *ad, uint32_t *ao)
+{
+	int i;
+	uint32_t *p, *p1, *p2, *p3;
+	int32_t *ch_info;
+	struct vfe31_output_ch *outp1, *outp2, *outp3;
+	struct msm_pmem_region *regp1 = NULL;
+	struct msm_pmem_region *regp2 = NULL;
+	struct msm_pmem_region *regp3 = NULL;
+	int ret;
+	struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata;
+
+	outp1 = NULL;
+	outp2 = NULL;
+	outp3 = NULL;
+
+	p = ao + 2;
+
+	/* Update the corresponding write masters for each output*/
+	ch_info = ao + V31_AXI_CFG_LEN;
+	vfe31_ctrl->outpath.out0.ch0 = 0x0000FFFF & *ch_info;
+	vfe31_ctrl->outpath.out0.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
+	vfe31_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info++;
+	vfe31_ctrl->outpath.out1.ch0 = 0x0000FFFF & *ch_info;
+	vfe31_ctrl->outpath.out1.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
+	vfe31_ctrl->outpath.out1.ch2 = 0x0000FFFF & *ch_info++;
+	vfe31_ctrl->outpath.out2.ch0 = 0x0000FFFF & *ch_info;
+	vfe31_ctrl->outpath.out2.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
+	vfe31_ctrl->outpath.out2.ch2 = 0x0000FFFF & *ch_info++;
+
+	CDBG("vfe31_config_axi: mode = %d, bufnum1 = %d, bufnum2 = %d"
+		"bufnum3 = %d", mode, ad->bufnum1, ad->bufnum2, ad->bufnum3);
+
+	switch (mode) {
+
+	case OUTPUT_2: {
+		if (ad->bufnum2 != 3)
+			return -EINVAL;
+		regp1 = &(ad->region[ad->bufnum1]);
+		outp1 = &(vfe31_ctrl->outpath.out0);
+		vfe31_ctrl->outpath.output_mode |= VFE31_OUTPUT_MODE_PT;
+
+		for (i = 0; i < 2; i++) {
+			p1 = ao + 6 + i;    /* wm0 for y  */
+			*p1 = (regp1->paddr + regp1->info.y_off);
+
+			p1 = ao + 12 + i;  /* wm1 for cbcr */
+			*p1 = (regp1->paddr + regp1->info.cbcr_off);
+			regp1++;
+		}
+		ret = vfe31_add_free_buf(outp1, regp1);
+		if (ret < 0)
+			return ret;
+	}
+		break;
+
+	case OUTPUT_1_AND_2:
+		/* use wm0& 4 for thumbnail, wm1&5 for main image.*/
+		if ((ad->bufnum1 < 1) || (ad->bufnum2 < 1))
+			return -EINVAL;
+		vfe31_ctrl->outpath.output_mode |=
+			VFE31_OUTPUT_MODE_S;  /* main image.*/
+		vfe31_ctrl->outpath.output_mode |=
+			VFE31_OUTPUT_MODE_PT;  /* thumbnail. */
+
+		/* this is thumbnail buffer. */
+		regp1 = &(ad->region[ad->bufnum1-1]);
+		/* this is main image buffer. */
+		regp2 = &(ad->region[ad->bufnum1+ad->bufnum2-1]);
+
+		outp1 = &(vfe31_ctrl->outpath.out0);
+		outp2 = &(vfe31_ctrl->outpath.out1); /* snapshot */
+
+		/*  Parse the buffers!!! */
+		if (ad->bufnum2 == 1) {	/* assuming bufnum1 = bufnum2 */
+			p1 = ao + 6;   /* wm0 ping */
+			*p1++ = (regp1->paddr + regp1->info.y_off);
+
+			/* this is to duplicate ping address to pong.*/
+			*p1 = (regp1->paddr + regp1->info.y_off);
+
+			p1 = ao + 30;  /* wm4 ping */
+			*p1++ = (regp1->paddr + regp1->info.cbcr_off);
+			CDBG("%s: regp1->info.cbcr_off = 0x%x\n", __func__,
+						 regp1->info.cbcr_off);
+
+			/* this is to duplicate ping address to pong.*/
+			*p1 = (regp1->paddr + regp1->info.cbcr_off);
+
+			p1 = ao + 12;   /* wm1 ping */
+			*p1++ = (regp2->paddr + regp2->info.y_off);
+
+			/* pong = ping,*/
+			*p1 = (regp2->paddr + regp2->info.y_off);
+
+			p1 = ao + 36;  /* wm5 */
+			*p1++ = (regp2->paddr + regp2->info.cbcr_off);
+			CDBG("%s: regp2->info.cbcr_off = 0x%x\n", __func__,
+						 regp2->info.cbcr_off);
+
+			/* pong = ping,*/
+			*p1 = (regp2->paddr + regp2->info.cbcr_off);
+		} else { /* more than one snapshot */
+			/* first fill ping & pong */
+			for (i = 0; i < 2; i++) {
+				p1 = ao + 6 + i;    /* wm0 for y  */
+				*p1 = (regp1->paddr + regp1->info.y_off);
+				p1 = ao + 30 + i;  /* wm4 for cbcr */
+				*p1 = (regp1->paddr + regp1->info.cbcr_off);
+				regp1--;
+			}
+
+			for (i = 0; i < 2; i++) {
+				p2 = ao + 12 + i;    /* wm1 for y  */
+				*p2 = (regp2->paddr + regp2->info.y_off);
+				p2 = ao + 36 + i;  /* wm5 for cbcr */
+				*p2 = (regp2->paddr + regp2->info.cbcr_off);
+				regp2--;
+			}
+
+			for (i = 2; i < ad->bufnum1; i++) {
+				ret = vfe31_add_free_buf(outp1, regp1);
+				if (ret < 0)
+					return ret;
+				regp1--;
+			}
+
+			for (i = 2; i < ad->bufnum2; i++) {
+				ret = vfe31_add_free_buf(outp2, regp2);
+				if (ret < 0)
+					return ret;
+				regp2--;
+			}
+		}
+		break;
+
+	case OUTPUT_1_2_AND_3:
+		CDBG("%s: OUTPUT_1_2_AND_3", __func__);
+		CDBG("%s: %d %d %d", __func__, ad->bufnum1, ad->bufnum2,
+			ad->bufnum3);
+		/* use wm0& 4 for postview, wm1&5 for preview.*/
+		/* use wm2& 6 for main img */
+		if ((ad->bufnum1 < 1) || (ad->bufnum2 < 1) || (ad->bufnum3 < 1))
+			return -EINVAL;
+		vfe31_ctrl->outpath.output_mode |=
+			VFE31_OUTPUT_MODE_S;  /* main image.*/
+		vfe31_ctrl->outpath.output_mode |=
+			VFE31_OUTPUT_MODE_P;  /* preview. */
+		vfe31_ctrl->outpath.output_mode |=
+			VFE31_OUTPUT_MODE_T;  /* thumbnail. */
+
+		/* this is preview buffer. */
+		regp1 = &(ad->region[0]);
+		/* this is thumbnail buffer. */
+		regp2 = &(ad->region[ad->bufnum1]);
+		/* this is main image buffer. */
+		regp3 = &(ad->region[ad->bufnum1+ad->bufnum2]);
+		outp1 = &(vfe31_ctrl->outpath.out0);
+		outp2 = &(vfe31_ctrl->outpath.out1);
+		outp3 = &(vfe31_ctrl->outpath.out2);
+
+		/*  Parse the buffers!!! */
+		/* first fill ping & pong */
+		for (i = 0; i < 2; i++) {
+			p1 = ao + 6 + i;    /* wm0 for y  */
+			*p1 = (regp1->paddr + regp1->info.y_off);
+			p1 = ao + 30 + i;  /* wm4 for cbcr */
+			*p1 = (regp1->paddr + regp1->info.cbcr_off);
+			regp1++;
+		}
+
+		for (i = 0; i < 2; i++) {
+			p2 = ao + 12 + i;    /* wm1 for y  */
+			*p2 = (regp2->paddr + regp2->info.y_off);
+			p2 = ao + 36 + i;  /* wm5 for cbcr */
+			*p2 = (regp2->paddr + regp2->info.cbcr_off);
+			regp2++;
+		}
+
+		for (i = 0; i < 2; i++) {
+			p3 = ao + 18 + i;    /* wm2 for y  */
+			*p3 = (regp3->paddr + regp3->info.y_off);
+			p3 = ao + 42 + i;  /* wm6 for cbcr */
+			*p3 = (regp3->paddr + regp3->info.cbcr_off);
+			regp3++;
+		}
+
+		for (i = 2; i < ad->bufnum1; i++) {
+			ret = vfe31_add_free_buf(outp1, regp1);
+			if (ret < 0)
+				return ret;
+			regp1++;
+		}
+
+		for (i = 2; i < ad->bufnum2; i++) {
+			ret = vfe31_add_free_buf(outp2, regp2);
+			if (ret < 0)
+				return ret;
+			regp2++;
+		}
+
+		for (i = 2; i < ad->bufnum3; i++) {
+			ret = vfe31_add_free_buf(outp3, regp3);
+			if (ret < 0)
+				return ret;
+			regp3++;
+		}
+		break;
+
+	case OUTPUT_1_AND_3: {
+		/* use wm0&4 for preview, wm1&5 for video.*/
+		if ((ad->bufnum1 < 2) || (ad->bufnum2 < 2))
+			return -EINVAL;
+
+#ifdef CONFIG_MSM_CAMERA_V4L2
+		*p++ = 0x1;    /* xbar cfg0 */
+		*p = 0x1a03;    /* xbar cfg1 */
+#endif
+		vfe31_ctrl->outpath.output_mode |=
+			VFE31_OUTPUT_MODE_V;  /* video*/
+		vfe31_ctrl->outpath.output_mode |=
+			VFE31_OUTPUT_MODE_PT;  /* preview */
+
+		regp1 = &(ad->region[0]); /* this is preview buffer. */
+		regp2 = &(ad->region[ad->bufnum1]);/* this is video buffer. */
+		outp1 = &(vfe31_ctrl->outpath.out0); /* preview */
+		outp2 = &(vfe31_ctrl->outpath.out2); /* video */
+
+
+		for (i = 0; i < 2; i++) {
+			p1 = ao + 6 + i;    /* wm0 for y  */
+			*p1 = (regp1->paddr + regp1->info.y_off);
+
+			p1 = ao + 30 + i;  /* wm4 for cbcr */
+			*p1 = (regp1->paddr + regp1->info.cbcr_off);
+			regp1++;
+		}
+
+		for (i = 0; i < 2; i++) {
+			p2 = ao + 12 + i;    /* wm1 for y  */
+			*p2 = (regp2->paddr + regp2->info.y_off);
+
+			p2 = ao + 36 + i;  /* wm5 for cbcr */
+			*p2 = (regp2->paddr + regp2->info.cbcr_off);
+			regp2++;
+		}
+		for (i = 2; i < ad->bufnum1; i++) {
+			ret = vfe31_add_free_buf(outp1, regp1);
+			if (ret < 0)
+				return ret;
+			regp1++;
+		}
+
+		for (i = 2; i < ad->bufnum2; i++) {
+			ret = vfe31_add_free_buf(outp2, regp2);
+			if (ret < 0)
+				return ret;
+			regp2++;
+		}
+	}
+		break;
+	case CAMIF_TO_AXI_VIA_OUTPUT_2: {  /* use wm0 only */
+		if (ad->bufnum2 < 1)
+			return -EINVAL;
+		CDBG("config axi for raw snapshot.\n");
+		vfe31_ctrl->outpath.out1.ch0 = 0; /* raw */
+		regp1 = &(ad->region[ad->bufnum1]);
+		vfe31_ctrl->outpath.output_mode |= VFE31_OUTPUT_MODE_S;
+		p1 = ao + 6;    /* wm0 for y  */
+		*p1 = (regp1->paddr + regp1->info.y_off);
+		if (p_sync->stereocam_enabled)
+			p_sync->stereo_state = STEREO_RAW_SNAP_IDLE;
+	}
+		break;
+	default:
+		break;
+	}
+	msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[V31_AXI_OUT_CFG].offset,
+		ao, vfe31_cmd[V31_AXI_OUT_CFG].length - V31_AXI_CH_INF_LEN);
+
+	return 0;
+}
+
+static void vfe31_reset_internal_variables(void)
+{
+	unsigned long flags;
+	vfe31_ctrl->vfeImaskCompositePacked = 0;
+	/* state control variables */
+	vfe31_ctrl->start_ack_pending = FALSE;
+	atomic_set(&irq_cnt, 0);
+
+	spin_lock_irqsave(&vfe31_ctrl->xbar_lock, flags);
+	vfe31_ctrl->xbar_update_pending = 0;
+	spin_unlock_irqrestore(&vfe31_ctrl->xbar_lock, flags);
+
+	atomic_set(&vfe31_ctrl->stop_ack_pending, 0);
+	atomic_set(&vfe31_ctrl->vstate, 0);
+
+	vfe31_ctrl->aec_ack_pending = FALSE;
+	vfe31_ctrl->af_ack_pending = FALSE;
+	vfe31_ctrl->awb_ack_pending = FALSE;
+	vfe31_ctrl->ihist_ack_pending = FALSE;
+	vfe31_ctrl->rs_ack_pending = FALSE;
+	vfe31_ctrl->cs_ack_pending = FALSE;
+
+	vfe31_ctrl->reset_ack_pending  = FALSE;
+
+	spin_lock_irqsave(&vfe31_ctrl->update_ack_lock, flags);
+	vfe31_ctrl->update_ack_pending = FALSE;
+	spin_unlock_irqrestore(&vfe31_ctrl->update_ack_lock, flags);
+
+	vfe31_ctrl->recording_state = VFE_REC_STATE_IDLE;
+
+	/* 0 for continuous mode, 1 for snapshot mode */
+	vfe31_ctrl->operation_mode = VFE_MODE_OF_OPERATION_CONTINUOUS;
+	vfe31_ctrl->outpath.output_mode = 0;
+	vfe31_ctrl->vfe_capture_count = 0;
+
+	/* this is unsigned 32 bit integer. */
+	vfe31_ctrl->vfeFrameId = 0;
+
+	vfe31_ctrl->output1Pattern = 0xffffffff;
+	vfe31_ctrl->output1Period  = 31;
+	vfe31_ctrl->output2Pattern = 0xffffffff;
+	vfe31_ctrl->output2Period  = 31;
+	vfe31_ctrl->vfeFrameSkipCount   = 0;
+	vfe31_ctrl->vfeFrameSkipPeriod  = 31;
+
+	/* Stats control variables. */
+	memset(&(vfe31_ctrl->afStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe31_ctrl->awbStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe31_ctrl->aecStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe31_ctrl->ihistStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe31_ctrl->rsStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe31_ctrl->csStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+}
+
+static void vfe31_reset(void)
+{
+	uint32_t vfe_version;
+	vfe31_reset_free_buf_queue_all();
+	vfe31_reset_internal_variables();
+
+	vfe31_reset_hist_cfg();
+	vfe_version = msm_io_r(vfe31_ctrl->vfebase);
+	CDBG("vfe_version = 0x%x\n", vfe_version);
+	/* disable all interrupts.  vfeImaskLocal is also reset to 0
+	* to begin with. */
+	msm_io_w(VFE_DISABLE_ALL_IRQS,
+		vfe31_ctrl->vfebase + VFE_IRQ_MASK_0);
+
+	msm_io_w(VFE_DISABLE_ALL_IRQS,
+		vfe31_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+	/* clear all pending interrupts*/
+	msm_io_w(VFE_CLEAR_ALL_IRQS, vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+	msm_io_w(VFE_CLEAR_ALL_IRQS, vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_IRQ_CMD);
+
+	/* enable reset_ack interrupt.  */
+	msm_io_w(VFE_IMASK_RESET,
+		vfe31_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+	/* Write to VFE_GLOBAL_RESET_CMD to reset the vfe hardware. Once reset
+	 * is done, hardware interrupt will be generated.  VFE ist processes
+	 * the interrupt to complete the function call.  Note that the reset
+	 * function is synchronous. */
+
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_io_w_mb(VFE_RESET_UPON_RESET_CMD,
+		vfe31_ctrl->vfebase + VFE_GLOBAL_RESET);
+}
+
+static int vfe31_operation_config(uint32_t *cmd)
+{
+	uint32_t *p = cmd;
+
+	vfe31_ctrl->operation_mode = *p;
+	vpe_ctrl->pad_2k_bool = (vfe31_ctrl->operation_mode & 1) ?
+		FALSE : TRUE;
+
+	vfe31_ctrl->stats_comp = *(++p);
+	vfe31_ctrl->hfr_mode = *(++p);
+
+	msm_io_w(*(++p), vfe31_ctrl->vfebase + VFE_CFG_OFF);
+	msm_io_w(*(++p), vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+	msm_io_w(*(++p), vfe31_ctrl->vfebase + VFE_REALIGN_BUF);
+	msm_io_w(*(++p), vfe31_ctrl->vfebase + VFE_CHROMA_UP);
+	msm_io_w(*(++p), vfe31_ctrl->vfebase + VFE_STATS_CFG);
+	wmb();
+	return 0;
+}
+static uint32_t vfe_stats_awb_buf_init(struct vfe_cmd_stats_buf *in)
+{
+	uint32_t *ptr = in->statsBuf;
+	uint32_t addr;
+
+	addr = ptr[0];
+	msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+	addr = ptr[1];
+	msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+	vfe31_ctrl->awbStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+	return 0;
+}
+
+
+static uint32_t vfe_stats_aec_buf_init(struct vfe_cmd_stats_buf *in)
+{
+	uint32_t *ptr = in->statsBuf;
+	uint32_t addr;
+
+	addr = ptr[0];
+	msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AEC_WR_PING_ADDR);
+	addr = ptr[1];
+	msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AEC_WR_PONG_ADDR);
+
+	vfe31_ctrl->aecStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+	return 0;
+}
+
+static uint32_t vfe_stats_af_buf_init(struct vfe_cmd_stats_buf *in)
+{
+	uint32_t *ptr = in->statsBuf;
+	uint32_t addr;
+
+	addr = ptr[0];
+	msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+	addr = ptr[1];
+	msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+
+	vfe31_ctrl->afStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+	return 0;
+}
+
+static uint32_t vfe_stats_ihist_buf_init(struct vfe_cmd_stats_buf *in)
+{
+	uint32_t *ptr = in->statsBuf;
+	uint32_t addr;
+
+	addr = ptr[0];
+	msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PING_ADDR);
+	addr = ptr[1];
+	msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PONG_ADDR);
+
+	vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+	return 0;
+}
+
+static uint32_t vfe_stats_rs_buf_init(struct vfe_cmd_stats_buf *in)
+{
+	uint32_t *ptr = in->statsBuf;
+	uint32_t addr;
+
+	addr = ptr[0];
+	msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PING_ADDR);
+	addr = ptr[1];
+	msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PONG_ADDR);
+
+	vfe31_ctrl->rsStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+	return 0;
+}
+static uint32_t vfe_stats_cs_buf_init(struct vfe_cmd_stats_buf *in)
+{
+	uint32_t *ptr = in->statsBuf;
+	uint32_t addr;
+
+	addr = ptr[0];
+	msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PING_ADDR);
+	addr = ptr[1];
+	msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PONG_ADDR);
+
+	vfe31_ctrl->csStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+	return 0;
+}
+
+static void vfe31_start_common(void)
+{
+	uint32_t irq_mask = 0x00E00021;
+	vfe31_ctrl->start_ack_pending = TRUE;
+	CDBG("VFE opertaion mode = 0x%x, output mode = 0x%x\n",
+		vfe31_ctrl->operation_mode, vfe31_ctrl->outpath.output_mode);
+	/* Enable IRQ for comp stats, Image master, SOF & Reg Update*/
+	if (vfe31_ctrl->stats_comp)
+		irq_mask |= 0x01000000;
+	else /* Enable IRQ for Image masters, AF stats, SOF & Reg Update */
+		irq_mask |= 0x00004000;
+
+	/* Enable EOF for video mode */
+	if (VFE_MODE_OF_OPERATION_VIDEO == vfe31_ctrl->operation_mode)
+		irq_mask |= 0x4;
+
+	msm_io_w(irq_mask, vfe31_ctrl->vfebase + VFE_IRQ_MASK_0);
+
+	msm_io_w(VFE_IMASK_RESET,
+		vfe31_ctrl->vfebase + VFE_IRQ_MASK_1);
+	/* enable out of order option */
+	msm_io_w(0x80000000, vfe31_ctrl->vfebase + VFE_AXI_CFG);
+	/* enable performance monitor */
+	msm_io_w(1, vfe31_ctrl->vfebase + VFE_BUS_PM_CFG);
+	msm_io_w(1, vfe31_ctrl->vfebase + VFE_BUS_PM_CMD);
+
+
+	msm_io_dump(vfe31_ctrl->vfebase, 0x600);
+
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+	msm_io_w(1, vfe31_ctrl->vfebase + VFE_CAMIF_COMMAND);
+	wmb();
+
+	atomic_set(&vfe31_ctrl->vstate, 1);
+}
+
+static int vfe31_start_recording(void)
+{
+	msm_camio_set_perf_lvl(S_VIDEO);
+	usleep(1000);
+	vfe31_ctrl->recording_state = VFE_REC_STATE_START_REQUESTED;
+	msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+	return 0;
+}
+
+static int vfe31_stop_recording(void)
+{
+	vfe31_ctrl->recording_state = VFE_REC_STATE_STOP_REQUESTED;
+	msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+	msm_camio_set_perf_lvl(S_PREVIEW);
+	return 0;
+}
+
+static void vfe31_liveshot(void)
+{
+	struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata;
+	if (p_sync)
+		p_sync->liveshot_enabled = true;
+}
+
+static void vfe31_stereocam(uint32_t enable)
+{
+	struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata;
+	if (p_sync) {
+		CDBG("%s: Enable StereoCam %d!!!\n", __func__, enable);
+		p_sync->stereocam_enabled = enable;
+	}
+}
+
+static int vfe31_zsl(void)
+{
+	uint32_t irq_comp_mask = 0;
+	/* capture command is valid for both idle and active state. */
+	irq_comp_mask	=
+		msm_io_r(vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+	CDBG("%s:op mode %d O/P Mode %d\n", __func__,
+		vfe31_ctrl->operation_mode, vfe31_ctrl->outpath.output_mode);
+	if ((vfe31_ctrl->operation_mode == VFE_MODE_OF_OPERATION_ZSL)) {
+		if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_P) {
+			irq_comp_mask |=
+				((0x1 << (vfe31_ctrl->outpath.out0.ch0)) |
+				(0x1 << (vfe31_ctrl->outpath.out0.ch1)));
+		}
+		if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_T) {
+			irq_comp_mask |=
+				((0x1 << (vfe31_ctrl->outpath.out1.ch0 + 8)) |
+				(0x1 << (vfe31_ctrl->outpath.out1.ch1 + 8)));
+		}
+		if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_S) {
+			irq_comp_mask |=
+			((0x1 << (vfe31_ctrl->outpath.out2.ch0 + 8)) |
+			(0x1 << (vfe31_ctrl->outpath.out2.ch1 + 8)));
+		}
+		if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_P) {
+			msm_io_w(1, vfe31_ctrl->vfebase +
+				vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+			msm_io_w(1, vfe31_ctrl->vfebase +
+				vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+		}
+		if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_T) {
+			msm_io_w(1, vfe31_ctrl->vfebase +
+				vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
+			msm_io_w(1, vfe31_ctrl->vfebase +
+				vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
+		}
+		if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_S) {
+			msm_io_w(1, vfe31_ctrl->vfebase +
+				vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out2.ch0]);
+			msm_io_w(1, vfe31_ctrl->vfebase +
+				vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out2.ch1]);
+		}
+	}
+	msm_io_w(irq_comp_mask, vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+	vfe31_start_common();
+	msm_camio_set_perf_lvl(S_ZSL);
+	usleep(1000);
+	/* for debug */
+	msm_io_w(1, vfe31_ctrl->vfebase + 0x18C);
+	msm_io_w(1, vfe31_ctrl->vfebase + 0x188);
+	return 0;
+}
+
+static int vfe31_capture(uint32_t num_frames_capture)
+{
+	uint32_t irq_comp_mask = 0;
+	struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata;
+
+	/* capture command is valid for both idle and active state. */
+	vfe31_ctrl->vfe_capture_count = num_frames_capture;
+	if (p_sync) {
+		p_sync->snap_count = num_frames_capture;
+		p_sync->thumb_count = num_frames_capture;
+	}
+
+	irq_comp_mask	=
+		msm_io_r(vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+	if ((vfe31_ctrl->operation_mode ==
+		 VFE_MODE_OF_OPERATION_SNAPSHOT) ||
+		(vfe31_ctrl->operation_mode ==
+		 VFE_MODE_OF_OPERATION_ZSL)){
+		if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_PT) {
+			irq_comp_mask |=
+				((0x1 << (vfe31_ctrl->outpath.out0.ch0 + 8)) |
+				(0x1 << (vfe31_ctrl->outpath.out0.ch1 + 8)));
+		}
+		if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_S) {
+			irq_comp_mask |=
+			((0x1 << (vfe31_ctrl->outpath.out1.ch0 + 8)) |
+			(0x1 << (vfe31_ctrl->outpath.out1.ch1 + 8)));
+		}
+		if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_PT) {
+			msm_io_w(1, vfe31_ctrl->vfebase +
+				vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+			msm_io_w(1, vfe31_ctrl->vfebase +
+				vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+		}
+		if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_S) {
+			msm_io_w(1, vfe31_ctrl->vfebase +
+				vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
+			msm_io_w(1, vfe31_ctrl->vfebase +
+				vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
+		}
+	} else {  /* this is raw snapshot mode. */
+		CDBG("config the comp imask for raw snapshot mode.\n");
+		if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_S) {
+			irq_comp_mask |=
+			(0x1 << (vfe31_ctrl->outpath.out1.ch0 + 8));
+			msm_io_w(1, vfe31_ctrl->vfebase +
+				vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
+		}
+	}
+	msm_io_w(irq_comp_mask, vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+	if (p_sync->stereocam_enabled)
+		msm_camio_set_perf_lvl(S_STEREO_CAPTURE);
+	else
+		msm_camio_set_perf_lvl(S_CAPTURE);
+
+	usleep(1000);
+	vfe31_start_common();
+	return 0;
+}
+
+static int vfe31_start(void)
+{
+	uint32_t irq_comp_mask = 0;
+	struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata;
+	/* start command now is only good for continuous mode. */
+	if ((vfe31_ctrl->operation_mode != VFE_MODE_OF_OPERATION_CONTINUOUS) &&
+		(vfe31_ctrl->operation_mode != VFE_MODE_OF_OPERATION_VIDEO))
+		return 0;
+	irq_comp_mask	=
+		msm_io_r(vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+	if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_PT) {
+		irq_comp_mask |= (0x1 << vfe31_ctrl->outpath.out0.ch0 |
+			0x1 << vfe31_ctrl->outpath.out0.ch1);
+	}
+
+	if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_V) {
+		irq_comp_mask |= (0x1 << (vfe31_ctrl->outpath.out2.ch0 + 16)|
+			0x1 << (vfe31_ctrl->outpath.out2.ch1 + 16));
+	}
+
+	msm_io_w(irq_comp_mask, vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+
+	if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_PT) {
+		msm_io_w(1, vfe31_ctrl->vfebase +
+			vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+		msm_io_w(1, vfe31_ctrl->vfebase +
+			vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+	}
+	if (p_sync->stereocam_enabled)
+		msm_camio_set_perf_lvl(S_STEREO_VIDEO);
+	else
+		msm_camio_set_perf_lvl(S_PREVIEW);
+
+	usleep(1000);
+	vfe31_start_common();
+	return 0;
+}
+
+static void vfe31_update(void)
+{
+	unsigned long flags;
+	CDBG("vfe31_update\n");
+
+	if (vfe31_ctrl->update_gamma) {
+		if (!msm_io_r(vfe31_ctrl->vfebase + V31_GAMMA_CFG_OFF))
+			msm_io_w(7, vfe31_ctrl->vfebase+V31_GAMMA_CFG_OFF);
+		else
+			msm_io_w(0, vfe31_ctrl->vfebase+V31_GAMMA_CFG_OFF);
+		vfe31_ctrl->update_gamma = false;
+	}
+	if (vfe31_ctrl->update_luma) {
+		if (!msm_io_r(vfe31_ctrl->vfebase + V31_LUMA_CFG_OFF))
+			msm_io_w(1, vfe31_ctrl->vfebase + V31_LUMA_CFG_OFF);
+		else
+			msm_io_w(0, vfe31_ctrl->vfebase + V31_LUMA_CFG_OFF);
+		vfe31_ctrl->update_luma = false;
+	}
+	spin_lock_irqsave(&vfe31_ctrl->update_ack_lock, flags);
+	vfe31_ctrl->update_ack_pending = TRUE;
+	spin_unlock_irqrestore(&vfe31_ctrl->update_ack_lock, flags);
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+	return;
+}
+
+static void vfe31_sync_timer_stop(void)
+{
+	uint32_t value = 0;
+	vfe31_ctrl->sync_timer_state = 0;
+	if (vfe31_ctrl->sync_timer_number == 0)
+		value = 0x10000;
+	else if (vfe31_ctrl->sync_timer_number == 1)
+		value = 0x20000;
+	else if (vfe31_ctrl->sync_timer_number == 2)
+		value = 0x40000;
+
+	/* Timer Stop */
+	msm_io_w_mb(value, vfe31_ctrl->vfebase + V31_SYNC_TIMER_OFF);
+}
+
+static void vfe31_sync_timer_start(const uint32_t *tbl)
+{
+	/* set bit 8 for auto increment. */
+	uint32_t value = 1;
+	uint32_t val;
+
+	vfe31_ctrl->sync_timer_state = *tbl++;
+	vfe31_ctrl->sync_timer_repeat_count = *tbl++;
+	vfe31_ctrl->sync_timer_number = *tbl++;
+	CDBG("%s timer_state %d, repeat_cnt %d timer number %d\n",
+		 __func__, vfe31_ctrl->sync_timer_state,
+		 vfe31_ctrl->sync_timer_repeat_count,
+		 vfe31_ctrl->sync_timer_number);
+
+	if (vfe31_ctrl->sync_timer_state) { /* Start Timer */
+		value = value << vfe31_ctrl->sync_timer_number;
+	} else { /* Stop Timer */
+		CDBG("Failed to Start timer\n");
+		 return;
+	}
+
+	/* Timer Start */
+	msm_io_w(value, vfe31_ctrl->vfebase + V31_SYNC_TIMER_OFF);
+	/* Sync Timer Line Start */
+	value = *tbl++;
+	msm_io_w(value, vfe31_ctrl->vfebase + V31_SYNC_TIMER_OFF +
+		4 + ((vfe31_ctrl->sync_timer_number) * 12));
+	/* Sync Timer Pixel Start */
+	value = *tbl++;
+	msm_io_w(value, vfe31_ctrl->vfebase + V31_SYNC_TIMER_OFF +
+			 8 + ((vfe31_ctrl->sync_timer_number) * 12));
+	/* Sync Timer Pixel Duration */
+	value = *tbl++;
+	val = camio_clk.vfe_clk_rate / 10000;
+	val = 10000000 / val;
+	val = value * 10000 / val;
+	CDBG("%s: Pixel Clk Cycles!!! %d \n", __func__, val);
+	msm_io_w(val, vfe31_ctrl->vfebase + V31_SYNC_TIMER_OFF +
+		12 + ((vfe31_ctrl->sync_timer_number) * 12));
+	/* Timer0 Active High/LOW */
+	value = *tbl++;
+	msm_io_w(value, vfe31_ctrl->vfebase + V31_SYNC_TIMER_POLARITY_OFF);
+	/* Selects sync timer 0 output to drive onto timer1 port */
+	value = 0;
+	msm_io_w(value, vfe31_ctrl->vfebase + V31_TIMER_SELECT_OFF);
+	wmb();
+}
+
+static void vfe31_program_dmi_cfg(enum VFE31_DMI_RAM_SEL bankSel)
+{
+	/* set bit 8 for auto increment. */
+	uint32_t value = VFE_DMI_CFG_DEFAULT;
+	value += (uint32_t)bankSel;
+
+	msm_io_w_mb(value, vfe31_ctrl->vfebase + VFE_DMI_CFG);
+	/* by default, always starts with offset 0.*/
+	msm_io_w(0, vfe31_ctrl->vfebase + VFE_DMI_ADDR);
+	wmb();
+}
+static void vfe31_write_gamma_cfg(enum VFE31_DMI_RAM_SEL channel_sel,
+						const uint32_t *tbl)
+{
+	int i;
+	uint32_t value, value1, value2;
+	vfe31_program_dmi_cfg(channel_sel);
+	/* for loop for extracting init table. */
+	for (i = 0 ; i < (VFE31_GAMMA_NUM_ENTRIES/2) ; i++) {
+		value = *tbl++;
+		value1 = value & 0x0000FFFF;
+		value2 = (value & 0xFFFF0000)>>16;
+		msm_io_w((value1), vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+		msm_io_w((value2), vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+	}
+	vfe31_program_dmi_cfg(NO_MEM_SELECTED);
+}
+
+static void vfe31_reset_hist_cfg()
+{
+	uint32_t i;
+	uint32_t value = 0;
+
+	vfe31_program_dmi_cfg(STATS_HIST_RAM);
+	for (i = 0 ; i < VFE31_HIST_TABLE_LENGTH ; i++)
+		msm_io_w(value, vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+	vfe31_program_dmi_cfg(NO_MEM_SELECTED);
+}
+
+static void vfe31_write_la_cfg(enum VFE31_DMI_RAM_SEL channel_sel,
+						const uint32_t *tbl)
+{
+	uint32_t i;
+	uint32_t value, value1, value2;
+
+	vfe31_program_dmi_cfg(channel_sel);
+	/* for loop for extracting init table. */
+	for (i = 0 ; i < (VFE31_LA_TABLE_LENGTH/2) ; i++) {
+		value = *tbl++;
+		value1 = value & 0x0000FFFF;
+		value2 = (value & 0xFFFF0000)>>16;
+		msm_io_w((value1), vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+		msm_io_w((value2), vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+	}
+	vfe31_program_dmi_cfg(NO_MEM_SELECTED);
+}
+
+static int vfe31_proc_general(struct msm_vfe31_cmd *cmd)
+{
+	int i , rc = 0;
+	uint32_t old_val = 0 , new_val = 0;
+	uint32_t *cmdp = NULL;
+	uint32_t *cmdp_local = NULL;
+	uint32_t snapshot_cnt = 0;
+	uint32_t stereo_cam_enable = 0;
+	struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata;
+
+	CDBG("vfe31_proc_general: cmdID = %s, length = %d\n",
+		vfe31_general_cmd[cmd->id], cmd->length);
+	switch (cmd->id) {
+	case V31_RESET:
+		pr_info("vfe31_proc_general: cmdID = %s\n",
+			vfe31_general_cmd[cmd->id]);
+		vfe31_reset();
+		break;
+	case V31_START:
+		pr_info("vfe31_proc_general: cmdID = %s\n",
+			vfe31_general_cmd[cmd->id]);
+		rc = vfe31_start();
+		break;
+	case V31_UPDATE:
+		vfe31_update();
+		break;
+	case V31_ZSL:
+		pr_info("vfe31_proc_general: cmdID = %s\n",
+			vfe31_general_cmd[cmd->id]);
+		vfe31_zsl();
+		break;
+	case V31_CAPTURE:
+		pr_info("vfe31_proc_general: cmdID = %s\n",
+			vfe31_general_cmd[cmd->id]);
+		if (copy_from_user(&snapshot_cnt, (void __user *)(cmd->value),
+				sizeof(uint32_t))) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		rc = vfe31_capture(snapshot_cnt);
+		break;
+	case V31_START_RECORDING:
+		pr_info("vfe31_proc_general: cmdID = %s\n",
+			vfe31_general_cmd[cmd->id]);
+		rc = vfe31_start_recording();
+		if (p_sync->stereocam_enabled)
+			p_sync->stereo_state = STEREO_VIDEO_ACTIVE;
+		break;
+	case V31_STOP_RECORDING:
+		pr_info("vfe31_proc_general: cmdID = %s\n",
+			vfe31_general_cmd[cmd->id]);
+		rc = vfe31_stop_recording();
+		if (p_sync->stereocam_enabled)
+			p_sync->stereo_state = STEREO_VIDEO_IDLE;
+		break;
+	case V31_OPERATION_CFG: {
+		if (cmd->length != V31_OPERATION_CFG_LEN) {
+			rc = -EINVAL;
+			goto proc_general_done;
+		}
+		cmdp = kmalloc(V31_OPERATION_CFG_LEN, GFP_ATOMIC);
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			V31_OPERATION_CFG_LEN)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		rc = vfe31_operation_config(cmdp);
+		}
+		break;
+
+	case V31_STATS_AE_START: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val |= AE_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+		cmdp, (vfe31_cmd[cmd->id].length));
+		}
+		break;
+	case V31_STATS_AF_START: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val |= AF_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+		cmdp, (vfe31_cmd[cmd->id].length));
+		}
+		break;
+	case V31_STATS_AWB_START: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val |= AWB_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+				cmdp, (vfe31_cmd[cmd->id].length));
+		}
+		break;
+
+	case V31_STATS_IHIST_START: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val |= IHIST_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+				cmdp, (vfe31_cmd[cmd->id].length));
+		}
+		break;
+
+	case V31_XBAR_CFG: {
+		unsigned long flags = 0;
+		spin_lock_irqsave(&vfe31_ctrl->xbar_lock, flags);
+		if ((cmd->length != V31_XBAR_CFG_LEN)
+			|| vfe31_ctrl->xbar_update_pending) {
+			rc = -EINVAL;
+			spin_unlock_irqrestore(&vfe31_ctrl->xbar_lock, flags);
+			goto proc_general_done;
+		}
+		spin_unlock_irqrestore(&vfe31_ctrl->xbar_lock, flags);
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		spin_lock_irqsave(&vfe31_ctrl->xbar_lock, flags);
+		vfe31_ctrl->xbar_cfg[0] = *cmdp;
+		vfe31_ctrl->xbar_cfg[1] = *(cmdp+1);
+		vfe31_ctrl->xbar_update_pending = 1;
+		spin_unlock_irqrestore(&vfe31_ctrl->xbar_lock, flags);
+		CDBG("%s: xbar0 0x%x xbar1 0x%x", __func__,
+			vfe31_ctrl->xbar_cfg[0],
+			vfe31_ctrl->xbar_cfg[1]);
+		}
+		break;
+
+	case V31_STATS_RS_START: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		/*
+		old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val |= RS_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		*/
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+				cmdp, (vfe31_cmd[cmd->id].length));
+		}
+		break;
+
+	case V31_STATS_CS_START: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		/*
+		old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val |= CS_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		*/
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+				cmdp, (vfe31_cmd[cmd->id].length));
+		}
+		break;
+
+	case V31_MCE_UPDATE:
+	case V31_MCE_CFG:{
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		/* Incrementing with 4 so as to point to the 2nd Register as
+		the 2nd register has the mce_enable bit */
+		old_val = msm_io_r(vfe31_ctrl->vfebase +
+						V31_CHROMA_SUP_OFF + 4);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		new_val = *cmdp_local;
+		old_val &= MCE_EN_MASK;
+		new_val = new_val | old_val;
+		msm_io_memcpy(vfe31_ctrl->vfebase + V31_CHROMA_SUP_OFF + 4,
+					&new_val, 4);
+		cmdp_local += 1;
+
+		old_val = msm_io_r(vfe31_ctrl->vfebase +
+						V31_CHROMA_SUP_OFF + 8);
+		new_val = *cmdp_local;
+		old_val &= MCE_Q_K_MASK;
+		new_val = new_val | old_val;
+		msm_io_memcpy(vfe31_ctrl->vfebase + V31_CHROMA_SUP_OFF + 8,
+		&new_val, 4);
+		cmdp_local += 1;
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+		cmdp_local, (vfe31_cmd[cmd->id].length));
+		}
+		break;
+	case V31_DEMOSAIC_2_UPDATE: /* 38 BPC update   */
+	case V31_DEMOSAIC_2_CFG: {  /* 14 BPC config   */
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		new_val = *cmdp_local;
+
+		old_val = msm_io_r(vfe31_ctrl->vfebase + V31_DEMOSAIC_0_OFF);
+		old_val &= BPC_MASK;
+
+		new_val = new_val | old_val;
+		*cmdp_local = new_val;
+		msm_io_memcpy(vfe31_ctrl->vfebase + V31_DEMOSAIC_0_OFF,
+					cmdp_local, 4);
+		cmdp_local += 1;
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+			cmdp_local, (vfe31_cmd[cmd->id].length));
+		}
+		break;
+	case V31_DEMOSAIC_1_UPDATE:/* 37 ABF update  */
+	case V31_DEMOSAIC_1_CFG: { /* 13 ABF config  */
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		new_val = *cmdp_local;
+
+		old_val = msm_io_r(vfe31_ctrl->vfebase + V31_DEMOSAIC_0_OFF);
+		old_val &= ABF_MASK;
+		new_val = new_val | old_val;
+		*cmdp_local = new_val;
+
+		msm_io_memcpy(vfe31_ctrl->vfebase + V31_DEMOSAIC_0_OFF,
+		    cmdp_local, 4);
+
+		cmdp_local += 1;
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+		cmdp_local, (vfe31_cmd[cmd->id].length));
+		}
+		break;
+	case V31_ROLL_OFF_CFG: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value) , cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+		cmdp_local, 16);
+		cmdp_local += 4;
+		vfe31_program_dmi_cfg(ROLLOFF_RAM);
+		/* for loop for extrcting init table. */
+		for (i = 0 ; i < (VFE31_ROLL_OFF_INIT_TABLE_SIZE * 2) ; i++) {
+			msm_io_w(*cmdp_local ,
+			vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+			cmdp_local++;
+		}
+		CDBG("done writing init table \n");
+		/* by default, always starts with offset 0. */
+		msm_io_w(LENS_ROLL_OFF_DELTA_TABLE_OFFSET,
+		vfe31_ctrl->vfebase + VFE_DMI_ADDR);
+		/* for loop for extracting delta table. */
+		for (i = 0 ; i < (VFE31_ROLL_OFF_DELTA_TABLE_SIZE * 2) ; i++) {
+			msm_io_w(*cmdp_local,
+			vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+			cmdp_local++;
+		}
+		vfe31_program_dmi_cfg(NO_MEM_SELECTED);
+		}
+		break;
+
+	case V31_LA_CFG:{
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		/* Select Bank 0*/
+		*cmdp = 0;
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+				cmdp, (vfe31_cmd[cmd->id].length));
+		cmdp += 1;
+		vfe31_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK0 , cmdp);
+		cmdp -= 1;
+		}
+		break;
+
+	case V31_LA_UPDATE: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = msm_io_r(vfe31_ctrl->vfebase + V31_LUMA_CFG_OFF);
+		cmdp += 1;
+		if (old_val != 0x0)
+			vfe31_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK0 , cmdp);
+		else
+			vfe31_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK1 , cmdp);
+		vfe31_ctrl->update_luma = true;
+		cmdp -= 1;
+		}
+		break;
+
+	case V31_SK_ENHAN_CFG:
+	case V31_SK_ENHAN_UPDATE:{
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		msm_io_memcpy(vfe31_ctrl->vfebase + V31_SCE_OFF,
+				cmdp, V31_SCE_LEN);
+		}
+		break;
+
+	case V31_LIVESHOT:
+		vfe31_liveshot();
+		break;
+
+	case V31_STEREOCAM:
+		if (copy_from_user(&stereo_cam_enable,
+			(void __user *)(cmd->value), sizeof(uint32_t))) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		vfe31_stereocam(stereo_cam_enable);
+		break;
+
+	case V31_RGB_G_CFG: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		/* Select Bank 0*/
+		*cmdp = 0;
+		msm_io_memcpy(vfe31_ctrl->vfebase + V31_RGB_G_OFF,
+				cmdp, 4);
+		cmdp += 1;
+		vfe31_write_gamma_cfg(RGBLUT_CHX_BANK0, cmdp);
+		cmdp -= 1;
+		}
+		break;
+
+	case V31_RGB_G_UPDATE: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp, (void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = msm_io_r(vfe31_ctrl->vfebase + V31_GAMMA_CFG_OFF);
+		cmdp += 1;
+
+		if (!old_val) {
+			vfe31_write_gamma_cfg(RGBLUT_CHX_BANK1, cmdp);
+		} else {
+			vfe31_write_gamma_cfg(RGBLUT_CHX_BANK0, cmdp);
+			}
+		vfe31_ctrl->update_gamma = true;
+		cmdp -= 1;
+		}
+		break;
+
+	case V31_STATS_AWB_STOP: {
+		old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= ~AWB_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		}
+		break;
+	case V31_STATS_AE_STOP: {
+		old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= ~AE_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		}
+		break;
+	case V31_STATS_AF_STOP: {
+		old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= ~AF_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		}
+		break;
+
+	case V31_STATS_IHIST_STOP: {
+		old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= ~IHIST_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		}
+		break;
+
+	case V31_STATS_RS_STOP: {
+		old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= ~RS_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		}
+		break;
+
+	case V31_STATS_CS_STOP: {
+		old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= ~CS_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		}
+		break;
+	case V31_STOP:
+		pr_info("vfe31_proc_general: cmdID = %s\n",
+			vfe31_general_cmd[cmd->id]);
+		vfe31_stop();
+		break;
+
+	case V31_SYNC_TIMER_SETTING:
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp, (void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		vfe31_sync_timer_start(cmdp);
+		break;
+
+	case V31_EZTUNE_CFG: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		*cmdp &= ~STATS_ENABLE_MASK;
+		old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= STATS_ENABLE_MASK;
+		*cmdp |= old_val;
+
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+			cmdp, (vfe31_cmd[cmd->id].length));
+		}
+		break;
+
+	default: {
+		if (cmd->length != vfe31_cmd[cmd->id].length)
+			return -EINVAL;
+
+		cmdp = kmalloc(vfe31_cmd[cmd->id].length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+
+		CHECKED_COPY_FROM_USER(cmdp);
+		msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+			cmdp, (vfe31_cmd[cmd->id].length));
+	}
+	break;
+
+	}
+
+proc_general_done:
+	kfree(cmdp);
+
+	return rc;
+}
+
+static void vfe31_stats_af_ack(struct vfe_cmd_stats_ack *pAck)
+{
+	vfe31_ctrl->afStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+	vfe31_ctrl->af_ack_pending = FALSE;
+}
+
+static void vfe31_stats_awb_ack(struct vfe_cmd_stats_ack *pAck)
+{
+	vfe31_ctrl->awbStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+	vfe31_ctrl->awb_ack_pending = FALSE;
+}
+
+static void vfe31_stats_aec_ack(struct vfe_cmd_stats_ack *pAck)
+{
+	vfe31_ctrl->aecStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+	vfe31_ctrl->aec_ack_pending = FALSE;
+}
+
+static void vfe31_stats_ihist_ack(struct vfe_cmd_stats_ack *pAck)
+{
+	vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+	vfe31_ctrl->ihist_ack_pending = FALSE;
+}
+
+static void vfe31_stats_rs_ack(struct vfe_cmd_stats_ack *pAck)
+{
+	vfe31_ctrl->rsStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+	vfe31_ctrl->rs_ack_pending = FALSE;
+}
+
+static void vfe31_stats_cs_ack(struct vfe_cmd_stats_ack *pAck)
+{
+	vfe31_ctrl->csStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+	vfe31_ctrl->cs_ack_pending = FALSE;
+}
+
+static int vfe31_config(struct msm_vfe_cfg_cmd *cmd, void *data)
+{
+	struct msm_vfe31_cmd vfecmd;
+
+	long rc = 0;
+	uint32_t i = 0;
+	struct vfe_cmd_stats_buf *scfg = NULL;
+	struct msm_pmem_region   *regptr = NULL;
+	struct vfe_cmd_stats_ack *sack = NULL;
+
+	if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE &&
+		cmd->cmd_type != CMD_SNAP_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
+		if (copy_from_user(&vfecmd,
+				(void __user *)(cmd->value),
+				sizeof(vfecmd))) {
+			pr_err("%s %d: copy_from_user failed\n", __func__,
+				__LINE__);
+			return -EFAULT;
+		}
+	} else {
+	/* here eith stats release or frame release. */
+		if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE &&
+			cmd->cmd_type != CMD_SNAP_BUF_RELEASE) {
+			/* then must be stats release. */
+			if (!data)
+				return -EFAULT;
+				sack = kmalloc(sizeof(struct vfe_cmd_stats_ack),
+				GFP_ATOMIC);
+				if (!sack)
+					return -ENOMEM;
+
+				sack->nextStatsBuf = *(uint32_t *)data;
+			}
+	}
+
+	CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
+
+	if ((cmd->cmd_type == CMD_STATS_AF_ENABLE) ||
+		(cmd->cmd_type == CMD_STATS_AWB_ENABLE) ||
+		(cmd->cmd_type == CMD_STATS_IHIST_ENABLE) ||
+		(cmd->cmd_type == CMD_STATS_RS_ENABLE) ||
+		(cmd->cmd_type == CMD_STATS_CS_ENABLE) ||
+		(cmd->cmd_type == CMD_STATS_AEC_ENABLE)) {
+		struct axidata *axid;
+		axid = data;
+		if (!axid) {
+			rc = -EFAULT;
+			goto vfe31_config_done;
+		}
+
+		scfg =
+			kmalloc(sizeof(struct vfe_cmd_stats_buf),
+				GFP_ATOMIC);
+		if (!scfg) {
+			rc = -ENOMEM;
+			goto vfe31_config_done;
+		}
+		regptr = axid->region;
+		if (axid->bufnum1 > 0) {
+			for (i = 0; i < axid->bufnum1; i++) {
+				scfg->statsBuf[i] =
+					(uint32_t)(regptr->paddr);
+				regptr++;
+			}
+		}
+		/* individual */
+		switch (cmd->cmd_type) {
+		case CMD_STATS_AEC_ENABLE:
+			rc = vfe_stats_aec_buf_init(scfg);
+			break;
+		case CMD_STATS_AF_ENABLE:
+			rc = vfe_stats_af_buf_init(scfg);
+			break;
+		case CMD_STATS_AWB_ENABLE:
+			rc = vfe_stats_awb_buf_init(scfg);
+			break;
+		case CMD_STATS_IHIST_ENABLE:
+			rc = vfe_stats_ihist_buf_init(scfg);
+			break;
+		case CMD_STATS_RS_ENABLE:
+			rc = vfe_stats_rs_buf_init(scfg);
+			break;
+		case CMD_STATS_CS_ENABLE:
+			rc = vfe_stats_cs_buf_init(scfg);
+			break;
+		}
+	}
+
+	switch (cmd->cmd_type) {
+	case CMD_GENERAL:
+		rc = vfe31_proc_general(&vfecmd);
+		break;
+
+	case CMD_FRAME_BUF_RELEASE: {
+		struct msm_frame *b;
+		unsigned long p;
+		int ret;
+		struct vfe31_output_ch *outch = NULL;
+		if (!data) {
+			rc = -EFAULT;
+			break;
+		}
+
+		b = (struct msm_frame *)(cmd->value);
+		p = *(unsigned long *)data;
+
+		CDBG("CMD_FRAME_BUF_RELEASE b->path = %d\n", b->path);
+
+		if (b->path & OUTPUT_TYPE_P) {
+			CDBG("CMD_FRAME_BUF_RELEASE got free buffer\n");
+			outch = &vfe31_ctrl->outpath.out0;
+		} else if (b->path & OUTPUT_TYPE_S) {
+			outch = &vfe31_ctrl->outpath.out1;
+		} else if (b->path & OUTPUT_TYPE_V) {
+			outch = &vfe31_ctrl->outpath.out2;
+		} else {
+			rc = -EFAULT;
+			break;
+		}
+
+		ret = vfe31_add_free_buf2(outch, p, b->y_off, b->cbcr_off);
+		if (ret < 0)
+			return ret;
+		break;
+	}
+
+	case CMD_SNAP_BUF_RELEASE: {
+		struct msm_frame *b;
+		unsigned long p;
+		int ret;
+		struct vfe31_output_ch *outch = NULL;
+		if (!data)
+			return -EFAULT;
+
+		b = (struct msm_frame *)(cmd->value);
+		p = *(unsigned long *)data;
+
+		CDBG("CMD_PIC_BUF_RELEASE b->path = %d\n", b->path);
+
+		if (b->path & OUTPUT_TYPE_T) {
+			CDBG("CMD_FRAME_BUF_RELEASE got free buffer\n");
+			outch = &vfe31_ctrl->outpath.out1;
+		} else if (b->path & OUTPUT_TYPE_S) {
+			outch = &vfe31_ctrl->outpath.out2;
+		} else
+			return -EFAULT;
+
+		ret = vfe31_add_free_buf2(outch, p, b->y_off, b->cbcr_off);
+		if (ret < 0)
+			return ret;
+		break;
+	}
+
+	case CMD_STATS_AEC_BUF_RELEASE:
+		vfe31_stats_aec_ack(sack);
+		break;
+
+	case CMD_STATS_AF_BUF_RELEASE:
+		vfe31_stats_af_ack(sack);
+		break;
+
+	case CMD_STATS_AWB_BUF_RELEASE:
+		vfe31_stats_awb_ack(sack);
+		break;
+
+	case CMD_STATS_IHIST_BUF_RELEASE:
+		vfe31_stats_ihist_ack(sack);
+		break;
+
+	case CMD_STATS_RS_BUF_RELEASE:
+		vfe31_stats_rs_ack(sack);
+		break;
+
+	case CMD_STATS_CS_BUF_RELEASE:
+		vfe31_stats_cs_ack(sack);
+		break;
+
+	case CMD_AXI_CFG_PREVIEW: {
+		struct axidata *axid;
+		uint32_t *axio = NULL;
+		axid = data;
+		if (!axid) {
+			rc = -EFAULT;
+			break;
+		}
+		axio =
+			kmalloc(vfe31_cmd[V31_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			break;
+		}
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe31_cmd[V31_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			rc = -EFAULT;
+			break;
+		}
+		vfe31_config_axi(OUTPUT_2, axid, axio);
+		kfree(axio);
+		break;
+	}
+
+	case CMD_RAW_PICT_AXI_CFG: {
+		struct axidata *axid;
+		uint32_t *axio = NULL;
+		axid = data;
+		if (!axid) {
+			rc = -EFAULT;
+			break;
+		}
+		axio =
+			kmalloc(vfe31_cmd[V31_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			break;
+		}
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe31_cmd[V31_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			rc = -EFAULT;
+			break;
+		}
+		vfe31_config_axi(CAMIF_TO_AXI_VIA_OUTPUT_2, axid, axio);
+		kfree(axio);
+		break;
+	}
+
+	case CMD_AXI_CFG_SNAP: {
+		struct axidata *axid;
+		uint32_t *axio = NULL;
+		CDBG("%s, CMD_AXI_CFG_SNAP\n", __func__);
+		axid = data;
+		if (!axid)
+			return -EFAULT;
+		axio =
+			kmalloc(vfe31_cmd[V31_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			break;
+		}
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe31_cmd[V31_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			rc = -EFAULT;
+			break;
+		}
+		vfe31_config_axi(OUTPUT_1_AND_2, axid, axio);
+		kfree(axio);
+		break;
+	}
+
+	case CMD_AXI_CFG_ZSL: {
+		struct axidata *axid;
+		uint32_t *axio = NULL;
+		CDBG("%s, CMD_AXI_CFG_ZSL\n", __func__);
+		axid = data;
+		if (!axid)
+			return -EFAULT;
+		axio =
+			kmalloc(vfe31_cmd[V31_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			break;
+		}
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe31_cmd[V31_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			rc = -EFAULT;
+			break;
+		}
+		vfe31_config_axi(OUTPUT_1_2_AND_3, axid, axio);
+		kfree(axio);
+	}
+		break;
+
+	case CMD_AXI_CFG_VIDEO: {
+		struct axidata *axid;
+		uint32_t *axio = NULL;
+		axid = data;
+		if (!axid) {
+			rc = -EFAULT;
+			break;
+		}
+
+		axio =
+			kmalloc(vfe31_cmd[V31_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			break;
+		}
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe31_cmd[V31_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			rc = -EFAULT;
+			break;
+		}
+		vfe31_config_axi(OUTPUT_1_AND_3, axid, axio);
+		kfree(axio);
+		break;
+	}
+
+	default:
+		break;
+	}
+vfe31_config_done:
+	kfree(scfg);
+	kfree(sack);
+	CDBG("%s done: rc = %d\n", __func__, (int) rc);
+	return rc;
+}
+
+static void vfe31_send_msg_no_payload(enum VFE31_MESSAGE_ID id)
+{
+	struct vfe_message msg;
+
+	CDBG("vfe31_send_msg_no_payload\n");
+	msg._d = id;
+	vfe31_proc_ops(id, &msg, 0);
+}
+
+static void vfe31_process_reg_update_irq(void)
+{
+	uint32_t  temp, old_val;
+	unsigned long flags;
+	if (vfe31_ctrl->recording_state == VFE_REC_STATE_START_REQUESTED) {
+		if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_V) {
+			msm_io_w(1, vfe31_ctrl->vfebase +
+				vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out2.ch0]);
+			msm_io_w(1, vfe31_ctrl->vfebase +
+				vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out2.ch1]);
+		}
+		vfe31_ctrl->recording_state = VFE_REC_STATE_STARTED;
+		if (vpe_ctrl->dis_en) {
+			old_val = msm_io_r(
+				vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+			old_val |= RS_CS_ENABLE_MASK;
+			msm_io_w(old_val,
+				vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		}
+		msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+		CDBG("start video triggered .\n");
+	} else if (vfe31_ctrl->recording_state
+			== VFE_REC_STATE_STOP_REQUESTED) {
+		if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_V) {
+			msm_io_w(0, vfe31_ctrl->vfebase +
+				vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out2.ch0]);
+			msm_io_w(0, vfe31_ctrl->vfebase +
+				vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out2.ch1]);
+		}
+
+		/*disable rs& cs when stop recording. */
+		old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= (~RS_CS_ENABLE_MASK);
+		msm_io_w(old_val,
+				vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		CDBG("stop video triggered\n");
+	}
+	if (vfe31_ctrl->start_ack_pending == TRUE) {
+		vfe31_send_msg_no_payload(MSG_ID_START_ACK);
+		vfe31_ctrl->start_ack_pending = FALSE;
+	} else {
+		if (vfe31_ctrl->recording_state ==
+			VFE_REC_STATE_STOP_REQUESTED) {
+			vfe31_ctrl->recording_state = VFE_REC_STATE_STOPPED;
+			msm_io_w_mb(1, vfe31_ctrl->vfebase +
+						VFE_REG_UPDATE_CMD);
+		} else if (vfe31_ctrl->recording_state ==
+			VFE_REC_STATE_STOPPED) {
+			CDBG("sent stop video rec ACK");
+			vfe31_send_msg_no_payload(MSG_ID_STOP_REC_ACK);
+			vfe31_ctrl->recording_state = VFE_REC_STATE_IDLE;
+		}
+		spin_lock_irqsave(&vfe31_ctrl->update_ack_lock, flags);
+		if (vfe31_ctrl->update_ack_pending == TRUE) {
+			vfe31_ctrl->update_ack_pending = FALSE;
+			spin_unlock_irqrestore(
+				&vfe31_ctrl->update_ack_lock, flags);
+			vfe31_send_msg_no_payload(MSG_ID_UPDATE_ACK);
+		} else {
+			spin_unlock_irqrestore(
+				&vfe31_ctrl->update_ack_lock, flags);
+		}
+	}
+	/* in snapshot mode */
+	if (vfe31_ctrl->operation_mode ==
+		VFE_MODE_OF_OPERATION_SNAPSHOT) {
+		/* later we need to add check for live snapshot mode. */
+
+		if (vfe31_ctrl->vfe_capture_count)
+			vfe31_ctrl->vfe_capture_count--;
+		/* if last frame to be captured: */
+		if (vfe31_ctrl->vfe_capture_count == 0) {
+			/* stop the bus output:  write master enable = 0*/
+			if (vfe31_ctrl->outpath.output_mode &
+					VFE31_OUTPUT_MODE_PT) {
+				msm_io_w(0, vfe31_ctrl->vfebase +
+					vfe31_AXI_WM_CFG[
+						vfe31_ctrl->outpath.out0.ch0]);
+				msm_io_w(0, vfe31_ctrl->vfebase +
+					vfe31_AXI_WM_CFG[vfe31_ctrl->
+						outpath.out0.ch1]);
+			}
+			if (vfe31_ctrl->outpath.output_mode &
+					VFE31_OUTPUT_MODE_S) {
+				msm_io_w(0, vfe31_ctrl->vfebase +
+					vfe31_AXI_WM_CFG[vfe31_ctrl->
+						outpath.out1.ch0]);
+				msm_io_w(0, vfe31_ctrl->vfebase +
+					vfe31_AXI_WM_CFG[vfe31_ctrl->
+						outpath.out1.ch1]);
+			}
+
+			/* Ensure the write order while writing
+			to the command register using the barrier */
+			msm_io_w_mb(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+				vfe31_ctrl->vfebase + VFE_CAMIF_COMMAND);
+
+			/* Ensure the read order while reading
+			to the command register using the barrier */
+			temp = msm_io_r_mb(vfe31_ctrl->vfebase +
+				VFE_CAMIF_COMMAND);
+		}
+		/* then do reg_update. */
+		msm_io_w_mb(1, vfe31_ctrl->vfebase +
+			VFE_REG_UPDATE_CMD);
+	} /* if snapshot mode. */
+}
+
+static void vfe31_set_default_reg_values(void)
+{
+	msm_io_w(0x800080, vfe31_ctrl->vfebase + VFE_DEMUX_GAIN_0);
+	msm_io_w(0x800080, vfe31_ctrl->vfebase + VFE_DEMUX_GAIN_1);
+	msm_io_w(0xFFFFF, vfe31_ctrl->vfebase + VFE_CGC_OVERRIDE);
+
+	/* default frame drop period and pattern */
+	msm_io_w(0x1f, vfe31_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG);
+	msm_io_w(0x1f, vfe31_ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_CFG);
+	msm_io_w(0xFFFFFFFF, vfe31_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN);
+	msm_io_w(0xFFFFFFFF,
+		vfe31_ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_PATTERN);
+	msm_io_w(0x1f, vfe31_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y);
+	msm_io_w(0x1f, vfe31_ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR);
+	msm_io_w(0xFFFFFFFF,
+		vfe31_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN);
+	msm_io_w(0xFFFFFFFF,
+		vfe31_ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR_PATTERN);
+	msm_io_w(0, vfe31_ctrl->vfebase + VFE_CLAMP_MIN);
+	msm_io_w(0xFFFFFF, vfe31_ctrl->vfebase + VFE_CLAMP_MAX);
+
+	/* stats UB config */
+	msm_io_w(0x3980007, vfe31_ctrl->vfebase + VFE_BUS_STATS_AEC_UB_CFG);
+	msm_io_w(0x3A00007, vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_UB_CFG);
+	msm_io_w(0x3A8000F, vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_UB_CFG);
+	msm_io_w(0x3B80007, vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_UB_CFG);
+	msm_io_w(0x3C0001F, vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_UB_CFG);
+	msm_io_w(0x3E0001F, vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_UB_CFG);
+}
+
+static void vfe31_process_reset_irq(void)
+{
+	atomic_set(&vfe31_ctrl->vstate, 0);
+	vfe31_ctrl->while_stopping_mask = VFE_IMASK_WHILE_STOPPING_1;
+	if (atomic_read(&vfe31_ctrl->stop_ack_pending)) {
+		/* this is from the stop command. */
+		atomic_set(&vfe31_ctrl->stop_ack_pending, 0);
+		vfe31_send_msg_no_payload(MSG_ID_STOP_ACK);
+	} else {
+		/* this is from reset command. */
+		vfe31_set_default_reg_values();
+
+		/* reload all write masters. (frame & line)*/
+		msm_io_w_mb(0x7FFF, vfe31_ctrl->vfebase + VFE_BUS_CMD);
+		vfe31_send_msg_no_payload(MSG_ID_RESET_ACK);
+	}
+}
+
+
+static void vfe31_process_axi_halt_irq(void)
+{
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_io_w_mb(AXI_HALT_CLEAR,
+		vfe31_ctrl->vfebase + VFE_AXI_CMD);
+	vfe31_ctrl->while_stopping_mask = VFE_IMASK_RESET;
+
+	/* disable all interrupts.  */
+	msm_io_w(VFE_DISABLE_ALL_IRQS,
+		vfe31_ctrl->vfebase + VFE_IRQ_MASK_0);
+	msm_io_w(VFE_DISABLE_ALL_IRQS,
+		vfe31_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+	/* clear all pending interrupts*/
+	msm_io_w(VFE_CLEAR_ALL_IRQS,
+		vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+	msm_io_w(VFE_CLEAR_ALL_IRQS,
+		vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_io_w_mb(1,
+		vfe31_ctrl->vfebase + VFE_IRQ_CMD);
+
+	/* now enable only halt_irq & reset_irq */
+	msm_io_w(0xf0000000,          /* this is for async timer. */
+		vfe31_ctrl->vfebase + VFE_IRQ_MASK_0);
+	msm_io_w(VFE_IMASK_RESET,
+		vfe31_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	CDBG("%s: about to reset vfe...\n", __func__);
+	msm_io_w_mb(VFE_RESET_UPON_STOP_CMD,
+		vfe31_ctrl->vfebase + VFE_GLOBAL_RESET);
+
+}
+
+static void vfe31_process_camif_sof_irq(void)
+{
+	uint32_t  temp;
+
+	/* in raw snapshot mode */
+	if (vfe31_ctrl->operation_mode ==
+		VFE_MODE_OF_OPERATION_RAW_SNAPSHOT) {
+		if (vfe31_ctrl->start_ack_pending) {
+			vfe31_send_msg_no_payload(MSG_ID_START_ACK);
+			vfe31_ctrl->start_ack_pending = FALSE;
+		}
+		if (vfe31_ctrl->vfe_capture_count)
+			vfe31_ctrl->vfe_capture_count--;
+		/* if last frame to be captured: */
+		if (vfe31_ctrl->vfe_capture_count == 0) {
+			/* Ensure the write order while writing
+			to the command register using the barrier */
+			msm_io_w_mb(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+				vfe31_ctrl->vfebase + VFE_CAMIF_COMMAND);
+			temp = msm_io_r_mb(vfe31_ctrl->vfebase +
+				VFE_CAMIF_COMMAND);
+		}
+	} /* if raw snapshot mode. */
+
+	if ((vfe31_ctrl->hfr_mode != HFR_MODE_OFF) &&
+		(vfe31_ctrl->operation_mode == VFE_MODE_OF_OPERATION_VIDEO) &&
+		(vfe31_ctrl->vfeFrameId % vfe31_ctrl->hfr_mode != 0)) {
+		vfe31_ctrl->vfeFrameId++;
+		CDBG("Skip the SOF notification when HFR enabled\n");
+		return;
+	}
+	vfe31_send_msg_no_payload(MSG_ID_SOF_ACK);
+	vfe31_ctrl->vfeFrameId++;
+	CDBG("camif_sof_irq, frameId = %d\n", vfe31_ctrl->vfeFrameId);
+
+	if (vfe31_ctrl->sync_timer_state) {
+		if (vfe31_ctrl->sync_timer_repeat_count == 0)
+			vfe31_sync_timer_stop();
+		else
+		vfe31_ctrl->sync_timer_repeat_count--;
+	}
+}
+
+static void vfe31_process_error_irq(uint32_t errStatus)
+{
+	uint32_t camifStatus, read_val;
+	uint32_t *temp;
+
+	if (errStatus & VFE31_IMASK_CAMIF_ERROR) {
+		pr_err("vfe31_irq: camif errors\n");
+		temp = (uint32_t *)(vfe31_ctrl->vfebase + VFE_CAMIF_STATUS);
+		camifStatus = msm_io_r(temp);
+		pr_err("camifStatus  = 0x%x\n", camifStatus);
+		vfe31_send_msg_no_payload(MSG_ID_CAMIF_ERROR);
+	}
+
+	if (errStatus & VFE31_IMASK_STATS_CS_OVWR)
+		pr_err("vfe31_irq: stats cs overwrite\n");
+
+	if (errStatus & VFE31_IMASK_STATS_IHIST_OVWR)
+		pr_err("vfe31_irq: stats ihist overwrite\n");
+
+	if (errStatus & VFE31_IMASK_REALIGN_BUF_Y_OVFL)
+		pr_err("vfe31_irq: realign bug Y overflow\n");
+
+	if (errStatus & VFE31_IMASK_REALIGN_BUF_CB_OVFL)
+		pr_err("vfe31_irq: realign bug CB overflow\n");
+
+	if (errStatus & VFE31_IMASK_REALIGN_BUF_CR_OVFL)
+		pr_err("vfe31_irq: realign bug CR overflow\n");
+
+	if (errStatus & VFE31_IMASK_VIOLATION)
+		pr_err("vfe31_irq: violation interrupt\n");
+
+	if (errStatus & VFE31_IMASK_IMG_MAST_0_BUS_OVFL)
+		pr_err("vfe31_irq: image master 0 bus overflow\n");
+
+	if (errStatus & VFE31_IMASK_IMG_MAST_1_BUS_OVFL)
+		pr_err("vfe31_irq: image master 1 bus overflow\n");
+
+	if (errStatus & VFE31_IMASK_IMG_MAST_2_BUS_OVFL)
+		pr_err("vfe31_irq: image master 2 bus overflow\n");
+
+	if (errStatus & VFE31_IMASK_IMG_MAST_3_BUS_OVFL)
+		pr_err("vfe31_irq: image master 3 bus overflow\n");
+
+	if (errStatus & VFE31_IMASK_IMG_MAST_4_BUS_OVFL)
+		pr_err("vfe31_irq: image master 4 bus overflow\n");
+
+	if (errStatus & VFE31_IMASK_IMG_MAST_5_BUS_OVFL)
+		pr_err("vfe31_irq: image master 5 bus overflow\n");
+
+	if (errStatus & VFE31_IMASK_IMG_MAST_6_BUS_OVFL)
+		pr_err("vfe31_irq: image master 6 bus overflow\n");
+
+	if (errStatus & VFE31_IMASK_STATS_AE_BUS_OVFL)
+		pr_err("vfe31_irq: ae stats bus overflow\n");
+
+	if (errStatus & VFE31_IMASK_STATS_AF_BUS_OVFL)
+		pr_err("vfe31_irq: af stats bus overflow\n");
+
+	if (errStatus & VFE31_IMASK_STATS_AWB_BUS_OVFL)
+		pr_err("vfe31_irq: awb stats bus overflow\n");
+
+	if (errStatus & VFE31_IMASK_STATS_RS_BUS_OVFL)
+		pr_err("vfe31_irq: rs stats bus overflow\n");
+
+	if (errStatus & VFE31_IMASK_STATS_CS_BUS_OVFL)
+		pr_err("vfe31_irq: cs stats bus overflow\n");
+
+	if (errStatus & VFE31_IMASK_STATS_IHIST_BUS_OVFL)
+		pr_err("vfe31_irq: ihist stats bus overflow\n");
+
+	if (errStatus & VFE31_IMASK_STATS_SKIN_BUS_OVFL)
+		pr_err("vfe31_irq: skin stats bus overflow\n");
+
+	if (errStatus & VFE31_IMASK_AXI_ERROR) {
+		pr_err("vfe31_irq: axi error\n");
+		/* read status too when overflow happens.*/
+		read_val = msm_io_r(vfe31_ctrl->vfebase +
+			VFE_BUS_PING_PONG_STATUS);
+		pr_debug("VFE_BUS_PING_PONG_STATUS = 0x%x\n", read_val);
+		read_val = msm_io_r(vfe31_ctrl->vfebase +
+			VFE_BUS_OPERATION_STATUS);
+		pr_debug("VFE_BUS_OPERATION_STATUS = 0x%x\n", read_val);
+		read_val = msm_io_r(vfe31_ctrl->vfebase +
+			VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_0);
+		pr_debug("VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_0 = 0x%x\n",
+			read_val);
+		read_val = msm_io_r(vfe31_ctrl->vfebase +
+			VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_1);
+		pr_debug("VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_1 = 0x%x\n",
+			read_val);
+		read_val = msm_io_r(vfe31_ctrl->vfebase +
+			VFE_AXI_STATUS);
+		pr_debug("VFE_AXI_STATUS = 0x%x\n", read_val);
+	}
+}
+
+#define VFE31_AXI_OFFSET 0x0050
+#define vfe31_get_ch_ping_addr(chn) \
+	(msm_io_r(vfe31_ctrl->vfebase + 0x0050 + 0x18 * (chn)))
+#define vfe31_get_ch_pong_addr(chn) \
+	(msm_io_r(vfe31_ctrl->vfebase + 0x0050 + 0x18 * (chn) + 4))
+#define vfe31_get_ch_addr(ping_pong, chn) \
+	(((ping_pong) & (1 << (chn))) == 0 ? \
+	vfe31_get_ch_pong_addr(chn) : vfe31_get_ch_ping_addr(chn))
+
+#define vfe31_put_ch_ping_addr(chn, addr) \
+	(msm_io_w((addr), vfe31_ctrl->vfebase + 0x0050 + 0x18 * (chn)))
+#define vfe31_put_ch_pong_addr(chn, addr) \
+	(msm_io_w((addr), vfe31_ctrl->vfebase + 0x0050 + 0x18 * (chn) + 4))
+#define vfe31_put_ch_addr(ping_pong, chn, addr) \
+	(((ping_pong) & (1 << (chn))) == 0 ?   \
+	vfe31_put_ch_pong_addr((chn), (addr)) : \
+	vfe31_put_ch_ping_addr((chn), (addr)))
+
+static void vfe31_process_output_path_irq_0(uint32_t ping_pong)
+{
+	uint32_t pyaddr, pcbcraddr;
+#ifdef CONFIG_MSM_CAMERA_V4L2
+	uint32_t pyaddr_ping, pcbcraddr_ping, pyaddr_pong, pcbcraddr_pong;
+#endif
+	struct vfe31_free_buf *free_buf = NULL;
+	/* we render frames in the following conditions:
+	1. Continuous mode and the free buffer is avaialable.
+	*/
+	free_buf = vfe31_get_free_buf(&vfe31_ctrl->outpath.out0);
+
+	if (free_buf) {
+		/* Y channel */
+		pyaddr = vfe31_get_ch_addr(ping_pong,
+			vfe31_ctrl->outpath.out0.ch0);
+		/* Chroma channel */
+		pcbcraddr = vfe31_get_ch_addr(ping_pong,
+			vfe31_ctrl->outpath.out0.ch1);
+
+		CDBG("output path 0, pyaddr = 0x%x, pcbcraddr = 0x%x\n",
+			 pyaddr, pcbcraddr);
+		/* Y channel */
+		vfe31_put_ch_addr(ping_pong,
+			vfe31_ctrl->outpath.out0.ch0,
+			free_buf->paddr + free_buf->y_off);
+		/* Chroma channel */
+		vfe31_put_ch_addr(ping_pong,
+			vfe31_ctrl->outpath.out0.ch1,
+			free_buf->paddr + free_buf->cbcr_off);
+
+		kfree(free_buf);
+		/* if continuous mode, for display. (preview) */
+		vfe_send_outmsg(MSG_ID_OUTPUT_P, pyaddr, pcbcraddr);
+	} else {
+		vfe31_ctrl->outpath.out0.frame_drop_cnt++;
+		pr_warning("path_irq_0 - no free buffer!\n");
+#ifdef CONFIG_MSM_CAMERA_V4L2
+		pr_info("Swapping ping and pong\n");
+
+		/*get addresses*/
+		/* Y channel */
+		pyaddr_ping = vfe31_get_ch_ping_addr(
+			vfe31_ctrl->outpath.out0.ch0);
+		/* Chroma channel */
+		pcbcraddr_ping = vfe31_get_ch_ping_addr(
+			vfe31_ctrl->outpath.out0.ch1);
+		/* Y channel */
+		pyaddr_pong = vfe31_get_ch_pong_addr(
+			vfe31_ctrl->outpath.out0.ch0);
+		/* Chroma channel */
+		pcbcraddr_pong = vfe31_get_ch_pong_addr(
+			vfe31_ctrl->outpath.out0.ch1);
+
+		CDBG("ping = 0x%p, pong = 0x%p\n", (void *)pyaddr_ping,
+			(void *)pyaddr_pong);
+		CDBG("ping_cbcr = 0x%p, pong_cbcr = 0x%p\n",
+			(void *)pcbcraddr_ping, (void *)pcbcraddr_pong);
+
+		/*put addresses*/
+		/* SWAP y channel*/
+		vfe31_put_ch_ping_addr(vfe31_ctrl->outpath.out0.ch0,
+			pyaddr_pong);
+		vfe31_put_ch_pong_addr(vfe31_ctrl->outpath.out0.ch0,
+			pyaddr_ping);
+		/* SWAP chroma channel*/
+		vfe31_put_ch_ping_addr(vfe31_ctrl->outpath.out0.ch1,
+			pcbcraddr_pong);
+		vfe31_put_ch_pong_addr(vfe31_ctrl->outpath.out0.ch1,
+			pcbcraddr_ping);
+		CDBG("after swap: ping = 0x%p, pong = 0x%p\n",
+			(void *)pyaddr_pong, (void *)pyaddr_ping);
+#endif
+	}
+}
+
+static void vfe31_process_snapshot_frame(uint32_t ping_pong)
+{
+	uint32_t pyaddr, pcbcraddr;
+	struct vfe31_free_buf *free_buf = NULL;
+	/* Y channel- Main Image */
+	pyaddr = vfe31_get_ch_addr(ping_pong,
+		vfe31_ctrl->outpath.out1.ch0);
+	/* Chroma channel - TN Image */
+	pcbcraddr = vfe31_get_ch_addr(ping_pong,
+		vfe31_ctrl->outpath.out1.ch1);
+
+	free_buf = vfe31_get_free_buf(&vfe31_ctrl->outpath.out1);
+	CDBG("%s: snapshot main, pyaddr = 0x%x, pcbcraddr = 0x%x\n",
+		__func__, pyaddr, pcbcraddr);
+	if (free_buf) {
+		/* Y channel */
+		vfe31_put_ch_addr(ping_pong,
+			vfe31_ctrl->outpath.out1.ch0,
+			free_buf->paddr + free_buf->y_off);
+		/* Chroma channel */
+		vfe31_put_ch_addr(ping_pong,
+			vfe31_ctrl->outpath.out1.ch1,
+			free_buf->paddr + free_buf->cbcr_off);
+		kfree(free_buf);
+	}
+	vfe_send_outmsg(MSG_ID_OUTPUT_S, pyaddr, pcbcraddr);
+
+	/* Y channel- TN Image */
+	pyaddr = vfe31_get_ch_addr(ping_pong,
+		vfe31_ctrl->outpath.out0.ch0);
+	/* Chroma channel - TN Image */
+	pcbcraddr = vfe31_get_ch_addr(ping_pong,
+		vfe31_ctrl->outpath.out0.ch1);
+
+	free_buf = vfe31_get_free_buf(&vfe31_ctrl->outpath.out0);
+	CDBG("%s: snapshot TN, pyaddr = 0x%x, pcbcraddr = 0x%x\n",
+		__func__, pyaddr, pcbcraddr);
+	if (free_buf) {
+		/* Y channel */
+		vfe31_put_ch_addr(ping_pong,
+			vfe31_ctrl->outpath.out0.ch0,
+			free_buf->paddr + free_buf->y_off);
+		/* Chroma channel */
+		vfe31_put_ch_addr(ping_pong,
+			vfe31_ctrl->outpath.out0.ch1,
+			free_buf->paddr + free_buf->cbcr_off);
+		kfree(free_buf);
+	}
+
+	vfe_send_outmsg(MSG_ID_OUTPUT_T, pyaddr, pcbcraddr);
+
+	/* in snapshot mode if done then send
+		snapshot done message */
+	if (vfe31_ctrl->vfe_capture_count == 0) {
+		vfe31_send_msg_no_payload(MSG_ID_SNAPSHOT_DONE);
+		/* Ensure the write order while writing
+			to the cmd register using barrier */
+		msm_io_w_mb(CAMIF_COMMAND_STOP_IMMEDIATELY,
+			vfe31_ctrl->vfebase +
+			VFE_CAMIF_COMMAND);
+	}
+}
+
+static void vfe31_process_raw_snapshot_frame(uint32_t ping_pong)
+{
+	uint32_t pyaddr, pcbcraddr;
+	struct vfe31_free_buf *free_buf = NULL;
+	struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata;
+
+	if (p_sync->stereocam_enabled)
+		p_sync->stereo_state = STEREO_RAW_SNAP_STARTED;
+
+	/* Y channel- Main Image */
+	pyaddr = vfe31_get_ch_addr(ping_pong,
+		vfe31_ctrl->outpath.out1.ch0);
+	/* Chroma channel - Main Image */
+	pcbcraddr = vfe31_get_ch_addr(ping_pong,
+		vfe31_ctrl->outpath.out1.ch1);
+
+	free_buf = vfe31_get_free_buf(&vfe31_ctrl->outpath.out1);
+	CDBG("%s: snapshot raw, pyaddr = 0x%x, pcbcraddr = 0x%x\n",
+		__func__, pyaddr, pcbcraddr);
+	if (free_buf) {
+		/* Y channel */
+		vfe31_put_ch_addr(ping_pong,
+			vfe31_ctrl->outpath.out1.ch0,
+			free_buf->paddr + free_buf->y_off);
+		/* Chroma channel */
+		vfe31_put_ch_addr(ping_pong,
+			vfe31_ctrl->outpath.out1.ch1,
+			free_buf->paddr + free_buf->cbcr_off);
+		kfree(free_buf);
+	}
+	 vfe_send_outmsg(MSG_ID_OUTPUT_S, pyaddr, pcbcraddr);
+
+	/* in snapshot mode if done then send
+		snapshot done message */
+	if (vfe31_ctrl->vfe_capture_count == 0) {
+		vfe31_send_msg_no_payload(MSG_ID_SNAPSHOT_DONE);
+		/* Ensure the write order while writing
+		to the cmd register using barrier */
+		msm_io_w_mb(CAMIF_COMMAND_STOP_IMMEDIATELY,
+			vfe31_ctrl->vfebase +
+			VFE_CAMIF_COMMAND);
+	}
+}
+static void vfe31_process_zsl_frame(uint32_t ping_pong)
+{
+	uint32_t pyaddr, pcbcraddr;
+	struct vfe31_free_buf *free_buf = NULL;
+	/* Y channel- Main Image */
+	pyaddr = vfe31_get_ch_addr(ping_pong,
+		vfe31_ctrl->outpath.out2.ch0);
+	/* Chroma channel - Main Image */
+	pcbcraddr = vfe31_get_ch_addr(ping_pong,
+		vfe31_ctrl->outpath.out2.ch1);
+
+	free_buf = vfe31_get_free_buf(&vfe31_ctrl->outpath.out2);
+	CDBG("%s: snapshot main, pyaddr = 0x%x, pcbcraddr = 0x%x\n",
+		__func__, pyaddr, pcbcraddr);
+	if (free_buf) {
+		/* Y channel */
+		vfe31_put_ch_addr(ping_pong,
+			vfe31_ctrl->outpath.out2.ch0,
+			free_buf->paddr + free_buf->y_off);
+		/* Chroma channel */
+		vfe31_put_ch_addr(ping_pong,
+			vfe31_ctrl->outpath.out2.ch1,
+			free_buf->paddr + free_buf->cbcr_off);
+		kfree(free_buf);
+	}
+	 vfe_send_outmsg(MSG_ID_OUTPUT_S, pyaddr, pcbcraddr);
+
+	/* Y channel- TN Image */
+	pyaddr = vfe31_get_ch_addr(ping_pong,
+		vfe31_ctrl->outpath.out1.ch0);
+	/* Chroma channel - TN Image */
+	pcbcraddr = vfe31_get_ch_addr(ping_pong,
+		vfe31_ctrl->outpath.out1.ch1);
+
+	free_buf = vfe31_get_free_buf(&vfe31_ctrl->outpath.out1);
+	CDBG("%s: snapshot TN, pyaddr = 0x%x, pcbcraddr = 0x%x\n",
+		__func__, pyaddr, pcbcraddr);
+	if (free_buf) {
+		/* Y channel */
+		vfe31_put_ch_addr(ping_pong,
+			vfe31_ctrl->outpath.out1.ch0,
+			free_buf->paddr + free_buf->y_off);
+		/* Chroma channel */
+		vfe31_put_ch_addr(ping_pong,
+			vfe31_ctrl->outpath.out1.ch1,
+			free_buf->paddr + free_buf->cbcr_off);
+		kfree(free_buf);
+	}
+
+	vfe_send_outmsg(MSG_ID_OUTPUT_T, pyaddr, pcbcraddr);
+}
+
+static void vfe31_process_output_path_irq_1(uint32_t ping_pong)
+{
+
+#ifdef CONFIG_MSM_CAMERA_V4L2
+	uint32_t pyaddr_ping, pcbcraddr_ping, pyaddr_pong, pcbcraddr_pong;
+#endif
+	CDBG("%s, operation_mode = %d, cap_cnt = %d\n", __func__,
+		vfe31_ctrl->operation_mode, vfe31_ctrl->vfe_capture_count);
+
+	/* In Snapshot mode */
+	if ((VFE_MODE_OF_OPERATION_SNAPSHOT == vfe31_ctrl->operation_mode)
+		&& ((vfe31_ctrl->vfe_capture_count <= 1)
+		|| (vfe31_free_buf_available(vfe31_ctrl->outpath.out0) &&
+		vfe31_free_buf_available(vfe31_ctrl->outpath.out1)))) {
+		vfe31_process_snapshot_frame(ping_pong);
+	} else if ((VFE_MODE_OF_OPERATION_RAW_SNAPSHOT ==
+		vfe31_ctrl->operation_mode) &&
+		((vfe31_ctrl->vfe_capture_count <= 1) ||
+		vfe31_free_buf_available(vfe31_ctrl->outpath.out1))) {
+		vfe31_process_raw_snapshot_frame(ping_pong);
+	} else if ((VFE_MODE_OF_OPERATION_ZSL == vfe31_ctrl->operation_mode)
+		&& (vfe31_free_buf_available(vfe31_ctrl->outpath.out1)
+		&& vfe31_free_buf_available(vfe31_ctrl->outpath.out2))) {
+		vfe31_process_zsl_frame(ping_pong);
+	} else {
+		vfe31_ctrl->outpath.out1.frame_drop_cnt++;
+		pr_info("path_irq_1 - no free buffer!\n");
+#ifdef CONFIG_MSM_CAMERA_V4L2
+		pr_info("Swapping ping and pong\n");
+
+		/*get addresses*/
+		/* Y channel */
+		pyaddr_ping = vfe31_get_ch_ping_addr(
+			vfe31_ctrl->outpath.out1.ch0);
+		/* Chroma channel */
+		pcbcraddr_ping = vfe31_get_ch_ping_addr(
+			vfe31_ctrl->outpath.out1.ch1);
+		/* Y channel */
+		pyaddr_pong = vfe31_get_ch_pong_addr(
+			vfe31_ctrl->outpath.out1.ch0);
+		/* Chroma channel */
+		pcbcraddr_pong = vfe31_get_ch_pong_addr(
+			vfe31_ctrl->outpath.out1.ch1);
+
+		CDBG("ping = 0x%p, pong = 0x%p\n", (void *)pyaddr_ping,
+			(void *)pyaddr_pong);
+		CDBG("ping_cbcr = 0x%p, pong_cbcr = 0x%p\n",
+			(void *)pcbcraddr_ping, (void *)pcbcraddr_pong);
+
+		/*put addresses*/
+		/* SWAP y channel*/
+		vfe31_put_ch_ping_addr(vfe31_ctrl->outpath.out1.ch0,
+			pyaddr_pong);
+		vfe31_put_ch_pong_addr(vfe31_ctrl->outpath.out1.ch0,
+			pyaddr_ping);
+		/* SWAP chroma channel*/
+		vfe31_put_ch_ping_addr(vfe31_ctrl->outpath.out1.ch1,
+			pcbcraddr_pong);
+		vfe31_put_ch_pong_addr(vfe31_ctrl->outpath.out1.ch1,
+			pcbcraddr_ping);
+		CDBG("after swap: ping = 0x%p, pong = 0x%p\n",
+			(void *)pyaddr_pong, (void *)pyaddr_ping);
+#endif
+	}
+
+}
+
+static void vfe31_process_output_path_irq_2(uint32_t ping_pong)
+{
+	uint32_t pyaddr, pcbcraddr;
+	struct vfe31_free_buf *free_buf = NULL;
+
+#ifdef CONFIG_MSM_CAMERA_V4L2
+	uint32_t pyaddr_ping, pcbcraddr_ping, pyaddr_pong, pcbcraddr_pong;
+#endif
+	/* we render frames in the following conditions:
+	1. Continuous mode and the free buffer is avaialable.
+	*/
+	CDBG("%s, operation_mode = %d, state %d\n", __func__,
+		vfe31_ctrl->operation_mode,
+		vfe31_ctrl->recording_state);
+	/* Ensure that both wm1 and wm5 ping and pong buffers are active*/
+	if (!(((ping_pong & 0x22) == 0x22) ||
+		((ping_pong & 0x22) == 0x0))) {
+		pr_err(" Irq_2 - skip the frame pp_status is not proper"
+			"PP_status = 0x%x\n", ping_pong);
+		return;
+	}
+	if (vfe31_ctrl->recording_state == VFE_REC_STATE_STOPPED) {
+		vfe31_ctrl->outpath.out2.frame_drop_cnt++;
+		pr_warning("path_irq_2 - recording stopped\n");
+		return;
+	}
+
+	free_buf = vfe31_get_free_buf(&vfe31_ctrl->outpath.out2);
+
+	if (free_buf) {
+		/* Y channel */
+		pyaddr = vfe31_get_ch_addr(ping_pong,
+			vfe31_ctrl->outpath.out2.ch0);
+		/* Chroma channel */
+		pcbcraddr = vfe31_get_ch_addr(ping_pong,
+			vfe31_ctrl->outpath.out2.ch1);
+
+		CDBG("video output, pyaddr = 0x%x, pcbcraddr = 0x%x\n",
+			pyaddr, pcbcraddr);
+
+		/* Y channel */
+		vfe31_put_ch_addr(ping_pong,
+		vfe31_ctrl->outpath.out2.ch0,
+		free_buf->paddr + free_buf->y_off);
+		/* Chroma channel */
+		vfe31_put_ch_addr(ping_pong,
+		vfe31_ctrl->outpath.out2.ch1,
+		free_buf->paddr + free_buf->cbcr_off);
+		kfree(free_buf);
+		vfe_send_outmsg(MSG_ID_OUTPUT_V, pyaddr, pcbcraddr);
+	} else {
+		vfe31_ctrl->outpath.out2.frame_drop_cnt++;
+		pr_warning("path_irq_2 - no free buffer!\n");
+
+#ifdef CONFIG_MSM_CAMERA_V4L2
+		pr_info("Swapping ping and pong\n");
+
+		/*get addresses*/
+		/* Y channel */
+		pyaddr_ping = vfe31_get_ch_ping_addr(
+			vfe31_ctrl->outpath.out2.ch0);
+		/* Chroma channel */
+		pcbcraddr_ping = vfe31_get_ch_ping_addr(
+			vfe31_ctrl->outpath.out2.ch1);
+		/* Y channel */
+		pyaddr_pong = vfe31_get_ch_pong_addr(
+			vfe31_ctrl->outpath.out2.ch0);
+		/* Chroma channel */
+		pcbcraddr_pong = vfe31_get_ch_pong_addr(
+			vfe31_ctrl->outpath.out2.ch1);
+
+		CDBG("ping = 0x%p, pong = 0x%p\n", (void *)pyaddr_ping,
+			(void *)pyaddr_pong);
+		CDBG("ping_cbcr = 0x%p, pong_cbcr = 0x%p\n",
+			(void *)pcbcraddr_ping, (void *)pcbcraddr_pong);
+
+		/*put addresses*/
+		/* SWAP y channel*/
+		vfe31_put_ch_ping_addr(vfe31_ctrl->outpath.out2.ch0,
+			pyaddr_pong);
+		vfe31_put_ch_pong_addr(vfe31_ctrl->outpath.out2.ch0,
+			pyaddr_ping);
+		/* SWAP chroma channel*/
+		vfe31_put_ch_ping_addr(vfe31_ctrl->outpath.out2.ch1,
+			pcbcraddr_pong);
+		vfe31_put_ch_pong_addr(vfe31_ctrl->outpath.out2.ch1,
+			pcbcraddr_ping);
+		CDBG("after swap: ping = 0x%p, pong = 0x%p\n",
+			(void *)pyaddr_pong, (void *)pyaddr_ping);
+#endif
+	}
+}
+
+
+static uint32_t  vfe31_process_stats_irq_common(uint32_t statsNum,
+						uint32_t newAddr) {
+
+	uint32_t pingpongStatus;
+	uint32_t returnAddr;
+	uint32_t pingpongAddr;
+
+	/* must be 0=ping, 1=pong */
+	pingpongStatus =
+		((msm_io_r(vfe31_ctrl->vfebase +
+		VFE_BUS_PING_PONG_STATUS))
+	& ((uint32_t)(1<<(statsNum + 7)))) >> (statsNum + 7);
+	/* stats bits starts at 7 */
+	CDBG("statsNum %d, pingpongStatus %d\n", statsNum, pingpongStatus);
+	pingpongAddr =
+		((uint32_t)(vfe31_ctrl->vfebase +
+				VFE_BUS_STATS_PING_PONG_BASE)) +
+				(3*statsNum)*4 + (1-pingpongStatus)*4;
+	returnAddr = msm_io_r((uint32_t *)pingpongAddr);
+	msm_io_w(newAddr, (uint32_t *)pingpongAddr);
+	return returnAddr;
+}
+
+static void vfe_send_stats_msg(void)
+{
+	struct  vfe_message msg;
+	/* fill message with right content. */
+	msg._u.msgStats.frameCounter = vfe31_ctrl->vfeFrameId;
+	msg._u.msgStats.status_bits = vfe31_ctrl->status_bits;
+	msg._d = MSG_ID_COMMON;
+
+	msg._u.msgStats.buff.aec = vfe31_ctrl->aecStatsControl.bufToRender;
+	msg._u.msgStats.buff.awb = vfe31_ctrl->awbStatsControl.bufToRender;
+	msg._u.msgStats.buff.af = vfe31_ctrl->afStatsControl.bufToRender;
+
+	msg._u.msgStats.buff.ihist = vfe31_ctrl->ihistStatsControl.bufToRender;
+	msg._u.msgStats.buff.rs = vfe31_ctrl->rsStatsControl.bufToRender;
+	msg._u.msgStats.buff.cs = vfe31_ctrl->csStatsControl.bufToRender;
+
+	vfe31_proc_ops(msg._d,
+		&msg, sizeof(struct vfe_message));
+	return;
+}
+
+static void vfe31_process_stats(void)
+{
+	int32_t process_stats = false;
+
+	CDBG("%s, stats = 0x%x\n", __func__, vfe31_ctrl->status_bits);
+
+	if (vfe31_ctrl->status_bits & VFE_IRQ_STATUS0_STATS_AEC) {
+		if (!vfe31_ctrl->aec_ack_pending) {
+			vfe31_ctrl->aec_ack_pending = TRUE;
+			vfe31_ctrl->aecStatsControl.bufToRender =
+				vfe31_process_stats_irq_common(statsAeNum,
+				vfe31_ctrl->aecStatsControl.nextFrameAddrBuf);
+			process_stats = true;
+		} else{
+			vfe31_ctrl->aecStatsControl.bufToRender = 0;
+			vfe31_ctrl->aecStatsControl.droppedStatsFrameCount++;
+		}
+	} else {
+		vfe31_ctrl->aecStatsControl.bufToRender = 0;
+	}
+
+	if (vfe31_ctrl->status_bits & VFE_IRQ_STATUS0_STATS_AWB) {
+		if (!vfe31_ctrl->awb_ack_pending) {
+			vfe31_ctrl->awb_ack_pending = TRUE;
+			vfe31_ctrl->awbStatsControl.bufToRender =
+				vfe31_process_stats_irq_common(statsAwbNum,
+				vfe31_ctrl->awbStatsControl.nextFrameAddrBuf);
+			process_stats = true;
+		} else{
+			vfe31_ctrl->awbStatsControl.droppedStatsFrameCount++;
+			vfe31_ctrl->awbStatsControl.bufToRender = 0;
+		}
+	} else {
+		vfe31_ctrl->awbStatsControl.bufToRender = 0;
+	}
+
+
+	if (vfe31_ctrl->status_bits & VFE_IRQ_STATUS0_STATS_AF) {
+		if (!vfe31_ctrl->af_ack_pending) {
+			vfe31_ctrl->af_ack_pending = TRUE;
+			vfe31_ctrl->afStatsControl.bufToRender =
+				vfe31_process_stats_irq_common(statsAfNum,
+				vfe31_ctrl->afStatsControl.nextFrameAddrBuf);
+			process_stats = true;
+		} else {
+			vfe31_ctrl->afStatsControl.bufToRender = 0;
+			vfe31_ctrl->afStatsControl.droppedStatsFrameCount++;
+		}
+	} else {
+		vfe31_ctrl->afStatsControl.bufToRender = 0;
+	}
+
+	if (vfe31_ctrl->status_bits & VFE_IRQ_STATUS0_STATS_IHIST) {
+		if (!vfe31_ctrl->ihist_ack_pending) {
+			vfe31_ctrl->ihist_ack_pending = TRUE;
+			vfe31_ctrl->ihistStatsControl.bufToRender =
+				vfe31_process_stats_irq_common(statsIhistNum,
+				vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf);
+			process_stats = true;
+		} else {
+			vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount++;
+			vfe31_ctrl->ihistStatsControl.bufToRender = 0;
+		}
+	} else {
+		vfe31_ctrl->ihistStatsControl.bufToRender = 0;
+	}
+
+	if (vfe31_ctrl->status_bits & VFE_IRQ_STATUS0_STATS_RS) {
+		if (!vfe31_ctrl->rs_ack_pending) {
+			vfe31_ctrl->rs_ack_pending = TRUE;
+			vfe31_ctrl->rsStatsControl.bufToRender =
+				vfe31_process_stats_irq_common(statsRsNum,
+				vfe31_ctrl->rsStatsControl.nextFrameAddrBuf);
+			process_stats = true;
+		} else {
+			vfe31_ctrl->rsStatsControl.droppedStatsFrameCount++;
+			vfe31_ctrl->rsStatsControl.bufToRender = 0;
+		}
+	} else {
+		vfe31_ctrl->rsStatsControl.bufToRender = 0;
+	}
+
+
+	if (vfe31_ctrl->status_bits & VFE_IRQ_STATUS0_STATS_CS) {
+		if (!vfe31_ctrl->cs_ack_pending) {
+			vfe31_ctrl->cs_ack_pending = TRUE;
+			vfe31_ctrl->csStatsControl.bufToRender =
+				vfe31_process_stats_irq_common(statsCsNum,
+				vfe31_ctrl->csStatsControl.nextFrameAddrBuf);
+			process_stats = true;
+		} else {
+			vfe31_ctrl->csStatsControl.droppedStatsFrameCount++;
+			vfe31_ctrl->csStatsControl.bufToRender = 0;
+		}
+	} else {
+		vfe31_ctrl->csStatsControl.bufToRender = 0;
+	}
+
+	if (process_stats)
+		vfe_send_stats_msg();
+
+	return;
+}
+
+static void vfe31_process_stats_irq(uint32_t *irqstatus)
+{
+	/* Subsample the stats according to the hfr speed*/
+	if ((vfe31_ctrl->hfr_mode != HFR_MODE_OFF) &&
+		(vfe31_ctrl->vfeFrameId % vfe31_ctrl->hfr_mode != 0)) {
+		CDBG("Skip the stats when HFR enabled\n");
+		return;
+	}
+
+	vfe31_ctrl->status_bits = VFE_COM_STATUS & *irqstatus;
+	vfe31_process_stats();
+	return;
+}
+
+static void vfe31_do_tasklet(unsigned long data)
+{
+	unsigned long flags;
+
+	struct vfe31_isr_queue_cmd *qcmd = NULL;
+
+	CDBG("=== vfe31_do_tasklet start === \n");
+
+	while (atomic_read(&irq_cnt)) {
+		spin_lock_irqsave(&vfe31_ctrl->tasklet_lock, flags);
+		qcmd = list_first_entry(&vfe31_ctrl->tasklet_q,
+			struct vfe31_isr_queue_cmd, list);
+		atomic_sub(1, &irq_cnt);
+
+		if (!qcmd) {
+			spin_unlock_irqrestore(&vfe31_ctrl->tasklet_lock,
+				flags);
+			return;
+		}
+
+		list_del(&qcmd->list);
+		spin_unlock_irqrestore(&vfe31_ctrl->tasklet_lock,
+			flags);
+
+		/* interrupt to be processed,  *qcmd has the payload.  */
+		if (qcmd->vfeInterruptStatus0 &
+			VFE_IRQ_STATUS0_REG_UPDATE_MASK) {
+			CDBG("irq regUpdateIrq\n");
+			vfe31_process_reg_update_irq();
+		}
+
+		if (qcmd->vfeInterruptStatus1 &
+			VFE_IMASK_RESET) {
+			CDBG("irq resetAckIrq\n");
+			vfe31_process_reset_irq();
+		}
+
+
+		if (qcmd->vfeInterruptStatus1 &
+			VFE_IMASK_AXI_HALT) {
+			CDBG("irq axi halt irq\n");
+			vfe31_process_axi_halt_irq();
+		}
+
+		if (atomic_read(&vfe31_ctrl->vstate)) {
+			if (qcmd->vfeInterruptStatus1 &
+					VFE31_IMASK_ERROR_ONLY_1) {
+				pr_err("irq	errorIrq\n");
+				vfe31_process_error_irq(
+					qcmd->vfeInterruptStatus1 &
+					VFE31_IMASK_ERROR_ONLY_1);
+			}
+
+			/* irqs below are only valid when in active state. */
+			/* next, check output path related interrupts. */
+			if (qcmd->vfeInterruptStatus0 &
+				VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK) {
+				CDBG("Image composite done 0 irq occured.\n");
+				vfe31_process_output_path_irq_0(
+					qcmd->vfePingPongStatus);
+			}
+
+			if (qcmd->vfeInterruptStatus0 &
+				VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK) {
+				CDBG("Image composite done 1 irq occured.\n");
+				vfe31_process_output_path_irq_1(
+					qcmd->vfePingPongStatus);
+			}
+
+			if (qcmd->vfeInterruptStatus0 &
+				VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE2_MASK) {
+				CDBG("Image composite done 2 irq occured.\n");
+				vfe31_process_output_path_irq_2(
+					qcmd->vfePingPongStatus);
+			}
+
+			/* then process stats irq. */
+			if (vfe31_ctrl->stats_comp) {
+				/* process stats comb interrupt. */
+				if (qcmd->vfeInterruptStatus0 &
+					VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK) {
+					CDBG("Stats composite irq occured.\n");
+					vfe31_process_stats_irq(
+						&qcmd->vfeInterruptStatus0);
+				}
+			} else {
+				/* process individual stats interrupt. */
+				if (qcmd->vfeInterruptStatus0 &
+						VFE_COM_STATUS) {
+					CDBG("VFE stats occured.\n");
+					vfe31_process_stats_irq(
+						&qcmd->vfeInterruptStatus0);
+				}
+				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS0_SYNC_TIMER0) {
+					CDBG("SYNC_TIMER 0 irq occured.\n");
+					vfe31_send_msg_no_payload(
+						MSG_ID_SYNC_TIMER0_DONE);
+				}
+				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS0_SYNC_TIMER1) {
+					CDBG("SYNC_TIMER 1 irq occured.\n");
+					vfe31_send_msg_no_payload(
+						MSG_ID_SYNC_TIMER1_DONE);
+				}
+				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS0_SYNC_TIMER2) {
+					CDBG("SYNC_TIMER 2 irq occured.\n");
+					vfe31_send_msg_no_payload(
+						MSG_ID_SYNC_TIMER2_DONE);
+				}
+			}
+		}
+		if (qcmd->vfeInterruptStatus0 &
+				VFE_IRQ_STATUS0_CAMIF_SOF_MASK) {
+			CDBG("irq	camifSofIrq\n");
+			vfe31_process_camif_sof_irq();
+		}
+		kfree(qcmd);
+	}
+	CDBG("=== vfe31_do_tasklet end === \n");
+}
+
+DECLARE_TASKLET(vfe31_tasklet, vfe31_do_tasklet, 0);
+
+static irqreturn_t vfe31_parse_irq(int irq_num, void *data)
+{
+	unsigned long flags;
+	struct vfe31_irq_status irq;
+	struct vfe31_isr_queue_cmd *qcmd;
+	uint32_t *val;
+	CDBG("vfe_parse_irq\n");
+	memset(&irq, 0, sizeof(struct vfe31_irq_status));
+
+	val = (uint32_t *)(vfe31_ctrl->vfebase + VFE_IRQ_STATUS_0);
+	irq.vfeIrqStatus0 = msm_io_r(val);
+
+	val = (uint32_t *)(vfe31_ctrl->vfebase + VFE_IRQ_STATUS_1);
+	irq.vfeIrqStatus1 = msm_io_r(val);
+
+	if (irq.vfeIrqStatus1 & VFE_IMASK_AXI_HALT) {
+		msm_io_w(VFE_IMASK_RESET, vfe31_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+		msm_io_w_mb(AXI_HALT_CLEAR,
+			vfe31_ctrl->vfebase + VFE_AXI_CMD);
+	}
+
+	val = (uint32_t *)(vfe31_ctrl->vfebase + VFE_CAMIF_STATUS);
+	irq.camifStatus = msm_io_r(val);
+	CDBG("camifStatus  = 0x%x\n", irq.camifStatus);
+
+	val = (uint32_t *)(vfe31_ctrl->vfebase + VFE_BUS_PING_PONG_STATUS);
+	irq.vfePingPongStatus = msm_io_r(val);
+
+	/* clear the pending interrupt of the same kind.*/
+	msm_io_w(irq.vfeIrqStatus0, vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+	msm_io_w(irq.vfeIrqStatus1, vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_IRQ_CMD);
+
+	if ((irq.vfeIrqStatus0 == 0) && (irq.vfeIrqStatus1 == 0)) {
+		CDBG("vfe_parse_irq: vfeIrqStatus0 & 1 are both 0!\n");
+		return IRQ_HANDLED;
+	}
+
+	qcmd = kzalloc(sizeof(struct vfe31_isr_queue_cmd),
+		GFP_ATOMIC);
+	if (!qcmd) {
+		pr_err("vfe_parse_irq: qcmd malloc failed!\n");
+		return IRQ_HANDLED;
+	}
+
+	if (atomic_read(&vfe31_ctrl->stop_ack_pending)) {
+		irq.vfeIrqStatus0 &= VFE_IMASK_WHILE_STOPPING_0;
+		irq.vfeIrqStatus1 &= vfe31_ctrl->while_stopping_mask;
+	}
+
+	spin_lock_irqsave(&vfe31_ctrl->xbar_lock, flags);
+	if ((irq.vfeIrqStatus0 &
+		VFE_IRQ_STATUS0_CAMIF_EOF_MASK) &&
+		vfe31_ctrl->xbar_update_pending) {
+		CDBG("irq camifEofIrq\n");
+		msm_io_memcpy(vfe31_ctrl->vfebase + V31_XBAR_CFG_OFF,
+			(void *)vfe31_ctrl->xbar_cfg, V31_XBAR_CFG_LEN);
+		vfe31_ctrl->xbar_update_pending = 0;
+	}
+	spin_unlock_irqrestore(&vfe31_ctrl->xbar_lock, flags);
+	CDBG("vfe_parse_irq: Irq_status0 = 0x%x, Irq_status1 = 0x%x.\n",
+		irq.vfeIrqStatus0, irq.vfeIrqStatus1);
+
+	qcmd->vfeInterruptStatus0 = irq.vfeIrqStatus0;
+	qcmd->vfeInterruptStatus1 = irq.vfeIrqStatus1;
+	qcmd->vfePingPongStatus = irq.vfePingPongStatus;
+
+	spin_lock_irqsave(&vfe31_ctrl->tasklet_lock, flags);
+	list_add_tail(&qcmd->list, &vfe31_ctrl->tasklet_q);
+
+	atomic_add(1, &irq_cnt);
+	spin_unlock_irqrestore(&vfe31_ctrl->tasklet_lock, flags);
+	tasklet_schedule(&vfe31_tasklet);
+	return IRQ_HANDLED;
+}
+
+static void vfe31_release(struct platform_device *pdev)
+{
+	struct resource	*vfemem, *vfeio;
+
+	vfe31_reset_free_buf_queue_all();
+	CDBG("%s, free_irq\n", __func__);
+	free_irq(vfe31_ctrl->vfeirq, 0);
+	tasklet_kill(&vfe31_tasklet);
+
+	if (atomic_read(&irq_cnt))
+		pr_warning("%s, Warning IRQ Count not ZERO\n", __func__);
+
+	vfemem = vfe31_ctrl->vfemem;
+	vfeio  = vfe31_ctrl->vfeio;
+
+	msm_vpe_release();
+
+	kfree(vfe31_ctrl->extdata);
+	iounmap(vfe31_ctrl->vfebase);
+	kfree(vfe31_ctrl);
+	vfe31_ctrl = NULL;
+	release_mem_region(vfemem->start, (vfemem->end - vfemem->start) + 1);
+	CDBG("%s, msm_camio_disable\n", __func__);
+	msm_camio_disable(pdev);
+	msm_camio_set_perf_lvl(S_EXIT);
+
+	vfe_syncdata = NULL;
+}
+
+static int vfe31_resource_init(struct msm_vfe_callback *presp,
+	struct platform_device *pdev, void *sdata)
+{
+	struct resource	*vfemem, *vfeirq, *vfeio;
+	int rc;
+	struct msm_camera_sensor_info *s_info;
+	s_info = pdev->dev.platform_data;
+
+	pdev->resource = s_info->resource;
+	pdev->num_resources = s_info->num_resources;
+
+	vfemem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!vfemem) {
+		pr_err("%s: no mem resource?\n", __func__);
+		return -ENODEV;
+	}
+
+	vfeirq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!vfeirq) {
+		pr_err("%s: no irq resource?\n", __func__);
+		return -ENODEV;
+	}
+
+	vfeio = request_mem_region(vfemem->start,
+		resource_size(vfemem), pdev->name);
+	if (!vfeio) {
+		pr_err("%s: VFE region already claimed\n", __func__);
+		return -EBUSY;
+	}
+
+	vfe31_ctrl = kzalloc(sizeof(struct vfe31_ctrl_type), GFP_KERNEL);
+	if (!vfe31_ctrl) {
+		rc = -ENOMEM;
+		goto cmd_init_failed1;
+	}
+
+	vfe31_ctrl->vfeirq = vfeirq->start;
+
+	vfe31_ctrl->vfebase =
+		ioremap(vfemem->start, (vfemem->end - vfemem->start) + 1);
+	if (!vfe31_ctrl->vfebase) {
+		rc = -ENOMEM;
+		pr_err("%s: vfe ioremap failed\n", __func__);
+		goto cmd_init_failed2;
+	}
+
+	if (presp && presp->vfe_resp)
+		vfe31_ctrl->resp = presp;
+	else {
+		rc = -EINVAL;
+		goto cmd_init_failed3;
+	}
+
+	vfe31_ctrl->extdata =
+		kmalloc(sizeof(struct vfe31_frame_extra), GFP_KERNEL);
+	if (!vfe31_ctrl->extdata) {
+		rc = -ENOMEM;
+		goto cmd_init_failed3;
+	}
+
+	vfe31_ctrl->extlen = sizeof(struct vfe31_frame_extra);
+
+	spin_lock_init(&vfe31_ctrl->io_lock);
+	spin_lock_init(&vfe31_ctrl->update_ack_lock);
+	spin_lock_init(&vfe31_ctrl->tasklet_lock);
+
+	INIT_LIST_HEAD(&vfe31_ctrl->tasklet_q);
+	vfe31_init_free_buf_queue();
+
+	vfe31_ctrl->syncdata = sdata;
+	vfe31_ctrl->vfemem = vfemem;
+	vfe31_ctrl->vfeio  = vfeio;
+	vfe31_ctrl->update_gamma = false;
+	vfe31_ctrl->update_luma = false;
+	vfe31_ctrl->s_info = s_info;
+	vfe31_ctrl->stats_comp = 0;
+	vfe31_ctrl->hfr_mode = HFR_MODE_OFF;
+	return 0;
+
+cmd_init_failed3:
+	free_irq(vfe31_ctrl->vfeirq, 0);
+	iounmap(vfe31_ctrl->vfebase);
+cmd_init_failed2:
+	kfree(vfe31_ctrl);
+cmd_init_failed1:
+	release_mem_region(vfemem->start, (vfemem->end - vfemem->start) + 1);
+	return rc;
+}
+
+static int vfe31_init(struct msm_vfe_callback *presp,
+	struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+	camio_clk = camdev->ioclk;
+
+	rc = vfe31_resource_init(presp, pdev, vfe_syncdata);
+	if (rc < 0)
+		return rc;
+	/* Bring up all the required GPIOs and Clocks */
+	rc = msm_camio_enable(pdev);
+	msm_camio_set_perf_lvl(S_INIT);
+	if (msm_vpe_open() < 0)
+		CDBG("%s: vpe_open failed\n", __func__);
+
+	/* TO DO: Need to release the VFE resources */
+	rc = request_irq(vfe31_ctrl->vfeirq, vfe31_parse_irq,
+			IRQF_TRIGGER_RISING, "vfe", 0);
+
+	return rc;
+}
+
+void msm_camvfe_fn_init(struct msm_camvfe_fn *fptr, void *data)
+{
+	fptr->vfe_init    = vfe31_init;
+	fptr->vfe_enable  = vfe31_enable;
+	fptr->vfe_config  = vfe31_config;
+	fptr->vfe_disable = vfe31_disable;
+	fptr->vfe_release = vfe31_release;
+	fptr->vfe_stop = vfe31_stop;
+	vfe_syncdata = data;
+}
+
+void msm_camvpe_fn_init(struct msm_camvpe_fn *fptr, void *data)
+{
+	fptr->vpe_reg		= msm_vpe_reg;
+	fptr->send_frame_to_vpe	= msm_send_frame_to_vpe;
+	fptr->vpe_config	= msm_vpe_config;
+	fptr->vpe_cfg_update	= msm_vpe_cfg_update;
+	fptr->dis		= &(vpe_ctrl->dis_en);
+	fptr->vpe_cfg_offset = msm_vpe_offset_update;
+	vpe_ctrl->syncdata = data;
+}
diff --git a/drivers/media/video/msm/msm_vfe31.h b/drivers/media/video/msm/msm_vfe31.h
new file mode 100644
index 0000000..e3c06ee
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe31.h
@@ -0,0 +1,1113 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __MSM_VFE31_H__
+#define __MSM_VFE31_H__
+
+#define TRUE  1
+#define FALSE 0
+
+/* at start of camif,  bit 1:0 = 0x01:enable
+ * image data capture at frame boundary. */
+#define CAMIF_COMMAND_START  0x00000005
+
+/* bit 2= 0x1:clear the CAMIF_STATUS register
+ * value. */
+#define CAMIF_COMMAND_CLEAR  0x00000004
+
+/* at stop of vfe pipeline, for now it is assumed
+ * that camif will stop at any time. Bit 1:0 = 0x10:
+ * disable image data capture immediately. */
+#define CAMIF_COMMAND_STOP_IMMEDIATELY  0x00000002
+
+/* at stop of vfe pipeline, for now it is assumed
+ * that camif will stop at any time. Bit 1:0 = 0x00:
+ * disable image data capture at frame boundary */
+#define CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY  0x00000000
+
+/* to halt axi bridge */
+#define AXI_HALT  0x00000001
+
+/* clear the halt bit. */
+#define AXI_HALT_CLEAR  0x00000000
+
+/* clear axi_halt_irq */
+#define MASK_AXI_HALT_IRQ	0xFF7FFFFF
+
+/* reset the pipeline when stop command is issued.
+ * (without reset the register.) bit 26-31 = 0,
+ * domain reset, bit 0-9 = 1 for module reset, except
+ * register module. */
+#define VFE_RESET_UPON_STOP_CMD  0x000003ef
+
+/* reset the pipeline when reset command.
+ * bit 26-31 = 0, domain reset, bit 0-9 = 1 for module reset. */
+#define VFE_RESET_UPON_RESET_CMD  0x000003ff
+
+/* bit 5 is for axi status idle or busy.
+ * 1 =  halted,  0 = busy */
+#define AXI_STATUS_BUSY_MASK 0x00000020
+
+/* bit 0 & bit 1 = 1, both y and cbcr irqs need to be present
+ * for frame done interrupt */
+#define VFE_COMP_IRQ_BOTH_Y_CBCR 3
+
+/* bit 1 = 1, only cbcr irq triggers frame done interrupt */
+#define VFE_COMP_IRQ_CBCR_ONLY 2
+
+/* bit 0 = 1, only y irq triggers frame done interrupt */
+#define VFE_COMP_IRQ_Y_ONLY 1
+
+/* bit 0 = 1, PM go;   bit1 = 1, PM stop */
+#define VFE_PERFORMANCE_MONITOR_GO   0x00000001
+#define VFE_PERFORMANCE_MONITOR_STOP 0x00000002
+
+/* bit 0 = 1, test gen go;   bit1 = 1, test gen stop */
+#define VFE_TEST_GEN_GO   0x00000001
+#define VFE_TEST_GEN_STOP 0x00000002
+
+/* the chroma is assumed to be interpolated between
+ * the luma samples.  JPEG 4:2:2 */
+#define VFE_CHROMA_UPSAMPLE_INTERPOLATED 0
+
+/* constants for irq registers */
+#define VFE_DISABLE_ALL_IRQS 0
+/* bit =1 is to clear the corresponding bit in VFE_IRQ_STATUS.  */
+#define VFE_CLEAR_ALL_IRQS   0xffffffff
+
+#define VFE_IRQ_STATUS0_CAMIF_SOF_MASK            0x00000001
+#define VFE_IRQ_STATUS0_CAMIF_EOF_MASK            0x00000004
+#define VFE_IRQ_STATUS0_REG_UPDATE_MASK           0x00000020
+#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK 0x00200000
+#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK 0x00400000
+#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE2_MASK 0x00800000
+#define VFE_IRQ_STATUS1_RESET_AXI_HALT_ACK_MASK   0x00800000
+#define VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK       0x01000000
+
+#define VFE_IRQ_STATUS0_STATS_AEC     0x2000  /* bit 13 */
+#define VFE_IRQ_STATUS0_STATS_AF      0x4000  /* bit 14 */
+#define VFE_IRQ_STATUS0_STATS_AWB     0x8000  /* bit 15 */
+#define VFE_IRQ_STATUS0_STATS_RS      0x10000  /* bit 16 */
+#define VFE_IRQ_STATUS0_STATS_CS      0x20000  /* bit 17 */
+#define VFE_IRQ_STATUS0_STATS_IHIST   0x40000  /* bit 18 */
+
+#define VFE_IRQ_STATUS0_SYNC_TIMER0   0x2000000  /* bit 25 */
+#define VFE_IRQ_STATUS0_SYNC_TIMER1   0x4000000  /* bit 26 */
+#define VFE_IRQ_STATUS0_SYNC_TIMER2   0x8000000  /* bit 27 */
+#define VFE_IRQ_STATUS0_ASYNC_TIMER0  0x10000000  /* bit 28 */
+#define VFE_IRQ_STATUS0_ASYNC_TIMER1  0x20000000  /* bit 29 */
+#define VFE_IRQ_STATUS0_ASYNC_TIMER2  0x40000000  /* bit 30 */
+#define VFE_IRQ_STATUS0_ASYNC_TIMER3  0x80000000  /* bit 31 */
+
+/* imask for while waiting for stop ack,  driver has already
+ * requested stop, waiting for reset irq, and async timer irq.
+ * For irq_status_0, bit 28-31 are for async timer. For
+ * irq_status_1, bit 22 for reset irq, bit 23 for axi_halt_ack
+   irq */
+#define VFE_IMASK_WHILE_STOPPING_0  0xF0000000
+#define VFE_IMASK_WHILE_STOPPING_1  0x00C00000
+#define VFE_IMASK_RESET             0x00400000
+#define VFE_IMASK_AXI_HALT          0x00800000
+
+
+/* no error irq in mask 0 */
+#define VFE_IMASK_ERROR_ONLY_0  0x0
+/* when normal case, don't want to block error status. */
+/* bit 0-21 are error irq bits */
+#define VFE_IMASK_ERROR_ONLY_1  0x003fffff
+
+/* For BPC bit 0,bit 12-17 and bit 26 -20 are set to zero and other's 1 */
+#define BPC_MASK 0xF80C0FFE
+
+/* For BPC bit 1 and 2 are set to zero and other's 1 */
+#define ABF_MASK 0xFFFFFFF9
+
+/* For MCE enable bit 28 set to zero and other's 1 */
+#define MCE_EN_MASK 0xEFFFFFFF
+
+/* For MCE Q_K bit 28 to 31 set to zero and other's 1 */
+#define MCE_Q_K_MASK 0x0FFFFFFF
+
+#define AWB_ENABLE_MASK 0x00000080     /* bit 7 */
+#define AF_ENABLE_MASK 0x00000040      /* bit 6 */
+#define AE_ENABLE_MASK 0x00000020      /* bit 5 */
+#define IHIST_ENABLE_MASK 0x00008000   /* bit 15 */
+#define RS_ENABLE_MASK 0x00000100      /* bit 8  */
+#define CS_ENABLE_MASK 0x00000200      /* bit 9  */
+#define RS_CS_ENABLE_MASK 0x00000300   /* bit 8,9  */
+#define STATS_ENABLE_MASK 0x000483E0   /* bit 18,15,9,8,7,6,5*/
+
+#define VFE_REG_UPDATE_TRIGGER           1
+#define VFE_PM_BUF_MAX_CNT_MASK          0xFF
+#define VFE_DMI_CFG_DEFAULT              0x00000100
+#define LENS_ROLL_OFF_DELTA_TABLE_OFFSET 32
+#define VFE_AE_PINGPONG_STATUS_BIT       0x80
+#define VFE_AF_PINGPONG_STATUS_BIT       0x100
+#define VFE_AWB_PINGPONG_STATUS_BIT      0x200
+
+#define HFR_MODE_OFF 1
+
+enum VFE31_DMI_RAM_SEL {
+	 NO_MEM_SELECTED          = 0,
+	 ROLLOFF_RAM              = 0x1,
+	 RGBLUT_RAM_CH0_BANK0     = 0x2,
+	 RGBLUT_RAM_CH0_BANK1     = 0x3,
+	 RGBLUT_RAM_CH1_BANK0     = 0x4,
+	 RGBLUT_RAM_CH1_BANK1     = 0x5,
+	 RGBLUT_RAM_CH2_BANK0     = 0x6,
+	 RGBLUT_RAM_CH2_BANK1     = 0x7,
+	 STATS_HIST_RAM           = 0x8,
+	 RGBLUT_CHX_BANK0         = 0x9,
+	 RGBLUT_CHX_BANK1         = 0xa,
+	 LUMA_ADAPT_LUT_RAM_BANK0 = 0xb,
+	 LUMA_ADAPT_LUT_RAM_BANK1 = 0xc
+};
+
+enum  VFE_STATE {
+	VFE_STATE_IDLE,
+	VFE_STATE_ACTIVE
+};
+
+enum  vfe_recording_state {
+	VFE_REC_STATE_IDLE,
+	VFE_REC_STATE_START_REQUESTED,
+	VFE_REC_STATE_STARTED,
+	VFE_REC_STATE_STOP_REQUESTED,
+	VFE_REC_STATE_STOPPED,
+};
+
+#define V31_DUMMY_0               0
+#define V31_SET_CLK               1
+#define V31_RESET                 2
+#define V31_START                 3
+#define V31_TEST_GEN_START        4
+#define V31_OPERATION_CFG         5
+#define V31_AXI_OUT_CFG           6
+#define V31_CAMIF_CFG             7
+#define V31_AXI_INPUT_CFG         8
+#define V31_BLACK_LEVEL_CFG       9
+#define V31_ROLL_OFF_CFG          10
+#define V31_DEMUX_CFG             11
+#define V31_DEMOSAIC_0_CFG        12 /* general */
+#define V31_DEMOSAIC_1_CFG        13 /* ABF     */
+#define V31_DEMOSAIC_2_CFG        14 /* BPC     */
+#define V31_FOV_CFG               15
+#define V31_MAIN_SCALER_CFG       16
+#define V31_WB_CFG                17
+#define V31_COLOR_COR_CFG         18
+#define V31_RGB_G_CFG             19
+#define V31_LA_CFG                20
+#define V31_CHROMA_EN_CFG         21
+#define V31_CHROMA_SUP_CFG        22
+#define V31_MCE_CFG               23
+#define V31_SK_ENHAN_CFG          24
+#define V31_ASF_CFG               25
+#define V31_S2Y_CFG               26
+#define V31_S2CbCr_CFG            27
+#define V31_CHROMA_SUBS_CFG       28
+#define V31_OUT_CLAMP_CFG         29
+#define V31_FRAME_SKIP_CFG        30
+#define V31_DUMMY_1               31
+#define V31_DUMMY_2               32
+#define V31_DUMMY_3               33
+#define V31_UPDATE                34
+#define V31_BL_LVL_UPDATE         35
+#define V31_DEMUX_UPDATE          36
+#define V31_DEMOSAIC_1_UPDATE     37 /* BPC */
+#define V31_DEMOSAIC_2_UPDATE     38 /* ABF */
+#define V31_FOV_UPDATE            39
+#define V31_MAIN_SCALER_UPDATE    40
+#define V31_WB_UPDATE             41
+#define V31_COLOR_COR_UPDATE      42
+#define V31_RGB_G_UPDATE          43
+#define V31_LA_UPDATE             44
+#define V31_CHROMA_EN_UPDATE      45
+#define V31_CHROMA_SUP_UPDATE     46
+#define V31_MCE_UPDATE            47
+#define V31_SK_ENHAN_UPDATE       48
+#define V31_S2CbCr_UPDATE         49
+#define V31_S2Y_UPDATE            50
+#define V31_ASF_UPDATE            51
+#define V31_FRAME_SKIP_UPDATE     52
+#define V31_CAMIF_FRAME_UPDATE    53
+#define V31_STATS_AF_UPDATE       54
+#define V31_STATS_AE_UPDATE       55
+#define V31_STATS_AWB_UPDATE      56
+#define V31_STATS_RS_UPDATE       57
+#define V31_STATS_CS_UPDATE       58
+#define V31_STATS_SKIN_UPDATE     59
+#define V31_STATS_IHIST_UPDATE    60
+#define V31_DUMMY_4               61
+#define V31_EPOCH1_ACK            62
+#define V31_EPOCH2_ACK            63
+#define V31_START_RECORDING       64
+#define V31_STOP_RECORDING        65
+#define V31_DUMMY_5               66
+#define V31_DUMMY_6               67
+#define V31_CAPTURE               68
+#define V31_DUMMY_7               69
+#define V31_STOP                  70
+#define V31_GET_HW_VERSION        71
+#define V31_GET_FRAME_SKIP_COUNTS 72
+#define V31_OUTPUT1_BUFFER_ENQ    73
+#define V31_OUTPUT2_BUFFER_ENQ    74
+#define V31_OUTPUT3_BUFFER_ENQ    75
+#define V31_JPEG_OUT_BUF_ENQ      76
+#define V31_RAW_OUT_BUF_ENQ       77
+#define V31_RAW_IN_BUF_ENQ        78
+#define V31_STATS_AF_ENQ          79
+#define V31_STATS_AE_ENQ          80
+#define V31_STATS_AWB_ENQ         81
+#define V31_STATS_RS_ENQ          82
+#define V31_STATS_CS_ENQ          83
+#define V31_STATS_SKIN_ENQ        84
+#define V31_STATS_IHIST_ENQ       85
+#define V31_DUMMY_8               86
+#define V31_JPEG_ENC_CFG          87
+#define V31_DUMMY_9               88
+#define V31_STATS_AF_START        89
+#define V31_STATS_AF_STOP         90
+#define V31_STATS_AE_START        91
+#define V31_STATS_AE_STOP         92
+#define V31_STATS_AWB_START       93
+#define V31_STATS_AWB_STOP        94
+#define V31_STATS_RS_START        95
+#define V31_STATS_RS_STOP         96
+#define V31_STATS_CS_START        97
+#define V31_STATS_CS_STOP         98
+#define V31_STATS_SKIN_START      99
+#define V31_STATS_SKIN_STOP       100
+#define V31_STATS_IHIST_START     101
+#define V31_STATS_IHIST_STOP      102
+#define V31_DUMMY_10              103
+#define V31_SYNC_TIMER_SETTING    104
+#define V31_ASYNC_TIMER_SETTING   105
+#define V31_LIVESHOT              106
+#define V31_ZSL                   107
+#define V31_STEREOCAM             108
+#define V31_LA_SETUP              109
+#define V31_XBAR_CFG              110
+#define V31_EZTUNE_CFG            111
+
+#define V31_CAMIF_OFF             0x000001E4
+#define V31_CAMIF_LEN             32
+
+#define V31_DEMUX_OFF             0x00000284
+#define V31_DEMUX_LEN             20
+
+#define V31_DEMOSAIC_0_OFF        0x00000298
+#define V31_DEMOSAIC_0_LEN        4
+/* ABF     */
+#define V31_DEMOSAIC_1_OFF        0x000002A4
+#define V31_DEMOSAIC_1_LEN        180
+/* BPC     */
+#define V31_DEMOSAIC_2_OFF        0x0000029C
+#define V31_DEMOSAIC_2_LEN        8
+
+/* gamma VFE_LUT_BANK_SEL*/
+#define V31_GAMMA_CFG_OFF         0x000003BC
+#define V31_LUMA_CFG_OFF          0x000003C0
+
+#define V31_OUT_CLAMP_OFF         0x00000524
+#define V31_OUT_CLAMP_LEN         8
+
+#define V31_OPERATION_CFG_LEN     32
+
+#define V31_AXI_OUT_OFF           0x00000038
+#define V31_AXI_OUT_LEN           212
+#define V31_AXI_CH_INF_LEN        24
+#define V31_AXI_CFG_LEN           47
+
+#define V31_FRAME_SKIP_OFF        0x00000504
+#define V31_FRAME_SKIP_LEN        32
+
+#define V31_CHROMA_SUBS_OFF       0x000004F8
+#define V31_CHROMA_SUBS_LEN       12
+
+#define V31_FOV_OFF           0x00000360
+#define V31_FOV_LEN           8
+
+#define V31_MAIN_SCALER_OFF 0x00000368
+#define V31_MAIN_SCALER_LEN 28
+
+#define V31_S2Y_OFF 0x000004D0
+#define V31_S2Y_LEN 20
+
+#define V31_S2CbCr_OFF 0x000004E4
+#define V31_S2CbCr_LEN 20
+
+#define V31_CHROMA_EN_OFF 0x000003C4
+#define V31_CHROMA_EN_LEN 36
+
+#define V31_SYNC_TIMER_OFF      0x0000020C
+#define V31_SYNC_TIMER_POLARITY_OFF 0x00000234
+#define V31_TIMER_SELECT_OFF        0x0000025C
+#define V31_SYNC_TIMER_LEN 28
+
+#define V31_ASYNC_TIMER_OFF 0x00000238
+#define V31_ASYNC_TIMER_LEN 28
+
+#define V31_BLACK_LEVEL_OFF 0x00000264
+#define V31_BLACK_LEVEL_LEN 16
+
+#define V31_ROLL_OFF_CFG_OFF 0x00000274
+#define V31_ROLL_OFF_CFG_LEN 16
+
+#define V31_COLOR_COR_OFF 0x00000388
+#define V31_COLOR_COR_LEN 52
+
+#define V31_WB_OFF 0x00000384
+#define V31_WB_LEN 4
+
+#define V31_RGB_G_OFF 0x000003BC
+#define V31_RGB_G_LEN 4
+
+#define V31_LA_OFF 0x000003C0
+#define V31_LA_LEN 4
+
+#define V31_SCE_OFF 0x00000418
+#define V31_SCE_LEN 136
+
+#define V31_CHROMA_SUP_OFF 0x000003E8
+#define V31_CHROMA_SUP_LEN 12
+
+#define V31_MCE_OFF 0x000003F4
+#define V31_MCE_LEN 36
+#define V31_STATS_AF_OFF 0x0000053c
+#define V31_STATS_AF_LEN 16
+
+#define V31_STATS_AE_OFF 0x00000534
+#define V31_STATS_AE_LEN 8
+
+#define V31_STATS_AWB_OFF 0x0000054c
+#define V31_STATS_AWB_LEN 32
+
+#define V31_STATS_IHIST_OFF 0x0000057c
+#define V31_STATS_IHIST_LEN 8
+
+#define V31_STATS_RS_OFF 0x0000056c
+#define V31_STATS_RS_LEN 8
+
+#define V31_STATS_CS_OFF 0x00000574
+#define V31_STATS_CS_LEN 8
+
+#define V31_XBAR_CFG_OFF 0x00000040
+#define V31_XBAR_CFG_LEN 8
+
+#define V31_EZTUNE_CFG_OFF 0x00000010
+#define V31_EZTUNE_CFG_LEN 4
+
+#define V31_ASF_OFF 0x000004A0
+#define V31_ASF_LEN 48
+#define V31_ASF_UPDATE_LEN 36
+
+#define V31_CAPTURE_LEN 4
+
+struct vfe_cmd_hw_version {
+	uint32_t minorVersion;
+	uint32_t majorVersion;
+	uint32_t coreVersion;
+};
+
+enum VFE_AXI_OUTPUT_MODE {
+	VFE_AXI_OUTPUT_MODE_Output1,
+	VFE_AXI_OUTPUT_MODE_Output2,
+	VFE_AXI_OUTPUT_MODE_Output1AndOutput2,
+	VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2,
+	VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1,
+	VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2,
+	VFE_AXI_LAST_OUTPUT_MODE_ENUM
+};
+
+enum VFE_RAW_WR_PATH_SEL {
+	VFE_RAW_OUTPUT_DISABLED,
+	VFE_RAW_OUTPUT_ENC_CBCR_PATH,
+	VFE_RAW_OUTPUT_VIEW_CBCR_PATH,
+	VFE_RAW_OUTPUT_PATH_INVALID
+};
+
+
+#define VFE_AXI_OUTPUT_BURST_LENGTH     4
+#define VFE_MAX_NUM_FRAGMENTS_PER_FRAME 4
+#define VFE_AXI_OUTPUT_CFG_FRAME_COUNT  3
+
+struct vfe_cmds_per_write_master {
+	uint16_t imageWidth;
+	uint16_t imageHeight;
+	uint16_t outRowCount;
+	uint16_t outRowIncrement;
+	uint32_t outFragments[VFE_AXI_OUTPUT_CFG_FRAME_COUNT]
+		[VFE_MAX_NUM_FRAGMENTS_PER_FRAME];
+};
+
+struct vfe_cmds_axi_per_output_path {
+	uint8_t fragmentCount;
+	struct vfe_cmds_per_write_master firstWM;
+	struct vfe_cmds_per_write_master secondWM;
+};
+
+enum VFE_AXI_BURST_LENGTH {
+	VFE_AXI_BURST_LENGTH_IS_2  = 2,
+	VFE_AXI_BURST_LENGTH_IS_4  = 4,
+	VFE_AXI_BURST_LENGTH_IS_8  = 8,
+	VFE_AXI_BURST_LENGTH_IS_16 = 16
+};
+
+
+struct vfe_cmd_fov_crop_config {
+	uint8_t enable;
+	uint16_t firstPixel;
+	uint16_t lastPixel;
+	uint16_t firstLine;
+	uint16_t lastLine;
+};
+
+struct vfe_cmds_main_scaler_stripe_init {
+	uint16_t MNCounterInit;
+	uint16_t phaseInit;
+};
+
+struct vfe_cmds_scaler_one_dimension {
+	uint8_t  enable;
+	uint16_t inputSize;
+	uint16_t outputSize;
+	uint32_t phaseMultiplicationFactor;
+	uint8_t  interpolationResolution;
+};
+
+struct vfe_cmd_main_scaler_config {
+	uint8_t enable;
+	struct vfe_cmds_scaler_one_dimension    hconfig;
+	struct vfe_cmds_scaler_one_dimension    vconfig;
+	struct vfe_cmds_main_scaler_stripe_init MNInitH;
+	struct vfe_cmds_main_scaler_stripe_init MNInitV;
+};
+
+struct vfe_cmd_scaler2_config {
+	uint8_t enable;
+	struct vfe_cmds_scaler_one_dimension hconfig;
+	struct vfe_cmds_scaler_one_dimension vconfig;
+};
+
+
+struct vfe_cmd_frame_skip_update {
+	uint32_t output1Pattern;
+	uint32_t output2Pattern;
+};
+
+struct vfe_cmd_output_clamp_config {
+	uint8_t minCh0;
+	uint8_t minCh1;
+	uint8_t minCh2;
+	uint8_t maxCh0;
+	uint8_t maxCh1;
+	uint8_t maxCh2;
+};
+
+struct vfe_cmd_chroma_subsample_config {
+	uint8_t enable;
+	uint8_t cropEnable;
+	uint8_t vsubSampleEnable;
+	uint8_t hsubSampleEnable;
+	uint8_t vCosited;
+	uint8_t hCosited;
+	uint8_t vCositedPhase;
+	uint8_t hCositedPhase;
+	uint16_t cropWidthFirstPixel;
+	uint16_t cropWidthLastPixel;
+	uint16_t cropHeightFirstLine;
+	uint16_t cropHeightLastLine;
+};
+
+enum VFE_START_INPUT_SOURCE {
+	VFE_START_INPUT_SOURCE_CAMIF,
+	VFE_START_INPUT_SOURCE_TESTGEN,
+	VFE_START_INPUT_SOURCE_AXI,
+	VFE_START_INPUT_SOURCE_INVALID
+};
+
+enum VFE_START_PIXEL_PATTERN {
+	VFE_BAYER_RGRGRG,
+	VFE_BAYER_GRGRGR,
+	VFE_BAYER_BGBGBG,
+	VFE_BAYER_GBGBGB,
+	VFE_YUV_YCbYCr,
+	VFE_YUV_YCrYCb,
+	VFE_YUV_CbYCrY,
+	VFE_YUV_CrYCbY
+};
+
+enum VFE_BUS_RD_INPUT_PIXEL_PATTERN {
+	VFE_BAYER_RAW,
+	VFE_YUV_INTERLEAVED,
+	VFE_YUV_PSEUDO_PLANAR_Y,
+	VFE_YUV_PSEUDO_PLANAR_CBCR
+};
+
+enum VFE_YUV_INPUT_COSITING_MODE {
+	VFE_YUV_COSITED,
+	VFE_YUV_INTERPOLATED
+};
+
+
+/* 13*1  */
+#define VFE31_ROLL_OFF_INIT_TABLE_SIZE  13
+/* 13*16 */
+#define VFE31_ROLL_OFF_DELTA_TABLE_SIZE 208
+
+#define VFE31_GAMMA_NUM_ENTRIES  64
+
+#define VFE31_LA_TABLE_LENGTH    64
+
+#define VFE31_HIST_TABLE_LENGTH  256
+
+struct vfe_cmds_demosaic_abf {
+	uint8_t   enable;
+	uint8_t   forceOn;
+	uint8_t   shift;
+	uint16_t  lpThreshold;
+	uint16_t  max;
+	uint16_t  min;
+	uint8_t   ratio;
+};
+
+struct vfe_cmds_demosaic_bpc {
+	uint8_t   enable;
+	uint16_t  fmaxThreshold;
+	uint16_t  fminThreshold;
+	uint16_t  redDiffThreshold;
+	uint16_t  blueDiffThreshold;
+	uint16_t  greenDiffThreshold;
+};
+
+struct vfe_cmd_demosaic_config {
+	uint8_t   enable;
+	uint8_t   slopeShift;
+	struct vfe_cmds_demosaic_abf abfConfig;
+	struct vfe_cmds_demosaic_bpc bpcConfig;
+};
+
+struct vfe_cmd_demosaic_bpc_update {
+	struct vfe_cmds_demosaic_bpc bpcUpdate;
+};
+
+struct vfe_cmd_demosaic_abf_update {
+	struct vfe_cmds_demosaic_abf abfUpdate;
+};
+
+struct vfe_cmd_white_balance_config {
+	uint8_t  enable;
+	uint16_t ch2Gain;
+	uint16_t ch1Gain;
+	uint16_t ch0Gain;
+};
+
+enum VFE_COLOR_CORRECTION_COEF_QFACTOR {
+	COEF_IS_Q7_SIGNED,
+	COEF_IS_Q8_SIGNED,
+	COEF_IS_Q9_SIGNED,
+	COEF_IS_Q10_SIGNED
+};
+
+struct vfe_cmd_color_correction_config {
+	uint8_t     enable;
+	enum VFE_COLOR_CORRECTION_COEF_QFACTOR coefQFactor;
+	int16_t  C0;
+	int16_t  C1;
+	int16_t  C2;
+	int16_t  C3;
+	int16_t  C4;
+	int16_t  C5;
+	int16_t  C6;
+	int16_t  C7;
+	int16_t  C8;
+	int16_t  K0;
+	int16_t  K1;
+	int16_t  K2;
+};
+
+#define VFE_LA_TABLE_LENGTH 64
+
+struct vfe_cmd_la_config {
+	uint8_t enable;
+	int16_t table[VFE_LA_TABLE_LENGTH];
+};
+
+#define VFE_GAMMA_TABLE_LENGTH 256
+enum VFE_RGB_GAMMA_TABLE_SELECT {
+	RGB_GAMMA_CH0_SELECTED,
+	RGB_GAMMA_CH1_SELECTED,
+	RGB_GAMMA_CH2_SELECTED,
+	RGB_GAMMA_CH0_CH1_SELECTED,
+	RGB_GAMMA_CH0_CH2_SELECTED,
+	RGB_GAMMA_CH1_CH2_SELECTED,
+	RGB_GAMMA_CH0_CH1_CH2_SELECTED
+};
+
+struct vfe_cmd_rgb_gamma_config {
+	uint8_t enable;
+	enum VFE_RGB_GAMMA_TABLE_SELECT channelSelect;
+	int16_t table[VFE_GAMMA_TABLE_LENGTH];
+};
+
+struct vfe_cmd_chroma_enhan_config {
+	uint8_t  enable;
+	int16_t am;
+	int16_t ap;
+	int16_t bm;
+	int16_t bp;
+	int16_t cm;
+	int16_t cp;
+	int16_t dm;
+	int16_t dp;
+	int16_t kcr;
+	int16_t kcb;
+	int16_t RGBtoYConversionV0;
+	int16_t RGBtoYConversionV1;
+	int16_t RGBtoYConversionV2;
+	uint8_t RGBtoYConversionOffset;
+};
+
+struct vfe_cmd_chroma_suppression_config {
+	uint8_t enable;
+	uint8_t m1;
+	uint8_t m3;
+	uint8_t n1;
+	uint8_t n3;
+	uint8_t nn1;
+	uint8_t mm1;
+};
+
+struct vfe_cmd_asf_config {
+	uint8_t enable;
+	uint8_t smoothFilterEnabled;
+	uint8_t sharpMode;
+	uint8_t smoothCoefCenter;
+	uint8_t smoothCoefSurr;
+	uint8_t normalizeFactor;
+	uint8_t sharpK1;
+	uint8_t sharpK2;
+	uint8_t sharpThreshE1;
+	int8_t sharpThreshE2;
+	int8_t sharpThreshE3;
+	int8_t sharpThreshE4;
+	int8_t sharpThreshE5;
+	int8_t filter1Coefficients[9];
+	int8_t filter2Coefficients[9];
+	uint8_t  cropEnable;
+	uint16_t cropFirstPixel;
+	uint16_t cropLastPixel;
+	uint16_t cropFirstLine;
+	uint16_t cropLastLine;
+};
+
+struct vfe_cmd_asf_update {
+	uint8_t enable;
+	uint8_t smoothFilterEnabled;
+	uint8_t sharpMode;
+	uint8_t smoothCoefCenter;
+	uint8_t smoothCoefSurr;
+	uint8_t normalizeFactor;
+	uint8_t sharpK1;
+	uint8_t sharpK2;
+	uint8_t sharpThreshE1;
+	int8_t  sharpThreshE2;
+	int8_t  sharpThreshE3;
+	int8_t  sharpThreshE4;
+	int8_t  sharpThreshE5;
+	int8_t  filter1Coefficients[9];
+	int8_t  filter2Coefficients[9];
+	uint8_t cropEnable;
+};
+
+enum VFE_TEST_GEN_SYNC_EDGE {
+	VFE_TEST_GEN_SYNC_EDGE_ActiveHigh,
+	VFE_TEST_GEN_SYNC_EDGE_ActiveLow
+};
+
+
+struct vfe_cmd_bus_pm_start {
+	uint8_t output2YWrPmEnable;
+	uint8_t output2CbcrWrPmEnable;
+	uint8_t output1YWrPmEnable;
+	uint8_t output1CbcrWrPmEnable;
+};
+
+struct  vfe_frame_skip_counts {
+	uint32_t  totalFrameCount;
+	uint32_t  output1Count;
+	uint32_t  output2Count;
+};
+
+enum VFE_AXI_RD_UNPACK_HBI_SEL {
+	VFE_AXI_RD_HBI_32_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_64_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_128_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_256_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_512_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_1024_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_2048_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_4096_CLOCK_CYCLES
+};
+
+enum VFE31_MESSAGE_ID {
+	MSG_ID_RESET_ACK, /* 0 */
+	MSG_ID_START_ACK,
+	MSG_ID_STOP_ACK,
+	MSG_ID_UPDATE_ACK,
+	MSG_ID_OUTPUT_P,
+	MSG_ID_OUTPUT_T,
+	MSG_ID_OUTPUT_S,
+	MSG_ID_OUTPUT_V,
+	MSG_ID_SNAPSHOT_DONE,
+	MSG_ID_COMMON,
+	MSG_ID_EPOCH1, /* 10 */
+	MSG_ID_EPOCH2,
+	MSG_ID_SYNC_TIMER0_DONE,
+	MSG_ID_SYNC_TIMER1_DONE,
+	MSG_ID_SYNC_TIMER2_DONE,
+	MSG_ID_ASYNC_TIMER0_DONE,
+	MSG_ID_ASYNC_TIMER1_DONE,
+	MSG_ID_ASYNC_TIMER2_DONE,
+	MSG_ID_ASYNC_TIMER3_DONE,
+	MSG_ID_AE_OVERFLOW,
+	MSG_ID_AF_OVERFLOW, /* 20 */
+	MSG_ID_AWB_OVERFLOW,
+	MSG_ID_RS_OVERFLOW,
+	MSG_ID_CS_OVERFLOW,
+	MSG_ID_IHIST_OVERFLOW,
+	MSG_ID_SKIN_OVERFLOW,
+	MSG_ID_AXI_ERROR,
+	MSG_ID_CAMIF_OVERFLOW,
+	MSG_ID_VIOLATION,
+	MSG_ID_CAMIF_ERROR,
+	MSG_ID_BUS_OVERFLOW, /* 30 */
+	MSG_ID_SOF_ACK,
+	MSG_ID_STOP_REC_ACK,
+};
+
+struct stats_buffer {
+	uint32_t aec;
+	uint32_t awb;
+	uint32_t af;
+	uint32_t ihist;
+	uint32_t rs;
+	uint32_t cs;
+	uint32_t skin;
+};
+
+struct vfe_msg_stats {
+	struct stats_buffer buff;
+	uint32_t    frameCounter;
+	uint32_t    status_bits;
+};
+
+
+struct vfe_frame_bpc_info {
+	uint32_t greenDefectPixelCount;
+	uint32_t redBlueDefectPixelCount;
+};
+
+struct vfe_frame_asf_info {
+	uint32_t  asfMaxEdge;
+	uint32_t  asfHbiCount;
+};
+
+struct vfe_msg_camif_status {
+	uint8_t  camifState;
+	uint32_t pixelCount;
+	uint32_t lineCount;
+};
+
+
+struct vfe31_irq_status {
+	uint32_t vfeIrqStatus0;
+	uint32_t vfeIrqStatus1;
+	uint32_t camifStatus;
+	uint32_t demosaicStatus;
+	uint32_t asfMaxEdge;
+	uint32_t vfePingPongStatus;
+};
+
+struct vfe_msg_output {
+	uint8_t   output_id;
+	uint32_t  yBuffer;
+	uint32_t  cbcrBuffer;
+	struct vfe_frame_bpc_info bpcInfo;
+	struct vfe_frame_asf_info asfInfo;
+	uint32_t  frameCounter;
+};
+
+struct vfe_message {
+	enum VFE31_MESSAGE_ID _d;
+	union {
+		struct vfe_msg_output              msgOut;
+		struct vfe_msg_stats               msgStats;
+		struct vfe_msg_camif_status        msgCamifError;
+   } _u;
+};
+
+/* New one for 7x30 */
+struct msm_vfe31_cmd {
+	int32_t  id;
+	uint16_t length;
+	void     *value;
+};
+
+#define V31_PREVIEW_AXI_FLAG  0x00000001
+#define V31_SNAPSHOT_AXI_FLAG (0x00000001<<1)
+
+struct vfe31_cmd_type {
+	uint16_t id;
+	uint32_t length;
+	uint32_t offset;
+	uint32_t flag;
+};
+
+struct vfe31_free_buf {
+	struct list_head node;
+	uint32_t paddr;
+	uint32_t y_off;
+	uint32_t cbcr_off;
+};
+
+struct vfe31_output_ch {
+	struct list_head free_buf_head;
+	spinlock_t free_buf_lock;
+	uint16_t output_fmt;
+	int8_t ch0;
+	int8_t ch1;
+	int8_t ch2;
+	uint32_t  frame_drop_cnt;
+};
+
+/* no error irq in mask 0 */
+#define VFE31_IMASK_ERROR_ONLY_0  0x0
+/* when normal case, don't want to block error status. */
+/* bit 0-21 are error irq bits */
+#define VFE31_IMASK_ERROR_ONLY_1               0x003FFFFF
+#define VFE31_IMASK_CAMIF_ERROR               (0x00000001<<0)
+#define VFE31_IMASK_STATS_CS_OVWR             (0x00000001<<1)
+#define VFE31_IMASK_STATS_IHIST_OVWR          (0x00000001<<2)
+#define VFE31_IMASK_REALIGN_BUF_Y_OVFL        (0x00000001<<3)
+#define VFE31_IMASK_REALIGN_BUF_CB_OVFL       (0x00000001<<4)
+#define VFE31_IMASK_REALIGN_BUF_CR_OVFL       (0x00000001<<5)
+#define VFE31_IMASK_VIOLATION                 (0x00000001<<6)
+#define VFE31_IMASK_IMG_MAST_0_BUS_OVFL       (0x00000001<<7)
+#define VFE31_IMASK_IMG_MAST_1_BUS_OVFL       (0x00000001<<8)
+#define VFE31_IMASK_IMG_MAST_2_BUS_OVFL       (0x00000001<<9)
+#define VFE31_IMASK_IMG_MAST_3_BUS_OVFL       (0x00000001<<10)
+#define VFE31_IMASK_IMG_MAST_4_BUS_OVFL       (0x00000001<<11)
+#define VFE31_IMASK_IMG_MAST_5_BUS_OVFL       (0x00000001<<12)
+#define VFE31_IMASK_IMG_MAST_6_BUS_OVFL       (0x00000001<<13)
+#define VFE31_IMASK_STATS_AE_BUS_OVFL         (0x00000001<<14)
+#define VFE31_IMASK_STATS_AF_BUS_OVFL         (0x00000001<<15)
+#define VFE31_IMASK_STATS_AWB_BUS_OVFL        (0x00000001<<16)
+#define VFE31_IMASK_STATS_RS_BUS_OVFL         (0x00000001<<17)
+#define VFE31_IMASK_STATS_CS_BUS_OVFL         (0x00000001<<18)
+#define VFE31_IMASK_STATS_IHIST_BUS_OVFL      (0x00000001<<19)
+#define VFE31_IMASK_STATS_SKIN_BUS_OVFL       (0x00000001<<20)
+#define VFE31_IMASK_AXI_ERROR                 (0x00000001<<21)
+
+#define VFE_COM_STATUS 0x000FE000
+
+struct vfe31_output_path {
+	uint16_t output_mode;     /* bitmask  */
+
+	struct vfe31_output_ch out0; /* preview and thumbnail */
+	struct vfe31_output_ch out1; /* snapshot */
+	struct vfe31_output_ch out2; /* video    */
+};
+
+struct vfe31_frame_extra {
+	uint32_t greenDefectPixelCount;
+	uint32_t redBlueDefectPixelCount;
+
+	uint32_t  asfMaxEdge;
+	uint32_t  asfHbiCount;
+
+	uint32_t yWrPmStats0;
+	uint32_t yWrPmStats1;
+	uint32_t cbcrWrPmStats0;
+	uint32_t cbcrWrPmStats1;
+
+	uint32_t  frameCounter;
+};
+
+#define VFE_DISABLE_ALL_IRQS             0
+#define VFE_CLEAR_ALL_IRQS               0xffffffff
+
+#define VFE_GLOBAL_RESET                 0x00000004
+#define VFE_CGC_OVERRIDE                 0x0000000C
+#define VFE_MODULE_CFG                   0x00000010
+#define VFE_CFG_OFF                      0x00000014
+#define VFE_IRQ_CMD                      0x00000018
+#define VFE_IRQ_MASK_0                   0x0000001C
+#define VFE_IRQ_MASK_1                   0x00000020
+#define VFE_IRQ_CLEAR_0                  0x00000024
+#define VFE_IRQ_CLEAR_1                  0x00000028
+#define VFE_IRQ_STATUS_0                 0x0000002C
+#define VFE_IRQ_STATUS_1                 0x00000030
+#define VFE_IRQ_COMP_MASK                0x00000034
+#define VFE_BUS_CMD                      0x00000038
+#define VFE_BUS_PING_PONG_STATUS         0x00000180
+#define VFE_BUS_OPERATION_STATUS         0x00000184
+
+#define VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_0        0x00000190
+#define VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_1        0x00000194
+
+#define VFE_AXI_CMD                      0x000001D8
+#define VFE_AXI_STATUS                   0x000001DC
+#define VFE_BUS_STATS_PING_PONG_BASE     0x000000F4
+
+#define VFE_BUS_STATS_AEC_WR_PING_ADDR   0x000000F4
+#define VFE_BUS_STATS_AEC_WR_PONG_ADDR   0x000000F8
+#define VFE_BUS_STATS_AEC_UB_CFG         0x000000FC
+#define VFE_BUS_STATS_AF_WR_PING_ADDR    0x00000100
+#define VFE_BUS_STATS_AF_WR_PONG_ADDR    0x00000104
+#define VFE_BUS_STATS_AF_UB_CFG          0x00000108
+#define VFE_BUS_STATS_AWB_WR_PING_ADDR   0x0000010C
+#define VFE_BUS_STATS_AWB_WR_PONG_ADDR   0x00000110
+#define VFE_BUS_STATS_AWB_UB_CFG         0x00000114
+#define VFE_BUS_STATS_RS_WR_PING_ADDR    0x00000118
+#define VFE_BUS_STATS_RS_WR_PONG_ADDR    0x0000011C
+#define VFE_BUS_STATS_RS_UB_CFG          0x00000120
+
+#define VFE_BUS_STATS_CS_WR_PING_ADDR    0x00000124
+#define VFE_BUS_STATS_CS_WR_PONG_ADDR    0x00000128
+#define VFE_BUS_STATS_CS_UB_CFG          0x0000012C
+#define VFE_BUS_STATS_HIST_WR_PING_ADDR  0x00000130
+#define VFE_BUS_STATS_HIST_WR_PONG_ADDR  0x00000134
+#define VFE_BUS_STATS_HIST_UB_CFG        0x00000138
+#define VFE_BUS_STATS_SKIN_WR_PING_ADDR  0x0000013C
+#define VFE_BUS_STATS_SKIN_WR_PONG_ADDR  0x00000140
+#define VFE_BUS_STATS_SKIN_UB_CFG        0x00000144
+#define VFE_BUS_PM_CMD                   0x00000188
+#define VFE_BUS_PM_CFG                   0x0000018C
+#define VFE_CAMIF_COMMAND                0x000001E0
+#define VFE_CAMIF_STATUS                 0x00000204
+#define VFE_REG_UPDATE_CMD               0x00000260
+#define VFE_DEMUX_GAIN_0                 0x00000288
+#define VFE_DEMUX_GAIN_1                 0x0000028C
+#define VFE_CHROMA_UP                    0x0000035C
+#define VFE_FRAMEDROP_ENC_Y_CFG          0x00000504
+#define VFE_FRAMEDROP_ENC_CBCR_CFG       0x00000508
+#define VFE_FRAMEDROP_ENC_Y_PATTERN      0x0000050C
+#define VFE_FRAMEDROP_ENC_CBCR_PATTERN   0x00000510
+#define VFE_FRAMEDROP_VIEW_Y             0x00000514
+#define VFE_FRAMEDROP_VIEW_CBCR          0x00000518
+#define VFE_FRAMEDROP_VIEW_Y_PATTERN     0x0000051C
+#define VFE_FRAMEDROP_VIEW_CBCR_PATTERN  0x00000520
+#define VFE_CLAMP_MAX                    0x00000524
+#define VFE_CLAMP_MIN                    0x00000528
+#define VFE_REALIGN_BUF                  0x0000052C
+#define VFE_STATS_CFG                    0x00000530
+#define VFE_DMI_CFG                      0x00000598
+#define VFE_DMI_ADDR                     0x0000059C
+#define VFE_DMI_DATA_LO                  0x000005A4
+#define VFE_AXI_CFG                      0x00000600
+
+struct vfe_stats_control {
+	uint8_t  ackPending;
+	uint32_t nextFrameAddrBuf;
+	uint32_t droppedStatsFrameCount;
+	uint32_t bufToRender;
+};
+
+struct vfe31_ctrl_type {
+	uint16_t operation_mode;     /* streaming or snapshot */
+	struct vfe31_output_path outpath;
+
+	uint32_t vfeImaskCompositePacked;
+
+	spinlock_t  update_ack_lock;
+	spinlock_t  io_lock;
+
+	int8_t aec_ack_pending;
+	int8_t awb_ack_pending;
+	int8_t af_ack_pending;
+	int8_t ihist_ack_pending;
+	int8_t rs_ack_pending;
+	int8_t cs_ack_pending;
+
+	struct msm_vfe_callback *resp;
+	uint32_t extlen;
+	void *extdata;
+
+	int8_t start_ack_pending;
+	atomic_t stop_ack_pending;
+	int8_t reset_ack_pending;
+	int8_t update_ack_pending;
+	enum vfe_recording_state recording_state;
+	int8_t output0_available;
+	int8_t output1_available;
+	int8_t update_gamma;
+	int8_t update_luma;
+	spinlock_t  tasklet_lock;
+	struct list_head tasklet_q;
+	int vfeirq;
+	void __iomem *vfebase;
+	void *syncdata;
+
+	struct resource	*vfemem;
+	struct resource *vfeio;
+
+	uint32_t stats_comp;
+	uint32_t hfr_mode;
+	atomic_t vstate;
+	uint32_t vfe_capture_count;
+	uint32_t sync_timer_repeat_count;
+	uint32_t sync_timer_state;
+	uint32_t sync_timer_number;
+
+	uint32_t vfeFrameId;
+	uint32_t output1Pattern;
+	uint32_t output1Period;
+	uint32_t output2Pattern;
+	uint32_t output2Period;
+	uint32_t vfeFrameSkipCount;
+	uint32_t vfeFrameSkipPeriod;
+	uint32_t status_bits;
+	struct vfe_stats_control afStatsControl;
+	struct vfe_stats_control awbStatsControl;
+	struct vfe_stats_control aecStatsControl;
+	struct vfe_stats_control ihistStatsControl;
+	struct vfe_stats_control rsStatsControl;
+	struct vfe_stats_control csStatsControl;
+	struct msm_camera_sensor_info *s_info;
+	struct vfe_message vMsgHold_Snap;
+	struct vfe_message vMsgHold_Thumb;
+	int8_t xbar_update_pending;
+	uint32_t xbar_cfg[2];
+	spinlock_t xbar_lock;
+	uint32_t while_stopping_mask;
+};
+
+#define statsAeNum      0
+#define statsAfNum      1
+#define statsAwbNum     2
+#define statsRsNum      3
+#define statsCsNum      4
+#define statsIhistNum   5
+#define statsSkinNum    6
+
+struct vfe_cmd_stats_ack{
+  uint32_t  nextStatsBuf;
+};
+
+#define VFE_STATS_BUFFER_COUNT            3
+
+struct vfe_cmd_stats_buf{
+   uint32_t statsBuf[VFE_STATS_BUFFER_COUNT];
+};
+#endif /* __MSM_VFE31_H__ */
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
new file mode 100644
index 0000000..4ca62ce
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -0,0 +1,3379 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/atomic.h>
+#include <mach/irqs.h>
+#include <mach/camera.h>
+#include <mach/msm_reqs.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#include "msm.h"
+#include "msm_vfe32.h"
+#include "msm_vpe1.h"
+
+atomic_t irq_cnt;
+
+#define CHECKED_COPY_FROM_USER(in) {					\
+	if (copy_from_user((in), (void __user *)cmd->value,		\
+			cmd->length)) {					\
+		rc = -EFAULT;						\
+		break;							\
+	}								\
+}
+
+static struct vfe32_ctrl_type *vfe32_ctrl;
+static struct msm_camera_io_clk camio_clk;
+static void  *vfe_syncdata;
+
+struct vfe32_isr_queue_cmd {
+	struct list_head list;
+	uint32_t                           vfeInterruptStatus0;
+	uint32_t                           vfeInterruptStatus1;
+	struct vfe_frame_asf_info          vfeAsfFrameInfo;
+	struct vfe_frame_bpc_info          vfeBpcFrameInfo;
+	struct vfe_msg_camif_status        vfeCamifStatusLocal;
+};
+
+static struct vfe32_cmd_type vfe32_cmd[] = {
+/* 0*/	{V32_DUMMY_0},
+		{V32_SET_CLK},
+		{V32_RESET},
+		{V32_START},
+		{V32_TEST_GEN_START},
+/* 5*/	{V32_OPERATION_CFG, V32_OPERATION_CFG_LEN},
+		{V32_AXI_OUT_CFG, V32_AXI_OUT_LEN, V32_AXI_OUT_OFF, 0xFF},
+		{V32_CAMIF_CFG, V32_CAMIF_LEN, V32_CAMIF_OFF, 0xFF},
+		{V32_AXI_INPUT_CFG},
+		{V32_BLACK_LEVEL_CFG, V32_BLACK_LEVEL_LEN, V32_BLACK_LEVEL_OFF,
+		0xFF},
+/*10*/  {V32_ROLL_OFF_CFG, V32_ROLL_OFF_CFG_LEN, V32_ROLL_OFF_CFG_OFF,
+		0xFF},
+		{V32_DEMUX_CFG, V32_DEMUX_LEN, V32_DEMUX_OFF, 0xFF},
+		{V32_FOV_CFG, V32_FOV_LEN, V32_FOV_OFF, 0xFF},
+		{V32_MAIN_SCALER_CFG, V32_MAIN_SCALER_LEN, V32_MAIN_SCALER_OFF,
+		0xFF},
+		{V32_WB_CFG, V32_WB_LEN, V32_WB_OFF, 0xFF},
+/*15*/	{V32_COLOR_COR_CFG, V32_COLOR_COR_LEN, V32_COLOR_COR_OFF, 0xFF},
+		{V32_RGB_G_CFG, V32_RGB_G_LEN, V32_RGB_G_OFF, 0xFF},
+		{V32_LA_CFG, V32_LA_LEN, V32_LA_OFF, 0xFF },
+		{V32_CHROMA_EN_CFG, V32_CHROMA_EN_LEN, V32_CHROMA_EN_OFF, 0xFF},
+		{V32_CHROMA_SUP_CFG, V32_CHROMA_SUP_LEN, V32_CHROMA_SUP_OFF,
+		0xFF},
+/*20*/	{V32_MCE_CFG, V32_MCE_LEN, V32_MCE_OFF, 0xFF},
+		{V32_SK_ENHAN_CFG, V32_SCE_LEN, V32_SCE_OFF, 0xFF},
+		{V32_ASF_CFG, V32_ASF_LEN, V32_ASF_OFF, 0xFF},
+		{V32_S2Y_CFG, V32_S2Y_LEN, V32_S2Y_OFF, 0xFF},
+		{V32_S2CbCr_CFG, V32_S2CbCr_LEN, V32_S2CbCr_OFF, 0xFF},
+/*25*/	{V32_CHROMA_SUBS_CFG, V32_CHROMA_SUBS_LEN, V32_CHROMA_SUBS_OFF,
+		0xFF},
+		{V32_OUT_CLAMP_CFG, V32_OUT_CLAMP_LEN, V32_OUT_CLAMP_OFF,
+		0xFF},
+		{V32_FRAME_SKIP_CFG, V32_FRAME_SKIP_LEN, V32_FRAME_SKIP_OFF,
+		0xFF},
+		{V32_DUMMY_1},
+		{V32_DUMMY_2},
+/*30*/	{V32_DUMMY_3},
+		{V32_UPDATE},
+		{V32_BL_LVL_UPDATE, V32_BLACK_LEVEL_LEN, V32_BLACK_LEVEL_OFF,
+		0xFF},
+		{V32_DEMUX_UPDATE, V32_DEMUX_LEN, V32_DEMUX_OFF, 0xFF},
+		{V32_FOV_UPDATE, V32_FOV_LEN, V32_FOV_OFF, 0xFF},
+/*35*/	{V32_MAIN_SCALER_UPDATE, V32_MAIN_SCALER_LEN, V32_MAIN_SCALER_OFF,
+		0xFF},
+		{V32_WB_UPDATE, V32_WB_LEN, V32_WB_OFF, 0xFF},
+		{V32_COLOR_COR_UPDATE, V32_COLOR_COR_LEN, V32_COLOR_COR_OFF,
+		0xFF},
+		{V32_RGB_G_UPDATE, V32_RGB_G_LEN, V32_CHROMA_EN_OFF, 0xFF},
+		{V32_LA_UPDATE, V32_LA_LEN, V32_LA_OFF, 0xFF },
+/*40*/	{V32_CHROMA_EN_UPDATE, V32_CHROMA_EN_LEN, V32_CHROMA_EN_OFF,
+		0xFF},
+		{V32_CHROMA_SUP_UPDATE, V32_CHROMA_SUP_LEN, V32_CHROMA_SUP_OFF,
+		0xFF},
+		{V32_MCE_UPDATE, V32_MCE_LEN, V32_MCE_OFF, 0xFF},
+		{V32_SK_ENHAN_UPDATE, V32_SCE_LEN, V32_SCE_OFF, 0xFF},
+		{V32_S2CbCr_UPDATE, V32_S2CbCr_LEN, V32_S2CbCr_OFF, 0xFF},
+/*45*/	{V32_S2Y_UPDATE, V32_S2Y_LEN, V32_S2Y_OFF, 0xFF},
+		{V32_ASF_UPDATE, V32_ASF_UPDATE_LEN, V32_ASF_OFF, 0xFF},
+		{V32_FRAME_SKIP_UPDATE},
+		{V32_CAMIF_FRAME_UPDATE},
+		{V32_STATS_AF_UPDATE, V32_STATS_AF_LEN, V32_STATS_AF_OFF},
+/*50*/	{V32_STATS_AE_UPDATE, V32_STATS_AE_LEN, V32_STATS_AE_OFF},
+		{V32_STATS_AWB_UPDATE, V32_STATS_AWB_LEN, V32_STATS_AWB_OFF},
+		{V32_STATS_RS_UPDATE, V32_STATS_RS_LEN, V32_STATS_RS_OFF},
+		{V32_STATS_CS_UPDATE, V32_STATS_CS_LEN, V32_STATS_CS_OFF},
+		{V32_STATS_SKIN_UPDATE},
+/*55*/	{V32_STATS_IHIST_UPDATE, V32_STATS_IHIST_LEN, V32_STATS_IHIST_OFF},
+		{V32_DUMMY_4},
+		{V32_EPOCH1_ACK},
+		{V32_EPOCH2_ACK},
+		{V32_START_RECORDING},
+/*60*/	{V32_STOP_RECORDING},
+		{V32_DUMMY_5},
+		{V32_DUMMY_6},
+		{V32_CAPTURE, V32_CAPTURE_LEN, 0xFF},
+		{V32_DUMMY_7},
+/*65*/	{V32_STOP},
+		{V32_GET_HW_VERSION},
+		{V32_GET_FRAME_SKIP_COUNTS},
+		{V32_OUTPUT1_BUFFER_ENQ},
+		{V32_OUTPUT2_BUFFER_ENQ},
+/*70*/	{V32_OUTPUT3_BUFFER_ENQ},
+		{V32_JPEG_OUT_BUF_ENQ},
+		{V32_RAW_OUT_BUF_ENQ},
+		{V32_RAW_IN_BUF_ENQ},
+		{V32_STATS_AF_ENQ},
+/*75*/	{V32_STATS_AE_ENQ},
+		{V32_STATS_AWB_ENQ},
+		{V32_STATS_RS_ENQ},
+		{V32_STATS_CS_ENQ},
+		{V32_STATS_SKIN_ENQ},
+/*80*/	{V32_STATS_IHIST_ENQ},
+		{V32_DUMMY_8},
+		{V32_JPEG_ENC_CFG},
+		{V32_DUMMY_9},
+		{V32_STATS_AF_START, V32_STATS_AF_LEN, V32_STATS_AF_OFF},
+/*85*/	{V32_STATS_AF_STOP},
+		{V32_STATS_AE_START, V32_STATS_AE_LEN, V32_STATS_AE_OFF},
+		{V32_STATS_AE_STOP},
+		{V32_STATS_AWB_START, V32_STATS_AWB_LEN, V32_STATS_AWB_OFF},
+		{V32_STATS_AWB_STOP},
+/*90*/	{V32_STATS_RS_START, V32_STATS_RS_LEN, V32_STATS_RS_OFF},
+		{V32_STATS_RS_STOP},
+		{V32_STATS_CS_START, V32_STATS_CS_LEN, V32_STATS_CS_OFF},
+		{V32_STATS_CS_STOP},
+		{V32_STATS_SKIN_START},
+/*95*/	{V32_STATS_SKIN_STOP},
+		{V32_STATS_IHIST_START,
+		V32_STATS_IHIST_LEN, V32_STATS_IHIST_OFF},
+		{V32_STATS_IHIST_STOP},
+		{V32_DUMMY_10},
+		{V32_SYNC_TIMER_SETTING, V32_SYNC_TIMER_LEN,
+			V32_SYNC_TIMER_OFF},
+/*100*/	{V32_ASYNC_TIMER_SETTING, V32_ASYNC_TIMER_LEN, V32_ASYNC_TIMER_OFF},
+		{V32_LIVESHOT},
+		{V32_LA_SETUP},
+		{V32_LINEARIZATION, V32_LINEARIZATION_LEN1,
+					V32_LINEARIZATION_OFF1},
+		{V32_DEMOSAICV3},
+/*105*/	{V32_DEMOSAICV3_ABCC_CFG},
+		{V32_DEMOSAICV3_DBCC_CFG, V32_DEMOSAICV3_DBCC_LEN,
+			V32_DEMOSAICV3_DBCC_OFF},
+		{V32_DEMOSAICV3_DBPC_CFG},
+		{V32_DEMOSAICV3_ABF_CFG},
+		{V32_DEMOSAICV3_ABCC_UPDATE},
+		{V32_DEMOSAICV3_DBCC_UPDATE, V32_DEMOSAICV3_DBCC_LEN,
+			V32_DEMOSAICV3_DBCC_OFF},
+		{V32_DEMOSAICV3_DBPC_UPDATE},
+};
+
+uint32_t vfe32_AXI_WM_CFG[] = {
+	0x0000004C,
+	0x00000064,
+	0x0000007C,
+	0x00000094,
+	0x000000AC,
+	0x000000C4,
+	0x000000DC,
+};
+
+static const char * const vfe32_general_cmd[] = {
+	"DUMMY_0",  /* 0 */
+	"SET_CLK",
+	"RESET",
+	"START",
+	"TEST_GEN_START",
+	"OPERATION_CFG",  /* 5 */
+	"AXI_OUT_CFG",
+	"CAMIF_CFG",
+	"AXI_INPUT_CFG",
+	"BLACK_LEVEL_CFG",
+	"ROLL_OFF_CFG",  /* 10 */
+	"DEMUX_CFG",
+	"FOV_CFG",
+	"MAIN_SCALER_CFG",
+	"WB_CFG",
+	"COLOR_COR_CFG", /* 15 */
+	"RGB_G_CFG",
+	"LA_CFG",
+	"CHROMA_EN_CFG",
+	"CHROMA_SUP_CFG",
+	"MCE_CFG", /* 20 */
+	"SK_ENHAN_CFG",
+	"ASF_CFG",
+	"S2Y_CFG",
+	"S2CbCr_CFG",
+	"CHROMA_SUBS_CFG",  /* 25 */
+	"OUT_CLAMP_CFG",
+	"FRAME_SKIP_CFG",
+	"DUMMY_1",
+	"DUMMY_2",
+	"DUMMY_3",  /* 30 */
+	"UPDATE",
+	"BL_LVL_UPDATE",
+	"DEMUX_UPDATE",
+	"FOV_UPDATE",
+	"MAIN_SCALER_UPDATE",  /* 35 */
+	"WB_UPDATE",
+	"COLOR_COR_UPDATE",
+	"RGB_G_UPDATE",
+	"LA_UPDATE",
+	"CHROMA_EN_UPDATE",  /* 40 */
+	"CHROMA_SUP_UPDATE",
+	"MCE_UPDATE",
+	"SK_ENHAN_UPDATE",
+	"S2CbCr_UPDATE",
+	"S2Y_UPDATE",  /* 45 */
+	"ASF_UPDATE",
+	"FRAME_SKIP_UPDATE",
+	"CAMIF_FRAME_UPDATE",
+	"STATS_AF_UPDATE",
+	"STATS_AE_UPDATE",  /* 50 */
+	"STATS_AWB_UPDATE",
+	"STATS_RS_UPDATE",
+	"STATS_CS_UPDATE",
+	"STATS_SKIN_UPDATE",
+	"STATS_IHIST_UPDATE",  /* 55 */
+	"DUMMY_4",
+	"EPOCH1_ACK",
+	"EPOCH2_ACK",
+	"START_RECORDING",
+	"STOP_RECORDING",  /* 60 */
+	"DUMMY_5",
+	"DUMMY_6",
+	"CAPTURE",
+	"DUMMY_7",
+	"STOP",  /* 65 */
+	"GET_HW_VERSION",
+	"GET_FRAME_SKIP_COUNTS",
+	"OUTPUT1_BUFFER_ENQ",
+	"OUTPUT2_BUFFER_ENQ",
+	"OUTPUT3_BUFFER_ENQ",  /* 70 */
+	"JPEG_OUT_BUF_ENQ",
+	"RAW_OUT_BUF_ENQ",
+	"RAW_IN_BUF_ENQ",
+	"STATS_AF_ENQ",
+	"STATS_AE_ENQ",  /* 75 */
+	"STATS_AWB_ENQ",
+	"STATS_RS_ENQ",
+	"STATS_CS_ENQ",
+	"STATS_SKIN_ENQ",
+	"STATS_IHIST_ENQ",  /* 80 */
+	"DUMMY_8",
+	"JPEG_ENC_CFG",
+	"DUMMY_9",
+	"STATS_AF_START",
+	"STATS_AF_STOP",  /* 85 */
+	"STATS_AE_START",
+	"STATS_AE_STOP",
+	"STATS_AWB_START",
+	"STATS_AWB_STOP",
+	"STATS_RS_START",  /* 90 */
+	"STATS_RS_STOP",
+	"STATS_CS_START",
+	"STATS_CS_STOP",
+	"STATS_SKIN_START",
+	"STATS_SKIN_STOP",  /* 95 */
+	"STATS_IHIST_START",
+	"STATS_IHIST_STOP",
+	"DUMMY_10",
+	"SYNC_TIMER_SETTING",
+	"ASYNC_TIMER_SETTING",  /* 100 */
+	"LIVESHOT",
+	"LA_SETUP",
+	"LINEARIZATION",
+	"DEMOSAICV3",
+	"DEMOSAICV3_ABCC_CFG", /* 105 */
+	"DEMOSAICV3_DBCC_CFG",
+	"DEMOSAICV3_DBPC_CFG",
+	"DEMOSAICV3_ABF_CFG", /* 108 */
+	"DEMOSAICV3_ABCC_UPDATE",
+	"DEMOSAICV3_DBCC_UPDATE",
+	"DEMOSAICV3_DBPC_UPDATE",
+	"EZTUNE_CFG",
+};
+
+static void vfe_addr_convert(struct msm_vfe_phy_info *pinfo,
+	enum vfe_resp_msg type, void *data, void **ext, int32_t *elen)
+{
+	uint8_t outid;
+	switch (type) {
+	case VFE_MSG_OUTPUT_T:
+	case VFE_MSG_OUTPUT_P:
+	case VFE_MSG_OUTPUT_S:
+	case VFE_MSG_OUTPUT_V:
+		pinfo->output_id =
+			((struct vfe_message *)data)->_u.msgOut.output_id;
+
+		switch (type) {
+		case VFE_MSG_OUTPUT_P:
+			outid = OUTPUT_TYPE_P;
+			break;
+		case VFE_MSG_OUTPUT_V:
+			outid = OUTPUT_TYPE_V;
+			break;
+		case VFE_MSG_OUTPUT_T:
+			outid = OUTPUT_TYPE_T;
+			break;
+		case VFE_MSG_OUTPUT_S:
+			outid = OUTPUT_TYPE_S;
+			break;
+		default:
+			outid = 0xff;
+			break;
+		}
+		pinfo->output_id = outid;
+		pinfo->y_phy =
+			((struct vfe_message *)data)->_u.msgOut.yBuffer;
+		pinfo->cbcr_phy =
+			((struct vfe_message *)data)->_u.msgOut.cbcrBuffer;
+
+		pinfo->frame_id =
+		((struct vfe_message *)data)->_u.msgOut.frameCounter;
+
+		((struct vfe_msg_output *)(vfe32_ctrl->extdata))->bpcInfo =
+		((struct vfe_message *)data)->_u.msgOut.bpcInfo;
+		((struct vfe_msg_output *)(vfe32_ctrl->extdata))->asfInfo =
+		((struct vfe_message *)data)->_u.msgOut.asfInfo;
+		((struct vfe_msg_output *)(vfe32_ctrl->extdata))->frameCounter =
+		((struct vfe_message *)data)->_u.msgOut.frameCounter;
+		*ext  = vfe32_ctrl->extdata;
+		*elen = vfe32_ctrl->extlen;
+		break;
+	case VFE_MSG_STATS_AF:
+	case VFE_MSG_STATS_AEC:
+	case VFE_MSG_STATS_AWB:
+	case VFE_MSG_STATS_IHIST:
+	case VFE_MSG_STATS_RS:
+	case VFE_MSG_STATS_CS:
+		pinfo->sbuf_phy =
+		((struct vfe_message *)data)->_u.msgStats.buffer;
+
+		pinfo->frame_id =
+		((struct vfe_message *)data)->_u.msgStats.frameCounter;
+
+		break;
+	default:
+		break;
+	} /* switch */
+}
+
+static void vfe32_proc_ops(enum VFE32_MESSAGE_ID id, void *msg, size_t len)
+{
+	struct msm_vfe_resp *rp;
+
+	rp = msm_isp_sync_alloc(sizeof(struct msm_vfe_resp),
+		vfe32_ctrl->syncdata, GFP_ATOMIC);
+	if (!rp) {
+		CDBG("rp: cannot allocate buffer\n");
+		return;
+	}
+	CDBG("vfe32_proc_ops, msgId = %d\n", id);
+	rp->evt_msg.type   = MSM_CAMERA_MSG;
+	rp->evt_msg.msg_id = id;
+	rp->evt_msg.len    = len;
+	rp->evt_msg.data   = msg;
+
+	switch (rp->evt_msg.msg_id) {
+	case MSG_ID_SNAPSHOT_DONE:
+		rp->type = VFE_MSG_SNAPSHOT;
+		break;
+
+	case MSG_ID_OUTPUT_P:
+		rp->type = VFE_MSG_OUTPUT_P;
+		vfe_addr_convert(&(rp->phy), VFE_MSG_OUTPUT_P,
+			rp->evt_msg.data, &(rp->extdata),
+			&(rp->extlen));
+		break;
+
+	case MSG_ID_OUTPUT_T:
+		rp->type = VFE_MSG_OUTPUT_T;
+		vfe_addr_convert(&(rp->phy), VFE_MSG_OUTPUT_T,
+			rp->evt_msg.data, &(rp->extdata),
+			&(rp->extlen));
+		break;
+
+	case MSG_ID_OUTPUT_S:
+		rp->type = VFE_MSG_OUTPUT_S;
+		vfe_addr_convert(&(rp->phy), VFE_MSG_OUTPUT_S,
+			rp->evt_msg.data, &(rp->extdata),
+			&(rp->extlen));
+		break;
+
+	case MSG_ID_OUTPUT_V:
+		rp->type = VFE_MSG_OUTPUT_V;
+		vfe_addr_convert(&(rp->phy), VFE_MSG_OUTPUT_V,
+			rp->evt_msg.data, &(rp->extdata),
+			&(rp->extlen));
+		break;
+
+	case MSG_ID_STATS_AF:
+		rp->type = VFE_MSG_STATS_AF;
+		vfe_addr_convert(&(rp->phy), VFE_MSG_STATS_AF,
+				rp->evt_msg.data, NULL, NULL);
+		break;
+
+	case MSG_ID_STATS_AWB:
+		rp->type = VFE_MSG_STATS_AWB;
+		vfe_addr_convert(&(rp->phy), VFE_MSG_STATS_AWB,
+				rp->evt_msg.data, NULL, NULL);
+		break;
+
+	case MSG_ID_STATS_AEC:
+		rp->type = VFE_MSG_STATS_AEC;
+		vfe_addr_convert(&(rp->phy), VFE_MSG_STATS_AEC,
+				rp->evt_msg.data, NULL, NULL);
+		break;
+
+	case MSG_ID_STATS_SKIN:
+		rp->type = VFE_MSG_STATS_SKIN;
+		vfe_addr_convert(&(rp->phy), VFE_MSG_STATS_SKIN,
+				rp->evt_msg.data, NULL, NULL);
+		break;
+
+	case MSG_ID_STATS_IHIST:
+		rp->type = VFE_MSG_STATS_IHIST;
+		vfe_addr_convert(&(rp->phy), VFE_MSG_STATS_IHIST,
+				rp->evt_msg.data, NULL, NULL);
+		break;
+
+	case MSG_ID_STATS_RS:
+		rp->type = VFE_MSG_STATS_RS;
+		vfe_addr_convert(&(rp->phy), VFE_MSG_STATS_RS,
+				rp->evt_msg.data, NULL, NULL);
+		break;
+
+	case MSG_ID_STATS_CS:
+		rp->type = VFE_MSG_STATS_CS;
+		vfe_addr_convert(&(rp->phy), VFE_MSG_STATS_CS,
+				rp->evt_msg.data, NULL, NULL);
+		break;
+
+	case MSG_ID_SYNC_TIMER0_DONE:
+		rp->type = VFE_MSG_SYNC_TIMER0;
+		break;
+
+	case MSG_ID_SYNC_TIMER1_DONE:
+		rp->type = VFE_MSG_SYNC_TIMER1;
+		break;
+
+	case MSG_ID_SYNC_TIMER2_DONE:
+		rp->type = VFE_MSG_SYNC_TIMER2;
+		break;
+
+	default:
+		rp->type = VFE_MSG_GENERAL;
+		break;
+	}
+
+	/* save the frame id.*/
+	rp->evt_msg.frame_id = rp->phy.frame_id;
+
+	v4l2_subdev_notify(vfe32_ctrl->subdev, NOTIFY_VFE_MSG_EVT, rp);
+}
+
+static void vfe_send_outmsg(uint8_t msgid, uint32_t pyaddr,
+	uint32_t pcbcraddr)
+{
+	struct vfe_message msg;
+	uint8_t outid;
+
+	msg._d = msgid;   /* now the output mode is redundnat. */
+
+	switch (msgid) {
+	case MSG_ID_OUTPUT_P:
+		outid = OUTPUT_TYPE_P;
+		break;
+	case MSG_ID_OUTPUT_V:
+		outid = OUTPUT_TYPE_V;
+		break;
+	case MSG_ID_OUTPUT_T:
+		outid = OUTPUT_TYPE_T;
+		break;
+	case MSG_ID_OUTPUT_S:
+		outid = OUTPUT_TYPE_S;
+		break;
+	default:
+		outid = 0xff;  /* -1 for error condition.*/
+		break;
+	}
+	msg._u.msgOut.output_id   = msgid;
+	msg._u.msgOut.yBuffer     = pyaddr;
+	msg._u.msgOut.cbcrBuffer  = pcbcraddr;
+	vfe32_proc_ops(msgid, &msg, sizeof(struct vfe_message));
+	return;
+}
+
+static void vfe32_stop(void)
+{
+	uint8_t  axiBusyFlag = true;
+	unsigned long flags;
+
+	atomic_set(&vfe32_ctrl->vstate, 0);
+
+	/* for reset hw modules, and send msg when reset_irq comes.*/
+	spin_lock_irqsave(&vfe32_ctrl->stop_flag_lock, flags);
+	vfe32_ctrl->stop_ack_pending = TRUE;
+	spin_unlock_irqrestore(&vfe32_ctrl->stop_flag_lock, flags);
+
+	/* disable all interrupts.  */
+	msm_io_w(VFE_DISABLE_ALL_IRQS,
+		vfe32_ctrl->vfebase + VFE_IRQ_MASK_0);
+	msm_io_w(VFE_DISABLE_ALL_IRQS,
+			vfe32_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+	/* clear all pending interrupts*/
+	msm_io_w(VFE_CLEAR_ALL_IRQS,
+		vfe32_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+	msm_io_w(VFE_CLEAR_ALL_IRQS,
+		vfe32_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_io_w_mb(1,
+		vfe32_ctrl->vfebase + VFE_IRQ_CMD);
+
+	/* in either continuous or snapshot mode, stop command can be issued
+	 * at any time. stop camif immediately. */
+	msm_io_w(CAMIF_COMMAND_STOP_IMMEDIATELY,
+		vfe32_ctrl->vfebase + VFE_CAMIF_COMMAND);
+	wmb();
+	/* axi halt command. */
+	msm_io_w(AXI_HALT,
+		vfe32_ctrl->vfebase + VFE_AXI_CMD);
+	wmb();
+	while (axiBusyFlag) {
+		if (msm_io_r(vfe32_ctrl->vfebase + VFE_AXI_STATUS) & 0x1)
+			axiBusyFlag = false;
+	}
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_io_w_mb(AXI_HALT_CLEAR,
+		vfe32_ctrl->vfebase + VFE_AXI_CMD);
+
+	/* after axi halt, then ok to apply global reset. */
+	/* enable reset_ack and async timer interrupt only while
+	stopping the pipeline.*/
+	msm_io_w(0xf0000000,
+		vfe32_ctrl->vfebase + VFE_IRQ_MASK_0);
+	msm_io_w(VFE_IMASK_WHILE_STOPPING_1,
+		vfe32_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_io_w_mb(VFE_RESET_UPON_STOP_CMD,
+		vfe32_ctrl->vfebase + VFE_GLOBAL_RESET);
+}
+
+static int vfe32_enqueue_free_buf(struct vfe32_output_ch *outch,
+	uint32_t paddr, uint32_t y_off, uint32_t cbcr_off)
+{
+	struct vfe32_free_buf *free_buf = NULL;
+	unsigned long flags = 0;
+	free_buf = kmalloc(sizeof(struct vfe32_free_buf), GFP_KERNEL);
+	if (!free_buf)
+		return -ENOMEM;
+
+	spin_lock_irqsave(&outch->free_buf_lock, flags);
+	free_buf->paddr = paddr;
+	free_buf->y_off = y_off;
+	free_buf->cbcr_off = cbcr_off;
+	list_add_tail(&free_buf->node, &outch->free_buf_queue);
+	CDBG("%s: free_buf paddr = 0x%x, y_off = %d, cbcr_off = %d\n",
+		__func__, free_buf->paddr, free_buf->y_off,
+		free_buf->cbcr_off);
+	spin_unlock_irqrestore(&outch->free_buf_lock, flags);
+	return 0;
+}
+
+static struct vfe32_free_buf *vfe32_dequeue_free_buf(
+	struct vfe32_output_ch *outch)
+{
+	unsigned long flags = 0;
+	struct vfe32_free_buf *free_buf = NULL;
+	spin_lock_irqsave(&outch->free_buf_lock, flags);
+	if (!list_empty(&outch->free_buf_queue)) {
+		free_buf = list_first_entry(&outch->free_buf_queue,
+			struct vfe32_free_buf, node);
+		if (free_buf)
+			list_del_init(&free_buf->node);
+	}
+	spin_unlock_irqrestore(&outch->free_buf_lock, flags);
+	return free_buf;
+}
+
+static void vfe32_reset_free_buf_queue(
+	struct vfe32_output_ch *outch)
+{
+	unsigned long flags = 0;
+	struct vfe32_free_buf *free_buf = NULL;
+	spin_lock_irqsave(&outch->free_buf_lock, flags);
+	while (!list_empty(&outch->free_buf_queue)) {
+		free_buf = list_first_entry(&outch->free_buf_queue,
+			struct vfe32_free_buf, node);
+		if (free_buf) {
+			list_del_init(&free_buf->node);
+			kfree(free_buf);
+		}
+	}
+	spin_unlock_irqrestore(&outch->free_buf_lock, flags);
+}
+
+static void vfe32_init_free_buf_queues(void)
+{
+	INIT_LIST_HEAD(&vfe32_ctrl->outpath.out0.free_buf_queue);
+	INIT_LIST_HEAD(&vfe32_ctrl->outpath.out1.free_buf_queue);
+	INIT_LIST_HEAD(&vfe32_ctrl->outpath.out2.free_buf_queue);
+	spin_lock_init(&vfe32_ctrl->outpath.out0.free_buf_lock);
+	spin_lock_init(&vfe32_ctrl->outpath.out1.free_buf_lock);
+	spin_lock_init(&vfe32_ctrl->outpath.out2.free_buf_lock);
+}
+
+static void vfe32_reset_free_buf_queues(void)
+{
+	vfe32_reset_free_buf_queue(&vfe32_ctrl->outpath.out0);
+	vfe32_reset_free_buf_queue(&vfe32_ctrl->outpath.out1);
+	vfe32_reset_free_buf_queue(&vfe32_ctrl->outpath.out2);
+}
+
+static int vfe32_config_axi(int mode, struct axidata *ad, uint32_t *ao)
+{
+	int ret;
+	int i;
+	uint32_t *p, *p1, *p2;
+	int32_t *ch_info;
+	struct vfe32_output_ch *outp1, *outp2;
+	struct msm_pmem_region *regp1 = NULL;
+	struct msm_pmem_region *regp2 = NULL;
+
+	outp1 = NULL;
+	outp2 = NULL;
+
+	p = ao + 2;
+
+	/* Update the corresponding write masters for each output*/
+	ch_info = ao + V32_AXI_CFG_LEN;
+	vfe32_ctrl->outpath.out0.ch0 = 0x0000FFFF & *ch_info;
+	vfe32_ctrl->outpath.out0.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
+	vfe32_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info++;
+	vfe32_ctrl->outpath.out1.ch0 = 0x0000FFFF & *ch_info;
+	vfe32_ctrl->outpath.out1.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
+	vfe32_ctrl->outpath.out1.ch2 = 0x0000FFFF & *ch_info++;
+	vfe32_ctrl->outpath.out2.ch0 = 0x0000FFFF & *ch_info;
+	vfe32_ctrl->outpath.out2.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
+	vfe32_ctrl->outpath.out2.ch2 = 0x0000FFFF & *ch_info++;
+
+	CDBG("vfe32_config_axi: mode = %d, bufnum1 = %d, bufnum2 = %d\n",
+		mode, ad->bufnum1, ad->bufnum2);
+
+	switch (mode) {
+
+	case OUTPUT_2: {
+		if (ad->bufnum2 < 3)
+			return -EINVAL;
+		regp1 = &(ad->region[ad->bufnum1]);
+		outp1 = &(vfe32_ctrl->outpath.out0);
+		vfe32_ctrl->outpath.output_mode |= VFE32_OUTPUT_MODE_PT;
+
+		for (i = 0; i < 2; i++) {
+			p1 = ao + 6 + i;    /* wm0 for y  */
+			*p1 = (regp1->paddr + regp1->info.y_off);
+
+			p1 = ao + 12 + i;  /* wm1 for cbcr */
+			*p1 = (regp1->paddr + regp1->info.cbcr_off);
+			regp1++;
+		}
+		for (i = 2; i < ad->bufnum2; i++) {
+			ret = vfe32_enqueue_free_buf(outp1, regp1->paddr,
+				regp1->info.y_off, regp1->info.cbcr_off);
+			if (ret < 0)
+				return ret;
+			regp1++;
+		}
+	}
+		break;
+
+	case OUTPUT_1_AND_2:
+		/* use wm0& 4 for thumbnail, wm1&5 for main image.*/
+		if ((ad->bufnum1 < 1) || (ad->bufnum2 < 1))
+			return -EINVAL;
+		vfe32_ctrl->outpath.output_mode |=
+			VFE32_OUTPUT_MODE_S;  /* main image.*/
+		vfe32_ctrl->outpath.output_mode |=
+			VFE32_OUTPUT_MODE_PT;  /* thumbnail. */
+
+		regp1 = &(ad->region[0]); /* this is thumbnail buffer. */
+		/* this is main image buffer. */
+		regp2 = &(ad->region[ad->bufnum1]);
+		outp1 = &(vfe32_ctrl->outpath.out0);
+		outp2 = &(vfe32_ctrl->outpath.out1); /* snapshot */
+
+		/*  Parse the buffers!!! */
+		if (ad->bufnum2 == 1) {	/* assuming bufnum1 = bufnum2 */
+			p1 = ao + 6;   /* wm0 ping */
+			*p1++ = (regp1->paddr + regp1->info.y_off);
+			/* this is to duplicate ping address to pong.*/
+			*p1 = (regp1->paddr + regp1->info.y_off);
+			p1 = ao + 30;  /* wm4 ping */
+			*p1++ = (regp1->paddr + regp1->info.cbcr_off);
+			/* this is to duplicate ping address to pong.*/
+			*p1 = (regp1->paddr + regp1->info.cbcr_off);
+			p1 = ao + 12;   /* wm1 ping */
+			*p1++ = (regp2->paddr + regp2->info.y_off);
+			/* pong = ping,*/
+			*p1 = (regp2->paddr + regp2->info.y_off);
+			p1 = ao + 36;  /* wm5 */
+			*p1++ = (regp2->paddr + regp2->info.cbcr_off);
+			*p1 = (regp2->paddr + regp2->info.cbcr_off);
+
+		} else { /* more than one snapshot */
+			/* first fill ping & pong */
+			for (i = 0; i < 2; i++) {
+				p1 = ao + 6 + i;    /* wm0 for y  */
+				*p1 = (regp1->paddr + regp1->info.y_off);
+				p1 = ao + 30 + i;  /* wm4 for cbcr */
+				*p1 = (regp1->paddr + regp1->info.cbcr_off);
+				regp1++;
+			}
+
+			for (i = 0; i < 2; i++) {
+				p2 = ao + 12 + i;    /* wm1 for y  */
+				*p2 = (regp2->paddr + regp2->info.y_off);
+				p2 = ao + 36 + i;  /* wm5 for cbcr */
+				*p2 = (regp2->paddr + regp2->info.cbcr_off);
+				regp2++;
+			}
+
+			for (i = 2; i < ad->bufnum1; i++) {
+				ret = vfe32_enqueue_free_buf(outp1,
+							regp1->paddr,
+							regp1->info.y_off,
+							regp1->info.cbcr_off);
+				if (ret < 0)
+					return ret;
+				regp1++;
+			}
+			for (i = 2; i < ad->bufnum2; i++) {
+				ret = vfe32_enqueue_free_buf(outp2,
+							regp2->paddr,
+							regp2->info.y_off,
+							regp2->info.cbcr_off);
+				if (ret < 0)
+					return ret;
+				regp2++;
+			}
+		}
+		break;
+
+	case OUTPUT_1_AND_3:
+		/* use wm0& 4 for preview, wm1&5 for video.*/
+		if ((ad->bufnum1 < 2) || (ad->bufnum2 < 2))
+			return -EINVAL;
+
+		vfe32_ctrl->outpath.output_mode |=
+			VFE32_OUTPUT_MODE_V;  /* video*/
+		vfe32_ctrl->outpath.output_mode |=
+			VFE32_OUTPUT_MODE_PT;  /* preview */
+
+		regp1 = &(ad->region[0]); /* this is preview buffer. */
+		regp2 = &(ad->region[ad->bufnum1]);/* this is video buffer. */
+		outp1 = &(vfe32_ctrl->outpath.out0); /* preview */
+		outp2 = &(vfe32_ctrl->outpath.out2); /* video */
+
+
+		for (i = 0; i < 2; i++) {
+			p1 = ao + 6 + i;    /* wm0 for y  */
+			*p1 = (regp1->paddr + regp1->info.y_off);
+
+			p1 = ao + 30 + i;  /* wm1 for cbcr */
+			*p1 = (regp1->paddr + regp1->info.cbcr_off);
+			regp1++;
+		}
+
+		for (i = 0; i < 2; i++) {
+			p2 = ao + 12 + i;    /* wm0 for y  */
+			*p2 = (regp2->paddr + regp2->info.y_off);
+
+			p2 = ao + 36 + i;  /* wm1 for cbcr */
+			*p2 = (regp2->paddr + regp2->info.cbcr_off);
+			regp2++;
+		}
+		for (i = 2; i < ad->bufnum1; i++) {
+			ret = vfe32_enqueue_free_buf(outp1, regp1->paddr,
+						regp1->info.y_off,
+						regp1->info.cbcr_off);
+			if (ret < 0)
+				return ret;
+			regp1++;
+		}
+		for (i = 2; i < ad->bufnum2; i++) {
+			ret = vfe32_enqueue_free_buf(outp2, regp2->paddr,
+						regp2->info.y_off,
+						regp2->info.cbcr_off);
+			if (ret < 0)
+				return ret;
+			regp2++;
+		}
+		break;
+	case CAMIF_TO_AXI_VIA_OUTPUT_2: {  /* use wm0 only */
+		if (ad->bufnum2 < 1)
+			return -EINVAL;
+		CDBG("config axi for raw snapshot.\n");
+		vfe32_ctrl->outpath.out1.ch0 = 0; /* raw */
+		regp1 = &(ad->region[ad->bufnum1]);
+		vfe32_ctrl->outpath.output_mode |= VFE32_OUTPUT_MODE_S;
+		p1 = ao + 6;    /* wm0 for y  */
+		*p1 = (regp1->paddr + regp1->info.y_off);
+		}
+		break;
+	default:
+		break;
+	}
+	msm_io_memcpy(vfe32_ctrl->vfebase + vfe32_cmd[V32_AXI_OUT_CFG].offset,
+		ao, vfe32_cmd[V32_AXI_OUT_CFG].length - V32_AXI_CH_INF_LEN);
+	return 0;
+}
+
+static void vfe32_reset_internal_variables(void)
+{
+	unsigned long flags;
+	vfe32_ctrl->vfeImaskCompositePacked = 0;
+	/* state control variables */
+	vfe32_ctrl->start_ack_pending = FALSE;
+	atomic_set(&irq_cnt, 0);
+
+	spin_lock_irqsave(&vfe32_ctrl->stop_flag_lock, flags);
+	vfe32_ctrl->stop_ack_pending  = FALSE;
+	spin_unlock_irqrestore(&vfe32_ctrl->stop_flag_lock, flags);
+
+	vfe32_ctrl->reset_ack_pending  = FALSE;
+
+	spin_lock_irqsave(&vfe32_ctrl->update_ack_lock, flags);
+	vfe32_ctrl->update_ack_pending = FALSE;
+	spin_unlock_irqrestore(&vfe32_ctrl->update_ack_lock, flags);
+
+	vfe32_ctrl->req_stop_video_rec = FALSE;
+	vfe32_ctrl->req_start_video_rec = FALSE;
+
+	atomic_set(&vfe32_ctrl->vstate, 0);
+
+	/* 0 for continuous mode, 1 for snapshot mode */
+	vfe32_ctrl->operation_mode = 0;
+	vfe32_ctrl->outpath.output_mode = 0;
+	vfe32_ctrl->vfe_capture_count = 0;
+
+	/* this is unsigned 32 bit integer. */
+	vfe32_ctrl->vfeFrameId = 0;
+	/* Stats control variables. */
+	memset(&(vfe32_ctrl->afStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe32_ctrl->awbStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe32_ctrl->aecStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe32_ctrl->ihistStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe32_ctrl->rsStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe32_ctrl->csStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+}
+
+static void vfe32_reset(void)
+{
+	uint32_t vfe_version;
+	vfe32_reset_free_buf_queues();
+	vfe32_reset_internal_variables();
+	vfe_version = msm_io_r(vfe32_ctrl->vfebase);
+	CDBG("vfe_version = 0x%x\n", vfe_version);
+	/* disable all interrupts.  vfeImaskLocal is also reset to 0
+	* to begin with. */
+	msm_io_w(VFE_DISABLE_ALL_IRQS,
+		vfe32_ctrl->vfebase + VFE_IRQ_MASK_0);
+
+	msm_io_w(VFE_DISABLE_ALL_IRQS,
+		vfe32_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+	/* clear all pending interrupts*/
+	msm_io_w(VFE_CLEAR_ALL_IRQS, vfe32_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+	msm_io_w(VFE_CLEAR_ALL_IRQS, vfe32_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_IRQ_CMD);
+
+	/* enable reset_ack interrupt.  */
+	msm_io_w(VFE_IMASK_WHILE_STOPPING_1,
+	vfe32_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+	/* Write to VFE_GLOBAL_RESET_CMD to reset the vfe hardware. Once reset
+	 * is done, hardware interrupt will be generated.  VFE ist processes
+	 * the interrupt to complete the function call.  Note that the reset
+	 * function is synchronous. */
+
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_io_w_mb(VFE_RESET_UPON_RESET_CMD,
+		vfe32_ctrl->vfebase + VFE_GLOBAL_RESET);
+}
+
+static int vfe32_operation_config(uint32_t *cmd)
+{
+	uint32_t *p = cmd;
+
+	vfe32_ctrl->operation_mode = *p;
+	vfe32_ctrl->stats_comp = *(++p);
+
+	msm_io_w(*(++p), vfe32_ctrl->vfebase + VFE_CFG);
+	msm_io_w(*(++p), vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+	msm_io_w(*(++p), vfe32_ctrl->vfebase + VFE_PIXEL_IF_CFG);
+	msm_io_w(*(++p), vfe32_ctrl->vfebase + VFE_REALIGN_BUF);
+	msm_io_w(*(++p), vfe32_ctrl->vfebase + VFE_CHROMA_UP);
+	msm_io_w(*(++p), vfe32_ctrl->vfebase + VFE_STATS_CFG);
+	return 0;
+}
+
+static uint32_t vfe_stats_awb_buf_init(struct vfe_cmd_stats_buf *in)
+{
+	uint32_t *ptr = in->statsBuf;
+	uint32_t addr;
+
+	addr = ptr[0];
+	msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+	addr = ptr[1];
+	msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+	vfe32_ctrl->awbStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+	return 0;
+}
+
+static uint32_t vfe_stats_aec_buf_init(struct vfe_cmd_stats_buf *in)
+{
+	uint32_t *ptr = in->statsBuf;
+	uint32_t addr;
+
+	addr = ptr[0];
+	msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_AEC_WR_PING_ADDR);
+	addr = ptr[1];
+	msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_AEC_WR_PONG_ADDR);
+
+	vfe32_ctrl->aecStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+	return 0;
+}
+
+static uint32_t vfe_stats_af_buf_init(struct vfe_cmd_stats_buf *in)
+{
+	uint32_t *ptr = in->statsBuf;
+	uint32_t addr;
+
+	addr = ptr[0];
+	msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+	addr = ptr[1];
+	msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+
+	vfe32_ctrl->afStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+	return 0;
+}
+
+static uint32_t vfe_stats_ihist_buf_init(struct vfe_cmd_stats_buf *in)
+{
+	uint32_t *ptr = in->statsBuf;
+	uint32_t addr;
+
+	addr = ptr[0];
+	msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PING_ADDR);
+	addr = ptr[1];
+	msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PONG_ADDR);
+
+	vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+	return 0;
+}
+
+static uint32_t vfe_stats_rs_buf_init(struct vfe_cmd_stats_buf *in)
+{
+	uint32_t *ptr = in->statsBuf;
+	uint32_t addr;
+
+	addr = ptr[0];
+	msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PING_ADDR);
+	addr = ptr[1];
+	msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PONG_ADDR);
+
+	vfe32_ctrl->rsStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+	return 0;
+}
+
+static uint32_t vfe_stats_cs_buf_init(struct vfe_cmd_stats_buf *in)
+{
+	uint32_t *ptr = in->statsBuf;
+	uint32_t addr;
+
+	addr = ptr[0];
+	msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PING_ADDR);
+	addr = ptr[1];
+	msm_io_w(addr, vfe32_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PONG_ADDR);
+
+	vfe32_ctrl->csStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+	return 0;
+}
+
+static void vfe32_start_common(void)
+{
+
+	vfe32_ctrl->start_ack_pending = TRUE;
+	CDBG("VFE opertaion mode = 0x%x, output mode = 0x%x\n",
+		vfe32_ctrl->operation_mode, vfe32_ctrl->outpath.output_mode);
+	msm_io_w(0x00EFE021, vfe32_ctrl->vfebase + VFE_IRQ_MASK_0);
+	msm_io_w(VFE_IMASK_WHILE_STOPPING_1,
+		vfe32_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+	msm_io_dump(vfe32_ctrl->vfebase, 0x740);
+
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+	msm_io_w(1, vfe32_ctrl->vfebase + VFE_CAMIF_COMMAND);
+	wmb();
+
+	atomic_set(&vfe32_ctrl->vstate, 1);
+}
+
+static int vfe32_start_recording(void)
+{
+	vfe32_ctrl->req_start_video_rec = TRUE;
+	/* Mask with 0x7 to extract the pixel pattern*/
+	switch (msm_io_r(vfe32_ctrl->vfebase + VFE_CFG) & 0x7) {
+	case VFE_YUV_YCbYCr:
+	case VFE_YUV_YCrYCb:
+	case VFE_YUV_CbYCrY:
+	case VFE_YUV_CrYCbY:
+		msm_io_w_mb(1,
+		vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int vfe32_stop_recording(void)
+{
+	vfe32_ctrl->req_stop_video_rec = TRUE;
+	/* Mask with 0x7 to extract the pixel pattern*/
+	switch (msm_io_r(vfe32_ctrl->vfebase + VFE_CFG) & 0x7) {
+	case VFE_YUV_YCbYCr:
+	case VFE_YUV_YCrYCb:
+	case VFE_YUV_CbYCrY:
+	case VFE_YUV_CrYCbY:
+		msm_io_w_mb(1,
+		vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static void vfe32_liveshot(void){
+	struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata;
+	if (p_sync)
+		p_sync->liveshot_enabled = true;
+}
+
+static int vfe32_capture(uint32_t num_frames_capture)
+{
+	uint32_t irq_comp_mask = 0;
+	struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata;
+	if (p_sync) {
+		p_sync->snap_count = num_frames_capture;
+		p_sync->thumb_count = num_frames_capture;
+	}
+	/* capture command is valid for both idle and active state. */
+	vfe32_ctrl->outpath.out1.capture_cnt = num_frames_capture;
+	if (vfe32_ctrl->operation_mode == VFE_MODE_OF_OPERATION_SNAPSHOT) {
+		vfe32_ctrl->outpath.out0.capture_cnt =
+		num_frames_capture;
+	}
+
+	vfe32_ctrl->vfe_capture_count = num_frames_capture;
+	irq_comp_mask	=
+		msm_io_r(vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+	if (vfe32_ctrl->operation_mode == VFE_MODE_OF_OPERATION_SNAPSHOT) {
+		if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_PT) {
+			irq_comp_mask |= (0x1 << vfe32_ctrl->outpath.out0.ch0 |
+					0x1 << vfe32_ctrl->outpath.out0.ch1);
+		}
+		if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_S) {
+			irq_comp_mask |=
+			(0x1 << (vfe32_ctrl->outpath.out1.ch0 + 8) |
+			0x1 << (vfe32_ctrl->outpath.out1.ch1 + 8));
+		}
+		if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_PT) {
+			msm_io_w(1, vfe32_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch0]);
+			msm_io_w(1, vfe32_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch1]);
+		}
+		if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_S) {
+			msm_io_w(1, vfe32_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch0]);
+			msm_io_w(1, vfe32_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch1]);
+		}
+	} else {  /* this is raw snapshot mode. */
+		if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_S) {
+			irq_comp_mask |=
+			(0x1 << (vfe32_ctrl->outpath.out1.ch0 + 8));
+			msm_io_w(1, vfe32_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch0]);
+			msm_io_w(0x1000, vfe32_ctrl->vfebase +
+					VFE_BUS_IO_FORMAT_CFG);
+		}
+	}
+	msm_io_w(irq_comp_mask, vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+	msm_io_r(vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+	vfe32_start_common();
+	msm_io_r(vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+	/* for debug */
+	msm_io_w(1, vfe32_ctrl->vfebase + 0x18C);
+	msm_io_w(1, vfe32_ctrl->vfebase + 0x188);
+	return 0;
+}
+
+static int vfe32_start(void)
+{
+	uint32_t irq_comp_mask = 0;
+	/* start command now is only good for continuous mode. */
+	if ((vfe32_ctrl->operation_mode != VFE_MODE_OF_OPERATION_CONTINUOUS) &&
+		(vfe32_ctrl->operation_mode != VFE_MODE_OF_OPERATION_VIDEO))
+		return 0;
+	irq_comp_mask	=
+		msm_io_r(vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+	if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_PT) {
+		irq_comp_mask |= (0x1 << vfe32_ctrl->outpath.out0.ch0 |
+			0x1 << vfe32_ctrl->outpath.out0.ch1);
+	}
+
+	if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_V) {
+		irq_comp_mask |= (0x1 << (vfe32_ctrl->outpath.out2.ch0 + 16)|
+			0x1 << (vfe32_ctrl->outpath.out2.ch1 + 16));
+	}
+
+	msm_io_w(irq_comp_mask, vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+	if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_PT) {
+		msm_io_w(1, vfe32_ctrl->vfebase +
+			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch0]);
+		msm_io_w(1, vfe32_ctrl->vfebase +
+			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch1]);
+	}
+	vfe32_start_common();
+	return 0;
+}
+
+static void vfe32_update(void)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&vfe32_ctrl->update_ack_lock, flags);
+	vfe32_ctrl->update_ack_pending = TRUE;
+	spin_unlock_irqrestore(&vfe32_ctrl->update_ack_lock, flags);
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+	return;
+}
+
+static void vfe32_sync_timer_stop(void)
+{
+	uint32_t value = 0;
+	vfe32_ctrl->sync_timer_state = 0;
+	if (vfe32_ctrl->sync_timer_number == 0)
+		value = 0x10000;
+	else if (vfe32_ctrl->sync_timer_number == 1)
+		value = 0x20000;
+	else if (vfe32_ctrl->sync_timer_number == 2)
+		value = 0x40000;
+
+	/* Timer Stop */
+	msm_io_w(value, vfe32_ctrl->vfebase + V32_SYNC_TIMER_OFF);
+}
+
+static void vfe32_sync_timer_start(const uint32_t *tbl)
+{
+	/* set bit 8 for auto increment. */
+	uint32_t value = 1;
+	uint32_t val;
+
+	vfe32_ctrl->sync_timer_state = *tbl++;
+	vfe32_ctrl->sync_timer_repeat_count = *tbl++;
+	vfe32_ctrl->sync_timer_number = *tbl++;
+	CDBG("%s timer_state %d, repeat_cnt %d timer number %d\n",
+		 __func__, vfe32_ctrl->sync_timer_state,
+		 vfe32_ctrl->sync_timer_repeat_count,
+		 vfe32_ctrl->sync_timer_number);
+
+	if (vfe32_ctrl->sync_timer_state) { /* Start Timer */
+		value = value << vfe32_ctrl->sync_timer_number;
+	} else { /* Stop Timer */
+		CDBG("Failed to Start timer\n");
+		return;
+	}
+
+	/* Timer Start */
+	msm_io_w(value, vfe32_ctrl->vfebase + V32_SYNC_TIMER_OFF);
+	/* Sync Timer Line Start */
+	value = *tbl++;
+	msm_io_w(value, vfe32_ctrl->vfebase + V32_SYNC_TIMER_OFF +
+		4 + ((vfe32_ctrl->sync_timer_number) * 12));
+	/* Sync Timer Pixel Start */
+	value = *tbl++;
+	msm_io_w(value, vfe32_ctrl->vfebase + V32_SYNC_TIMER_OFF +
+			 8 + ((vfe32_ctrl->sync_timer_number) * 12));
+	/* Sync Timer Pixel Duration */
+	value = *tbl++;
+	val = camio_clk.vfe_clk_rate / 10000;
+	val = 10000000 / val;
+	val = value * 10000 / val;
+	CDBG("%s: Pixel Clk Cycles!!! %d\n", __func__, val);
+	msm_io_w(val, vfe32_ctrl->vfebase + V32_SYNC_TIMER_OFF +
+		12 + ((vfe32_ctrl->sync_timer_number) * 12));
+	/* Timer0 Active High/LOW */
+	value = *tbl++;
+	msm_io_w(value, vfe32_ctrl->vfebase + V32_SYNC_TIMER_POLARITY_OFF);
+	/* Selects sync timer 0 output to drive onto timer1 port */
+	value = 0;
+	msm_io_w(value, vfe32_ctrl->vfebase + V32_TIMER_SELECT_OFF);
+}
+
+static void vfe32_program_dmi_cfg(enum VFE32_DMI_RAM_SEL bankSel)
+{
+	/* set bit 8 for auto increment. */
+	uint32_t value = VFE_DMI_CFG_DEFAULT;
+	value += (uint32_t)bankSel;
+
+	msm_io_w(value, vfe32_ctrl->vfebase + VFE_DMI_CFG);
+	/* by default, always starts with offset 0.*/
+	msm_io_w(0, vfe32_ctrl->vfebase + VFE_DMI_ADDR);
+}
+static void vfe32_write_gamma_cfg(enum VFE32_DMI_RAM_SEL channel_sel,
+						const uint32_t *tbl)
+{
+	int i;
+	uint32_t value, value1, value2;
+	vfe32_program_dmi_cfg(channel_sel);
+	/* for loop for extracting init table. */
+	for (i = 0 ; i < (VFE32_GAMMA_NUM_ENTRIES/2) ; i++) {
+		value = *tbl++;
+		value1 = value & 0x0000FFFF;
+		value2 = (value & 0xFFFF0000)>>16;
+		msm_io_w((value1), vfe32_ctrl->vfebase + VFE_DMI_DATA_LO);
+		msm_io_w((value2), vfe32_ctrl->vfebase + VFE_DMI_DATA_LO);
+	}
+	vfe32_program_dmi_cfg(NO_MEM_SELECTED);
+}
+
+static void vfe32_write_la_cfg(enum VFE32_DMI_RAM_SEL channel_sel,
+						const uint32_t *tbl)
+{
+	uint32_t i;
+	uint32_t value, value1, value2;
+
+	vfe32_program_dmi_cfg(channel_sel);
+	/* for loop for extracting init table. */
+	for (i = 0 ; i < (VFE32_LA_TABLE_LENGTH/2) ; i++) {
+		value = *tbl++;
+		value1 = value & 0x0000FFFF;
+		value2 = (value & 0xFFFF0000)>>16;
+		msm_io_w((value1), vfe32_ctrl->vfebase + VFE_DMI_DATA_LO);
+		msm_io_w((value2), vfe32_ctrl->vfebase + VFE_DMI_DATA_LO);
+	}
+	vfe32_program_dmi_cfg(NO_MEM_SELECTED);
+}
+
+
+static int vfe32_proc_general(struct msm_vfe32_cmd *cmd)
+{
+	int i , rc = 0;
+	uint32_t old_val = 0 , new_val = 0;
+	uint32_t *cmdp = NULL;
+	uint32_t *cmdp_local = NULL;
+	uint32_t snapshot_cnt = 0;
+
+	CDBG("vfe32_proc_general: cmdID = %s, length = %d\n",
+		vfe32_general_cmd[cmd->id], cmd->length);
+	switch (cmd->id) {
+	case V32_RESET:
+		pr_info("vfe32_proc_general: cmdID = %s\n",
+			vfe32_general_cmd[cmd->id]);
+		vfe32_reset();
+		break;
+	case V32_START:
+		pr_info("vfe32_proc_general: cmdID = %s\n",
+			vfe32_general_cmd[cmd->id]);
+		rc = vfe32_start();
+		break;
+	case V32_UPDATE:
+		vfe32_update();
+		break;
+	case V32_CAPTURE:
+		pr_info("vfe32_proc_general: cmdID = %s\n",
+			vfe32_general_cmd[cmd->id]);
+		if (copy_from_user(&snapshot_cnt, (void __user *)(cmd->value),
+				sizeof(uint32_t))) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		rc = vfe32_capture(snapshot_cnt);
+		break;
+	case V32_START_RECORDING:
+		pr_info("vfe32_proc_general: cmdID = %s\n",
+			vfe32_general_cmd[cmd->id]);
+		rc = vfe32_start_recording();
+		break;
+	case V32_STOP_RECORDING:
+		pr_info("vfe32_proc_general: cmdID = %s\n",
+			vfe32_general_cmd[cmd->id]);
+		rc = vfe32_stop_recording();
+		break;
+	case V32_OPERATION_CFG: {
+		if (cmd->length != V32_OPERATION_CFG_LEN) {
+			rc = -EINVAL;
+			goto proc_general_done;
+		}
+		cmdp = kmalloc(V32_OPERATION_CFG_LEN, GFP_ATOMIC);
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			V32_OPERATION_CFG_LEN)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		rc = vfe32_operation_config(cmdp);
+		}
+		break;
+
+	case V32_STATS_AE_START: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val |= AE_BG_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		msm_io_memcpy(vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+		cmdp, (vfe32_cmd[cmd->id].length));
+		}
+		break;
+	case V32_STATS_AF_START: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val |= AF_BF_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		msm_io_memcpy(vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+		cmdp, (vfe32_cmd[cmd->id].length));
+		}
+		break;
+	case V32_STATS_AWB_START: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val |= AWB_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		msm_io_memcpy(vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+				cmdp, (vfe32_cmd[cmd->id].length));
+		}
+		break;
+
+	case V32_STATS_IHIST_START: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val |= IHIST_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		msm_io_memcpy(vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+				cmdp, (vfe32_cmd[cmd->id].length));
+		}
+		break;
+
+
+	case V32_STATS_RS_START: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		/*
+		old_val = msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val |= RS_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		*/
+		msm_io_memcpy(vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+				cmdp, (vfe32_cmd[cmd->id].length));
+		}
+		break;
+
+	case V32_STATS_CS_START: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		/*
+		old_val = msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val |= CS_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		*/
+		msm_io_memcpy(vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+				cmdp, (vfe32_cmd[cmd->id].length));
+		}
+		break;
+
+	case V32_MCE_UPDATE:
+	case V32_MCE_CFG:{
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		/* Incrementing with 4 so as to point to the 2nd Register as
+		the 2nd register has the mce_enable bit */
+		old_val = msm_io_r(vfe32_ctrl->vfebase + V32_CHROMA_EN_OFF + 4);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		new_val = *cmdp_local;
+		old_val &= MCE_EN_MASK;
+		new_val = new_val | old_val;
+		msm_io_memcpy(vfe32_ctrl->vfebase + V32_CHROMA_EN_OFF + 4,
+					&new_val, 4);
+		cmdp_local += 1;
+
+		old_val = msm_io_r(vfe32_ctrl->vfebase + V32_CHROMA_EN_OFF + 8);
+		new_val = *cmdp_local;
+		old_val &= MCE_Q_K_MASK;
+		new_val = new_val | old_val;
+		msm_io_memcpy(vfe32_ctrl->vfebase + V32_CHROMA_EN_OFF + 8,
+		&new_val, 4);
+		cmdp_local += 1;
+		msm_io_memcpy(vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+		cmdp_local, (vfe32_cmd[cmd->id].length));
+		}
+		break;
+	case V32_BLACK_LEVEL_CFG:
+		rc = -EFAULT;
+		goto proc_general_done;
+	case V32_ROLL_OFF_CFG: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value) , cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		msm_io_memcpy(vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+		cmdp_local, 16);
+		cmdp_local += 4;
+		vfe32_program_dmi_cfg(ROLLOFF_RAM);
+		/* for loop for extrcting init table. */
+		for (i = 0 ; i < (VFE32_ROLL_OFF_INIT_TABLE_SIZE * 2) ; i++) {
+			msm_io_w(*cmdp_local ,
+			vfe32_ctrl->vfebase + VFE_DMI_DATA_LO);
+			cmdp_local++;
+		}
+		CDBG("done writing init table\n");
+		/* by default, always starts with offset 0. */
+		msm_io_w(LENS_ROLL_OFF_DELTA_TABLE_OFFSET,
+		vfe32_ctrl->vfebase + VFE_DMI_ADDR);
+		/* for loop for extracting delta table. */
+		for (i = 0 ; i < (VFE32_ROLL_OFF_DELTA_TABLE_SIZE * 2) ; i++) {
+			msm_io_w(*cmdp_local,
+			vfe32_ctrl->vfebase + VFE_DMI_DATA_LO);
+			cmdp_local++;
+		}
+		vfe32_program_dmi_cfg(NO_MEM_SELECTED);
+		}
+		break;
+
+	case V32_LA_CFG:
+	case V32_LA_UPDATE: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		msm_io_memcpy(vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+				cmdp, (vfe32_cmd[cmd->id].length));
+
+		old_val = *cmdp;
+		cmdp += 1;
+		if (old_val == 0x0)
+			vfe32_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK0 , cmdp);
+		else
+			vfe32_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK1 , cmdp);
+		cmdp -= 1;
+		}
+		break;
+
+	case V32_SK_ENHAN_CFG:
+	case V32_SK_ENHAN_UPDATE:{
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		msm_io_memcpy(vfe32_ctrl->vfebase + V32_SCE_OFF,
+				cmdp, V32_SCE_LEN);
+		}
+		break;
+
+	case V32_LIVESHOT:
+		vfe32_liveshot();
+		break;
+
+	case V32_LINEARIZATION:
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		msm_io_memcpy(vfe32_ctrl->vfebase + V32_LINEARIZATION_OFF1,
+				cmdp_local, V32_LINEARIZATION_LEN1);
+		cmdp_local += 4;
+		msm_io_memcpy(vfe32_ctrl->vfebase + V32_LINEARIZATION_OFF2,
+						cmdp_local,
+						V32_LINEARIZATION_LEN2);
+		break;
+
+	case V32_DEMOSAICV3:
+		if (cmd->length !=
+			V32_DEMOSAICV3_0_LEN+V32_DEMOSAICV3_1_LEN) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+
+		msm_io_memcpy(vfe32_ctrl->vfebase + V32_DEMOSAICV3_0_OFF,
+			cmdp_local, V32_DEMOSAICV3_0_LEN);
+		cmdp_local += 1;
+		msm_io_memcpy(vfe32_ctrl->vfebase + V32_DEMOSAICV3_1_OFF,
+			cmdp_local, V32_DEMOSAICV3_1_LEN);
+		break;
+
+	case V32_DEMOSAICV3_ABCC_CFG:
+		rc = -EFAULT;
+		break;
+
+	case V32_DEMOSAICV3_DBCC_CFG:
+	case V32_DEMOSAICV3_DBCC_UPDATE:
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		new_val = *cmdp_local;
+
+		old_val = msm_io_r(vfe32_ctrl->vfebase + V32_DEMOSAICV3_0_OFF);
+		old_val &= DBCC_MASK;
+
+		new_val = new_val | old_val;
+		*cmdp_local = new_val;
+		msm_io_memcpy(vfe32_ctrl->vfebase + V32_DEMOSAICV3_0_OFF,
+					cmdp_local, 4);
+		cmdp_local += 1;
+		msm_io_memcpy(vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+			cmdp_local, (vfe32_cmd[cmd->id].length));
+		break;
+
+	case V32_DEMOSAICV3_DBPC_CFG:
+	case V32_DEMOSAICV3_DBPC_UPDATE:
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		new_val = *cmdp_local;
+
+		old_val = msm_io_r(vfe32_ctrl->vfebase + V32_DEMOSAICV3_0_OFF);
+		old_val &= DBPC_MASK;
+
+		new_val = new_val | old_val;
+		*cmdp_local = new_val;
+		msm_io_memcpy(vfe32_ctrl->vfebase +
+			V32_DEMOSAICV3_0_OFF,
+			cmdp_local, V32_DEMOSAICV3_LEN);
+		cmdp_local += 1;
+		msm_io_memcpy(vfe32_ctrl->vfebase +
+			V32_DEMOSAICV3_DBPC_CFG_OFF,
+			cmdp_local, V32_DEMOSAICV3_DBPC_LEN);
+		cmdp_local += 1;
+		msm_io_memcpy(vfe32_ctrl->vfebase +
+			V32_DEMOSAICV3_DBPC_CFG_OFF0,
+			cmdp_local, V32_DEMOSAICV3_DBPC_LEN);
+		cmdp_local += 1;
+		msm_io_memcpy(vfe32_ctrl->vfebase +
+			V32_DEMOSAICV3_DBPC_CFG_OFF1,
+			cmdp_local, V32_DEMOSAICV3_DBPC_LEN);
+		cmdp_local += 1;
+		msm_io_memcpy(vfe32_ctrl->vfebase +
+			V32_DEMOSAICV3_DBPC_CFG_OFF2,
+			cmdp_local, V32_DEMOSAICV3_DBPC_LEN);
+		break;
+
+	case V32_RGB_G_CFG: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		msm_io_memcpy(vfe32_ctrl->vfebase + V32_RGB_G_OFF,
+				cmdp, 4);
+		cmdp += 1;
+		vfe32_write_gamma_cfg(RGBLUT_RAM_CH0_BANK0 , cmdp);
+		vfe32_write_gamma_cfg(RGBLUT_RAM_CH1_BANK0 , cmdp);
+		vfe32_write_gamma_cfg(RGBLUT_RAM_CH2_BANK0 , cmdp);
+		cmdp -= 1;
+		}
+		break;
+
+	case V32_RGB_G_UPDATE: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp, (void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+
+		msm_io_memcpy(vfe32_ctrl->vfebase + V32_RGB_G_OFF, cmdp, 4);
+		old_val = *cmdp;
+		cmdp += 1;
+
+		if (old_val) {
+			vfe32_write_gamma_cfg(RGBLUT_RAM_CH0_BANK1 , cmdp);
+			vfe32_write_gamma_cfg(RGBLUT_RAM_CH1_BANK1 , cmdp);
+			vfe32_write_gamma_cfg(RGBLUT_RAM_CH2_BANK1 , cmdp);
+		} else {
+			vfe32_write_gamma_cfg(RGBLUT_RAM_CH0_BANK0 , cmdp);
+			vfe32_write_gamma_cfg(RGBLUT_RAM_CH1_BANK0 , cmdp);
+			vfe32_write_gamma_cfg(RGBLUT_RAM_CH2_BANK0 , cmdp);
+		}
+		cmdp -= 1;
+		}
+		break;
+
+	case V32_STATS_AWB_STOP: {
+		old_val = msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= ~AWB_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		}
+		break;
+	case V32_STATS_AE_STOP: {
+		old_val = msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= ~AE_BG_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		}
+		break;
+	case V32_STATS_AF_STOP: {
+		old_val = msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= ~AF_BF_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		}
+		break;
+
+	case V32_STATS_IHIST_STOP: {
+		old_val = msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= ~IHIST_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		}
+		break;
+
+	case V32_STATS_RS_STOP: {
+		old_val = msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= ~RS_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		}
+		break;
+
+	case V32_STATS_CS_STOP: {
+		old_val = msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= ~CS_ENABLE_MASK;
+		msm_io_w(old_val,
+			vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		}
+		break;
+	case V32_STOP:
+		pr_info("vfe32_proc_general: cmdID = %s\n",
+			vfe32_general_cmd[cmd->id]);
+		vfe32_stop();
+		break;
+
+	case V32_SYNC_TIMER_SETTING:
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp, (void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		vfe32_sync_timer_start(cmdp);
+		break;
+
+	case V32_EZTUNE_CFG: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		*cmdp &= ~STATS_ENABLE_MASK;
+		old_val = msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= STATS_ENABLE_MASK;
+		*cmdp |= old_val;
+
+		msm_io_memcpy(vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+			cmdp, (vfe32_cmd[cmd->id].length));
+		}
+		break;
+
+	default: {
+		if (cmd->length != vfe32_cmd[cmd->id].length)
+			return -EINVAL;
+
+		cmdp = kmalloc(vfe32_cmd[cmd->id].length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+
+		CHECKED_COPY_FROM_USER(cmdp);
+		msm_io_memcpy(vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+			cmdp, (vfe32_cmd[cmd->id].length));
+	}
+	break;
+
+	}
+
+proc_general_done:
+	kfree(cmdp);
+
+	return rc;
+}
+
+static void vfe32_stats_af_ack(struct vfe_cmd_stats_ack *pAck)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&vfe32_ctrl->af_ack_lock, flags);
+	vfe32_ctrl->afStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+	vfe32_ctrl->afStatsControl.ackPending = FALSE;
+	spin_unlock_irqrestore(&vfe32_ctrl->af_ack_lock, flags);
+}
+
+static void vfe32_stats_awb_ack(struct vfe_cmd_stats_ack *pAck)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&vfe32_ctrl->awb_ack_lock, flags);
+	vfe32_ctrl->awbStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+	vfe32_ctrl->awbStatsControl.ackPending = FALSE;
+	spin_unlock_irqrestore(&vfe32_ctrl->awb_ack_lock, flags);
+}
+
+static void vfe32_stats_aec_ack(struct vfe_cmd_stats_ack *pAck)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&vfe32_ctrl->aec_ack_lock, flags);
+	vfe32_ctrl->aecStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+	vfe32_ctrl->aecStatsControl.ackPending = FALSE;
+	spin_unlock_irqrestore(&vfe32_ctrl->aec_ack_lock, flags);
+}
+
+static void vfe32_stats_ihist_ack(struct vfe_cmd_stats_ack *pAck)
+{
+	vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+	vfe32_ctrl->ihistStatsControl.ackPending = FALSE;
+}
+static void vfe32_stats_rs_ack(struct vfe_cmd_stats_ack *pAck)
+{
+	vfe32_ctrl->rsStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+	vfe32_ctrl->rsStatsControl.ackPending = FALSE;
+}
+static void vfe32_stats_cs_ack(struct vfe_cmd_stats_ack *pAck)
+{
+	vfe32_ctrl->csStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+	vfe32_ctrl->csStatsControl.ackPending = FALSE;
+}
+
+
+static inline void vfe32_read_irq_status(struct vfe32_irq_status *out)
+{
+	uint32_t *temp;
+	memset(out, 0, sizeof(struct vfe32_irq_status));
+	temp = (uint32_t *)(vfe32_ctrl->vfebase + VFE_IRQ_STATUS_0);
+	out->vfeIrqStatus0 = msm_io_r(temp);
+
+	temp = (uint32_t *)(vfe32_ctrl->vfebase + VFE_IRQ_STATUS_1);
+	out->vfeIrqStatus1 = msm_io_r(temp);
+
+	temp = (uint32_t *)(vfe32_ctrl->vfebase + VFE_CAMIF_STATUS);
+	out->camifStatus = msm_io_r(temp);
+	CDBG("camifStatus  = 0x%x\n", out->camifStatus);
+
+	/* clear the pending interrupt of the same kind.*/
+	msm_io_w(out->vfeIrqStatus0, vfe32_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+	msm_io_w(out->vfeIrqStatus1, vfe32_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_IRQ_CMD);
+
+}
+
+static void vfe32_send_msg_no_payload(enum VFE32_MESSAGE_ID id)
+{
+	struct vfe_message msg;
+
+	CDBG("vfe32_send_msg_no_payload\n");
+	msg._d = id;
+	vfe32_proc_ops(id, &msg, 0);
+}
+
+static void vfe32_process_reg_update_irq(void)
+{
+	uint32_t  temp, old_val;
+	unsigned long flags;
+	if (vfe32_ctrl->req_start_video_rec) {
+		if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_V) {
+			msm_io_w(1, vfe32_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out2.ch0]);
+			msm_io_w(1, vfe32_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out2.ch1]);
+			/* Mask with 0x7 to extract the pixel pattern*/
+			switch (msm_io_r(vfe32_ctrl->vfebase + VFE_CFG)
+				& 0x7) {
+			case VFE_YUV_YCbYCr:
+			case VFE_YUV_YCrYCb:
+			case VFE_YUV_CbYCrY:
+			case VFE_YUV_CrYCbY:
+				msm_io_w_mb(1,
+				vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+				break;
+			default:
+				break;
+			}
+		}
+		vfe32_ctrl->req_start_video_rec =  FALSE;
+		if (vpe_ctrl && vpe_ctrl->dis_en) {
+			old_val = msm_io_r(
+				vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+			old_val |= RS_CS_ENABLE_MASK;
+			msm_io_w(old_val,
+				vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		}
+		CDBG("start video triggered .\n");
+	} else if (vfe32_ctrl->req_stop_video_rec) {
+		if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_V) {
+			msm_io_w(0, vfe32_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out2.ch0]);
+			msm_io_w(0, vfe32_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out2.ch1]);
+			/* Mask with 0x7 to extract the pixel pattern*/
+			switch (msm_io_r(vfe32_ctrl->vfebase + VFE_CFG)
+				& 0x7) {
+			case VFE_YUV_YCbYCr:
+			case VFE_YUV_YCrYCb:
+			case VFE_YUV_CbYCrY:
+			case VFE_YUV_CrYCbY:
+				msm_io_w_mb(1,
+				vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+				break;
+			default:
+				break;
+			}
+		}
+		vfe32_ctrl->req_stop_video_rec =  FALSE;
+		vfe32_send_msg_no_payload(MSG_ID_STOP_REC_ACK);
+
+		/*disable rs& cs when stop recording. */
+		old_val = msm_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= (~RS_CS_ENABLE_MASK);
+		msm_io_w(old_val, vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+
+		CDBG("stop video triggered .\n");
+	}
+	if (vfe32_ctrl->start_ack_pending == TRUE) {
+		vfe32_send_msg_no_payload(MSG_ID_START_ACK);
+		vfe32_ctrl->start_ack_pending = FALSE;
+	} else {
+		spin_lock_irqsave(&vfe32_ctrl->update_ack_lock, flags);
+		if (vfe32_ctrl->update_ack_pending == TRUE) {
+			vfe32_ctrl->update_ack_pending = FALSE;
+			spin_unlock_irqrestore(
+				&vfe32_ctrl->update_ack_lock, flags);
+			vfe32_send_msg_no_payload(MSG_ID_UPDATE_ACK);
+		} else {
+			spin_unlock_irqrestore(
+				&vfe32_ctrl->update_ack_lock, flags);
+		}
+	}
+	if (vfe32_ctrl->operation_mode ==
+		VFE_MODE_OF_OPERATION_SNAPSHOT) {  /* in snapshot mode */
+		/* later we need to add check for live snapshot mode. */
+		vfe32_ctrl->vfe_capture_count--;
+		/* if last frame to be captured: */
+		if (vfe32_ctrl->vfe_capture_count == 0) {
+			/* stop the bus output:  write master enable = 0*/
+			if (vfe32_ctrl->outpath.output_mode &
+					VFE32_OUTPUT_MODE_PT) {
+				msm_io_w(0, vfe32_ctrl->vfebase +
+					vfe32_AXI_WM_CFG[vfe32_ctrl->
+						outpath.out0.ch0]);
+				msm_io_w(0, vfe32_ctrl->vfebase +
+					vfe32_AXI_WM_CFG[vfe32_ctrl->
+						outpath.out0.ch1]);
+			}
+			if (vfe32_ctrl->outpath.output_mode &
+					VFE32_OUTPUT_MODE_S) {
+				msm_io_w(0, vfe32_ctrl->vfebase +
+					vfe32_AXI_WM_CFG[vfe32_ctrl->
+							outpath.out1.ch0]);
+				msm_io_w(0, vfe32_ctrl->vfebase +
+					vfe32_AXI_WM_CFG[vfe32_ctrl->
+							outpath.out1.ch1]);
+			}
+
+			/* Ensure the write order while writing
+			to the command register using the barrier */
+			msm_io_w_mb(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+				vfe32_ctrl->vfebase + VFE_CAMIF_COMMAND);
+
+			/* Ensure the read order while reading
+			to the command register using the barrier */
+			temp = msm_io_r_mb(vfe32_ctrl->vfebase +
+				VFE_CAMIF_COMMAND);
+			/* then do reg_update. */
+			msm_io_w(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+		}
+	} /* if snapshot mode. */
+}
+
+static void vfe32_set_default_reg_values(void)
+{
+	msm_io_w(0x800080, vfe32_ctrl->vfebase + VFE_DEMUX_GAIN_0);
+	msm_io_w(0x800080, vfe32_ctrl->vfebase + VFE_DEMUX_GAIN_1);
+	/* What value should we program CGC_OVERRIDE to? */
+	msm_io_w(0xFFFFF, vfe32_ctrl->vfebase + VFE_CGC_OVERRIDE);
+
+	/* default frame drop period and pattern */
+	msm_io_w(0x1f, vfe32_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG);
+	msm_io_w(0x1f, vfe32_ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_CFG);
+	msm_io_w(0xFFFFFFFF, vfe32_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN);
+	msm_io_w(0xFFFFFFFF,
+		vfe32_ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_PATTERN);
+	msm_io_w(0x1f, vfe32_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y);
+	msm_io_w(0x1f, vfe32_ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR);
+	msm_io_w(0xFFFFFFFF,
+		vfe32_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN);
+	msm_io_w(0xFFFFFFFF,
+		vfe32_ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR_PATTERN);
+	msm_io_w(0, vfe32_ctrl->vfebase + VFE_CLAMP_MIN);
+	msm_io_w(0xFFFFFF, vfe32_ctrl->vfebase + VFE_CLAMP_MAX);
+
+	/* stats UB config */
+	msm_io_w(0x3980007, vfe32_ctrl->vfebase + VFE_BUS_STATS_AEC_UB_CFG);
+	msm_io_w(0x3A00007, vfe32_ctrl->vfebase + VFE_BUS_STATS_AF_UB_CFG);
+	msm_io_w(0x3A8000F, vfe32_ctrl->vfebase + VFE_BUS_STATS_AWB_UB_CFG);
+	msm_io_w(0x3B80007, vfe32_ctrl->vfebase + VFE_BUS_STATS_RS_UB_CFG);
+	msm_io_w(0x3C0001F, vfe32_ctrl->vfebase + VFE_BUS_STATS_CS_UB_CFG);
+	msm_io_w(0x3E0001F, vfe32_ctrl->vfebase + VFE_BUS_STATS_HIST_UB_CFG);
+}
+
+static void vfe32_process_reset_irq(void)
+{
+	unsigned long flags;
+
+	atomic_set(&vfe32_ctrl->vstate, 0);
+
+	spin_lock_irqsave(&vfe32_ctrl->stop_flag_lock, flags);
+	if (vfe32_ctrl->stop_ack_pending) {
+		vfe32_ctrl->stop_ack_pending = FALSE;
+		spin_unlock_irqrestore(&vfe32_ctrl->stop_flag_lock, flags);
+		vfe32_send_msg_no_payload(MSG_ID_STOP_ACK);
+	} else {
+		spin_unlock_irqrestore(&vfe32_ctrl->stop_flag_lock, flags);
+		/* this is from reset command. */
+		vfe32_set_default_reg_values();
+
+		/* reload all write masters. (frame & line)*/
+		msm_io_w(0x7FFF, vfe32_ctrl->vfebase + VFE_BUS_CMD);
+		vfe32_send_msg_no_payload(MSG_ID_RESET_ACK);
+	}
+}
+
+static void vfe32_process_camif_sof_irq(void)
+{
+	uint32_t  temp;
+
+	/* in raw snapshot mode */
+	if (vfe32_ctrl->operation_mode ==
+		VFE_MODE_OF_OPERATION_RAW_SNAPSHOT) {
+		if (vfe32_ctrl->start_ack_pending) {
+			vfe32_send_msg_no_payload(MSG_ID_START_ACK);
+			vfe32_ctrl->start_ack_pending = FALSE;
+		}
+		vfe32_ctrl->vfe_capture_count--;
+		/* if last frame to be captured: */
+		if (vfe32_ctrl->vfe_capture_count == 0) {
+			/* Ensure the write order while writing
+			to the command register using the barrier */
+			msm_io_w_mb(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+				vfe32_ctrl->vfebase + VFE_CAMIF_COMMAND);
+			temp = msm_io_r_mb(vfe32_ctrl->vfebase +
+				VFE_CAMIF_COMMAND);
+		}
+	} /* if raw snapshot mode. */
+	vfe32_send_msg_no_payload(MSG_ID_SOF_ACK);
+	vfe32_ctrl->vfeFrameId++;
+	CDBG("camif_sof_irq, frameId = %d\n", vfe32_ctrl->vfeFrameId);
+
+	if (vfe32_ctrl->sync_timer_state) {
+		if (vfe32_ctrl->sync_timer_repeat_count == 0)
+			vfe32_sync_timer_stop();
+		else
+			vfe32_ctrl->sync_timer_repeat_count--;
+	}
+}
+
+static void vfe32_process_error_irq(uint32_t errStatus)
+{
+	uint32_t camifStatus;
+	uint32_t *temp;
+
+	if (errStatus & VFE32_IMASK_CAMIF_ERROR) {
+		pr_err("vfe32_irq: camif errors\n");
+		temp = (uint32_t *)(vfe32_ctrl->vfebase + VFE_CAMIF_STATUS);
+		camifStatus = msm_io_r(temp);
+		pr_err("camifStatus  = 0x%x\n", camifStatus);
+		vfe32_send_msg_no_payload(MSG_ID_CAMIF_ERROR);
+	}
+
+	if (errStatus & VFE32_IMASK_BHIST_OVWR)
+		pr_err("vfe32_irq: stats bhist overwrite\n");
+
+	if (errStatus & VFE32_IMASK_STATS_CS_OVWR)
+		pr_err("vfe32_irq: stats cs overwrite\n");
+
+	if (errStatus & VFE32_IMASK_STATS_IHIST_OVWR)
+		pr_err("vfe32_irq: stats ihist overwrite\n");
+
+	if (errStatus & VFE32_IMASK_REALIGN_BUF_Y_OVFL)
+		pr_err("vfe32_irq: realign bug Y overflow\n");
+
+	if (errStatus & VFE32_IMASK_REALIGN_BUF_CB_OVFL)
+		pr_err("vfe32_irq: realign bug CB overflow\n");
+
+	if (errStatus & VFE32_IMASK_REALIGN_BUF_CR_OVFL)
+		pr_err("vfe32_irq: realign bug CR overflow\n");
+
+	if (errStatus & VFE32_IMASK_VIOLATION)
+		pr_err("vfe32_irq: violation interrupt\n");
+
+	if (errStatus & VFE32_IMASK_IMG_MAST_0_BUS_OVFL)
+		pr_err("vfe32_irq: image master 0 bus overflow\n");
+
+	if (errStatus & VFE32_IMASK_IMG_MAST_1_BUS_OVFL)
+		pr_err("vfe32_irq: image master 1 bus overflow\n");
+
+	if (errStatus & VFE32_IMASK_IMG_MAST_2_BUS_OVFL)
+		pr_err("vfe32_irq: image master 2 bus overflow\n");
+
+	if (errStatus & VFE32_IMASK_IMG_MAST_3_BUS_OVFL)
+		pr_err("vfe32_irq: image master 3 bus overflow\n");
+
+	if (errStatus & VFE32_IMASK_IMG_MAST_4_BUS_OVFL)
+		pr_err("vfe32_irq: image master 4 bus overflow\n");
+
+	if (errStatus & VFE32_IMASK_IMG_MAST_5_BUS_OVFL)
+		pr_err("vfe32_irq: image master 5 bus overflow\n");
+
+	if (errStatus & VFE32_IMASK_IMG_MAST_6_BUS_OVFL)
+		pr_err("vfe32_irq: image master 6 bus overflow\n");
+
+	if (errStatus & VFE32_IMASK_STATS_AE_BG_BUS_OVFL)
+		pr_err("vfe32_irq: ae/bg stats bus overflow\n");
+
+	if (errStatus & VFE32_IMASK_STATS_AF_BF_BUS_OVFL)
+		pr_err("vfe32_irq: af/bf stats bus overflow\n");
+
+	if (errStatus & VFE32_IMASK_STATS_AWB_BUS_OVFL)
+		pr_err("vfe32_irq: awb stats bus overflow\n");
+
+	if (errStatus & VFE32_IMASK_STATS_RS_BUS_OVFL)
+		pr_err("vfe32_irq: rs stats bus overflow\n");
+
+	if (errStatus & VFE32_IMASK_STATS_CS_BUS_OVFL)
+		pr_err("vfe32_irq: cs stats bus overflow\n");
+
+	if (errStatus & VFE32_IMASK_STATS_IHIST_BUS_OVFL)
+		pr_err("vfe32_irq: ihist stats bus overflow\n");
+
+	if (errStatus & VFE32_IMASK_STATS_SKIN_BHIST_BUS_OVFL)
+		pr_err("vfe32_irq: skin/bhist stats bus overflow\n");
+
+	if (errStatus & VFE32_IMASK_AXI_ERROR)
+		pr_err("vfe32_irq: axi error\n");
+}
+
+#define VFE32_AXI_OFFSET 0x0050
+#define vfe32_get_ch_ping_addr(chn) \
+	(msm_io_r(vfe32_ctrl->vfebase + 0x0050 + 0x18 * (chn)))
+#define vfe32_get_ch_pong_addr(chn) \
+	(msm_io_r(vfe32_ctrl->vfebase + 0x0050 + 0x18 * (chn) + 4))
+#define vfe32_get_ch_addr(ping_pong, chn) \
+	(((ping_pong) & (1 << (chn))) == 0 ? \
+	vfe32_get_ch_pong_addr(chn) : vfe32_get_ch_ping_addr(chn))
+
+#define vfe32_put_ch_ping_addr(chn, addr) \
+	(msm_io_w((addr), vfe32_ctrl->vfebase + 0x0050 + 0x18 * (chn)))
+#define vfe32_put_ch_pong_addr(chn, addr) \
+	(msm_io_w((addr), vfe32_ctrl->vfebase + 0x0050 + 0x18 * (chn) + 4))
+#define vfe32_put_ch_addr(ping_pong, chn, addr) \
+	(((ping_pong) & (1 << (chn))) == 0 ?   \
+	vfe32_put_ch_pong_addr((chn), (addr)) : \
+	vfe32_put_ch_ping_addr((chn), (addr)))
+
+static void vfe32_process_output_path_irq_0(void)
+{
+	uint32_t ping_pong;
+	uint32_t pyaddr, pcbcraddr;
+#ifdef CONFIG_MSM_CAMERA_V4L2
+	uint32_t pyaddr_ping, pcbcraddr_ping, pyaddr_pong, pcbcraddr_pong;
+#endif
+	uint8_t out_bool = 0;
+	struct vfe32_free_buf *free_buf = NULL;
+	free_buf = vfe32_dequeue_free_buf(&vfe32_ctrl->outpath.out0);
+	/* we render frames in the following conditions:
+	1. Continuous mode and the free buffer is avaialable.
+	2. In snapshot shot mode, free buffer is not always available.
+	when pending snapshot count is <=1,  then no need to use
+	free buffer.
+	*/
+	out_bool =
+		((vfe32_ctrl->operation_mode ==
+		VFE_MODE_OF_OPERATION_SNAPSHOT ||
+		vfe32_ctrl->operation_mode ==
+		VFE_MODE_OF_OPERATION_RAW_SNAPSHOT) &&
+		(vfe32_ctrl->vfe_capture_count <= 1)) ||
+		free_buf;
+	if (out_bool) {
+		ping_pong = msm_io_r(vfe32_ctrl->vfebase +
+			VFE_BUS_PING_PONG_STATUS);
+
+		/* Y channel */
+		pyaddr = vfe32_get_ch_addr(ping_pong,
+			vfe32_ctrl->outpath.out0.ch0);
+		/* Chroma channel */
+		pcbcraddr = vfe32_get_ch_addr(ping_pong,
+			vfe32_ctrl->outpath.out0.ch1);
+
+		CDBG("output path 0, pyaddr = 0x%x, pcbcraddr = 0x%x\n",
+			pyaddr, pcbcraddr);
+		if (free_buf) {
+			/* Y channel */
+			vfe32_put_ch_addr(ping_pong,
+			vfe32_ctrl->outpath.out0.ch0,
+			free_buf->paddr + free_buf->y_off);
+			/* Chroma channel */
+			vfe32_put_ch_addr(ping_pong,
+			vfe32_ctrl->outpath.out0.ch1,
+			free_buf->paddr + free_buf->cbcr_off);
+		}
+		if (vfe32_ctrl->operation_mode ==
+			VFE_MODE_OF_OPERATION_SNAPSHOT) {
+			/* will add message for multi-shot. */
+			vfe32_ctrl->outpath.out0.capture_cnt--;
+			vfe_send_outmsg(MSG_ID_OUTPUT_T, pyaddr,
+				pcbcraddr);
+		} else {
+			/* always send message for continous mode. */
+			/* if continuous mode, for display. (preview) */
+			vfe_send_outmsg(MSG_ID_OUTPUT_P, pyaddr,
+				pcbcraddr);
+		}
+	} else {
+		vfe32_ctrl->outpath.out0.frame_drop_cnt++;
+		pr_warning("path_irq_0 - no free buffer!\n");
+#ifdef CONFIG_MSM_CAMERA_V4L2
+		pr_info("Swapping ping and pong\n");
+
+		/*get addresses*/
+		/* Y channel */
+		pyaddr_ping = vfe32_get_ch_ping_addr(
+			vfe32_ctrl->outpath.out0.ch0);
+		/* Chroma channel */
+		pcbcraddr_ping = vfe32_get_ch_ping_addr(
+			vfe32_ctrl->outpath.out0.ch1);
+		/* Y channel */
+		pyaddr_pong = vfe32_get_ch_pong_addr(
+			vfe32_ctrl->outpath.out0.ch0);
+		/* Chroma channel */
+		pcbcraddr_pong = vfe32_get_ch_pong_addr(
+			vfe32_ctrl->outpath.out0.ch1);
+
+		CDBG("ping = 0x%p, pong = 0x%p\n", (void *)pyaddr_ping,
+						(void *)pyaddr_pong);
+		CDBG("ping_cbcr = 0x%p, pong_cbcr = 0x%p\n",
+			(void *)pcbcraddr_ping, (void *)pcbcraddr_pong);
+
+		/*put addresses*/
+		/* SWAP y channel*/
+		vfe32_put_ch_ping_addr(vfe32_ctrl->outpath.out0.ch0,
+							pyaddr_pong);
+		vfe32_put_ch_pong_addr(vfe32_ctrl->outpath.out0.ch0,
+							pyaddr_ping);
+		/* SWAP chroma channel*/
+		vfe32_put_ch_ping_addr(vfe32_ctrl->outpath.out0.ch1,
+						pcbcraddr_pong);
+		vfe32_put_ch_pong_addr(vfe32_ctrl->outpath.out0.ch1,
+						pcbcraddr_ping);
+		CDBG("after swap: ping = 0x%p, pong = 0x%p\n",
+			(void *)pyaddr_pong, (void *)pyaddr_ping);
+#endif
+	}
+}
+
+static void vfe32_process_output_path_irq_1(void)
+{
+	uint32_t ping_pong;
+	uint32_t pyaddr, pcbcraddr;
+#ifdef CONFIG_MSM_CAMERA_V4L2
+	uint32_t pyaddr_ping, pcbcraddr_ping, pyaddr_pong, pcbcraddr_pong;
+#endif
+	/* this must be snapshot main image output. */
+	uint8_t out_bool = 0;
+	struct vfe32_free_buf *free_buf = NULL;
+	free_buf = vfe32_dequeue_free_buf(&vfe32_ctrl->outpath.out1);
+
+	/* we render frames in the following conditions:
+	1. Continuous mode and the free buffer is avaialable.
+	2. In snapshot shot mode, free buffer is not always available.
+	-- when pending snapshot count is <=1,  then no need to use
+	free buffer.
+	*/
+	out_bool =
+		((vfe32_ctrl->operation_mode ==
+			VFE_MODE_OF_OPERATION_SNAPSHOT ||
+			vfe32_ctrl->operation_mode ==
+			VFE_MODE_OF_OPERATION_RAW_SNAPSHOT) &&
+		 (vfe32_ctrl->vfe_capture_count <= 1)) || free_buf;
+	if (out_bool) {
+		ping_pong = msm_io_r(vfe32_ctrl->vfebase +
+			VFE_BUS_PING_PONG_STATUS);
+
+		/* Y channel */
+		pyaddr = vfe32_get_ch_addr(ping_pong,
+			vfe32_ctrl->outpath.out1.ch0);
+		/* Chroma channel */
+		pcbcraddr = vfe32_get_ch_addr(ping_pong,
+			vfe32_ctrl->outpath.out1.ch1);
+
+		CDBG("snapshot main, pyaddr = 0x%x, pcbcraddr = 0x%x\n",
+			pyaddr, pcbcraddr);
+		if (free_buf) {
+			/* Y channel */
+			vfe32_put_ch_addr(ping_pong,
+			vfe32_ctrl->outpath.out1.ch0,
+			free_buf->paddr + free_buf->y_off);
+			/* Chroma channel */
+			vfe32_put_ch_addr(ping_pong,
+			vfe32_ctrl->outpath.out1.ch1,
+			free_buf->paddr + free_buf->cbcr_off);
+		}
+		if (vfe32_ctrl->operation_mode ==
+			VFE_MODE_OF_OPERATION_SNAPSHOT ||
+			vfe32_ctrl->operation_mode ==
+			VFE_MODE_OF_OPERATION_RAW_SNAPSHOT) {
+			vfe32_ctrl->outpath.out1.capture_cnt--;
+			vfe_send_outmsg(MSG_ID_OUTPUT_S, pyaddr,
+				pcbcraddr);
+		}
+	} else {
+		vfe32_ctrl->outpath.out1.frame_drop_cnt++;
+		pr_warning("path_irq_1 - no free buffer!\n");
+#ifdef CONFIG_MSM_CAMERA_V4L2
+		pr_info("Swapping ping and pong\n");
+
+		/*get addresses*/
+		/* Y channel */
+		pyaddr_ping = vfe32_get_ch_ping_addr(
+			vfe32_ctrl->outpath.out1.ch0);
+		/* Chroma channel */
+		pcbcraddr_ping = vfe32_get_ch_ping_addr(
+			vfe32_ctrl->outpath.out1.ch1);
+		/* Y channel */
+		pyaddr_pong = vfe32_get_ch_pong_addr(
+			vfe32_ctrl->outpath.out1.ch0);
+		/* Chroma channel */
+		pcbcraddr_pong = vfe32_get_ch_pong_addr(
+			vfe32_ctrl->outpath.out1.ch1);
+
+		CDBG("ping = 0x%p, pong = 0x%p\n", (void *)pyaddr_ping,
+						(void *)pyaddr_pong);
+		CDBG("ping_cbcr = 0x%p, pong_cbcr = 0x%p\n",
+			(void *)pcbcraddr_ping, (void *)pcbcraddr_pong);
+
+		/*put addresses*/
+		/* SWAP y channel*/
+		vfe32_put_ch_ping_addr(vfe32_ctrl->outpath.out1.ch0,
+							pyaddr_pong);
+		vfe32_put_ch_pong_addr(vfe32_ctrl->outpath.out1.ch0,
+							pyaddr_ping);
+		/* SWAP chroma channel*/
+		vfe32_put_ch_ping_addr(vfe32_ctrl->outpath.out1.ch1,
+						pcbcraddr_pong);
+		vfe32_put_ch_pong_addr(vfe32_ctrl->outpath.out1.ch1,
+						pcbcraddr_ping);
+		CDBG("after swap: ping = 0x%p, pong = 0x%p\n",
+			(void *)pyaddr_pong, (void *)pyaddr_ping);
+#endif
+	}
+}
+
+static void vfe32_process_output_path_irq_2(void)
+{
+	uint32_t ping_pong;
+	uint32_t pyaddr, pcbcraddr;
+#ifdef CONFIG_MSM_CAMERA_V4L2
+	uint32_t pyaddr_ping, pcbcraddr_ping, pyaddr_pong, pcbcraddr_pong;
+#endif
+	uint8_t out_bool = 0;
+	struct vfe32_free_buf *free_buf = NULL;
+	free_buf = vfe32_dequeue_free_buf(&vfe32_ctrl->outpath.out2);
+
+	/* we render frames in the following conditions:
+	1. Continuous mode and the free buffer is avaialable.
+	2. In snapshot shot mode, free buffer is not always available.
+	-- when pending snapshot count is <=1,  then no need to use
+	free buffer.
+	*/
+	out_bool =
+		((vfe32_ctrl->operation_mode ==
+			VFE_MODE_OF_OPERATION_SNAPSHOT) &&
+		(vfe32_ctrl->vfe_capture_count <= 1)) || free_buf;
+
+	CDBG("%s: op mode = %d, capture_cnt = %d\n", __func__,
+		 vfe32_ctrl->operation_mode, vfe32_ctrl->vfe_capture_count);
+
+	if (out_bool) {
+		ping_pong = msm_io_r(vfe32_ctrl->vfebase +
+			VFE_BUS_PING_PONG_STATUS);
+
+		/* Y channel */
+		pyaddr = vfe32_get_ch_addr(ping_pong,
+			vfe32_ctrl->outpath.out2.ch0);
+		/* Chroma channel */
+		pcbcraddr = vfe32_get_ch_addr(ping_pong,
+			vfe32_ctrl->outpath.out2.ch1);
+
+		CDBG("video output, pyaddr = 0x%x, pcbcraddr = 0x%x\n",
+			pyaddr, pcbcraddr);
+
+		if (free_buf) {
+			/* Y channel */
+			vfe32_put_ch_addr(ping_pong,
+			vfe32_ctrl->outpath.out2.ch0,
+			free_buf->paddr + free_buf->y_off);
+			/* Chroma channel */
+			vfe32_put_ch_addr(ping_pong,
+			vfe32_ctrl->outpath.out2.ch1,
+			free_buf->paddr + free_buf->cbcr_off);
+		}
+		vfe_send_outmsg(MSG_ID_OUTPUT_V, pyaddr, pcbcraddr);
+	} else {
+		vfe32_ctrl->outpath.out2.frame_drop_cnt++;
+		pr_warning("path_irq_2 - no free buffer!\n");
+#ifdef CONFIG_MSM_CAMERA_V4L2
+		pr_info("Swapping ping and pong\n");
+
+		/*get addresses*/
+		/* Y channel */
+		pyaddr_ping = vfe32_get_ch_ping_addr(
+			vfe32_ctrl->outpath.out2.ch0);
+		/* Chroma channel */
+		pcbcraddr_ping = vfe32_get_ch_ping_addr(
+			vfe32_ctrl->outpath.out2.ch1);
+		/* Y channel */
+		pyaddr_pong = vfe32_get_ch_pong_addr(
+			vfe32_ctrl->outpath.out2.ch0);
+		/* Chroma channel */
+		pcbcraddr_pong = vfe32_get_ch_pong_addr(
+			vfe32_ctrl->outpath.out2.ch1);
+
+		CDBG("ping = 0x%p, pong = 0x%p\n", (void *)pyaddr_ping,
+						(void *)pyaddr_pong);
+		CDBG("ping_cbcr = 0x%p, pong_cbcr = 0x%p\n",
+			(void *)pcbcraddr_ping, (void *)pcbcraddr_pong);
+
+		/*put addresses*/
+		/* SWAP y channel*/
+		vfe32_put_ch_ping_addr(vfe32_ctrl->outpath.out2.ch0,
+							pyaddr_pong);
+		vfe32_put_ch_pong_addr(vfe32_ctrl->outpath.out2.ch0,
+							pyaddr_ping);
+		/* SWAP chroma channel*/
+		vfe32_put_ch_ping_addr(vfe32_ctrl->outpath.out2.ch1,
+						pcbcraddr_pong);
+		vfe32_put_ch_pong_addr(vfe32_ctrl->outpath.out2.ch1,
+						pcbcraddr_ping);
+		CDBG("after swap: ping = 0x%p, pong = 0x%p\n",
+			(void *)pyaddr_pong, (void *)pyaddr_ping);
+#endif
+	}
+}
+
+static void vfe32_process_stats_comb_irq(uint32_t *irqstatus)
+{
+	return;
+}
+
+static uint32_t  vfe32_process_stats_irq_common(uint32_t statsNum,
+						uint32_t newAddr) {
+
+	uint32_t pingpongStatus;
+	uint32_t returnAddr;
+	uint32_t pingpongAddr;
+
+	/* must be 0=ping, 1=pong */
+	pingpongStatus =
+		((msm_io_r(vfe32_ctrl->vfebase +
+		VFE_BUS_PING_PONG_STATUS))
+	& ((uint32_t)(1<<(statsNum + 7)))) >> (statsNum + 7);
+	/* stats bits starts at 7 */
+	CDBG("statsNum %d, pingpongStatus %d\n", statsNum, pingpongStatus);
+	pingpongAddr =
+		((uint32_t)(vfe32_ctrl->vfebase +
+				VFE_BUS_STATS_PING_PONG_BASE)) +
+				(3*statsNum)*4 + (1-pingpongStatus)*4;
+	returnAddr = msm_io_r((uint32_t *)pingpongAddr);
+	msm_io_w(newAddr, (uint32_t *)pingpongAddr);
+	return returnAddr;
+}
+
+static void
+vfe_send_stats_msg(uint32_t bufAddress, uint32_t statsNum)
+{
+	unsigned long flags;
+	struct  vfe_message msg;
+	/* fill message with right content. */
+	/* @todo This is causing issues, need further investigate */
+	/* spin_lock_irqsave(&ctrl->state_lock, flags); */
+	msg._u.msgStats.frameCounter = vfe32_ctrl->vfeFrameId;
+	msg._u.msgStats.buffer = bufAddress;
+
+	switch (statsNum) {
+	case statsAeNum:{
+		msg._d = MSG_ID_STATS_AEC;
+		spin_lock_irqsave(&vfe32_ctrl->aec_ack_lock, flags);
+		vfe32_ctrl->aecStatsControl.ackPending = TRUE;
+		spin_unlock_irqrestore(&vfe32_ctrl->aec_ack_lock, flags);
+		}
+		break;
+	case statsAfNum:{
+		msg._d = MSG_ID_STATS_AF;
+		spin_lock_irqsave(&vfe32_ctrl->af_ack_lock, flags);
+		vfe32_ctrl->afStatsControl.ackPending = TRUE;
+		spin_unlock_irqrestore(&vfe32_ctrl->af_ack_lock, flags);
+		}
+		break;
+	case statsAwbNum: {
+		msg._d = MSG_ID_STATS_AWB;
+		spin_lock_irqsave(&vfe32_ctrl->awb_ack_lock, flags);
+		vfe32_ctrl->awbStatsControl.ackPending = TRUE;
+		spin_unlock_irqrestore(&vfe32_ctrl->awb_ack_lock, flags);
+		}
+		break;
+
+	case statsIhistNum: {
+		msg._d = MSG_ID_STATS_IHIST;
+		vfe32_ctrl->ihistStatsControl.ackPending = TRUE;
+		}
+		break;
+	case statsRsNum: {
+		msg._d = MSG_ID_STATS_RS;
+		vfe32_ctrl->rsStatsControl.ackPending = TRUE;
+		}
+		break;
+	case statsCsNum: {
+		msg._d = MSG_ID_STATS_CS;
+		vfe32_ctrl->csStatsControl.ackPending = TRUE;
+		}
+		break;
+
+	default:
+		goto stats_done;
+	}
+
+	vfe32_proc_ops(msg._d,
+		&msg, sizeof(struct vfe_message));
+stats_done:
+	/* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
+	return;
+}
+
+static void vfe32_process_stats_ae_irq(void)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&vfe32_ctrl->aec_ack_lock, flags);
+	if (!(vfe32_ctrl->aecStatsControl.ackPending)) {
+		spin_unlock_irqrestore(&vfe32_ctrl->aec_ack_lock, flags);
+		vfe32_ctrl->aecStatsControl.bufToRender =
+			vfe32_process_stats_irq_common(statsAeNum,
+			vfe32_ctrl->aecStatsControl.nextFrameAddrBuf);
+
+		vfe_send_stats_msg(vfe32_ctrl->aecStatsControl.bufToRender,
+						statsAeNum);
+	} else{
+		spin_unlock_irqrestore(&vfe32_ctrl->aec_ack_lock, flags);
+		vfe32_ctrl->aecStatsControl.droppedStatsFrameCount++;
+	}
+}
+
+static void vfe32_process_stats_awb_irq(void)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&vfe32_ctrl->awb_ack_lock, flags);
+	if (!(vfe32_ctrl->awbStatsControl.ackPending)) {
+		spin_unlock_irqrestore(&vfe32_ctrl->awb_ack_lock, flags);
+		vfe32_ctrl->awbStatsControl.bufToRender =
+			vfe32_process_stats_irq_common(statsAwbNum,
+			vfe32_ctrl->awbStatsControl.nextFrameAddrBuf);
+
+		vfe_send_stats_msg(vfe32_ctrl->awbStatsControl.bufToRender,
+						statsAwbNum);
+	} else{
+		spin_unlock_irqrestore(&vfe32_ctrl->awb_ack_lock, flags);
+		vfe32_ctrl->awbStatsControl.droppedStatsFrameCount++;
+	}
+}
+
+static void vfe32_process_stats_af_irq(void)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&vfe32_ctrl->af_ack_lock, flags);
+	if (!(vfe32_ctrl->afStatsControl.ackPending)) {
+		spin_unlock_irqrestore(&vfe32_ctrl->af_ack_lock, flags);
+		vfe32_ctrl->afStatsControl.bufToRender =
+			vfe32_process_stats_irq_common(statsAfNum,
+			vfe32_ctrl->afStatsControl.nextFrameAddrBuf);
+
+		vfe_send_stats_msg(vfe32_ctrl->afStatsControl.bufToRender,
+						statsAfNum);
+	} else{
+		spin_unlock_irqrestore(&vfe32_ctrl->af_ack_lock, flags);
+		vfe32_ctrl->afStatsControl.droppedStatsFrameCount++;
+	}
+}
+
+static void vfe32_process_stats_ihist_irq(void)
+{
+	if (!(vfe32_ctrl->ihistStatsControl.ackPending)) {
+		vfe32_ctrl->ihistStatsControl.bufToRender =
+			vfe32_process_stats_irq_common(statsIhistNum,
+			vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf);
+
+		vfe_send_stats_msg(vfe32_ctrl->ihistStatsControl.bufToRender,
+						statsIhistNum);
+	} else
+		vfe32_ctrl->ihistStatsControl.droppedStatsFrameCount++;
+}
+
+static void vfe32_process_stats_rs_irq(void)
+{
+	if (!(vfe32_ctrl->rsStatsControl.ackPending)) {
+		vfe32_ctrl->rsStatsControl.bufToRender =
+			vfe32_process_stats_irq_common(statsRsNum,
+			vfe32_ctrl->rsStatsControl.nextFrameAddrBuf);
+
+		vfe_send_stats_msg(vfe32_ctrl->rsStatsControl.bufToRender,
+						statsRsNum);
+	} else
+		vfe32_ctrl->rsStatsControl.droppedStatsFrameCount++;
+}
+
+static void vfe32_process_stats_cs_irq(void)
+{
+	if (!(vfe32_ctrl->csStatsControl.ackPending)) {
+		vfe32_ctrl->csStatsControl.bufToRender =
+			vfe32_process_stats_irq_common(statsCsNum,
+			vfe32_ctrl->csStatsControl.nextFrameAddrBuf);
+
+		vfe_send_stats_msg(vfe32_ctrl->csStatsControl.bufToRender,
+						statsCsNum);
+	} else
+		vfe32_ctrl->csStatsControl.droppedStatsFrameCount++;
+}
+
+static void vfe32_do_tasklet(unsigned long data)
+{
+	unsigned long flags;
+
+	struct vfe32_isr_queue_cmd *qcmd = NULL;
+
+	CDBG("=== vfe32_do_tasklet start ===\n");
+
+	while (atomic_read(&irq_cnt)) {
+		spin_lock_irqsave(&vfe32_ctrl->tasklet_lock, flags);
+		qcmd = list_first_entry(&vfe32_ctrl->tasklet_q,
+			struct vfe32_isr_queue_cmd, list);
+		atomic_sub(1, &irq_cnt);
+
+		if (!qcmd) {
+			spin_unlock_irqrestore(&vfe32_ctrl->tasklet_lock,
+				flags);
+			return;
+		}
+
+		list_del(&qcmd->list);
+		spin_unlock_irqrestore(&vfe32_ctrl->tasklet_lock,
+			flags);
+
+		/* interrupt to be processed,  *qcmd has the payload.  */
+		if (qcmd->vfeInterruptStatus0 &
+				VFE_IRQ_STATUS0_REG_UPDATE_MASK) {
+			CDBG("irq	regUpdateIrq\n");
+			vfe32_process_reg_update_irq();
+		}
+
+		if (qcmd->vfeInterruptStatus1 &
+				VFE_IMASK_WHILE_STOPPING_1) {
+			CDBG("irq	resetAckIrq\n");
+			vfe32_process_reset_irq();
+		}
+
+		if (atomic_read(&vfe32_ctrl->vstate)) {
+			if (qcmd->vfeInterruptStatus1 &
+					VFE32_IMASK_ERROR_ONLY_1) {
+				pr_err("irq	errorIrq\n");
+				vfe32_process_error_irq(
+					qcmd->vfeInterruptStatus1 &
+					VFE32_IMASK_ERROR_ONLY_1);
+			}
+			/* next, check output path related interrupts. */
+			if (qcmd->vfeInterruptStatus0 &
+				VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK) {
+				CDBG("Image composite done 0 irq occured.\n");
+				vfe32_process_output_path_irq_0();
+			}
+			if (qcmd->vfeInterruptStatus0 &
+				VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK) {
+				CDBG("Image composite done 1 irq occured.\n");
+				vfe32_process_output_path_irq_1();
+			}
+			if (qcmd->vfeInterruptStatus0 &
+				VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE2_MASK) {
+				CDBG("Image composite done 2 irq occured.\n");
+				vfe32_process_output_path_irq_2();
+			}
+			/* in snapshot mode if done then send
+			snapshot done message */
+			if (vfe32_ctrl->operation_mode ==
+				VFE_MODE_OF_OPERATION_SNAPSHOT ||
+				vfe32_ctrl->operation_mode ==
+				VFE_MODE_OF_OPERATION_RAW_SNAPSHOT) {
+				if ((vfe32_ctrl->outpath.out0.capture_cnt == 0)
+						&& (vfe32_ctrl->outpath.out1.
+						capture_cnt == 0)) {
+					vfe32_send_msg_no_payload(
+						MSG_ID_SNAPSHOT_DONE);
+
+					/* Ensure the write order while writing
+					to the cmd register using barrier */
+					msm_io_w_mb(
+						CAMIF_COMMAND_STOP_IMMEDIATELY,
+						vfe32_ctrl->vfebase +
+						VFE_CAMIF_COMMAND);
+				}
+			}
+			/* then process stats irq. */
+			if (vfe32_ctrl->stats_comp) {
+				/* process stats comb interrupt. */
+				if (qcmd->vfeInterruptStatus0 &
+					VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK) {
+					CDBG("Stats composite irq occured.\n");
+					vfe32_process_stats_comb_irq(
+						&qcmd->vfeInterruptStatus0);
+				}
+			} else {
+				/* process individual stats interrupt. */
+				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS0_STATS_AEC) {
+					CDBG("Stats AEC irq occured.\n");
+					vfe32_process_stats_ae_irq();
+				}
+				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS0_STATS_AWB) {
+					CDBG("Stats AWB irq occured.\n");
+					vfe32_process_stats_awb_irq();
+				}
+				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS0_STATS_AF) {
+					CDBG("Stats AF irq occured.\n");
+					vfe32_process_stats_af_irq();
+				}
+				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS0_STATS_IHIST) {
+					CDBG("Stats IHIST irq occured.\n");
+					vfe32_process_stats_ihist_irq();
+				}
+				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS0_STATS_RS) {
+					CDBG("Stats RS irq occured.\n");
+					vfe32_process_stats_rs_irq();
+				}
+				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS0_STATS_CS) {
+					CDBG("Stats CS irq occured.\n");
+					vfe32_process_stats_cs_irq();
+				}
+				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS0_SYNC_TIMER0) {
+					CDBG("SYNC_TIMER 0 irq occured.\n");
+					vfe32_send_msg_no_payload(
+						MSG_ID_SYNC_TIMER0_DONE);
+				}
+				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS0_SYNC_TIMER1) {
+					CDBG("SYNC_TIMER 1 irq occured.\n");
+					vfe32_send_msg_no_payload(
+						MSG_ID_SYNC_TIMER1_DONE);
+				}
+				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS0_SYNC_TIMER2) {
+					CDBG("SYNC_TIMER 2 irq occured.\n");
+					vfe32_send_msg_no_payload(
+						MSG_ID_SYNC_TIMER2_DONE);
+				}
+			}
+		}
+		if (qcmd->vfeInterruptStatus0 &
+				VFE_IRQ_STATUS0_CAMIF_SOF_MASK) {
+			CDBG("irq	camifSofIrq\n");
+			vfe32_process_camif_sof_irq();
+		}
+		kfree(qcmd);
+	}
+	CDBG("=== vfe32_do_tasklet end ===\n");
+}
+
+DECLARE_TASKLET(vfe32_tasklet, vfe32_do_tasklet, 0);
+
+static irqreturn_t vfe32_parse_irq(int irq_num, void *data)
+{
+	unsigned long flags;
+	struct vfe32_irq_status irq;
+	struct vfe32_isr_queue_cmd *qcmd;
+
+	CDBG("vfe_parse_irq\n");
+
+	vfe32_read_irq_status(&irq);
+
+	if ((irq.vfeIrqStatus0 == 0) && (irq.vfeIrqStatus1 == 0)) {
+		CDBG("vfe_parse_irq: vfeIrqStatus0 & 1 are both 0!\n");
+		return IRQ_HANDLED;
+	}
+
+	qcmd = kzalloc(sizeof(struct vfe32_isr_queue_cmd),
+		GFP_ATOMIC);
+	if (!qcmd) {
+		pr_err("vfe_parse_irq: qcmd malloc failed!\n");
+		return IRQ_HANDLED;
+	}
+
+	spin_lock_irqsave(&vfe32_ctrl->stop_flag_lock, flags);
+	if (vfe32_ctrl->stop_ack_pending) {
+		irq.vfeIrqStatus0 &= VFE_IMASK_WHILE_STOPPING_0;
+		irq.vfeIrqStatus1 &= VFE_IMASK_WHILE_STOPPING_1;
+	}
+	spin_unlock_irqrestore(&vfe32_ctrl->stop_flag_lock, flags);
+
+	CDBG("vfe_parse_irq: Irq_status0 = 0x%x, Irq_status1 = 0x%x.\n",
+		irq.vfeIrqStatus0, irq.vfeIrqStatus1);
+
+	qcmd->vfeInterruptStatus0 = irq.vfeIrqStatus0;
+	qcmd->vfeInterruptStatus1 = irq.vfeIrqStatus1;
+
+	spin_lock_irqsave(&vfe32_ctrl->tasklet_lock, flags);
+	list_add_tail(&qcmd->list, &vfe32_ctrl->tasklet_q);
+
+	atomic_add(1, &irq_cnt);
+	spin_unlock_irqrestore(&vfe32_ctrl->tasklet_lock, flags);
+	tasklet_schedule(&vfe32_tasklet);
+	return IRQ_HANDLED;
+}
+
+static int vfe32_resource_init(struct platform_device *pdev, void *sdata)
+{
+	struct resource	*vfemem, *vfeirq, *vfeio;
+	int rc;
+	struct msm_camera_sensor_info *s_info;
+	s_info = pdev->dev.platform_data;
+
+	pdev->resource = s_info->resource;
+	pdev->num_resources = s_info->num_resources;
+
+	vfemem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!vfemem) {
+		pr_err("%s: no mem resource?\n", __func__);
+		return -ENODEV;
+	}
+
+	vfeirq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!vfeirq) {
+		pr_err("%s: no irq resource?\n", __func__);
+		return -ENODEV;
+	}
+
+	vfeio = request_mem_region(vfemem->start,
+		resource_size(vfemem), pdev->name);
+	if (!vfeio) {
+		pr_err("%s: VFE region already claimed\n", __func__);
+		return -EBUSY;
+	}
+
+	vfe32_ctrl = kzalloc(sizeof(struct vfe32_ctrl_type), GFP_KERNEL);
+	if (!vfe32_ctrl) {
+		rc = -ENOMEM;
+		goto cmd_init_failed1;
+	}
+
+	vfe32_ctrl->vfeirq = vfeirq->start;
+
+	vfe32_ctrl->vfebase =
+		ioremap(vfemem->start, (vfemem->end - vfemem->start) + 1);
+	if (!vfe32_ctrl->vfebase) {
+		rc = -ENOMEM;
+		pr_err("%s: vfe ioremap failed\n", __func__);
+		goto cmd_init_failed2;
+	}
+
+	vfe32_ctrl->extdata =
+		kmalloc(sizeof(struct vfe32_frame_extra), GFP_KERNEL);
+	if (!vfe32_ctrl->extdata) {
+		rc = -ENOMEM;
+		goto cmd_init_failed3;
+	}
+
+	vfe32_ctrl->extlen = sizeof(struct vfe32_frame_extra);
+
+	spin_lock_init(&vfe32_ctrl->stop_flag_lock);
+	spin_lock_init(&vfe32_ctrl->state_lock);
+	spin_lock_init(&vfe32_ctrl->io_lock);
+	spin_lock_init(&vfe32_ctrl->update_ack_lock);
+	spin_lock_init(&vfe32_ctrl->tasklet_lock);
+
+	spin_lock_init(&vfe32_ctrl->aec_ack_lock);
+	spin_lock_init(&vfe32_ctrl->awb_ack_lock);
+	spin_lock_init(&vfe32_ctrl->af_ack_lock);
+	INIT_LIST_HEAD(&vfe32_ctrl->tasklet_q);
+	vfe32_init_free_buf_queues();
+
+	vfe32_ctrl->syncdata = sdata;
+	vfe32_ctrl->vfemem = vfemem;
+	vfe32_ctrl->vfeio  = vfeio;
+	return 0;
+
+cmd_init_failed3:
+	free_irq(vfe32_ctrl->vfeirq, 0);
+	iounmap(vfe32_ctrl->vfebase);
+cmd_init_failed2:
+	kfree(vfe32_ctrl);
+cmd_init_failed1:
+	release_mem_region(vfemem->start, (vfemem->end - vfemem->start) + 1);
+	return rc;
+}
+
+static long msm_vfe_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int subdev_cmd, void *arg)
+{
+	struct msm_vfe32_cmd vfecmd;
+	struct msm_camvfe_params *vfe_params =
+		(struct msm_camvfe_params *)arg;
+	struct msm_vfe_cfg_cmd *cmd = vfe_params->vfe_cfg;
+	void *data = vfe_params->data;
+
+	long rc = 0;
+	uint32_t i = 0;
+	struct vfe_cmd_stats_buf *scfg = NULL;
+	struct msm_pmem_region   *regptr = NULL;
+	struct vfe_cmd_stats_ack *sack = NULL;
+	if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
+		if (copy_from_user(&vfecmd,
+				(void __user *)(cmd->value),
+				sizeof(vfecmd))) {
+			pr_err("%s %d: copy_from_user failed\n", __func__,
+				__LINE__);
+			return -EFAULT;
+		}
+	} else {
+	/* here eith stats release or frame release. */
+		if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE) {
+			/* then must be stats release. */
+			if (!data)
+				return -EFAULT;
+			sack = kmalloc(sizeof(struct vfe_cmd_stats_ack),
+							GFP_ATOMIC);
+			if (!sack)
+				return -ENOMEM;
+
+			sack->nextStatsBuf = *(uint32_t *)data;
+		}
+	}
+
+	CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
+
+	if ((cmd->cmd_type == CMD_STATS_AF_ENABLE)    ||
+		(cmd->cmd_type == CMD_STATS_AWB_ENABLE)   ||
+		(cmd->cmd_type == CMD_STATS_IHIST_ENABLE) ||
+		(cmd->cmd_type == CMD_STATS_RS_ENABLE)    ||
+		(cmd->cmd_type == CMD_STATS_CS_ENABLE)    ||
+		(cmd->cmd_type == CMD_STATS_AEC_ENABLE)) {
+		struct axidata *axid;
+		axid = data;
+		if (!axid) {
+			rc = -EFAULT;
+			goto vfe32_config_done;
+		}
+
+		scfg =
+			kmalloc(sizeof(struct vfe_cmd_stats_buf),
+				GFP_ATOMIC);
+		if (!scfg) {
+			rc = -ENOMEM;
+			goto vfe32_config_done;
+		}
+		regptr = axid->region;
+		if (axid->bufnum1 > 0) {
+			for (i = 0; i < axid->bufnum1; i++) {
+				scfg->statsBuf[i] =
+					(uint32_t)(regptr->paddr);
+				regptr++;
+			}
+		}
+		/* individual */
+		switch (cmd->cmd_type) {
+		case CMD_STATS_AEC_ENABLE:
+			rc = vfe_stats_aec_buf_init(scfg);
+			break;
+		case CMD_STATS_AF_ENABLE:
+			rc = vfe_stats_af_buf_init(scfg);
+			break;
+		case CMD_STATS_AWB_ENABLE:
+			rc = vfe_stats_awb_buf_init(scfg);
+			break;
+		case CMD_STATS_IHIST_ENABLE:
+			rc = vfe_stats_ihist_buf_init(scfg);
+			break;
+		case CMD_STATS_RS_ENABLE:
+			rc = vfe_stats_rs_buf_init(scfg);
+			break;
+		case CMD_STATS_CS_ENABLE:
+			rc = vfe_stats_cs_buf_init(scfg);
+			break;
+		}
+	}
+	switch (cmd->cmd_type) {
+	case CMD_GENERAL:
+		rc = vfe32_proc_general(&vfecmd);
+		break;
+	case CMD_FRAME_BUF_RELEASE: {
+		struct msm_frame *b;
+		unsigned long p;
+		struct vfe32_output_ch *outch = NULL;
+		if (!data) {
+			rc = -EFAULT;
+			break;
+		}
+
+		b = (struct msm_frame *)(cmd->value);
+		p = *(unsigned long *)data;
+
+		CDBG("CMD_FRAME_BUF_RELEASE b->path = %d\n", b->path);
+
+		if ((b->path & OUTPUT_TYPE_P) || (b->path & OUTPUT_TYPE_T)) {
+			CDBG("CMD_FRAME_BUF_RELEASE got free buffer\n");
+			outch = &vfe32_ctrl->outpath.out0;
+		} else if (b->path & OUTPUT_TYPE_S) {
+			outch = &vfe32_ctrl->outpath.out1;
+		} else if (b->path & OUTPUT_TYPE_V) {
+			outch = &vfe32_ctrl->outpath.out2;
+		} else {
+			rc = -EFAULT;
+			break;
+		}
+
+		rc = vfe32_enqueue_free_buf(outch, p, b->y_off, b->cbcr_off);
+	}
+		break;
+
+	case CMD_SNAP_BUF_RELEASE:
+		break;
+	case CMD_STATS_AEC_BUF_RELEASE:
+		vfe32_stats_aec_ack(sack);
+		break;
+	case CMD_STATS_AF_BUF_RELEASE:
+		vfe32_stats_af_ack(sack);
+		break;
+	case CMD_STATS_AWB_BUF_RELEASE:
+		vfe32_stats_awb_ack(sack);
+		break;
+
+	case CMD_STATS_IHIST_BUF_RELEASE:
+		vfe32_stats_ihist_ack(sack);
+		break;
+	case CMD_STATS_RS_BUF_RELEASE:
+		vfe32_stats_rs_ack(sack);
+		break;
+	case CMD_STATS_CS_BUF_RELEASE:
+		vfe32_stats_cs_ack(sack);
+		break;
+
+	case CMD_AXI_CFG_PREVIEW: {
+		struct axidata *axid;
+		uint32_t *axio = NULL;
+		axid = data;
+		if (!axid) {
+			rc = -EFAULT;
+			break;
+		}
+		axio =
+			kmalloc(vfe32_cmd[V32_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			break;
+		}
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe32_cmd[V32_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			rc = -EFAULT;
+			break;
+		}
+		vfe32_config_axi(OUTPUT_2, axid, axio);
+		kfree(axio);
+	}
+		break;
+
+	case CMD_RAW_PICT_AXI_CFG: {
+		struct axidata *axid;
+		uint32_t *axio = NULL;
+		axid = data;
+		if (!axid) {
+			rc = -EFAULT;
+			break;
+		}
+		axio = kmalloc(vfe32_cmd[V32_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			break;
+		}
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe32_cmd[V32_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			rc = -EFAULT;
+			break;
+		}
+		vfe32_config_axi(CAMIF_TO_AXI_VIA_OUTPUT_2, axid, axio);
+		kfree(axio);
+	}
+		break;
+
+	case CMD_AXI_CFG_SNAP: {
+		struct axidata *axid;
+		uint32_t *axio = NULL;
+		axid = data;
+		if (!axid)
+			return -EFAULT;
+		axio =
+			kmalloc(vfe32_cmd[V32_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			break;
+		}
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe32_cmd[V32_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			rc = -EFAULT;
+			break;
+		}
+		vfe32_config_axi(OUTPUT_1_AND_2, axid, axio);
+		kfree(axio);
+	}
+		break;
+
+	case CMD_AXI_CFG_VIDEO: {
+		struct axidata *axid;
+		uint32_t *axio = NULL;
+		axid = data;
+		if (!axid) {
+			rc = -EFAULT;
+			break;
+		}
+
+		axio = kmalloc(vfe32_cmd[V32_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			break;
+		}
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe32_cmd[V32_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			rc = -EFAULT;
+			break;
+		}
+		vfe32_config_axi(OUTPUT_1_AND_3, axid, axio);
+		kfree(axio);
+	}
+		break;
+	default:
+		break;
+	}
+vfe32_config_done:
+	kfree(scfg);
+	kfree(sack);
+	CDBG("%s done: rc = %d\n", __func__, (int) rc);
+	return rc;
+}
+
+static const struct v4l2_subdev_core_ops msm_vfe_subdev_core_ops = {
+	.ioctl = msm_vfe_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_vfe_subdev_ops = {
+	.core = &msm_vfe_subdev_core_ops,
+};
+
+int msm_vfe_subdev_init(struct v4l2_subdev *sd, void *data,
+	struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+	v4l2_subdev_init(sd, &msm_vfe_subdev_ops);
+	v4l2_set_subdev_hostdata(sd, data);
+	snprintf(sd->name, sizeof(sd->name), "vfe3.2");
+
+	vfe_syncdata = data;
+
+	camio_clk = camdev->ioclk;
+
+	rc = vfe32_resource_init(pdev, vfe_syncdata);
+	if (rc < 0)
+		return rc;
+
+	vfe32_ctrl->subdev = sd;
+	/* Bring up all the required GPIOs and Clocks */
+	rc = msm_camio_enable(pdev);
+	msm_camio_set_perf_lvl(S_INIT);
+	msm_camio_set_perf_lvl(S_PREVIEW);
+
+	/* TO DO: Need to release the VFE resources */
+	rc = request_irq(vfe32_ctrl->vfeirq, vfe32_parse_irq,
+			IRQF_TRIGGER_RISING, "vfe", 0);
+
+	return rc;
+}
+
+void msm_vfe_subdev_release(struct platform_device *pdev)
+{
+	struct resource	*vfemem, *vfeio;
+
+	vfe32_reset_free_buf_queues();
+	CDBG("%s, free_irq\n", __func__);
+	free_irq(vfe32_ctrl->vfeirq, 0);
+	tasklet_kill(&vfe32_tasklet);
+
+	if (atomic_read(&irq_cnt))
+		pr_warning("%s, Warning IRQ Count not ZERO\n", __func__);
+
+	vfemem = vfe32_ctrl->vfemem;
+	vfeio  = vfe32_ctrl->vfeio;
+
+	kfree(vfe32_ctrl->extdata);
+	iounmap(vfe32_ctrl->vfebase);
+	kfree(vfe32_ctrl);
+	vfe32_ctrl = NULL;
+	release_mem_region(vfemem->start, (vfemem->end - vfemem->start) + 1);
+	CDBG("%s, msm_camio_disable\n", __func__);
+	msm_camio_disable(pdev);
+	msm_camio_set_perf_lvl(S_EXIT);
+
+	vfe_syncdata = NULL;
+}
+
+void msm_camvpe_fn_init(struct msm_camvpe_fn *fptr, void *data)
+{
+	fptr->vpe_reg		= msm_vpe_reg;
+	fptr->send_frame_to_vpe	= msm_send_frame_to_vpe;
+	fptr->vpe_config	= msm_vpe_config;
+	fptr->vpe_cfg_update	= msm_vpe_cfg_update;
+	fptr->dis		= &(vpe_ctrl->dis_en);
+	vpe_ctrl->syncdata = data;
+}
diff --git a/drivers/media/video/msm/msm_vfe32.h b/drivers/media/video/msm/msm_vfe32.h
new file mode 100644
index 0000000..4d48c6b
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe32.h
@@ -0,0 +1,1104 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __MSM_VFE32_H__
+#define __MSM_VFE32_H__
+
+#define TRUE  1
+#define FALSE 0
+
+/* at start of camif,  bit 1:0 = 0x01:enable
+ * image data capture at frame boundary. */
+#define CAMIF_COMMAND_START  0x00000005
+
+/* bit 2= 0x1:clear the CAMIF_STATUS register
+ * value. */
+#define CAMIF_COMMAND_CLEAR  0x00000004
+
+/* at stop of vfe pipeline, for now it is assumed
+ * that camif will stop at any time. Bit 1:0 = 0x10:
+ * disable image data capture immediately. */
+#define CAMIF_COMMAND_STOP_IMMEDIATELY  0x00000002
+
+/* at stop of vfe pipeline, for now it is assumed
+ * that camif will stop at any time. Bit 1:0 = 0x00:
+ * disable image data capture at frame boundary */
+#define CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY  0x00000000
+
+/* to halt axi bridge */
+#define AXI_HALT  0x00000001
+
+/* clear the halt bit. */
+#define AXI_HALT_CLEAR  0x00000000
+
+/* reset the pipeline when stop command is issued.
+ * (without reset the register.) bit 26-32 = 0,
+ * domain reset, bit 0-9 = 1 for module reset, except
+ * register module. */
+#define VFE_RESET_UPON_STOP_CMD  0x000003ef
+
+/* reset the pipeline when reset command.
+ * bit 26-32 = 0, domain reset, bit 0-9 = 1 for module reset. */
+#define VFE_RESET_UPON_RESET_CMD  0x000003ff
+
+/* bit 5 is for axi status idle or busy.
+ * 1 =  halted,  0 = busy */
+#define AXI_STATUS_BUSY_MASK 0x00000020
+
+/* bit 0 & bit 1 = 1, both y and cbcr irqs need to be present
+ * for frame done interrupt */
+#define VFE_COMP_IRQ_BOTH_Y_CBCR 3
+
+/* bit 1 = 1, only cbcr irq triggers frame done interrupt */
+#define VFE_COMP_IRQ_CBCR_ONLY 2
+
+/* bit 0 = 1, only y irq triggers frame done interrupt */
+#define VFE_COMP_IRQ_Y_ONLY 1
+
+/* bit 0 = 1, PM go;   bit1 = 1, PM stop */
+#define VFE_PERFORMANCE_MONITOR_GO   0x00000001
+#define VFE_PERFORMANCE_MONITOR_STOP 0x00000002
+
+/* bit 0 = 1, test gen go;   bit1 = 1, test gen stop */
+#define VFE_TEST_GEN_GO   0x00000001
+#define VFE_TEST_GEN_STOP 0x00000002
+
+/* the chroma is assumed to be interpolated between
+ * the luma samples.  JPEG 4:2:2 */
+#define VFE_CHROMA_UPSAMPLE_INTERPOLATED 0
+
+/* constants for irq registers */
+#define VFE_DISABLE_ALL_IRQS 0
+/* bit =1 is to clear the corresponding bit in VFE_IRQ_STATUS.  */
+#define VFE_CLEAR_ALL_IRQS   0xffffffff
+
+#define VFE_IRQ_STATUS0_CAMIF_SOF_MASK            0x00000001
+#define VFE_IRQ_STATUS0_REG_UPDATE_MASK           0x00000020
+#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK 0x00200000
+#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK 0x00400000
+#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE2_MASK 0x00800000
+#define VFE_IRQ_STATUS1_RESET_AXI_HALT_ACK_MASK   0x00800000
+#define VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK       0x01000000
+
+#define VFE_IRQ_STATUS0_STATS_AEC     0x2000  /* bit 13 */
+#define VFE_IRQ_STATUS0_STATS_AF      0x4000  /* bit 14 */
+#define VFE_IRQ_STATUS0_STATS_AWB     0x8000  /* bit 15 */
+#define VFE_IRQ_STATUS0_STATS_RS      0x10000  /* bit 16 */
+#define VFE_IRQ_STATUS0_STATS_CS      0x20000  /* bit 17 */
+#define VFE_IRQ_STATUS0_STATS_IHIST   0x40000  /* bit 18 */
+
+#define VFE_IRQ_STATUS0_SYNC_TIMER0   0x2000000  /* bit 25 */
+#define VFE_IRQ_STATUS0_SYNC_TIMER1   0x4000000  /* bit 26 */
+#define VFE_IRQ_STATUS0_SYNC_TIMER2   0x8000000  /* bit 27 */
+#define VFE_IRQ_STATUS0_ASYNC_TIMER0  0x10000000  /* bit 28 */
+#define VFE_IRQ_STATUS0_ASYNC_TIMER1  0x20000000  /* bit 29 */
+#define VFE_IRQ_STATUS0_ASYNC_TIMER2  0x40000000  /* bit 30 */
+#define VFE_IRQ_STATUS0_ASYNC_TIMER3  0x80000000  /* bit 32 */
+
+/* imask for while waiting for stop ack,  driver has already
+ * requested stop, waiting for reset irq, and async timer irq.
+ * For irq_status_0, bit 28-32 are for async timer. For
+ * irq_status_1, bit 22 for reset irq, bit 23 for axi_halt_ack
+   irq */
+#define VFE_IMASK_WHILE_STOPPING_0  0xF0000000
+#define VFE_IMASK_WHILE_STOPPING_1  0x00800000
+
+/* no error irq in mask 0 */
+#define VFE_IMASK_ERROR_ONLY_0  0x0
+/* when normal case, don't want to block error status. */
+/* bit 0-21 are error irq bits */
+#define VFE_IMASK_ERROR_ONLY_1  0x003fffff
+
+/* For BPC bit 0,bit 12-17 and bit 26 -20 are set to zero and other's 1 */
+#define BPC_MASK 0xF80C0FFE
+
+/* For BPC bit 1 and 2 are set to zero and other's 1 */
+#define ABF_MASK 0xFFFFFFF9
+
+
+/* For DBPC bit 0 is set to zero and other's 1 */
+#define DBPC_MASK 0xFFFFFFFE
+
+/* For DBPC bit 1 is set to zero and other's 1 */
+#define DBCC_MASK 0xFFFFFFFD
+
+/* For MCE enable bit 28 set to zero and other's 1 */
+#define MCE_EN_MASK 0xEFFFFFFF
+
+/* For MCE Q_K bit 28 to 32 set to zero and other's 1 */
+#define MCE_Q_K_MASK 0x0FFFFFFF
+
+#define AE_BG_ENABLE_MASK 0x00000020      /* bit 5 */
+#define AF_BF_ENABLE_MASK 0x00000040      /* bit 6 */
+#define AWB_ENABLE_MASK 0x00000080     /* bit 7 */
+#define RS_ENABLE_MASK 0x00000100      /* bit 8  */
+#define CS_ENABLE_MASK 0x00000200      /* bit 9  */
+#define RS_CS_ENABLE_MASK 0x00000300   /* bit 8,9  */
+#define CLF_ENABLE_MASK 0x00002000     /* bit 13 */
+#define IHIST_ENABLE_MASK 0x00010000   /* bit 16 */
+#define STATS_ENABLE_MASK 0x000903E0   /* bit 19,16,9,8,7,6,5*/
+
+#define VFE_REG_UPDATE_TRIGGER           1
+#define VFE_PM_BUF_MAX_CNT_MASK          0xFF
+#define VFE_DMI_CFG_DEFAULT              0x00000100
+#define LENS_ROLL_OFF_DELTA_TABLE_OFFSET 32
+#define VFE_AE_PINGPONG_STATUS_BIT       0x80
+#define VFE_AF_PINGPONG_STATUS_BIT       0x100
+#define VFE_AWB_PINGPONG_STATUS_BIT      0x200
+
+
+enum VFE32_DMI_RAM_SEL {
+	NO_MEM_SELECTED          = 0,
+	BLACK_LUT_RAM_BANK0      = 0x1,
+	BLACK_LUT_RAM_BANK1      = 0x2,
+	ROLLOFF_RAM              = 0x3,
+	DEMOSAIC_LUT_RAM_BANK0   = 0x4,
+	DEMOSAIC_LUT_RAM_BANK1   = 0x5,
+	STATS_BHIST_RAM0         = 0x6,
+	STATS_BHIST_RAM1         = 0x7,
+	RGBLUT_RAM_CH0_BANK0     = 0x8,
+	RGBLUT_RAM_CH0_BANK1     = 0x9,
+	RGBLUT_RAM_CH1_BANK0     = 0xa,
+	RGBLUT_RAM_CH1_BANK1     = 0xb,
+	RGBLUT_RAM_CH2_BANK0     = 0xc,
+	RGBLUT_RAM_CH2_BANK1     = 0xd,
+	RGBLUT_CHX_BANK0         = 0xe,
+	RGBLUT_CHX_BANK1         = 0xf,
+	STATS_IHIST_RAM          = 0x10,
+	LUMA_ADAPT_LUT_RAM_BANK0 = 0x11,
+	LUMA_ADAPT_LUT_RAM_BANK1 = 0x12
+};
+
+enum  VFE_STATE {
+	VFE_STATE_IDLE,
+	VFE_STATE_ACTIVE
+};
+
+#define V32_DUMMY_0               0
+#define V32_SET_CLK               1
+#define V32_RESET                 2
+#define V32_START                 3
+#define V32_TEST_GEN_START        4
+#define V32_OPERATION_CFG         5
+#define V32_AXI_OUT_CFG           6
+#define V32_CAMIF_CFG             7
+#define V32_AXI_INPUT_CFG         8
+#define V32_BLACK_LEVEL_CFG       9
+#define V32_ROLL_OFF_CFG          10
+#define V32_DEMUX_CFG             11
+#define V32_FOV_CFG               12
+#define V32_MAIN_SCALER_CFG       13
+#define V32_WB_CFG                14
+#define V32_COLOR_COR_CFG         15
+#define V32_RGB_G_CFG             16
+#define V32_LA_CFG                17
+#define V32_CHROMA_EN_CFG         18
+#define V32_CHROMA_SUP_CFG        19
+#define V32_MCE_CFG               20
+#define V32_SK_ENHAN_CFG          21
+#define V32_ASF_CFG               22
+#define V32_S2Y_CFG               23
+#define V32_S2CbCr_CFG            24
+#define V32_CHROMA_SUBS_CFG       25
+#define V32_OUT_CLAMP_CFG         26
+#define V32_FRAME_SKIP_CFG        27
+#define V32_DUMMY_1               28
+#define V32_DUMMY_2               29
+#define V32_DUMMY_3               30
+#define V32_UPDATE                31
+#define V32_BL_LVL_UPDATE         32
+#define V32_DEMUX_UPDATE          33
+#define V32_FOV_UPDATE            34
+#define V32_MAIN_SCALER_UPDATE    35
+#define V32_WB_UPDATE             36
+#define V32_COLOR_COR_UPDATE      37
+#define V32_RGB_G_UPDATE          38
+#define V32_LA_UPDATE             39
+#define V32_CHROMA_EN_UPDATE      40
+#define V32_CHROMA_SUP_UPDATE     41
+#define V32_MCE_UPDATE            42
+#define V32_SK_ENHAN_UPDATE       43
+#define V32_S2CbCr_UPDATE         44
+#define V32_S2Y_UPDATE            45
+#define V32_ASF_UPDATE            46
+#define V32_FRAME_SKIP_UPDATE     47
+#define V32_CAMIF_FRAME_UPDATE    48
+#define V32_STATS_AF_UPDATE       49
+#define V32_STATS_AE_UPDATE       50
+#define V32_STATS_AWB_UPDATE      51
+#define V32_STATS_RS_UPDATE       52
+#define V32_STATS_CS_UPDATE       53
+#define V32_STATS_SKIN_UPDATE     54
+#define V32_STATS_IHIST_UPDATE    55
+#define V32_DUMMY_4               56
+#define V32_EPOCH1_ACK            57
+#define V32_EPOCH2_ACK            58
+#define V32_START_RECORDING       59
+#define V32_STOP_RECORDING        60
+#define V32_DUMMY_5               61
+#define V32_DUMMY_6               62
+#define V32_CAPTURE               63
+#define V32_DUMMY_7               64
+#define V32_STOP                  65
+#define V32_GET_HW_VERSION        66
+#define V32_GET_FRAME_SKIP_COUNTS 67
+#define V32_OUTPUT1_BUFFER_ENQ    68
+#define V32_OUTPUT2_BUFFER_ENQ    69
+#define V32_OUTPUT3_BUFFER_ENQ    70
+#define V32_JPEG_OUT_BUF_ENQ      71
+#define V32_RAW_OUT_BUF_ENQ       72
+#define V32_RAW_IN_BUF_ENQ        73
+#define V32_STATS_AF_ENQ          74
+#define V32_STATS_AE_ENQ          75
+#define V32_STATS_AWB_ENQ         76
+#define V32_STATS_RS_ENQ          77
+#define V32_STATS_CS_ENQ          78
+#define V32_STATS_SKIN_ENQ        79
+#define V32_STATS_IHIST_ENQ       80
+#define V32_DUMMY_8               81
+#define V32_JPEG_ENC_CFG          82
+#define V32_DUMMY_9               83
+#define V32_STATS_AF_START        84
+#define V32_STATS_AF_STOP         85
+#define V32_STATS_AE_START        86
+#define V32_STATS_AE_STOP         87
+#define V32_STATS_AWB_START       88
+#define V32_STATS_AWB_STOP        89
+#define V32_STATS_RS_START        90
+#define V32_STATS_RS_STOP         91
+#define V32_STATS_CS_START        92
+#define V32_STATS_CS_STOP         93
+#define V32_STATS_SKIN_START      94
+#define V32_STATS_SKIN_STOP       95
+#define V32_STATS_IHIST_START     96
+#define V32_STATS_IHIST_STOP      97
+#define V32_DUMMY_10              98
+#define V32_SYNC_TIMER_SETTING    99
+#define V32_ASYNC_TIMER_SETTING   100
+#define V32_LIVESHOT              101
+#define V32_LA_SETUP              102
+
+#define V32_LINEARIZATION         103
+#define V32_DEMOSAICV3            104
+#define V32_DEMOSAICV3_ABCC_CFG   105
+#define V32_DEMOSAICV3_DBCC_CFG       106
+#define V32_DEMOSAICV3_DBPC_CFG       107
+#define V32_DEMOSAICV3_ABF_CFG        108
+#define V32_DEMOSAICV3_ABCC_UPDATE    109
+#define V32_DEMOSAICV3_DBCC_UPDATE    110
+#define V32_DEMOSAICV3_DBPC_UPDATE    111
+#define V32_EZTUNE_CFG            112
+
+#define V32_CLF_CFG               118
+#define V32_CLF_UPDATE            119
+#define V32_STATS_IHIST3_2_START  120
+#define V32_STATS_IHIST3_2_UPDATE 121
+#define V32_CAMIF3_2_CONFIG       122
+
+#define V32_CAMIF_OFF             0x000001E4
+#define V32_CAMIF_LEN             32
+
+#define V32_DEMUX_OFF             0x00000284
+#define V32_DEMUX_LEN             20
+
+#define V32_DEMOSAICV3_0_OFF      0x00000298
+#define V32_DEMOSAICV3_0_LEN      4
+#define V32_DEMOSAICV3_1_OFF      0x0000061C
+#define V32_DEMOSAICV3_1_LEN      88
+/* BPC     */
+#define V32_DEMOSAIC_2_OFF        0x0000029C
+#define V32_DEMOSAIC_2_LEN        8
+
+#define V32_OUT_CLAMP_OFF         0x00000524
+#define V32_OUT_CLAMP_LEN         8
+
+#define V32_OPERATION_CFG_LEN     32
+
+#define V32_AXI_OUT_OFF           0x00000038
+#define V32_AXI_OUT_LEN           212
+#define V32_AXI_CH_INF_LEN        24
+#define V32_AXI_CFG_LEN           47
+
+#define V32_FRAME_SKIP_OFF        0x00000504
+#define V32_FRAME_SKIP_LEN        32
+
+#define V32_CHROMA_SUBS_OFF       0x000004F8
+#define V32_CHROMA_SUBS_LEN       12
+
+#define V32_FOV_OFF           0x00000360
+#define V32_FOV_LEN           8
+
+#define V32_MAIN_SCALER_OFF 0x00000368
+#define V32_MAIN_SCALER_LEN 28
+
+#define V32_S2Y_OFF 0x000004D0
+#define V32_S2Y_LEN 20
+
+#define V32_S2CbCr_OFF 0x000004E4
+#define V32_S2CbCr_LEN 20
+
+#define V32_CHROMA_EN_OFF 0x000003C4
+#define V32_CHROMA_EN_LEN 36
+
+#define V32_SYNC_TIMER_OFF      0x0000020C
+#define V32_SYNC_TIMER_POLARITY_OFF 0x00000234
+#define V32_TIMER_SELECT_OFF        0x0000025C
+#define V32_SYNC_TIMER_LEN 28
+
+#define V32_ASYNC_TIMER_OFF 0x00000238
+#define V32_ASYNC_TIMER_LEN 28
+
+#define V32_BLACK_LEVEL_OFF 0x00000264
+#define V32_BLACK_LEVEL_LEN 16
+
+#define V32_ROLL_OFF_CFG_OFF 0x00000274
+#define V32_ROLL_OFF_CFG_LEN 16
+
+#define V32_COLOR_COR_OFF 0x00000388
+#define V32_COLOR_COR_LEN 52
+
+#define V32_WB_OFF 0x00000384
+#define V32_WB_LEN 4
+
+#define V32_RGB_G_OFF 0x000003BC
+#define V32_RGB_G_LEN 4
+
+#define V32_LA_OFF 0x000003C0
+#define V32_LA_LEN 4
+
+#define V32_SCE_OFF 0x00000418
+#define V32_SCE_LEN 136
+
+#define V32_CHROMA_SUP_OFF 0x000003E8
+#define V32_CHROMA_SUP_LEN 12
+
+#define V32_MCE_OFF 0x000003E8
+#define V32_MCE_LEN 36
+#define V32_STATS_AF_OFF 0x0000053c
+#define V32_STATS_AF_LEN 16
+
+#define V32_STATS_AE_OFF 0x00000534
+#define V32_STATS_AE_LEN 8
+
+#define V32_STATS_AWB_OFF 0x0000054c
+#define V32_STATS_AWB_LEN 32
+
+#define V32_STATS_IHIST_OFF 0x0000057c
+#define V32_STATS_IHIST_LEN 8
+
+#define V32_STATS_RS_OFF 0x0000056c
+#define V32_STATS_RS_LEN 8
+
+#define V32_STATS_CS_OFF 0x00000574
+#define V32_STATS_CS_LEN 8
+
+
+#define V32_ASF_OFF 0x000004A0
+#define V32_ASF_LEN 48
+#define V32_ASF_UPDATE_LEN 36
+
+#define V32_CAPTURE_LEN 4
+
+#define V32_LINEARIZATION_OFF1 0x00000264
+#define V32_LINEARIZATION_LEN1 16
+
+#define V32_LINEARIZATION_OFF2 0x0000067C
+#define V32_LINEARIZATION_LEN2 52
+
+#define V32_DEMOSAICV3_OFF 0x00000298
+#define V32_DEMOSAICV3_LEN 4
+
+#define V32_DEMOSAICV3_DBPC_CFG_OFF  0x0000029C
+#define V32_DEMOSAICV3_DBPC_LEN 4
+
+#define V32_DEMOSAICV3_DBPC_CFG_OFF0 0x000002a0
+#define V32_DEMOSAICV3_DBPC_CFG_OFF1 0x00000604
+#define V32_DEMOSAICV3_DBPC_CFG_OFF2 0x00000608
+
+#define V32_DEMOSAICV3_DBCC_OFF 0x0000060C
+#define V32_DEMOSAICV3_DBCC_LEN 16
+
+#define V32_DEMOSAICV3_ABF_OFF 0x0000029C
+#define V32_DEMOSAICV3_ABF_LEN
+
+#define V32_EZTUNE_CFG_OFF 0x00000010
+#define V32_EZTUNE_CFG_LEN 4
+
+struct vfe_cmd_hw_version {
+	uint32_t minorVersion;
+	uint32_t majorVersion;
+	uint32_t coreVersion;
+};
+
+enum VFE_AXI_OUTPUT_MODE {
+	VFE_AXI_OUTPUT_MODE_Output1,
+	VFE_AXI_OUTPUT_MODE_Output2,
+	VFE_AXI_OUTPUT_MODE_Output1AndOutput2,
+	VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2,
+	VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1,
+	VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2,
+	VFE_AXI_LAST_OUTPUT_MODE_ENUM
+};
+
+enum VFE_RAW_WR_PATH_SEL {
+	VFE_RAW_OUTPUT_DISABLED,
+	VFE_RAW_OUTPUT_ENC_CBCR_PATH,
+	VFE_RAW_OUTPUT_VIEW_CBCR_PATH,
+	VFE_RAW_OUTPUT_PATH_INVALID
+};
+
+
+#define VFE_AXI_OUTPUT_BURST_LENGTH     4
+#define VFE_MAX_NUM_FRAGMENTS_PER_FRAME 4
+#define VFE_AXI_OUTPUT_CFG_FRAME_COUNT  3
+
+struct vfe_cmds_per_write_master {
+	uint16_t imageWidth;
+	uint16_t imageHeight;
+	uint16_t outRowCount;
+	uint16_t outRowIncrement;
+	uint32_t outFragments[VFE_AXI_OUTPUT_CFG_FRAME_COUNT]
+		[VFE_MAX_NUM_FRAGMENTS_PER_FRAME];
+};
+
+struct vfe_cmds_axi_per_output_path {
+	uint8_t fragmentCount;
+	struct vfe_cmds_per_write_master firstWM;
+	struct vfe_cmds_per_write_master secondWM;
+};
+
+enum VFE_AXI_BURST_LENGTH {
+	VFE_AXI_BURST_LENGTH_IS_2  = 2,
+	VFE_AXI_BURST_LENGTH_IS_4  = 4,
+	VFE_AXI_BURST_LENGTH_IS_8  = 8,
+	VFE_AXI_BURST_LENGTH_IS_16 = 16
+};
+
+
+struct vfe_cmd_fov_crop_config {
+	uint8_t enable;
+	uint16_t firstPixel;
+	uint16_t lastPixel;
+	uint16_t firstLine;
+	uint16_t lastLine;
+};
+
+struct vfe_cmds_main_scaler_stripe_init {
+	uint16_t MNCounterInit;
+	uint16_t phaseInit;
+};
+
+struct vfe_cmds_scaler_one_dimension {
+	uint8_t  enable;
+	uint16_t inputSize;
+	uint16_t outputSize;
+	uint32_t phaseMultiplicationFactor;
+	uint8_t  interpolationResolution;
+};
+
+struct vfe_cmd_main_scaler_config {
+	uint8_t enable;
+	struct vfe_cmds_scaler_one_dimension    hconfig;
+	struct vfe_cmds_scaler_one_dimension    vconfig;
+	struct vfe_cmds_main_scaler_stripe_init MNInitH;
+	struct vfe_cmds_main_scaler_stripe_init MNInitV;
+};
+
+struct vfe_cmd_scaler2_config {
+	uint8_t enable;
+	struct vfe_cmds_scaler_one_dimension hconfig;
+	struct vfe_cmds_scaler_one_dimension vconfig;
+};
+
+
+struct vfe_cmd_frame_skip_update {
+	uint32_t output1Pattern;
+	uint32_t output2Pattern;
+};
+
+struct vfe_cmd_output_clamp_config {
+	uint8_t minCh0;
+	uint8_t minCh1;
+	uint8_t minCh2;
+	uint8_t maxCh0;
+	uint8_t maxCh1;
+	uint8_t maxCh2;
+};
+
+struct vfe_cmd_chroma_subsample_config {
+	uint8_t enable;
+	uint8_t cropEnable;
+	uint8_t vsubSampleEnable;
+	uint8_t hsubSampleEnable;
+	uint8_t vCosited;
+	uint8_t hCosited;
+	uint8_t vCositedPhase;
+	uint8_t hCositedPhase;
+	uint16_t cropWidthFirstPixel;
+	uint16_t cropWidthLastPixel;
+	uint16_t cropHeightFirstLine;
+	uint16_t cropHeightLastLine;
+};
+
+enum VFE_START_PIXEL_PATTERN {
+	VFE_BAYER_RGRGRG,
+	VFE_BAYER_GRGRGR,
+	VFE_BAYER_BGBGBG,
+	VFE_BAYER_GBGBGB,
+	VFE_YUV_YCbYCr,
+	VFE_YUV_YCrYCb,
+	VFE_YUV_CbYCrY,
+	VFE_YUV_CrYCbY
+};
+
+enum VFE_BUS_RD_INPUT_PIXEL_PATTERN {
+	VFE_BAYER_RAW,
+	VFE_YUV_INTERLEAVED,
+	VFE_YUV_PSEUDO_PLANAR_Y,
+	VFE_YUV_PSEUDO_PLANAR_CBCR
+};
+
+enum VFE_YUV_INPUT_COSITING_MODE {
+	VFE_YUV_COSITED,
+	VFE_YUV_INTERPOLATED
+};
+
+
+/* 13*1  */
+#define VFE32_ROLL_OFF_INIT_TABLE_SIZE  13
+/* 13*16 */
+#define VFE32_ROLL_OFF_DELTA_TABLE_SIZE 208
+
+#define VFE32_GAMMA_NUM_ENTRIES  64
+
+#define VFE32_LA_TABLE_LENGTH    64
+
+struct vfe_cmds_demosaic_abf {
+	uint8_t   enable;
+	uint8_t   forceOn;
+	uint8_t   shift;
+	uint16_t  lpThreshold;
+	uint16_t  max;
+	uint16_t  min;
+	uint8_t   ratio;
+};
+
+struct vfe_cmds_demosaic_bpc {
+	uint8_t   enable;
+	uint16_t  fmaxThreshold;
+	uint16_t  fminThreshold;
+	uint16_t  redDiffThreshold;
+	uint16_t  blueDiffThreshold;
+	uint16_t  greenDiffThreshold;
+};
+
+struct vfe_cmd_demosaic_config {
+	uint8_t   enable;
+	uint8_t   slopeShift;
+	struct vfe_cmds_demosaic_abf abfConfig;
+	struct vfe_cmds_demosaic_bpc bpcConfig;
+};
+
+struct vfe_cmd_demosaic_bpc_update {
+	struct vfe_cmds_demosaic_bpc bpcUpdate;
+};
+
+struct vfe_cmd_demosaic_abf_update {
+	struct vfe_cmds_demosaic_abf abfUpdate;
+};
+
+struct vfe_cmd_white_balance_config {
+	uint8_t  enable;
+	uint16_t ch2Gain;
+	uint16_t ch1Gain;
+	uint16_t ch0Gain;
+};
+
+enum VFE_COLOR_CORRECTION_COEF_QFACTOR {
+	COEF_IS_Q7_SIGNED,
+	COEF_IS_Q8_SIGNED,
+	COEF_IS_Q9_SIGNED,
+	COEF_IS_Q10_SIGNED
+};
+
+struct vfe_cmd_color_correction_config {
+	uint8_t     enable;
+	enum VFE_COLOR_CORRECTION_COEF_QFACTOR coefQFactor;
+	int16_t  C0;
+	int16_t  C1;
+	int16_t  C2;
+	int16_t  C3;
+	int16_t  C4;
+	int16_t  C5;
+	int16_t  C6;
+	int16_t  C7;
+	int16_t  C8;
+	int16_t  K0;
+	int16_t  K1;
+	int16_t  K2;
+};
+
+#define VFE_LA_TABLE_LENGTH 64
+
+struct vfe_cmd_la_config {
+	uint8_t enable;
+	int16_t table[VFE_LA_TABLE_LENGTH];
+};
+
+#define VFE_GAMMA_TABLE_LENGTH 256
+enum VFE_RGB_GAMMA_TABLE_SELECT {
+	RGB_GAMMA_CH0_SELECTED,
+	RGB_GAMMA_CH1_SELECTED,
+	RGB_GAMMA_CH2_SELECTED,
+	RGB_GAMMA_CH0_CH1_SELECTED,
+	RGB_GAMMA_CH0_CH2_SELECTED,
+	RGB_GAMMA_CH1_CH2_SELECTED,
+	RGB_GAMMA_CH0_CH1_CH2_SELECTED
+};
+
+struct vfe_cmd_rgb_gamma_config {
+	uint8_t enable;
+	enum VFE_RGB_GAMMA_TABLE_SELECT channelSelect;
+	int16_t table[VFE_GAMMA_TABLE_LENGTH];
+};
+
+struct vfe_cmd_chroma_enhan_config {
+	uint8_t  enable;
+	int16_t am;
+	int16_t ap;
+	int16_t bm;
+	int16_t bp;
+	int16_t cm;
+	int16_t cp;
+	int16_t dm;
+	int16_t dp;
+	int16_t kcr;
+	int16_t kcb;
+	int16_t RGBtoYConversionV0;
+	int16_t RGBtoYConversionV1;
+	int16_t RGBtoYConversionV2;
+	uint8_t RGBtoYConversionOffset;
+};
+
+struct vfe_cmd_chroma_suppression_config {
+	uint8_t enable;
+	uint8_t m1;
+	uint8_t m3;
+	uint8_t n1;
+	uint8_t n3;
+	uint8_t nn1;
+	uint8_t mm1;
+};
+
+struct vfe_cmd_asf_config {
+	uint8_t enable;
+	uint8_t smoothFilterEnabled;
+	uint8_t sharpMode;
+	uint8_t smoothCoefCenter;
+	uint8_t smoothCoefSurr;
+	uint8_t normalizeFactor;
+	uint8_t sharpK1;
+	uint8_t sharpK2;
+	uint8_t sharpThreshE1;
+	int8_t sharpThreshE2;
+	int8_t sharpThreshE3;
+	int8_t sharpThreshE4;
+	int8_t sharpThreshE5;
+	int8_t filter1Coefficients[9];
+	int8_t filter2Coefficients[9];
+	uint8_t  cropEnable;
+	uint16_t cropFirstPixel;
+	uint16_t cropLastPixel;
+	uint16_t cropFirstLine;
+	uint16_t cropLastLine;
+};
+
+struct vfe_cmd_asf_update {
+	uint8_t enable;
+	uint8_t smoothFilterEnabled;
+	uint8_t sharpMode;
+	uint8_t smoothCoefCenter;
+	uint8_t smoothCoefSurr;
+	uint8_t normalizeFactor;
+	uint8_t sharpK1;
+	uint8_t sharpK2;
+	uint8_t sharpThreshE1;
+	int8_t  sharpThreshE2;
+	int8_t  sharpThreshE3;
+	int8_t  sharpThreshE4;
+	int8_t  sharpThreshE5;
+	int8_t  filter1Coefficients[9];
+	int8_t  filter2Coefficients[9];
+	uint8_t cropEnable;
+};
+
+enum VFE_TEST_GEN_SYNC_EDGE {
+	VFE_TEST_GEN_SYNC_EDGE_ActiveHigh,
+	VFE_TEST_GEN_SYNC_EDGE_ActiveLow
+};
+
+
+struct vfe_cmd_bus_pm_start {
+	uint8_t output2YWrPmEnable;
+	uint8_t output2CbcrWrPmEnable;
+	uint8_t output1YWrPmEnable;
+	uint8_t output1CbcrWrPmEnable;
+};
+
+struct  vfe_frame_skip_counts {
+	uint32_t  totalFrameCount;
+	uint32_t  output1Count;
+	uint32_t  output2Count;
+};
+
+enum VFE_AXI_RD_UNPACK_HBI_SEL {
+	VFE_AXI_RD_HBI_32_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_64_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_128_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_256_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_512_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_1024_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_2048_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_4096_CLOCK_CYCLES
+};
+
+enum VFE32_MESSAGE_ID {
+	MSG_ID_RESET_ACK, /* 0 */
+	MSG_ID_START_ACK,
+	MSG_ID_STOP_ACK,
+	MSG_ID_UPDATE_ACK,
+	MSG_ID_OUTPUT_P,
+	MSG_ID_OUTPUT_T,
+	MSG_ID_OUTPUT_S,
+	MSG_ID_OUTPUT_V,
+	MSG_ID_SNAPSHOT_DONE,
+	MSG_ID_STATS_AEC,
+	MSG_ID_STATS_AF, /* 10 */
+	MSG_ID_STATS_AWB,
+	MSG_ID_STATS_RS,
+	MSG_ID_STATS_CS,
+	MSG_ID_STATS_IHIST,
+	MSG_ID_STATS_SKIN,
+	MSG_ID_EPOCH1,
+	MSG_ID_EPOCH2,
+	MSG_ID_SYNC_TIMER0_DONE,
+	MSG_ID_SYNC_TIMER1_DONE,
+	MSG_ID_SYNC_TIMER2_DONE, /* 20 */
+	MSG_ID_ASYNC_TIMER0_DONE,
+	MSG_ID_ASYNC_TIMER1_DONE,
+	MSG_ID_ASYNC_TIMER2_DONE,
+	MSG_ID_ASYNC_TIMER3_DONE,
+	MSG_ID_AE_OVERFLOW,
+	MSG_ID_AF_OVERFLOW,
+	MSG_ID_AWB_OVERFLOW,
+	MSG_ID_RS_OVERFLOW,
+	MSG_ID_CS_OVERFLOW,
+	MSG_ID_IHIST_OVERFLOW, /* 30 */
+	MSG_ID_SKIN_OVERFLOW,
+	MSG_ID_AXI_ERROR,
+	MSG_ID_CAMIF_OVERFLOW,
+	MSG_ID_VIOLATION,
+	MSG_ID_CAMIF_ERROR,
+	MSG_ID_BUS_OVERFLOW,
+	MSG_ID_SOF_ACK,
+	MSG_ID_STOP_REC_ACK,
+};
+
+struct vfe_msg_stats {
+	uint32_t    buffer;
+	uint32_t    frameCounter;
+};
+
+
+struct vfe_frame_bpc_info {
+	uint32_t greenDefectPixelCount;
+	uint32_t redBlueDefectPixelCount;
+};
+
+struct vfe_frame_asf_info {
+	uint32_t  asfMaxEdge;
+	uint32_t  asfHbiCount;
+};
+
+struct vfe_msg_camif_status {
+	uint8_t  camifState;
+	uint32_t pixelCount;
+	uint32_t lineCount;
+};
+
+
+struct vfe32_irq_status {
+	uint32_t vfeIrqStatus0;
+	uint32_t vfeIrqStatus1;
+	uint32_t camifStatus;
+	uint32_t demosaicStatus;
+	uint32_t asfMaxEdge;
+};
+
+struct vfe_msg_output {
+	uint8_t   output_id;
+	uint32_t  yBuffer;
+	uint32_t  cbcrBuffer;
+	struct vfe_frame_bpc_info bpcInfo;
+	struct vfe_frame_asf_info asfInfo;
+	uint32_t  frameCounter;
+};
+
+struct vfe_message {
+	enum VFE32_MESSAGE_ID _d;
+	union {
+		struct vfe_msg_output              msgOut;
+		struct vfe_msg_stats               msgStats;
+		struct vfe_msg_camif_status        msgCamifError;
+	} _u;
+};
+
+/* New one for 7x30 */
+struct msm_vfe32_cmd {
+	int32_t  id;
+	uint16_t length;
+	void     *value;
+};
+
+#define V32_PREVIEW_AXI_FLAG  0x00000001
+#define V32_SNAPSHOT_AXI_FLAG (0x00000001<<1)
+
+struct vfe32_cmd_type {
+	uint16_t id;
+	uint32_t length;
+	uint32_t offset;
+	uint32_t flag;
+};
+
+struct vfe32_free_buf {
+	struct list_head node;
+	uint32_t paddr;
+	uint32_t y_off;
+	uint32_t cbcr_off;
+};
+
+struct vfe32_output_ch {
+	struct list_head free_buf_queue;
+	spinlock_t free_buf_lock;
+	uint16_t output_fmt;
+	int8_t ch0;
+	int8_t ch1;
+	int8_t ch2;
+	uint32_t  capture_cnt;
+	uint32_t  frame_drop_cnt;
+};
+
+/* no error irq in mask 0 */
+#define VFE32_IMASK_ERROR_ONLY_0  0x0
+/* when normal case, don't want to block error status. */
+/* bit 0-21 are error irq bits */
+#define VFE32_IMASK_ERROR_ONLY_1               0x005FFFFF
+#define VFE32_IMASK_CAMIF_ERROR               (0x00000001<<0)
+#define VFE32_IMASK_BHIST_OVWR                (0x00000001<<1)
+#define VFE32_IMASK_STATS_CS_OVWR             (0x00000001<<2)
+#define VFE32_IMASK_STATS_IHIST_OVWR          (0x00000001<<3)
+#define VFE32_IMASK_REALIGN_BUF_Y_OVFL        (0x00000001<<4)
+#define VFE32_IMASK_REALIGN_BUF_CB_OVFL       (0x00000001<<5)
+#define VFE32_IMASK_REALIGN_BUF_CR_OVFL       (0x00000001<<6)
+#define VFE32_IMASK_VIOLATION                 (0x00000001<<7)
+#define VFE32_IMASK_IMG_MAST_0_BUS_OVFL       (0x00000001<<8)
+#define VFE32_IMASK_IMG_MAST_1_BUS_OVFL       (0x00000001<<9)
+#define VFE32_IMASK_IMG_MAST_2_BUS_OVFL       (0x00000001<<10)
+#define VFE32_IMASK_IMG_MAST_3_BUS_OVFL       (0x00000001<<11)
+#define VFE32_IMASK_IMG_MAST_4_BUS_OVFL       (0x00000001<<12)
+#define VFE32_IMASK_IMG_MAST_5_BUS_OVFL       (0x00000001<<13)
+#define VFE32_IMASK_IMG_MAST_6_BUS_OVFL       (0x00000001<<14)
+#define VFE32_IMASK_STATS_AE_BG_BUS_OVFL      (0x00000001<<15)
+#define VFE32_IMASK_STATS_AF_BF_BUS_OVFL      (0x00000001<<16)
+#define VFE32_IMASK_STATS_AWB_BUS_OVFL        (0x00000001<<17)
+#define VFE32_IMASK_STATS_RS_BUS_OVFL         (0x00000001<<18)
+#define VFE32_IMASK_STATS_CS_BUS_OVFL         (0x00000001<<19)
+#define VFE32_IMASK_STATS_IHIST_BUS_OVFL      (0x00000001<<20)
+#define VFE32_IMASK_STATS_SKIN_BHIST_BUS_OVFL (0x00000001<<21)
+#define VFE32_IMASK_AXI_ERROR                 (0x00000001<<22)
+
+struct vfe32_output_path {
+	uint16_t output_mode;     /* bitmask  */
+
+	struct vfe32_output_ch out0; /* preview and thumbnail */
+	struct vfe32_output_ch out1; /* snapshot */
+	struct vfe32_output_ch out2; /* video    */
+};
+
+struct vfe32_frame_extra {
+	uint32_t greenDefectPixelCount;
+	uint32_t redBlueDefectPixelCount;
+
+	uint32_t  asfMaxEdge;
+	uint32_t  asfHbiCount;
+
+	uint32_t yWrPmStats0;
+	uint32_t yWrPmStats1;
+	uint32_t cbcrWrPmStats0;
+	uint32_t cbcrWrPmStats1;
+
+	uint32_t  frameCounter;
+};
+
+#define VFE_DISABLE_ALL_IRQS            0
+#define VFE_CLEAR_ALL_IRQS              0xffffffff
+
+#define VFE_HW_VERSION			0x00000000
+#define VFE_GLOBAL_RESET                0x00000004
+#define VFE_MODULE_RESET		0x00000008
+#define VFE_CGC_OVERRIDE                0x0000000C
+#define VFE_MODULE_CFG                  0x00000010
+#define VFE_CFG				0x00000014
+#define VFE_IRQ_CMD                     0x00000018
+#define VFE_IRQ_MASK_0                  0x0000001C
+#define VFE_IRQ_MASK_1                  0x00000020
+#define VFE_IRQ_CLEAR_0                 0x00000024
+#define VFE_IRQ_CLEAR_1                 0x00000028
+#define VFE_IRQ_STATUS_0                0x0000002C
+#define VFE_IRQ_STATUS_1                0x00000030
+#define VFE_IRQ_COMP_MASK               0x00000034
+#define VFE_BUS_CMD                     0x00000038
+#define VFE_BUS_PING_PONG_STATUS        0x00000180
+#define VFE_AXI_CMD                     0x000001D8
+#define VFE_AXI_STATUS        0x000001DC
+#define VFE_BUS_STATS_PING_PONG_BASE    0x000000F4
+
+#define VFE_BUS_STATS_AEC_WR_PING_ADDR    0x000000F4
+#define VFE_BUS_STATS_AEC_WR_PONG_ADDR    0x000000F8
+#define VFE_BUS_STATS_AEC_UB_CFG          0x000000FC
+#define VFE_BUS_STATS_AF_WR_PING_ADDR     0x00000100
+#define VFE_BUS_STATS_AF_WR_PONG_ADDR     0x00000104
+#define VFE_BUS_STATS_AF_UB_CFG           0x00000108
+#define VFE_BUS_STATS_AWB_WR_PING_ADDR    0x0000010C
+#define VFE_BUS_STATS_AWB_WR_PONG_ADDR    0x00000110
+#define VFE_BUS_STATS_AWB_UB_CFG          0x00000114
+#define VFE_BUS_STATS_RS_WR_PING_ADDR    0x00000118
+#define VFE_BUS_STATS_RS_WR_PONG_ADDR    0x0000011C
+#define VFE_BUS_STATS_RS_UB_CFG          0x00000120
+
+#define VFE_BUS_STATS_CS_WR_PING_ADDR    0x00000124
+#define VFE_BUS_STATS_CS_WR_PONG_ADDR    0x00000128
+#define VFE_BUS_STATS_CS_UB_CFG          0x0000012C
+#define VFE_BUS_STATS_HIST_WR_PING_ADDR   0x00000130
+#define VFE_BUS_STATS_HIST_WR_PONG_ADDR   0x00000134
+#define VFE_BUS_STATS_HIST_UB_CFG          0x00000138
+#define VFE_BUS_STATS_SKIN_WR_PING_ADDR    0x0000013C
+#define VFE_BUS_STATS_SKIN_WR_PONG_ADDR    0x00000140
+#define VFE_BUS_STATS_SKIN_UB_CFG          0x00000144
+#define VFE_CAMIF_COMMAND               0x000001E0
+#define VFE_CAMIF_STATUS                0x00000204
+#define VFE_REG_UPDATE_CMD              0x00000260
+#define VFE_DEMUX_GAIN_0                0x00000288
+#define VFE_DEMUX_GAIN_1                0x0000028C
+#define VFE_CHROMA_UP                   0x0000035C
+#define VFE_FRAMEDROP_ENC_Y_CFG         0x00000504
+#define VFE_FRAMEDROP_ENC_CBCR_CFG      0x00000508
+#define VFE_FRAMEDROP_ENC_Y_PATTERN     0x0000050C
+#define VFE_FRAMEDROP_ENC_CBCR_PATTERN  0x00000510
+#define VFE_FRAMEDROP_VIEW_Y            0x00000514
+#define VFE_FRAMEDROP_VIEW_CBCR         0x00000518
+#define VFE_FRAMEDROP_VIEW_Y_PATTERN    0x0000051C
+#define VFE_FRAMEDROP_VIEW_CBCR_PATTERN 0x00000520
+#define VFE_CLAMP_MAX                   0x00000524
+#define VFE_CLAMP_MIN                   0x00000528
+#define VFE_REALIGN_BUF                 0x0000052C
+#define VFE_STATS_CFG                   0x00000530
+#define VFE_DMI_CFG                     0x00000598
+#define VFE_DMI_ADDR                    0x0000059C
+#define VFE_DMI_DATA_LO                 0x000005A4
+#define VFE_BUS_IO_FORMAT_CFG		0x000006F8
+#define VFE_PIXEL_IF_CFG                0x000006FC
+
+struct vfe_stats_control {
+	uint8_t  ackPending;
+	uint32_t nextFrameAddrBuf;
+	uint32_t droppedStatsFrameCount;
+	uint32_t bufToRender;
+};
+
+struct vfe32_ctrl_type {
+	uint16_t operation_mode;     /* streaming or snapshot */
+	struct vfe32_output_path outpath;
+
+	uint32_t vfeImaskCompositePacked;
+
+	spinlock_t  stop_flag_lock;
+	spinlock_t  update_ack_lock;
+	spinlock_t  state_lock;
+	spinlock_t  io_lock;
+
+	spinlock_t  aec_ack_lock;
+	spinlock_t  awb_ack_lock;
+	spinlock_t  af_ack_lock;
+
+	uint32_t extlen;
+	void *extdata;
+
+	int8_t start_ack_pending;
+	int8_t stop_ack_pending;
+	int8_t reset_ack_pending;
+	int8_t update_ack_pending;
+	int8_t req_start_video_rec;
+	int8_t req_stop_video_rec;
+
+	spinlock_t  tasklet_lock;
+	struct list_head tasklet_q;
+	int vfeirq;
+	void __iomem *vfebase;
+	void *syncdata;
+
+	struct resource	*vfemem;
+	struct resource *vfeio;
+
+	uint32_t stats_comp;
+	atomic_t vstate;
+	uint32_t vfe_capture_count;
+	uint32_t sync_timer_repeat_count;
+	uint32_t sync_timer_state;
+	uint32_t sync_timer_number;
+
+	uint32_t vfeFrameId;
+	uint32_t output1Pattern;
+	uint32_t output1Period;
+	uint32_t output2Pattern;
+	uint32_t output2Period;
+	uint32_t vfeFrameSkipCount;
+	uint32_t vfeFrameSkipPeriod;
+	struct vfe_stats_control afStatsControl;
+	struct vfe_stats_control awbStatsControl;
+	struct vfe_stats_control aecStatsControl;
+	struct vfe_stats_control ihistStatsControl;
+	struct vfe_stats_control rsStatsControl;
+	struct vfe_stats_control csStatsControl;
+
+	/* v4l2 subdev */
+	struct v4l2_subdev *subdev;
+};
+
+#define statsAeNum      0
+#define statsAfNum      1
+#define statsAwbNum     2
+#define statsRsNum      3
+#define statsCsNum      4
+#define statsIhistNum   5
+#define statsSkinNum    6
+
+struct vfe_cmd_stats_ack {
+	uint32_t  nextStatsBuf;
+};
+
+#define VFE_STATS_BUFFER_COUNT            3
+
+struct vfe_cmd_stats_buf {
+	uint32_t statsBuf[VFE_STATS_BUFFER_COUNT];
+};
+#endif /* __MSM_VFE32_H__ */
diff --git a/drivers/media/video/msm/msm_vfe7x.c b/drivers/media/video/msm/msm_vfe7x.c
new file mode 100644
index 0000000..316aacf
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe7x.c
@@ -0,0 +1,783 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/msm_adsp.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <mach/msm_adsp.h>
+#include <mach/clk.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include "msm_vfe7x.h"
+#include <linux/pm_qos_params.h>
+
+#define QDSP_CMDQUEUE 25
+
+#define VFE_RESET_CMD 0
+#define VFE_START_CMD 1
+#define VFE_STOP_CMD  2
+#define VFE_FRAME_ACK 20
+#define STATS_AF_ACK  21
+#define STATS_WE_ACK  22
+
+#define MSG_STOP_ACK  1
+#define MSG_SNAPSHOT  2
+#define MSG_OUTPUT1   6
+#define MSG_OUTPUT2   7
+#define MSG_STATS_AF  8
+#define MSG_STATS_WE  9
+#define MSG_OUTPUT_S  10
+#define MSG_OUTPUT_T  11
+
+#define VFE_ADSP_EVENT 0xFFFF
+#define SNAPSHOT_MASK_MODE 0x00000002
+#define MSM_AXI_QOS_PREVIEW	192000
+#define MSM_AXI_QOS_SNAPSHOT	192000
+
+
+static struct msm_adsp_module *qcam_mod;
+static struct msm_adsp_module *vfe_mod;
+static struct msm_vfe_callback *resp;
+static void *extdata;
+static uint32_t extlen;
+
+struct mutex vfe_lock;
+static void     *vfe_syncdata;
+static uint8_t vfestopped;
+static uint32_t vfetask_state;
+static int cnt;
+
+static struct stop_event stopevent;
+
+unsigned long paddr_s_y;
+unsigned long paddr_s_cbcr;
+unsigned long paddr_t_y;
+unsigned long paddr_t_cbcr;
+
+static void vfe_7x_convert(struct msm_vfe_phy_info *pinfo,
+		enum vfe_resp_msg type,
+		void *data, void **ext, int32_t *elen)
+{
+	switch (type) {
+	case VFE_MSG_OUTPUT_P: {
+		pinfo->y_phy = ((struct vfe_endframe *)data)->y_address;
+		pinfo->cbcr_phy =
+			((struct vfe_endframe *)data)->cbcr_address;
+
+		pinfo->output_id = OUTPUT_TYPE_P;
+
+		CDBG("vfe_7x_convert, y_phy = 0x%x, cbcr_phy = 0x%x\n",
+				 pinfo->y_phy, pinfo->cbcr_phy);
+
+		((struct vfe_frame_extra *)extdata)->bl_evencol =
+		((struct vfe_endframe *)data)->blacklevelevencolumn;
+
+		((struct vfe_frame_extra *)extdata)->bl_oddcol =
+		((struct vfe_endframe *)data)->blackleveloddcolumn;
+
+		((struct vfe_frame_extra *)extdata)->g_def_p_cnt =
+		((struct vfe_endframe *)data)->greendefectpixelcount;
+
+		((struct vfe_frame_extra *)extdata)->r_b_def_p_cnt =
+		((struct vfe_endframe *)data)->redbluedefectpixelcount;
+
+		*ext  = extdata;
+		*elen = extlen;
+	}
+		break;
+
+	case VFE_MSG_OUTPUT_S: {
+		pinfo->y_phy = paddr_s_y;
+		pinfo->cbcr_phy = paddr_s_cbcr;
+		pinfo->output_id = OUTPUT_TYPE_S;
+		CDBG("vfe_7x_convert: y_phy = 0x%x cbcr_phy = 0x%x\n",
+					pinfo->y_phy, pinfo->cbcr_phy);
+	}
+		break;
+
+	case VFE_MSG_OUTPUT_T: {
+		pinfo->y_phy = paddr_t_y;
+		pinfo->cbcr_phy = paddr_t_cbcr;
+		pinfo->output_id = OUTPUT_TYPE_T;
+		CDBG("vfe_7x_convert: y_phy = 0x%x cbcr_phy = 0x%x\n",
+					pinfo->y_phy, pinfo->cbcr_phy);
+	}
+		break;
+
+	case VFE_MSG_STATS_AF:
+	case VFE_MSG_STATS_WE:
+		pinfo->sbuf_phy = *(uint32_t *)data;
+		break;
+
+	default:
+		break;
+	} /* switch */
+}
+
+static void vfe_7x_ops(void *driver_data, unsigned id, size_t len,
+		void (*getevent)(void *ptr, size_t len))
+{
+	uint32_t evt_buf[3];
+	struct msm_vfe_resp *rp;
+	void *data;
+	CDBG("%s:id=%d\n", __func__, id);
+
+	len = (id == VFE_ADSP_EVENT) ? 0 : len;
+	data = resp->vfe_alloc(sizeof(struct msm_vfe_resp) + len,
+		vfe_syncdata,  GFP_ATOMIC);
+
+	if (!data) {
+		pr_err("%s: rp: cannot allocate buffer\n", __func__);
+		return;
+	}
+	rp = (struct msm_vfe_resp *)data;
+	rp->evt_msg.len = len;
+
+	if (id == VFE_ADSP_EVENT) {
+		/* event */
+		rp->type           = VFE_EVENT;
+		rp->evt_msg.type   = MSM_CAMERA_EVT;
+		getevent(evt_buf, sizeof(evt_buf));
+		rp->evt_msg.msg_id = evt_buf[0];
+	CDBG("%s:event:msg_id=%d\n", __func__, rp->evt_msg.msg_id);
+		resp->vfe_resp(rp, MSM_CAM_Q_VFE_EVT, vfe_syncdata,
+		GFP_ATOMIC);
+	} else {
+		/* messages */
+		rp->evt_msg.type   = MSM_CAMERA_MSG;
+		rp->evt_msg.msg_id = id;
+		rp->evt_msg.data = rp + 1;
+		getevent(rp->evt_msg.data, len);
+	CDBG("%s:messages:msg_id=%d\n", __func__, rp->evt_msg.msg_id);
+
+		switch (rp->evt_msg.msg_id) {
+		case MSG_SNAPSHOT:
+			update_axi_qos(MSM_AXI_QOS_PREVIEW);
+			vfe_7x_ops(driver_data, MSG_OUTPUT_S, len, getevent);
+			vfe_7x_ops(driver_data, MSG_OUTPUT_T, len, getevent);
+			rp->type = VFE_MSG_SNAPSHOT;
+			break;
+
+		case MSG_OUTPUT_S:
+			rp->type = VFE_MSG_OUTPUT_S;
+			vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT_S,
+				rp->evt_msg.data, &(rp->extdata),
+				&(rp->extlen));
+			break;
+
+		case MSG_OUTPUT_T:
+			rp->type = VFE_MSG_OUTPUT_T;
+			vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT_T,
+				rp->evt_msg.data, &(rp->extdata),
+				&(rp->extlen));
+			break;
+
+		case MSG_OUTPUT1:
+		case MSG_OUTPUT2:
+			rp->type = VFE_MSG_OUTPUT_P;
+			vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT_P,
+				rp->evt_msg.data, &(rp->extdata),
+				&(rp->extlen));
+			break;
+
+		case MSG_STATS_AF:
+			rp->type = VFE_MSG_STATS_AF;
+			vfe_7x_convert(&(rp->phy), VFE_MSG_STATS_AF,
+					rp->evt_msg.data, NULL, NULL);
+			break;
+
+		case MSG_STATS_WE:
+			rp->type = VFE_MSG_STATS_WE;
+			vfe_7x_convert(&(rp->phy), VFE_MSG_STATS_WE,
+					rp->evt_msg.data, NULL, NULL);
+
+			CDBG("MSG_STATS_WE: phy = 0x%x\n", rp->phy.sbuf_phy);
+			break;
+
+		case MSG_STOP_ACK:
+			rp->type = VFE_MSG_GENERAL;
+			stopevent.state = 1;
+			wake_up(&stopevent.wait);
+			break;
+
+
+		default:
+			rp->type = VFE_MSG_GENERAL;
+			break;
+		}
+		resp->vfe_resp(rp, MSM_CAM_Q_VFE_MSG, vfe_syncdata, GFP_ATOMIC);
+	}
+}
+
+static struct msm_adsp_ops vfe_7x_sync = {
+	.event = vfe_7x_ops,
+};
+
+static int vfe_7x_enable(struct camera_enable_cmd *enable)
+{
+	int rc = -EFAULT;
+
+	if (!strcmp(enable->name, "QCAMTASK"))
+		rc = msm_adsp_enable(qcam_mod);
+	else if (!strcmp(enable->name, "VFETASK")) {
+		rc = msm_adsp_enable(vfe_mod);
+		vfetask_state = 1;
+	}
+
+	if (!cnt) {
+		add_axi_qos();
+		cnt++;
+	}
+	return rc;
+}
+
+static int vfe_7x_disable(struct camera_enable_cmd *enable,
+		struct platform_device *dev __attribute__((unused)))
+{
+	int rc = -EFAULT;
+
+	if (!strcmp(enable->name, "QCAMTASK"))
+		rc = msm_adsp_disable(qcam_mod);
+	else if (!strcmp(enable->name, "VFETASK")) {
+		rc = msm_adsp_disable(vfe_mod);
+		vfetask_state = 0;
+	}
+
+	return rc;
+}
+
+static int vfe_7x_stop(void)
+{
+	int rc = 0;
+	uint32_t stopcmd = VFE_STOP_CMD;
+	rc = msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
+				&stopcmd, sizeof(uint32_t));
+	if (rc < 0) {
+		CDBG("%s:%d: failed rc = %d \n", __func__, __LINE__, rc);
+		return rc;
+	}
+
+	stopevent.state = 0;
+	rc = wait_event_timeout(stopevent.wait,
+		stopevent.state != 0,
+		msecs_to_jiffies(stopevent.timeout));
+
+	return rc;
+}
+
+static void vfe_7x_release(struct platform_device *pdev)
+{
+	mutex_lock(&vfe_lock);
+	vfe_syncdata = NULL;
+	mutex_unlock(&vfe_lock);
+
+	if (!vfestopped) {
+		CDBG("%s:%d:Calling vfe_7x_stop()\n", __func__, __LINE__);
+		vfe_7x_stop();
+	} else
+		vfestopped = 0;
+
+	msm_adsp_disable(qcam_mod);
+	msm_adsp_disable(vfe_mod);
+	vfetask_state = 0;
+
+	msm_adsp_put(qcam_mod);
+	msm_adsp_put(vfe_mod);
+
+	msm_camio_disable(pdev);
+
+	kfree(extdata);
+	extlen = 0;
+
+	/* Release AXI */
+	release_axi_qos();
+	cnt = 0;
+}
+
+static int vfe_7x_init(struct msm_vfe_callback *presp,
+	struct platform_device *dev)
+{
+	int rc = 0;
+
+	init_waitqueue_head(&stopevent.wait);
+	stopevent.timeout = 200;
+	stopevent.state = 0;
+
+	if (presp && presp->vfe_resp)
+		resp = presp;
+	else
+		return -EFAULT;
+
+	/* Bring up all the required GPIOs and Clocks */
+	rc = msm_camio_enable(dev);
+	if (rc < 0)
+		return rc;
+	msm_camio_camif_pad_reg_reset();
+
+	extlen = sizeof(struct vfe_frame_extra);
+
+	extdata =
+		kmalloc(extlen, GFP_ATOMIC);
+	if (!extdata) {
+		rc = -ENOMEM;
+		goto init_fail;
+	}
+
+	rc = msm_adsp_get("QCAMTASK", &qcam_mod, &vfe_7x_sync, NULL);
+	if (rc) {
+		rc = -EBUSY;
+		goto get_qcam_fail;
+	}
+
+	rc = msm_adsp_get("VFETASK", &vfe_mod, &vfe_7x_sync, NULL);
+	if (rc) {
+		rc = -EBUSY;
+		goto get_vfe_fail;
+	}
+
+	return 0;
+
+get_vfe_fail:
+	msm_adsp_put(qcam_mod);
+get_qcam_fail:
+	kfree(extdata);
+init_fail:
+	extlen = 0;
+	return rc;
+}
+
+static int vfe_7x_config_axi(int mode,
+	struct axidata *ad, struct axiout *ao)
+{
+	struct msm_pmem_region *regptr;
+	unsigned long *bptr;
+	int    cnt;
+
+	int rc = 0;
+
+	if (mode == OUTPUT_1 || mode == OUTPUT_1_AND_2) {
+		regptr = ad->region;
+
+		CDBG("bufnum1 = %d\n", ad->bufnum1);
+		if (mode == OUTPUT_1_AND_2) {
+			paddr_t_y = regptr->paddr + regptr->info.y_off;
+			paddr_t_cbcr = regptr->paddr +  regptr->info.cbcr_off;
+		}
+
+		CDBG("config_axi1: O1, phy = 0x%lx, y_off = %d, cbcr_off =%d\n",
+			regptr->paddr, regptr->info.y_off,
+			regptr->info.cbcr_off);
+
+		bptr = &ao->output1buffer1_y_phy;
+		for (cnt = 0; cnt < ad->bufnum1; cnt++) {
+			*bptr = regptr->paddr + regptr->info.y_off;
+			bptr++;
+			*bptr = regptr->paddr + regptr->info.cbcr_off;
+
+			bptr++;
+			regptr++;
+		}
+
+		regptr--;
+		for (cnt = 0; cnt < (8 - ad->bufnum1); cnt++) {
+			*bptr = regptr->paddr + regptr->info.y_off;
+			bptr++;
+			*bptr = regptr->paddr + regptr->info.cbcr_off;
+			bptr++;
+		}
+	} /* if OUTPUT1 or Both */
+
+	if (mode == OUTPUT_2 || mode == OUTPUT_1_AND_2) {
+		regptr = &(ad->region[ad->bufnum1]);
+
+		CDBG("bufnum2 = %d\n", ad->bufnum2);
+		paddr_s_y = regptr->paddr +  regptr->info.y_off;
+		paddr_s_cbcr = regptr->paddr +  regptr->info.cbcr_off;
+		CDBG("config_axi2: O2, phy = 0x%lx, y_off = %d, cbcr_off =%d\n",
+		     regptr->paddr, regptr->info.y_off, regptr->info.cbcr_off);
+
+		bptr = &ao->output2buffer1_y_phy;
+		for (cnt = 0; cnt < ad->bufnum2; cnt++) {
+			*bptr = regptr->paddr + regptr->info.y_off;
+			bptr++;
+			*bptr = regptr->paddr + regptr->info.cbcr_off;
+
+			bptr++;
+			regptr++;
+		}
+
+		regptr--;
+		for (cnt = 0; cnt < (8 - ad->bufnum2); cnt++) {
+			*bptr = regptr->paddr + regptr->info.y_off;
+			bptr++;
+			*bptr = regptr->paddr + regptr->info.cbcr_off;
+			bptr++;
+		}
+	}
+
+	return rc;
+}
+
+static int vfe_7x_config(struct msm_vfe_cfg_cmd *cmd, void *data)
+{
+	struct msm_pmem_region *regptr;
+	unsigned char buf[256];
+
+	struct vfe_stats_ack sack;
+	struct axidata *axid;
+	uint32_t i, op_mode;
+	uint32_t *_mode;
+
+	struct vfe_stats_we_cfg *scfg = NULL;
+	struct vfe_stats_af_cfg *sfcfg = NULL;
+
+	struct axiout *axio = NULL;
+	void   *cmd_data = NULL;
+	void   *cmd_data_alloc = NULL;
+	long rc = 0;
+	struct msm_vfe_command_7k *vfecmd;
+
+	vfecmd =
+			kmalloc(sizeof(struct msm_vfe_command_7k),
+				GFP_ATOMIC);
+	if (!vfecmd) {
+		pr_err("vfecmd alloc failed!\n");
+		return -ENOMEM;
+	}
+
+	if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE &&
+	    cmd->cmd_type != CMD_STATS_BUF_RELEASE &&
+	    cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
+		if (copy_from_user(vfecmd,
+				(void __user *)(cmd->value),
+				sizeof(struct msm_vfe_command_7k))) {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+	}
+
+	switch (cmd->cmd_type) {
+	case CMD_STATS_AEC_AWB_ENABLE:
+	case CMD_STATS_AXI_CFG: {
+		axid = data;
+		if (!axid) {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+
+		scfg =
+			kmalloc(sizeof(struct vfe_stats_we_cfg),
+				GFP_ATOMIC);
+		if (!scfg) {
+			rc = -ENOMEM;
+			goto config_failure;
+		}
+
+		if (copy_from_user(scfg,
+					(void __user *)(vfecmd->value),
+					vfecmd->length)) {
+
+			rc = -EFAULT;
+			goto config_done;
+		}
+
+		CDBG("STATS_ENABLE: bufnum = %d, enabling = %d\n",
+			axid->bufnum1, scfg->wb_expstatsenable);
+
+		if (axid->bufnum1 > 0) {
+			regptr = axid->region;
+
+			for (i = 0; i < axid->bufnum1; i++) {
+
+				CDBG("STATS_ENABLE, phy = 0x%lx\n",
+					regptr->paddr);
+
+				scfg->wb_expstatoutputbuffer[i] =
+					(void *)regptr->paddr;
+				regptr++;
+			}
+
+			cmd_data = scfg;
+
+		} else {
+			rc = -EINVAL;
+			goto config_done;
+		}
+	}
+		break;
+
+	case CMD_STATS_AF_ENABLE:
+	case CMD_STATS_AF_AXI_CFG: {
+		axid = data;
+		if (!axid) {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+
+		sfcfg =
+			kmalloc(sizeof(struct vfe_stats_af_cfg),
+				GFP_ATOMIC);
+
+		if (!sfcfg) {
+			rc = -ENOMEM;
+			goto config_failure;
+		}
+
+		if (copy_from_user(sfcfg,
+					(void __user *)(vfecmd->value),
+					vfecmd->length)) {
+
+			rc = -EFAULT;
+			goto config_done;
+		}
+
+		CDBG("AF_ENABLE: bufnum = %d, enabling = %d\n",
+			axid->bufnum1, sfcfg->af_enable);
+
+		if (axid->bufnum1 > 0) {
+			regptr = &axid->region[0];
+
+			for (i = 0; i < axid->bufnum1; i++) {
+
+				CDBG("STATS_ENABLE, phy = 0x%lx\n",
+					regptr->paddr);
+
+				sfcfg->af_outbuf[i] =
+					(void *)regptr->paddr;
+
+				regptr++;
+			}
+
+			cmd_data = sfcfg;
+
+		} else {
+			rc = -EINVAL;
+			goto config_done;
+		}
+	}
+		break;
+
+	case CMD_FRAME_BUF_RELEASE: {
+		struct msm_frame *b;
+		unsigned long p;
+		struct vfe_outputack fack;
+		if (!data)  {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+
+		b = (struct msm_frame *)(cmd->value);
+		p = *(unsigned long *)data;
+
+		fack.header = VFE_FRAME_ACK;
+
+		fack.output2newybufferaddress =
+			(void *)(p + b->y_off);
+
+		fack.output2newcbcrbufferaddress =
+			(void *)(p + b->cbcr_off);
+
+		vfecmd->queue = QDSP_CMDQUEUE;
+		vfecmd->length = sizeof(struct vfe_outputack);
+		cmd_data = &fack;
+	}
+		break;
+
+	case CMD_SNAP_BUF_RELEASE:
+		break;
+
+	case CMD_STATS_BUF_RELEASE: {
+		CDBG("vfe_7x_config: CMD_STATS_BUF_RELEASE\n");
+		if (!data) {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+
+		sack.header = STATS_WE_ACK;
+		sack.bufaddr = (void *)*(uint32_t *)data;
+
+		vfecmd->queue  = QDSP_CMDQUEUE;
+		vfecmd->length = sizeof(struct vfe_stats_ack);
+		cmd_data = &sack;
+	}
+		break;
+
+	case CMD_STATS_AF_BUF_RELEASE: {
+		CDBG("vfe_7x_config: CMD_STATS_AF_BUF_RELEASE\n");
+		if (!data) {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+
+		sack.header = STATS_AF_ACK;
+		sack.bufaddr = (void *)*(uint32_t *)data;
+
+		vfecmd->queue  = QDSP_CMDQUEUE;
+		vfecmd->length = sizeof(struct vfe_stats_ack);
+		cmd_data = &sack;
+	}
+		break;
+
+	case CMD_GENERAL:
+	case CMD_STATS_DISABLE: {
+		if (vfecmd->length > 256) {
+			cmd_data_alloc =
+			cmd_data = kmalloc(vfecmd->length, GFP_ATOMIC);
+			if (!cmd_data) {
+				rc = -ENOMEM;
+				goto config_failure;
+			}
+		} else
+			cmd_data = buf;
+
+		if (copy_from_user(cmd_data,
+					(void __user *)(vfecmd->value),
+					vfecmd->length)) {
+
+			rc = -EFAULT;
+			goto config_done;
+		}
+
+		if (vfecmd->queue == QDSP_CMDQUEUE) {
+			switch (*(uint32_t *)cmd_data) {
+			case VFE_RESET_CMD:
+				msm_camio_vfe_blk_reset();
+				vfestopped = 0;
+				break;
+
+			case VFE_START_CMD:
+				_mode = (uint32_t *)cmd_data;
+				op_mode = *(++_mode);
+				if (op_mode & SNAPSHOT_MASK_MODE) {
+					/* request AXI bus for snapshot */
+					if (update_axi_qos(MSM_AXI_QOS_SNAPSHOT)
+						< 0) {
+						rc = -EFAULT;
+						goto config_failure;
+					}
+				} else {
+					/* request AXI bus for snapshot */
+					if (update_axi_qos(MSM_AXI_QOS_PREVIEW)
+						< 0) {
+						rc = -EFAULT;
+						goto config_failure;
+					}
+				}
+				msm_camio_camif_pad_reg_reset_2();
+				vfestopped = 0;
+				break;
+
+			case VFE_STOP_CMD:
+				vfestopped = 1;
+				goto config_send;
+
+			default:
+				break;
+			}
+		} /* QDSP_CMDQUEUE */
+	}
+		break;
+	case CMD_AXI_CFG_PREVIEW:
+	case CMD_RAW_PICT_AXI_CFG: {
+		axid = data;
+		if (!axid) {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+
+		axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			goto config_failure;
+		}
+
+		if (copy_from_user(axio, (void __user *)(vfecmd->value),
+					sizeof(struct axiout))) {
+			rc = -EFAULT;
+			goto config_done;
+		}
+
+		vfe_7x_config_axi(OUTPUT_2, axid, axio);
+		cmd_data = axio;
+	}
+		break;
+
+	case CMD_AXI_CFG_SNAP: {
+		axid = data;
+		if (!axid) {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+
+		axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			goto config_failure;
+		}
+
+		if (copy_from_user(axio, (void __user *)(vfecmd->value),
+					sizeof(struct axiout))) {
+			rc = -EFAULT;
+			goto config_done;
+		}
+
+		vfe_7x_config_axi(OUTPUT_1_AND_2, axid, axio);
+
+		cmd_data = axio;
+	}
+		break;
+
+	default:
+		break;
+	} /* switch */
+
+	if (vfestopped)
+		goto config_done;
+
+config_send:
+	CDBG("send adsp command = %d\n", *(uint32_t *)cmd_data);
+	if (vfetask_state)
+		rc = msm_adsp_write(vfe_mod, vfecmd->queue,
+					cmd_data, vfecmd->length);
+config_done:
+	if (cmd_data_alloc != NULL)
+		kfree(cmd_data_alloc);
+
+config_failure:
+	kfree(scfg);
+	kfree(axio);
+	kfree(vfecmd);
+	return rc;
+}
+
+void msm_camvfe_fn_init(struct msm_camvfe_fn *fptr, void *data)
+{
+	mutex_init(&vfe_lock);
+	fptr->vfe_init    = vfe_7x_init;
+	fptr->vfe_enable  = vfe_7x_enable;
+	fptr->vfe_config  = vfe_7x_config;
+	fptr->vfe_disable = vfe_7x_disable;
+	fptr->vfe_release = vfe_7x_release;
+	vfe_syncdata = data;
+}
+
+void msm_camvpe_fn_init(struct msm_camvpe_fn *fptr, void *data)
+{
+	fptr->vpe_reg		= NULL;
+	fptr->send_frame_to_vpe	= NULL;
+	fptr->vpe_config	= NULL;
+	fptr->vpe_cfg_update	= NULL;
+	fptr->dis		= NULL;
+}
diff --git a/drivers/media/video/msm/msm_vfe7x.h b/drivers/media/video/msm/msm_vfe7x.h
new file mode 100644
index 0000000..dd3571f
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe7x.h
@@ -0,0 +1,265 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __MSM_VFE7X_H__
+#define __MSM_VFE7X_H__
+#include <media/msm_camera.h>
+#include <mach/camera.h>
+
+struct vfe_frame_extra {
+	uint32_t  bl_evencol;
+	uint32_t  bl_oddcol;
+	uint16_t  g_def_p_cnt;
+	uint16_t  r_b_def_p_cnt;
+};
+
+struct vfe_endframe {
+	uint32_t      y_address;
+	uint32_t      cbcr_address;
+
+	unsigned int  blacklevelevencolumn:23;
+	uint16_t      reserved1:9;
+	unsigned int  blackleveloddcolumn:23;
+	uint16_t      reserved2:9;
+
+	uint16_t      greendefectpixelcount:8;
+	uint16_t      reserved3:8;
+	uint16_t      redbluedefectpixelcount:8;
+	uint16_t      reserved4:8;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_outputack {
+	uint32_t  header;
+	void      *output2newybufferaddress;
+	void      *output2newcbcrbufferaddress;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_stats_ack {
+	uint32_t header;
+	/* MUST BE 64 bit ALIGNED */
+	void     *bufaddr;
+} __attribute__((packed, aligned(4)));
+
+/* AXI Output Config Command sent to DSP */
+struct axiout {
+	uint32_t            cmdheader:32;
+	int 		    outputmode:3;
+	uint8_t             format:2;
+	uint32_t            /* reserved */ : 27;
+
+	/* AXI Output 1 Y Configuration, Part 1 */
+	uint32_t            out1yimageheight:12;
+	uint32_t            /* reserved */ : 4;
+	uint32_t            out1yimagewidthin64bitwords:10;
+	uint32_t            /* reserved */ : 6;
+
+	/* AXI Output 1 Y Configuration, Part 2 */
+	uint8_t             out1yburstlen:2;
+	uint32_t            out1ynumrows:12;
+	uint32_t            out1yrowincin64bitincs:12;
+	uint32_t            /* reserved */ : 6;
+
+	/* AXI Output 1 CbCr Configuration, Part 1 */
+	uint32_t            out1cbcrimageheight:12;
+	uint32_t            /* reserved */ : 4;
+	uint32_t            out1cbcrimagewidthin64bitwords:10;
+	uint32_t            /* reserved */ : 6;
+
+	/* AXI Output 1 CbCr Configuration, Part 2 */
+	uint8_t             out1cbcrburstlen:2;
+	uint32_t            out1cbcrnumrows:12;
+	uint32_t            out1cbcrrowincin64bitincs:12;
+	uint32_t            /* reserved */ : 6;
+
+	/* AXI Output 2 Y Configuration, Part 1 */
+	uint32_t            out2yimageheight:12;
+	uint32_t            /* reserved */ : 4;
+	uint32_t            out2yimagewidthin64bitwords:10;
+	uint32_t            /* reserved */ : 6;
+
+	/* AXI Output 2 Y Configuration, Part 2 */
+	uint8_t             out2yburstlen:2;
+	uint32_t            out2ynumrows:12;
+	uint32_t            out2yrowincin64bitincs:12;
+	uint32_t            /* reserved */ : 6;
+
+	/* AXI Output 2 CbCr Configuration, Part 1 */
+	uint32_t            out2cbcrimageheight:12;
+	uint32_t            /* reserved */ : 4;
+	uint32_t            out2cbcrimagewidtein64bitwords:10;
+	uint32_t            /* reserved */ : 6;
+
+	/* AXI Output 2 CbCr Configuration, Part 2 */
+	uint8_t             out2cbcrburstlen:2;
+	uint32_t            out2cbcrnumrows:12;
+	uint32_t            out2cbcrrowincin64bitincs:12;
+	uint32_t            /* reserved */ : 6;
+
+	/* Address configuration:
+	 * output1 phisycal address */
+	unsigned long   output1buffer1_y_phy;
+	unsigned long   output1buffer1_cbcr_phy;
+	unsigned long   output1buffer2_y_phy;
+	unsigned long   output1buffer2_cbcr_phy;
+	unsigned long   output1buffer3_y_phy;
+	unsigned long   output1buffer3_cbcr_phy;
+	unsigned long   output1buffer4_y_phy;
+	unsigned long   output1buffer4_cbcr_phy;
+	unsigned long   output1buffer5_y_phy;
+	unsigned long   output1buffer5_cbcr_phy;
+	unsigned long   output1buffer6_y_phy;
+	unsigned long   output1buffer6_cbcr_phy;
+	unsigned long   output1buffer7_y_phy;
+	unsigned long   output1buffer7_cbcr_phy;
+	unsigned long   output1buffer8_y_phy;
+	unsigned long   output1buffer8_cbcr_phy;
+
+	/* output2 phisycal address */
+	unsigned long   output2buffer1_y_phy;
+	unsigned long   output2buffer1_cbcr_phy;
+	unsigned long   output2buffer2_y_phy;
+	unsigned long   output2buffer2_cbcr_phy;
+	unsigned long   output2buffer3_y_phy;
+	unsigned long   output2buffer3_cbcr_phy;
+	unsigned long   output2buffer4_y_phy;
+	unsigned long   output2buffer4_cbcr_phy;
+	unsigned long   output2buffer5_y_phy;
+	unsigned long   output2buffer5_cbcr_phy;
+	unsigned long   output2buffer6_y_phy;
+	unsigned long   output2buffer6_cbcr_phy;
+	unsigned long   output2buffer7_y_phy;
+	unsigned long   output2buffer7_cbcr_phy;
+	unsigned long   output2buffer8_y_phy;
+	unsigned long   output2buffer8_cbcr_phy;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_stats_we_cfg {
+	uint32_t       header;
+
+	/* White Balance/Exposure Statistic Selection */
+	uint8_t        wb_expstatsenable:1;
+	uint8_t        wb_expstatbuspriorityselection:1;
+	unsigned int   wb_expstatbuspriorityvalue:4;
+	unsigned int   /* reserved */ : 26;
+
+	/* White Balance/Exposure Statistic Configuration, Part 1 */
+	uint8_t        exposurestatregions:1;
+	uint8_t        exposurestatsubregions:1;
+	unsigned int   /* reserved */ : 14;
+
+	unsigned int   whitebalanceminimumy:8;
+	unsigned int   whitebalancemaximumy:8;
+
+	/* White Balance/Exposure Statistic Configuration, Part 2 */
+	uint8_t wb_expstatslopeofneutralregionline[
+		NUM_WB_EXP_NEUTRAL_REGION_LINES];
+
+	/* White Balance/Exposure Statistic Configuration, Part 3 */
+	unsigned int   wb_expstatcrinterceptofneutralregionline2:12;
+	unsigned int   /* reserved */ : 4;
+	unsigned int   wb_expstatcbinterceptofneutralreginnline1:12;
+	unsigned int    /* reserved */ : 4;
+
+	/* White Balance/Exposure Statistic Configuration, Part 4 */
+	unsigned int   wb_expstatcrinterceptofneutralregionline4:12;
+	unsigned int   /* reserved */ : 4;
+	unsigned int   wb_expstatcbinterceptofneutralregionline3:12;
+	unsigned int   /* reserved */ : 4;
+
+	/* White Balance/Exposure Statistic Output Buffer Header */
+	unsigned int   wb_expmetricheaderpattern:8;
+	unsigned int   /* reserved */ : 24;
+
+	/* White Balance/Exposure Statistic Output Buffers-MUST
+	* BE 64 bit ALIGNED */
+	void  *wb_expstatoutputbuffer[NUM_WB_EXP_STAT_OUTPUT_BUFFERS];
+} __attribute__((packed, aligned(4)));
+
+struct vfe_stats_af_cfg {
+	uint32_t header;
+
+	/* Autofocus Statistic Selection */
+	uint8_t       af_enable:1;
+	uint8_t       af_busprioritysel:1;
+	unsigned int  af_buspriorityval:4;
+	unsigned int  /* reserved */ : 26;
+
+	/* Autofocus Statistic Configuration, Part 1 */
+	unsigned int  af_singlewinvoffset:12;
+	unsigned int  /* reserved */ : 4;
+	unsigned int  af_singlewinhoffset:12;
+	unsigned int  /* reserved */ : 3;
+	uint8_t       af_winmode:1;
+
+	/* Autofocus Statistic Configuration, Part 2 */
+	unsigned int  af_singglewinvh:11;
+	unsigned int  /* reserved */ : 5;
+	unsigned int  af_singlewinhw:11;
+	unsigned int  /* reserved */ : 5;
+
+	/* Autofocus Statistic Configuration, Parts 3-6 */
+	uint8_t       af_multiwingrid[NUM_AUTOFOCUS_MULTI_WINDOW_GRIDS];
+
+	/* Autofocus Statistic Configuration, Part 7 */
+	signed int    af_metrichpfcoefa00:5;
+	signed int    af_metrichpfcoefa04:5;
+	unsigned int  af_metricmaxval:11;
+	uint8_t       af_metricsel:1;
+	unsigned int  /* reserved */ : 10;
+
+	/* Autofocus Statistic Configuration, Part 8 */
+	signed int    af_metrichpfcoefa20:5;
+	signed int    af_metrichpfcoefa21:5;
+	signed int    af_metrichpfcoefa22:5;
+	signed int    af_metrichpfcoefa23:5;
+	signed int    af_metrichpfcoefa24:5;
+	unsigned int  /* reserved */ : 7;
+
+	/* Autofocus Statistic Output Buffer Header */
+	unsigned int  af_metrichp:8;
+	unsigned int  /* reserved */ : 24;
+
+	/* Autofocus Statistic Output Buffers - MUST BE 64 bit ALIGNED!!! */
+	void *af_outbuf[NUM_AF_STAT_OUTPUT_BUFFERS];
+} __attribute__((packed, aligned(4))); /* VFE_StatsAutofocusConfigCmdType */
+
+struct msm_camera_frame_msg {
+	unsigned long   output_y_address;
+	unsigned long   output_cbcr_address;
+
+	unsigned int    blacklevelevenColumn:23;
+	uint16_t        reserved1:9;
+	unsigned int    blackleveloddColumn:23;
+	uint16_t        reserved2:9;
+
+	uint16_t        greendefectpixelcount:8;
+	uint16_t        reserved3:8;
+	uint16_t        redbluedefectpixelcount:8;
+	uint16_t        reserved4:8;
+} __attribute__((packed, aligned(4)));
+
+/* New one for 7k */
+struct msm_vfe_command_7k {
+	uint16_t queue;
+	uint16_t length;
+	void     *value;
+};
+
+struct stop_event {
+  wait_queue_head_t wait;
+	int state;
+  int timeout;
+};
+
+
+#endif /* __MSM_VFE7X_H__ */
diff --git a/drivers/media/video/msm/msm_vfe7x27a.c b/drivers/media/video/msm/msm_vfe7x27a.c
new file mode 100644
index 0000000..c8bfacc
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe7x27a.c
@@ -0,0 +1,742 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/msm_adsp.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <linux/pm_qos_params.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <mach/msm_adsp.h>
+#include <mach/clk.h>
+#include <mach/camera.h>
+#include "msm_vfe7x27a.h"
+
+#define QDSP_CMDQUEUE 25
+
+#define VFE_RESET_CMD 0
+#define VFE_START_CMD 1
+#define VFE_STOP_CMD  2
+#define VFE_FRAME_ACK 20
+#define STATS_AF_ACK  21
+#define STATS_WE_ACK  22
+
+#define MSG_STOP_ACK  1
+#define MSG_SNAPSHOT  2
+#define MSG_OUTPUT1   6
+#define MSG_OUTPUT2   7
+#define MSG_STATS_AF  8
+#define MSG_STATS_WE  9
+#define MSG_OUTPUT_S  23
+#define MSG_OUTPUT_T  22
+#define MSG_SOF       15
+
+#define VFE_ADSP_EVENT 0xFFFF
+#define SNAPSHOT_MASK_MODE 0x00000002
+#define MSM_AXI_QOS_PREVIEW	122000
+#define MSM_AXI_QOS_SNAPSHOT	192000
+
+
+static struct msm_adsp_module *qcam_mod;
+static struct msm_adsp_module *vfe_mod;
+static struct msm_vfe_callback *resp;
+static void *extdata;
+static uint32_t extlen;
+
+struct mutex vfe_lock;
+static void     *vfe_syncdata;
+static uint8_t vfestopped;
+
+static struct stop_event stopevent;
+
+unsigned long paddr_s_y;
+unsigned long paddr_s_cbcr;
+unsigned long paddr_t_y;
+unsigned long paddr_t_cbcr;
+static uint32_t op_mode;
+
+static void vfe_7x_convert(struct msm_vfe_phy_info *pinfo,
+		enum vfe_resp_msg type,
+		void *data, void **ext, int32_t *elen)
+{
+	switch (type) {
+	case VFE_MSG_OUTPUT_P: {
+		pinfo->y_phy = ((struct vfe_endframe *)data)->y_address;
+		pinfo->cbcr_phy =
+			((struct vfe_endframe *)data)->cbcr_address;
+
+		pinfo->output_id = OUTPUT_TYPE_P;
+
+		CDBG("vfe_7x_convert, y_phy = 0x%x, cbcr_phy = 0x%x\n",
+				 pinfo->y_phy, pinfo->cbcr_phy);
+
+		memcpy(((struct vfe_frame_extra *)extdata),
+			&((struct vfe_endframe *)data)->extra,
+			sizeof(struct vfe_frame_extra));
+
+		*ext  = extdata;
+		*elen = extlen;
+		pinfo->frame_id =
+				((struct vfe_frame_extra *)extdata)->frame_id;
+	}
+		break;
+	case VFE_MSG_OUTPUT_S: {
+		pinfo->y_phy = paddr_s_y;
+		pinfo->cbcr_phy = paddr_s_cbcr;
+		pinfo->output_id = OUTPUT_TYPE_S;
+		CDBG("vfe_7x_convert: y_phy = 0x%x cbcr_phy = 0x%x\n",
+					pinfo->y_phy, pinfo->cbcr_phy);
+	}
+		break;
+	case VFE_MSG_OUTPUT_T: {
+		pinfo->y_phy = paddr_t_y;
+		pinfo->cbcr_phy = paddr_t_cbcr;
+		pinfo->output_id = OUTPUT_TYPE_T;
+		CDBG("vfe_7x_convert: y_phy = 0x%x cbcr_phy = 0x%x\n",
+					pinfo->y_phy, pinfo->cbcr_phy);
+	}
+		break;
+	case VFE_MSG_STATS_AF:
+	case VFE_MSG_STATS_WE:
+		pinfo->sbuf_phy = *(uint32_t *)data;
+		pinfo->frame_id = *(((uint32_t *)data) + 1);
+		CDBG("frame id = %d\n", pinfo->frame_id);
+		break;
+	default:
+		break;
+	}
+}
+
+static void vfe_7x_ops(void *driver_data, unsigned id, size_t len,
+		void (*getevent)(void *ptr, size_t len))
+{
+	uint32_t evt_buf[3];
+	struct msm_vfe_resp *rp;
+	void *data;
+	CDBG("%s:id=%d\n", __func__, id);
+
+	len = (id == VFE_ADSP_EVENT) ? 0 : len;
+	data = resp->vfe_alloc(sizeof(struct msm_vfe_resp) + len,
+		vfe_syncdata,  GFP_ATOMIC);
+
+	if (!data) {
+		pr_err("%s: rp: cannot allocate buffer\n", __func__);
+		return;
+	}
+	rp = data;
+	rp->evt_msg.len = len;
+
+	if (id == VFE_ADSP_EVENT) {
+		/* event */
+		rp->type           = VFE_EVENT;
+		rp->evt_msg.type   = MSM_CAMERA_EVT;
+		getevent(evt_buf, sizeof(evt_buf));
+		rp->evt_msg.msg_id = evt_buf[0];
+		CDBG("%s:event:msg_id=%d\n", __func__, rp->evt_msg.msg_id);
+		resp->vfe_resp(rp, MSM_CAM_Q_VFE_EVT, vfe_syncdata,
+		GFP_ATOMIC);
+	} else {
+		/* messages */
+		rp->evt_msg.type   = MSM_CAMERA_MSG;
+		rp->evt_msg.msg_id = id;
+		rp->evt_msg.data = rp + 1;
+		getevent(rp->evt_msg.data, len);
+		CDBG("%s:messages:msg_id=%d\n", __func__, rp->evt_msg.msg_id);
+
+		switch (rp->evt_msg.msg_id) {
+		case MSG_SNAPSHOT:
+			msm_camio_set_perf_lvl(S_PREVIEW);
+			vfe_7x_ops(driver_data, MSG_OUTPUT_S, len, getevent);
+			vfe_7x_ops(driver_data, MSG_OUTPUT_T, len, getevent);
+			rp->type = VFE_MSG_SNAPSHOT;
+			break;
+		case MSG_OUTPUT_S:
+			rp->type = VFE_MSG_OUTPUT_S;
+			vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT_S,
+					rp->evt_msg.data, &(rp->extdata),
+					&(rp->extlen));
+			break;
+		case MSG_OUTPUT_T:
+			rp->type = VFE_MSG_OUTPUT_T;
+			vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT_T,
+					rp->evt_msg.data, &(rp->extdata),
+					&(rp->extlen));
+			break;
+		case MSG_OUTPUT1:
+		case MSG_OUTPUT2:
+			if (op_mode & SNAPSHOT_MASK_MODE) {
+				resp->vfe_free(data);
+				return;
+			}
+			rp->type = VFE_MSG_OUTPUT_P;
+			vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT_P,
+				rp->evt_msg.data, &(rp->extdata),
+				&(rp->extlen));
+			break;
+		case MSG_STATS_AF:
+			rp->type = VFE_MSG_STATS_AF;
+			vfe_7x_convert(&(rp->phy), VFE_MSG_STATS_AF,
+					rp->evt_msg.data, NULL, NULL);
+			break;
+		case MSG_STATS_WE:
+			rp->type = VFE_MSG_STATS_WE;
+			vfe_7x_convert(&(rp->phy), VFE_MSG_STATS_WE,
+					rp->evt_msg.data, NULL, NULL);
+
+			CDBG("MSG_STATS_WE: phy = 0x%x\n", rp->phy.sbuf_phy);
+			break;
+		case MSG_STOP_ACK:
+			rp->type = VFE_MSG_GENERAL;
+			stopevent.state = 1;
+			wake_up(&stopevent.wait);
+			break;
+		default:
+			rp->type = VFE_MSG_GENERAL;
+			break;
+		}
+		if (id != MSG_SOF)
+			resp->vfe_resp(rp, MSM_CAM_Q_VFE_MSG,
+					vfe_syncdata, GFP_ATOMIC);
+	}
+}
+
+static struct msm_adsp_ops vfe_7x_sync = {
+	.event = vfe_7x_ops,
+};
+
+static int vfe_7x_enable(struct camera_enable_cmd *enable)
+{
+	int rc = -EFAULT;
+	static int cnt;
+
+	if (!strcmp(enable->name, "QCAMTASK"))
+		rc = msm_adsp_enable(qcam_mod);
+	else if (!strcmp(enable->name, "VFETASK"))
+		rc = msm_adsp_enable(vfe_mod);
+
+	if (!cnt) {
+		msm_camio_set_perf_lvl(S_INIT);
+		cnt++;
+	}
+	return rc;
+}
+
+static int vfe_7x_disable(struct camera_enable_cmd *enable,
+		struct platform_device *dev __attribute__((unused)))
+{
+	int rc = -EFAULT;
+
+	if (!strcmp(enable->name, "QCAMTASK"))
+		rc = msm_adsp_disable(qcam_mod);
+	else if (!strcmp(enable->name, "VFETASK"))
+		rc = msm_adsp_disable(vfe_mod);
+
+	return rc;
+}
+
+static int vfe_7x_stop(void)
+{
+	int rc = 0;
+	uint32_t stopcmd = VFE_STOP_CMD;
+	rc = msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
+				&stopcmd, sizeof(uint32_t));
+	if (rc < 0) {
+		CDBG("%s:%d: failed rc = %d\n", __func__, __LINE__, rc);
+		return rc;
+	}
+
+	stopevent.state = 0;
+	rc = wait_event_timeout(stopevent.wait,
+		stopevent.state != 0,
+		msecs_to_jiffies(stopevent.timeout));
+
+	return rc;
+}
+
+static void vfe_7x_release(struct platform_device *pdev)
+{
+	mutex_lock(&vfe_lock);
+	vfe_syncdata = NULL;
+	mutex_unlock(&vfe_lock);
+
+	if (!vfestopped) {
+		CDBG("%s:%d:Calling vfe_7x_stop()\n", __func__, __LINE__);
+		vfe_7x_stop();
+	} else
+		vfestopped = 0;
+
+	msm_adsp_disable(qcam_mod);
+	msm_adsp_disable(vfe_mod);
+
+	msm_adsp_put(qcam_mod);
+	msm_adsp_put(vfe_mod);
+
+	msm_camio_disable(pdev);
+
+	kfree(extdata);
+	extlen = 0;
+
+	/* set back the AXI frequency to default */
+	/* TODO msm_camio_set_perf_lvl(S_DEFAULT); */
+}
+
+static int vfe_7x_init(struct msm_vfe_callback *presp,
+	struct platform_device *dev)
+{
+	int rc = 0;
+
+	init_waitqueue_head(&stopevent.wait);
+	stopevent.timeout = 200;
+	stopevent.state = 0;
+
+	if (presp && presp->vfe_resp)
+		resp = presp;
+	else
+		return -EFAULT;
+
+	/* Bring up all the required GPIOs and Clocks */
+	rc = msm_camio_enable(dev);
+	if (rc < 0)
+		return rc;
+
+	extlen = sizeof(struct vfe_frame_extra);
+
+	extdata = kmalloc(extlen, GFP_ATOMIC);
+	if (!extdata) {
+		rc = -ENOMEM;
+		goto init_fail;
+	}
+
+	rc = msm_adsp_get("QCAMTASK", &qcam_mod, &vfe_7x_sync, NULL);
+	if (rc) {
+		rc = -EBUSY;
+		goto get_qcam_fail;
+	}
+
+	rc = msm_adsp_get("VFETASK", &vfe_mod, &vfe_7x_sync, NULL);
+	if (rc) {
+		rc = -EBUSY;
+		goto get_vfe_fail;
+	}
+
+	return 0;
+
+get_vfe_fail:
+	msm_adsp_put(qcam_mod);
+get_qcam_fail:
+	kfree(extdata);
+init_fail:
+	extlen = 0;
+	return rc;
+}
+
+static int vfe_7x_config_axi(int mode,
+	struct axidata *ad, struct axiout *ao)
+{
+	struct msm_pmem_region *regptr;
+	unsigned long *bptr;
+	int    cnt;
+
+	int rc = 0;
+
+	if (mode == OUTPUT_1 || mode == OUTPUT_1_AND_2) {
+		regptr = ad->region;
+
+		CDBG("bufnum1 = %d\n", ad->bufnum1);
+		if (mode == OUTPUT_1_AND_2) {
+			paddr_t_y = regptr->paddr + regptr->info.y_off;
+			paddr_t_cbcr = regptr->paddr +  regptr->info.cbcr_off;
+		}
+
+		CDBG("config_axi1: O1, phy = 0x%lx, y_off = %d, cbcr_off =%d\n",
+			regptr->paddr, regptr->info.y_off,
+			regptr->info.cbcr_off);
+
+		bptr = &ao->output1buffer1_y_phy;
+		for (cnt = 0; cnt < ad->bufnum1; cnt++) {
+			*bptr = regptr->paddr + regptr->info.y_off;
+			bptr++;
+			*bptr = regptr->paddr + regptr->info.cbcr_off;
+
+			bptr++;
+			regptr++;
+		}
+
+		regptr--;
+		for (cnt = 0; cnt < (8 - ad->bufnum1); cnt++) {
+			*bptr = regptr->paddr + regptr->info.y_off;
+			bptr++;
+			*bptr = regptr->paddr + regptr->info.cbcr_off;
+			bptr++;
+		}
+	}
+
+	if (mode == OUTPUT_2 || mode == OUTPUT_1_AND_2) {
+		regptr = &(ad->region[ad->bufnum1]);
+
+		CDBG("bufnum2 = %d\n", ad->bufnum2);
+		paddr_s_y = regptr->paddr +  regptr->info.y_off;
+		paddr_s_cbcr = regptr->paddr +  regptr->info.cbcr_off;
+
+		CDBG("config_axi2: O2, phy = 0x%lx, y_off = %d, cbcr_off =%d\n",
+		     regptr->paddr, regptr->info.y_off, regptr->info.cbcr_off);
+
+		bptr = &ao->output2buffer1_y_phy;
+		for (cnt = 0; cnt < ad->bufnum2; cnt++) {
+			*bptr = regptr->paddr + regptr->info.y_off;
+			bptr++;
+			*bptr = regptr->paddr + regptr->info.cbcr_off;
+
+			bptr++;
+			regptr++;
+		}
+
+		regptr--;
+		for (cnt = 0; cnt < (8 - ad->bufnum2); cnt++) {
+			*bptr = regptr->paddr + regptr->info.y_off;
+			bptr++;
+			*bptr = regptr->paddr + regptr->info.cbcr_off;
+			bptr++;
+		}
+	}
+
+	return rc;
+}
+
+static int vfe_7x_config(struct msm_vfe_cfg_cmd *cmd, void *data)
+{
+	struct msm_pmem_region *regptr;
+	unsigned char buf[256];
+
+	struct vfe_stats_ack sack;
+	struct axidata *axid;
+	uint32_t i;
+	uint32_t *_mode;
+
+	struct vfe_stats_we_cfg *scfg = NULL;
+	struct vfe_stats_af_cfg *sfcfg = NULL;
+
+	struct axiout *axio = NULL;
+	void   *cmd_data = NULL;
+	void   *cmd_data_alloc = NULL;
+	long rc = 0;
+	struct msm_vfe_command_7k *vfecmd;
+
+	vfecmd = kmalloc(sizeof(struct msm_vfe_command_7k), GFP_ATOMIC);
+	if (!vfecmd) {
+		pr_err("vfecmd alloc failed!\n");
+		return -ENOMEM;
+	}
+
+	if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE &&
+	    cmd->cmd_type != CMD_STATS_BUF_RELEASE &&
+	    cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
+		if (copy_from_user(vfecmd,
+				(void __user *)(cmd->value),
+				sizeof(struct msm_vfe_command_7k))) {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+	}
+
+	switch (cmd->cmd_type) {
+	case CMD_STATS_AEC_AWB_ENABLE:
+	case CMD_STATS_AXI_CFG: {
+		axid = data;
+		if (!axid) {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+
+		scfg =
+			kmalloc(sizeof(struct vfe_stats_we_cfg),
+				GFP_ATOMIC);
+		if (!scfg) {
+			rc = -ENOMEM;
+			goto config_failure;
+		}
+
+		if (copy_from_user(scfg,
+					(void __user *)(vfecmd->value),
+					vfecmd->length)) {
+
+			rc = -EFAULT;
+			goto config_done;
+		}
+
+		CDBG("STATS_ENABLE: bufnum = %d, enabling = %d\n",
+			axid->bufnum1, scfg->wb_expstatsenable);
+
+		if (axid->bufnum1 > 0) {
+			regptr = axid->region;
+
+			for (i = 0; i < axid->bufnum1; i++) {
+
+				CDBG("STATS_ENABLE, phy = 0x%lx\n",
+					regptr->paddr);
+
+				scfg->wb_expstatoutputbuffer[i] =
+					(void *)regptr->paddr;
+				regptr++;
+			}
+
+			cmd_data = scfg;
+
+		} else {
+			rc = -EINVAL;
+			goto config_done;
+		}
+	}
+		break;
+	case CMD_STATS_AF_ENABLE:
+	case CMD_STATS_AF_AXI_CFG: {
+		axid = data;
+		if (!axid) {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+
+		sfcfg =
+			kmalloc(sizeof(struct vfe_stats_af_cfg),
+				GFP_ATOMIC);
+
+		if (!sfcfg) {
+			rc = -ENOMEM;
+			goto config_failure;
+		}
+
+		if (copy_from_user(sfcfg,
+					(void __user *)(vfecmd->value),
+					vfecmd->length)) {
+
+			rc = -EFAULT;
+			goto config_done;
+		}
+
+		CDBG("AF_ENABLE: bufnum = %d, enabling = %d\n",
+			axid->bufnum1, sfcfg->af_enable);
+
+		if (axid->bufnum1 > 0) {
+			regptr = &axid->region[0];
+
+			for (i = 0; i < axid->bufnum1; i++) {
+
+				CDBG("STATS_ENABLE, phy = 0x%lx\n",
+					regptr->paddr);
+
+				sfcfg->af_outbuf[i] =
+					(void *)regptr->paddr;
+
+				regptr++;
+			}
+
+			cmd_data = sfcfg;
+
+		} else {
+			rc = -EINVAL;
+			goto config_done;
+		}
+	}
+		break;
+	case CMD_FRAME_BUF_RELEASE: {
+		struct msm_frame *b;
+		unsigned long p;
+		struct vfe_outputack fack;
+		if (!data)  {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+
+		b = (struct msm_frame *)(cmd->value);
+		p = *(unsigned long *)data;
+
+		fack.header = VFE_FRAME_ACK;
+
+		fack.output2newybufferaddress =
+			(void *)(p + b->y_off);
+
+		fack.output2newcbcrbufferaddress =
+			(void *)(p + b->cbcr_off);
+
+		vfecmd->queue = QDSP_CMDQUEUE;
+		vfecmd->length = sizeof(struct vfe_outputack);
+		cmd_data = &fack;
+	}
+		break;
+	case CMD_SNAP_BUF_RELEASE:
+		break;
+	case CMD_STATS_BUF_RELEASE: {
+		CDBG("vfe_7x_config: CMD_STATS_BUF_RELEASE\n");
+		if (!data) {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+
+		sack.header = STATS_WE_ACK;
+		sack.bufaddr = (void *)*(uint32_t *)data;
+
+		vfecmd->queue  = QDSP_CMDQUEUE;
+		vfecmd->length = sizeof(struct vfe_stats_ack);
+		cmd_data = &sack;
+	}
+		break;
+	case CMD_STATS_AF_BUF_RELEASE: {
+		CDBG("vfe_7x_config: CMD_STATS_AF_BUF_RELEASE\n");
+		if (!data) {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+
+		sack.header = STATS_AF_ACK;
+		sack.bufaddr = (void *)*(uint32_t *)data;
+
+		vfecmd->queue  = QDSP_CMDQUEUE;
+		vfecmd->length = sizeof(struct vfe_stats_ack);
+		cmd_data = &sack;
+	}
+		break;
+	case CMD_GENERAL:
+	case CMD_STATS_DISABLE: {
+		if (vfecmd->length > 256) {
+			cmd_data_alloc =
+			cmd_data = kmalloc(vfecmd->length, GFP_ATOMIC);
+			if (!cmd_data) {
+				rc = -ENOMEM;
+				goto config_failure;
+			}
+		} else
+			cmd_data = buf;
+
+		if (copy_from_user(cmd_data,
+					(void __user *)(vfecmd->value),
+					vfecmd->length)) {
+
+			rc = -EFAULT;
+			goto config_done;
+		}
+
+		if (vfecmd->queue == QDSP_CMDQUEUE) {
+			switch (*(uint32_t *)cmd_data) {
+			case VFE_RESET_CMD:
+				msm_camio_vfe_blk_reset();
+				vfestopped = 0;
+				break;
+			case VFE_START_CMD:
+				_mode = (uint32_t *)cmd_data;
+				op_mode = *(++_mode);
+				if (op_mode & SNAPSHOT_MASK_MODE)
+					msm_camio_set_perf_lvl(S_CAPTURE);
+				else
+					msm_camio_set_perf_lvl(S_PREVIEW);
+				vfestopped = 0;
+				break;
+			case VFE_STOP_CMD:
+				vfestopped = 1;
+				goto config_send;
+
+			default:
+				break;
+			}
+		} /* QDSP_CMDQUEUE */
+	}
+		break;
+	case CMD_AXI_CFG_PREVIEW:
+	case CMD_RAW_PICT_AXI_CFG: {
+		axid = data;
+		if (!axid) {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+
+		axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			goto config_failure;
+		}
+
+		if (copy_from_user(axio, (void __user *)(vfecmd->value),
+					sizeof(struct axiout))) {
+			rc = -EFAULT;
+			goto config_done;
+		}
+
+		vfe_7x_config_axi(OUTPUT_2, axid, axio);
+		cmd_data = axio;
+	}
+		break;
+	case CMD_AXI_CFG_SNAP: {
+		axid = data;
+		if (!axid) {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+
+		axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			goto config_failure;
+		}
+
+		if (copy_from_user(axio, (void __user *)(vfecmd->value),
+					sizeof(struct axiout))) {
+			rc = -EFAULT;
+			goto config_done;
+		}
+
+		vfe_7x_config_axi(OUTPUT_1_AND_2, axid, axio);
+
+		cmd_data = axio;
+	}
+		break;
+	default:
+		break;
+	}
+
+	if (vfestopped)
+		goto config_done;
+
+config_send:
+	CDBG("send adsp command = %d\n", *(uint32_t *)cmd_data);
+	rc = msm_adsp_write(vfe_mod, vfecmd->queue,
+				cmd_data, vfecmd->length);
+
+config_done:
+	kfree(cmd_data_alloc);
+
+config_failure:
+	kfree(scfg);
+	kfree(axio);
+	kfree(vfecmd);
+	return rc;
+}
+
+void msm_camvfe_fn_init(struct msm_camvfe_fn *fptr, void *data)
+{
+	mutex_init(&vfe_lock);
+	fptr->vfe_init    = vfe_7x_init;
+	fptr->vfe_enable  = vfe_7x_enable;
+	fptr->vfe_config  = vfe_7x_config;
+	fptr->vfe_disable = vfe_7x_disable;
+	fptr->vfe_release = vfe_7x_release;
+	vfe_syncdata = data;
+}
+
+void msm_camvpe_fn_init(struct msm_camvpe_fn *fptr, void *data)
+{
+	fptr->vpe_reg		= NULL;
+	fptr->send_frame_to_vpe	= NULL;
+	fptr->vpe_config	= NULL;
+	fptr->vpe_cfg_update	= NULL;
+	fptr->dis		= NULL;
+}
diff --git a/drivers/media/video/msm/msm_vfe7x27a.h b/drivers/media/video/msm/msm_vfe7x27a.h
new file mode 100644
index 0000000..a488206
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe7x27a.h
@@ -0,0 +1,300 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __MSM_VFE7X_H__
+#define __MSM_VFE7X_H__
+#include <media/msm_camera.h>
+#include <mach/camera.h>
+
+struct vfe_frame_extra {
+	uint32_t	bl_evencol:23;
+	uint32_t	rvd1:9;
+	uint32_t	bl_oddcol:23;
+	uint32_t	rvd2:9;
+
+	uint32_t	d_dbpc_stats_hot:16;
+	uint32_t	d_dbpc_stats_cold:16;
+
+	uint32_t	d_dbpc_stats_0_hot:10;
+	uint32_t	rvd3:6;
+	uint32_t	d_dbpc_stats_0_cold:10;
+	uint32_t	rvd4:6;
+	uint32_t	d_dbpc_stats_1_hot:10;
+	uint32_t	rvd5:6;
+	uint32_t	d_dbpc_stats_1_cold:10;
+	uint32_t	rvd6:6;
+
+	uint32_t	asf_max_edge;
+
+	uint32_t	e_y_wm_pm_stats_0:21;
+	uint32_t	rvd7:11;
+	uint32_t	e_y_wm_pm_stats_1_bl:8;
+	uint32_t	rvd8:8;
+	uint32_t	e_y_wm_pm_stats_1_nl:12;
+	uint32_t	rvd9:4;
+
+	uint32_t	e_cbcr_wm_pm_stats_0:21;
+	uint32_t	rvd10:11;
+	uint32_t	e_cbcr_wm_pm_stats_1_bl:8;
+	uint32_t	rvd11:8;
+	uint32_t	e_cbcr_wm_pm_stats_1_nl:12;
+	uint32_t	rvd12:4;
+
+	uint32_t	v_y_wm_pm_stats_0:21;
+	uint32_t	rvd13:11;
+	uint32_t	v_y_wm_pm_stats_1_bl:8;
+	uint32_t	rvd14:8;
+	uint32_t	v_y_wm_pm_stats_1_nl:12;
+	uint32_t	rvd15:4;
+
+	uint32_t	v_cbcr_wm_pm_stats_0:21;
+	uint32_t	rvd16:11;
+	uint32_t	v_cbcr_wm_pm_stats_1_bl:8;
+	uint32_t	rvd17:8;
+	uint32_t	v_cbcr_wm_pm_stats_1_nl:12;
+	uint32_t	rvd18:4;
+
+	uint32_t      frame_id;
+};
+
+struct vfe_endframe {
+	uint32_t      y_address;
+	uint32_t      cbcr_address;
+
+	struct vfe_frame_extra extra;
+} __packed;
+
+struct vfe_outputack {
+	uint32_t  header;
+	void      *output2newybufferaddress;
+	void      *output2newcbcrbufferaddress;
+} __packed;
+
+struct vfe_stats_ack {
+	uint32_t header;
+	/* MUST BE 64 bit ALIGNED */
+	void     *bufaddr;
+} __packed;
+
+/* AXI Output Config Command sent to DSP */
+struct axiout {
+	uint32_t            cmdheader:32;
+	int                 outputmode:3;
+	uint8_t             format:2;
+	uint32_t            /* reserved */ : 27;
+
+	/* AXI Output 1 Y Configuration, Part 1 */
+	uint32_t            out1yimageheight:12;
+	uint32_t            /* reserved */ : 4;
+	uint32_t            out1yimagewidthin64bitwords:10;
+	uint32_t            /* reserved */ : 6;
+
+	/* AXI Output 1 Y Configuration, Part 2 */
+	uint8_t             out1yburstlen:2;
+	uint32_t            out1ynumrows:12;
+	uint32_t            out1yrowincin64bitincs:12;
+	uint32_t            /* reserved */ : 6;
+
+	/* AXI Output 1 CbCr Configuration, Part 1 */
+	uint32_t            out1cbcrimageheight:12;
+	uint32_t            /* reserved */ : 4;
+	uint32_t            out1cbcrimagewidthin64bitwords:10;
+	uint32_t            /* reserved */ : 6;
+
+	/* AXI Output 1 CbCr Configuration, Part 2 */
+	uint8_t             out1cbcrburstlen:2;
+	uint32_t            out1cbcrnumrows:12;
+	uint32_t            out1cbcrrowincin64bitincs:12;
+	uint32_t            /* reserved */ : 6;
+
+	/* AXI Output 2 Y Configuration, Part 1 */
+	uint32_t            out2yimageheight:12;
+	uint32_t            /* reserved */ : 4;
+	uint32_t            out2yimagewidthin64bitwords:10;
+	uint32_t            /* reserved */ : 6;
+
+	/* AXI Output 2 Y Configuration, Part 2 */
+	uint8_t             out2yburstlen:2;
+	uint32_t            out2ynumrows:12;
+	uint32_t            out2yrowincin64bitincs:12;
+	uint32_t            /* reserved */ : 6;
+
+	/* AXI Output 2 CbCr Configuration, Part 1 */
+	uint32_t            out2cbcrimageheight:12;
+	uint32_t            /* reserved */ : 4;
+	uint32_t            out2cbcrimagewidtein64bitwords:10;
+	uint32_t            /* reserved */ : 6;
+
+	/* AXI Output 2 CbCr Configuration, Part 2 */
+	uint8_t             out2cbcrburstlen:2;
+	uint32_t            out2cbcrnumrows:12;
+	uint32_t            out2cbcrrowincin64bitincs:12;
+	uint32_t            /* reserved */ : 6;
+
+	/* Address configuration:
+	 * output1 phisycal address */
+	unsigned long   output1buffer1_y_phy;
+	unsigned long   output1buffer1_cbcr_phy;
+	unsigned long   output1buffer2_y_phy;
+	unsigned long   output1buffer2_cbcr_phy;
+	unsigned long   output1buffer3_y_phy;
+	unsigned long   output1buffer3_cbcr_phy;
+	unsigned long   output1buffer4_y_phy;
+	unsigned long   output1buffer4_cbcr_phy;
+	unsigned long   output1buffer5_y_phy;
+	unsigned long   output1buffer5_cbcr_phy;
+	unsigned long   output1buffer6_y_phy;
+	unsigned long   output1buffer6_cbcr_phy;
+	unsigned long   output1buffer7_y_phy;
+	unsigned long   output1buffer7_cbcr_phy;
+	unsigned long   output1buffer8_y_phy;
+	unsigned long   output1buffer8_cbcr_phy;
+
+	/* output2 phisycal address */
+	unsigned long   output2buffer1_y_phy;
+	unsigned long   output2buffer1_cbcr_phy;
+	unsigned long   output2buffer2_y_phy;
+	unsigned long   output2buffer2_cbcr_phy;
+	unsigned long   output2buffer3_y_phy;
+	unsigned long   output2buffer3_cbcr_phy;
+	unsigned long   output2buffer4_y_phy;
+	unsigned long   output2buffer4_cbcr_phy;
+	unsigned long   output2buffer5_y_phy;
+	unsigned long   output2buffer5_cbcr_phy;
+	unsigned long   output2buffer6_y_phy;
+	unsigned long   output2buffer6_cbcr_phy;
+	unsigned long   output2buffer7_y_phy;
+	unsigned long   output2buffer7_cbcr_phy;
+	unsigned long   output2buffer8_y_phy;
+	unsigned long   output2buffer8_cbcr_phy;
+} __packed;
+
+struct vfe_stats_we_cfg {
+	uint32_t       header;
+
+	/* White Balance/Exposure Statistic Selection */
+	uint8_t        wb_expstatsenable:1;
+	uint8_t        wb_expstatbuspriorityselection:1;
+	unsigned int   wb_expstatbuspriorityvalue:4;
+	unsigned int   /* reserved */ : 26;
+
+	/* White Balance/Exposure Statistic Configuration, Part 1 */
+	uint8_t        exposurestatregions:1;
+	uint8_t        exposurestatsubregions:1;
+	unsigned int   /* reserved */ : 14;
+
+	unsigned int   whitebalanceminimumy:8;
+	unsigned int   whitebalancemaximumy:8;
+
+	/* White Balance/Exposure Statistic Configuration, Part 2 */
+	uint8_t wb_expstatslopeofneutralregionline[
+		NUM_WB_EXP_NEUTRAL_REGION_LINES];
+
+	/* White Balance/Exposure Statistic Configuration, Part 3 */
+	unsigned int   wb_expstatcrinterceptofneutralregionline2:12;
+	unsigned int   /* reserved */ : 4;
+	unsigned int   wb_expstatcbinterceptofneutralreginnline1:12;
+	unsigned int    /* reserved */ : 4;
+
+	/* White Balance/Exposure Statistic Configuration, Part 4 */
+	unsigned int   wb_expstatcrinterceptofneutralregionline4:12;
+	unsigned int   /* reserved */ : 4;
+	unsigned int   wb_expstatcbinterceptofneutralregionline3:12;
+	unsigned int   /* reserved */ : 4;
+
+	/* White Balance/Exposure Statistic Output Buffer Header */
+	unsigned int   wb_expmetricheaderpattern:8;
+	unsigned int   /* reserved */ : 24;
+
+	/* White Balance/Exposure Statistic Output Buffers-MUST
+	* BE 64 bit ALIGNED */
+	void  *wb_expstatoutputbuffer[NUM_WB_EXP_STAT_OUTPUT_BUFFERS];
+} __packed;
+
+struct vfe_stats_af_cfg {
+	uint32_t header;
+
+	/* Autofocus Statistic Selection */
+	uint8_t       af_enable:1;
+	uint8_t       af_busprioritysel:1;
+	unsigned int  af_buspriorityval:4;
+	unsigned int  /* reserved */ : 26;
+
+	/* Autofocus Statistic Configuration, Part 1 */
+	unsigned int  af_singlewinvoffset:12;
+	unsigned int  /* reserved */ : 4;
+	unsigned int  af_singlewinhoffset:12;
+	unsigned int  /* reserved */ : 3;
+	uint8_t       af_winmode:1;
+
+	/* Autofocus Statistic Configuration, Part 2 */
+	unsigned int  af_singglewinvh:11;
+	unsigned int  /* reserved */ : 5;
+	unsigned int  af_singlewinhw:11;
+	unsigned int  /* reserved */ : 5;
+
+	/* Autofocus Statistic Configuration, Parts 3-6 */
+	uint8_t       af_multiwingrid[NUM_AUTOFOCUS_MULTI_WINDOW_GRIDS];
+
+	/* Autofocus Statistic Configuration, Part 7 */
+	signed int    af_metrichpfcoefa00:5;
+	signed int    af_metrichpfcoefa04:5;
+	unsigned int  af_metricmaxval:11;
+	uint8_t       af_metricsel:1;
+	unsigned int  /* reserved */ : 10;
+
+	/* Autofocus Statistic Configuration, Part 8 */
+	signed int    af_metrichpfcoefa20:5;
+	signed int    af_metrichpfcoefa21:5;
+	signed int    af_metrichpfcoefa22:5;
+	signed int    af_metrichpfcoefa23:5;
+	signed int    af_metrichpfcoefa24:5;
+	unsigned int  /* reserved */ : 7;
+
+	/* Autofocus Statistic Output Buffer Header */
+	unsigned int  af_metrichp:8;
+	unsigned int  /* reserved */ : 24;
+
+	/* Autofocus Statistic Output Buffers - MUST BE 64 bit ALIGNED!!! */
+	void *af_outbuf[NUM_AF_STAT_OUTPUT_BUFFERS];
+} __packed; /* VFE_StatsAutofocusConfigCmdType */
+
+struct msm_camera_frame_msg {
+	unsigned long   output_y_address;
+	unsigned long   output_cbcr_address;
+
+	unsigned int    blacklevelevenColumn:23;
+	uint16_t        reserved1:9;
+	unsigned int    blackleveloddColumn:23;
+	uint16_t        reserved2:9;
+
+	uint16_t        greendefectpixelcount:8;
+	uint16_t        reserved3:8;
+	uint16_t        redbluedefectpixelcount:8;
+	uint16_t        reserved4:8;
+} __packed;
+
+/* New one for 7k */
+struct msm_vfe_command_7k {
+	uint16_t queue;
+	uint16_t length;
+	void     *value;
+};
+
+struct stop_event {
+	wait_queue_head_t wait;
+	int state;
+	int timeout;
+};
+
+
+#endif /* __MSM_VFE7X_H__ */
diff --git a/drivers/media/video/msm/msm_vfe8x.c b/drivers/media/video/msm/msm_vfe8x.c
new file mode 100644
index 0000000..0bf1785
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe8x.c
@@ -0,0 +1,842 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <mach/irqs.h>
+#include "msm_vfe8x_proc.h"
+#include <linux/pm_qos_params.h>
+
+#define ON  1
+#define OFF 0
+
+static const char *vfe_general_cmd[] = {
+	"START",  /* 0 */
+	"RESET",
+	"AXI_INPUT_CONFIG",
+	"CAMIF_CONFIG",
+	"AXI_OUTPUT_CONFIG",
+	"BLACK_LEVEL_CONFIG",  /* 5 */
+	"ROLL_OFF_CONFIG",
+	"DEMUX_CHANNEL_GAIN_CONFIG",
+	"DEMOSAIC_CONFIG",
+	"FOV_CROP_CONFIG",
+	"MAIN_SCALER_CONFIG",  /* 10 */
+	"WHITE_BALANCE_CONFIG",
+	"COLOR_CORRECTION_CONFIG",
+	"LA_CONFIG",
+	"RGB_GAMMA_CONFIG",
+	"CHROMA_ENHAN_CONFIG",  /* 15 */
+	"CHROMA_SUPPRESSION_CONFIG",
+	"ASF_CONFIG",
+	"SCALER2Y_CONFIG",
+	"SCALER2CbCr_CONFIG",
+	"CHROMA_SUBSAMPLE_CONFIG",  /* 20 */
+	"FRAME_SKIP_CONFIG",
+	"OUTPUT_CLAMP_CONFIG",
+	"TEST_GEN_START",
+	"UPDATE",
+	"OUTPUT1_ACK",  /* 25 */
+	"OUTPUT2_ACK",
+	"EPOCH1_ACK",
+	"EPOCH2_ACK",
+	"STATS_AUTOFOCUS_ACK",
+	"STATS_WB_EXP_ACK",  /* 30 */
+	"BLACK_LEVEL_UPDATE",
+	"DEMUX_CHANNEL_GAIN_UPDATE",
+	"DEMOSAIC_BPC_UPDATE",
+	"DEMOSAIC_ABF_UPDATE",
+	"FOV_CROP_UPDATE",  /* 35 */
+	"WHITE_BALANCE_UPDATE",
+	"COLOR_CORRECTION_UPDATE",
+	"LA_UPDATE",
+	"RGB_GAMMA_UPDATE",
+	"CHROMA_ENHAN_UPDATE",  /* 40 */
+	"CHROMA_SUPPRESSION_UPDATE",
+	"MAIN_SCALER_UPDATE",
+	"SCALER2CbCr_UPDATE",
+	"SCALER2Y_UPDATE",
+	"ASF_UPDATE",  /* 45 */
+	"FRAME_SKIP_UPDATE",
+	"CAMIF_FRAME_UPDATE",
+	"STATS_AUTOFOCUS_UPDATE",
+	"STATS_WB_EXP_UPDATE",
+	"STOP",  /* 50 */
+	"GET_HW_VERSION",
+	"STATS_SETTING",
+	"STATS_AUTOFOCUS_START",
+	"STATS_AUTOFOCUS_STOP",
+	"STATS_WB_EXP_START",  /* 55 */
+	"STATS_WB_EXP_STOP",
+	"ASYNC_TIMER_SETTING",
+};
+
+static void     *vfe_syncdata;
+
+static int vfe_enable(struct camera_enable_cmd *enable)
+{
+	return 0;
+}
+
+static int vfe_disable(struct camera_enable_cmd *enable,
+	struct platform_device *dev)
+{
+	vfe_stop();
+	msm_camio_disable(dev);
+	return 0;
+}
+
+static void vfe_release(struct platform_device *dev)
+{
+	msm_camio_disable(dev);
+	vfe_cmd_release(dev);
+	update_axi_qos(PM_QOS_DEFAULT_VALUE);
+	vfe_syncdata = NULL;
+}
+
+static void vfe_config_axi(int mode,
+			   struct axidata *ad,
+			   struct vfe_cmd_axi_output_config *ao)
+{
+	struct msm_pmem_region *regptr, *regptr1;
+	int i, j;
+	uint32_t *p1, *p2;
+
+	if (mode == OUTPUT_1 || mode == OUTPUT_1_AND_2) {
+		regptr = ad->region;
+		for (i = 0; i < ad->bufnum1; i++) {
+
+			p1 = &(ao->output1.outputY.outFragments[i][0]);
+			p2 = &(ao->output1.outputCbcr.outFragments[i][0]);
+
+			for (j = 0; j < ao->output1.fragmentCount; j++) {
+
+				*p1 = regptr->paddr + regptr->info.y_off;
+				p1++;
+
+				*p2 = regptr->paddr + regptr->info.cbcr_off;
+				p2++;
+			}
+			regptr++;
+		}
+	} /* if OUTPUT1 or Both */
+
+	if (mode == OUTPUT_2 || mode == OUTPUT_1_AND_2) {
+
+		regptr = &(ad->region[ad->bufnum1]);
+		CDBG("bufnum2 = %d\n", ad->bufnum2);
+
+		for (i = 0; i < ad->bufnum2; i++) {
+
+			p1 = &(ao->output2.outputY.outFragments[i][0]);
+			p2 = &(ao->output2.outputCbcr.outFragments[i][0]);
+
+			CDBG("config_axi: O2, phy = 0x%lx, y_off = %d, "\
+			     "cbcr_off = %d\n", regptr->paddr,
+			     regptr->info.y_off, regptr->info.cbcr_off);
+
+			for (j = 0; j < ao->output2.fragmentCount; j++) {
+
+				*p1 = regptr->paddr + regptr->info.y_off;
+				CDBG("vfe_config_axi: p1 = 0x%x\n", *p1);
+				p1++;
+
+				*p2 = regptr->paddr + regptr->info.cbcr_off;
+				CDBG("vfe_config_axi: p2 = 0x%x\n", *p2);
+				p2++;
+			}
+			regptr++;
+		}
+	}
+	/* For video configuration */
+	if (mode == OUTPUT_1_AND_3) {
+		/* this is preview buffer. */
+		regptr =  &(ad->region[0]);
+		/* this is video buffer. */
+		regptr1 = &(ad->region[ad->bufnum1]);
+		CDBG("bufnum1 = %d\n", ad->bufnum1);
+		CDBG("bufnum2 = %d\n", ad->bufnum2);
+
+	for (i = 0; i < ad->bufnum1; i++) {
+		p1 = &(ao->output1.outputY.outFragments[i][0]);
+		p2 = &(ao->output1.outputCbcr.outFragments[i][0]);
+
+		CDBG("config_axi: O1, phy = 0x%lx, y_off = %d, "\
+			 "cbcr_off = %d\n", regptr->paddr,
+			 regptr->info.y_off, regptr->info.cbcr_off);
+
+			for (j = 0; j < ao->output1.fragmentCount; j++) {
+
+				*p1 = regptr->paddr + regptr->info.y_off;
+				CDBG("vfe_config_axi: p1 = 0x%x\n", *p1);
+				p1++;
+
+				*p2 = regptr->paddr + regptr->info.cbcr_off;
+				CDBG("vfe_config_axi: p2 = 0x%x\n", *p2);
+				p2++;
+			}
+			regptr++;
+		}
+	for (i = 0; i < ad->bufnum2; i++) {
+		p1 = &(ao->output2.outputY.outFragments[i][0]);
+		p2 = &(ao->output2.outputCbcr.outFragments[i][0]);
+
+		CDBG("config_axi: O2, phy = 0x%lx, y_off = %d, "\
+			 "cbcr_off = %d\n", regptr1->paddr,
+			 regptr1->info.y_off, regptr1->info.cbcr_off);
+
+			for (j = 0; j < ao->output2.fragmentCount; j++) {
+
+				*p1 = regptr1->paddr + regptr1->info.y_off;
+				CDBG("vfe_config_axi: p1 = 0x%x\n", *p1);
+				p1++;
+
+				*p2 = regptr1->paddr + regptr1->info.cbcr_off;
+				CDBG("vfe_config_axi: p2 = 0x%x\n", *p2);
+				p2++;
+			}
+			regptr1++;
+		}
+	}
+
+}
+
+#define CHECKED_COPY_FROM_USER(in) {					\
+	if (cmd->length != sizeof(*(in))) {				\
+		pr_err("msm_camera: %s:%d cmd %d: user data size %d "	\
+			"!= kernel data size %d\n",			\
+			__func__, __LINE__,				\
+			cmd->id, cmd->length, sizeof(*(in)));		\
+		rc = -EIO;						\
+		break;							\
+	}								\
+	if (copy_from_user((in), (void __user *)cmd->value,		\
+			sizeof(*(in)))) {				\
+		rc = -EFAULT;						\
+		break;							\
+	}								\
+}
+
+static int vfe_proc_general(struct msm_vfe_command_8k *cmd)
+{
+	int rc = 0;
+
+	CDBG("%s: cmdID = %s\n", __func__, vfe_general_cmd[cmd->id]);
+
+	switch (cmd->id) {
+	case VFE_CMD_ID_RESET:
+		msm_camio_vfe_blk_reset();
+		msm_camio_camif_pad_reg_reset_2();
+		vfe_reset();
+		break;
+
+	case VFE_CMD_ID_START: {
+		struct vfe_cmd_start start;
+			CHECKED_COPY_FROM_USER(&start);
+
+		/* msm_camio_camif_pad_reg_reset_2(); */
+		msm_camio_camif_pad_reg_reset();
+		vfe_start(&start);
+	}
+		break;
+
+	case VFE_CMD_ID_CAMIF_CONFIG: {
+		struct vfe_cmd_camif_config camif;
+			CHECKED_COPY_FROM_USER(&camif);
+
+		vfe_camif_config(&camif);
+	}
+		break;
+
+	case VFE_CMD_ID_BLACK_LEVEL_CONFIG: {
+		struct vfe_cmd_black_level_config bl;
+			CHECKED_COPY_FROM_USER(&bl);
+
+		vfe_black_level_config(&bl);
+	}
+		break;
+
+	case VFE_CMD_ID_ROLL_OFF_CONFIG:{
+			/* rolloff is too big to be on the stack */
+			struct vfe_cmd_roll_off_config *rolloff =
+			    kmalloc(sizeof(struct vfe_cmd_roll_off_config),
+				    GFP_KERNEL);
+			if (!rolloff) {
+				pr_err("%s: out of memory\n", __func__);
+				rc = -ENOMEM;
+				break;
+			}
+			/* Wrap CHECKED_COPY_FROM_USER() in a do-while(0) loop
+			 * to make sure we free rolloff when copy_from_user()
+			 * fails.
+			 */
+			do {
+				CHECKED_COPY_FROM_USER(rolloff);
+				vfe_roll_off_config(rolloff);
+			} while (0);
+			kfree(rolloff);
+	}
+		break;
+
+	case VFE_CMD_ID_DEMUX_CHANNEL_GAIN_CONFIG: {
+		struct vfe_cmd_demux_channel_gain_config demuxc;
+			CHECKED_COPY_FROM_USER(&demuxc);
+
+		/* demux is always enabled.  */
+		vfe_demux_channel_gain_config(&demuxc);
+	}
+		break;
+
+	case VFE_CMD_ID_DEMOSAIC_CONFIG: {
+		struct vfe_cmd_demosaic_config demosaic;
+			CHECKED_COPY_FROM_USER(&demosaic);
+
+		vfe_demosaic_config(&demosaic);
+	}
+		break;
+
+	case VFE_CMD_ID_FOV_CROP_CONFIG:
+	case VFE_CMD_ID_FOV_CROP_UPDATE: {
+		struct vfe_cmd_fov_crop_config fov;
+			CHECKED_COPY_FROM_USER(&fov);
+
+		vfe_fov_crop_config(&fov);
+	}
+		break;
+
+	case VFE_CMD_ID_MAIN_SCALER_CONFIG:
+	case VFE_CMD_ID_MAIN_SCALER_UPDATE: {
+		struct vfe_cmd_main_scaler_config mainds;
+			CHECKED_COPY_FROM_USER(&mainds);
+
+		vfe_main_scaler_config(&mainds);
+	}
+		break;
+
+	case VFE_CMD_ID_WHITE_BALANCE_CONFIG:
+	case VFE_CMD_ID_WHITE_BALANCE_UPDATE: {
+		struct vfe_cmd_white_balance_config wb;
+			CHECKED_COPY_FROM_USER(&wb);
+
+		vfe_white_balance_config(&wb);
+	}
+		break;
+
+	case VFE_CMD_ID_COLOR_CORRECTION_CONFIG:
+	case VFE_CMD_ID_COLOR_CORRECTION_UPDATE: {
+		struct vfe_cmd_color_correction_config cc;
+			CHECKED_COPY_FROM_USER(&cc);
+
+		vfe_color_correction_config(&cc);
+	}
+		break;
+
+	case VFE_CMD_ID_LA_CONFIG: {
+		struct vfe_cmd_la_config la;
+			CHECKED_COPY_FROM_USER(&la);
+
+		vfe_la_config(&la);
+	}
+		break;
+
+	case VFE_CMD_ID_RGB_GAMMA_CONFIG: {
+		struct vfe_cmd_rgb_gamma_config rgb;
+			CHECKED_COPY_FROM_USER(&rgb);
+
+		rc = vfe_rgb_gamma_config(&rgb);
+	}
+		break;
+
+	case VFE_CMD_ID_CHROMA_ENHAN_CONFIG:
+	case VFE_CMD_ID_CHROMA_ENHAN_UPDATE: {
+		struct vfe_cmd_chroma_enhan_config chrom;
+			CHECKED_COPY_FROM_USER(&chrom);
+
+		vfe_chroma_enhan_config(&chrom);
+	}
+		break;
+
+	case VFE_CMD_ID_CHROMA_SUPPRESSION_CONFIG:
+	case VFE_CMD_ID_CHROMA_SUPPRESSION_UPDATE: {
+		struct vfe_cmd_chroma_suppression_config chromsup;
+			CHECKED_COPY_FROM_USER(&chromsup);
+
+		vfe_chroma_sup_config(&chromsup);
+	}
+		break;
+
+	case VFE_CMD_ID_ASF_CONFIG: {
+		struct vfe_cmd_asf_config asf;
+			CHECKED_COPY_FROM_USER(&asf);
+
+		vfe_asf_config(&asf);
+	}
+		break;
+
+	case VFE_CMD_ID_SCALER2Y_CONFIG:
+	case VFE_CMD_ID_SCALER2Y_UPDATE: {
+		struct vfe_cmd_scaler2_config ds2y;
+			CHECKED_COPY_FROM_USER(&ds2y);
+
+		vfe_scaler2y_config(&ds2y);
+	}
+		break;
+
+	case VFE_CMD_ID_SCALER2CbCr_CONFIG:
+	case VFE_CMD_ID_SCALER2CbCr_UPDATE: {
+		struct vfe_cmd_scaler2_config ds2cbcr;
+			CHECKED_COPY_FROM_USER(&ds2cbcr);
+
+		vfe_scaler2cbcr_config(&ds2cbcr);
+	}
+		break;
+
+	case VFE_CMD_ID_CHROMA_SUBSAMPLE_CONFIG: {
+		struct vfe_cmd_chroma_subsample_config sub;
+			CHECKED_COPY_FROM_USER(&sub);
+
+		vfe_chroma_subsample_config(&sub);
+	}
+		break;
+
+	case VFE_CMD_ID_FRAME_SKIP_CONFIG: {
+		struct vfe_cmd_frame_skip_config fskip;
+			CHECKED_COPY_FROM_USER(&fskip);
+
+		vfe_frame_skip_config(&fskip);
+	}
+		break;
+
+	case VFE_CMD_ID_OUTPUT_CLAMP_CONFIG: {
+		struct vfe_cmd_output_clamp_config clamp;
+			CHECKED_COPY_FROM_USER(&clamp);
+
+		vfe_output_clamp_config(&clamp);
+	}
+		break;
+
+	/* module update commands */
+	case VFE_CMD_ID_BLACK_LEVEL_UPDATE: {
+		struct vfe_cmd_black_level_config blk;
+			CHECKED_COPY_FROM_USER(&blk);
+
+		vfe_black_level_update(&blk);
+	}
+		break;
+
+	case VFE_CMD_ID_DEMUX_CHANNEL_GAIN_UPDATE: {
+		struct vfe_cmd_demux_channel_gain_config dmu;
+			CHECKED_COPY_FROM_USER(&dmu);
+
+		vfe_demux_channel_gain_update(&dmu);
+	}
+		break;
+
+	case VFE_CMD_ID_DEMOSAIC_BPC_UPDATE: {
+		struct vfe_cmd_demosaic_bpc_update demo_bpc;
+			CHECKED_COPY_FROM_USER(&demo_bpc);
+
+		vfe_demosaic_bpc_update(&demo_bpc);
+	}
+		break;
+
+	case VFE_CMD_ID_DEMOSAIC_ABF_UPDATE: {
+		struct vfe_cmd_demosaic_abf_update demo_abf;
+			CHECKED_COPY_FROM_USER(&demo_abf);
+
+		vfe_demosaic_abf_update(&demo_abf);
+	}
+		break;
+
+	case VFE_CMD_ID_LA_UPDATE: {
+		struct vfe_cmd_la_config la;
+			CHECKED_COPY_FROM_USER(&la);
+
+		vfe_la_update(&la);
+	}
+		break;
+
+	case VFE_CMD_ID_RGB_GAMMA_UPDATE: {
+		struct vfe_cmd_rgb_gamma_config rgb;
+			CHECKED_COPY_FROM_USER(&rgb);
+
+		rc = vfe_rgb_gamma_update(&rgb);
+	}
+		break;
+
+	case VFE_CMD_ID_ASF_UPDATE: {
+		struct vfe_cmd_asf_update asf;
+			CHECKED_COPY_FROM_USER(&asf);
+
+		vfe_asf_update(&asf);
+	}
+		break;
+
+	case VFE_CMD_ID_FRAME_SKIP_UPDATE: {
+		struct vfe_cmd_frame_skip_update fskip;
+			CHECKED_COPY_FROM_USER(&fskip);
+			/* Start recording */
+			if (fskip.output2Pattern == 0xffffffff)
+				update_axi_qos(MSM_AXI_QOS_RECORDING);
+			 else if (fskip.output2Pattern == 0)
+				update_axi_qos(MSM_AXI_QOS_PREVIEW);
+
+		vfe_frame_skip_update(&fskip);
+	}
+		break;
+
+	case VFE_CMD_ID_CAMIF_FRAME_UPDATE: {
+		struct vfe_cmds_camif_frame fup;
+			CHECKED_COPY_FROM_USER(&fup);
+
+		vfe_camif_frame_update(&fup);
+	}
+		break;
+
+	/* stats update commands */
+	case VFE_CMD_ID_STATS_AUTOFOCUS_UPDATE: {
+		struct vfe_cmd_stats_af_update afup;
+			CHECKED_COPY_FROM_USER(&afup);
+
+		vfe_stats_update_af(&afup);
+	}
+		break;
+
+	case VFE_CMD_ID_STATS_WB_EXP_UPDATE: {
+		struct vfe_cmd_stats_wb_exp_update wbexp;
+			CHECKED_COPY_FROM_USER(&wbexp);
+
+		vfe_stats_update_wb_exp(&wbexp);
+	}
+		break;
+
+	/* control of start, stop, update, etc... */
+	case VFE_CMD_ID_STOP:
+		vfe_stop();
+		break;
+
+	case VFE_CMD_ID_GET_HW_VERSION:
+		break;
+
+	/* stats */
+	case VFE_CMD_ID_STATS_SETTING: {
+		struct vfe_cmd_stats_setting stats;
+			CHECKED_COPY_FROM_USER(&stats);
+
+		vfe_stats_setting(&stats);
+	}
+		break;
+
+	case VFE_CMD_ID_STATS_AUTOFOCUS_START: {
+		struct vfe_cmd_stats_af_start af;
+			CHECKED_COPY_FROM_USER(&af);
+
+		vfe_stats_start_af(&af);
+	}
+		break;
+
+	case VFE_CMD_ID_STATS_AUTOFOCUS_STOP:
+		vfe_stats_af_stop();
+		break;
+
+	case VFE_CMD_ID_STATS_WB_EXP_START: {
+		struct vfe_cmd_stats_wb_exp_start awexp;
+			CHECKED_COPY_FROM_USER(&awexp);
+
+		vfe_stats_start_wb_exp(&awexp);
+	}
+		break;
+
+	case VFE_CMD_ID_STATS_WB_EXP_STOP:
+		vfe_stats_wb_exp_stop();
+		break;
+
+	case VFE_CMD_ID_ASYNC_TIMER_SETTING:
+		break;
+
+	case VFE_CMD_ID_UPDATE:
+		vfe_update();
+		break;
+
+	/* test gen */
+	case VFE_CMD_ID_TEST_GEN_START:
+		break;
+
+/*
+  acknowledge from upper layer
+	these are not in general command.
+
+	case VFE_CMD_ID_OUTPUT1_ACK:
+		break;
+	case VFE_CMD_ID_OUTPUT2_ACK:
+		break;
+	case VFE_CMD_ID_EPOCH1_ACK:
+		break;
+	case VFE_CMD_ID_EPOCH2_ACK:
+		break;
+	case VFE_CMD_ID_STATS_AUTOFOCUS_ACK:
+		break;
+	case VFE_CMD_ID_STATS_WB_EXP_ACK:
+		break;
+*/
+
+	default:
+		pr_err("%s: invalid cmd id %d\n", __func__, cmd->id);
+		rc = -EINVAL;
+		break;
+	} /* switch */
+
+	return rc;
+}
+
+static int vfe_config(struct msm_vfe_cfg_cmd *cmd, void *data)
+{
+	struct msm_pmem_region *regptr;
+	struct msm_vfe_command_8k vfecmd;
+	struct vfe_cmd_axi_output_config axio;
+	struct axidata *axid = data;
+
+	int rc = 0;
+
+
+	if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
+
+		if (copy_from_user(&vfecmd,
+			(void __user *)(cmd->value), sizeof(vfecmd))) {
+			pr_err("%s %d: copy_from_user failed\n",
+				__func__, __LINE__);
+			return -EFAULT;
+		}
+	}
+
+	CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
+
+	switch (cmd->cmd_type) {
+	case CMD_GENERAL:
+		rc = vfe_proc_general(&vfecmd);
+		break;
+
+	case CMD_STATS_ENABLE:
+	case CMD_STATS_AXI_CFG: {
+			int i;
+			struct vfe_cmd_stats_setting scfg;
+
+			BUG_ON(!axid);
+
+			if (vfecmd.length != sizeof(scfg)) {
+				pr_err
+				("msm_camera: %s: cmd %d: user-space "\
+				"data size %d != kernel data size %d\n",
+				__func__,
+				cmd->cmd_type, vfecmd.length,
+				sizeof(scfg));
+				return -EIO;
+			}
+
+			if (copy_from_user(&scfg,
+				(void __user *)(vfecmd.value),
+				sizeof(scfg))) {
+				pr_err("%s %d: copy_from_user failed\n",
+				__func__, __LINE__);
+			return -EFAULT;
+		}
+
+		regptr = axid->region;
+		if (axid->bufnum1 > 0) {
+			for (i = 0; i < axid->bufnum1; i++) {
+					scfg.awbBuffer[i] =
+					(uint32_t)(regptr->paddr);
+				regptr++;
+			}
+		}
+
+		if (axid->bufnum2 > 0) {
+			for (i = 0; i < axid->bufnum2; i++) {
+					scfg.afBuffer[i] =
+					(uint32_t)(regptr->paddr);
+				regptr++;
+			}
+		}
+
+			vfe_stats_setting(&scfg);
+	}
+		break;
+
+	case CMD_STATS_AF_AXI_CFG:
+		break;
+
+	case CMD_FRAME_BUF_RELEASE: {
+		/* preview buffer release */
+		struct msm_frame *b;
+		unsigned long p;
+		struct vfe_cmd_output_ack fack;
+
+			BUG_ON(!data);
+
+		b = (struct msm_frame *)(cmd->value);
+		p = *(unsigned long *)data;
+
+			fack.ybufaddr[0] = (uint32_t) (p + b->y_off);
+
+			fack.chromabufaddr[0] = (uint32_t) (p + b->cbcr_off);
+
+		if (b->path == OUTPUT_TYPE_P)
+			vfe_output_p_ack(&fack);
+
+		if ((b->path == OUTPUT_TYPE_V)
+			 || (b->path == OUTPUT_TYPE_S))
+			vfe_output_v_ack(&fack);
+	}
+		break;
+
+	case CMD_SNAP_BUF_RELEASE:
+		break;
+
+	case CMD_STATS_BUF_RELEASE: {
+		struct vfe_cmd_stats_wb_exp_ack sack;
+
+			BUG_ON(!data);
+
+		sack.nextWbExpOutputBufferAddr = *(uint32_t *)data;
+		vfe_stats_wb_exp_ack(&sack);
+	}
+		break;
+
+	case CMD_STATS_AF_BUF_RELEASE: {
+		struct vfe_cmd_stats_af_ack ack;
+
+			BUG_ON(!data);
+
+		ack.nextAFOutputBufferAddr = *(uint32_t *)data;
+		vfe_stats_af_ack(&ack);
+	}
+		break;
+
+	case CMD_AXI_CFG_PREVIEW:
+	case CMD_RAW_PICT_AXI_CFG: {
+
+			BUG_ON(!axid);
+
+			if (copy_from_user(&axio, (void __user *)(vfecmd.value),
+				sizeof(axio))) {
+				pr_err("%s %d: copy_from_user failed\n",
+					__func__, __LINE__);
+			return -EFAULT;
+		}
+			/* Validate the data from user space */
+			if (axio.output2.fragmentCount <
+				VFE_MIN_NUM_FRAGMENTS_PER_FRAME ||
+				axio.output2.fragmentCount >
+				VFE_MAX_NUM_FRAGMENTS_PER_FRAME)
+				return -EINVAL;
+
+			vfe_config_axi(OUTPUT_2, axid, &axio);
+			axio.outputDataSize = 0;
+			vfe_axi_output_config(&axio);
+	}
+		break;
+
+	case CMD_AXI_CFG_SNAP: {
+
+			BUG_ON(!axid);
+
+			if (copy_from_user(&axio, (void __user *)(vfecmd.value),
+				sizeof(axio))) {
+				pr_err("%s %d: copy_from_user failed\n",
+					__func__, __LINE__);
+			return -EFAULT;
+		}
+			/* Validate the data from user space */
+			if (axio.output1.fragmentCount <
+				VFE_MIN_NUM_FRAGMENTS_PER_FRAME ||
+				axio.output1.fragmentCount >
+				VFE_MAX_NUM_FRAGMENTS_PER_FRAME ||
+				axio.output2.fragmentCount <
+				VFE_MIN_NUM_FRAGMENTS_PER_FRAME ||
+				axio.output2.fragmentCount >
+				VFE_MAX_NUM_FRAGMENTS_PER_FRAME)
+				return -EINVAL;
+
+			vfe_config_axi(OUTPUT_1_AND_2, axid, &axio);
+			vfe_axi_output_config(&axio);
+	}
+		break;
+
+	case CMD_AXI_CFG_VIDEO: {
+			BUG_ON(!axid);
+
+			if (copy_from_user(&axio, (void __user *)(vfecmd.value),
+				sizeof(axio))) {
+				pr_err("%s %d: copy_from_user failed\n",
+					__func__, __LINE__);
+			return -EFAULT;
+		}
+			/* Validate the data from user space */
+			if (axio.output1.fragmentCount <
+				VFE_MIN_NUM_FRAGMENTS_PER_FRAME ||
+				axio.output1.fragmentCount >
+				VFE_MAX_NUM_FRAGMENTS_PER_FRAME ||
+				axio.output2.fragmentCount <
+				VFE_MIN_NUM_FRAGMENTS_PER_FRAME ||
+				axio.output2.fragmentCount >
+				VFE_MAX_NUM_FRAGMENTS_PER_FRAME)
+				return -EINVAL;
+
+			vfe_config_axi(OUTPUT_1_AND_3, axid, &axio);
+			axio.outputDataSize = 0;
+			vfe_axi_output_config(&axio);
+	}
+		break;
+
+	default:
+		break;
+	} /* switch */
+
+	return rc;
+}
+
+static int vfe_init(struct msm_vfe_callback *presp, struct platform_device *dev)
+{
+	int rc = 0;
+
+	rc = vfe_cmd_init(presp, dev, vfe_syncdata);
+	if (rc < 0)
+		return rc;
+
+	/* Bring up all the required GPIOs and Clocks */
+	rc = msm_camio_enable(dev);
+
+	return rc;
+}
+
+void msm_camvfe_fn_init(struct msm_camvfe_fn *fptr, void *data)
+{
+	fptr->vfe_init    = vfe_init;
+	fptr->vfe_enable  = vfe_enable;
+	fptr->vfe_config  = vfe_config;
+	fptr->vfe_disable = vfe_disable;
+	fptr->vfe_release = vfe_release;
+	vfe_syncdata = data;
+}
+
+void msm_camvpe_fn_init(struct msm_camvpe_fn *fptr, void *data)
+{
+	fptr->vpe_reg		= NULL;
+	fptr->send_frame_to_vpe	= NULL;
+	fptr->vpe_config	= NULL;
+	fptr->vpe_cfg_update	= NULL;
+	fptr->dis		= NULL;
+}
diff --git a/drivers/media/video/msm/msm_vfe8x.h b/drivers/media/video/msm/msm_vfe8x.h
new file mode 100644
index 0000000..1b3148f
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe8x.h
@@ -0,0 +1,909 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __MSM_VFE8X_H__
+#define __MSM_VFE8X_H__
+
+#define TRUE  1
+#define FALSE 0
+#define boolean uint8_t
+
+enum  VFE_STATE {
+	VFE_STATE_IDLE,
+	VFE_STATE_ACTIVE
+};
+
+enum vfe_cmd_id {
+	/*
+	*Important! Command_ID are arranged in order.
+	*Don't change!*/
+	VFE_CMD_ID_START,
+	VFE_CMD_ID_RESET,
+
+	/* bus and camif config */
+	VFE_CMD_ID_AXI_INPUT_CONFIG,
+	VFE_CMD_ID_CAMIF_CONFIG,
+	VFE_CMD_ID_AXI_OUTPUT_CONFIG,
+
+	/* module config  */
+	VFE_CMD_ID_BLACK_LEVEL_CONFIG,
+	VFE_CMD_ID_ROLL_OFF_CONFIG,
+	VFE_CMD_ID_DEMUX_CHANNEL_GAIN_CONFIG,
+	VFE_CMD_ID_DEMOSAIC_CONFIG,
+	VFE_CMD_ID_FOV_CROP_CONFIG,
+	VFE_CMD_ID_MAIN_SCALER_CONFIG,
+	VFE_CMD_ID_WHITE_BALANCE_CONFIG,
+	VFE_CMD_ID_COLOR_CORRECTION_CONFIG,
+	VFE_CMD_ID_LA_CONFIG,
+	VFE_CMD_ID_RGB_GAMMA_CONFIG,
+	VFE_CMD_ID_CHROMA_ENHAN_CONFIG,
+	VFE_CMD_ID_CHROMA_SUPPRESSION_CONFIG,
+	VFE_CMD_ID_ASF_CONFIG,
+	VFE_CMD_ID_SCALER2Y_CONFIG,
+	VFE_CMD_ID_SCALER2CbCr_CONFIG,
+	VFE_CMD_ID_CHROMA_SUBSAMPLE_CONFIG,
+	VFE_CMD_ID_FRAME_SKIP_CONFIG,
+	VFE_CMD_ID_OUTPUT_CLAMP_CONFIG,
+
+	/* test gen */
+	VFE_CMD_ID_TEST_GEN_START,
+
+	VFE_CMD_ID_UPDATE,
+
+	/* ackownledge from upper layer */
+	VFE_CMD_ID_OUTPUT1_ACK,
+	VFE_CMD_ID_OUTPUT2_ACK,
+	VFE_CMD_ID_EPOCH1_ACK,
+	VFE_CMD_ID_EPOCH2_ACK,
+	VFE_CMD_ID_STATS_AUTOFOCUS_ACK,
+	VFE_CMD_ID_STATS_WB_EXP_ACK,
+
+	/* module update commands */
+	VFE_CMD_ID_BLACK_LEVEL_UPDATE,
+	VFE_CMD_ID_DEMUX_CHANNEL_GAIN_UPDATE,
+	VFE_CMD_ID_DEMOSAIC_BPC_UPDATE,
+	VFE_CMD_ID_DEMOSAIC_ABF_UPDATE,
+	VFE_CMD_ID_FOV_CROP_UPDATE,
+	VFE_CMD_ID_WHITE_BALANCE_UPDATE,
+	VFE_CMD_ID_COLOR_CORRECTION_UPDATE,
+	VFE_CMD_ID_LA_UPDATE,
+	VFE_CMD_ID_RGB_GAMMA_UPDATE,
+	VFE_CMD_ID_CHROMA_ENHAN_UPDATE,
+	VFE_CMD_ID_CHROMA_SUPPRESSION_UPDATE,
+	VFE_CMD_ID_MAIN_SCALER_UPDATE,
+	VFE_CMD_ID_SCALER2CbCr_UPDATE,
+	VFE_CMD_ID_SCALER2Y_UPDATE,
+	VFE_CMD_ID_ASF_UPDATE,
+	VFE_CMD_ID_FRAME_SKIP_UPDATE,
+	VFE_CMD_ID_CAMIF_FRAME_UPDATE,
+
+	/* stats update commands */
+	VFE_CMD_ID_STATS_AUTOFOCUS_UPDATE,
+	VFE_CMD_ID_STATS_WB_EXP_UPDATE,
+
+	/* control of start, stop, update, etc... */
+  VFE_CMD_ID_STOP,
+	VFE_CMD_ID_GET_HW_VERSION,
+
+	/* stats */
+	VFE_CMD_ID_STATS_SETTING,
+	VFE_CMD_ID_STATS_AUTOFOCUS_START,
+	VFE_CMD_ID_STATS_AUTOFOCUS_STOP,
+	VFE_CMD_ID_STATS_WB_EXP_START,
+	VFE_CMD_ID_STATS_WB_EXP_STOP,
+
+	VFE_CMD_ID_ASYNC_TIMER_SETTING,
+
+	/* max id  */
+	VFE_CMD_ID_MAX
+};
+
+struct vfe_cmd_hw_version {
+	uint32_t minorVersion;
+	uint32_t majorVersion;
+	uint32_t coreVersion;
+};
+
+enum VFE_CAMIF_SYNC_EDGE {
+	VFE_CAMIF_SYNC_EDGE_ActiveHigh,
+	VFE_CAMIF_SYNC_EDGE_ActiveLow
+};
+
+enum VFE_CAMIF_SYNC_MODE {
+	VFE_CAMIF_SYNC_MODE_APS,
+	VFE_CAMIF_SYNC_MODE_EFS,
+	VFE_CAMIF_SYNC_MODE_ELS,
+	VFE_CAMIF_SYNC_MODE_ILLEGAL
+};
+
+struct vfe_cmds_camif_efs {
+	uint8_t efsendofline;
+	uint8_t efsstartofline;
+	uint8_t efsendofframe;
+	uint8_t efsstartofframe;
+};
+
+struct vfe_cmds_camif_frame {
+	uint16_t pixelsPerLine;
+	uint16_t linesPerFrame;
+};
+
+struct vfe_cmds_camif_window {
+	uint16_t firstpixel;
+	uint16_t lastpixel;
+	uint16_t firstline;
+	uint16_t lastline;
+};
+
+enum CAMIF_SUBSAMPLE_FRAME_SKIP {
+	CAMIF_SUBSAMPLE_FRAME_SKIP_0,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_AllFrames,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_2Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_3Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_4Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_5Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_6Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_7Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_8Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_9Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_10Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_11Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_12Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_13Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_14Frame,
+	CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_15Frame
+};
+
+struct vfe_cmds_camif_subsample {
+	uint16_t pixelskipmask;
+	uint16_t lineskipmask;
+	enum CAMIF_SUBSAMPLE_FRAME_SKIP frameskip;
+	uint8_t frameskipmode;
+	uint8_t pixelskipwrap;
+};
+
+struct vfe_cmds_camif_epoch {
+	uint8_t  enable;
+	uint16_t lineindex;
+};
+
+struct vfe_cmds_camif_cfg {
+	enum VFE_CAMIF_SYNC_EDGE  vSyncEdge;
+	enum VFE_CAMIF_SYNC_EDGE  hSyncEdge;
+	enum VFE_CAMIF_SYNC_MODE  syncMode;
+	uint8_t vfeSubSampleEnable;
+	uint8_t busSubSampleEnable;
+	uint8_t irqSubSampleEnable;
+	uint8_t binningEnable;
+	uint8_t misrEnable;
+};
+
+struct vfe_cmd_camif_config {
+	struct vfe_cmds_camif_cfg camifConfig;
+	struct vfe_cmds_camif_efs EFS;
+	struct vfe_cmds_camif_frame     frame;
+	struct vfe_cmds_camif_window    window;
+	struct vfe_cmds_camif_subsample subsample;
+	struct vfe_cmds_camif_epoch     epoch1;
+	struct vfe_cmds_camif_epoch     epoch2;
+};
+
+enum VFE_AXI_OUTPUT_MODE {
+	VFE_AXI_OUTPUT_MODE_Output1,
+	VFE_AXI_OUTPUT_MODE_Output2,
+	VFE_AXI_OUTPUT_MODE_Output1AndOutput2,
+	VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2,
+	VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1,
+	VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2,
+	VFE_AXI_LAST_OUTPUT_MODE_ENUM
+};
+
+enum VFE_RAW_WR_PATH_SEL {
+	VFE_RAW_OUTPUT_DISABLED,
+	VFE_RAW_OUTPUT_ENC_CBCR_PATH,
+	VFE_RAW_OUTPUT_VIEW_CBCR_PATH,
+	VFE_RAW_OUTPUT_PATH_INVALID
+};
+
+enum VFE_RAW_PIXEL_DATA_SIZE {
+	VFE_RAW_PIXEL_DATA_SIZE_8BIT,
+	VFE_RAW_PIXEL_DATA_SIZE_10BIT,
+	VFE_RAW_PIXEL_DATA_SIZE_12BIT,
+};
+
+#define VFE_AXI_OUTPUT_BURST_LENGTH     4
+#define VFE_MAX_NUM_FRAGMENTS_PER_FRAME 4
+#define VFE_MIN_NUM_FRAGMENTS_PER_FRAME 1
+#define VFE_AXI_OUTPUT_CFG_FRAME_COUNT  3
+
+struct vfe_cmds_axi_out_per_component {
+	uint16_t imageWidth;
+	uint16_t imageHeight;
+	uint16_t outRowCount;
+	uint16_t outRowIncrement;
+	uint32_t outFragments[VFE_AXI_OUTPUT_CFG_FRAME_COUNT]
+		[VFE_MAX_NUM_FRAGMENTS_PER_FRAME];
+};
+
+struct vfe_cmds_axi_per_output_path {
+	uint8_t fragmentCount;
+	struct vfe_cmds_axi_out_per_component outputY;
+	struct vfe_cmds_axi_out_per_component outputCbcr;
+};
+
+enum VFE_AXI_BURST_LENGTH {
+	VFE_AXI_BURST_LENGTH_IS_2  = 2,
+	VFE_AXI_BURST_LENGTH_IS_4  = 4,
+	VFE_AXI_BURST_LENGTH_IS_8  = 8,
+	VFE_AXI_BURST_LENGTH_IS_16 = 16
+};
+
+struct vfe_cmd_axi_output_config {
+	enum VFE_AXI_BURST_LENGTH burstLength;
+	enum VFE_AXI_OUTPUT_MODE outputMode;
+	enum VFE_RAW_PIXEL_DATA_SIZE outputDataSize;
+	struct vfe_cmds_axi_per_output_path output1;
+	struct vfe_cmds_axi_per_output_path output2;
+};
+
+struct vfe_cmd_fov_crop_config {
+	uint8_t enable;
+	uint16_t firstPixel;
+	uint16_t lastPixel;
+	uint16_t firstLine;
+	uint16_t lastLine;
+};
+
+struct vfe_cmds_main_scaler_stripe_init {
+	uint16_t MNCounterInit;
+	uint16_t phaseInit;
+};
+
+struct vfe_cmds_scaler_one_dimension {
+	uint8_t  enable;
+	uint16_t inputSize;
+	uint16_t outputSize;
+	uint32_t phaseMultiplicationFactor;
+	uint8_t  interpolationResolution;
+};
+
+struct vfe_cmd_main_scaler_config {
+	uint8_t enable;
+	struct vfe_cmds_scaler_one_dimension    hconfig;
+	struct vfe_cmds_scaler_one_dimension    vconfig;
+	struct vfe_cmds_main_scaler_stripe_init MNInitH;
+	struct vfe_cmds_main_scaler_stripe_init MNInitV;
+};
+
+struct vfe_cmd_scaler2_config {
+	uint8_t enable;
+	struct vfe_cmds_scaler_one_dimension hconfig;
+	struct vfe_cmds_scaler_one_dimension vconfig;
+};
+
+struct vfe_cmd_frame_skip_config {
+	uint8_t output1Period;
+	uint32_t output1Pattern;
+	uint8_t output2Period;
+	uint32_t output2Pattern;
+};
+
+struct vfe_cmd_frame_skip_update {
+	uint32_t output1Pattern;
+	uint32_t output2Pattern;
+};
+
+struct vfe_cmd_output_clamp_config {
+	uint8_t minCh0;
+	uint8_t minCh1;
+	uint8_t minCh2;
+	uint8_t maxCh0;
+	uint8_t maxCh1;
+	uint8_t maxCh2;
+};
+
+struct vfe_cmd_chroma_subsample_config {
+	uint8_t enable;
+	uint8_t cropEnable;
+	uint8_t vsubSampleEnable;
+	uint8_t hsubSampleEnable;
+	uint8_t vCosited;
+	uint8_t hCosited;
+	uint8_t vCositedPhase;
+	uint8_t hCositedPhase;
+	uint16_t cropWidthFirstPixel;
+	uint16_t cropWidthLastPixel;
+	uint16_t cropHeightFirstLine;
+	uint16_t cropHeightLastLine;
+};
+
+enum VFE_START_INPUT_SOURCE {
+	VFE_START_INPUT_SOURCE_CAMIF,
+	VFE_START_INPUT_SOURCE_TESTGEN,
+	VFE_START_INPUT_SOURCE_AXI,
+	VFE_START_INPUT_SOURCE_INVALID
+};
+
+enum VFE_START_OPERATION_MODE {
+	VFE_START_OPERATION_MODE_CONTINUOUS,
+	VFE_START_OPERATION_MODE_SNAPSHOT
+};
+
+enum VFE_START_PIXEL_PATTERN {
+	VFE_BAYER_RGRGRG,
+	VFE_BAYER_GRGRGR,
+	VFE_BAYER_BGBGBG,
+	VFE_BAYER_GBGBGB,
+	VFE_YUV_YCbYCr,
+	VFE_YUV_YCrYCb,
+	VFE_YUV_CbYCrY,
+	VFE_YUV_CrYCbY
+};
+
+enum VFE_BUS_RD_INPUT_PIXEL_PATTERN {
+	VFE_BAYER_RAW,
+	VFE_YUV_INTERLEAVED,
+	VFE_YUV_PSEUDO_PLANAR_Y,
+	VFE_YUV_PSEUDO_PLANAR_CBCR
+};
+
+enum VFE_YUV_INPUT_COSITING_MODE {
+	VFE_YUV_COSITED,
+	VFE_YUV_INTERPOLATED
+};
+
+struct vfe_cmd_start {
+	enum VFE_START_INPUT_SOURCE inputSource;
+	enum VFE_START_OPERATION_MODE operationMode;
+	uint8_t     snapshotCount;
+	enum VFE_START_PIXEL_PATTERN pixel;
+	enum VFE_YUV_INPUT_COSITING_MODE yuvInputCositingMode;
+};
+
+struct vfe_cmd_output_ack {
+	uint32_t ybufaddr[VFE_MAX_NUM_FRAGMENTS_PER_FRAME];
+	uint32_t chromabufaddr[VFE_MAX_NUM_FRAGMENTS_PER_FRAME];
+};
+
+#define VFE_STATS_BUFFER_COUNT 3
+
+struct vfe_cmd_stats_setting {
+	uint16_t frameHDimension;
+	uint16_t frameVDimension;
+	uint8_t  afBusPrioritySelection;
+	uint8_t  afBusPriority;
+	uint8_t  awbBusPrioritySelection;
+	uint8_t  awbBusPriority;
+	uint8_t  histBusPrioritySelection;
+	uint8_t  histBusPriority;
+	uint32_t afBuffer[VFE_STATS_BUFFER_COUNT];
+	uint32_t awbBuffer[VFE_STATS_BUFFER_COUNT];
+	uint32_t histBuffer[VFE_STATS_BUFFER_COUNT];
+};
+
+struct vfe_cmd_stats_af_start {
+	uint8_t  enable;
+	uint8_t  windowMode;
+	uint16_t windowHOffset;
+	uint16_t windowVOffset;
+	uint16_t windowWidth;
+	uint16_t windowHeight;
+	uint8_t  gridForMultiWindows[16];
+	uint8_t     metricSelection;
+	int16_t  metricMax;
+	int8_t   highPassCoef[7];
+	int8_t   bufferHeader;
+};
+
+struct vfe_cmd_stats_af_update {
+	uint8_t  windowMode;
+	uint16_t windowHOffset;
+	uint16_t windowVOffset;
+	uint16_t windowWidth;
+	uint16_t windowHeight;
+};
+
+struct vfe_cmd_stats_wb_exp_start {
+	uint8_t   enable;
+	uint8_t   wbExpRegions;
+	uint8_t   wbExpSubRegion;
+	uint8_t   awbYMin;
+	uint8_t   awbYMax;
+	int8_t    awbMCFG[4];
+	int16_t   awbCCFG[4];
+	int8_t    axwHeader;
+};
+
+struct vfe_cmd_stats_wb_exp_update {
+	uint8_t wbExpRegions;
+	uint8_t wbExpSubRegion;
+	int8_t  awbYMin;
+	int8_t  awbYMax;
+	int8_t  awbMCFG[4];
+	int16_t awbCCFG[4];
+};
+
+struct vfe_cmd_stats_af_ack {
+	uint32_t nextAFOutputBufferAddr;
+};
+
+struct vfe_cmd_stats_wb_exp_ack {
+	uint32_t  nextWbExpOutputBufferAddr;
+};
+
+struct vfe_cmd_black_level_config {
+	uint8_t  enable;
+	uint16_t evenEvenAdjustment;
+	uint16_t evenOddAdjustment;
+	uint16_t oddEvenAdjustment;
+	uint16_t oddOddAdjustment;
+};
+
+/* 13*1  */
+#define  VFE_ROLL_OFF_INIT_TABLE_SIZE  13
+/* 13*16 */
+#define  VFE_ROLL_OFF_DELTA_TABLE_SIZE 208
+
+struct vfe_cmd_roll_off_config {
+	uint8_t  enable;
+	uint16_t gridWidth;
+	uint16_t gridHeight;
+	uint16_t  yDelta;
+	uint8_t  gridXIndex;
+	uint8_t  gridYIndex;
+	uint16_t gridPixelXIndex;
+	uint16_t gridPixelYIndex;
+	uint16_t yDeltaAccum;
+	uint16_t initTableR[VFE_ROLL_OFF_INIT_TABLE_SIZE];
+	uint16_t initTableGr[VFE_ROLL_OFF_INIT_TABLE_SIZE];
+	uint16_t initTableB[VFE_ROLL_OFF_INIT_TABLE_SIZE];
+	uint16_t initTableGb[VFE_ROLL_OFF_INIT_TABLE_SIZE];
+	int16_t  deltaTableR[VFE_ROLL_OFF_DELTA_TABLE_SIZE];
+	int16_t  deltaTableGr[VFE_ROLL_OFF_DELTA_TABLE_SIZE];
+	int16_t  deltaTableB[VFE_ROLL_OFF_DELTA_TABLE_SIZE];
+	int16_t  deltaTableGb[VFE_ROLL_OFF_DELTA_TABLE_SIZE];
+};
+
+struct vfe_cmd_demux_channel_gain_config {
+	uint16_t ch0EvenGain;
+	uint16_t ch0OddGain;
+	uint16_t ch1Gain;
+	uint16_t ch2Gain;
+};
+
+struct vfe_cmds_demosaic_abf {
+	uint8_t   enable;
+	uint8_t   forceOn;
+	uint8_t   shift;
+	uint16_t  lpThreshold;
+	uint16_t  max;
+	uint16_t  min;
+	uint8_t   ratio;
+};
+
+struct vfe_cmds_demosaic_bpc {
+	uint8_t   enable;
+	uint16_t  fmaxThreshold;
+	uint16_t  fminThreshold;
+	uint16_t  redDiffThreshold;
+	uint16_t  blueDiffThreshold;
+	uint16_t  greenDiffThreshold;
+};
+
+struct vfe_cmd_demosaic_config {
+	uint8_t   enable;
+	uint8_t   slopeShift;
+	struct vfe_cmds_demosaic_abf abfConfig;
+	struct vfe_cmds_demosaic_bpc bpcConfig;
+};
+
+struct vfe_cmd_demosaic_bpc_update {
+	struct vfe_cmds_demosaic_bpc bpcUpdate;
+};
+
+struct vfe_cmd_demosaic_abf_update {
+	struct vfe_cmds_demosaic_abf abfUpdate;
+};
+
+struct vfe_cmd_white_balance_config {
+	uint8_t  enable;
+	uint16_t ch2Gain;
+	uint16_t ch1Gain;
+	uint16_t ch0Gain;
+};
+
+enum VFE_COLOR_CORRECTION_COEF_QFACTOR {
+	COEF_IS_Q7_SIGNED,
+	COEF_IS_Q8_SIGNED,
+	COEF_IS_Q9_SIGNED,
+	COEF_IS_Q10_SIGNED
+};
+
+struct vfe_cmd_color_correction_config {
+	uint8_t     enable;
+	enum VFE_COLOR_CORRECTION_COEF_QFACTOR coefQFactor;
+	int16_t  C0;
+	int16_t  C1;
+	int16_t  C2;
+	int16_t  C3;
+	int16_t  C4;
+	int16_t  C5;
+	int16_t  C6;
+	int16_t  C7;
+	int16_t  C8;
+	int16_t  K0;
+	int16_t  K1;
+	int16_t  K2;
+};
+
+#define VFE_LA_TABLE_LENGTH 256
+struct vfe_cmd_la_config {
+	uint8_t enable;
+	int16_t table[VFE_LA_TABLE_LENGTH];
+};
+
+#define VFE_GAMMA_TABLE_LENGTH 256
+enum VFE_RGB_GAMMA_TABLE_SELECT {
+	RGB_GAMMA_CH0_SELECTED,
+	RGB_GAMMA_CH1_SELECTED,
+	RGB_GAMMA_CH2_SELECTED,
+	RGB_GAMMA_CH0_CH1_SELECTED,
+	RGB_GAMMA_CH0_CH2_SELECTED,
+	RGB_GAMMA_CH1_CH2_SELECTED,
+	RGB_GAMMA_CH0_CH1_CH2_SELECTED
+};
+
+struct vfe_cmd_rgb_gamma_config {
+	uint8_t enable;
+	enum VFE_RGB_GAMMA_TABLE_SELECT channelSelect;
+	int16_t table[VFE_GAMMA_TABLE_LENGTH];
+};
+
+struct vfe_cmd_chroma_enhan_config {
+	uint8_t  enable;
+	int16_t am;
+	int16_t ap;
+	int16_t bm;
+	int16_t bp;
+	int16_t cm;
+	int16_t cp;
+	int16_t dm;
+	int16_t dp;
+	int16_t kcr;
+	int16_t kcb;
+	int16_t RGBtoYConversionV0;
+	int16_t RGBtoYConversionV1;
+	int16_t RGBtoYConversionV2;
+	uint8_t RGBtoYConversionOffset;
+};
+
+struct vfe_cmd_chroma_suppression_config {
+	uint8_t enable;
+	uint8_t m1;
+	uint8_t m3;
+	uint8_t n1;
+	uint8_t n3;
+	uint8_t nn1;
+	uint8_t mm1;
+};
+
+struct vfe_cmd_asf_config {
+	uint8_t enable;
+	uint8_t smoothFilterEnabled;
+	uint8_t sharpMode;
+	uint8_t smoothCoefCenter;
+	uint8_t smoothCoefSurr;
+	uint8_t normalizeFactor;
+	uint8_t sharpK1;
+	uint8_t sharpK2;
+	uint8_t sharpThreshE1;
+	int8_t sharpThreshE2;
+	int8_t sharpThreshE3;
+	int8_t sharpThreshE4;
+	int8_t sharpThreshE5;
+	int8_t filter1Coefficients[9];
+	int8_t filter2Coefficients[9];
+	uint8_t  cropEnable;
+	uint16_t cropFirstPixel;
+	uint16_t cropLastPixel;
+	uint16_t cropFirstLine;
+	uint16_t cropLastLine;
+};
+
+struct vfe_cmd_asf_update {
+	uint8_t enable;
+	uint8_t smoothFilterEnabled;
+	uint8_t sharpMode;
+	uint8_t smoothCoefCenter;
+	uint8_t smoothCoefSurr;
+	uint8_t normalizeFactor;
+	uint8_t sharpK1;
+	uint8_t sharpK2;
+	uint8_t sharpThreshE1;
+	int8_t  sharpThreshE2;
+	int8_t  sharpThreshE3;
+	int8_t  sharpThreshE4;
+	int8_t  sharpThreshE5;
+	int8_t  filter1Coefficients[9];
+	int8_t  filter2Coefficients[9];
+	uint8_t cropEnable;
+};
+
+enum VFE_TEST_GEN_SYNC_EDGE {
+	VFE_TEST_GEN_SYNC_EDGE_ActiveHigh,
+	VFE_TEST_GEN_SYNC_EDGE_ActiveLow
+};
+
+struct vfe_cmd_test_gen_start {
+	uint8_t pixelDataSelect;
+	uint8_t systematicDataSelect;
+	enum VFE_TEST_GEN_SYNC_EDGE  hsyncEdge;
+	enum VFE_TEST_GEN_SYNC_EDGE  vsyncEdge;
+	uint16_t numFrame;
+	enum VFE_RAW_PIXEL_DATA_SIZE pixelDataSize;
+	uint16_t imageWidth;
+	uint16_t imageHeight;
+	uint32_t startOfFrameOffset;
+	uint32_t endOfFrameNOffset;
+	uint16_t startOfLineOffset;
+	uint16_t endOfLineNOffset;
+	uint16_t hbi;
+	uint8_t  vblEnable;
+	uint16_t vbl;
+	uint8_t  startOfFrameDummyLine;
+	uint8_t  endOfFrameDummyLine;
+	uint8_t  unicolorBarEnable;
+	uint8_t  colorBarsSplitEnable;
+	uint8_t  unicolorBarSelect;
+	enum VFE_START_PIXEL_PATTERN  colorBarsPixelPattern;
+	uint8_t  colorBarsRotatePeriod;
+	uint16_t testGenRandomSeed;
+};
+
+struct vfe_cmd_bus_pm_start {
+	uint8_t output2YWrPmEnable;
+	uint8_t output2CbcrWrPmEnable;
+	uint8_t output1YWrPmEnable;
+	uint8_t output1CbcrWrPmEnable;
+};
+
+struct vfe_cmd_camif_frame_update {
+	struct vfe_cmds_camif_frame camifFrame;
+};
+
+struct vfe_cmd_sync_timer_setting {
+	uint8_t  whichSyncTimer;
+	uint8_t  operation;
+	uint8_t  polarity;
+	uint16_t repeatCount;
+	uint16_t hsyncCount;
+	uint32_t pclkCount;
+	uint32_t outputDuration;
+};
+
+struct vfe_cmd_async_timer_setting {
+	uint8_t  whichAsyncTimer;
+	uint8_t  operation;
+	uint8_t  polarity;
+	uint16_t repeatCount;
+	uint16_t inactiveCount;
+	uint32_t activeCount;
+};
+
+struct  vfe_frame_skip_counts {
+	uint32_t  totalFrameCount;
+	uint32_t  output1Count;
+	uint32_t  output2Count;
+};
+
+enum VFE_AXI_RD_UNPACK_HBI_SEL {
+	VFE_AXI_RD_HBI_32_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_64_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_128_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_256_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_512_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_1024_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_2048_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_4096_CLOCK_CYCLES
+};
+
+struct vfe_cmd_axi_input_config {
+	uint32_t  fragAddr[4];
+	uint8_t   totalFragmentCount;
+	uint16_t  ySize;
+	uint16_t  xOffset;
+	uint16_t  xSize;
+	uint16_t  rowIncrement;
+	uint16_t  numOfRows;
+	enum VFE_AXI_BURST_LENGTH burstLength;
+	uint8_t   unpackPhase;
+	enum VFE_AXI_RD_UNPACK_HBI_SEL unpackHbi;
+	enum VFE_RAW_PIXEL_DATA_SIZE   pixelSize;
+	uint8_t   padRepeatCountLeft;
+	uint8_t   padRepeatCountRight;
+	uint8_t   padRepeatCountTop;
+	uint8_t   padRepeatCountBottom;
+	uint8_t   padLeftComponentSelectCycle0;
+	uint8_t   padLeftComponentSelectCycle1;
+	uint8_t   padLeftComponentSelectCycle2;
+	uint8_t   padLeftComponentSelectCycle3;
+	uint8_t   padLeftStopCycle0;
+	uint8_t   padLeftStopCycle1;
+	uint8_t   padLeftStopCycle2;
+	uint8_t   padLeftStopCycle3;
+	uint8_t   padRightComponentSelectCycle0;
+	uint8_t   padRightComponentSelectCycle1;
+	uint8_t   padRightComponentSelectCycle2;
+	uint8_t   padRightComponentSelectCycle3;
+	uint8_t   padRightStopCycle0;
+	uint8_t   padRightStopCycle1;
+	uint8_t   padRightStopCycle2;
+	uint8_t   padRightStopCycle3;
+	uint8_t   padTopLineCount;
+	uint8_t   padBottomLineCount;
+};
+
+struct vfe_interrupt_status {
+	uint8_t camifErrorIrq;
+	uint8_t camifSofIrq;
+	uint8_t camifEolIrq;
+	uint8_t camifEofIrq;
+	uint8_t camifEpoch1Irq;
+	uint8_t camifEpoch2Irq;
+	uint8_t camifOverflowIrq;
+	uint8_t ceIrq;
+	uint8_t regUpdateIrq;
+	uint8_t resetAckIrq;
+	uint8_t encYPingpongIrq;
+	uint8_t encCbcrPingpongIrq;
+	uint8_t viewYPingpongIrq;
+	uint8_t viewCbcrPingpongIrq;
+	uint8_t rdPingpongIrq;
+	uint8_t afPingpongIrq;
+	uint8_t awbPingpongIrq;
+	uint8_t histPingpongIrq;
+	uint8_t encIrq;
+	uint8_t viewIrq;
+	uint8_t busOverflowIrq;
+	uint8_t afOverflowIrq;
+	uint8_t awbOverflowIrq;
+	uint8_t syncTimer0Irq;
+	uint8_t syncTimer1Irq;
+	uint8_t syncTimer2Irq;
+	uint8_t asyncTimer0Irq;
+	uint8_t asyncTimer1Irq;
+	uint8_t asyncTimer2Irq;
+	uint8_t asyncTimer3Irq;
+	uint8_t axiErrorIrq;
+	uint8_t violationIrq;
+	uint8_t anyErrorIrqs;
+	uint8_t anyOutput1PathIrqs;
+	uint8_t anyOutput2PathIrqs;
+	uint8_t anyOutputPathIrqs;
+	uint8_t anyAsyncTimerIrqs;
+	uint8_t anySyncTimerIrqs;
+	uint8_t anyIrqForActiveStatesOnly;
+};
+
+enum VFE_MESSAGE_ID {
+	VFE_MSG_ID_RESET_ACK,
+	VFE_MSG_ID_START_ACK,
+	VFE_MSG_ID_STOP_ACK,
+	VFE_MSG_ID_UPDATE_ACK,
+	VFE_MSG_ID_OUTPUT_P,
+	VFE_MSG_ID_OUTPUT_V,
+	VFE_MSG_ID_OUTPUT_S,
+	VFE_MSG_ID_OUTPUT_T,
+	VFE_MSG_ID_SNAPSHOT_DONE,
+	VFE_MSG_ID_STATS_AUTOFOCUS,
+	VFE_MSG_ID_STATS_WB_EXP,
+	VFE_MSG_ID_EPOCH1,
+	VFE_MSG_ID_EPOCH2,
+	VFE_MSG_ID_SYNC_TIMER0_DONE,
+	VFE_MSG_ID_SYNC_TIMER1_DONE,
+	VFE_MSG_ID_SYNC_TIMER2_DONE,
+	VFE_MSG_ID_ASYNC_TIMER0_DONE,
+	VFE_MSG_ID_ASYNC_TIMER1_DONE,
+	VFE_MSG_ID_ASYNC_TIMER2_DONE,
+	VFE_MSG_ID_ASYNC_TIMER3_DONE,
+	VFE_MSG_ID_AF_OVERFLOW,
+	VFE_MSG_ID_AWB_OVERFLOW,
+	VFE_MSG_ID_AXI_ERROR,
+	VFE_MSG_ID_CAMIF_OVERFLOW,
+	VFE_MSG_ID_VIOLATION,
+	VFE_MSG_ID_CAMIF_ERROR,
+	VFE_MSG_ID_BUS_OVERFLOW,
+	VFE_MSG_ID_SOF_ACK,
+};
+
+struct vfe_msg_stats_autofocus {
+	uint32_t    afBuffer;
+	uint32_t    frameCounter;
+};
+
+struct vfe_msg_stats_wb_exp {
+	uint32_t awbBuffer;
+	uint32_t frameCounter;
+};
+
+struct vfe_frame_bpc_info {
+	uint32_t greenDefectPixelCount;
+	uint32_t redBlueDefectPixelCount;
+};
+
+struct vfe_frame_asf_info {
+	uint32_t  asfMaxEdge;
+	uint32_t  asfHbiCount;
+};
+
+struct vfe_msg_camif_status {
+	uint8_t  camifState;
+	uint32_t pixelCount;
+	uint32_t lineCount;
+};
+
+struct vfe_bus_pm_per_path {
+	uint32_t yWrPmStats0;
+	uint32_t yWrPmStats1;
+	uint32_t cbcrWrPmStats0;
+	uint32_t cbcrWrPmStats1;
+};
+
+struct vfe_bus_performance_monitor {
+	struct vfe_bus_pm_per_path encPathPmInfo;
+	struct vfe_bus_pm_per_path viewPathPmInfo;
+};
+
+struct vfe_irq_thread_msg {
+	uint32_t  vfeIrqStatus;
+	uint32_t  camifStatus;
+	uint32_t  demosaicStatus;
+	uint32_t  asfMaxEdge;
+	struct vfe_bus_performance_monitor pmInfo;
+};
+
+struct vfe_msg_output {
+	uint32_t  yBuffer;
+	uint32_t  cbcrBuffer;
+	struct vfe_frame_bpc_info bpcInfo;
+	struct vfe_frame_asf_info asfInfo;
+	uint32_t  frameCounter;
+	struct vfe_bus_pm_per_path pmData;
+};
+
+struct vfe_message {
+	enum VFE_MESSAGE_ID _d;
+	union {
+		struct vfe_msg_output              msgOutput1;
+		struct vfe_msg_output              msgOutput2;
+		struct vfe_msg_stats_autofocus     msgStatsAf;
+		struct vfe_msg_stats_wb_exp        msgStatsWbExp;
+		struct vfe_msg_camif_status        msgCamifError;
+		struct vfe_bus_performance_monitor msgBusOverflow;
+   } _u;
+};
+
+/* New one for 8k */
+struct msm_vfe_command_8k {
+	int id;
+	uint16_t length;
+	void     *value;
+};
+
+struct vfe_frame_extra {
+	struct vfe_frame_bpc_info bpcInfo;
+	struct vfe_frame_asf_info asfInfo;
+	uint32_t  frameCounter;
+	struct vfe_bus_pm_per_path pmData;
+};
+#endif /* __MSM_VFE8X_H__ */
diff --git a/drivers/media/video/msm/msm_vfe8x_proc.c b/drivers/media/video/msm/msm_vfe8x_proc.c
new file mode 100644
index 0000000..9764557
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe8x_proc.c
@@ -0,0 +1,3888 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include "msm_vfe8x_proc.h"
+#include <media/msm_camera.h>
+#include <mach/board.h>
+
+struct isr_queue_cmd {
+	struct list_head list;
+	struct vfe_interrupt_status vfeInterruptStatus;
+	struct vfe_frame_asf_info vfeAsfFrameInfo;
+	struct vfe_frame_bpc_info vfeBpcFrameInfo;
+	struct vfe_msg_camif_status vfeCamifStatusLocal;
+	struct vfe_bus_performance_monitor vfePmData;
+};
+
+struct msm_vfe8x_ctrl {
+	/* bit 1:0 ENC_IRQ_MASK = 0x11:
+	 * generate IRQ when both y and cbcr frame is ready. */
+
+	/* bit 1:0 VIEW_IRQ_MASK= 0x11:
+	 * generate IRQ when both y and cbcr frame is ready. */
+	struct vfe_irq_composite_mask_config vfeIrqCompositeMaskLocal;
+	struct vfe_module_enable vfeModuleEnableLocal;
+	struct vfe_camif_cfg_data   vfeCamifConfigLocal;
+	struct vfe_interrupt_mask   vfeImaskLocal;
+	struct vfe_stats_cmd_data   vfeStatsCmdLocal;
+	struct vfe_bus_cfg_data     vfeBusConfigLocal;
+	struct vfe_cmd_bus_pm_start vfeBusPmConfigLocal;
+	struct vfe_bus_cmd_data     vfeBusCmdLocal;
+	enum vfe_interrupt_name     vfeInterruptNameLocal;
+	uint32_t vfeLaBankSel;
+	struct vfe_gamma_lut_sel  vfeGammaLutSel;
+
+	boolean vfeStartAckPendingFlag;
+	boolean vfeStopAckPending;
+	boolean vfeResetAckPending;
+	boolean vfeUpdateAckPending;
+
+	enum VFE_AXI_OUTPUT_MODE        axiOutputMode;
+	enum VFE_START_OPERATION_MODE   vfeOperationMode;
+
+	atomic_t vfe_serv_interrupt;
+
+	uint32_t            vfeSnapShotCount;
+	uint32_t            vfeRequestedSnapShotCount;
+	boolean             vfeStatsPingPongReloadFlag;
+	uint32_t            vfeFrameId;
+
+	struct vfe_cmd_frame_skip_config vfeFrameSkip;
+	uint32_t vfeFrameSkipPattern;
+	uint8_t  vfeFrameSkipCount;
+	uint8_t  vfeFrameSkipPeriod;
+
+	boolean  vfeTestGenStartFlag;
+	uint32_t vfeImaskPacked;
+	uint32_t vfeImaskCompositePacked;
+	enum VFE_RAW_PIXEL_DATA_SIZE       axiInputDataSize;
+	struct vfe_irq_thread_msg          vfeIrqThreadMsgLocal;
+
+	struct vfe_output_path_combo  viewPath;
+	struct vfe_output_path_combo  encPath;
+	struct vfe_frame_skip_counts vfeDroppedFrameCounts;
+	struct vfe_stats_control afStatsControl;
+	struct vfe_stats_control awbStatsControl;
+
+	enum VFE_STATE  vstate;
+
+	struct msm_vfe_callback *resp;
+	struct vfe_frame_extra extdata;
+
+	struct isr_queue_cmd irqs[10];
+	spinlock_t irqs_lock;
+	int irq_get;
+	int irq_put;
+
+	int vfeirq;
+	void __iomem *vfebase;
+
+	void *syncdata;
+};
+
+static struct msm_vfe8x_ctrl *ctrl;
+static spinlock_t msm_vfe_ctrl_lock;
+
+static void vfe_prog_hw(uint8_t *hwreg, uint32_t *inptr, uint32_t regcnt)
+{
+	/* unsigned long flags; */
+	uint32_t i;
+	uint32_t *p;
+
+	/* @todo This is causing issues, need further investigate */
+	/* spin_lock_irqsave(&ctrl->io_lock, flags); */
+
+	p = (uint32_t *)(hwreg);
+	for (i = 0; i < (regcnt >> 2); i++)
+		writel(*inptr++, p++);
+		/* *p++ = *inptr++; */
+
+	/* spin_unlock_irqrestore(&ctrl->io_lock, flags); */
+}
+
+static void
+vfe_set_bus_pipo_addr(struct vfe_output_path_combo *vpath,
+	struct vfe_output_path_combo *epath)
+{
+	vpath->yPath.hwRegPingAddress = (uint8_t *)
+		(ctrl->vfebase + VFE_BUS_VIEW_Y_WR_PING_ADDR);
+	vpath->yPath.hwRegPongAddress = (uint8_t *)
+		(ctrl->vfebase + VFE_BUS_VIEW_Y_WR_PONG_ADDR);
+	vpath->cbcrPath.hwRegPingAddress = (uint8_t *)
+		(ctrl->vfebase + VFE_BUS_VIEW_CBCR_WR_PING_ADDR);
+	vpath->cbcrPath.hwRegPongAddress = (uint8_t *)
+		(ctrl->vfebase + VFE_BUS_VIEW_CBCR_WR_PONG_ADDR);
+
+	epath->yPath.hwRegPingAddress = (uint8_t *)
+		(ctrl->vfebase + VFE_BUS_ENC_Y_WR_PING_ADDR);
+	epath->yPath.hwRegPongAddress = (uint8_t *)
+		(ctrl->vfebase + VFE_BUS_ENC_Y_WR_PONG_ADDR);
+	epath->cbcrPath.hwRegPingAddress = (uint8_t *)
+		(ctrl->vfebase + VFE_BUS_ENC_CBCR_WR_PING_ADDR);
+	epath->cbcrPath.hwRegPongAddress = (uint8_t *)
+		(ctrl->vfebase + VFE_BUS_ENC_CBCR_WR_PONG_ADDR);
+}
+
+static void vfe_axi_output(struct vfe_cmd_axi_output_config *in,
+	struct vfe_output_path_combo *out1,
+	struct vfe_output_path_combo *out2, uint16_t out)
+{
+	struct vfe_axi_out_cfg cmd;
+
+	uint16_t temp;
+	uint32_t burstLength;
+
+	memset(&cmd, 0, sizeof(cmd));
+	/* force it to burst length 4, hardware does not support it. */
+	burstLength = 1;
+
+	/* AXI Output 2 Y Configuration*/
+	/* VFE_BUS_ENC_Y_WR_PING_ADDR  */
+	cmd.out2YPingAddr = out2->yPath.addressBuffer[0];
+
+	/* VFE_BUS_ENC_Y_WR_PONG_ADDR  */
+	cmd.out2YPongAddr = out2->yPath.addressBuffer[1];
+
+	/* VFE_BUS_ENC_Y_WR_IMAGE_SIZE */
+	cmd.out2YImageHeight = in->output2.outputY.imageHeight;
+	/* convert the image width and row increment to be in
+	 * unit of 64bit (8 bytes) */
+	temp = (in->output2.outputY.imageWidth + (out - 1)) / out;
+	cmd.out2YImageWidthin64bit = temp;
+
+	/* VFE_BUS_ENC_Y_WR_BUFFER_CFG */
+	cmd.out2YBurstLength = burstLength;
+	cmd.out2YNumRows = in->output2.outputY.outRowCount;
+	temp = (in->output2.outputY.outRowIncrement + (out - 1)) / out;
+	cmd.out2YRowIncrementIn64bit = temp;
+
+	/* AXI Output 2 Cbcr Configuration*/
+	/* VFE_BUS_ENC_Cbcr_WR_PING_ADDR  */
+	cmd.out2CbcrPingAddr = out2->cbcrPath.addressBuffer[0];
+
+	/* VFE_BUS_ENC_Cbcr_WR_PONG_ADDR  */
+	cmd.out2CbcrPongAddr = out2->cbcrPath.addressBuffer[1];
+
+	/* VFE_BUS_ENC_Cbcr_WR_IMAGE_SIZE */
+	cmd.out2CbcrImageHeight = in->output2.outputCbcr.imageHeight;
+	temp = (in->output2.outputCbcr.imageWidth + (out - 1)) / out;
+	cmd.out2CbcrImageWidthIn64bit = temp;
+
+	/* VFE_BUS_ENC_Cbcr_WR_BUFFER_CFG */
+	cmd.out2CbcrBurstLength = burstLength;
+	cmd.out2CbcrNumRows = in->output2.outputCbcr.outRowCount;
+	temp = (in->output2.outputCbcr.outRowIncrement + (out - 1)) / out;
+	cmd.out2CbcrRowIncrementIn64bit = temp;
+
+	/* AXI Output 1 Y Configuration */
+	/* VFE_BUS_VIEW_Y_WR_PING_ADDR  */
+	cmd.out1YPingAddr = out1->yPath.addressBuffer[0];
+
+	/* VFE_BUS_VIEW_Y_WR_PONG_ADDR */
+	cmd.out1YPongAddr = out1->yPath.addressBuffer[1];
+
+	/* VFE_BUS_VIEW_Y_WR_IMAGE_SIZE */
+	cmd.out1YImageHeight = in->output1.outputY.imageHeight;
+	temp = (in->output1.outputY.imageWidth + (out - 1)) / out;
+	cmd.out1YImageWidthin64bit = temp;
+
+	/* VFE_BUS_VIEW_Y_WR_BUFFER_CFG     */
+	cmd.out1YBurstLength = burstLength;
+	cmd.out1YNumRows = in->output1.outputY.outRowCount;
+
+	temp = (in->output1.outputY.outRowIncrement + (out - 1)) / out;
+	cmd.out1YRowIncrementIn64bit = temp;
+
+	/* AXI Output 1 Cbcr Configuration*/
+	cmd.out1CbcrPingAddr = out1->cbcrPath.addressBuffer[0];
+
+	/* VFE_BUS_VIEW_Cbcr_WR_PONG_ADDR  */
+	cmd.out1CbcrPongAddr = out1->cbcrPath.addressBuffer[1];
+
+	/* VFE_BUS_VIEW_Cbcr_WR_IMAGE_SIZE */
+	cmd.out1CbcrImageHeight = in->output1.outputCbcr.imageHeight;
+	temp = (in->output1.outputCbcr.imageWidth + (out - 1)) / out;
+	cmd.out1CbcrImageWidthIn64bit = temp;
+
+	cmd.out1CbcrBurstLength = burstLength;
+	cmd.out1CbcrNumRows = in->output1.outputCbcr.outRowCount;
+	temp = (in->output1.outputCbcr.outRowIncrement + (out - 1)) / out;
+
+	cmd.out1CbcrRowIncrementIn64bit = temp;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_BUS_ENC_Y_WR_PING_ADDR,
+		(uint32_t *)&cmd, sizeof(cmd));
+}
+
+static void vfe_reg_bus_cfg(struct vfe_bus_cfg_data *in)
+{
+	struct vfe_axi_bus_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.stripeRdPathEn      = in->stripeRdPathEn;
+	cmd.encYWrPathEn        = in->encYWrPathEn;
+	cmd.encCbcrWrPathEn     = in->encCbcrWrPathEn;
+	cmd.viewYWrPathEn       = in->viewYWrPathEn;
+	cmd.viewCbcrWrPathEn    = in->viewCbcrWrPathEn;
+	cmd.rawPixelDataSize    = (uint32_t)in->rawPixelDataSize;
+	cmd.rawWritePathSelect  = (uint32_t)in->rawWritePathSelect;
+
+	/*  program vfe_bus_cfg */
+	writel(*((uint32_t *)&cmd), ctrl->vfebase + VFE_BUS_CFG);
+}
+
+static void vfe_reg_camif_config(struct vfe_camif_cfg_data *in)
+{
+	struct VFE_CAMIFConfigType cfg;
+
+	memset(&cfg, 0, sizeof(cfg));
+
+	cfg.VSyncEdge = in->camifCfgFromCmd.vSyncEdge;
+
+	cfg.HSyncEdge = in->camifCfgFromCmd.hSyncEdge;
+
+	cfg.syncMode = in->camifCfgFromCmd.syncMode;
+
+	cfg.vfeSubsampleEnable = in->camifCfgFromCmd.vfeSubSampleEnable;
+
+	cfg.busSubsampleEnable = in->camifCfgFromCmd.busSubSampleEnable;
+
+	cfg.camif2vfeEnable = in->camif2OutputEnable;
+
+	cfg.camif2busEnable = in->camif2BusEnable;
+
+	cfg.irqSubsampleEnable = in->camifCfgFromCmd.irqSubSampleEnable;
+
+	cfg.binningEnable = in->camifCfgFromCmd.binningEnable;
+
+	cfg.misrEnable = in->camifCfgFromCmd.misrEnable;
+
+	/*  program camif_config */
+	writel(*((uint32_t *)&cfg), ctrl->vfebase + CAMIF_CONFIG);
+}
+
+static void vfe_reg_bus_cmd(struct vfe_bus_cmd_data *in)
+{
+	struct vfe_buscmd cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.stripeReload        = in->stripeReload;
+	cmd.busPingpongReload   = in->busPingpongReload;
+	cmd.statsPingpongReload = in->statsPingpongReload;
+
+	writel(*((uint32_t *)&cmd), ctrl->vfebase + VFE_BUS_CMD);
+
+	CDBG("bus command = 0x%x\n", (*((uint32_t *)&cmd)));
+
+	/* this is needed, as the control bits are pulse based.
+	 * Don't want to reload bus pingpong again. */
+	in->busPingpongReload = 0;
+	in->statsPingpongReload = 0;
+	in->stripeReload = 0;
+}
+
+static void vfe_reg_module_cfg(struct vfe_module_enable *in)
+{
+	struct vfe_mod_enable ena;
+
+	memset(&ena, 0, sizeof(ena));
+
+	ena.blackLevelCorrectionEnable = in->blackLevelCorrectionEnable;
+	ena.lensRollOffEnable          = in->lensRollOffEnable;
+	ena.demuxEnable                = in->demuxEnable;
+	ena.chromaUpsampleEnable       = in->chromaUpsampleEnable;
+	ena.demosaicEnable             = in->demosaicEnable;
+	ena.statsEnable                = in->statsEnable;
+	ena.cropEnable                 = in->cropEnable;
+	ena.mainScalerEnable           = in->mainScalerEnable;
+	ena.whiteBalanceEnable         = in->whiteBalanceEnable;
+	ena.colorCorrectionEnable      = in->colorCorrectionEnable;
+	ena.yHistEnable                = in->yHistEnable;
+	ena.skinToneEnable             = in->skinToneEnable;
+	ena.lumaAdaptationEnable       = in->lumaAdaptationEnable;
+	ena.rgbLUTEnable               = in->rgbLUTEnable;
+	ena.chromaEnhanEnable          = in->chromaEnhanEnable;
+	ena.asfEnable                  = in->asfEnable;
+	ena.chromaSuppressionEnable    = in->chromaSuppressionEnable;
+	ena.chromaSubsampleEnable      = in->chromaSubsampleEnable;
+	ena.scaler2YEnable             = in->scaler2YEnable;
+	ena.scaler2CbcrEnable          = in->scaler2CbcrEnable;
+
+	writel(*((uint32_t *)&ena), ctrl->vfebase + VFE_MODULE_CFG);
+}
+
+static void vfe_program_dmi_cfg(enum VFE_DMI_RAM_SEL bankSel)
+{
+	/* set bit 8 for auto increment. */
+	uint32_t value = (uint32_t) ctrl->vfebase + VFE_DMI_CFG_DEFAULT;
+
+	value += (uint32_t)bankSel;
+	/* CDBG("dmi cfg input bank is  0x%x\n", bankSel); */
+
+	writel(value, ctrl->vfebase + VFE_DMI_CFG);
+	writel(0, ctrl->vfebase + VFE_DMI_ADDR);
+}
+
+static void vfe_write_lens_roll_off_table(struct vfe_cmd_roll_off_config *in)
+{
+	uint16_t i;
+	uint32_t data;
+
+	uint16_t *initGr = in->initTableGr;
+	uint16_t *initGb = in->initTableGb;
+	uint16_t *initB =  in->initTableB;
+	uint16_t *initR =  in->initTableR;
+
+	int16_t *pDeltaGr = in->deltaTableGr;
+	int16_t *pDeltaGb = in->deltaTableGb;
+	int16_t *pDeltaB =  in->deltaTableB;
+	int16_t *pDeltaR =  in->deltaTableR;
+
+	vfe_program_dmi_cfg(ROLLOFF_RAM);
+
+	/* first pack and write init table */
+	for (i = 0; i < VFE_ROLL_OFF_INIT_TABLE_SIZE; i++) {
+		data = (((uint32_t)(*initR)) & 0x0000FFFF) |
+			(((uint32_t)(*initGr)) << 16);
+		initR++;
+		initGr++;
+
+		writel(data, ctrl->vfebase + VFE_DMI_DATA_LO);
+
+		data = (((uint32_t)(*initB)) & 0x0000FFFF) |
+			(((uint32_t)(*initGb))<<16);
+		initB++;
+		initGb++;
+
+		writel(data, ctrl->vfebase + VFE_DMI_DATA_LO);
+	}
+
+	/* there are gaps between the init table and delta table,
+	 * set the offset for delta table. */
+	writel(LENS_ROLL_OFF_DELTA_TABLE_OFFSET, ctrl->vfebase + VFE_DMI_ADDR);
+
+	/* pack and write delta table */
+	for (i = 0; i < VFE_ROLL_OFF_DELTA_TABLE_SIZE; i++) {
+		data = (((int)(*pDeltaR)) & 0x0000FFFF) |
+			(((int)(*pDeltaGr))<<16);
+		pDeltaR++;
+		pDeltaGr++;
+
+		writel(data, ctrl->vfebase + VFE_DMI_DATA_LO);
+
+		data = (((int)(*pDeltaB)) & 0x0000FFFF) |
+			(((int)(*pDeltaGb))<<16);
+		pDeltaB++;
+		pDeltaGb++;
+
+		writel(data, ctrl->vfebase + VFE_DMI_DATA_LO);
+	}
+
+	/* After DMI transfer, to make it safe, need to set the
+	 * DMI_CFG to unselect any SRAM
+	 */
+	/* unselect the SRAM Bank. */
+	writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG);
+}
+
+static void vfe_set_default_reg_values(void)
+{
+	writel(0x800080, ctrl->vfebase + VFE_DEMUX_GAIN_0);
+	writel(0x800080, ctrl->vfebase + VFE_DEMUX_GAIN_1);
+	writel(0xFFFFF, ctrl->vfebase + VFE_CGC_OVERRIDE);
+
+	/* default frame drop period and pattern */
+	writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG);
+	writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_CFG);
+	writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN);
+	writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_PATTERN);
+	writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_CFG);
+	writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR_CFG);
+	writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN);
+	writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR_PATTERN);
+	writel(0, ctrl->vfebase + VFE_CLAMP_MIN_CFG);
+	writel(0xFFFFFF, ctrl->vfebase + VFE_CLAMP_MAX_CFG);
+}
+
+static void vfe_config_demux(uint32_t period, uint32_t even, uint32_t odd)
+{
+	writel(period, ctrl->vfebase + VFE_DEMUX_CFG);
+	writel(even, ctrl->vfebase + VFE_DEMUX_EVEN_CFG);
+	writel(odd, ctrl->vfebase + VFE_DEMUX_ODD_CFG);
+}
+
+static void vfe_pm_stop(void)
+{
+	writel(VFE_PERFORMANCE_MONITOR_STOP, ctrl->vfebase + VFE_BUS_PM_CMD);
+}
+
+static void vfe_camif_stop_immediately(void)
+{
+	writel(CAMIF_COMMAND_STOP_IMMEDIATELY, ctrl->vfebase + CAMIF_COMMAND);
+	writel(0, ctrl->vfebase + VFE_CGC_OVERRIDE);
+}
+
+static void vfe_program_reg_update_cmd(uint32_t value)
+{
+	writel(value, ctrl->vfebase + VFE_REG_UPDATE_CMD);
+}
+
+static void vfe_program_global_reset_cmd(uint32_t value)
+{
+	writel(value, ctrl->vfebase + VFE_GLOBAL_RESET_CMD);
+}
+
+static void vfe_program_axi_cmd(uint32_t value)
+{
+	writel(value, ctrl->vfebase + VFE_AXI_CMD);
+}
+
+static void vfe_program_irq_composite_mask(uint32_t value)
+{
+	writel(value, ctrl->vfebase + VFE_IRQ_COMPOSITE_MASK);
+}
+
+static inline void vfe_program_irq_mask(uint32_t value)
+{
+	writel(value, ctrl->vfebase + VFE_IRQ_MASK);
+}
+
+static uint32_t vfe_read_axi_status(void)
+{
+	return readl(ctrl->vfebase + VFE_AXI_STATUS);
+}
+
+static void
+vfe_set_stats_pingpong_address(struct vfe_stats_control *afControl,
+	struct vfe_stats_control *awbControl)
+{
+	afControl->hwRegPingAddress = (uint8_t *)
+		(ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+	afControl->hwRegPongAddress = (uint8_t *)
+		(ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+
+	awbControl->hwRegPingAddress = (uint8_t *)
+		(ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+	awbControl->hwRegPongAddress = (uint8_t *)
+		(ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+}
+
+static void vfe_program_lut_bank_sel(struct vfe_gamma_lut_sel *in)
+{
+	struct VFE_GammaLutSelect_ConfigCmdType cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.ch0BankSelect = in->ch0BankSelect;
+	cmd.ch1BankSelect = in->ch1BankSelect;
+	cmd.ch2BankSelect = in->ch2BankSelect;
+	CDBG("VFE gamma lut bank selection is 0x%x\n", *((uint32_t *)&cmd));
+	vfe_prog_hw(ctrl->vfebase + VFE_LUT_BANK_SEL,
+		(uint32_t *)&cmd, sizeof(cmd));
+}
+
+static void vfe_program_stats_cmd(struct vfe_stats_cmd_data *in)
+{
+	struct VFE_StatsCmdType stats;
+	memset(&stats, 0, sizeof(stats));
+
+	stats.autoFocusEnable        = in->autoFocusEnable;
+	stats.axwEnable              = in->axwEnable;
+	stats.histEnable             = in->histEnable;
+	stats.clearHistEnable        = in->clearHistEnable;
+	stats.histAutoClearEnable    = in->histAutoClearEnable;
+	stats.colorConversionEnable  = in->colorConversionEnable;
+
+	writel(*((uint32_t *)&stats), ctrl->vfebase + VFE_STATS_CMD);
+}
+
+static void vfe_pm_start(struct vfe_cmd_bus_pm_start *in)
+{
+	struct VFE_Bus_Pm_ConfigCmdType cmd;
+	memset(&cmd, 0, sizeof(struct VFE_Bus_Pm_ConfigCmdType));
+
+	cmd.output2YWrPmEnable     = in->output2YWrPmEnable;
+	cmd.output2CbcrWrPmEnable  = in->output2CbcrWrPmEnable;
+	cmd.output1YWrPmEnable     = in->output1YWrPmEnable;
+	cmd.output1CbcrWrPmEnable  = in->output1CbcrWrPmEnable;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_BUS_PM_CFG,
+		(uint32_t *)&cmd, sizeof(cmd));
+}
+
+static void vfe_8k_pm_start(struct vfe_cmd_bus_pm_start *in)
+{
+	in->output1CbcrWrPmEnable = ctrl->vfeBusConfigLocal.viewCbcrWrPathEn;
+	in->output1YWrPmEnable    = ctrl->vfeBusConfigLocal.viewYWrPathEn;
+	in->output2CbcrWrPmEnable = ctrl->vfeBusConfigLocal.encCbcrWrPathEn;
+	in->output2YWrPmEnable    = ctrl->vfeBusConfigLocal.encYWrPathEn;
+
+	if (in->output1CbcrWrPmEnable || in->output1YWrPmEnable)
+		ctrl->viewPath.pmEnabled = TRUE;
+
+	if (in->output2CbcrWrPmEnable || in->output2YWrPmEnable)
+		ctrl->encPath.pmEnabled = TRUE;
+
+	vfe_pm_start(in);
+
+	writel(VFE_PERFORMANCE_MONITOR_GO, ctrl->vfebase + VFE_BUS_PM_CMD);
+}
+
+static uint32_t vfe_irq_pack(struct vfe_interrupt_mask data)
+{
+	struct vfe_irqenable packedData;
+
+	memset(&packedData, 0, sizeof(packedData));
+
+	packedData.camifErrorIrq          = data.camifErrorIrq;
+	packedData.camifSofIrq            = data.camifSofIrq;
+	packedData.camifEolIrq            = data.camifEolIrq;
+	packedData.camifEofIrq            = data.camifEofIrq;
+	packedData.camifEpoch1Irq         = data.camifEpoch1Irq;
+	packedData.camifEpoch2Irq         = data.camifEpoch2Irq;
+	packedData.camifOverflowIrq       = data.camifOverflowIrq;
+	packedData.ceIrq                  = data.ceIrq;
+	packedData.regUpdateIrq           = data.regUpdateIrq;
+	packedData.resetAckIrq            = data.resetAckIrq;
+	packedData.encYPingpongIrq        = data.encYPingpongIrq;
+	packedData.encCbcrPingpongIrq     = data.encCbcrPingpongIrq;
+	packedData.viewYPingpongIrq       = data.viewYPingpongIrq;
+	packedData.viewCbcrPingpongIrq    = data.viewCbcrPingpongIrq;
+	packedData.rdPingpongIrq          = data.rdPingpongIrq;
+	packedData.afPingpongIrq          = data.afPingpongIrq;
+	packedData.awbPingpongIrq         = data.awbPingpongIrq;
+	packedData.histPingpongIrq        = data.histPingpongIrq;
+	packedData.encIrq                 = data.encIrq;
+	packedData.viewIrq                = data.viewIrq;
+	packedData.busOverflowIrq         = data.busOverflowIrq;
+	packedData.afOverflowIrq          = data.afOverflowIrq;
+	packedData.awbOverflowIrq         = data.awbOverflowIrq;
+	packedData.syncTimer0Irq          = data.syncTimer0Irq;
+	packedData.syncTimer1Irq          = data.syncTimer1Irq;
+	packedData.syncTimer2Irq          = data.syncTimer2Irq;
+	packedData.asyncTimer0Irq         = data.asyncTimer0Irq;
+	packedData.asyncTimer1Irq         = data.asyncTimer1Irq;
+	packedData.asyncTimer2Irq         = data.asyncTimer2Irq;
+	packedData.asyncTimer3Irq         = data.asyncTimer3Irq;
+	packedData.axiErrorIrq            = data.axiErrorIrq;
+	packedData.violationIrq           = data.violationIrq;
+
+	return *((uint32_t *)&packedData);
+}
+
+static uint32_t
+vfe_irq_composite_pack(struct vfe_irq_composite_mask_config data)
+{
+	struct VFE_Irq_Composite_MaskType packedData;
+
+	memset(&packedData, 0, sizeof(packedData));
+
+	packedData.encIrqComMaskBits   = data.encIrqComMask;
+	packedData.viewIrqComMaskBits  = data.viewIrqComMask;
+	packedData.ceDoneSelBits       = data.ceDoneSel;
+
+	return *((uint32_t *)&packedData);
+}
+
+static void vfe_addr_convert(struct msm_vfe_phy_info *pinfo,
+				enum vfe_resp_msg type, void *data, void **ext,
+				int *elen)
+{
+	switch (type) {
+	case VFE_MSG_OUTPUT_P:
+	case VFE_MSG_OUTPUT_V:{
+		pinfo->y_phy =
+			((struct vfe_message *)data)->_u.msgOutput2.yBuffer;
+		pinfo->cbcr_phy =
+			((struct vfe_message *)data)->_u.msgOutput2.
+			cbcrBuffer;
+		ctrl->extdata.bpcInfo =
+			((struct vfe_message *)data)->_u.msgOutput2.bpcInfo;
+		ctrl->extdata.asfInfo =
+			((struct vfe_message *)data)->_u.msgOutput2.asfInfo;
+		ctrl->extdata.frameCounter =
+			((struct vfe_message *)data)->_u.msgOutput2.
+			frameCounter;
+		ctrl->extdata.pmData =
+		((struct vfe_message *)data)->_u.msgOutput2.pmData;
+		*ext = &ctrl->extdata;
+		*elen = sizeof(ctrl->extdata);
+	}
+		break;
+
+	case VFE_MSG_STATS_AF:
+		pinfo->sbuf_phy =
+		((struct vfe_message *)data)->_u.msgStatsAf.afBuffer;
+		break;
+
+	case VFE_MSG_STATS_WE:
+		pinfo->sbuf_phy =
+		((struct vfe_message *)data)->_u.msgStatsWbExp.awbBuffer;
+		break;
+
+	default:
+		break;
+	} /* switch */
+}
+
+static boolean vfe_send_preview_msg(struct msm_vfe_resp *rp,
+			struct vfe_message *msg, void *data);
+static boolean vfe_send_video_msg(struct msm_vfe_resp *rp,
+			struct vfe_message *msg, void *data);
+static boolean vfe_send_mainimage_msg(struct msm_vfe_resp *rp,
+			struct vfe_message *msg, void *data);
+static boolean vfe_send_thumbnail_msg(struct msm_vfe_resp *rp,
+			struct vfe_message *msg, void *data);
+static boolean vfe_send_af_stats_msg(struct msm_vfe_resp *rp,
+			struct vfe_message *msg, void *data);
+static boolean vfe_send_awb_stats_msg(struct msm_vfe_resp *rp,
+			struct vfe_message *msg, void *data);
+static boolean vfe_send_camif_error_msg(struct msm_vfe_resp *rp,
+			struct vfe_message *msg, void *data);
+static boolean vfe_send_bus_overflow_msg(struct msm_vfe_resp *rp,
+			struct vfe_message *msg, void *data);
+static boolean vfe_send_sof_msg(struct msm_vfe_resp *rp,
+			struct vfe_message *msg, void *data);
+
+static boolean invalid(struct msm_vfe_resp *rp,
+		struct vfe_message *_m, void *_d)
+{
+	BUG_ON(1); /* this function should not be called. */
+	return FALSE;
+}
+
+static struct {
+	boolean (*fn)(struct msm_vfe_resp *rp, struct vfe_message *msg,
+		void *data);
+	enum vfe_resp_msg rt; /* reponse type */
+} vfe_funcs[] = {
+	[VFE_MSG_ID_RESET_ACK] = { NULL, VFE_MSG_GENERAL },
+	[VFE_MSG_ID_START_ACK] = { NULL, VFE_MSG_GENERAL },
+	[VFE_MSG_ID_STOP_ACK] = { NULL, VFE_MSG_GENERAL },
+	[VFE_MSG_ID_UPDATE_ACK] = { NULL, VFE_MSG_GENERAL },
+	[VFE_MSG_ID_OUTPUT_P] = { vfe_send_preview_msg, VFE_MSG_OUTPUT_P },
+	[VFE_MSG_ID_OUTPUT_V] = { vfe_send_video_msg, VFE_MSG_OUTPUT_V },
+	[VFE_MSG_ID_OUTPUT_S] = { vfe_send_mainimage_msg, VFE_MSG_OUTPUT_S },
+	[VFE_MSG_ID_OUTPUT_T] = { vfe_send_thumbnail_msg, VFE_MSG_OUTPUT_T },
+	[VFE_MSG_ID_SNAPSHOT_DONE] = { NULL, VFE_MSG_SNAPSHOT },
+	[VFE_MSG_ID_STATS_AUTOFOCUS] = { vfe_send_af_stats_msg,
+		VFE_MSG_STATS_AF },
+	[VFE_MSG_ID_STATS_WB_EXP] = { vfe_send_awb_stats_msg,
+		VFE_MSG_STATS_WE },
+	[VFE_MSG_ID_EPOCH1] = { NULL, VFE_MSG_GENERAL },
+	[VFE_MSG_ID_EPOCH2] = { NULL, VFE_MSG_GENERAL },
+	[VFE_MSG_ID_SYNC_TIMER0_DONE] = { invalid },
+	[VFE_MSG_ID_SYNC_TIMER1_DONE] = { invalid },
+	[VFE_MSG_ID_SYNC_TIMER2_DONE] = { invalid },
+	[VFE_MSG_ID_ASYNC_TIMER0_DONE] = { invalid },
+	[VFE_MSG_ID_ASYNC_TIMER1_DONE] = { invalid },
+	[VFE_MSG_ID_ASYNC_TIMER2_DONE] = { invalid },
+	[VFE_MSG_ID_ASYNC_TIMER3_DONE] = { invalid },
+	[VFE_MSG_ID_AF_OVERFLOW] = { NULL, VFE_MSG_GENERAL },
+	[VFE_MSG_ID_AWB_OVERFLOW] = { NULL, VFE_MSG_GENERAL },
+	[VFE_MSG_ID_AXI_ERROR] = { NULL, VFE_MSG_GENERAL },
+	[VFE_MSG_ID_CAMIF_OVERFLOW] = { NULL, VFE_MSG_GENERAL },
+	[VFE_MSG_ID_VIOLATION] = { invalid },
+	[VFE_MSG_ID_CAMIF_ERROR] = { vfe_send_camif_error_msg,
+		VFE_MSG_GENERAL },
+	[VFE_MSG_ID_BUS_OVERFLOW] = { vfe_send_bus_overflow_msg,
+		VFE_MSG_GENERAL },
+	[VFE_MSG_ID_SOF_ACK] = { vfe_send_sof_msg,
+		VFE_MSG_GENERAL },
+};
+
+static void vfe_proc_ops(enum VFE_MESSAGE_ID id, void *data)
+{
+	struct msm_vfe_resp *rp;
+	struct vfe_message *msg;
+
+	if (id >= ARRAY_SIZE(vfe_funcs) || vfe_funcs[id].fn == invalid) {
+		pr_err("%s: invalid VFE message id %d\n", __func__, id);
+		return;
+	}
+
+	/* In 8k, OUTPUT1 & OUTPUT2 messages arrive before SNAPSHOT_DONE.
+	 * We don't send such messages to the user.  Note that we can do
+	 * this in the vfe_func[] callback, but that would cause us to
+	 * allocate and then immediately free the msm_vfe_resp structure,
+	 * which is wasteful.
+	 */
+	if ((ctrl->vfeOperationMode == VFE_START_OPERATION_MODE_SNAPSHOT) &&
+			(id == VFE_MSG_ID_OUTPUT_T ||
+			 id == VFE_MSG_ID_OUTPUT_S))
+		return;
+
+	rp = ctrl->resp->vfe_alloc(sizeof(*rp) +
+					(vfe_funcs[id].fn ? sizeof(*msg) : 0),
+					ctrl->syncdata,
+					GFP_ATOMIC);
+	if (!rp) {
+		pr_err("%s: out of memory\n", __func__);
+		return;
+	}
+
+	rp->type = vfe_funcs[id].rt;
+	rp->evt_msg.type = MSM_CAMERA_MSG;
+	rp->evt_msg.msg_id = id;
+
+	if (!vfe_funcs[id].fn) {
+		rp->evt_msg.len = 0;
+		rp->evt_msg.data = 0;
+	} else {
+		/* populate the message accordingly */
+		if (vfe_funcs[id].fn)
+			rp->evt_msg.data = msg =
+				(struct vfe_message *)(rp + 1);
+		else
+			rp->evt_msg.data = msg = 0;
+		rp->evt_msg.len = sizeof(*msg);
+		msg->_d = id;
+		if (vfe_funcs[id].fn(rp, msg, data) == FALSE) {
+			pr_warning("%s: freeing memory: handler for %d "
+				"returned false\n", __func__, id);
+			ctrl->resp->vfe_free(rp);
+			return;
+		}
+}
+
+	ctrl->resp->vfe_resp(rp, MSM_CAM_Q_VFE_MSG, ctrl->syncdata, GFP_KERNEL);
+}
+
+static boolean vfe_send_bus_overflow_msg(struct msm_vfe_resp *rp,
+			struct vfe_message *msg,
+			void *data)
+{
+#if 0
+	memcpy(&(msg->_u.msgBusOverflow),
+		&ctrl->vfePmData, sizeof(ctrl->vfePmData));
+#endif
+	return TRUE;
+}
+
+static boolean vfe_send_sof_msg(struct msm_vfe_resp *rp,
+			struct vfe_message *msg,
+			void *data)
+{
+	return TRUE;
+}
+static boolean vfe_send_camif_error_msg(struct msm_vfe_resp *rp,
+			struct vfe_message *msg,
+			void *data)
+{
+#if 0
+	memcpy(&(msg->_u.msgCamifError),
+	       &ctrl->vfeCamifStatusLocal, sizeof(ctrl->vfeCamifStatusLocal));
+#endif
+	return TRUE;
+}
+
+static void vfe_process_error_irq(struct vfe_interrupt_status *irqstatus)
+{
+	/* all possible error irq.  Note error irqs are not enabled, it is
+	 * checked only when other interrupts are present. */
+	if (irqstatus->afOverflowIrq)
+		vfe_proc_ops(VFE_MSG_ID_AF_OVERFLOW, NULL);
+
+	if (irqstatus->awbOverflowIrq)
+		vfe_proc_ops(VFE_MSG_ID_AWB_OVERFLOW, NULL);
+
+	if (irqstatus->axiErrorIrq)
+		vfe_proc_ops(VFE_MSG_ID_AXI_ERROR, NULL);
+
+	if (irqstatus->busOverflowIrq)
+		vfe_proc_ops(VFE_MSG_ID_BUS_OVERFLOW, NULL);
+
+	if (irqstatus->camifErrorIrq) {
+		CDBG("vfe_irq: camif errors\n");
+		vfe_proc_ops(VFE_MSG_ID_CAMIF_ERROR, NULL);
+	}
+
+	if (irqstatus->camifOverflowIrq)
+		vfe_proc_ops(VFE_MSG_ID_CAMIF_OVERFLOW, NULL);
+
+	if (irqstatus->violationIrq)
+		pr_err("%s: violation irq\n", __func__);
+}
+
+static void vfe_process_camif_sof_irq(void)
+{
+	/* increment the frame id number. */
+	ctrl->vfeFrameId++;
+
+	CDBG("camif_sof_irq, frameId = %d\n", ctrl->vfeFrameId);
+
+	/* In snapshot mode, if frame skip is programmed,
+	* need to check it accordingly to stop camif at
+	* correct frame boundary. For the dropped frames,
+	* there won't be any output path irqs, but there is
+	* still SOF irq, which can help us determine when
+	* to stop the camif.
+	*/
+	if (ctrl->vfeOperationMode) {
+		if ((1 << ctrl->vfeFrameSkipCount)&ctrl->vfeFrameSkipPattern) {
+
+			ctrl->vfeSnapShotCount--;
+			if (ctrl->vfeSnapShotCount == 0)
+				/* terminate vfe pipeline at frame boundary. */
+				writel(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+					ctrl->vfebase + CAMIF_COMMAND);
+		}
+
+		/* update frame skip counter for bit checking. */
+		ctrl->vfeFrameSkipCount++;
+		if (ctrl->vfeFrameSkipCount == (ctrl->vfeFrameSkipPeriod + 1))
+			ctrl->vfeFrameSkipCount = 0;
+	}
+	vfe_proc_ops(VFE_MSG_ID_SOF_ACK, NULL);
+}
+
+static boolean vfe_get_af_pingpong_status(void)
+{
+	uint32_t busPingPongStatus =
+		readl(ctrl->vfebase + VFE_BUS_PINGPONG_STATUS);
+	return !!(busPingPongStatus & VFE_AF_PINGPONG_STATUS_BIT);
+}
+
+static uint32_t vfe_read_af_buf_addr(boolean pipo)
+{
+	if (pipo == FALSE)
+		return readl(ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+	else
+		return readl(ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+}
+
+static void vfe_update_af_buf_addr(boolean pipo, uint32_t addr)
+{
+	if (pipo == FALSE)
+		writel(addr, ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+	else
+		writel(addr, ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+}
+
+static boolean vfe_send_af_stats_msg(struct msm_vfe_resp *rp,
+		struct vfe_message *msg, void *data)
+{
+	uint32_t afBufAddress = (uint32_t)data;
+
+	/* fill message with right content. */
+	/* @todo This is causing issues, need further investigate */
+	/* spin_lock_irqsave(&ctrl->state_lock, flags); */
+	if (ctrl->vstate != VFE_STATE_ACTIVE)
+		return FALSE;
+
+	msg->_u.msgStatsAf.afBuffer = afBufAddress;
+	msg->_u.msgStatsAf.frameCounter = ctrl->vfeFrameId;
+
+	ctrl->afStatsControl.ackPending = TRUE;
+
+	vfe_addr_convert(&(rp->phy), rp->type, msg, NULL, NULL);
+	/* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
+	return TRUE;
+}
+
+static void vfe_process_stats_af_irq(void)
+{
+	boolean bufferAvailable;
+
+	if (!(ctrl->afStatsControl.ackPending)) {
+
+		/* read hardware status. */
+		ctrl->afStatsControl.pingPongStatus =
+			vfe_get_af_pingpong_status();
+
+		bufferAvailable = (ctrl->afStatsControl.pingPongStatus) ^ 1;
+
+		ctrl->afStatsControl.bufToRender =
+			vfe_read_af_buf_addr(bufferAvailable);
+
+		/* update the same buffer address (ping or pong) */
+		vfe_update_af_buf_addr(bufferAvailable,
+			ctrl->afStatsControl.nextFrameAddrBuf);
+
+		vfe_proc_ops(VFE_MSG_ID_STATS_AUTOFOCUS,
+			(void *)ctrl->afStatsControl.bufToRender);
+	} else
+		ctrl->afStatsControl.droppedStatsFrameCount++;
+}
+
+static boolean vfe_get_awb_pingpong_status(void)
+{
+	uint32_t busPingPongStatus =
+
+		readl(ctrl->vfebase + VFE_BUS_PINGPONG_STATUS);
+
+	return !!(busPingPongStatus & VFE_AWB_PINGPONG_STATUS_BIT);
+
+}
+
+static uint32_t vfe_read_awb_buf_addr(boolean pingpong)
+{
+	if (pingpong == FALSE)
+		return readl(ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+	else
+		return readl(ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+}
+
+static void vfe_update_awb_buf_addr(boolean pingpong, uint32_t addr)
+{
+	if (pingpong == FALSE)
+		writel(addr, ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+	else
+		writel(addr, ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+}
+
+static boolean vfe_send_awb_stats_msg(struct msm_vfe_resp *rp,
+		struct vfe_message *msg, void *data)
+{
+	uint32_t awbBufAddress = (uint32_t)data;
+
+	/* fill message with right content. */
+	/* @todo This is causing issues, need further investigate */
+	/* spin_lock_irqsave(&ctrl->state_lock, flags); */
+	if (ctrl->vstate != VFE_STATE_ACTIVE)
+		return FALSE;
+
+	msg->_u.msgStatsWbExp.awbBuffer = awbBufAddress;
+	msg->_u.msgStatsWbExp.frameCounter = ctrl->vfeFrameId;
+
+
+	ctrl->awbStatsControl.ackPending = TRUE;
+
+	vfe_addr_convert(&(rp->phy),
+			rp->type, msg,
+			NULL, NULL);
+
+	return TRUE;
+}
+
+static void vfe_process_stats_awb_irq(void)
+{
+	boolean bufferAvailable;
+
+	if (!(ctrl->awbStatsControl.ackPending)) {
+
+		ctrl->awbStatsControl.pingPongStatus =
+			vfe_get_awb_pingpong_status();
+
+		bufferAvailable = (ctrl->awbStatsControl.pingPongStatus) ^ 1;
+
+		ctrl->awbStatsControl.bufToRender =
+			vfe_read_awb_buf_addr(bufferAvailable);
+
+		vfe_update_awb_buf_addr(bufferAvailable,
+			ctrl->awbStatsControl.nextFrameAddrBuf);
+
+		vfe_proc_ops(VFE_MSG_ID_STATS_WB_EXP,
+			(void *)ctrl->awbStatsControl.bufToRender);
+
+	} else
+		ctrl->awbStatsControl.droppedStatsFrameCount++;
+}
+
+static void vfe_write_gamma_table(uint8_t channel,
+	boolean bank, int16_t *pTable)
+{
+	uint16_t i;
+
+	enum VFE_DMI_RAM_SEL dmiRamSel = NO_MEM_SELECTED;
+
+	switch (channel) {
+	case 0:
+		if (bank == 0)
+			dmiRamSel = RGBLUT_RAM_CH0_BANK0;
+		else
+			dmiRamSel = RGBLUT_RAM_CH0_BANK1;
+		break;
+
+	case 1:
+		if (bank == 0)
+			dmiRamSel = RGBLUT_RAM_CH1_BANK0;
+		else
+			dmiRamSel = RGBLUT_RAM_CH1_BANK1;
+		break;
+
+	case 2:
+		if (bank == 0)
+			dmiRamSel = RGBLUT_RAM_CH2_BANK0;
+		else
+			dmiRamSel = RGBLUT_RAM_CH2_BANK1;
+		break;
+
+	default:
+		break;
+	}
+
+	vfe_program_dmi_cfg(dmiRamSel);
+
+	for (i = 0; i < VFE_GAMMA_TABLE_LENGTH; i++) {
+		writel((uint32_t)(*pTable), ctrl->vfebase + VFE_DMI_DATA_LO);
+		pTable++;
+	}
+
+	/* After DMI transfer, need to set the DMI_CFG to unselect any SRAM
+	unselect the SRAM Bank. */
+	writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG);
+}
+
+static void vfe_prog_hw_testgen_cmd(uint32_t value)
+{
+	writel(value, ctrl->vfebase + VFE_HW_TESTGEN_CMD);
+}
+
+static inline void vfe_read_irq_status(struct vfe_irq_thread_msg *out)
+{
+	uint32_t *temp;
+
+	memset(out, 0, sizeof(struct vfe_irq_thread_msg));
+
+	temp = (uint32_t *)(ctrl->vfebase + VFE_IRQ_STATUS);
+	out->vfeIrqStatus = readl(temp);
+
+	temp = (uint32_t *)(ctrl->vfebase + CAMIF_STATUS);
+	out->camifStatus = readl(temp);
+
+/*	this for YUV performance tuning
+	writel(0x7, ctrl->vfebase + CAMIF_COMMAND);
+	writel(0x3, ctrl->vfebase + CAMIF_COMMAND);
+	CDBG("camifStatus  = 0x%x\n", out->camifStatus);
+*/
+/*
+	temp = (uint32_t *)(ctrl->vfebase + VFE_DEMOSAIC_STATUS);
+	out->demosaicStatus = readl(temp);
+
+	temp = (uint32_t *)(ctrl->vfebase + VFE_ASF_MAX_EDGE);
+	out->asfMaxEdge = readl(temp);
+
+	temp = (uint32_t *)(ctrl->vfebase + VFE_BUS_ENC_Y_WR_PM_STATS_0);
+*/
+
+#if 0
+	out->pmInfo.encPathPmInfo.yWrPmStats0      = readl(temp++);
+	out->pmInfo.encPathPmInfo.yWrPmStats1      = readl(temp++);
+	out->pmInfo.encPathPmInfo.cbcrWrPmStats0   = readl(temp++);
+	out->pmInfo.encPathPmInfo.cbcrWrPmStats1   = readl(temp++);
+	out->pmInfo.viewPathPmInfo.yWrPmStats0     = readl(temp++);
+	out->pmInfo.viewPathPmInfo.yWrPmStats1     = readl(temp++);
+	out->pmInfo.viewPathPmInfo.cbcrWrPmStats0  = readl(temp++);
+	out->pmInfo.viewPathPmInfo.cbcrWrPmStats1  = readl(temp);
+#endif /* if 0 Jeff */
+}
+
+static void
+vfe_parse_interrupt_status(struct vfe_interrupt_status *ret,
+uint32_t irqStatusIn)
+{
+	struct vfe_irqenable hwstat;
+	boolean temp;
+
+	memset(&hwstat, 0, sizeof(hwstat));
+	memset(ret, 0, sizeof(*ret));
+
+	hwstat = *((struct vfe_irqenable *)(&irqStatusIn));
+
+	ret->camifErrorIrq = hwstat.camifErrorIrq;
+	ret->camifSofIrq = hwstat.camifSofIrq;
+	ret->camifEolIrq = hwstat.camifEolIrq;
+	ret->camifEofIrq = hwstat.camifEofIrq;
+	ret->camifEpoch1Irq = hwstat.camifEpoch1Irq;
+	ret->camifEpoch2Irq = hwstat.camifEpoch2Irq;
+	ret->camifOverflowIrq = hwstat.camifOverflowIrq;
+	ret->ceIrq = hwstat.ceIrq;
+	ret->regUpdateIrq = hwstat.regUpdateIrq;
+	ret->resetAckIrq = hwstat.resetAckIrq;
+	ret->encYPingpongIrq = hwstat.encYPingpongIrq;
+	ret->encCbcrPingpongIrq = hwstat.encCbcrPingpongIrq;
+	ret->viewYPingpongIrq = hwstat.viewYPingpongIrq;
+	ret->viewCbcrPingpongIrq = hwstat.viewCbcrPingpongIrq;
+	ret->rdPingpongIrq = hwstat.rdPingpongIrq;
+	ret->afPingpongIrq = hwstat.afPingpongIrq;
+	ret->awbPingpongIrq = hwstat.awbPingpongIrq;
+	ret->histPingpongIrq = hwstat.histPingpongIrq;
+	ret->encIrq = hwstat.encIrq;
+	ret->viewIrq = hwstat.viewIrq;
+	ret->busOverflowIrq = hwstat.busOverflowIrq;
+	ret->afOverflowIrq = hwstat.afOverflowIrq;
+	ret->awbOverflowIrq = hwstat.awbOverflowIrq;
+	ret->syncTimer0Irq = hwstat.syncTimer0Irq;
+	ret->syncTimer1Irq = hwstat.syncTimer1Irq;
+	ret->syncTimer2Irq = hwstat.syncTimer2Irq;
+	ret->asyncTimer0Irq = hwstat.asyncTimer0Irq;
+	ret->asyncTimer1Irq = hwstat.asyncTimer1Irq;
+	ret->asyncTimer2Irq = hwstat.asyncTimer2Irq;
+	ret->asyncTimer3Irq = hwstat.asyncTimer3Irq;
+	ret->axiErrorIrq = hwstat.axiErrorIrq;
+	ret->violationIrq = hwstat.violationIrq;
+
+	/* logic OR of any error bits
+	 * although each irq corresponds to a bit, the data type here is a
+	 * boolean already. hence use logic operation.
+	 */
+	temp =
+	    ret->camifErrorIrq ||
+	    ret->camifOverflowIrq ||
+	    ret->afOverflowIrq ||
+	    ret->awbOverflowIrq ||
+	    ret->awbPingpongIrq ||
+	    ret->afPingpongIrq ||
+	    ret->busOverflowIrq || ret->axiErrorIrq || ret->violationIrq;
+
+	ret->anyErrorIrqs = temp;
+
+	/* logic OR of any output path bits*/
+	temp = ret->encYPingpongIrq || ret->encCbcrPingpongIrq || ret->encIrq;
+
+	ret->anyOutput2PathIrqs = temp;
+
+	temp = ret->viewYPingpongIrq || ret->viewCbcrPingpongIrq ||
+		ret->viewIrq;
+
+	ret->anyOutput1PathIrqs = temp;
+
+	ret->anyOutputPathIrqs =
+	    ret->anyOutput1PathIrqs || ret->anyOutput2PathIrqs;
+
+	/* logic OR of any sync timer bits*/
+	temp = ret->syncTimer0Irq || ret->syncTimer1Irq || ret->syncTimer2Irq;
+
+	ret->anySyncTimerIrqs = temp;
+
+	/* logic OR of any async timer bits*/
+	temp =
+	    ret->asyncTimer0Irq ||
+	    ret->asyncTimer1Irq || ret->asyncTimer2Irq || ret->asyncTimer3Irq;
+
+	ret->anyAsyncTimerIrqs = temp;
+
+	/* bool for all interrupts that are not allowed in idle state */
+	temp =
+	    ret->anyErrorIrqs ||
+	    ret->anyOutputPathIrqs ||
+	    ret->anySyncTimerIrqs ||
+	    ret->regUpdateIrq ||
+	    ret->awbPingpongIrq ||
+	    ret->afPingpongIrq ||
+	    ret->camifSofIrq || ret->camifEpoch2Irq || ret->camifEpoch1Irq;
+
+	ret->anyIrqForActiveStatesOnly = temp;
+}
+
+static void
+vfe_get_asf_frame_info(struct vfe_frame_asf_info *rc,
+struct vfe_irq_thread_msg *in)
+{
+	struct vfe_asf_info     asfInfoTemp;
+
+	memset(rc, 0, sizeof(*rc));
+	memset(&asfInfoTemp, 0, sizeof(asfInfoTemp));
+
+	asfInfoTemp = *((struct vfe_asf_info *)(&(in->asfMaxEdge)));
+
+	rc->asfHbiCount = asfInfoTemp.HBICount;
+	rc->asfMaxEdge = asfInfoTemp.maxEdge;
+}
+
+static void
+vfe_get_demosaic_frame_info(struct vfe_frame_bpc_info *rc,
+struct vfe_irq_thread_msg *in)
+{
+	struct vfe_bps_info     bpcInfoTemp;
+
+	memset(rc, 0, sizeof(*rc));
+	memset(&bpcInfoTemp, 0, sizeof(bpcInfoTemp));
+
+	bpcInfoTemp = *((struct vfe_bps_info *)(&(in->demosaicStatus)));
+
+	rc->greenDefectPixelCount = bpcInfoTemp.greenBadPixelCount;
+
+	rc->redBlueDefectPixelCount = bpcInfoTemp.RedBlueBadPixelCount;
+}
+
+static void
+vfe_get_camif_status(struct vfe_msg_camif_status *rc,
+struct vfe_irq_thread_msg *in)
+{
+	struct vfe_camif_stats camifStatusTemp;
+
+	memset(rc, 0, sizeof(*rc));
+	memset(&camifStatusTemp, 0, sizeof(camifStatusTemp));
+
+	camifStatusTemp = *((struct vfe_camif_stats *)(&(in->camifStatus)));
+
+	rc->camifState = (boolean) camifStatusTemp.camifHalt;
+	rc->lineCount = camifStatusTemp.lineCount;
+	rc->pixelCount = camifStatusTemp.pixelCount;
+}
+
+static void
+vfe_get_performance_monitor_data(struct vfe_bus_performance_monitor *rc,
+		struct vfe_irq_thread_msg *in)
+{
+	memset(rc, 0, sizeof(*rc));
+
+	rc->encPathPmInfo.yWrPmStats0 = in->pmInfo.encPathPmInfo.yWrPmStats0;
+	rc->encPathPmInfo.yWrPmStats1 = in->pmInfo.encPathPmInfo.yWrPmStats1;
+	rc->encPathPmInfo.cbcrWrPmStats0 =
+		in->pmInfo.encPathPmInfo.cbcrWrPmStats0;
+	rc->encPathPmInfo.cbcrWrPmStats1 =
+		in->pmInfo.encPathPmInfo.cbcrWrPmStats1;
+	rc->viewPathPmInfo.yWrPmStats0 = in->pmInfo.viewPathPmInfo.yWrPmStats0;
+	rc->viewPathPmInfo.yWrPmStats1 = in->pmInfo.viewPathPmInfo.yWrPmStats1;
+	rc->viewPathPmInfo.cbcrWrPmStats0 =
+		in->pmInfo.viewPathPmInfo.cbcrWrPmStats0;
+	rc->viewPathPmInfo.cbcrWrPmStats1 =
+	    in->pmInfo.viewPathPmInfo.cbcrWrPmStats1;
+}
+
+static void vfe_process_reg_update_irq(void)
+{
+	CDBG("vfe_process_reg_update_irq: ackPendingFlag is %d\n",
+	ctrl->vfeStartAckPendingFlag);
+	if (ctrl->vfeStartAckPendingFlag == TRUE) {
+		vfe_proc_ops(VFE_MSG_ID_START_ACK, NULL);
+		ctrl->vfeStartAckPendingFlag = FALSE;
+	} else
+		vfe_proc_ops(VFE_MSG_ID_UPDATE_ACK, NULL);
+}
+
+static void vfe_process_reset_irq(void)
+{
+	/* unsigned long flags; */
+
+	/* @todo This is causing issues, need further investigate */
+	/* spin_lock_irqsave(&ctrl->state_lock, flags); */
+	ctrl->vstate = VFE_STATE_IDLE;
+	/* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
+
+	if (ctrl->vfeStopAckPending == TRUE) {
+		ctrl->vfeStopAckPending = FALSE;
+		vfe_proc_ops(VFE_MSG_ID_STOP_ACK, NULL);
+	} else {
+		vfe_set_default_reg_values();
+		vfe_proc_ops(VFE_MSG_ID_RESET_ACK, NULL);
+	}
+}
+
+static void vfe_process_pingpong_irq(struct vfe_output_path *in,
+	uint8_t fragmentCount)
+{
+	uint16_t circularIndex;
+	uint32_t nextFragmentAddr;
+
+	/* get next fragment address from circular buffer */
+	circularIndex    = (in->fragIndex) % (2 * fragmentCount);
+	nextFragmentAddr = in->addressBuffer[circularIndex];
+
+	in->fragIndex = circularIndex + 1;
+
+	/* use next fragment to program hardware ping/pong address. */
+	if (in->hwCurrentFlag == ping) {
+		writel(nextFragmentAddr, in->hwRegPingAddress);
+		in->hwCurrentFlag = pong;
+
+	} else {
+		writel(nextFragmentAddr, in->hwRegPongAddress);
+		in->hwCurrentFlag = ping;
+	}
+}
+
+static boolean vfe_send_video_msg(struct msm_vfe_resp *rp,
+		struct vfe_message *msg, void *data)
+{
+	struct vfe_msg_output *pPayload = data;
+
+	if (ctrl->vstate != VFE_STATE_ACTIVE)
+		return FALSE;
+	memcpy(&(msg->_u),
+		(void *)pPayload, sizeof(struct vfe_msg_output));
+
+	rp->phy.output_id = OUTPUT_TYPE_V;
+	CDBG("vfe_send_video_msg rp->type= %d\n", rp->type);
+
+	vfe_addr_convert(&(rp->phy),
+			rp->type, msg,
+			&(rp->extdata), &(rp->extlen));
+	return TRUE;
+}
+
+static boolean vfe_send_preview_msg(struct msm_vfe_resp *rp,
+		struct vfe_message *msg, void *data)
+{
+	struct vfe_msg_output *pPayload = data;
+
+	if (ctrl->vstate != VFE_STATE_ACTIVE)
+		return FALSE;
+
+	memcpy(&(msg->_u), (void *)pPayload, sizeof(struct vfe_msg_output));
+
+	rp->phy.output_id = OUTPUT_TYPE_P;
+	CDBG("vfe_send_preview_msg rp->type= %d\n", rp->type);
+
+	vfe_addr_convert(&(rp->phy),
+			rp->type, msg,
+			&(rp->extdata), &(rp->extlen));
+
+	return TRUE;
+}
+
+
+static boolean vfe_send_thumbnail_msg(struct msm_vfe_resp *rp,
+		struct vfe_message *msg, void *data)
+{
+	struct vfe_msg_output *pPayload = data;
+
+	if (ctrl->vstate != VFE_STATE_ACTIVE)
+		return FALSE;
+
+	memcpy(&(msg->_u), (void *)pPayload, sizeof(struct vfe_msg_output));
+
+	rp->phy.output_id = OUTPUT_TYPE_T;
+	CDBG("vfe_send_thumbnail_msg rp->type= %d\n", rp->type);
+
+	if (ctrl->viewPath.snapshotPendingCount <= 1)
+		ctrl->viewPath.ackPending = FALSE;
+
+	vfe_addr_convert(&(rp->phy),
+			rp->type, msg,
+			&(rp->extdata), &(rp->extlen));
+	return TRUE;
+}
+
+static boolean vfe_send_mainimage_msg(struct msm_vfe_resp *rp,
+		struct vfe_message *msg, void *data)
+{
+	struct vfe_msg_output *pPayload = data;
+
+	if (ctrl->vstate != VFE_STATE_ACTIVE)
+		return FALSE;
+
+	memcpy(&(msg->_u), (void *)pPayload, sizeof(struct vfe_msg_output));
+
+	rp->phy.output_id = OUTPUT_TYPE_S;
+	CDBG("vfe_send_mainimage_msg rp->type= %d\n", rp->type);
+
+	if (ctrl->encPath.snapshotPendingCount <= 1) {
+		ctrl->encPath.ackPending = FALSE;
+	}
+
+	vfe_addr_convert(&(rp->phy),
+			rp->type, msg,
+			&(rp->extdata), &(rp->extlen));
+
+	return TRUE;
+}
+
+static void vfe_send_output_msg(boolean whichOutputPath,
+	uint32_t yPathAddr, uint32_t cbcrPathAddr)
+{
+	struct vfe_msg_output msgPayload;
+
+	msgPayload.yBuffer = yPathAddr;
+	msgPayload.cbcrBuffer = cbcrPathAddr;
+
+	/* asf info is common for both output1 and output2 */
+#if 0
+	msgPayload.asfInfo.asfHbiCount = ctrl->vfeAsfFrameInfo.asfHbiCount;
+	msgPayload.asfInfo.asfMaxEdge = ctrl->vfeAsfFrameInfo.asfMaxEdge;
+
+	/* demosaic info is common for both output1 and output2 */
+	msgPayload.bpcInfo.greenDefectPixelCount =
+		ctrl->vfeBpcFrameInfo.greenDefectPixelCount;
+	msgPayload.bpcInfo.redBlueDefectPixelCount =
+		ctrl->vfeBpcFrameInfo.redBlueDefectPixelCount;
+#endif /* if 0 */
+
+	/* frame ID is common for both paths. */
+	msgPayload.frameCounter = ctrl->vfeFrameId;
+
+	if (whichOutputPath) {
+		/* msgPayload.pmData = ctrl->vfePmData.encPathPmInfo; */
+		ctrl->encPath.ackPending = TRUE;
+
+		if (ctrl->vfeOperationMode == 0) {
+			if (ctrl->axiOutputMode ==
+				VFE_AXI_OUTPUT_MODE_Output1AndOutput2) {
+				/* video mode */
+				vfe_proc_ops(VFE_MSG_ID_OUTPUT_V, &msgPayload);
+			} else{
+				/* preview mode */
+				vfe_proc_ops(VFE_MSG_ID_OUTPUT_P, &msgPayload);
+			}
+		} else {
+			vfe_proc_ops(VFE_MSG_ID_OUTPUT_S, &msgPayload);
+		}
+
+	} else {
+		/* physical output1 path from vfe */
+		ctrl->viewPath.ackPending = TRUE;
+
+		if (ctrl->vfeOperationMode == 0) {
+			vfe_proc_ops(VFE_MSG_ID_OUTPUT_P, &msgPayload);
+			CDBG(" video mode display output.\n");
+
+		} else{
+			vfe_proc_ops(VFE_MSG_ID_OUTPUT_T, &msgPayload);
+			CDBG(" snapshot mode thumbnail output.\n");
+		}
+	}
+}
+
+static void vfe_process_frame_done_irq_multi_frag(struct vfe_output_path_combo
+						  *in)
+{
+	uint32_t yAddress, cbcrAddress;
+	uint16_t idx;
+	uint32_t *ptrY;
+	uint32_t *ptrCbcr;
+	const uint32_t *ptrSrc;
+	uint8_t i;
+
+	if (!in->ackPending) {
+
+		idx = (in->currentFrame) * (in->fragCount);
+
+		/* Send output message. */
+		yAddress = in->yPath.addressBuffer[idx];
+		cbcrAddress = in->cbcrPath.addressBuffer[idx];
+
+		/* copy next frame to current frame. */
+		ptrSrc  = in->nextFrameAddrBuf;
+		ptrY = (uint32_t *)&in->yPath.addressBuffer[idx];
+		ptrCbcr = (uint32_t *)&in->cbcrPath.addressBuffer[idx];
+
+		/* Copy Y address */
+		for (i = 0; i < in->fragCount; i++)
+			*ptrY++ = *ptrSrc++;
+
+		/* Copy Cbcr address */
+		for (i = 0; i < in->fragCount; i++)
+			*ptrCbcr++ = *ptrSrc++;
+
+		vfe_send_output_msg(in->whichOutputPath, yAddress, cbcrAddress);
+
+	} else {
+		if (in->whichOutputPath == 0)
+			ctrl->vfeDroppedFrameCounts.output1Count++;
+
+		if (in->whichOutputPath == 1)
+			ctrl->vfeDroppedFrameCounts.output2Count++;
+	}
+
+	/* toggle current frame. */
+	in->currentFrame = in->currentFrame^1;
+
+	if (ctrl->vfeOperationMode)
+		in->snapshotPendingCount--;
+}
+
+static void vfe_process_frame_done_irq_no_frag_io(
+		struct vfe_output_path_combo *in,
+		uint32_t *pNextAddr,
+	uint32_t *pdestRenderAddr)
+{
+	uint32_t busPingPongStatus;
+	uint32_t tempAddress;
+
+	/* 1. read hw status register. */
+	busPingPongStatus = readl(ctrl->vfebase + VFE_BUS_PINGPONG_STATUS);
+
+	CDBG("hardware status is 0x%x\n", busPingPongStatus);
+
+	/* 2. determine ping or pong */
+	/* use cbcr status */
+	busPingPongStatus = busPingPongStatus & (1<<(in->cbcrStatusBit));
+
+	/* 3. read out address and update address */
+	if (busPingPongStatus == 0) {
+		/* hw is working on ping, render pong buffer */
+		/* a. read out pong address */
+		/* read out y address. */
+		tempAddress = readl(in->yPath.hwRegPongAddress);
+
+		CDBG("pong 1 addr = 0x%x\n", tempAddress);
+		*pdestRenderAddr++ = tempAddress;
+		/* read out cbcr address. */
+		tempAddress = readl(in->cbcrPath.hwRegPongAddress);
+
+		CDBG("pong 2 addr = 0x%x\n", tempAddress);
+		*pdestRenderAddr = tempAddress;
+
+		/* b. update pong address */
+		writel(*pNextAddr++, in->yPath.hwRegPongAddress);
+		writel(*pNextAddr, in->cbcrPath.hwRegPongAddress);
+	} else {
+		/* hw is working on pong, render ping buffer */
+
+		/* a. read out ping address */
+		tempAddress = readl(in->yPath.hwRegPingAddress);
+		CDBG("ping 1 addr = 0x%x\n", tempAddress);
+		*pdestRenderAddr++ = tempAddress;
+		tempAddress = readl(in->cbcrPath.hwRegPingAddress);
+
+		CDBG("ping 2 addr = 0x%x\n", tempAddress);
+		*pdestRenderAddr = tempAddress;
+
+		/* b. update ping address */
+		writel(*pNextAddr++, in->yPath.hwRegPingAddress);
+		CDBG("NextAddress = 0x%x\n", *pNextAddr);
+		writel(*pNextAddr, in->cbcrPath.hwRegPingAddress);
+	}
+}
+
+static void vfe_process_frame_done_irq_no_frag(struct vfe_output_path_combo *in)
+{
+	uint32_t addressToRender[2];
+
+	if (!in->ackPending) {
+		vfe_process_frame_done_irq_no_frag_io(in,
+						      in->nextFrameAddrBuf,
+						      addressToRender);
+
+		/* use addressToRender to send out message. */
+		vfe_send_output_msg(in->whichOutputPath,
+				addressToRender[0], addressToRender[1]);
+
+	} else {
+		/* ackPending is still there, accumulate dropped frame count.
+		 * These count can be read through ioctrl command. */
+		CDBG("waiting frame ACK\n");
+
+		if (in->whichOutputPath == 0)
+			ctrl->vfeDroppedFrameCounts.output1Count++;
+
+		if (in->whichOutputPath == 1)
+			ctrl->vfeDroppedFrameCounts.output2Count++;
+	}
+
+	/* in case of multishot when upper layer did not ack, there will still
+	 * be a snapshot done msg sent out, even though the number of frames
+	 * sent out may be less than the desired number of frames.  snapshot
+	 * done msg would be helpful to indicate that vfe pipeline has stop,
+	 * and in good known state.
+	 */
+	if (ctrl->vfeOperationMode)
+		in->snapshotPendingCount--;
+}
+
+static void vfe_process_output_path_irq(struct vfe_interrupt_status *irqstatus)
+{
+	/* unsigned long flags; */
+
+	/* process the view path interrupts */
+	if (irqstatus->anyOutput1PathIrqs) {
+		if (ctrl->viewPath.multiFrag) {
+
+			if (irqstatus->viewCbcrPingpongIrq)
+				vfe_process_pingpong_irq(&
+							 (ctrl->viewPath.
+							  cbcrPath),
+							 ctrl->viewPath.
+							 fragCount);
+
+			if (irqstatus->viewYPingpongIrq)
+				vfe_process_pingpong_irq(&
+							 (ctrl->viewPath.yPath),
+							 ctrl->viewPath.
+							 fragCount);
+
+			if (irqstatus->viewIrq)
+				vfe_process_frame_done_irq_multi_frag(&ctrl->
+								      viewPath);
+
+		} else {
+			/* typical case for no fragment,
+			 only frame done irq is enabled. */
+			if (irqstatus->viewIrq)
+				vfe_process_frame_done_irq_no_frag(&ctrl->
+								   viewPath);
+		}
+	}
+
+	/* process the encoder path interrupts */
+	if (irqstatus->anyOutput2PathIrqs) {
+		if (ctrl->encPath.multiFrag) {
+			if (irqstatus->encCbcrPingpongIrq)
+				vfe_process_pingpong_irq(&
+							 (ctrl->encPath.
+							  cbcrPath),
+							 ctrl->encPath.
+							 fragCount);
+
+			if (irqstatus->encYPingpongIrq)
+				vfe_process_pingpong_irq(&(ctrl->encPath.yPath),
+							 ctrl->encPath.
+							 fragCount);
+
+			if (irqstatus->encIrq)
+				vfe_process_frame_done_irq_multi_frag(&ctrl->
+								      encPath);
+
+		} else {
+			if (irqstatus->encIrq)
+				vfe_process_frame_done_irq_no_frag(&ctrl->
+								   encPath);
+		}
+	}
+
+	if (ctrl->vfeOperationMode) {
+		if ((ctrl->encPath.snapshotPendingCount == 0) &&
+				(ctrl->viewPath.snapshotPendingCount == 0)) {
+
+			/* @todo This is causing issues, further investigate */
+			/* spin_lock_irqsave(&ctrl->state_lock, flags); */
+			ctrl->vstate = VFE_STATE_IDLE;
+			/* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
+
+			vfe_proc_ops(VFE_MSG_ID_SNAPSHOT_DONE, NULL);
+			vfe_camif_stop_immediately();
+			vfe_prog_hw_testgen_cmd(VFE_TEST_GEN_STOP);
+			vfe_pm_stop();
+		}
+	}
+}
+
+static void __vfe_do_tasklet(struct isr_queue_cmd *qcmd)
+{
+	if (qcmd->vfeInterruptStatus.regUpdateIrq) {
+		CDBG("irq regUpdateIrq\n");
+		vfe_process_reg_update_irq();
+	}
+
+	if (qcmd->vfeInterruptStatus.resetAckIrq) {
+		CDBG("%s: process resetAckIrq\n", __func__);
+		vfe_process_reset_irq();
+	}
+
+	if (ctrl->vstate != VFE_STATE_ACTIVE)
+		return;
+
+#if 0
+	if (qcmd->vfeInterruptStatus.camifEpoch1Irq)
+		vfe_proc_ops(VFE_MSG_ID_EPOCH1);
+
+	if (qcmd->vfeInterruptStatus.camifEpoch2Irq)
+		vfe_proc_ops(VFE_MSG_ID_EPOCH2);
+#endif /* Jeff */
+
+	/* next, check output path related interrupts. */
+	if (qcmd->vfeInterruptStatus.anyOutputPathIrqs) {
+		CDBG("irq: anyOutputPathIrqs\n");
+		vfe_process_output_path_irq(&qcmd->vfeInterruptStatus);
+	}
+
+	if (qcmd->vfeInterruptStatus.afPingpongIrq)
+		vfe_process_stats_af_irq();
+
+	if (qcmd->vfeInterruptStatus.awbPingpongIrq)
+		vfe_process_stats_awb_irq();
+
+	/* any error irqs*/
+	if (qcmd->vfeInterruptStatus.anyErrorIrqs)
+		vfe_process_error_irq(&qcmd->vfeInterruptStatus);
+
+#if 0
+	if (qcmd->vfeInterruptStatus.anySyncTimerIrqs)
+		vfe_process_sync_timer_irq();
+
+	if (qcmd->vfeInterruptStatus.anyAsyncTimerIrqs)
+		vfe_process_async_timer_irq();
+#endif /* Jeff */
+
+	if (qcmd->vfeInterruptStatus.camifSofIrq) {
+		CDBG("irq: camifSofIrq\n");
+		vfe_process_camif_sof_irq();
+	}
+}
+
+static struct isr_queue_cmd *get_irq_cmd_nosync(void)
+{
+	int old_get = ctrl->irq_get++;
+	ctrl->irq_get = ctrl->irq_get % ARRAY_SIZE(ctrl->irqs);
+	if (ctrl->irq_get == ctrl->irq_put) {
+		pr_err("%s: out of irq command packets\n", __func__);
+		ctrl->irq_get = old_get;
+		return NULL;
+	}
+
+	return ctrl->irqs + old_get;
+}
+
+static struct isr_queue_cmd *next_irq_cmd(void)
+{
+	unsigned long flags;
+	struct isr_queue_cmd *cmd;
+	spin_lock_irqsave(&ctrl->irqs_lock, flags);
+	if (ctrl->irq_get == ctrl->irq_put) {
+		spin_unlock_irqrestore(&ctrl->irqs_lock, flags);
+		return NULL; /* already empty */
+	}
+	cmd = ctrl->irqs + ctrl->irq_put;
+	spin_unlock_irqrestore(&ctrl->irqs_lock, flags);
+	return cmd;
+}
+
+static void put_irq_cmd(void)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&ctrl->irqs_lock, flags);
+	if (ctrl->irq_get == ctrl->irq_put) {
+		spin_unlock_irqrestore(&ctrl->irqs_lock, flags);
+		return; /* already empty */
+	}
+	ctrl->irq_put++;
+	ctrl->irq_put %= ARRAY_SIZE(ctrl->irqs);
+	spin_unlock_irqrestore(&ctrl->irqs_lock, flags);
+}
+
+static void vfe_do_tasklet(unsigned long data)
+{
+	int cnt = 0;
+	unsigned long flags;
+	struct isr_queue_cmd *qcmd = NULL;
+
+	spin_lock_irqsave(&msm_vfe_ctrl_lock, flags);
+	if (!ctrl) {
+		spin_unlock_irqrestore(&msm_vfe_ctrl_lock, flags);
+		return;
+	}
+
+	CDBG("%s\n", __func__);
+
+	while ((qcmd = next_irq_cmd())) {
+		__vfe_do_tasklet(qcmd);
+		put_irq_cmd();
+		cnt++;
+	}
+
+	if (cnt > ARRAY_SIZE(ctrl->irqs)/2)
+		CDBG("%s: serviced %d vfe interrupts\n", __func__, cnt);
+
+	spin_unlock_irqrestore(&msm_vfe_ctrl_lock, flags);
+}
+
+DECLARE_TASKLET(vfe_tasklet, vfe_do_tasklet, 0);
+
+static irqreturn_t vfe_parse_irq(int irq_num, void *data)
+{
+	unsigned long flags;
+	uint32_t irqStatusLocal;
+	struct vfe_irq_thread_msg irq;
+	struct isr_queue_cmd *qcmd;
+
+	CDBG("vfe_parse_irq\n");
+
+	if (!atomic_read(&ctrl->vfe_serv_interrupt))
+		return IRQ_HANDLED;
+
+	vfe_read_irq_status(&irq);
+
+	if (irq.vfeIrqStatus == 0) {
+		CDBG("vfe_parse_irq: irq.vfeIrqStatus is 0\n");
+		return IRQ_HANDLED;
+	}
+
+	if (ctrl->vfeStopAckPending)
+		irqStatusLocal = (VFE_IMASK_WHILE_STOPPING & irq.vfeIrqStatus);
+	else
+		irqStatusLocal =
+			((ctrl->vfeImaskPacked | VFE_IMASK_ERROR_ONLY) &
+				irq.vfeIrqStatus);
+
+	spin_lock_irqsave(&ctrl->irqs_lock, flags);
+	qcmd = get_irq_cmd_nosync();
+	if (!qcmd) {
+		spin_unlock_irqrestore(&ctrl->irqs_lock, flags);
+		goto done;
+	}
+	/* first parse the interrupt status to local data structures. */
+	vfe_parse_interrupt_status(&qcmd->vfeInterruptStatus, irqStatusLocal);
+	vfe_get_asf_frame_info(&qcmd->vfeAsfFrameInfo, &irq);
+	vfe_get_demosaic_frame_info(&qcmd->vfeBpcFrameInfo, &irq);
+	vfe_get_camif_status(&qcmd->vfeCamifStatusLocal, &irq);
+	vfe_get_performance_monitor_data(&qcmd->vfePmData, &irq);
+	spin_unlock_irqrestore(&ctrl->irqs_lock, flags);
+	tasklet_schedule(&vfe_tasklet);
+
+done:
+	/* clear the pending interrupt of the same kind.*/
+	writel(irq.vfeIrqStatus, ctrl->vfebase + VFE_IRQ_CLEAR);
+
+	return IRQ_HANDLED;
+}
+
+int vfe_cmd_init(struct msm_vfe_callback *presp,
+	struct platform_device *pdev, void *sdata)
+{
+	struct resource	*vfemem, *vfeirq, *vfeio;
+	int rc;
+	struct msm_camera_sensor_info *s_info;
+	s_info = pdev->dev.platform_data;
+
+	pdev->resource = s_info->resource;
+	pdev->num_resources = s_info->num_resources;
+
+	vfemem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!vfemem) {
+		pr_err("%s: no mem resource\n", __func__);
+		return -ENODEV;
+	}
+
+	vfeirq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!vfeirq) {
+		pr_err("%s: no irq resource\n", __func__);
+		return -ENODEV;
+	}
+
+	vfeio = request_mem_region(vfemem->start,
+		resource_size(vfemem), pdev->name);
+	if (!vfeio) {
+		pr_err("%s: VFE region already claimed\n", __func__);
+		return -EBUSY;
+	}
+
+	ctrl = kzalloc(sizeof(struct msm_vfe8x_ctrl), GFP_KERNEL);
+	if (!ctrl) {
+		pr_err("%s: out of memory\n", __func__);
+		rc = -ENOMEM;
+		goto cmd_init_failed1;
+	}
+	atomic_set(&ctrl->vfe_serv_interrupt, 0);
+	ctrl->vfeirq  = vfeirq->start;
+
+	ctrl->vfebase =
+		ioremap(vfemem->start, (vfemem->end - vfemem->start) + 1);
+	if (!ctrl->vfebase) {
+		pr_err("%s: ioremap failed\n", __func__);
+		rc = -ENOMEM;
+		goto cmd_init_failed2;
+	}
+
+	rc = request_irq(ctrl->vfeirq, vfe_parse_irq,
+		IRQF_TRIGGER_RISING, "vfe", 0);
+	if (rc < 0) {
+		pr_err("%s: request_irq(%d) failed\n", __func__, ctrl->vfeirq);
+		goto cmd_init_failed2;
+	}
+
+	if (presp && presp->vfe_resp)
+		ctrl->resp = presp;
+	else {
+		pr_err("%s: no vfe_resp function\n", __func__);
+
+		rc = -EIO;
+		goto cmd_init_failed3;
+	}
+
+	ctrl->syncdata = sdata;
+	return 0;
+
+cmd_init_failed3:
+	disable_irq(ctrl->vfeirq);
+	free_irq(ctrl->vfeirq, 0);
+	iounmap(ctrl->vfebase);
+cmd_init_failed2:
+	kfree(ctrl);
+cmd_init_failed1:
+	release_mem_region(vfemem->start, (vfemem->end - vfemem->start) + 1);
+	return rc;
+}
+
+void vfe_cmd_release(struct platform_device *dev)
+{
+	struct resource	*mem;
+	unsigned long flags;
+	atomic_set(&ctrl->vfe_serv_interrupt, 0);
+	disable_irq(ctrl->vfeirq);
+	free_irq(ctrl->vfeirq, 0);
+
+	iounmap(ctrl->vfebase);
+	mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	release_mem_region(mem->start, (mem->end - mem->start) + 1);
+
+	spin_lock_irqsave(&msm_vfe_ctrl_lock, flags);
+	kfree(ctrl);
+	ctrl = 0;
+	spin_unlock_irqrestore(&msm_vfe_ctrl_lock, flags);
+}
+
+void vfe_stats_af_stop(void)
+{
+	ctrl->vfeStatsCmdLocal.autoFocusEnable = FALSE;
+	ctrl->vfeImaskLocal.afPingpongIrq = FALSE;
+}
+
+void vfe_stop(void)
+{
+	int spin_cnt = 0;
+	uint32_t vfeAxiStauts;
+
+	/* for reset hw modules, and send msg when reset_irq comes.*/
+	ctrl->vfeStopAckPending = TRUE;
+
+	ctrl->vfeStatsPingPongReloadFlag = FALSE;
+	vfe_pm_stop();
+
+	/* disable all interrupts.  */
+	vfe_program_irq_mask(VFE_DISABLE_ALL_IRQS);
+
+	/* in either continuous or snapshot mode, stop command can be issued
+	 * at any time.
+	 */
+	vfe_camif_stop_immediately();
+	vfe_program_axi_cmd(AXI_HALT);
+	vfe_prog_hw_testgen_cmd(VFE_TEST_GEN_STOP);
+
+	do {
+		vfeAxiStauts = vfe_read_axi_status();
+		spin_cnt++;
+	} while (!(vfeAxiStauts & AXI_STATUS_BUSY_MASK));
+	if (spin_cnt > 1)
+		pr_warning("%s: spin_cnt %d\n", __func__, spin_cnt);
+
+	vfe_program_axi_cmd(AXI_HALT_CLEAR);
+
+	/* clear all pending interrupts */
+	writel(VFE_CLEAR_ALL_IRQS, ctrl->vfebase + VFE_IRQ_CLEAR);
+
+	/* enable reset_ack and async timer interrupt only while stopping
+	 * the pipeline.
+	 */
+	vfe_program_irq_mask(VFE_IMASK_WHILE_STOPPING);
+
+	vfe_program_global_reset_cmd(VFE_RESET_UPON_STOP_CMD);
+}
+
+void vfe_update(void)
+{
+	ctrl->vfeModuleEnableLocal.statsEnable =
+		ctrl->vfeStatsCmdLocal.autoFocusEnable |
+		ctrl->vfeStatsCmdLocal.axwEnable;
+
+	vfe_reg_module_cfg(&ctrl->vfeModuleEnableLocal);
+
+	vfe_program_stats_cmd(&ctrl->vfeStatsCmdLocal);
+
+	ctrl->vfeImaskPacked = vfe_irq_pack(ctrl->vfeImaskLocal);
+	vfe_program_irq_mask(ctrl->vfeImaskPacked);
+
+	if ((ctrl->vfeModuleEnableLocal.statsEnable == TRUE) &&
+			(ctrl->vfeStatsPingPongReloadFlag == FALSE)) {
+		ctrl->vfeStatsPingPongReloadFlag = TRUE;
+
+		ctrl->vfeBusCmdLocal.statsPingpongReload = TRUE;
+		vfe_reg_bus_cmd(&ctrl->vfeBusCmdLocal);
+	}
+
+	vfe_program_reg_update_cmd(VFE_REG_UPDATE_TRIGGER);
+}
+
+int vfe_rgb_gamma_update(struct vfe_cmd_rgb_gamma_config *in)
+{
+	int rc = 0;
+
+	ctrl->vfeModuleEnableLocal.rgbLUTEnable = in->enable;
+
+	switch (in->channelSelect) {
+	case RGB_GAMMA_CH0_SELECTED:
+		ctrl->vfeGammaLutSel.ch0BankSelect ^= 1;
+		vfe_write_gamma_table(0,
+				      ctrl->vfeGammaLutSel.ch0BankSelect,
+				      in->table);
+		break;
+
+	case RGB_GAMMA_CH1_SELECTED:
+		ctrl->vfeGammaLutSel.ch1BankSelect ^= 1;
+		vfe_write_gamma_table(1,
+				      ctrl->vfeGammaLutSel.ch1BankSelect,
+				      in->table);
+		break;
+
+	case RGB_GAMMA_CH2_SELECTED:
+		ctrl->vfeGammaLutSel.ch2BankSelect ^= 1;
+		vfe_write_gamma_table(2,
+				      ctrl->vfeGammaLutSel.ch2BankSelect,
+				      in->table);
+		break;
+
+	case RGB_GAMMA_CH0_CH1_SELECTED:
+		ctrl->vfeGammaLutSel.ch0BankSelect ^= 1;
+		ctrl->vfeGammaLutSel.ch1BankSelect ^= 1;
+		vfe_write_gamma_table(0, ctrl->vfeGammaLutSel.ch0BankSelect,
+			in->table);
+		vfe_write_gamma_table(1, ctrl->vfeGammaLutSel.ch1BankSelect,
+			in->table);
+		break;
+
+	case RGB_GAMMA_CH0_CH2_SELECTED:
+		ctrl->vfeGammaLutSel.ch0BankSelect ^= 1;
+		ctrl->vfeGammaLutSel.ch2BankSelect ^= 1;
+		vfe_write_gamma_table(0, ctrl->vfeGammaLutSel.ch0BankSelect,
+			in->table);
+		vfe_write_gamma_table(2, ctrl->vfeGammaLutSel.ch2BankSelect,
+			in->table);
+		break;
+
+	case RGB_GAMMA_CH1_CH2_SELECTED:
+		ctrl->vfeGammaLutSel.ch1BankSelect ^= 1;
+		ctrl->vfeGammaLutSel.ch2BankSelect ^= 1;
+		vfe_write_gamma_table(1, ctrl->vfeGammaLutSel.ch1BankSelect,
+			in->table);
+		vfe_write_gamma_table(2, ctrl->vfeGammaLutSel.ch2BankSelect,
+			in->table);
+		break;
+
+	case RGB_GAMMA_CH0_CH1_CH2_SELECTED:
+		ctrl->vfeGammaLutSel.ch0BankSelect ^= 1;
+		ctrl->vfeGammaLutSel.ch1BankSelect ^= 1;
+		ctrl->vfeGammaLutSel.ch2BankSelect ^= 1;
+		vfe_write_gamma_table(0, ctrl->vfeGammaLutSel.ch0BankSelect,
+			in->table);
+		vfe_write_gamma_table(1, ctrl->vfeGammaLutSel.ch1BankSelect,
+			in->table);
+		vfe_write_gamma_table(2, ctrl->vfeGammaLutSel.ch2BankSelect,
+			in->table);
+		break;
+
+	default:
+		pr_err("%s: invalid gamma channel %d\n", __func__,
+			in->channelSelect);
+		return -EINVAL;
+	} /* switch */
+
+	/* update the gammaLutSel register. */
+	vfe_program_lut_bank_sel(&ctrl->vfeGammaLutSel);
+
+	return rc;
+}
+
+int vfe_rgb_gamma_config(struct vfe_cmd_rgb_gamma_config *in)
+{
+	int rc = 0;
+
+	ctrl->vfeModuleEnableLocal.rgbLUTEnable = in->enable;
+
+	switch (in->channelSelect) {
+	case RGB_GAMMA_CH0_SELECTED:
+vfe_write_gamma_table(0, 0, in->table);
+break;
+
+	case RGB_GAMMA_CH1_SELECTED:
+		vfe_write_gamma_table(1, 0, in->table);
+		break;
+
+	case RGB_GAMMA_CH2_SELECTED:
+		vfe_write_gamma_table(2, 0, in->table);
+		break;
+
+	case RGB_GAMMA_CH0_CH1_SELECTED:
+		vfe_write_gamma_table(0, 0, in->table);
+		vfe_write_gamma_table(1, 0, in->table);
+		break;
+
+	case RGB_GAMMA_CH0_CH2_SELECTED:
+		vfe_write_gamma_table(0, 0, in->table);
+		vfe_write_gamma_table(2, 0, in->table);
+		break;
+
+	case RGB_GAMMA_CH1_CH2_SELECTED:
+		vfe_write_gamma_table(1, 0, in->table);
+		vfe_write_gamma_table(2, 0, in->table);
+		break;
+
+	case RGB_GAMMA_CH0_CH1_CH2_SELECTED:
+		vfe_write_gamma_table(0, 0, in->table);
+		vfe_write_gamma_table(1, 0, in->table);
+		vfe_write_gamma_table(2, 0, in->table);
+		break;
+
+	default:
+		pr_err("%s: invalid gamma channel %d\n", __func__,
+			in->channelSelect);
+		rc = -EINVAL;
+		break;
+	} /* switch */
+
+	return rc;
+}
+
+void vfe_stats_af_ack(struct vfe_cmd_stats_af_ack *in)
+{
+	ctrl->afStatsControl.nextFrameAddrBuf = in->nextAFOutputBufferAddr;
+	ctrl->afStatsControl.ackPending = FALSE;
+}
+
+void vfe_stats_wb_exp_ack(struct vfe_cmd_stats_wb_exp_ack *in)
+{
+	ctrl->awbStatsControl.nextFrameAddrBuf = in->nextWbExpOutputBufferAddr;
+	ctrl->awbStatsControl.ackPending = FALSE;
+}
+
+
+void vfe_output_v_ack(struct vfe_cmd_output_ack *in)
+{
+	const uint32_t *psrc;
+	uint32_t *pdest;
+	uint8_t i;
+
+	pdest = ctrl->encPath.nextFrameAddrBuf;
+
+	CDBG("video_frame_ack: ack addr = 0x%x\n", in->ybufaddr[0]);
+
+	psrc = in->ybufaddr;
+	for (i = 0; i < ctrl->encPath.fragCount; i++)
+		*pdest++ = *psrc++;
+
+	psrc = in->chromabufaddr;
+	for (i = 0; i < ctrl->encPath.fragCount; i++)
+		*pdest++ = *psrc++;
+
+	ctrl->encPath.ackPending = FALSE;
+}
+
+void vfe_output_p_ack(struct vfe_cmd_output_ack *in)
+{
+	const uint32_t *psrc;
+	uint32_t *pdest;
+	uint8_t i;
+
+	if (ctrl->axiOutputMode == VFE_AXI_OUTPUT_MODE_Output1AndOutput2) {
+		/* video mode, preview comes from output1 path */
+
+	pdest = ctrl->viewPath.nextFrameAddrBuf;
+
+	psrc = in->ybufaddr;
+	for (i = 0; i < ctrl->viewPath.fragCount; i++)
+		*pdest++ = *psrc++;
+
+	psrc = in->chromabufaddr;
+	for (i = 0; i < ctrl->viewPath.fragCount; i++)
+		*pdest++ = *psrc++;
+
+	ctrl->viewPath.ackPending = FALSE;
+
+	} else { /* preview mode, preview comes from output2 path. */
+		pdest = ctrl->encPath.nextFrameAddrBuf;
+
+		psrc = in->ybufaddr;
+		for (i = 0; i < ctrl->encPath.fragCount; i++)
+			*pdest++ = *psrc++;
+
+		psrc = in->chromabufaddr;
+		for (i = 0; i < ctrl->encPath.fragCount; i++)
+			*pdest++ = *psrc++;
+
+		ctrl->encPath.ackPending = FALSE;
+
+	}
+}
+
+void vfe_start(struct vfe_cmd_start *in)
+{
+	uint32_t  pmstatus = 0;
+	boolean rawmode;
+	uint32_t  demperiod = 0;
+	uint32_t  demeven = 0;
+	uint32_t  demodd = 0;
+
+	/* derived from other commands.  (camif config, axi output config,
+	 * etc)
+	*/
+	struct vfe_cfg hwcfg;
+	struct vfe_upsample_cfg chromupcfg;
+
+	CDBG("vfe_start operationMode = %d\n", in->operationMode);
+
+	memset(&hwcfg, 0, sizeof(hwcfg));
+	memset(&chromupcfg, 0, sizeof(chromupcfg));
+
+	switch (in->pixel) {
+	case VFE_BAYER_RGRGRG:
+		demperiod = 1;
+		demeven = 0xC9;
+		demodd = 0xAC;
+		break;
+
+	case VFE_BAYER_GRGRGR:
+		demperiod = 1;
+		demeven = 0x9C;
+		demodd = 0xCA;
+		break;
+
+	case VFE_BAYER_BGBGBG:
+		demperiod = 1;
+		demeven = 0xCA;
+		demodd = 0x9C;
+		break;
+
+	case VFE_BAYER_GBGBGB:
+		demperiod = 1;
+		demeven = 0xAC;
+		demodd = 0xC9;
+		break;
+
+	case VFE_YUV_YCbYCr:
+		demperiod = 3;
+		demeven = 0x9CAC;
+		demodd = 0x9CAC;
+		break;
+
+	case VFE_YUV_YCrYCb:
+		demperiod = 3;
+		demeven = 0xAC9C;
+		demodd = 0xAC9C;
+		break;
+
+	case VFE_YUV_CbYCrY:
+		demperiod = 3;
+		demeven = 0xC9CA;
+		demodd = 0xC9CA;
+		break;
+
+	case VFE_YUV_CrYCbY:
+		demperiod = 3;
+		demeven = 0xCAC9;
+		demodd = 0xCAC9;
+		break;
+
+	default:
+		return;
+	}
+
+	vfe_config_demux(demperiod, demeven, demodd);
+
+	vfe_program_lut_bank_sel(&ctrl->vfeGammaLutSel);
+
+	/* save variables to local. */
+	ctrl->vfeOperationMode = in->operationMode;
+	if (ctrl->vfeOperationMode == VFE_START_OPERATION_MODE_SNAPSHOT) {
+
+		update_axi_qos(MSM_AXI_QOS_SNAPSHOT);
+		/* in snapshot mode, initialize snapshot count*/
+		ctrl->vfeSnapShotCount = in->snapshotCount;
+
+		/* save the requested count, this is temporarily done, to
+		help with HJR / multishot. */
+		ctrl->vfeRequestedSnapShotCount = ctrl->vfeSnapShotCount;
+
+		CDBG("requested snapshot count = %d\n", ctrl->vfeSnapShotCount);
+
+		/* Assumption is to have the same pattern and period for both
+		paths, if both paths are used. */
+		if (ctrl->viewPath.pathEnabled) {
+			ctrl->viewPath.snapshotPendingCount = in->snapshotCount;
+
+			ctrl->vfeFrameSkipPattern =
+				ctrl->vfeFrameSkip.output1Pattern;
+			ctrl->vfeFrameSkipPeriod =
+				ctrl->vfeFrameSkip.output1Period;
+		}
+
+		if (ctrl->encPath.pathEnabled) {
+			ctrl->encPath.snapshotPendingCount = in->snapshotCount;
+
+			ctrl->vfeFrameSkipPattern =
+				ctrl->vfeFrameSkip.output2Pattern;
+			ctrl->vfeFrameSkipPeriod =
+				ctrl->vfeFrameSkip.output2Period;
+		}
+	} else
+		update_axi_qos(MSM_AXI_QOS_PREVIEW);
+
+	/* enable color conversion for bayer sensor
+	if stats enabled, need to do color conversion. */
+	if (in->pixel <= VFE_BAYER_GBGBGB)
+		ctrl->vfeStatsCmdLocal.colorConversionEnable = TRUE;
+
+	vfe_program_stats_cmd(&ctrl->vfeStatsCmdLocal);
+
+	if (in->pixel >= VFE_YUV_YCbYCr)
+		ctrl->vfeModuleEnableLocal.chromaUpsampleEnable = TRUE;
+
+	ctrl->vfeModuleEnableLocal.demuxEnable = TRUE;
+
+	/* if any stats module is enabled, the main bit is enabled. */
+	ctrl->vfeModuleEnableLocal.statsEnable =
+		ctrl->vfeStatsCmdLocal.autoFocusEnable |
+		ctrl->vfeStatsCmdLocal.axwEnable;
+
+	vfe_reg_module_cfg(&ctrl->vfeModuleEnableLocal);
+
+	/* in case of offline processing, do not need to config camif. Having
+	 * bus output enabled in camif_config register might confuse the
+	 * hardware?
+	 */
+	if (in->inputSource != VFE_START_INPUT_SOURCE_AXI) {
+		vfe_reg_camif_config(&ctrl->vfeCamifConfigLocal);
+	} else {
+		/* offline processing, enable axi read */
+		ctrl->vfeBusConfigLocal.stripeRdPathEn = TRUE;
+		ctrl->vfeBusCmdLocal.stripeReload = TRUE;
+		ctrl->vfeBusConfigLocal.rawPixelDataSize =
+			ctrl->axiInputDataSize;
+	}
+
+	vfe_reg_bus_cfg(&ctrl->vfeBusConfigLocal);
+
+	/* directly from start command */
+	hwcfg.pixelPattern = in->pixel;
+	hwcfg.inputSource = in->inputSource;
+	writel(*(uint32_t *)&hwcfg, ctrl->vfebase + VFE_CFG);
+
+	/* regardless module enabled or not, it does not hurt
+	 * to program the cositing mode. */
+	chromupcfg.chromaCositingForYCbCrInputs = in->yuvInputCositingMode;
+
+	writel(*(uint32_t *)&chromupcfg,
+		ctrl->vfebase + VFE_CHROMA_UPSAMPLE_CFG);
+
+	/* MISR to monitor the axi read. */
+	writel(0xd8, ctrl->vfebase + VFE_BUS_MISR_MAST_CFG_0);
+
+	/* clear all pending interrupts. */
+	writel(VFE_CLEAR_ALL_IRQS, ctrl->vfebase + VFE_IRQ_CLEAR);
+
+	/*  define how composite interrupt work.  */
+	ctrl->vfeImaskCompositePacked =
+		vfe_irq_composite_pack(ctrl->vfeIrqCompositeMaskLocal);
+
+	vfe_program_irq_composite_mask(ctrl->vfeImaskCompositePacked);
+
+	/*  enable all necessary interrupts.      */
+	ctrl->vfeImaskLocal.camifSofIrq  = TRUE;
+	ctrl->vfeImaskLocal.regUpdateIrq = TRUE;
+	ctrl->vfeImaskLocal.resetAckIrq  = TRUE;
+
+	ctrl->vfeImaskPacked = vfe_irq_pack(ctrl->vfeImaskLocal);
+	vfe_program_irq_mask(ctrl->vfeImaskPacked);
+
+	/* enable bus performance monitor */
+	vfe_8k_pm_start(&ctrl->vfeBusPmConfigLocal);
+
+	/* trigger vfe reg update */
+	ctrl->vfeStartAckPendingFlag = TRUE;
+
+	/* write bus command to trigger reload of ping pong buffer. */
+	ctrl->vfeBusCmdLocal.busPingpongReload = TRUE;
+
+	if (ctrl->vfeModuleEnableLocal.statsEnable == TRUE) {
+		ctrl->vfeBusCmdLocal.statsPingpongReload = TRUE;
+		ctrl->vfeStatsPingPongReloadFlag = TRUE;
+	}
+
+	writel(VFE_REG_UPDATE_TRIGGER, ctrl->vfebase + VFE_REG_UPDATE_CMD);
+
+	/* program later than the reg update. */
+	vfe_reg_bus_cmd(&ctrl->vfeBusCmdLocal);
+
+	if ((in->inputSource ==
+			 VFE_START_INPUT_SOURCE_CAMIF) ||
+	    (in->inputSource == VFE_START_INPUT_SOURCE_TESTGEN))
+		writel(CAMIF_COMMAND_START, ctrl->vfebase + CAMIF_COMMAND);
+
+	/* start test gen if it is enabled */
+	if (ctrl->vfeTestGenStartFlag == TRUE) {
+		ctrl->vfeTestGenStartFlag = FALSE;
+		vfe_prog_hw_testgen_cmd(VFE_TEST_GEN_GO);
+	}
+
+	CDBG("ctrl->axiOutputMode = %d\n", ctrl->axiOutputMode);
+	if (ctrl->axiOutputMode == VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2) {
+		/* raw dump mode */
+		rawmode = TRUE;
+
+		while (rawmode) {
+			pmstatus =
+				readl(ctrl->vfebase +
+					VFE_BUS_ENC_CBCR_WR_PM_STATS_1);
+
+			if ((pmstatus & VFE_PM_BUF_MAX_CNT_MASK) != 0)
+				rawmode = FALSE;
+		}
+
+		vfe_proc_ops(VFE_MSG_ID_START_ACK, NULL);
+		ctrl->vfeStartAckPendingFlag = FALSE;
+	}
+
+	ctrl->vstate = VFE_STATE_ACTIVE;
+}
+
+void vfe_la_update(struct vfe_cmd_la_config *in)
+{
+	int16_t *pTable;
+	enum VFE_DMI_RAM_SEL dmiRamSel;
+	int i;
+
+	pTable = in->table;
+	ctrl->vfeModuleEnableLocal.lumaAdaptationEnable = in->enable;
+
+	/* toggle the bank to be used. */
+	ctrl->vfeLaBankSel ^= 1;
+
+	if (ctrl->vfeLaBankSel == 0)
+		dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK0;
+	else
+		dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK1;
+
+	/* configure the DMI_CFG to select right sram */
+	vfe_program_dmi_cfg(dmiRamSel);
+
+	for (i = 0; i < VFE_LA_TABLE_LENGTH; i++) {
+		writel((uint32_t)(*pTable), ctrl->vfebase + VFE_DMI_DATA_LO);
+		pTable++;
+	}
+
+	/* After DMI transfer, to make it safe, need to set
+	 * the DMI_CFG to unselect any SRAM */
+	writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG);
+	writel(ctrl->vfeLaBankSel, ctrl->vfebase + VFE_LA_CFG);
+}
+
+void vfe_la_config(struct vfe_cmd_la_config *in)
+{
+	uint16_t i;
+	int16_t  *pTable;
+	enum VFE_DMI_RAM_SEL dmiRamSel;
+
+	pTable = in->table;
+	ctrl->vfeModuleEnableLocal.lumaAdaptationEnable = in->enable;
+
+	if (ctrl->vfeLaBankSel == 0)
+		dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK0;
+	else
+		dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK1;
+
+	/* configure the DMI_CFG to select right sram */
+	vfe_program_dmi_cfg(dmiRamSel);
+
+	for (i = 0; i < VFE_LA_TABLE_LENGTH; i++) {
+		writel((uint32_t)(*pTable), ctrl->vfebase + VFE_DMI_DATA_LO);
+		pTable++;
+	}
+
+	/* After DMI transfer, to make it safe, need to set the
+	 * DMI_CFG to unselect any SRAM */
+	writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG);
+
+	/* can only be bank 0 or bank 1 for now. */
+	writel(ctrl->vfeLaBankSel, ctrl->vfebase + VFE_LA_CFG);
+	CDBG("VFE Luma adaptation bank selection is 0x%x\n",
+			 *(uint32_t *)&ctrl->vfeLaBankSel);
+}
+
+void vfe_test_gen_start(struct vfe_cmd_test_gen_start *in)
+{
+	struct VFE_TestGen_ConfigCmdType cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.numFrame              = in->numFrame;
+	cmd.pixelDataSelect       = in->pixelDataSelect;
+	cmd.systematicDataSelect  = in->systematicDataSelect;
+	cmd.pixelDataSize         = (uint32_t)in->pixelDataSize;
+	cmd.hsyncEdge             = (uint32_t)in->hsyncEdge;
+	cmd.vsyncEdge             = (uint32_t)in->vsyncEdge;
+	cmd.imageWidth            = in->imageWidth;
+	cmd.imageHeight           = in->imageHeight;
+	cmd.sofOffset             = in->startOfFrameOffset;
+	cmd.eofNOffset            = in->endOfFrameNOffset;
+	cmd.solOffset             = in->startOfLineOffset;
+	cmd.eolNOffset            = in->endOfLineNOffset;
+	cmd.hBlankInterval        = in->hbi;
+	cmd.vBlankInterval        = in->vbl;
+	cmd.vBlankIntervalEnable  = in->vblEnable;
+	cmd.sofDummy              = in->startOfFrameDummyLine;
+	cmd.eofDummy              = in->endOfFrameDummyLine;
+	cmd.unicolorBarSelect     = in->unicolorBarSelect;
+	cmd.unicolorBarEnable     = in->unicolorBarEnable;
+	cmd.splitEnable           = in->colorBarsSplitEnable;
+	cmd.pixelPattern          = (uint32_t)in->colorBarsPixelPattern;
+	cmd.rotatePeriod          = in->colorBarsRotatePeriod;
+	cmd.randomSeed            = in->testGenRandomSeed;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_HW_TESTGEN_CFG,
+		(uint32_t *) &cmd, sizeof(cmd));
+}
+
+void vfe_frame_skip_update(struct vfe_cmd_frame_skip_update *in)
+{
+	struct VFE_FRAME_SKIP_UpdateCmdType cmd;
+
+	cmd.yPattern    = in->output1Pattern;
+	cmd.cbcrPattern = in->output1Pattern;
+	vfe_prog_hw(ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN,
+		(uint32_t *)&cmd, sizeof(cmd));
+
+	cmd.yPattern    = in->output2Pattern;
+	cmd.cbcrPattern = in->output2Pattern;
+	vfe_prog_hw(ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN,
+		(uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_frame_skip_config(struct vfe_cmd_frame_skip_config *in)
+{
+	struct vfe_frame_skip_cfg cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	ctrl->vfeFrameSkip = *in;
+
+	cmd.output2YPeriod     = in->output2Period;
+	cmd.output2CbCrPeriod  = in->output2Period;
+	cmd.output2YPattern    = in->output2Pattern;
+	cmd.output2CbCrPattern = in->output2Pattern;
+	cmd.output1YPeriod     = in->output1Period;
+	cmd.output1CbCrPeriod  = in->output1Period;
+	cmd.output1YPattern    = in->output1Pattern;
+	cmd.output1CbCrPattern = in->output1Pattern;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG,
+		(uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_output_clamp_config(struct vfe_cmd_output_clamp_config *in)
+{
+	struct vfe_output_clamp_cfg cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.yChanMax  = in->maxCh0;
+	cmd.cbChanMax = in->maxCh1;
+	cmd.crChanMax = in->maxCh2;
+
+	cmd.yChanMin  = in->minCh0;
+	cmd.cbChanMin = in->minCh1;
+	cmd.crChanMin = in->minCh2;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_CLAMP_MAX_CFG, (uint32_t *)&cmd,
+		sizeof(cmd));
+}
+
+void vfe_camif_frame_update(struct vfe_cmds_camif_frame *in)
+{
+	struct vfe_camifframe_update cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.pixelsPerLine = in->pixelsPerLine;
+	cmd.linesPerFrame = in->linesPerFrame;
+
+	vfe_prog_hw(ctrl->vfebase + CAMIF_FRAME_CONFIG, (uint32_t *)&cmd,
+		sizeof(cmd));
+}
+
+void vfe_color_correction_config(struct vfe_cmd_color_correction_config *in)
+{
+	struct vfe_color_correction_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	ctrl->vfeModuleEnableLocal.colorCorrectionEnable = in->enable;
+
+	cmd.c0 = in->C0;
+	cmd.c1 = in->C1;
+	cmd.c2 = in->C2;
+	cmd.c3 = in->C3;
+	cmd.c4 = in->C4;
+	cmd.c5 = in->C5;
+	cmd.c6 = in->C6;
+	cmd.c7 = in->C7;
+	cmd.c8 = in->C8;
+
+	cmd.k0 = in->K0;
+	cmd.k1 = in->K1;
+	cmd.k2 = in->K2;
+
+	cmd.coefQFactor = in->coefQFactor;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_COLOR_CORRECT_COEFF_0,
+		(uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_demosaic_abf_update(struct vfe_cmd_demosaic_abf_update *in)
+{
+struct vfe_demosaic_cfg cmd;
+	struct vfe_demosaic_abf_cfg cmdabf;
+	uint32_t temp;
+
+	memset(&cmd, 0, sizeof(cmd));
+	temp = readl(ctrl->vfebase + VFE_DEMOSAIC_CFG);
+
+	cmd = *((struct vfe_demosaic_cfg *)(&temp));
+	cmd.abfEnable       = in->abfUpdate.enable;
+	cmd.forceAbfOn      = in->abfUpdate.forceOn;
+	cmd.abfShift        = in->abfUpdate.shift;
+	vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_CFG,
+		(uint32_t *)&cmd, sizeof(cmd));
+
+	cmdabf.lpThreshold  = in->abfUpdate.lpThreshold;
+	cmdabf.ratio        = in->abfUpdate.ratio;
+	cmdabf.minValue     = in->abfUpdate.min;
+	cmdabf.maxValue     = in->abfUpdate.max;
+	vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_ABF_CFG_0,
+		(uint32_t *)&cmdabf, sizeof(cmdabf));
+}
+
+void vfe_demosaic_bpc_update(struct vfe_cmd_demosaic_bpc_update *in)
+{
+	struct vfe_demosaic_cfg cmd;
+	struct vfe_demosaic_bpc_cfg cmdbpc;
+	uint32_t temp;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	temp = readl(ctrl->vfebase + VFE_DEMOSAIC_CFG);
+
+	cmd = *((struct vfe_demosaic_cfg *)(&temp));
+	cmd.badPixelCorrEnable = in->bpcUpdate.enable;
+	cmd.fminThreshold      = in->bpcUpdate.fminThreshold;
+	cmd.fmaxThreshold      = in->bpcUpdate.fmaxThreshold;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_CFG,
+		(uint32_t *)&cmd, sizeof(cmd));
+
+	cmdbpc.blueDiffThreshold  = in->bpcUpdate.blueDiffThreshold;
+	cmdbpc.redDiffThreshold   = in->bpcUpdate.redDiffThreshold;
+	cmdbpc.greenDiffThreshold = in->bpcUpdate.greenDiffThreshold;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_BPC_CFG_0,
+		(uint32_t *)&cmdbpc, sizeof(cmdbpc));
+}
+
+void vfe_demosaic_config(struct vfe_cmd_demosaic_config *in)
+{
+	struct vfe_demosaic_cfg cmd;
+	struct vfe_demosaic_bpc_cfg cmd_bpc;
+	struct vfe_demosaic_abf_cfg cmd_abf;
+
+	memset(&cmd, 0, sizeof(cmd));
+	memset(&cmd_bpc, 0, sizeof(cmd_bpc));
+	memset(&cmd_abf, 0, sizeof(cmd_abf));
+
+	ctrl->vfeModuleEnableLocal.demosaicEnable = in->enable;
+
+	cmd.abfEnable          = in->abfConfig.enable;
+	cmd.badPixelCorrEnable = in->bpcConfig.enable;
+	cmd.forceAbfOn         = in->abfConfig.forceOn;
+	cmd.abfShift           = in->abfConfig.shift;
+	cmd.fminThreshold      = in->bpcConfig.fminThreshold;
+	cmd.fmaxThreshold      = in->bpcConfig.fmaxThreshold;
+	cmd.slopeShift         = in->slopeShift;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_CFG,
+		(uint32_t *)&cmd, sizeof(cmd));
+
+	cmd_abf.lpThreshold = in->abfConfig.lpThreshold;
+	cmd_abf.ratio       = in->abfConfig.ratio;
+	cmd_abf.minValue    = in->abfConfig.min;
+	cmd_abf.maxValue    = in->abfConfig.max;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_ABF_CFG_0,
+		(uint32_t *)&cmd_abf, sizeof(cmd_abf));
+
+	cmd_bpc.blueDiffThreshold   = in->bpcConfig.blueDiffThreshold;
+	cmd_bpc.redDiffThreshold    = in->bpcConfig.redDiffThreshold;
+	cmd_bpc.greenDiffThreshold  = in->bpcConfig.greenDiffThreshold;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_BPC_CFG_0,
+		(uint32_t *)&cmd_bpc, sizeof(cmd_bpc));
+}
+
+void vfe_demux_channel_gain_update(struct vfe_cmd_demux_channel_gain_config *in)
+{
+	struct vfe_demux_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.ch0EvenGain  = in->ch0EvenGain;
+	cmd.ch0OddGain   = in->ch0OddGain;
+	cmd.ch1Gain      = in->ch1Gain;
+	cmd.ch2Gain      = in->ch2Gain;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_DEMUX_GAIN_0,
+		(uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_demux_channel_gain_config(struct vfe_cmd_demux_channel_gain_config *in)
+{
+	struct vfe_demux_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.ch0EvenGain = in->ch0EvenGain;
+	cmd.ch0OddGain  = in->ch0OddGain;
+	cmd.ch1Gain     = in->ch1Gain;
+	cmd.ch2Gain     = in->ch2Gain;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_DEMUX_GAIN_0,
+		(uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_black_level_update(struct vfe_cmd_black_level_config *in)
+{
+	struct vfe_blacklevel_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	ctrl->vfeModuleEnableLocal.blackLevelCorrectionEnable = in->enable;
+
+	cmd.evenEvenAdjustment = in->evenEvenAdjustment;
+	cmd.evenOddAdjustment  = in->evenOddAdjustment;
+	cmd.oddEvenAdjustment  = in->oddEvenAdjustment;
+	cmd.oddOddAdjustment   = in->oddOddAdjustment;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_BLACK_EVEN_EVEN_VALUE,
+		(uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_black_level_config(struct vfe_cmd_black_level_config *in)
+{
+	struct vfe_blacklevel_cfg cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	ctrl->vfeModuleEnableLocal.blackLevelCorrectionEnable = in->enable;
+
+	cmd.evenEvenAdjustment = in->evenEvenAdjustment;
+	cmd.evenOddAdjustment  = in->evenOddAdjustment;
+	cmd.oddEvenAdjustment  = in->oddEvenAdjustment;
+	cmd.oddOddAdjustment   = in->oddOddAdjustment;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_BLACK_EVEN_EVEN_VALUE,
+		(uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_asf_update(struct vfe_cmd_asf_update *in)
+{
+	struct vfe_asf_update cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	ctrl->vfeModuleEnableLocal.asfEnable = in->enable;
+
+	cmd.smoothEnable     = in->smoothFilterEnabled;
+	cmd.sharpMode        = in->sharpMode;
+	cmd.smoothCoeff0     = in->smoothCoefCenter;
+	cmd.smoothCoeff1     = in->smoothCoefSurr;
+	cmd.cropEnable       = in->cropEnable;
+	cmd.sharpThresholdE1 = in->sharpThreshE1;
+	cmd.sharpDegreeK1    = in->sharpK1;
+	cmd.sharpDegreeK2    = in->sharpK2;
+	cmd.normalizeFactor  = in->normalizeFactor;
+	cmd.sharpThresholdE2 = in->sharpThreshE2;
+	cmd.sharpThresholdE3 = in->sharpThreshE3;
+	cmd.sharpThresholdE4 = in->sharpThreshE4;
+	cmd.sharpThresholdE5 = in->sharpThreshE5;
+	cmd.F1Coeff0         = in->filter1Coefficients[0];
+	cmd.F1Coeff1         = in->filter1Coefficients[1];
+	cmd.F1Coeff2         = in->filter1Coefficients[2];
+	cmd.F1Coeff3         = in->filter1Coefficients[3];
+	cmd.F1Coeff4         = in->filter1Coefficients[4];
+	cmd.F1Coeff5         = in->filter1Coefficients[5];
+	cmd.F1Coeff6         = in->filter1Coefficients[6];
+	cmd.F1Coeff7         = in->filter1Coefficients[7];
+	cmd.F1Coeff8         = in->filter1Coefficients[8];
+	cmd.F2Coeff0         = in->filter2Coefficients[0];
+	cmd.F2Coeff1         = in->filter2Coefficients[1];
+	cmd.F2Coeff2         = in->filter2Coefficients[2];
+	cmd.F2Coeff3         = in->filter2Coefficients[3];
+	cmd.F2Coeff4         = in->filter2Coefficients[4];
+	cmd.F2Coeff5         = in->filter2Coefficients[5];
+	cmd.F2Coeff6         = in->filter2Coefficients[6];
+	cmd.F2Coeff7         = in->filter2Coefficients[7];
+	cmd.F2Coeff8         = in->filter2Coefficients[8];
+
+	vfe_prog_hw(ctrl->vfebase + VFE_ASF_CFG,
+		(uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_asf_config(struct vfe_cmd_asf_config *in)
+{
+	struct vfe_asf_update     cmd;
+	struct vfe_asfcrop_cfg cmd2;
+
+	memset(&cmd, 0, sizeof(cmd));
+	memset(&cmd2, 0, sizeof(cmd2));
+
+	ctrl->vfeModuleEnableLocal.asfEnable = in->enable;
+
+	cmd.smoothEnable       = in->smoothFilterEnabled;
+	cmd.sharpMode          = in->sharpMode;
+	cmd.smoothCoeff0       = in->smoothCoefCenter;
+	cmd.smoothCoeff1       = in->smoothCoefSurr;
+	cmd.cropEnable         = in->cropEnable;
+	cmd.sharpThresholdE1   = in->sharpThreshE1;
+	cmd.sharpDegreeK1      = in->sharpK1;
+	cmd.sharpDegreeK2      = in->sharpK2;
+	cmd.normalizeFactor    = in->normalizeFactor;
+	cmd.sharpThresholdE2   = in->sharpThreshE2;
+	cmd.sharpThresholdE3   = in->sharpThreshE3;
+	cmd.sharpThresholdE4   = in->sharpThreshE4;
+	cmd.sharpThresholdE5   = in->sharpThreshE5;
+	cmd.F1Coeff0           = in->filter1Coefficients[0];
+	cmd.F1Coeff1           = in->filter1Coefficients[1];
+	cmd.F1Coeff2           = in->filter1Coefficients[2];
+	cmd.F1Coeff3           = in->filter1Coefficients[3];
+	cmd.F1Coeff4           = in->filter1Coefficients[4];
+	cmd.F1Coeff5           = in->filter1Coefficients[5];
+	cmd.F1Coeff6           = in->filter1Coefficients[6];
+	cmd.F1Coeff7           = in->filter1Coefficients[7];
+	cmd.F1Coeff8           = in->filter1Coefficients[8];
+	cmd.F2Coeff0           = in->filter2Coefficients[0];
+	cmd.F2Coeff1           = in->filter2Coefficients[1];
+	cmd.F2Coeff2           = in->filter2Coefficients[2];
+	cmd.F2Coeff3           = in->filter2Coefficients[3];
+	cmd.F2Coeff4           = in->filter2Coefficients[4];
+	cmd.F2Coeff5           = in->filter2Coefficients[5];
+	cmd.F2Coeff6           = in->filter2Coefficients[6];
+	cmd.F2Coeff7           = in->filter2Coefficients[7];
+	cmd.F2Coeff8           = in->filter2Coefficients[8];
+
+	vfe_prog_hw(ctrl->vfebase + VFE_ASF_CFG,
+		(uint32_t *)&cmd, sizeof(cmd));
+
+	cmd2.firstLine  = in->cropFirstLine;
+	cmd2.lastLine   = in->cropLastLine;
+	cmd2.firstPixel = in->cropFirstPixel;
+	cmd2.lastPixel  = in->cropLastPixel;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_ASF_CROP_WIDTH_CFG,
+		(uint32_t *)&cmd2, sizeof(cmd2));
+}
+
+void vfe_white_balance_config(struct vfe_cmd_white_balance_config *in)
+{
+	struct vfe_wb_cfg cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	ctrl->vfeModuleEnableLocal.whiteBalanceEnable = in->enable;
+
+	cmd.ch0Gain = in->ch0Gain;
+	cmd.ch1Gain = in->ch1Gain;
+	cmd.ch2Gain = in->ch2Gain;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_WB_CFG,
+		(uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_chroma_sup_config(struct vfe_cmd_chroma_suppression_config *in)
+{
+	struct vfe_chroma_suppress_cfg cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	ctrl->vfeModuleEnableLocal.chromaSuppressionEnable = in->enable;
+
+	cmd.m1  = in->m1;
+	cmd.m3  = in->m3;
+	cmd.n1  = in->n1;
+	cmd.n3  = in->n3;
+	cmd.mm1 = in->mm1;
+	cmd.nn1 = in->nn1;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_CHROMA_SUPPRESS_CFG_0,
+		(uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_roll_off_config(struct vfe_cmd_roll_off_config *in)
+{
+	struct vfe_rolloff_cfg cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	ctrl->vfeModuleEnableLocal.lensRollOffEnable = in->enable;
+
+	cmd.gridWidth   = in->gridWidth;
+	cmd.gridHeight  = in->gridHeight;
+	cmd.yDelta      = in->yDelta;
+	cmd.gridX       = in->gridXIndex;
+	cmd.gridY       = in->gridYIndex;
+	cmd.pixelX      = in->gridPixelXIndex;
+	cmd.pixelY      = in->gridPixelYIndex;
+	cmd.yDeltaAccum = in->yDeltaAccum;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_ROLLOFF_CFG_0,
+		(uint32_t *)&cmd, sizeof(cmd));
+
+	vfe_write_lens_roll_off_table(in);
+}
+
+void vfe_chroma_subsample_config(struct vfe_cmd_chroma_subsample_config *in)
+{
+	struct vfe_chromasubsample_cfg cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	ctrl->vfeModuleEnableLocal.chromaSubsampleEnable = in->enable;
+
+	cmd.hCositedPhase       = in->hCositedPhase;
+	cmd.vCositedPhase       = in->vCositedPhase;
+	cmd.hCosited            = in->hCosited;
+	cmd.vCosited            = in->vCosited;
+	cmd.hsubSampleEnable    = in->hsubSampleEnable;
+	cmd.vsubSampleEnable    = in->vsubSampleEnable;
+	cmd.cropEnable          = in->cropEnable;
+	cmd.cropWidthLastPixel  = in->cropWidthLastPixel;
+	cmd.cropWidthFirstPixel = in->cropWidthFirstPixel;
+	cmd.cropHeightLastLine  = in->cropHeightLastLine;
+	cmd.cropHeightFirstLine = in->cropHeightFirstLine;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_CHROMA_SUBSAMPLE_CFG,
+		(uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_chroma_enhan_config(struct vfe_cmd_chroma_enhan_config *in)
+{
+	struct vfe_chroma_enhance_cfg cmd;
+	struct vfe_color_convert_cfg cmd2;
+
+	memset(&cmd, 0, sizeof(cmd));
+	memset(&cmd2, 0, sizeof(cmd2));
+
+	ctrl->vfeModuleEnableLocal.chromaEnhanEnable = in->enable;
+
+	cmd.ap             = in->ap;
+	cmd.am             = in->am;
+	cmd.bp             = in->bp;
+	cmd.bm             = in->bm;
+	cmd.cp             = in->cp;
+	cmd.cm             = in->cm;
+	cmd.dp             = in->dp;
+	cmd.dm             = in->dm;
+	cmd.kcb            = in->kcb;
+	cmd.kcr            = in->kcr;
+
+	cmd2.v0            = in->RGBtoYConversionV0;
+	cmd2.v1            = in->RGBtoYConversionV1;
+	cmd2.v2            = in->RGBtoYConversionV2;
+	cmd2.ConvertOffset = in->RGBtoYConversionOffset;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_CHROMA_ENHAN_A,
+		(uint32_t *)&cmd, sizeof(cmd));
+
+	vfe_prog_hw(ctrl->vfebase + VFE_COLOR_CONVERT_COEFF_0,
+		(uint32_t *)&cmd2, sizeof(cmd2));
+}
+
+void vfe_scaler2cbcr_config(struct vfe_cmd_scaler2_config *in)
+{
+	struct vfe_scaler2_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	ctrl->vfeModuleEnableLocal.scaler2CbcrEnable = in->enable;
+
+	cmd.hEnable              = in->hconfig.enable;
+	cmd.vEnable              = in->vconfig.enable;
+	cmd.inWidth              = in->hconfig.inputSize;
+	cmd.outWidth             = in->hconfig.outputSize;
+	cmd.horizPhaseMult       = in->hconfig.phaseMultiplicationFactor;
+	cmd.horizInterResolution = in->hconfig.interpolationResolution;
+	cmd.inHeight             = in->vconfig.inputSize;
+	cmd.outHeight            = in->vconfig.outputSize;
+	cmd.vertPhaseMult        = in->vconfig.phaseMultiplicationFactor;
+	cmd.vertInterResolution  = in->vconfig.interpolationResolution;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_SCALE_CBCR_CFG,
+		(uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_scaler2y_config(struct vfe_cmd_scaler2_config *in)
+{
+	struct vfe_scaler2_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	ctrl->vfeModuleEnableLocal.scaler2YEnable = in->enable;
+
+	cmd.hEnable               = in->hconfig.enable;
+	cmd.vEnable               = in->vconfig.enable;
+	cmd.inWidth               = in->hconfig.inputSize;
+	cmd.outWidth              = in->hconfig.outputSize;
+	cmd.horizPhaseMult        = in->hconfig.phaseMultiplicationFactor;
+	cmd.horizInterResolution  = in->hconfig.interpolationResolution;
+	cmd.inHeight              = in->vconfig.inputSize;
+	cmd.outHeight             = in->vconfig.outputSize;
+	cmd.vertPhaseMult         = in->vconfig.phaseMultiplicationFactor;
+	cmd.vertInterResolution   = in->vconfig.interpolationResolution;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_SCALE_Y_CFG,
+		(uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_main_scaler_config(struct vfe_cmd_main_scaler_config *in)
+{
+	struct vfe_main_scaler_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	ctrl->vfeModuleEnableLocal.mainScalerEnable = in->enable;
+
+	cmd.hEnable              = in->hconfig.enable;
+	cmd.vEnable              = in->vconfig.enable;
+	cmd.inWidth              = in->hconfig.inputSize;
+	cmd.outWidth             = in->hconfig.outputSize;
+	cmd.horizPhaseMult       = in->hconfig.phaseMultiplicationFactor;
+	cmd.horizInterResolution = in->hconfig.interpolationResolution;
+	cmd.horizMNInit          = in->MNInitH.MNCounterInit;
+	cmd.horizPhaseInit       = in->MNInitH.phaseInit;
+	cmd.inHeight             = in->vconfig.inputSize;
+	cmd.outHeight            = in->vconfig.outputSize;
+	cmd.vertPhaseMult        = in->vconfig.phaseMultiplicationFactor;
+	cmd.vertInterResolution  = in->vconfig.interpolationResolution;
+	cmd.vertMNInit           = in->MNInitV.MNCounterInit;
+	cmd.vertPhaseInit        = in->MNInitV.phaseInit;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_SCALE_CFG,
+		(uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_stats_wb_exp_stop(void)
+{
+	ctrl->vfeStatsCmdLocal.axwEnable = FALSE;
+	ctrl->vfeImaskLocal.awbPingpongIrq = FALSE;
+}
+
+void vfe_stats_update_wb_exp(struct vfe_cmd_stats_wb_exp_update *in)
+{
+	struct vfe_statsawb_update   cmd;
+	struct vfe_statsawbae_update cmd2;
+
+	memset(&cmd, 0, sizeof(cmd));
+	memset(&cmd2, 0, sizeof(cmd2));
+
+	cmd.m1  = in->awbMCFG[0];
+	cmd.m2  = in->awbMCFG[1];
+	cmd.m3  = in->awbMCFG[2];
+	cmd.m4  = in->awbMCFG[3];
+	cmd.c1  = in->awbCCFG[0];
+	cmd.c2  = in->awbCCFG[1];
+	cmd.c3  = in->awbCCFG[2];
+	cmd.c4  = in->awbCCFG[3];
+	vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWB_MCFG,
+		(uint32_t *)&cmd, sizeof(cmd));
+
+	cmd2.aeRegionCfg    = in->wbExpRegions;
+	cmd2.aeSubregionCfg = in->wbExpSubRegion;
+	cmd2.awbYMin        = in->awbYMin;
+	cmd2.awbYMax        = in->awbYMax;
+	vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWBAE_CFG,
+		(uint32_t *)&cmd2, sizeof(cmd2));
+}
+
+void vfe_stats_update_af(struct vfe_cmd_stats_af_update *in)
+{
+	struct vfe_statsaf_update cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.windowVOffset = in->windowVOffset;
+	cmd.windowHOffset = in->windowHOffset;
+	cmd.windowMode    = in->windowMode;
+	cmd.windowHeight  = in->windowHeight;
+	cmd.windowWidth   = in->windowWidth;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_STATS_AF_CFG,
+		(uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_stats_start_wb_exp(struct vfe_cmd_stats_wb_exp_start *in)
+{
+	struct vfe_statsawb_update   cmd;
+	struct vfe_statsawbae_update cmd2;
+	struct vfe_statsaxw_hdr_cfg  cmd3;
+
+	ctrl->vfeStatsCmdLocal.axwEnable   =  in->enable;
+	ctrl->vfeImaskLocal.awbPingpongIrq = TRUE;
+
+	memset(&cmd, 0, sizeof(cmd));
+	memset(&cmd2, 0, sizeof(cmd2));
+	memset(&cmd3, 0, sizeof(cmd3));
+
+	cmd.m1  = in->awbMCFG[0];
+	cmd.m2  = in->awbMCFG[1];
+	cmd.m3  = in->awbMCFG[2];
+	cmd.m4  = in->awbMCFG[3];
+	cmd.c1  = in->awbCCFG[0];
+	cmd.c2  = in->awbCCFG[1];
+	cmd.c3  = in->awbCCFG[2];
+	cmd.c4  = in->awbCCFG[3];
+	vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWB_MCFG,
+		(uint32_t *)&cmd, sizeof(cmd));
+
+	cmd2.aeRegionCfg     = in->wbExpRegions;
+	cmd2.aeSubregionCfg  = in->wbExpSubRegion;
+	cmd2.awbYMin         = in->awbYMin;
+	cmd2.awbYMax         = in->awbYMax;
+	vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWBAE_CFG,
+		(uint32_t *)&cmd2, sizeof(cmd2));
+
+	cmd3.axwHeader       = in->axwHeader;
+	vfe_prog_hw(ctrl->vfebase + VFE_STATS_AXW_HEADER,
+		(uint32_t *)&cmd3, sizeof(cmd3));
+}
+
+void vfe_stats_start_af(struct vfe_cmd_stats_af_start *in)
+{
+	struct vfe_statsaf_update cmd;
+	struct vfe_statsaf_cfg    cmd2;
+
+	memset(&cmd, 0, sizeof(cmd));
+	memset(&cmd2, 0, sizeof(cmd2));
+
+	ctrl->vfeStatsCmdLocal.autoFocusEnable = in->enable;
+	ctrl->vfeImaskLocal.afPingpongIrq = TRUE;
+
+	cmd.windowVOffset = in->windowVOffset;
+	cmd.windowHOffset = in->windowHOffset;
+	cmd.windowMode    = in->windowMode;
+	cmd.windowHeight  = in->windowHeight;
+	cmd.windowWidth   = in->windowWidth;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_STATS_AF_CFG,
+		(uint32_t *)&cmd, sizeof(cmd));
+
+	cmd2.a00       = in->highPassCoef[0];
+	cmd2.a04       = in->highPassCoef[1];
+	cmd2.a20       = in->highPassCoef[2];
+	cmd2.a21       = in->highPassCoef[3];
+	cmd2.a22       = in->highPassCoef[4];
+	cmd2.a23       = in->highPassCoef[5];
+	cmd2.a24       = in->highPassCoef[6];
+	cmd2.fvMax     = in->metricMax;
+	cmd2.fvMetric  = in->metricSelection;
+	cmd2.afHeader  = in->bufferHeader;
+	cmd2.entry00   = in->gridForMultiWindows[0];
+	cmd2.entry01   = in->gridForMultiWindows[1];
+	cmd2.entry02   = in->gridForMultiWindows[2];
+	cmd2.entry03   = in->gridForMultiWindows[3];
+	cmd2.entry10   = in->gridForMultiWindows[4];
+	cmd2.entry11   = in->gridForMultiWindows[5];
+	cmd2.entry12   = in->gridForMultiWindows[6];
+	cmd2.entry13   = in->gridForMultiWindows[7];
+	cmd2.entry20   = in->gridForMultiWindows[8];
+	cmd2.entry21   = in->gridForMultiWindows[9];
+	cmd2.entry22   = in->gridForMultiWindows[10];
+	cmd2.entry23   = in->gridForMultiWindows[11];
+	cmd2.entry30   = in->gridForMultiWindows[12];
+	cmd2.entry31   = in->gridForMultiWindows[13];
+	cmd2.entry32   = in->gridForMultiWindows[14];
+	cmd2.entry33   = in->gridForMultiWindows[15];
+
+	vfe_prog_hw(ctrl->vfebase + VFE_STATS_AF_GRID_0,
+		(uint32_t *)&cmd2, sizeof(cmd2));
+}
+
+void vfe_stats_setting(struct vfe_cmd_stats_setting *in)
+{
+	struct vfe_statsframe cmd1;
+	struct vfe_busstats_wrprio cmd2;
+
+	memset(&cmd1, 0, sizeof(cmd1));
+	memset(&cmd2, 0, sizeof(cmd2));
+
+	ctrl->afStatsControl.addressBuffer[0] = in->afBuffer[0];
+	ctrl->afStatsControl.addressBuffer[1] = in->afBuffer[1];
+	ctrl->afStatsControl.nextFrameAddrBuf = in->afBuffer[2];
+
+	ctrl->awbStatsControl.addressBuffer[0] = in->awbBuffer[0];
+	ctrl->awbStatsControl.addressBuffer[1] = in->awbBuffer[1];
+	ctrl->awbStatsControl.nextFrameAddrBuf = in->awbBuffer[2];
+
+	cmd1.lastPixel = in->frameHDimension;
+	cmd1.lastLine  = in->frameVDimension;
+	vfe_prog_hw(ctrl->vfebase + VFE_STATS_FRAME_SIZE,
+		(uint32_t *)&cmd1, sizeof(cmd1));
+
+	cmd2.afBusPriority    = in->afBusPriority;
+	cmd2.awbBusPriority   = in->awbBusPriority;
+	cmd2.histBusPriority  = in->histBusPriority;
+	cmd2.afBusPriorityEn  = in->afBusPrioritySelection;
+	cmd2.awbBusPriorityEn = in->awbBusPrioritySelection;
+	cmd2.histBusPriorityEn = in->histBusPrioritySelection;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_BUS_STATS_WR_PRIORITY,
+		(uint32_t *)&cmd2, sizeof(cmd2));
+
+	/* Program the bus ping pong address for statistics modules. */
+	writel(in->afBuffer[0], ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+	writel(in->afBuffer[1], ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+	writel(in->awbBuffer[0],
+		ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+	writel(in->awbBuffer[1],
+		ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+	writel(in->histBuffer[0],
+		ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PING_ADDR);
+	writel(in->histBuffer[1],
+		ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PONG_ADDR);
+}
+
+void vfe_axi_input_config(struct vfe_cmd_axi_input_config *in)
+{
+	struct VFE_AxiInputCmdType cmd;
+	uint32_t xSizeWord, axiRdUnpackPattern;
+	uint8_t  axiInputPpw;
+	uint32_t busPingpongRdIrqEnable;
+
+	ctrl->vfeImaskLocal.rdPingpongIrq = TRUE;
+
+	switch (in->pixelSize) {
+	case VFE_RAW_PIXEL_DATA_SIZE_10BIT:
+		ctrl->axiInputDataSize = VFE_RAW_PIXEL_DATA_SIZE_10BIT;
+		break;
+
+	case VFE_RAW_PIXEL_DATA_SIZE_12BIT:
+		ctrl->axiInputDataSize = VFE_RAW_PIXEL_DATA_SIZE_12BIT;
+		break;
+
+	case VFE_RAW_PIXEL_DATA_SIZE_8BIT:
+	default:
+		ctrl->axiInputDataSize = VFE_RAW_PIXEL_DATA_SIZE_8BIT;
+		break;
+	}
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	switch (in->pixelSize) {
+	case VFE_RAW_PIXEL_DATA_SIZE_10BIT:
+		axiInputPpw = 6;
+		axiRdUnpackPattern = 0xD43210;
+		break;
+
+	case VFE_RAW_PIXEL_DATA_SIZE_12BIT:
+		axiInputPpw = 5;
+		axiRdUnpackPattern = 0xC3210;
+		break;
+
+	case VFE_RAW_PIXEL_DATA_SIZE_8BIT:
+	default:
+		axiInputPpw = 8;
+		axiRdUnpackPattern = 0xF6543210;
+		break;
+	}
+
+	xSizeWord =
+		((((in->xOffset % axiInputPpw) + in->xSize) +
+			(axiInputPpw-1)) / axiInputPpw) - 1;
+
+	cmd.stripeStartAddr0  = in->fragAddr[0];
+	cmd.stripeStartAddr1  = in->fragAddr[1];
+	cmd.stripeStartAddr2  = in->fragAddr[2];
+	cmd.stripeStartAddr3  = in->fragAddr[3];
+	cmd.ySize             = in->ySize;
+	cmd.yOffsetDelta      = 0;
+	cmd.xSizeWord         = xSizeWord;
+	cmd.burstLength       = 1;
+	cmd.NumOfRows         = in->numOfRows;
+	cmd.RowIncrement = (in->rowIncrement + (axiInputPpw - 1)) / axiInputPpw;
+	cmd.mainUnpackHeight  = in->ySize;
+	cmd.mainUnpackWidth   = in->xSize - 1;
+	cmd.mainUnpackHbiSel  = (uint32_t)in->unpackHbi;
+	cmd.mainUnpackPhase   = in->unpackPhase;
+	cmd.unpackPattern     = axiRdUnpackPattern;
+	cmd.padLeft           = in->padRepeatCountLeft;
+	cmd.padRight          = in->padRepeatCountRight;
+	cmd.padTop            = in->padRepeatCountTop;
+	cmd.padBottom         = in->padRepeatCountBottom;
+	cmd.leftUnpackPattern0   = in->padLeftComponentSelectCycle0;
+	cmd.leftUnpackPattern1   = in->padLeftComponentSelectCycle1;
+	cmd.leftUnpackPattern2   = in->padLeftComponentSelectCycle2;
+	cmd.leftUnpackPattern3   = in->padLeftComponentSelectCycle3;
+	cmd.leftUnpackStop0      = in->padLeftStopCycle0;
+	cmd.leftUnpackStop1      = in->padLeftStopCycle1;
+	cmd.leftUnpackStop2      = in->padLeftStopCycle2;
+	cmd.leftUnpackStop3      = in->padLeftStopCycle3;
+	cmd.rightUnpackPattern0  = in->padRightComponentSelectCycle0;
+	cmd.rightUnpackPattern1  = in->padRightComponentSelectCycle1;
+	cmd.rightUnpackPattern2  = in->padRightComponentSelectCycle2;
+	cmd.rightUnpackPattern3  = in->padRightComponentSelectCycle3;
+	cmd.rightUnpackStop0     = in->padRightStopCycle0;
+	cmd.rightUnpackStop1     = in->padRightStopCycle1;
+	cmd.rightUnpackStop2     = in->padRightStopCycle2;
+	cmd.rightUnpackStop3     = in->padRightStopCycle3;
+	cmd.topUnapckPattern     = in->padTopLineCount;
+	cmd.bottomUnapckPattern  = in->padBottomLineCount;
+
+	/*  program vfe_bus_cfg */
+	vfe_prog_hw(ctrl->vfebase + VFE_BUS_STRIPE_RD_ADDR_0,
+		(uint32_t *)&cmd, sizeof(cmd));
+
+	/* hacking code, put it to default value */
+	busPingpongRdIrqEnable = 0xf;
+
+	writel(busPingpongRdIrqEnable, ctrl->vfebase + VFE_BUS_PINGPONG_IRQ_EN);
+}
+
+void vfe_axi_output_config(struct vfe_cmd_axi_output_config *in)
+{
+	/* local variable  */
+	uint32_t *pcircle;
+	uint32_t *pdest;
+	uint32_t *psrc;
+	uint8_t  i;
+	uint8_t  fcnt;
+	uint16_t axioutpw = 8;
+
+	/* parameters check, condition and usage mode check */
+	ctrl->encPath.fragCount = in->output2.fragmentCount;
+	if (ctrl->encPath.fragCount > 1)
+		ctrl->encPath.multiFrag = TRUE;
+
+	ctrl->viewPath.fragCount = in->output1.fragmentCount;
+	if (ctrl->viewPath.fragCount > 1)
+		ctrl->viewPath.multiFrag = TRUE;
+
+	/* VFE_BUS_CFG.  raw data size */
+	ctrl->vfeBusConfigLocal.rawPixelDataSize = in->outputDataSize;
+
+	switch (in->outputDataSize) {
+	case VFE_RAW_PIXEL_DATA_SIZE_8BIT:
+		axioutpw = 8;
+		break;
+
+	case VFE_RAW_PIXEL_DATA_SIZE_10BIT:
+		axioutpw = 6;
+		break;
+
+	case VFE_RAW_PIXEL_DATA_SIZE_12BIT:
+		axioutpw = 5;
+		break;
+	}
+
+	ctrl->axiOutputMode = in->outputMode;
+
+	CDBG("axiOutputMode = %d\n", ctrl->axiOutputMode);
+
+	switch (ctrl->axiOutputMode) {
+	case VFE_AXI_OUTPUT_MODE_Output1: {
+		ctrl->vfeCamifConfigLocal.camif2BusEnable   = FALSE;
+		ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE;
+		ctrl->vfeBusConfigLocal.rawWritePathSelect  =
+			VFE_RAW_OUTPUT_DISABLED;
+
+		ctrl->encPath.pathEnabled                   = FALSE;
+		ctrl->vfeImaskLocal.encIrq                  = FALSE;
+		ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+			VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+		ctrl->vfeBusConfigLocal.encYWrPathEn          = FALSE;
+		ctrl->vfeBusConfigLocal.encCbcrWrPathEn       = FALSE;
+		ctrl->viewPath.pathEnabled                    = TRUE;
+		ctrl->vfeImaskLocal.viewIrq                   = TRUE;
+		ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+			VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+		ctrl->vfeBusConfigLocal.viewYWrPathEn    = TRUE;
+		ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = TRUE;
+
+		if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+				ctrl->encPath.multiFrag)
+			ctrl->vfeImaskLocal.encYPingpongIrq    = TRUE;
+
+		if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+				ctrl->encPath.multiFrag)
+			ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE;
+
+		if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+				ctrl->viewPath.multiFrag)
+			ctrl->vfeImaskLocal.viewYPingpongIrq   = TRUE;
+
+		if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+				ctrl->viewPath.multiFrag)
+			ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE;
+	} /* VFE_AXI_OUTPUT_MODE_Output1 */
+		break;
+
+	case VFE_AXI_OUTPUT_MODE_Output2: {
+		ctrl->vfeCamifConfigLocal.camif2BusEnable   = FALSE;
+		ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE;
+		ctrl->vfeBusConfigLocal.rawWritePathSelect  =
+			VFE_RAW_OUTPUT_DISABLED;
+
+		ctrl->encPath.pathEnabled                   = TRUE;
+		ctrl->vfeImaskLocal.encIrq                  = TRUE;
+		ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+			VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+		ctrl->vfeBusConfigLocal.encYWrPathEn        = TRUE;
+		ctrl->vfeBusConfigLocal.encCbcrWrPathEn     = TRUE;
+
+		ctrl->viewPath.pathEnabled                   = FALSE;
+		ctrl->vfeImaskLocal.viewIrq                  = FALSE;
+		ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+			VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+		ctrl->vfeBusConfigLocal.viewYWrPathEn        = FALSE;
+		ctrl->vfeBusConfigLocal.viewCbcrWrPathEn     = FALSE;
+
+		if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+				ctrl->encPath.multiFrag)
+			ctrl->vfeImaskLocal.encYPingpongIrq    = TRUE;
+
+		if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+				ctrl->encPath.multiFrag)
+			ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE;
+
+		if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+				ctrl->viewPath.multiFrag)
+			ctrl->vfeImaskLocal.viewYPingpongIrq   = TRUE;
+
+		if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+				ctrl->viewPath.multiFrag)
+			ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE;
+	} /* VFE_AXI_OUTPUT_MODE_Output2 */
+			break;
+
+	case VFE_AXI_OUTPUT_MODE_Output1AndOutput2: {
+		ctrl->vfeCamifConfigLocal.camif2BusEnable    = FALSE;
+		ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE;
+		ctrl->vfeBusConfigLocal.rawWritePathSelect   =
+			VFE_RAW_OUTPUT_DISABLED;
+
+		ctrl->encPath.pathEnabled                    = TRUE;
+		ctrl->vfeImaskLocal.encIrq                   = TRUE;
+		ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+			VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+		ctrl->vfeBusConfigLocal.encYWrPathEn         = TRUE;
+		ctrl->vfeBusConfigLocal.encCbcrWrPathEn      = TRUE;
+		ctrl->viewPath.pathEnabled                   = TRUE;
+		ctrl->vfeImaskLocal.viewIrq                  = TRUE;
+		ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+			VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+		ctrl->vfeBusConfigLocal.viewYWrPathEn        = TRUE;
+		ctrl->vfeBusConfigLocal.viewCbcrWrPathEn     = TRUE;
+
+		if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+				ctrl->encPath.multiFrag)
+			ctrl->vfeImaskLocal.encYPingpongIrq    = TRUE;
+
+		if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+				ctrl->encPath.multiFrag)
+			ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE;
+
+		if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+				ctrl->viewPath.multiFrag)
+			ctrl->vfeImaskLocal.viewYPingpongIrq   = TRUE;
+
+		if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+				ctrl->viewPath.multiFrag)
+			ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE;
+	} /* VFE_AXI_OUTPUT_MODE_Output1AndOutput2 */
+		break;
+
+	case VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2: {
+		/* For raw snapshot, we need both ping and pong buffer
+		 * initialized to the same address. Otherwise, if we
+		 * leave the pong buffer to NULL, there will be axi_error.
+		 * Note that ideally we should deal with this at upper layer,
+		 * which is in msm_vfe8x.c */
+		if (!in->output2.outputCbcr.outFragments[1][0]) {
+			in->output2.outputCbcr.outFragments[1][0] =
+				in->output2.outputCbcr.outFragments[0][0];
+		}
+
+		ctrl->vfeCamifConfigLocal.camif2BusEnable   = TRUE;
+		ctrl->vfeCamifConfigLocal.camif2OutputEnable = FALSE;
+		ctrl->vfeBusConfigLocal.rawWritePathSelect  =
+			VFE_RAW_OUTPUT_ENC_CBCR_PATH;
+
+		ctrl->encPath.pathEnabled                   = TRUE;
+		ctrl->vfeImaskLocal.encIrq                  = TRUE;
+		ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+			VFE_COMP_IRQ_CBCR_ONLY;
+
+		ctrl->vfeBusConfigLocal.encYWrPathEn        = FALSE;
+		ctrl->vfeBusConfigLocal.encCbcrWrPathEn     = TRUE;
+
+		ctrl->viewPath.pathEnabled                   = FALSE;
+		ctrl->vfeImaskLocal.viewIrq                  = FALSE;
+		ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+			VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+		ctrl->vfeBusConfigLocal.viewYWrPathEn        = FALSE;
+		ctrl->vfeBusConfigLocal.viewCbcrWrPathEn     = FALSE;
+
+		if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+				ctrl->encPath.multiFrag)
+			ctrl->vfeImaskLocal.encYPingpongIrq    = TRUE;
+
+		if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+				ctrl->encPath.multiFrag)
+			ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE;
+
+		if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+				ctrl->viewPath.multiFrag)
+			ctrl->vfeImaskLocal.viewYPingpongIrq   = TRUE;
+
+		if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+				ctrl->viewPath.multiFrag)
+			ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE;
+	} /* VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2 */
+		break;
+
+	case VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1: {
+		ctrl->vfeCamifConfigLocal.camif2BusEnable   = TRUE;
+		ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE;
+		ctrl->vfeBusConfigLocal.rawWritePathSelect  =
+			VFE_RAW_OUTPUT_VIEW_CBCR_PATH;
+
+		ctrl->encPath.pathEnabled                   = TRUE;
+		ctrl->vfeImaskLocal.encIrq                  = TRUE;
+		ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+			VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+		ctrl->vfeBusConfigLocal.encYWrPathEn        = TRUE;
+		ctrl->vfeBusConfigLocal.encCbcrWrPathEn     = TRUE;
+
+		ctrl->viewPath.pathEnabled                   = TRUE;
+		ctrl->vfeImaskLocal.viewIrq                  = TRUE;
+		ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+			VFE_COMP_IRQ_CBCR_ONLY;
+
+		ctrl->vfeBusConfigLocal.viewYWrPathEn        = FALSE;
+		ctrl->vfeBusConfigLocal.viewCbcrWrPathEn     = TRUE;
+
+		if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+				ctrl->encPath.multiFrag)
+			ctrl->vfeImaskLocal.encYPingpongIrq    = TRUE;
+
+		if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+				ctrl->encPath.multiFrag)
+			ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE;
+
+		if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+				ctrl->viewPath.multiFrag)
+			ctrl->vfeImaskLocal.viewYPingpongIrq   = TRUE;
+
+		if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+				ctrl->viewPath.multiFrag)
+			ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE;
+	} /* VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1 */
+		break;
+
+	case VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2: {
+		ctrl->vfeCamifConfigLocal.camif2BusEnable   = TRUE;
+		ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE;
+		ctrl->vfeBusConfigLocal.rawWritePathSelect  =
+			VFE_RAW_OUTPUT_ENC_CBCR_PATH;
+
+		ctrl->encPath.pathEnabled                     = TRUE;
+		ctrl->vfeImaskLocal.encIrq                    = TRUE;
+		ctrl->vfeIrqCompositeMaskLocal.encIrqComMask  =
+			VFE_COMP_IRQ_CBCR_ONLY;
+
+		ctrl->vfeBusConfigLocal.encYWrPathEn          = FALSE;
+		ctrl->vfeBusConfigLocal.encCbcrWrPathEn       = TRUE;
+
+		ctrl->viewPath.pathEnabled                    = TRUE;
+		ctrl->vfeImaskLocal.viewIrq                   = TRUE;
+
+		ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+			VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+		ctrl->vfeBusConfigLocal.viewYWrPathEn         = TRUE;
+		ctrl->vfeBusConfigLocal.viewCbcrWrPathEn      = TRUE;
+
+		if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+				ctrl->encPath.multiFrag)
+			ctrl->vfeImaskLocal.encYPingpongIrq       = TRUE;
+
+		if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+				ctrl->encPath.multiFrag)
+			ctrl->vfeImaskLocal.encCbcrPingpongIrq    = TRUE;
+
+		if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+				ctrl->viewPath.multiFrag)
+			ctrl->vfeImaskLocal.viewYPingpongIrq      = TRUE;
+
+		if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+				ctrl->viewPath.multiFrag)
+			ctrl->vfeImaskLocal.viewCbcrPingpongIrq   = TRUE;
+	} /* VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2 */
+		break;
+
+	case VFE_AXI_LAST_OUTPUT_MODE_ENUM:
+		break;
+	} /* switch */
+
+	/* Save the addresses for each path. */
+	/* output2 path */
+	fcnt = ctrl->encPath.fragCount;
+
+	pcircle = ctrl->encPath.yPath.addressBuffer;
+	pdest = ctrl->encPath.nextFrameAddrBuf;
+
+	psrc = &(in->output2.outputY.outFragments[0][0]);
+	for (i = 0; i < fcnt; i++)
+		*pcircle++ = *psrc++;
+
+	psrc = &(in->output2.outputY.outFragments[1][0]);
+	for (i = 0; i < fcnt; i++)
+		*pcircle++ = *psrc++;
+
+	psrc = &(in->output2.outputY.outFragments[2][0]);
+	for (i = 0; i < fcnt; i++)
+		*pdest++ = *psrc++;
+
+	pcircle = ctrl->encPath.cbcrPath.addressBuffer;
+
+	psrc = &(in->output2.outputCbcr.outFragments[0][0]);
+	for (i = 0; i < fcnt; i++)
+		*pcircle++ = *psrc++;
+
+	psrc = &(in->output2.outputCbcr.outFragments[1][0]);
+	for (i = 0; i < fcnt; i++)
+		*pcircle++ = *psrc++;
+
+	psrc = &(in->output2.outputCbcr.outFragments[2][0]);
+	for (i = 0; i < fcnt; i++)
+		*pdest++ = *psrc++;
+
+	vfe_set_bus_pipo_addr(&ctrl->viewPath, &ctrl->encPath);
+
+	ctrl->encPath.ackPending = FALSE;
+	ctrl->encPath.currentFrame = ping;
+	ctrl->encPath.whichOutputPath = 1;
+	ctrl->encPath.yPath.fragIndex = 2;
+	ctrl->encPath.cbcrPath.fragIndex = 2;
+	ctrl->encPath.yPath.hwCurrentFlag = ping;
+	ctrl->encPath.cbcrPath.hwCurrentFlag = ping;
+
+	/* output1 path */
+	pcircle = ctrl->viewPath.yPath.addressBuffer;
+	pdest = ctrl->viewPath.nextFrameAddrBuf;
+	fcnt = ctrl->viewPath.fragCount;
+
+	psrc = &(in->output1.outputY.outFragments[0][0]);
+	for (i = 0; i < fcnt; i++)
+		*pcircle++ = *psrc++;
+
+	psrc = &(in->output1.outputY.outFragments[1][0]);
+	for (i = 0; i < fcnt; i++)
+		*pcircle++ = *psrc++;
+
+	psrc = &(in->output1.outputY.outFragments[2][0]);
+	for (i = 0; i < fcnt; i++)
+		*pdest++ = *psrc++;
+
+	pcircle = ctrl->viewPath.cbcrPath.addressBuffer;
+
+	psrc = &(in->output1.outputCbcr.outFragments[0][0]);
+	for (i = 0; i < fcnt; i++)
+		*pcircle++ = *psrc++;
+
+	psrc = &(in->output1.outputCbcr.outFragments[1][0]);
+	for (i = 0; i < fcnt; i++)
+		*pcircle++ = *psrc++;
+
+	psrc = &(in->output1.outputCbcr.outFragments[2][0]);
+	for (i = 0; i < fcnt; i++)
+		*pdest++ = *psrc++;
+
+	ctrl->viewPath.ackPending = FALSE;
+	ctrl->viewPath.currentFrame = ping;
+	ctrl->viewPath.whichOutputPath = 0;
+	ctrl->viewPath.yPath.fragIndex = 2;
+	ctrl->viewPath.cbcrPath.fragIndex = 2;
+	ctrl->viewPath.yPath.hwCurrentFlag = ping;
+	ctrl->viewPath.cbcrPath.hwCurrentFlag = ping;
+
+	/* call to program the registers. */
+	vfe_axi_output(in, &ctrl->viewPath, &ctrl->encPath, axioutpw);
+}
+
+void vfe_camif_config(struct vfe_cmd_camif_config *in)
+{
+	struct vfe_camifcfg cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	CDBG("camif.frame pixelsPerLine = %d\n", in->frame.pixelsPerLine);
+	CDBG("camif.frame linesPerFrame = %d\n", in->frame.linesPerFrame);
+	CDBG("camif.window firstpixel = %d\n", in->window.firstpixel);
+	CDBG("camif.window lastpixel = %d\n",  in->window.lastpixel);
+	CDBG("camif.window firstline = %d\n",  in->window.firstline);
+	CDBG("camif.window lastline = %d\n",   in->window.lastline);
+
+	/* determine if epoch interrupt needs to be enabled.  */
+	if ((in->epoch1.enable == TRUE) &&
+	    (in->epoch1.lineindex <= in->frame.linesPerFrame))
+		ctrl->vfeImaskLocal.camifEpoch1Irq = 1;
+
+	if ((in->epoch2.enable == TRUE) &&
+	    (in->epoch2.lineindex <= in->frame.linesPerFrame)) {
+		ctrl->vfeImaskLocal.camifEpoch2Irq = 1;
+	}
+
+	/*  save the content to program CAMIF_CONFIG seperately. */
+	ctrl->vfeCamifConfigLocal.camifCfgFromCmd = in->camifConfig;
+
+	/* EFS_Config */
+	cmd.efsEndOfLine     = in->EFS.efsendofline;
+	cmd.efsStartOfLine   = in->EFS.efsstartofline;
+	cmd.efsEndOfFrame    = in->EFS.efsendofframe;
+	cmd.efsStartOfFrame  = in->EFS.efsstartofframe;
+
+	/* Frame Config */
+	cmd.frameConfigPixelsPerLine = in->frame.pixelsPerLine;
+	cmd.frameConfigLinesPerFrame = in->frame.linesPerFrame;
+
+	/* Window Width Config */
+	cmd.windowWidthCfgLastPixel  = in->window.lastpixel;
+	cmd.windowWidthCfgFirstPixel = in->window.firstpixel;
+
+	/* Window Height Config */
+	cmd.windowHeightCfglastLine   = in->window.lastline;
+	cmd.windowHeightCfgfirstLine  = in->window.firstline;
+
+	/* Subsample 1 Config */
+	cmd.subsample1CfgPixelSkip = in->subsample.pixelskipmask;
+	cmd.subsample1CfgLineSkip  = in->subsample.lineskipmask;
+
+	/* Subsample 2 Config */
+	cmd.subsample2CfgFrameSkip      = in->subsample.frameskip;
+	cmd.subsample2CfgFrameSkipMode  = in->subsample.frameskipmode;
+	cmd.subsample2CfgPixelSkipWrap  = in->subsample.pixelskipwrap;
+
+	/* Epoch Interrupt */
+	cmd.epoch1Line = in->epoch1.lineindex;
+	cmd.epoch2Line = in->epoch2.lineindex;
+
+	vfe_prog_hw(ctrl->vfebase + CAMIF_EFS_CONFIG,
+		(uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_fov_crop_config(struct vfe_cmd_fov_crop_config *in)
+{
+	struct vfe_fov_crop_cfg cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	ctrl->vfeModuleEnableLocal.cropEnable = in->enable;
+
+	/* FOV Corp, Part 1 */
+	cmd.lastPixel  = in->lastPixel;
+	cmd.firstPixel = in->firstPixel;
+
+	/* FOV Corp, Part 2 */
+	cmd.lastLine   = in->lastLine;
+	cmd.firstLine  = in->firstLine;
+
+	vfe_prog_hw(ctrl->vfebase + VFE_CROP_WIDTH_CFG,
+		(uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_get_hw_version(struct vfe_cmd_hw_version *out)
+{
+	uint32_t vfeHwVersionPacked;
+	struct vfe_hw_ver ver;
+
+	vfeHwVersionPacked = readl(ctrl->vfebase + VFE_HW_VERSION);
+
+	ver = *((struct vfe_hw_ver *)&vfeHwVersionPacked);
+
+	out->coreVersion  = ver.coreVersion;
+	out->minorVersion = ver.minorVersion;
+	out->majorVersion = ver.majorVersion;
+}
+
+static void vfe_reset_internal_variables(void)
+{
+	/* local variables to program the hardware. */
+	ctrl->vfeImaskPacked = 0;
+	ctrl->vfeImaskCompositePacked = 0;
+
+	/* FALSE = disable,  1 = enable. */
+	memset(&ctrl->vfeModuleEnableLocal, 0,
+		sizeof(ctrl->vfeModuleEnableLocal));
+
+	/* 0 = disable, 1 = enable */
+	memset(&ctrl->vfeCamifConfigLocal, 0,
+		sizeof(ctrl->vfeCamifConfigLocal));
+	/* 0 = disable, 1 = enable */
+	memset(&ctrl->vfeImaskLocal, 0, sizeof(ctrl->vfeImaskLocal));
+	memset(&ctrl->vfeStatsCmdLocal, 0, sizeof(ctrl->vfeStatsCmdLocal));
+	memset(&ctrl->vfeBusConfigLocal, 0, sizeof(ctrl->vfeBusConfigLocal));
+	memset(&ctrl->vfeBusPmConfigLocal, 0,
+		sizeof(ctrl->vfeBusPmConfigLocal));
+	memset(&ctrl->vfeBusCmdLocal, 0, sizeof(ctrl->vfeBusCmdLocal));
+	memset(&ctrl->vfeInterruptNameLocal, 0,
+		sizeof(ctrl->vfeInterruptNameLocal));
+	memset(&ctrl->vfeDroppedFrameCounts, 0,
+		sizeof(ctrl->vfeDroppedFrameCounts));
+	memset(&ctrl->vfeIrqThreadMsgLocal, 0,
+		sizeof(ctrl->vfeIrqThreadMsgLocal));
+
+	/* state control variables */
+	ctrl->vfeStartAckPendingFlag = FALSE;
+	ctrl->vfeStopAckPending = FALSE;
+	ctrl->vfeIrqCompositeMaskLocal.ceDoneSel = 0;
+	ctrl->vfeIrqCompositeMaskLocal.encIrqComMask = VFE_COMP_IRQ_BOTH_Y_CBCR;
+	ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+		VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+	ctrl->vstate = VFE_STATE_IDLE;
+
+	ctrl->axiOutputMode = VFE_AXI_LAST_OUTPUT_MODE_ENUM;
+	/* 0 for continuous mode, 1 for snapshot mode */
+	ctrl->vfeOperationMode = VFE_START_OPERATION_MODE_CONTINUOUS;
+	ctrl->vfeSnapShotCount = 0;
+	ctrl->vfeStatsPingPongReloadFlag = FALSE;
+	/* this is unsigned 32 bit integer. */
+	ctrl->vfeFrameId = 0;
+	ctrl->vfeFrameSkip.output1Pattern = 0xffffffff;
+	ctrl->vfeFrameSkip.output1Period  = 31;
+	ctrl->vfeFrameSkip.output2Pattern = 0xffffffff;
+	ctrl->vfeFrameSkip.output2Period  = 31;
+	ctrl->vfeFrameSkipPattern = 0xffffffff;
+	ctrl->vfeFrameSkipCount   = 0;
+	ctrl->vfeFrameSkipPeriod  = 31;
+
+	memset((void *)&ctrl->encPath, 0, sizeof(ctrl->encPath));
+	memset((void *)&ctrl->viewPath, 0, sizeof(ctrl->viewPath));
+
+	ctrl->encPath.whichOutputPath  = 1;
+	ctrl->encPath.cbcrStatusBit    = 5;
+	ctrl->viewPath.whichOutputPath = 0;
+	ctrl->viewPath.cbcrStatusBit   = 7;
+
+	ctrl->vfeTestGenStartFlag = FALSE;
+
+	/* default to bank 0. */
+	ctrl->vfeLaBankSel = 0;
+
+	/* default to bank 0 for all channels. */
+	memset(&ctrl->vfeGammaLutSel, 0, sizeof(ctrl->vfeGammaLutSel));
+
+	/* Stats control variables. */
+	memset(&ctrl->afStatsControl, 0, sizeof(ctrl->afStatsControl));
+	memset(&ctrl->awbStatsControl, 0, sizeof(ctrl->awbStatsControl));
+	vfe_set_stats_pingpong_address(&ctrl->afStatsControl,
+		&ctrl->awbStatsControl);
+}
+
+void vfe_reset(void)
+{
+	spin_lock_init(&msm_vfe_ctrl_lock);
+	vfe_reset_internal_variables();
+
+	atomic_set(&ctrl->vfe_serv_interrupt, 1);
+	ctrl->vfeImaskLocal.resetAckIrq = TRUE;
+	ctrl->vfeImaskPacked = vfe_irq_pack(ctrl->vfeImaskLocal);
+
+	/* disable all interrupts. */
+	writel(VFE_DISABLE_ALL_IRQS, ctrl->vfebase + VFE_IRQ_COMPOSITE_MASK);
+
+	/* clear all pending interrupts*/
+	writel(VFE_CLEAR_ALL_IRQS, ctrl->vfebase + VFE_IRQ_CLEAR);
+
+	/* enable reset_ack interrupt.  */
+	writel(ctrl->vfeImaskPacked, ctrl->vfebase + VFE_IRQ_MASK);
+
+	writel(VFE_RESET_UPON_RESET_CMD, ctrl->vfebase + VFE_GLOBAL_RESET_CMD);
+}
diff --git a/drivers/media/video/msm/msm_vfe8x_proc.h b/drivers/media/video/msm/msm_vfe8x_proc.h
new file mode 100644
index 0000000..da00e8f
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe8x_proc.h
@@ -0,0 +1,1563 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __MSM_VFE8X_REG_H__
+#define __MSM_VFE8X_REG_H__
+
+#include <mach/msm_iomap.h>
+#include <mach/camera.h>
+#include "msm_vfe8x.h"
+
+
+#define MSM_AXI_QOS_PREVIEW		128000
+#define MSM_AXI_QOS_SNAPSHOT	128000
+#define MSM_AXI_QOS_RECORDING	128000
+
+
+/* at start of camif,  bit 1:0 = 0x01:enable
+ * image data capture at frame boundary. */
+#define CAMIF_COMMAND_START  0x00000005
+
+/* bit 2= 0x1:clear the CAMIF_STATUS register
+ * value. */
+#define CAMIF_COMMAND_CLEAR  0x00000004
+
+/* at stop of vfe pipeline, for now it is assumed
+ * that camif will stop at any time. Bit 1:0 = 0x10:
+ * disable image data capture immediately. */
+#define CAMIF_COMMAND_STOP_IMMEDIATELY  0x00000002
+
+/* at stop of vfe pipeline, for now it is assumed
+ * that camif will stop at any time. Bit 1:0 = 0x00:
+ * disable image data capture at frame boundary */
+#define CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY  0x00000000
+
+/* to halt axi bridge */
+#define AXI_HALT  0x00000001
+
+/* clear the halt bit. */
+#define AXI_HALT_CLEAR  0x00000000
+
+/* reset the pipeline when stop command is issued.
+ * (without reset the register.) bit 26-31 = 0,
+ * domain reset, bit 0-9 = 1 for module reset, except
+ * register module. */
+#define VFE_RESET_UPON_STOP_CMD  0x000003ef
+
+/* reset the pipeline when reset command.
+ * bit 26-31 = 0, domain reset, bit 0-9 = 1 for module reset. */
+#define VFE_RESET_UPON_RESET_CMD  0x000003ff
+
+/* bit 5 is for axi status idle or busy.
+ * 1 =  halted,  0 = busy */
+#define AXI_STATUS_BUSY_MASK 0x00000020
+
+/* bit 0 & bit 1 = 1, both y and cbcr irqs need to be present
+ * for frame done interrupt */
+#define VFE_COMP_IRQ_BOTH_Y_CBCR 3
+
+/* bit 1 = 1, only cbcr irq triggers frame done interrupt */
+#define VFE_COMP_IRQ_CBCR_ONLY 2
+
+/* bit 0 = 1, only y irq triggers frame done interrupt */
+#define VFE_COMP_IRQ_Y_ONLY 1
+
+/* bit 0 = 1, PM go;   bit1 = 1, PM stop */
+#define VFE_PERFORMANCE_MONITOR_GO   0x00000001
+#define VFE_PERFORMANCE_MONITOR_STOP 0x00000002
+
+/* bit 0 = 1, test gen go;   bit1 = 1, test gen stop */
+#define VFE_TEST_GEN_GO   0x00000001
+#define VFE_TEST_GEN_STOP 0x00000002
+
+/* the chroma is assumed to be interpolated between
+ * the luma samples.  JPEG 4:2:2 */
+#define VFE_CHROMA_UPSAMPLE_INTERPOLATED 0
+
+/* constants for irq registers */
+#define VFE_DISABLE_ALL_IRQS 0
+/* bit =1 is to clear the corresponding bit in VFE_IRQ_STATUS.  */
+#define VFE_CLEAR_ALL_IRQS   0xffffffff
+/* imask for while waiting for stop ack,  driver has already
+ * requested stop, waiting for reset irq,
+ * bit 29,28,27,26 for async timer, bit 9 for reset */
+#define VFE_IMASK_WHILE_STOPPING  0x3c000200
+
+/* when normal case, don't want to block error status.
+ * bit 0,6,20,21,22,30,31 */
+#define VFE_IMASK_ERROR_ONLY             0xC0700041
+#define VFE_REG_UPDATE_TRIGGER           1
+#define VFE_PM_BUF_MAX_CNT_MASK          0xFF
+#define VFE_DMI_CFG_DEFAULT              0x00000100
+#define LENS_ROLL_OFF_DELTA_TABLE_OFFSET 32
+#define VFE_AF_PINGPONG_STATUS_BIT       0x100
+#define VFE_AWB_PINGPONG_STATUS_BIT      0x200
+
+/* VFE I/O registers */
+enum {
+	VFE_HW_VERSION                    = 0x00000000,
+	VFE_GLOBAL_RESET_CMD              = 0x00000004,
+	VFE_MODULE_RESET                  = 0x00000008,
+	VFE_CGC_OVERRIDE                  = 0x0000000C,
+	VFE_MODULE_CFG                    = 0x00000010,
+	VFE_CFG                           = 0x00000014,
+	VFE_IRQ_MASK                      = 0x00000018,
+	VFE_IRQ_CLEAR                     = 0x0000001C,
+VFE_IRQ_STATUS                    = 0x00000020,
+VFE_IRQ_COMPOSITE_MASK            = 0x00000024,
+VFE_BUS_CMD                       = 0x00000028,
+VFE_BUS_CFG                       = 0x0000002C,
+VFE_BUS_ENC_Y_WR_PING_ADDR        = 0x00000030,
+VFE_BUS_ENC_Y_WR_PONG_ADDR        = 0x00000034,
+VFE_BUS_ENC_Y_WR_IMAGE_SIZE       = 0x00000038,
+VFE_BUS_ENC_Y_WR_BUFFER_CFG       = 0x0000003C,
+VFE_BUS_ENC_CBCR_WR_PING_ADDR     = 0x00000040,
+VFE_BUS_ENC_CBCR_WR_PONG_ADDR     = 0x00000044,
+VFE_BUS_ENC_CBCR_WR_IMAGE_SIZE    = 0x00000048,
+VFE_BUS_ENC_CBCR_WR_BUFFER_CFG    = 0x0000004C,
+VFE_BUS_VIEW_Y_WR_PING_ADDR       = 0x00000050,
+VFE_BUS_VIEW_Y_WR_PONG_ADDR       = 0x00000054,
+VFE_BUS_VIEW_Y_WR_IMAGE_SIZE      = 0x00000058,
+VFE_BUS_VIEW_Y_WR_BUFFER_CFG      = 0x0000005C,
+VFE_BUS_VIEW_CBCR_WR_PING_ADDR    = 0x00000060,
+VFE_BUS_VIEW_CBCR_WR_PONG_ADDR    = 0x00000064,
+VFE_BUS_VIEW_CBCR_WR_IMAGE_SIZE   = 0x00000068,
+VFE_BUS_VIEW_CBCR_WR_BUFFER_CFG   = 0x0000006C,
+VFE_BUS_STATS_AF_WR_PING_ADDR     = 0x00000070,
+VFE_BUS_STATS_AF_WR_PONG_ADDR     = 0x00000074,
+VFE_BUS_STATS_AWB_WR_PING_ADDR    = 0x00000078,
+VFE_BUS_STATS_AWB_WR_PONG_ADDR    = 0x0000007C,
+VFE_BUS_STATS_HIST_WR_PING_ADDR   = 0x00000080,
+VFE_BUS_STATS_HIST_WR_PONG_ADDR   = 0x00000084,
+VFE_BUS_STATS_WR_PRIORITY         = 0x00000088,
+VFE_BUS_STRIPE_RD_ADDR_0          = 0x0000008C,
+VFE_BUS_STRIPE_RD_ADDR_1          = 0x00000090,
+VFE_BUS_STRIPE_RD_ADDR_2          = 0x00000094,
+VFE_BUS_STRIPE_RD_ADDR_3          = 0x00000098,
+VFE_BUS_STRIPE_RD_VSIZE           = 0x0000009C,
+VFE_BUS_STRIPE_RD_HSIZE           = 0x000000A0,
+VFE_BUS_STRIPE_RD_BUFFER_CFG      = 0x000000A4,
+VFE_BUS_STRIPE_RD_UNPACK_CFG      = 0x000000A8,
+VFE_BUS_STRIPE_RD_UNPACK          = 0x000000AC,
+VFE_BUS_STRIPE_RD_PAD_SIZE        = 0x000000B0,
+VFE_BUS_STRIPE_RD_PAD_L_UNPACK    = 0x000000B4,
+VFE_BUS_STRIPE_RD_PAD_R_UNPACK    = 0x000000B8,
+VFE_BUS_STRIPE_RD_PAD_TB_UNPACK   = 0x000000BC,
+VFE_BUS_PINGPONG_IRQ_EN           = 0x000000C0,
+VFE_BUS_PINGPONG_STATUS           = 0x000000C4,
+VFE_BUS_PM_CMD                    = 0x000000C8,
+VFE_BUS_PM_CFG                    = 0x000000CC,
+VFE_BUS_ENC_Y_WR_PM_STATS_0       = 0x000000D0,
+VFE_BUS_ENC_Y_WR_PM_STATS_1       = 0x000000D4,
+VFE_BUS_ENC_CBCR_WR_PM_STATS_0    = 0x000000D8,
+VFE_BUS_ENC_CBCR_WR_PM_STATS_1    = 0x000000DC,
+VFE_BUS_VIEW_Y_WR_PM_STATS_0      = 0x000000E0,
+VFE_BUS_VIEW_Y_WR_PM_STATS_1      = 0x000000E4,
+VFE_BUS_VIEW_CBCR_WR_PM_STATS_0   = 0x000000E8,
+VFE_BUS_VIEW_CBCR_WR_PM_STATS_1   = 0x000000EC,
+VFE_BUS_MISR_CFG                  = 0x000000F4,
+VFE_BUS_MISR_MAST_CFG_0           = 0x000000F8,
+VFE_BUS_MISR_MAST_CFG_1           = 0x000000FC,
+VFE_BUS_MISR_RD_VAL               = 0x00000100,
+VFE_AXI_CMD                       = 0x00000104,
+VFE_AXI_CFG                       = 0x00000108,
+VFE_AXI_STATUS                    = 0x0000010C,
+CAMIF_COMMAND                     = 0x00000110,
+CAMIF_CONFIG                      = 0x00000114,
+CAMIF_EFS_CONFIG                  = 0x00000118,
+CAMIF_FRAME_CONFIG                = 0x0000011C,
+CAMIF_WINDOW_WIDTH_CONFIG         = 0x00000120,
+CAMIF_WINDOW_HEIGHT_CONFIG        = 0x00000124,
+CAMIF_SUBSAMPLE1_CONFIG           = 0x00000128,
+CAMIF_SUBSAMPLE2_CONFIG           = 0x0000012C,
+CAMIF_EPOCH_IRQ                   = 0x00000130,
+CAMIF_STATUS                      = 0x00000134,
+CAMIF_MISR                        = 0x00000138,
+VFE_SYNC_TIMER_CMD                = 0x0000013C,
+VFE_SYNC_TIMER0_LINE_START        = 0x00000140,
+VFE_SYNC_TIMER0_PIXEL_START       = 0x00000144,
+VFE_SYNC_TIMER0_PIXEL_DURATION    = 0x00000148,
+VFE_SYNC_TIMER1_LINE_START        = 0x0000014C,
+VFE_SYNC_TIMER1_PIXEL_START       = 0x00000150,
+VFE_SYNC_TIMER1_PIXEL_DURATION    = 0x00000154,
+VFE_SYNC_TIMER2_LINE_START        = 0x00000158,
+VFE_SYNC_TIMER2_PIXEL_START       = 0x0000015C,
+VFE_SYNC_TIMER2_PIXEL_DURATION    = 0x00000160,
+VFE_SYNC_TIMER_POLARITY           = 0x00000164,
+VFE_ASYNC_TIMER_CMD               = 0x00000168,
+VFE_ASYNC_TIMER0_CFG_0            = 0x0000016C,
+VFE_ASYNC_TIMER0_CFG_1            = 0x00000170,
+VFE_ASYNC_TIMER1_CFG_0            = 0x00000174,
+VFE_ASYNC_TIMER1_CFG_1            = 0x00000178,
+VFE_ASYNC_TIMER2_CFG_0            = 0x0000017C,
+VFE_ASYNC_TIMER2_CFG_1            = 0x00000180,
+VFE_ASYNC_TIMER3_CFG_0            = 0x00000184,
+VFE_ASYNC_TIMER3_CFG_1            = 0x00000188,
+VFE_TIMER_SEL                     = 0x0000018C,
+VFE_REG_UPDATE_CMD                = 0x00000190,
+VFE_BLACK_EVEN_EVEN_VALUE         = 0x00000194,
+VFE_BLACK_EVEN_ODD_VALUE          = 0x00000198,
+VFE_BLACK_ODD_EVEN_VALUE          = 0x0000019C,
+VFE_BLACK_ODD_ODD_VALUE           = 0x000001A0,
+VFE_ROLLOFF_CFG_0                 = 0x000001A4,
+VFE_ROLLOFF_CFG_1                 = 0x000001A8,
+VFE_ROLLOFF_CFG_2                 = 0x000001AC,
+VFE_DEMUX_CFG                     = 0x000001B0,
+VFE_DEMUX_GAIN_0                  = 0x000001B4,
+VFE_DEMUX_GAIN_1                  = 0x000001B8,
+VFE_DEMUX_EVEN_CFG                = 0x000001BC,
+VFE_DEMUX_ODD_CFG                 = 0x000001C0,
+VFE_DEMOSAIC_CFG                  = 0x000001C4,
+VFE_DEMOSAIC_ABF_CFG_0            = 0x000001C8,
+VFE_DEMOSAIC_ABF_CFG_1            = 0x000001CC,
+VFE_DEMOSAIC_BPC_CFG_0            = 0x000001D0,
+VFE_DEMOSAIC_BPC_CFG_1            = 0x000001D4,
+VFE_DEMOSAIC_STATUS               = 0x000001D8,
+VFE_CHROMA_UPSAMPLE_CFG           = 0x000001DC,
+VFE_CROP_WIDTH_CFG                = 0x000001E0,
+VFE_CROP_HEIGHT_CFG               = 0x000001E4,
+VFE_COLOR_CORRECT_COEFF_0         = 0x000001E8,
+VFE_COLOR_CORRECT_COEFF_1         = 0x000001EC,
+VFE_COLOR_CORRECT_COEFF_2         = 0x000001F0,
+VFE_COLOR_CORRECT_COEFF_3         = 0x000001F4,
+VFE_COLOR_CORRECT_COEFF_4         = 0x000001F8,
+VFE_COLOR_CORRECT_COEFF_5         = 0x000001FC,
+VFE_COLOR_CORRECT_COEFF_6         = 0x00000200,
+VFE_COLOR_CORRECT_COEFF_7         = 0x00000204,
+VFE_COLOR_CORRECT_COEFF_8         = 0x00000208,
+VFE_COLOR_CORRECT_OFFSET_0        = 0x0000020C,
+VFE_COLOR_CORRECT_OFFSET_1        = 0x00000210,
+VFE_COLOR_CORRECT_OFFSET_2        = 0x00000214,
+VFE_COLOR_CORRECT_COEFF_Q         = 0x00000218,
+VFE_LA_CFG                        = 0x0000021C,
+VFE_LUT_BANK_SEL                  = 0x00000220,
+VFE_CHROMA_ENHAN_A                = 0x00000224,
+VFE_CHROMA_ENHAN_B                = 0x00000228,
+VFE_CHROMA_ENHAN_C                = 0x0000022C,
+VFE_CHROMA_ENHAN_D                = 0x00000230,
+VFE_CHROMA_ENHAN_K                = 0x00000234,
+VFE_COLOR_CONVERT_COEFF_0         = 0x00000238,
+VFE_COLOR_CONVERT_COEFF_1         = 0x0000023C,
+VFE_COLOR_CONVERT_COEFF_2         = 0x00000240,
+VFE_COLOR_CONVERT_OFFSET          = 0x00000244,
+VFE_ASF_CFG                       = 0x00000248,
+VFE_ASF_SHARP_CFG_0               = 0x0000024C,
+VFE_ASF_SHARP_CFG_1               = 0x00000250,
+VFE_ASF_SHARP_COEFF_0             = 0x00000254,
+VFE_ASF_SHARP_COEFF_1             = 0x00000258,
+VFE_ASF_SHARP_COEFF_2             = 0x0000025C,
+VFE_ASF_SHARP_COEFF_3             = 0x00000260,
+VFE_ASF_MAX_EDGE                  = 0x00000264,
+VFE_ASF_CROP_WIDTH_CFG            = 0x00000268,
+VFE_ASF_CROP_HEIGHT_CFG           = 0x0000026C,
+VFE_SCALE_CFG                     = 0x00000270,
+VFE_SCALE_H_IMAGE_SIZE_CFG        = 0x00000274,
+VFE_SCALE_H_PHASE_CFG             = 0x00000278,
+VFE_SCALE_H_STRIPE_CFG            = 0x0000027C,
+VFE_SCALE_V_IMAGE_SIZE_CFG        = 0x00000280,
+VFE_SCALE_V_PHASE_CFG             = 0x00000284,
+VFE_SCALE_V_STRIPE_CFG            = 0x00000288,
+VFE_SCALE_Y_CFG                   = 0x0000028C,
+VFE_SCALE_Y_H_IMAGE_SIZE_CFG      = 0x00000290,
+VFE_SCALE_Y_H_PHASE_CFG           = 0x00000294,
+VFE_SCALE_Y_V_IMAGE_SIZE_CFG      = 0x00000298,
+VFE_SCALE_Y_V_PHASE_CFG           = 0x0000029C,
+VFE_SCALE_CBCR_CFG                = 0x000002A0,
+VFE_SCALE_CBCR_H_IMAGE_SIZE_CFG   = 0x000002A4,
+VFE_SCALE_CBCR_H_PHASE_CFG        = 0x000002A8,
+VFE_SCALE_CBCR_V_IMAGE_SIZE_CFG   = 0x000002AC,
+VFE_SCALE_CBCR_V_PHASE_CFG        = 0x000002B0,
+VFE_WB_CFG                        = 0x000002B4,
+VFE_CHROMA_SUPPRESS_CFG_0         = 0x000002B8,
+VFE_CHROMA_SUPPRESS_CFG_1         = 0x000002BC,
+VFE_CHROMA_SUBSAMPLE_CFG          = 0x000002C0,
+VFE_CHROMA_SUB_CROP_WIDTH_CFG     = 0x000002C4,
+VFE_CHROMA_SUB_CROP_HEIGHT_CFG    = 0x000002C8,
+VFE_FRAMEDROP_ENC_Y_CFG           = 0x000002CC,
+VFE_FRAMEDROP_ENC_CBCR_CFG        = 0x000002D0,
+VFE_FRAMEDROP_ENC_Y_PATTERN       = 0x000002D4,
+VFE_FRAMEDROP_ENC_CBCR_PATTERN    = 0x000002D8,
+VFE_FRAMEDROP_VIEW_Y_CFG          = 0x000002DC,
+VFE_FRAMEDROP_VIEW_CBCR_CFG       = 0x000002E0,
+VFE_FRAMEDROP_VIEW_Y_PATTERN      = 0x000002E4,
+VFE_FRAMEDROP_VIEW_CBCR_PATTERN   = 0x000002E8,
+VFE_CLAMP_MAX_CFG                 = 0x000002EC,
+VFE_CLAMP_MIN_CFG                 = 0x000002F0,
+VFE_STATS_CMD                     = 0x000002F4,
+VFE_STATS_AF_CFG                  = 0x000002F8,
+VFE_STATS_AF_DIM                  = 0x000002FC,
+VFE_STATS_AF_GRID_0               = 0x00000300,
+VFE_STATS_AF_GRID_1               = 0x00000304,
+VFE_STATS_AF_GRID_2               = 0x00000308,
+VFE_STATS_AF_GRID_3               = 0x0000030C,
+VFE_STATS_AF_HEADER               = 0x00000310,
+VFE_STATS_AF_COEF0                = 0x00000314,
+VFE_STATS_AF_COEF1                = 0x00000318,
+VFE_STATS_AWBAE_CFG               = 0x0000031C,
+VFE_STATS_AXW_HEADER              = 0x00000320,
+VFE_STATS_AWB_MCFG                = 0x00000324,
+VFE_STATS_AWB_CCFG1               = 0x00000328,
+VFE_STATS_AWB_CCFG2               = 0x0000032C,
+VFE_STATS_HIST_HEADER             = 0x00000330,
+VFE_STATS_HIST_INNER_OFFSET       = 0x00000334,
+VFE_STATS_HIST_INNER_DIM          = 0x00000338,
+VFE_STATS_FRAME_SIZE              = 0x0000033C,
+VFE_DMI_CFG                       = 0x00000340,
+VFE_DMI_ADDR                      = 0x00000344,
+VFE_DMI_DATA_HI                   = 0x00000348,
+VFE_DMI_DATA_LO                   = 0x0000034C,
+VFE_DMI_RAM_AUTO_LOAD_CMD         = 0x00000350,
+VFE_DMI_RAM_AUTO_LOAD_STATUS      = 0x00000354,
+VFE_DMI_RAM_AUTO_LOAD_CFG         = 0x00000358,
+VFE_DMI_RAM_AUTO_LOAD_SEED        = 0x0000035C,
+VFE_TESTBUS_SEL                   = 0x00000360,
+VFE_TESTGEN_CFG                   = 0x00000364,
+VFE_SW_TESTGEN_CMD                = 0x00000368,
+VFE_HW_TESTGEN_CMD                = 0x0000036C,
+VFE_HW_TESTGEN_CFG                = 0x00000370,
+VFE_HW_TESTGEN_IMAGE_CFG          = 0x00000374,
+VFE_HW_TESTGEN_SOF_OFFSET_CFG     = 0x00000378,
+VFE_HW_TESTGEN_EOF_NOFFSET_CFG    = 0x0000037C,
+VFE_HW_TESTGEN_SOL_OFFSET_CFG     = 0x00000380,
+VFE_HW_TESTGEN_EOL_NOFFSET_CFG    = 0x00000384,
+VFE_HW_TESTGEN_HBI_CFG            = 0x00000388,
+VFE_HW_TESTGEN_VBL_CFG            = 0x0000038C,
+VFE_HW_TESTGEN_SOF_DUMMY_LINE_CFG2 = 0x00000390,
+VFE_HW_TESTGEN_EOF_DUMMY_LINE_CFG2 = 0x00000394,
+VFE_HW_TESTGEN_COLOR_BARS_CFG     = 0x00000398,
+VFE_HW_TESTGEN_RANDOM_CFG         = 0x0000039C,
+VFE_SPARE                         = 0x000003A0,
+};
+
+#define ping 0x0
+#define pong 0x1
+
+struct vfe_bus_cfg_data {
+	boolean                  stripeRdPathEn;
+	boolean                  encYWrPathEn;
+	boolean                  encCbcrWrPathEn;
+	boolean                  viewYWrPathEn;
+	boolean                  viewCbcrWrPathEn;
+	enum VFE_RAW_PIXEL_DATA_SIZE rawPixelDataSize;
+	enum VFE_RAW_WR_PATH_SEL     rawWritePathSelect;
+};
+
+struct vfe_camif_cfg_data {
+	boolean camif2OutputEnable;
+	boolean camif2BusEnable;
+	struct vfe_cmds_camif_cfg camifCfgFromCmd;
+};
+
+struct vfe_irq_composite_mask_config {
+	uint8_t encIrqComMask;
+	uint8_t viewIrqComMask;
+	uint8_t ceDoneSel;
+};
+
+/* define a structure for each output path.*/
+struct vfe_output_path {
+	uint32_t addressBuffer[8];
+	uint16_t fragIndex;
+	boolean  hwCurrentFlag;
+	uint8_t  *hwRegPingAddress;
+	uint8_t  *hwRegPongAddress;
+};
+
+struct vfe_output_path_combo {
+	boolean           whichOutputPath;
+	boolean           pathEnabled;
+	boolean           multiFrag;
+	uint8_t           fragCount;
+	boolean           ackPending;
+	uint8_t           currentFrame;
+	uint32_t          nextFrameAddrBuf[8];
+	struct vfe_output_path   yPath;
+	struct vfe_output_path   cbcrPath;
+	uint8_t           snapshotPendingCount;
+	boolean           pmEnabled;
+	uint8_t           cbcrStatusBit;
+};
+
+struct vfe_stats_control {
+	boolean  ackPending;
+	uint32_t addressBuffer[2];
+	uint32_t nextFrameAddrBuf;
+	boolean  pingPongStatus;
+	uint8_t  *hwRegPingAddress;
+	uint8_t  *hwRegPongAddress;
+	uint32_t droppedStatsFrameCount;
+	uint32_t bufToRender;
+};
+
+struct vfe_gamma_lut_sel {
+	boolean  ch0BankSelect;
+	boolean  ch1BankSelect;
+	boolean  ch2BankSelect;
+};
+
+struct vfe_interrupt_mask {
+	boolean  camifErrorIrq;
+	boolean  camifSofIrq;
+	boolean  camifEolIrq;
+	boolean  camifEofIrq;
+	boolean  camifEpoch1Irq;
+	boolean  camifEpoch2Irq;
+	boolean  camifOverflowIrq;
+	boolean  ceIrq;
+	boolean  regUpdateIrq;
+	boolean  resetAckIrq;
+	boolean  encYPingpongIrq;
+	boolean  encCbcrPingpongIrq;
+	boolean  viewYPingpongIrq;
+	boolean  viewCbcrPingpongIrq;
+	boolean  rdPingpongIrq;
+	boolean  afPingpongIrq;
+	boolean  awbPingpongIrq;
+	boolean  histPingpongIrq;
+	boolean  encIrq;
+	boolean  viewIrq;
+	boolean  busOverflowIrq;
+	boolean  afOverflowIrq;
+	boolean  awbOverflowIrq;
+	boolean  syncTimer0Irq;
+	boolean  syncTimer1Irq;
+	boolean  syncTimer2Irq;
+	boolean  asyncTimer0Irq;
+	boolean  asyncTimer1Irq;
+	boolean  asyncTimer2Irq;
+	boolean  asyncTimer3Irq;
+	boolean  axiErrorIrq;
+	boolean  violationIrq;
+};
+
+enum vfe_interrupt_name {
+	CAMIF_ERROR_IRQ,
+	CAMIF_SOF_IRQ,
+	CAMIF_EOL_IRQ,
+	CAMIF_EOF_IRQ,
+	CAMIF_EPOCH1_IRQ,
+	CAMIF_EPOCH2_IRQ,
+	CAMIF_OVERFLOW_IRQ,
+	CE_IRQ,
+	REG_UPDATE_IRQ,
+	RESET_ACK_IRQ,
+	ENC_Y_PINGPONG_IRQ,
+	ENC_CBCR_PINGPONG_IRQ,
+	VIEW_Y_PINGPONG_IRQ,
+	VIEW_CBCR_PINGPONG_IRQ,
+	RD_PINGPONG_IRQ,
+	AF_PINGPONG_IRQ,
+	AWB_PINGPONG_IRQ,
+	HIST_PINGPONG_IRQ,
+	ENC_IRQ,
+	VIEW_IRQ,
+	BUS_OVERFLOW_IRQ,
+	AF_OVERFLOW_IRQ,
+	AWB_OVERFLOW_IRQ,
+	SYNC_TIMER0_IRQ,
+	SYNC_TIMER1_IRQ,
+	SYNC_TIMER2_IRQ,
+	ASYNC_TIMER0_IRQ,
+	ASYNC_TIMER1_IRQ,
+	ASYNC_TIMER2_IRQ,
+	ASYNC_TIMER3_IRQ,
+	AXI_ERROR_IRQ,
+	VIOLATION_IRQ
+};
+
+enum VFE_DMI_RAM_SEL {
+	NO_MEM_SELECTED          = 0,
+	ROLLOFF_RAM              = 0x1,
+	RGBLUT_RAM_CH0_BANK0     = 0x2,
+	RGBLUT_RAM_CH0_BANK1     = 0x3,
+	RGBLUT_RAM_CH1_BANK0     = 0x4,
+	RGBLUT_RAM_CH1_BANK1     = 0x5,
+	RGBLUT_RAM_CH2_BANK0     = 0x6,
+	RGBLUT_RAM_CH2_BANK1     = 0x7,
+	STATS_HIST_CB_EVEN_RAM   = 0x8,
+	STATS_HIST_CB_ODD_RAM    = 0x9,
+	STATS_HIST_CR_EVEN_RAM   = 0xa,
+	STATS_HIST_CR_ODD_RAM    = 0xb,
+	RGBLUT_CHX_BANK0         = 0xc,
+	RGBLUT_CHX_BANK1         = 0xd,
+	LUMA_ADAPT_LUT_RAM_BANK0 = 0xe,
+	LUMA_ADAPT_LUT_RAM_BANK1 = 0xf
+};
+
+struct vfe_module_enable {
+	boolean  blackLevelCorrectionEnable;
+	boolean  lensRollOffEnable;
+	boolean  demuxEnable;
+	boolean  chromaUpsampleEnable;
+	boolean  demosaicEnable;
+	boolean  statsEnable;
+	boolean  cropEnable;
+	boolean  mainScalerEnable;
+	boolean  whiteBalanceEnable;
+	boolean  colorCorrectionEnable;
+	boolean  yHistEnable;
+	boolean  skinToneEnable;
+	boolean  lumaAdaptationEnable;
+	boolean  rgbLUTEnable;
+	boolean  chromaEnhanEnable;
+	boolean  asfEnable;
+	boolean  chromaSuppressionEnable;
+	boolean  chromaSubsampleEnable;
+	boolean  scaler2YEnable;
+	boolean  scaler2CbcrEnable;
+};
+
+struct vfe_bus_cmd_data {
+	boolean  stripeReload;
+	boolean  busPingpongReload;
+	boolean  statsPingpongReload;
+};
+
+struct vfe_stats_cmd_data {
+	boolean  autoFocusEnable;
+	boolean  axwEnable;
+	boolean  histEnable;
+	boolean  clearHistEnable;
+	boolean  histAutoClearEnable;
+	boolean  colorConversionEnable;
+};
+
+struct vfe_hw_ver {
+	uint32_t minorVersion:8;
+	uint32_t majorVersion:8;
+	uint32_t coreVersion:4;
+	uint32_t /* reserved */ : 12;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_cfg {
+	uint32_t pixelPattern:3;
+	uint32_t /* reserved */ : 13;
+	uint32_t inputSource:2;
+	uint32_t /* reserved */ : 14;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_buscmd {
+	uint32_t  stripeReload:1;
+	uint32_t  /* reserved */ : 3;
+	uint32_t  busPingpongReload:1;
+	uint32_t  statsPingpongReload:1;
+	uint32_t  /* reserved */ : 26;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_Irq_Composite_MaskType {
+	uint32_t  encIrqComMaskBits:2;
+	uint32_t  viewIrqComMaskBits:2;
+	uint32_t  ceDoneSelBits:5;
+	uint32_t  /* reserved */ : 23;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_mod_enable {
+	uint32_t blackLevelCorrectionEnable:1;
+	uint32_t lensRollOffEnable:1;
+	uint32_t demuxEnable:1;
+	uint32_t chromaUpsampleEnable:1;
+	uint32_t demosaicEnable:1;
+	uint32_t statsEnable:1;
+	uint32_t cropEnable:1;
+	uint32_t mainScalerEnable:1;
+	uint32_t whiteBalanceEnable:1;
+	uint32_t colorCorrectionEnable:1;
+	uint32_t yHistEnable:1;
+	uint32_t skinToneEnable:1;
+	uint32_t lumaAdaptationEnable:1;
+	uint32_t rgbLUTEnable:1;
+	uint32_t chromaEnhanEnable:1;
+	uint32_t asfEnable:1;
+	uint32_t chromaSuppressionEnable:1;
+	uint32_t chromaSubsampleEnable:1;
+	uint32_t scaler2YEnable:1;
+	uint32_t scaler2CbcrEnable:1;
+	uint32_t /* reserved */ : 14;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_irqenable {
+	uint32_t camifErrorIrq:1;
+	uint32_t camifSofIrq:1;
+	uint32_t camifEolIrq:1;
+	uint32_t camifEofIrq:1;
+	uint32_t camifEpoch1Irq:1;
+	uint32_t camifEpoch2Irq:1;
+	uint32_t camifOverflowIrq:1;
+	uint32_t ceIrq:1;
+	uint32_t regUpdateIrq:1;
+	uint32_t resetAckIrq:1;
+	uint32_t encYPingpongIrq:1;
+	uint32_t encCbcrPingpongIrq:1;
+	uint32_t viewYPingpongIrq:1;
+	uint32_t viewCbcrPingpongIrq:1;
+	uint32_t rdPingpongIrq:1;
+	uint32_t afPingpongIrq:1;
+	uint32_t awbPingpongIrq:1;
+	uint32_t histPingpongIrq:1;
+	uint32_t encIrq:1;
+	uint32_t viewIrq:1;
+	uint32_t busOverflowIrq:1;
+	uint32_t afOverflowIrq:1;
+	uint32_t awbOverflowIrq:1;
+	uint32_t syncTimer0Irq:1;
+	uint32_t syncTimer1Irq:1;
+	uint32_t syncTimer2Irq:1;
+	uint32_t asyncTimer0Irq:1;
+	uint32_t asyncTimer1Irq:1;
+	uint32_t asyncTimer2Irq:1;
+	uint32_t asyncTimer3Irq:1;
+	uint32_t axiErrorIrq:1;
+	uint32_t violationIrq:1;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_upsample_cfg {
+	uint32_t chromaCositingForYCbCrInputs:1;
+	uint32_t /* reserved */ : 31;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_CAMIFConfigType {
+	/* CAMIF Config */
+	uint32_t  /* reserved */ : 1;
+	uint32_t  VSyncEdge:1;
+	uint32_t  HSyncEdge:1;
+	uint32_t  syncMode:2;
+	uint32_t  vfeSubsampleEnable:1;
+	uint32_t  /* reserved */ : 1;
+	uint32_t  busSubsampleEnable:1;
+	uint32_t  camif2vfeEnable:1;
+	uint32_t  /* reserved */ : 1;
+	uint32_t  camif2busEnable:1;
+	uint32_t  irqSubsampleEnable:1;
+	uint32_t  binningEnable:1;
+	uint32_t  /* reserved */ : 18;
+	uint32_t  misrEnable:1;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_camifcfg {
+	/* EFS_Config */
+	uint32_t efsEndOfLine:8;
+	uint32_t efsStartOfLine:8;
+	uint32_t efsEndOfFrame:8;
+	uint32_t efsStartOfFrame:8;
+	/* Frame Config */
+	uint32_t frameConfigPixelsPerLine:14;
+	uint32_t /* reserved */ : 2;
+	uint32_t frameConfigLinesPerFrame:14;
+	uint32_t /* reserved */ : 2;
+	/* Window Width Config */
+	uint32_t windowWidthCfgLastPixel:14;
+	uint32_t /* reserved */ : 2;
+	uint32_t windowWidthCfgFirstPixel:14;
+	uint32_t /* reserved */ : 2;
+	/* Window Height Config */
+	uint32_t windowHeightCfglastLine:14;
+	uint32_t /* reserved */ : 2;
+	uint32_t windowHeightCfgfirstLine:14;
+	uint32_t /* reserved */ : 2;
+	/* Subsample 1 Config */
+	uint32_t subsample1CfgPixelSkip:16;
+	uint32_t subsample1CfgLineSkip:16;
+	/* Subsample 2 Config */
+	uint32_t subsample2CfgFrameSkip:4;
+	uint32_t subsample2CfgFrameSkipMode:1;
+	uint32_t subsample2CfgPixelSkipWrap:1;
+	uint32_t /* reserved */ : 26;
+	/* Epoch Interrupt */
+	uint32_t epoch1Line:14;
+	uint32_t /* reserved */ : 2;
+	uint32_t epoch2Line:14;
+	uint32_t /* reserved */ : 2;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_camifframe_update {
+	uint32_t pixelsPerLine:14;
+	uint32_t /* reserved */ : 2;
+	uint32_t linesPerFrame:14;
+	uint32_t /* reserved */ : 2;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_axi_bus_cfg {
+	uint32_t  stripeRdPathEn:1;
+	uint32_t  /* reserved */ : 3;
+	uint32_t  encYWrPathEn:1;
+	uint32_t  encCbcrWrPathEn:1;
+	uint32_t  viewYWrPathEn:1;
+	uint32_t  viewCbcrWrPathEn:1;
+	uint32_t  rawPixelDataSize:2;
+	uint32_t  rawWritePathSelect:2;
+	uint32_t  /* reserved */ : 20;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_axi_out_cfg {
+	uint32_t  out2YPingAddr:32;
+	uint32_t  out2YPongAddr:32;
+	uint32_t  out2YImageHeight:12;
+	uint32_t  /* reserved */ : 4;
+	uint32_t  out2YImageWidthin64bit:10;
+	uint32_t  /* reserved */ : 6;
+	uint32_t  out2YBurstLength:2;
+	uint32_t  /* reserved */ : 2;
+	uint32_t  out2YNumRows:12;
+	uint32_t  out2YRowIncrementIn64bit:12;
+	uint32_t  /* reserved */ : 4;
+	uint32_t  out2CbcrPingAddr:32;
+	uint32_t  out2CbcrPongAddr:32;
+	uint32_t  out2CbcrImageHeight:12;
+	uint32_t  /* reserved */ : 4;
+	uint32_t  out2CbcrImageWidthIn64bit:10;
+	uint32_t  /* reserved */ : 6;
+	uint32_t  out2CbcrBurstLength:2;
+	uint32_t  /* reserved */ : 2;
+	uint32_t  out2CbcrNumRows:12;
+	uint32_t  out2CbcrRowIncrementIn64bit:12;
+	uint32_t  /* reserved */ : 4;
+	uint32_t  out1YPingAddr:32;
+	uint32_t  out1YPongAddr:32;
+	uint32_t  out1YImageHeight:12;
+	uint32_t  /* reserved */ : 4;
+	uint32_t  out1YImageWidthin64bit:10;
+	uint32_t  /* reserved */ : 6;
+	uint32_t  out1YBurstLength:2;
+	uint32_t  /* reserved */ : 2;
+	uint32_t  out1YNumRows:12;
+	uint32_t  out1YRowIncrementIn64bit:12;
+	uint32_t  /* reserved */ : 4;
+	uint32_t  out1CbcrPingAddr:32;
+	uint32_t  out1CbcrPongAddr:32;
+	uint32_t  out1CbcrImageHeight:12;
+	uint32_t  /* reserved */ : 4;
+	uint32_t  out1CbcrImageWidthIn64bit:10;
+	uint32_t  /* reserved */ : 6;
+	uint32_t  out1CbcrBurstLength:2;
+	uint32_t  /* reserved */ : 2;
+	uint32_t  out1CbcrNumRows:12;
+	uint32_t  out1CbcrRowIncrementIn64bit:12;
+	uint32_t  /* reserved */ : 4;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_output_clamp_cfg {
+	/* Output Clamp Maximums */
+	uint32_t yChanMax:8;
+	uint32_t cbChanMax:8;
+	uint32_t crChanMax:8;
+	uint32_t /* reserved */ : 8;
+	/* Output Clamp Minimums */
+	uint32_t yChanMin:8;
+	uint32_t cbChanMin:8;
+	uint32_t crChanMin:8;
+	uint32_t /* reserved */ : 8;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_fov_crop_cfg {
+	uint32_t lastPixel:12;
+	uint32_t /* reserved */ : 4;
+	uint32_t firstPixel:12;
+	uint32_t /* reserved */ : 4;
+
+	/* FOV Corp, Part 2 */
+	uint32_t lastLine:12;
+	uint32_t /* reserved */ : 4;
+	uint32_t firstLine:12;
+	uint32_t /* reserved */ : 4;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_FRAME_SKIP_UpdateCmdType {
+	uint32_t  yPattern:32;
+	uint32_t  cbcrPattern:32;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_frame_skip_cfg {
+	/* Frame Drop Enc (output2) */
+	uint32_t output2YPeriod:5;
+	uint32_t /* reserved */	: 27;
+	uint32_t output2CbCrPeriod:5;
+	uint32_t /* reserved */ : 27;
+	uint32_t output2YPattern:32;
+	uint32_t output2CbCrPattern:32;
+	/* Frame Drop View (output1) */
+	uint32_t output1YPeriod:5;
+	uint32_t /* reserved */ : 27;
+	uint32_t output1CbCrPeriod:5;
+	uint32_t /* reserved */ : 27;
+	uint32_t output1YPattern:32;
+	uint32_t output1CbCrPattern:32;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_main_scaler_cfg {
+	/* Scaler Enable Config */
+	uint32_t hEnable:1;
+	uint32_t vEnable:1;
+	uint32_t /* reserved */ : 30;
+	/* Scale H Image Size Config */
+	uint32_t inWidth:12;
+	uint32_t /* reserved */ : 4;
+	uint32_t outWidth:12;
+	uint32_t /* reserved */ : 4;
+	/* Scale H Phase Config */
+	uint32_t horizPhaseMult:18;
+	uint32_t /* reserved */ : 2;
+	uint32_t horizInterResolution:2;
+	uint32_t /* reserved */ : 10;
+	/* Scale H Stripe Config */
+	uint32_t horizMNInit:12;
+	uint32_t /* reserved */ : 4;
+	uint32_t horizPhaseInit:15;
+	uint32_t /* reserved */ : 1;
+	/* Scale V Image Size Config */
+	uint32_t inHeight:12;
+	uint32_t /* reserved */ : 4;
+	uint32_t outHeight:12;
+	uint32_t /* reserved */ : 4;
+	/* Scale V Phase Config */
+	uint32_t vertPhaseMult:18;
+	uint32_t /* reserved */ : 2;
+	uint32_t vertInterResolution:2;
+	uint32_t /* reserved */ : 10;
+	/* Scale V Stripe Config */
+	uint32_t vertMNInit:12;
+	uint32_t /* reserved */ : 4;
+	uint32_t vertPhaseInit:15;
+	uint32_t /* reserved */ : 1;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_scaler2_cfg {
+	/* Scaler   Enable Config */
+	uint32_t  hEnable:1;
+	uint32_t  vEnable:1;
+	uint32_t  /* reserved */ : 30;
+	/* Scaler   H Image Size Config */
+	uint32_t  inWidth:12;
+	uint32_t  /* reserved */ : 4;
+	uint32_t  outWidth:12;
+	uint32_t  /* reserved */ : 4;
+	/* Scaler   H Phase Config */
+	uint32_t  horizPhaseMult:18;
+	uint32_t  /* reserved */ : 2;
+	uint32_t  horizInterResolution:2;
+	uint32_t  /* reserved */ : 10;
+	/* Scaler   V Image Size Config */
+	uint32_t  inHeight:12;
+	uint32_t  /* reserved */ : 4;
+	uint32_t  outHeight:12;
+	uint32_t  /* reserved */ : 4;
+	/* Scaler   V Phase Config */
+	uint32_t  vertPhaseMult:18;
+	uint32_t  /* reserved */ : 2;
+	uint32_t  vertInterResolution:2;
+	uint32_t  /* reserved */ : 10;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_rolloff_cfg {
+	/* Rolloff 0 Config */
+	uint32_t  gridWidth:9;
+	uint32_t  gridHeight:9;
+	uint32_t  yDelta:9;
+	uint32_t  /* reserved */ : 5;
+	/* Rolloff 1 Config*/
+	uint32_t  gridX:4;
+	uint32_t  gridY:4;
+	uint32_t  pixelX:9;
+	uint32_t  /* reserved */ : 3;
+	uint32_t  pixelY:9;
+	uint32_t  /* reserved */ : 3;
+	/* Rolloff 2 Config */
+	uint32_t  yDeltaAccum:12;
+	uint32_t  /* reserved */ : 20;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_asf_update {
+	/* ASF Config Command */
+	uint32_t smoothEnable:1;
+	uint32_t sharpMode:2;
+	uint32_t /* reserved */ : 1;
+	uint32_t smoothCoeff1:4;
+	uint32_t smoothCoeff0:8;
+	uint32_t pipeFlushCount:12;
+	uint32_t pipeFlushOvd:1;
+	uint32_t flushHaltOvd:1;
+	uint32_t cropEnable:1;
+	uint32_t /* reserved */ : 1;
+	/* Sharpening Config 0 */
+	uint32_t sharpThresholdE1:7;
+	uint32_t /* reserved */ : 1;
+	uint32_t sharpDegreeK1:5;
+	uint32_t /* reserved */ : 3;
+	uint32_t sharpDegreeK2:5;
+	uint32_t /* reserved */ : 3;
+	uint32_t normalizeFactor:7;
+	uint32_t /* reserved */ : 1;
+	/* Sharpening Config 1 */
+	uint32_t sharpThresholdE2:8;
+	uint32_t sharpThresholdE3:8;
+	uint32_t sharpThresholdE4:8;
+	uint32_t sharpThresholdE5:8;
+	/* Sharpening Coefficients 0 */
+	uint32_t F1Coeff0:6;
+	uint32_t F1Coeff1:6;
+	uint32_t F1Coeff2:6;
+	uint32_t F1Coeff3:6;
+	uint32_t F1Coeff4:6;
+	uint32_t /* reserved */ : 2;
+	/* Sharpening Coefficients 1 */
+	uint32_t F1Coeff5:6;
+	uint32_t F1Coeff6:6;
+	uint32_t F1Coeff7:6;
+	uint32_t F1Coeff8:7;
+	uint32_t /* reserved */ : 7;
+	/* Sharpening Coefficients 2 */
+	uint32_t F2Coeff0:6;
+	uint32_t F2Coeff1:6;
+	uint32_t F2Coeff2:6;
+	uint32_t F2Coeff3:6;
+	uint32_t F2Coeff4:6;
+	uint32_t /* reserved */ : 2;
+	/* Sharpening Coefficients 3 */
+	uint32_t F2Coeff5:6;
+	uint32_t F2Coeff6:6;
+	uint32_t F2Coeff7:6;
+	uint32_t F2Coeff8:7;
+	uint32_t /* reserved */ : 7;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_asfcrop_cfg {
+	/* ASF Crop Width Config */
+	uint32_t lastPixel:12;
+	uint32_t /* reserved */ : 4;
+	uint32_t firstPixel:12;
+	uint32_t /* reserved */ : 4;
+	/* ASP Crop Height Config */
+	uint32_t lastLine:12;
+	uint32_t /* reserved */ : 4;
+	uint32_t firstLine:12;
+	uint32_t /* reserved */ : 4;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_chroma_suppress_cfg {
+	/* Chroma Suppress 0 Config */
+	uint32_t m1:8;
+	uint32_t m3:8;
+	uint32_t n1:3;
+	uint32_t /* reserved */ : 1;
+	uint32_t n3:3;
+	uint32_t /* reserved */ : 9;
+	/* Chroma Suppress 1 Config */
+	uint32_t mm1:8;
+	uint32_t nn1:3;
+	uint32_t /* reserved */ : 21;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_chromasubsample_cfg {
+	/* Chroma Subsample Selection */
+	uint32_t  hCositedPhase:1;
+	uint32_t  vCositedPhase:1;
+	uint32_t  hCosited:1;
+	uint32_t  vCosited:1;
+	uint32_t  hsubSampleEnable:1;
+	uint32_t  vsubSampleEnable:1;
+	uint32_t  cropEnable:1;
+	uint32_t  /* reserved */ : 25;
+	uint32_t  cropWidthLastPixel:12;
+	uint32_t  /* reserved */ : 4;
+	uint32_t  cropWidthFirstPixel:12;
+	uint32_t  /* reserved */ : 4;
+	uint32_t  cropHeightLastLine:12;
+	uint32_t  /* reserved */ : 4;
+	uint32_t  cropHeightFirstLine:12;
+	uint32_t  /* reserved */ : 4;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_blacklevel_cfg {
+	/* Black Even-Even Value Config */
+	uint32_t    evenEvenAdjustment:9;
+	uint32_t   /* reserved */ : 23;
+	/* Black Even-Odd Value Config */
+	uint32_t    evenOddAdjustment:9;
+	uint32_t   /* reserved */ : 23;
+	/* Black Odd-Even Value Config */
+	uint32_t    oddEvenAdjustment:9;
+	uint32_t   /* reserved */ : 23;
+	/* Black Odd-Odd Value Config */
+	uint32_t    oddOddAdjustment:9;
+	uint32_t   /* reserved */ : 23;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_demux_cfg {
+	/* Demux Gain 0 Config */
+	uint32_t  ch0EvenGain:10;
+	uint32_t  /* reserved */ : 6;
+	uint32_t  ch0OddGain:10;
+	uint32_t  /* reserved */ : 6;
+	/* Demux Gain 1 Config */
+	uint32_t  ch1Gain:10;
+	uint32_t  /* reserved */ : 6;
+	uint32_t  ch2Gain:10;
+	uint32_t  /* reserved */ : 6;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_bps_info {
+  uint32_t greenBadPixelCount:8;
+  uint32_t /* reserved */ : 8;
+  uint32_t RedBlueBadPixelCount:8;
+  uint32_t /* reserved */ : 8;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_demosaic_cfg {
+	/* Demosaic Config */
+	uint32_t abfEnable:1;
+	uint32_t badPixelCorrEnable:1;
+	uint32_t forceAbfOn:1;
+	uint32_t /* reserved */ : 1;
+	uint32_t abfShift:4;
+	uint32_t fminThreshold:7;
+	uint32_t /* reserved */ : 1;
+	uint32_t fmaxThreshold:7;
+	uint32_t /* reserved */ : 5;
+	uint32_t slopeShift:3;
+	uint32_t /* reserved */ : 1;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_demosaic_bpc_cfg {
+	/* Demosaic BPC Config 0 */
+	uint32_t blueDiffThreshold:12;
+	uint32_t redDiffThreshold:12;
+	uint32_t /* reserved */ : 8;
+	/* Demosaic BPC Config 1 */
+	uint32_t greenDiffThreshold:12;
+	uint32_t /* reserved */ : 20;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_demosaic_abf_cfg {
+	/* Demosaic ABF Config 0 */
+	uint32_t lpThreshold:10;
+	uint32_t /* reserved */ : 22;
+	/* Demosaic ABF Config 1 */
+	uint32_t ratio:4;
+	uint32_t minValue:10;
+	uint32_t /* reserved */ : 2;
+	uint32_t maxValue:10;
+	uint32_t /* reserved */ : 6;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_color_correction_cfg {
+	/* Color Corr. Coefficient 0 Config */
+	uint32_t   c0:12;
+	uint32_t   /* reserved */ : 20;
+	/* Color Corr. Coefficient 1 Config */
+	uint32_t   c1:12;
+	uint32_t   /* reserved */ : 20;
+	/* Color Corr. Coefficient 2 Config */
+	uint32_t   c2:12;
+	uint32_t   /* reserved */ : 20;
+	/* Color Corr. Coefficient 3 Config */
+	uint32_t   c3:12;
+	uint32_t   /* reserved */ : 20;
+	/* Color Corr. Coefficient 4 Config */
+	uint32_t   c4:12;
+	uint32_t   /* reserved */ : 20;
+	/* Color Corr. Coefficient 5 Config */
+	uint32_t   c5:12;
+	uint32_t   /* reserved */ : 20;
+	/* Color Corr. Coefficient 6 Config */
+	uint32_t   c6:12;
+	uint32_t   /* reserved */ : 20;
+	/* Color Corr. Coefficient 7 Config */
+	uint32_t   c7:12;
+	uint32_t   /* reserved */ : 20;
+	/* Color Corr. Coefficient 8 Config */
+	uint32_t   c8:12;
+	uint32_t   /* reserved */ : 20;
+	/* Color Corr. Offset 0 Config */
+	uint32_t   k0:11;
+	uint32_t   /* reserved */ : 21;
+	/* Color Corr. Offset 1 Config */
+	uint32_t   k1:11;
+	uint32_t   /* reserved */ : 21;
+	/* Color Corr. Offset 2 Config */
+	uint32_t   k2:11;
+	uint32_t   /* reserved */ : 21;
+	/* Color Corr. Coefficient Q Config */
+	uint32_t   coefQFactor:2;
+	uint32_t   /* reserved */ : 30;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_LumaAdaptation_ConfigCmdType {
+	/* LA Config */
+	uint32_t   lutBankSelect:1;
+	uint32_t   /* reserved */ : 31;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_wb_cfg {
+	/* WB Config */
+	uint32_t ch0Gain:9;
+	uint32_t ch1Gain:9;
+	uint32_t ch2Gain:9;
+	uint32_t /* reserved */ : 5;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_GammaLutSelect_ConfigCmdType {
+	/* LUT Bank Select Config */
+	uint32_t   ch0BankSelect:1;
+	uint32_t   ch1BankSelect:1;
+	uint32_t   ch2BankSelect:1;
+	uint32_t   /* reserved */ : 29;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_chroma_enhance_cfg {
+	/* Chroma Enhance A Config */
+	uint32_t ap:11;
+	uint32_t /* reserved */ : 5;
+	uint32_t am:11;
+	uint32_t /* reserved */ : 5;
+	/* Chroma Enhance B Config */
+	uint32_t bp:11;
+	uint32_t /* reserved */ : 5;
+	uint32_t bm:11;
+	uint32_t /* reserved */ : 5;
+	/* Chroma Enhance C Config */
+	uint32_t cp:11;
+	uint32_t /* reserved */ : 5;
+	uint32_t cm:11;
+	uint32_t /* reserved */ : 5;
+	/* Chroma Enhance D Config */
+	uint32_t dp:11;
+	uint32_t /* reserved */ : 5;
+	uint32_t dm:11;
+	uint32_t /* reserved */ : 5;
+	/* Chroma Enhance K Config */
+	uint32_t kcb:11;
+	uint32_t /* reserved */ : 5;
+	uint32_t kcr:11;
+	uint32_t /* reserved */ : 5;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_color_convert_cfg {
+	/* Conversion Coefficient 0 */
+	uint32_t v0:12;
+	uint32_t /* reserved */ : 20;
+	/* Conversion Coefficient 1 */
+	uint32_t v1:12;
+	uint32_t /* reserved */ : 20;
+	/* Conversion Coefficient 2 */
+	uint32_t v2:12;
+	uint32_t /* reserved */ : 20;
+	/* Conversion Offset */
+	uint32_t ConvertOffset:8;
+	uint32_t /* reserved */ : 24;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_SyncTimer_ConfigCmdType {
+	/* Timer Line Start Config */
+	uint32_t       timerLineStart:12;
+	uint32_t       /* reserved */ : 20;
+	/* Timer Pixel Start Config */
+	uint32_t       timerPixelStart:18;
+	uint32_t       /* reserved */ : 14;
+	/* Timer Pixel Duration Config */
+	uint32_t       timerPixelDuration:28;
+	uint32_t       /* reserved */ : 4;
+	/* Sync Timer Polarity Config */
+	uint32_t       timer0Polarity:1;
+	uint32_t       timer1Polarity:1;
+	uint32_t       timer2Polarity:1;
+	uint32_t       /* reserved */ : 29;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_AsyncTimer_ConfigCmdType {
+	/* Async Timer Config 0 */
+	uint32_t     inactiveLength:20;
+	uint32_t     numRepetition:10;
+	uint32_t     /* reserved */ : 1;
+	uint32_t     polarity:1;
+	/* Async Timer Config 1 */
+	uint32_t     activeLength:20;
+	uint32_t     /* reserved */ : 12;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_AWBAEStatistics_ConfigCmdType {
+	/* AWB autoexposure Config */
+	uint32_t    aeRegionConfig:1;
+	uint32_t    aeSubregionConfig:1;
+	uint32_t    /* reserved */ : 14;
+	uint32_t    awbYMin:8;
+	uint32_t    awbYMax:8;
+	/* AXW Header */
+	uint32_t    axwHeader:8;
+	uint32_t    /* reserved */ : 24;
+	/* AWB Mconfig */
+	uint32_t    m4:8;
+	uint32_t    m3:8;
+	uint32_t    m2:8;
+	uint32_t    m1:8;
+	/* AWB Cconfig */
+	uint32_t    c2:12;
+	uint32_t    /* reserved */ : 4;
+	uint32_t    c1:12;
+	uint32_t    /* reserved */ : 4;
+	/* AWB Cconfig 2 */
+	uint32_t    c4:12;
+	uint32_t    /* reserved */ : 4;
+	uint32_t    c3:12;
+	uint32_t    /* reserved */ : 4;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_TestGen_ConfigCmdType {
+	/* HW Test Gen Config */
+	uint32_t   numFrame:10;
+	uint32_t   /* reserved */ : 2;
+	uint32_t   pixelDataSelect:1;
+	uint32_t   systematicDataSelect:1;
+	uint32_t   /* reserved */ : 2;
+	uint32_t   pixelDataSize:2;
+	uint32_t   hsyncEdge:1;
+	uint32_t   vsyncEdge:1;
+	uint32_t   /* reserved */ : 12;
+	/* HW Test Gen Image Config */
+	uint32_t   imageWidth:14;
+	uint32_t   /* reserved */ : 2;
+	uint32_t   imageHeight:14;
+	uint32_t   /* reserved */ : 2;
+	/* SOF Offset Config */
+	uint32_t   sofOffset:24;
+	uint32_t   /* reserved */ : 8;
+	/* EOF NOffset Config */
+	uint32_t   eofNOffset:24;
+	uint32_t   /* reserved */ : 8;
+	/* SOL Offset Config */
+	uint32_t   solOffset:9;
+	uint32_t   /* reserved */ : 23;
+	/* EOL NOffset Config */
+	uint32_t   eolNOffset:9;
+	uint32_t   /* reserved */ : 23;
+	/* HBI Config */
+	uint32_t   hBlankInterval:14;
+	uint32_t   /* reserved */ : 18;
+	/* VBL Config */
+	uint32_t   vBlankInterval:14;
+	uint32_t   /* reserved */ : 2;
+	uint32_t   vBlankIntervalEnable:1;
+	uint32_t   /* reserved */ : 15;
+	/* SOF Dummy Line Config */
+	uint32_t   sofDummy:8;
+	uint32_t   /* reserved */ : 24;
+	/* EOF Dummy Line Config */
+	uint32_t   eofDummy:8;
+	uint32_t   /* reserved */ : 24;
+	/* Color Bars Config */
+	uint32_t   unicolorBarSelect:3;
+	uint32_t   /* reserved */ : 1;
+	uint32_t   unicolorBarEnable:1;
+	uint32_t   splitEnable:1;
+	uint32_t   pixelPattern:2;
+	uint32_t   rotatePeriod:6;
+	uint32_t   /* reserved */ : 18;
+	/* Random Config */
+	uint32_t   randomSeed:16;
+	uint32_t   /* reserved */ : 16;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_Bus_Pm_ConfigCmdType {
+	/* VFE Bus Performance Monitor Config */
+	uint32_t  output2YWrPmEnable:1;
+	uint32_t  output2CbcrWrPmEnable:1;
+	uint32_t  output1YWrPmEnable:1;
+	uint32_t  output1CbcrWrPmEnable:1;
+	uint32_t  /* reserved */ : 28;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_asf_info {
+	/* asf max edge  */
+	uint32_t maxEdge:13;
+	uint32_t /* reserved */ : 3;
+	/* HBi count  */
+	uint32_t HBICount:12;
+	uint32_t /* reserved */ : 4;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_camif_stats {
+  uint32_t  pixelCount:14;
+  uint32_t  /* reserved */ : 2;
+  uint32_t  lineCount:14;
+  uint32_t  /* reserved */ : 1;
+  uint32_t  camifHalt:1;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_StatsCmdType {
+	uint32_t  autoFocusEnable:1;
+	uint32_t  axwEnable:1;
+	uint32_t  histEnable:1;
+	uint32_t  clearHistEnable:1;
+	uint32_t  histAutoClearEnable:1;
+	uint32_t  colorConversionEnable:1;
+	uint32_t  /* reserved */ : 26;
+} __attribute__((packed, aligned(4)));
+
+
+struct vfe_statsframe {
+	uint32_t lastPixel:12;
+	uint32_t /* reserved */ : 4;
+	uint32_t lastLine:12;
+	uint32_t /* reserved */ : 4;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_busstats_wrprio {
+	uint32_t afBusPriority:4;
+	uint32_t awbBusPriority:4;
+	uint32_t histBusPriority:4;
+	uint32_t afBusPriorityEn:1;
+	uint32_t awbBusPriorityEn:1;
+	uint32_t histBusPriorityEn:1;
+	uint32_t /* reserved */ : 17;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_statsaf_update {
+	/* VFE_STATS_AF_CFG */
+	uint32_t windowVOffset:12;
+	uint32_t /* reserved */ : 4;
+	uint32_t windowHOffset:12;
+	uint32_t /* reserved */ : 3;
+	uint32_t windowMode:1;
+
+	/* VFE_STATS_AF_DIM */
+	uint32_t windowHeight:12;
+	uint32_t /* reserved */ : 4;
+	uint32_t windowWidth:12;
+	uint32_t /* reserved */ : 4;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_statsaf_cfg {
+	/* VFE_STATS_AF_GRID_0 */
+	uint32_t  entry00:8;
+	uint32_t  entry01:8;
+	uint32_t  entry02:8;
+	uint32_t  entry03:8;
+
+	/* VFE_STATS_AF_GRID_1 */
+	uint32_t  entry10:8;
+	uint32_t  entry11:8;
+	uint32_t  entry12:8;
+	uint32_t  entry13:8;
+
+	/* VFE_STATS_AF_GRID_2 */
+	uint32_t  entry20:8;
+	uint32_t  entry21:8;
+	uint32_t  entry22:8;
+	uint32_t  entry23:8;
+
+	/* VFE_STATS_AF_GRID_3 */
+	uint32_t  entry30:8;
+	uint32_t  entry31:8;
+	uint32_t  entry32:8;
+	uint32_t  entry33:8;
+
+	/* VFE_STATS_AF_HEADER */
+	uint32_t  afHeader:8;
+	uint32_t  /* reserved */ : 24;
+	/*  VFE_STATS_AF_COEF0 */
+	uint32_t  a00:5;
+	uint32_t  a04:5;
+	uint32_t  fvMax:11;
+	uint32_t  fvMetric:1;
+	uint32_t  /* reserved */ : 10;
+
+	/* VFE_STATS_AF_COEF1 */
+	uint32_t  a20:5;
+	uint32_t  a21:5;
+	uint32_t  a22:5;
+	uint32_t  a23:5;
+	uint32_t  a24:5;
+	uint32_t  /* reserved */ : 7;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_statsawbae_update {
+	uint32_t  aeRegionCfg:1;
+	uint32_t  aeSubregionCfg:1;
+	uint32_t  /* reserved */ : 14;
+	uint32_t  awbYMin:8;
+	uint32_t  awbYMax:8;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_statsaxw_hdr_cfg {
+	/* Stats AXW Header Config */
+	uint32_t axwHeader:8;
+	uint32_t /* reserved */ : 24;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_statsawb_update {
+	/* AWB MConfig */
+	uint32_t  m4:8;
+	uint32_t  m3:8;
+	uint32_t  m2:8;
+	uint32_t  m1:8;
+
+	/* AWB CConfig1 */
+	uint32_t  c2:12;
+	uint32_t  /* reserved */ : 4;
+	uint32_t  c1:12;
+	uint32_t  /* reserved */ : 4;
+
+	/* AWB CConfig2 */
+	uint32_t  c4:12;
+	uint32_t  /* reserved */ : 4;
+	uint32_t  c3:12;
+	uint32_t  /* reserved */ : 4;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_SyncTimerCmdType {
+	uint32_t  hsyncCount:12;
+	uint32_t  /* reserved */ : 20;
+	uint32_t  pclkCount:18;
+	uint32_t  /* reserved */ : 14;
+	uint32_t  outputDuration:28;
+	uint32_t  /* reserved */ : 4;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_AsyncTimerCmdType {
+	/*  config 0 */
+	uint32_t    inactiveCount:20;
+	uint32_t    repeatCount:10;
+	uint32_t    /* reserved */ : 1;
+	uint32_t    polarity:1;
+	/*  config 1 */
+	uint32_t    activeCount:20;
+	uint32_t    /* reserved */ : 12;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_AxiInputCmdType {
+	uint32_t   stripeStartAddr0:32;
+	uint32_t   stripeStartAddr1:32;
+	uint32_t   stripeStartAddr2:32;
+	uint32_t   stripeStartAddr3:32;
+
+	uint32_t   ySize:12;
+	uint32_t   yOffsetDelta:12;
+	uint32_t   /* reserved */ : 8;
+
+	/* bus_stripe_rd_hSize */
+	uint32_t   /* reserved */ : 16;
+	uint32_t   xSizeWord:10;
+	uint32_t   /* reserved */ : 6;
+
+	/* bus_stripe_rd_buffer_cfg */
+	uint32_t   burstLength:2;
+	uint32_t   /* reserved */ : 2;
+	uint32_t   NumOfRows:12;
+	uint32_t   RowIncrement:12;
+	uint32_t   /* reserved */ : 4;
+
+	/* bus_stripe_rd_unpack_cfg */
+	uint32_t   mainUnpackHeight:12;
+	uint32_t   mainUnpackWidth:13;
+	uint32_t   mainUnpackHbiSel:3;
+	uint32_t   mainUnpackPhase:3;
+	uint32_t   /* reserved */ : 1;
+
+	/* bus_stripe_rd_unpack */
+	uint32_t   unpackPattern:32;
+
+	/* bus_stripe_rd_pad_size */
+	uint32_t   padLeft:7;
+	uint32_t   /* reserved */ : 1;
+	uint32_t   padRight:7;
+	uint32_t   /* reserved */ : 1;
+	uint32_t   padTop:7;
+	uint32_t   /* reserved */ : 1;
+	uint32_t   padBottom:7;
+	uint32_t   /* reserved */ : 1;
+
+	/* bus_stripe_rd_pad_L_unpack */
+	uint32_t   leftUnpackPattern0:4;
+	uint32_t   leftUnpackPattern1:4;
+	uint32_t   leftUnpackPattern2:4;
+	uint32_t   leftUnpackPattern3:4;
+	uint32_t   leftUnpackStop0:1;
+	uint32_t   leftUnpackStop1:1;
+	uint32_t   leftUnpackStop2:1;
+	uint32_t   leftUnpackStop3:1;
+	uint32_t   /* reserved */ : 12;
+
+	/* bus_stripe_rd_pad_R_unpack */
+	uint32_t   rightUnpackPattern0:4;
+	uint32_t   rightUnpackPattern1:4;
+	uint32_t   rightUnpackPattern2:4;
+	uint32_t   rightUnpackPattern3:4;
+	uint32_t   rightUnpackStop0:1;
+	uint32_t   rightUnpackStop1:1;
+	uint32_t   rightUnpackStop2:1;
+	uint32_t   rightUnpackStop3:1;
+	uint32_t   /* reserved */ : 12;
+
+	/* bus_stripe_rd_pad_tb_unpack */
+	uint32_t   topUnapckPattern:4;
+	uint32_t   /* reserved */ : 12;
+	uint32_t   bottomUnapckPattern:4;
+	uint32_t   /* reserved */ : 12;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_AxiRdFragIrqEnable {
+	uint32_t stripeRdFragirq0Enable:1;
+	uint32_t stripeRdFragirq1Enable:1;
+	uint32_t stripeRdFragirq2Enable:1;
+	uint32_t stripeRdFragirq3Enable:1;
+	uint32_t   /* reserved */ : 28;
+} __attribute__((packed, aligned(4)));
+
+int vfe_cmd_init(struct msm_vfe_callback *, struct platform_device *, void *);
+void vfe_stats_af_stop(void);
+void vfe_stop(void);
+void vfe_update(void);
+int vfe_rgb_gamma_update(struct vfe_cmd_rgb_gamma_config *);
+int vfe_rgb_gamma_config(struct vfe_cmd_rgb_gamma_config *);
+void vfe_stats_wb_exp_ack(struct vfe_cmd_stats_wb_exp_ack *);
+void vfe_stats_af_ack(struct vfe_cmd_stats_af_ack *);
+void vfe_start(struct vfe_cmd_start *);
+void vfe_la_update(struct vfe_cmd_la_config *);
+void vfe_la_config(struct vfe_cmd_la_config *);
+void vfe_test_gen_start(struct vfe_cmd_test_gen_start *);
+void vfe_frame_skip_update(struct vfe_cmd_frame_skip_update *);
+void vfe_frame_skip_config(struct vfe_cmd_frame_skip_config *);
+void vfe_output_clamp_config(struct vfe_cmd_output_clamp_config *);
+void vfe_camif_frame_update(struct vfe_cmds_camif_frame *);
+void vfe_color_correction_config(struct vfe_cmd_color_correction_config *);
+void vfe_demosaic_abf_update(struct vfe_cmd_demosaic_abf_update *);
+void vfe_demosaic_bpc_update(struct vfe_cmd_demosaic_bpc_update *);
+void vfe_demosaic_config(struct vfe_cmd_demosaic_config *);
+void vfe_demux_channel_gain_update(struct vfe_cmd_demux_channel_gain_config *);
+void vfe_demux_channel_gain_config(struct vfe_cmd_demux_channel_gain_config *);
+void vfe_black_level_update(struct vfe_cmd_black_level_config *);
+void vfe_black_level_config(struct vfe_cmd_black_level_config *);
+void vfe_asf_update(struct vfe_cmd_asf_update *);
+void vfe_asf_config(struct vfe_cmd_asf_config *);
+void vfe_white_balance_config(struct vfe_cmd_white_balance_config *);
+void vfe_chroma_sup_config(struct vfe_cmd_chroma_suppression_config *);
+void vfe_roll_off_config(struct vfe_cmd_roll_off_config *);
+void vfe_chroma_subsample_config(struct vfe_cmd_chroma_subsample_config *);
+void vfe_chroma_enhan_config(struct vfe_cmd_chroma_enhan_config *);
+void vfe_scaler2cbcr_config(struct vfe_cmd_scaler2_config *);
+void vfe_scaler2y_config(struct vfe_cmd_scaler2_config *);
+void vfe_main_scaler_config(struct vfe_cmd_main_scaler_config *);
+void vfe_stats_wb_exp_stop(void);
+void vfe_stats_update_wb_exp(struct vfe_cmd_stats_wb_exp_update *);
+void vfe_stats_update_af(struct vfe_cmd_stats_af_update *);
+void vfe_stats_start_wb_exp(struct vfe_cmd_stats_wb_exp_start *);
+void vfe_stats_start_af(struct vfe_cmd_stats_af_start *);
+void vfe_stats_setting(struct vfe_cmd_stats_setting *);
+void vfe_axi_input_config(struct vfe_cmd_axi_input_config *);
+void vfe_axi_output_config(struct vfe_cmd_axi_output_config *);
+void vfe_camif_config(struct vfe_cmd_camif_config *);
+void vfe_fov_crop_config(struct vfe_cmd_fov_crop_config *);
+void vfe_get_hw_version(struct vfe_cmd_hw_version *);
+void vfe_reset(void);
+void vfe_cmd_release(struct platform_device *);
+void vfe_output_p_ack(struct vfe_cmd_output_ack *);
+void vfe_output_v_ack(struct vfe_cmd_output_ack *);
+#endif /* __MSM_VFE8X_REG_H__ */
diff --git a/drivers/media/video/msm/msm_vpe1.c b/drivers/media/video/msm/msm_vpe1.c
new file mode 100644
index 0000000..70b9448
--- /dev/null
+++ b/drivers/media/video/msm/msm_vpe1.c
@@ -0,0 +1,1446 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <mach/irqs.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include "msm_vpe1.h"
+#include <mach/msm_reqs.h>
+#include <linux/pm_qos_params.h>
+#include <linux/clk.h>
+#include <mach/clk.h>
+#include <asm/div64.h>
+
+static int vpe_enable(uint32_t);
+static int vpe_disable(void);
+static int vpe_update_scaler(struct video_crop_t *pcrop);
+static struct vpe_device_type  vpe_device_data;
+static struct vpe_device_type  *vpe_device;
+struct vpe_ctrl_type    *vpe_ctrl;
+char *vpe_general_cmd[] = {
+	"VPE_DUMMY_0",  /* 0 */
+	"VPE_SET_CLK",
+	"VPE_RESET",
+	"VPE_START",
+	"VPE_ABORT",
+	"VPE_OPERATION_MODE_CFG",  /* 5 */
+	"VPE_INPUT_PLANE_CFG",
+	"VPE_OUTPUT_PLANE_CFG",
+	"VPE_INPUT_PLANE_UPDATE",
+	"VPE_SCALE_CFG_TYPE",
+	"VPE_ROTATION_CFG_TYPE",  /* 10 */
+	"VPE_AXI_OUT_CFG",
+	"VPE_CMD_DIS_OFFSET_CFG",
+	"VPE_ENABLE",
+	"VPE_DISABLE",
+};
+static uint32_t orig_src_y, orig_src_cbcr;
+
+#define CHECKED_COPY_FROM_USER(in) {					\
+	if (copy_from_user((in), (void __user *)cmd->value,		\
+			cmd->length)) {					\
+		rc = -EFAULT;						\
+		break;							\
+	}								\
+}
+
+#define msm_dequeue_vpe(queue, member) ({			\
+	unsigned long flags;					\
+	struct msm_device_queue *__q = (queue);			\
+	struct msm_queue_cmd *qcmd = 0;				\
+	spin_lock_irqsave(&__q->lock, flags);			\
+	if (!list_empty(&__q->list)) {				\
+		__q->len--;					\
+		qcmd = list_first_entry(&__q->list,		\
+				struct msm_queue_cmd, member);	\
+		list_del_init(&qcmd->member);			\
+	}							\
+	spin_unlock_irqrestore(&__q->lock, flags);		\
+	qcmd;							\
+})
+
+/*
+static   struct vpe_cmd_type vpe_cmd[] = {
+		{VPE_DUMMY_0, 0},
+		{VPE_SET_CLK, 0},
+		{VPE_RESET, 0},
+		{VPE_START, 0},
+		{VPE_ABORT, 0},
+		{VPE_OPERATION_MODE_CFG, VPE_OPERATION_MODE_CFG_LEN},
+		{VPE_INPUT_PLANE_CFG, VPE_INPUT_PLANE_CFG_LEN},
+		{VPE_OUTPUT_PLANE_CFG, VPE_OUTPUT_PLANE_CFG_LEN},
+		{VPE_INPUT_PLANE_UPDATE, VPE_INPUT_PLANE_UPDATE_LEN},
+		{VPE_SCALE_CFG_TYPE, VPE_SCALER_CONFIG_LEN},
+		{VPE_ROTATION_CFG_TYPE, 0},
+		{VPE_AXI_OUT_CFG, 0},
+		{VPE_CMD_DIS_OFFSET_CFG, VPE_DIS_OFFSET_CFG_LEN},
+};
+*/
+
+static long long vpe_do_div(long long num, long long den)
+{
+	do_div(num, den);
+	return num;
+}
+
+static int vpe_start(void)
+{
+	/*  enable the frame irq, bit 0 = Display list 0 ROI done */
+	msm_io_w(1, vpe_device->vpebase + VPE_INTR_ENABLE_OFFSET);
+	msm_io_dump(vpe_device->vpebase + 0x10000, 0x250);
+	/* this triggers the operation. */
+	msm_io_w(1, vpe_device->vpebase + VPE_DL0_START_OFFSET);
+
+	return 0;
+}
+
+void vpe_reset_state_variables(void)
+{
+	/* initialize local variables for state control, etc.*/
+	vpe_ctrl->op_mode = 0;
+	vpe_ctrl->state = VPE_STATE_INIT;
+	spin_lock_init(&vpe_ctrl->tasklet_lock);
+	spin_lock_init(&vpe_ctrl->state_lock);
+	INIT_LIST_HEAD(&vpe_ctrl->tasklet_q);
+}
+
+static void vpe_config_axi_default(void)
+{
+	msm_io_w(0x25, vpe_device->vpebase + VPE_AXI_ARB_2_OFFSET);
+
+	CDBG("%s: yaddr %ld cbcraddr %ld", __func__,
+		 vpe_ctrl->out_y_addr, vpe_ctrl->out_cbcr_addr);
+
+	if (!vpe_ctrl->out_y_addr || !vpe_ctrl->out_cbcr_addr)
+		return;
+
+	msm_io_w(vpe_ctrl->out_y_addr,
+		vpe_device->vpebase + VPE_OUTP0_ADDR_OFFSET);
+	/* for video  CbCr address */
+	msm_io_w(vpe_ctrl->out_cbcr_addr,
+		vpe_device->vpebase + VPE_OUTP1_ADDR_OFFSET);
+
+}
+
+static int vpe_reset(void)
+{
+	uint32_t vpe_version;
+	uint32_t rc;
+
+	vpe_reset_state_variables();
+	vpe_version = msm_io_r(vpe_device->vpebase + VPE_HW_VERSION_OFFSET);
+	CDBG("vpe_version = 0x%x\n", vpe_version);
+
+	/* disable all interrupts.*/
+	msm_io_w(0, vpe_device->vpebase + VPE_INTR_ENABLE_OFFSET);
+	/* clear all pending interrupts*/
+	msm_io_w(0x1fffff, vpe_device->vpebase + VPE_INTR_CLEAR_OFFSET);
+
+	/* write sw_reset to reset the core. */
+	msm_io_w(0x10, vpe_device->vpebase + VPE_SW_RESET_OFFSET);
+
+	/* then poll the reset bit, it should be self-cleared. */
+	while (1) {
+		rc =
+		msm_io_r(vpe_device->vpebase + VPE_SW_RESET_OFFSET) & 0x10;
+		if (rc == 0)
+			break;
+	}
+
+	/*  at this point, hardware is reset. Then pogram to default
+		values. */
+	msm_io_w(VPE_AXI_RD_ARB_CONFIG_VALUE,
+			vpe_device->vpebase + VPE_AXI_RD_ARB_CONFIG_OFFSET);
+
+	msm_io_w(VPE_CGC_ENABLE_VALUE,
+			vpe_device->vpebase + VPE_CGC_EN_OFFSET);
+
+	msm_io_w(1, vpe_device->vpebase + VPE_CMD_MODE_OFFSET);
+
+	msm_io_w(VPE_DEFAULT_OP_MODE_VALUE,
+			vpe_device->vpebase + VPE_OP_MODE_OFFSET);
+
+	msm_io_w(VPE_DEFAULT_SCALE_CONFIG,
+			vpe_device->vpebase + VPE_SCALE_CONFIG_OFFSET);
+
+	vpe_config_axi_default();
+	return 0;
+}
+
+int msm_vpe_cfg_update(void *pinfo)
+{
+	uint32_t  rot_flag, rc = 0;
+	struct video_crop_t *pcrop = (struct video_crop_t *)pinfo;
+
+	rot_flag = msm_io_r(vpe_device->vpebase +
+						VPE_OP_MODE_OFFSET) & 0xE00;
+	if (pinfo != NULL) {
+		CDBG("Crop info in2_w = %d, in2_h = %d "
+			"out2_h = %d out2_w = %d \n", pcrop->in2_w,
+			pcrop->in2_h,
+			pcrop->out2_h, pcrop->out2_w);
+		rc = vpe_update_scaler(pcrop);
+	}
+	CDBG("return rc = %d rot_flag = %d\n", rc, rot_flag);
+	rc |= rot_flag;
+
+	return rc;
+}
+
+void vpe_update_scale_coef(uint32_t *p)
+{
+	uint32_t i, offset;
+	offset = *p;
+	for (i = offset; i < (VPE_SCALE_COEFF_NUM + offset); i++) {
+		msm_io_w(*(++p), vpe_device->vpebase + VPE_SCALE_COEFF_LSBn(i));
+		msm_io_w(*(++p), vpe_device->vpebase + VPE_SCALE_COEFF_MSBn(i));
+	}
+}
+
+void vpe_input_plane_config(uint32_t *p)
+{
+	msm_io_w(*p, vpe_device->vpebase + VPE_SRC_FORMAT_OFFSET);
+	msm_io_w(*(++p), vpe_device->vpebase + VPE_SRC_UNPACK_PATTERN1_OFFSET);
+	msm_io_w(*(++p), vpe_device->vpebase + VPE_SRC_IMAGE_SIZE_OFFSET);
+	msm_io_w(*(++p), vpe_device->vpebase + VPE_SRC_YSTRIDE1_OFFSET);
+	msm_io_w(*(++p), vpe_device->vpebase + VPE_SRC_SIZE_OFFSET);
+	vpe_ctrl->in_h_w = *p;
+	msm_io_w(*(++p), vpe_device->vpebase + VPE_SRC_XY_OFFSET);
+}
+
+void vpe_output_plane_config(uint32_t *p)
+{
+	msm_io_w(*p, vpe_device->vpebase + VPE_OUT_FORMAT_OFFSET);
+	msm_io_w(*(++p), vpe_device->vpebase + VPE_OUT_PACK_PATTERN1_OFFSET);
+	msm_io_w(*(++p), vpe_device->vpebase + VPE_OUT_YSTRIDE1_OFFSET);
+	msm_io_w(*(++p), vpe_device->vpebase + VPE_OUT_SIZE_OFFSET);
+	msm_io_w(*(++p), vpe_device->vpebase + VPE_OUT_XY_OFFSET);
+	vpe_ctrl->pcbcr_dis_offset = *(++p);
+}
+
+static int vpe_operation_config(uint32_t *p)
+{
+	uint32_t  outw, outh, temp;
+	msm_io_w(*p, vpe_device->vpebase + VPE_OP_MODE_OFFSET);
+
+	temp = msm_io_r(vpe_device->vpebase + VPE_OUT_SIZE_OFFSET);
+	outw = temp & 0xFFF;
+	outh = (temp & 0xFFF0000) >> 16;
+
+	if (*p++ & 0xE00) {
+		/* rotation enabled. */
+		vpe_ctrl->out_w = outh;
+		vpe_ctrl->out_h = outw;
+	} else {
+		vpe_ctrl->out_w = outw;
+		vpe_ctrl->out_h = outh;
+	}
+	vpe_ctrl->dis_en = *p;
+	return 0;
+}
+
+/* Later we can separate the rotation and scaler calc. If
+*  rotation is enabled, simply swap the destination dimension.
+*  And then pass the already swapped output size to this
+*  function. */
+static int vpe_update_scaler(struct video_crop_t *pcrop)
+{
+	uint32_t out_ROI_width, out_ROI_height;
+	uint32_t src_ROI_width, src_ROI_height;
+
+	uint32_t rc = 0;  /* default to no zoom. */
+	/*
+	* phase_step_x, phase_step_y, phase_init_x and phase_init_y
+	* are represented in fixed-point, unsigned 3.29 format
+	*/
+	uint32_t phase_step_x = 0;
+	uint32_t phase_step_y = 0;
+	uint32_t phase_init_x = 0;
+	uint32_t phase_init_y = 0;
+
+	uint32_t src_roi, src_x, src_y, src_xy, temp;
+	uint32_t yscale_filter_sel, xscale_filter_sel;
+	uint32_t scale_unit_sel_x, scale_unit_sel_y;
+	uint64_t numerator, denominator;
+
+	if ((pcrop->in2_w >= pcrop->out2_w) &&
+		(pcrop->in2_h >= pcrop->out2_h)) {
+		CDBG(" =======VPE no zoom needed.\n");
+
+		temp = msm_io_r(vpe_device->vpebase + VPE_OP_MODE_OFFSET)
+		& 0xfffffffc;
+		msm_io_w(temp, vpe_device->vpebase + VPE_OP_MODE_OFFSET);
+
+
+		msm_io_w(0, vpe_device->vpebase + VPE_SRC_XY_OFFSET);
+
+		CDBG("vpe_ctrl->in_h_w = %d \n", vpe_ctrl->in_h_w);
+		msm_io_w(vpe_ctrl->in_h_w , vpe_device->vpebase +
+				VPE_SRC_SIZE_OFFSET);
+
+		return rc;
+	}
+	/* If fall through then scaler is needed.*/
+
+	CDBG("========VPE zoom needed.\n");
+	/* assumption is both direction need zoom. this can be
+	improved. */
+	temp =
+		msm_io_r(vpe_device->vpebase + VPE_OP_MODE_OFFSET) | 0x3;
+	msm_io_w(temp, vpe_device->vpebase + VPE_OP_MODE_OFFSET);
+
+	src_ROI_width = pcrop->in2_w;
+	src_ROI_height = pcrop->in2_h;
+	out_ROI_width = pcrop->out2_w;
+	out_ROI_height = pcrop->out2_h;
+
+	CDBG("src w = 0x%x, h=0x%x, dst w = 0x%x, h =0x%x.\n",
+		src_ROI_width, src_ROI_height, out_ROI_width,
+		out_ROI_height);
+	src_roi = (src_ROI_height << 16) + src_ROI_width;
+
+	msm_io_w(src_roi, vpe_device->vpebase + VPE_SRC_SIZE_OFFSET);
+
+	src_x = (out_ROI_width - src_ROI_width)/2;
+	src_y = (out_ROI_height - src_ROI_height)/2;
+
+	CDBG("src_x = %d, src_y=%d.\n", src_x, src_y);
+
+	src_xy = src_y*(1<<16) + src_x;
+	msm_io_w(src_xy, vpe_device->vpebase +
+			VPE_SRC_XY_OFFSET);
+	CDBG("src_xy = %d, src_roi=%d.\n", src_xy, src_roi);
+
+	/* decide whether to use FIR or M/N for scaling */
+	if ((out_ROI_width == 1 && src_ROI_width < 4) ||
+		(src_ROI_width < 4 * out_ROI_width - 3))
+		scale_unit_sel_x = 0;/* use FIR scalar */
+	else
+		scale_unit_sel_x = 1;/* use M/N scalar */
+
+	if ((out_ROI_height == 1 && src_ROI_height < 4) ||
+		(src_ROI_height < 4 * out_ROI_height - 3))
+		scale_unit_sel_y = 0;/* use FIR scalar */
+	else
+		scale_unit_sel_y = 1;/* use M/N scalar */
+
+	/* calculate phase step for the x direction */
+
+	/* if destination is only 1 pixel wide,
+	the value of phase_step_x
+	is unimportant. Assigning phase_step_x to
+	src ROI width as an arbitrary value. */
+	if (out_ROI_width == 1)
+		phase_step_x = (uint32_t) ((src_ROI_width) <<
+						SCALER_PHASE_BITS);
+
+		/* if using FIR scalar */
+	else if (scale_unit_sel_x == 0) {
+
+		/* Calculate the quotient ( src_ROI_width - 1 )
+		/ ( out_ROI_width - 1)
+		with u3.29 precision. Quotient is rounded up to
+		the larger 29th decimal point. */
+		numerator = (uint64_t)(src_ROI_width - 1) <<
+			SCALER_PHASE_BITS;
+		/* never equals to 0 because of the
+		"(out_ROI_width == 1 )"*/
+		denominator = (uint64_t)(out_ROI_width - 1);
+		/* divide and round up to the larger 29th
+		decimal point. */
+		phase_step_x = (uint32_t) vpe_do_div((numerator +
+					denominator - 1), denominator);
+	} else if (scale_unit_sel_x == 1) { /* if M/N scalar */
+		/* Calculate the quotient ( src_ROI_width ) /
+		( out_ROI_width)
+		with u3.29 precision. Quotient is rounded down to the
+		smaller 29th decimal point. */
+		numerator = (uint64_t)(src_ROI_width) <<
+			SCALER_PHASE_BITS;
+		denominator = (uint64_t)(out_ROI_width);
+		phase_step_x =
+			(uint32_t) vpe_do_div(numerator, denominator);
+	}
+	/* calculate phase step for the y direction */
+
+	/* if destination is only 1 pixel wide, the value of
+		phase_step_x is unimportant. Assigning phase_step_x
+		to src ROI width as an arbitrary value. */
+	if (out_ROI_height == 1)
+		phase_step_y =
+		(uint32_t) ((src_ROI_height) << SCALER_PHASE_BITS);
+
+	/* if FIR scalar */
+	else if (scale_unit_sel_y == 0) {
+		/* Calculate the quotient ( src_ROI_height - 1 ) /
+		( out_ROI_height - 1)
+		with u3.29 precision. Quotient is rounded up to the
+		larger 29th decimal point. */
+		numerator = (uint64_t)(src_ROI_height - 1) <<
+			SCALER_PHASE_BITS;
+		/* never equals to 0 because of the "
+		( out_ROI_height == 1 )" case */
+		denominator = (uint64_t)(out_ROI_height - 1);
+		/* Quotient is rounded up to the larger
+		29th decimal point. */
+		phase_step_y =
+		(uint32_t) vpe_do_div(
+			(numerator + denominator - 1), denominator);
+	} else if (scale_unit_sel_y == 1) { /* if M/N scalar */
+		/* Calculate the quotient ( src_ROI_height )
+		/ ( out_ROI_height)
+		with u3.29 precision. Quotient is rounded down
+		to the smaller 29th decimal point. */
+		numerator = (uint64_t)(src_ROI_height) <<
+			SCALER_PHASE_BITS;
+		denominator = (uint64_t)(out_ROI_height);
+		phase_step_y = (uint32_t) vpe_do_div(
+			numerator, denominator);
+	}
+
+	/* decide which set of FIR coefficients to use */
+	if (phase_step_x > HAL_MDP_PHASE_STEP_2P50)
+		xscale_filter_sel = 0;
+	else if (phase_step_x > HAL_MDP_PHASE_STEP_1P66)
+		xscale_filter_sel = 1;
+	else if (phase_step_x > HAL_MDP_PHASE_STEP_1P25)
+		xscale_filter_sel = 2;
+	else
+		xscale_filter_sel = 3;
+
+	if (phase_step_y > HAL_MDP_PHASE_STEP_2P50)
+		yscale_filter_sel = 0;
+	else if (phase_step_y > HAL_MDP_PHASE_STEP_1P66)
+		yscale_filter_sel = 1;
+	else if (phase_step_y > HAL_MDP_PHASE_STEP_1P25)
+		yscale_filter_sel = 2;
+	else
+		yscale_filter_sel = 3;
+
+	/* calculate phase init for the x direction */
+
+	/* if using FIR scalar */
+	if (scale_unit_sel_x == 0) {
+		if (out_ROI_width == 1)
+			phase_init_x =
+				(uint32_t) ((src_ROI_width - 1) <<
+							SCALER_PHASE_BITS);
+		else
+			phase_init_x = 0;
+	} else if (scale_unit_sel_x == 1) /* M over N scalar  */
+		phase_init_x = 0;
+
+	/* calculate phase init for the y direction
+	if using FIR scalar */
+	if (scale_unit_sel_y == 0) {
+		if (out_ROI_height == 1)
+			phase_init_y =
+			(uint32_t) ((src_ROI_height -
+						1) << SCALER_PHASE_BITS);
+		else
+			phase_init_y = 0;
+	} else if (scale_unit_sel_y == 1) /* M over N scalar   */
+		phase_init_y = 0;
+
+	CDBG("phase step x = %d, step y = %d.\n",
+		 phase_step_x, phase_step_y);
+	CDBG("phase init x = %d, init y = %d.\n",
+		 phase_init_x, phase_init_y);
+
+	msm_io_w(phase_step_x, vpe_device->vpebase +
+			VPE_SCALE_PHASEX_STEP_OFFSET);
+	msm_io_w(phase_step_y, vpe_device->vpebase +
+			VPE_SCALE_PHASEY_STEP_OFFSET);
+
+	msm_io_w(phase_init_x, vpe_device->vpebase +
+			VPE_SCALE_PHASEX_INIT_OFFSET);
+
+	msm_io_w(phase_init_y, vpe_device->vpebase +
+			VPE_SCALE_PHASEY_INIT_OFFSET);
+
+	return 1;
+}
+
+static int vpe_update_scaler_with_dis(struct video_crop_t *pcrop,
+				struct dis_offset_type *dis_offset)
+{
+	uint32_t out_ROI_width, out_ROI_height;
+	uint32_t src_ROI_width, src_ROI_height;
+
+	uint32_t rc = 0;  /* default to no zoom. */
+	/*
+	* phase_step_x, phase_step_y, phase_init_x and phase_init_y
+	* are represented in fixed-point, unsigned 3.29 format
+	*/
+	uint32_t phase_step_x = 0;
+	uint32_t phase_step_y = 0;
+	uint32_t phase_init_x = 0;
+	uint32_t phase_init_y = 0;
+
+	uint32_t src_roi, temp;
+	int32_t  src_x, src_y, src_xy;
+	uint32_t yscale_filter_sel, xscale_filter_sel;
+	uint32_t scale_unit_sel_x, scale_unit_sel_y;
+	uint64_t numerator, denominator;
+	int32_t  zoom_dis_x, zoom_dis_y;
+
+	CDBG("%s: pcrop->in2_w = %d, pcrop->in2_h = %d\n", __func__,
+		 pcrop->in2_w, pcrop->in2_h);
+	CDBG("%s: pcrop->out2_w = %d, pcrop->out2_h = %d\n", __func__,
+		 pcrop->out2_w, pcrop->out2_h);
+
+	if ((pcrop->in2_w >= pcrop->out2_w) &&
+		(pcrop->in2_h >= pcrop->out2_h)) {
+		CDBG(" =======VPE no zoom needed, DIS is still enabled. \n");
+
+		temp = msm_io_r(vpe_device->vpebase + VPE_OP_MODE_OFFSET)
+		& 0xfffffffc;
+		msm_io_w(temp, vpe_device->vpebase + VPE_OP_MODE_OFFSET);
+
+		/* no zoom, use dis offset directly. */
+		src_xy = dis_offset->dis_offset_y * (1<<16) +
+			dis_offset->dis_offset_x;
+
+		msm_io_w(src_xy, vpe_device->vpebase + VPE_SRC_XY_OFFSET);
+
+		CDBG("vpe_ctrl->in_h_w = 0x%x \n", vpe_ctrl->in_h_w);
+		msm_io_w(vpe_ctrl->in_h_w, vpe_device->vpebase +
+				 VPE_SRC_SIZE_OFFSET);
+		return rc;
+	}
+	/* If fall through then scaler is needed.*/
+
+	CDBG("========VPE zoom needed + DIS enabled.\n");
+	/* assumption is both direction need zoom. this can be
+	 improved. */
+	temp = msm_io_r(vpe_device->vpebase +
+					VPE_OP_MODE_OFFSET) | 0x3;
+	msm_io_w(temp, vpe_device->vpebase +
+			VPE_OP_MODE_OFFSET);
+	zoom_dis_x = dis_offset->dis_offset_x *
+		pcrop->in2_w / pcrop->out2_w;
+	zoom_dis_y = dis_offset->dis_offset_y *
+		pcrop->in2_h / pcrop->out2_h;
+
+	src_x = zoom_dis_x + (pcrop->out2_w-pcrop->in2_w)/2;
+	src_y = zoom_dis_y + (pcrop->out2_h-pcrop->in2_h)/2;
+
+	out_ROI_width = vpe_ctrl->out_w;
+	out_ROI_height = vpe_ctrl->out_h;
+
+	src_ROI_width = out_ROI_width * pcrop->in2_w / pcrop->out2_w;
+	src_ROI_height = out_ROI_height * pcrop->in2_h / pcrop->out2_h;
+
+	/* clamp to output size.  This is because along
+	processing, we mostly do truncation, therefore
+	dis_offset tends to be
+	smaller values.  The intention was to make sure that the
+	offset does not exceed margin.   But in the case it could
+	result src_roi bigger, due to subtract a smaller value. */
+	CDBG("src w = 0x%x, h=0x%x, dst w = 0x%x, h =0x%x.\n",
+		src_ROI_width, src_ROI_height, out_ROI_width,
+		out_ROI_height);
+
+	src_roi = (src_ROI_height << 16) + src_ROI_width;
+
+	msm_io_w(src_roi, vpe_device->vpebase + VPE_SRC_SIZE_OFFSET);
+
+	CDBG("src_x = %d, src_y=%d.\n", src_x, src_y);
+
+	src_xy = src_y*(1<<16) + src_x;
+	msm_io_w(src_xy, vpe_device->vpebase +
+			VPE_SRC_XY_OFFSET);
+	CDBG("src_xy = 0x%x, src_roi=0x%x.\n", src_xy, src_roi);
+
+	/* decide whether to use FIR or M/N for scaling */
+	if ((out_ROI_width == 1 && src_ROI_width < 4) ||
+		(src_ROI_width < 4 * out_ROI_width - 3))
+		scale_unit_sel_x = 0;/* use FIR scalar */
+	else
+		scale_unit_sel_x = 1;/* use M/N scalar */
+
+	if ((out_ROI_height == 1 && src_ROI_height < 4) ||
+		(src_ROI_height < 4 * out_ROI_height - 3))
+		scale_unit_sel_y = 0;/* use FIR scalar */
+	else
+		scale_unit_sel_y = 1;/* use M/N scalar */
+	/* calculate phase step for the x direction */
+
+	/* if destination is only 1 pixel wide, the value of
+	phase_step_x is unimportant. Assigning phase_step_x
+	to src ROI width as an arbitrary value. */
+	if (out_ROI_width == 1)
+		phase_step_x = (uint32_t) ((src_ROI_width) <<
+							SCALER_PHASE_BITS);
+	else if (scale_unit_sel_x == 0) { /* if using FIR scalar */
+		/* Calculate the quotient ( src_ROI_width - 1 )
+		/ ( out_ROI_width - 1)with u3.29 precision.
+		Quotient is rounded up to the larger
+		29th decimal point. */
+		numerator =
+			(uint64_t)(src_ROI_width - 1) <<
+			SCALER_PHASE_BITS;
+		/* never equals to 0 because of the "
+		(out_ROI_width == 1 )"*/
+		denominator = (uint64_t)(out_ROI_width - 1);
+		/* divide and round up to the larger 29th
+		decimal point. */
+		phase_step_x = (uint32_t) vpe_do_div(
+			(numerator + denominator - 1), denominator);
+	} else if (scale_unit_sel_x == 1) { /* if M/N scalar */
+		/* Calculate the quotient
+		( src_ROI_width ) / ( out_ROI_width)
+		with u3.29 precision. Quotient is rounded
+		down to the smaller 29th decimal point. */
+		numerator = (uint64_t)(src_ROI_width) <<
+			SCALER_PHASE_BITS;
+		denominator = (uint64_t)(out_ROI_width);
+		phase_step_x =
+			(uint32_t) vpe_do_div(numerator, denominator);
+	}
+	/* calculate phase step for the y direction */
+
+	/* if destination is only 1 pixel wide, the value of
+		phase_step_x is unimportant. Assigning phase_step_x
+		to src ROI width as an arbitrary value. */
+	if (out_ROI_height == 1)
+		phase_step_y =
+		(uint32_t) ((src_ROI_height) << SCALER_PHASE_BITS);
+	else if (scale_unit_sel_y == 0) { /* if FIR scalar */
+		/* Calculate the quotient
+		( src_ROI_height - 1 ) / ( out_ROI_height - 1)
+		with u3.29 precision. Quotient is rounded up to the
+		larger 29th decimal point. */
+		numerator = (uint64_t)(src_ROI_height - 1) <<
+			SCALER_PHASE_BITS;
+		/* never equals to 0 because of the
+		"( out_ROI_height == 1 )" case */
+		denominator = (uint64_t)(out_ROI_height - 1);
+		/* Quotient is rounded up to the larger 29th
+		decimal point. */
+		phase_step_y =
+		(uint32_t) vpe_do_div(
+		(numerator + denominator - 1), denominator);
+	} else if (scale_unit_sel_y == 1) { /* if M/N scalar */
+		/* Calculate the quotient ( src_ROI_height ) / ( out_ROI_height)
+		with u3.29 precision. Quotient is rounded down to the smaller
+		29th decimal point. */
+		numerator = (uint64_t)(src_ROI_height) <<
+			SCALER_PHASE_BITS;
+		denominator = (uint64_t)(out_ROI_height);
+		phase_step_y = (uint32_t) vpe_do_div(
+			numerator, denominator);
+	}
+
+	/* decide which set of FIR coefficients to use */
+	if (phase_step_x > HAL_MDP_PHASE_STEP_2P50)
+		xscale_filter_sel = 0;
+	else if (phase_step_x > HAL_MDP_PHASE_STEP_1P66)
+		xscale_filter_sel = 1;
+	else if (phase_step_x > HAL_MDP_PHASE_STEP_1P25)
+		xscale_filter_sel = 2;
+	else
+		xscale_filter_sel = 3;
+
+	if (phase_step_y > HAL_MDP_PHASE_STEP_2P50)
+		yscale_filter_sel = 0;
+	else if (phase_step_y > HAL_MDP_PHASE_STEP_1P66)
+		yscale_filter_sel = 1;
+	else if (phase_step_y > HAL_MDP_PHASE_STEP_1P25)
+		yscale_filter_sel = 2;
+	else
+		yscale_filter_sel = 3;
+
+	/* calculate phase init for the x direction */
+
+	/* if using FIR scalar */
+	if (scale_unit_sel_x == 0) {
+		if (out_ROI_width == 1)
+			phase_init_x =
+			(uint32_t) ((src_ROI_width - 1) <<
+						SCALER_PHASE_BITS);
+		else
+			phase_init_x = 0;
+
+	} else if (scale_unit_sel_x == 1) /* M over N scalar  */
+		phase_init_x = 0;
+
+	/* calculate phase init for the y direction
+	if using FIR scalar */
+	if (scale_unit_sel_y == 0) {
+		if (out_ROI_height == 1)
+			phase_init_y =
+			(uint32_t) ((src_ROI_height -
+						1) << SCALER_PHASE_BITS);
+		else
+			phase_init_y = 0;
+
+	} else if (scale_unit_sel_y == 1) /* M over N scalar   */
+		phase_init_y = 0;
+
+	CDBG("phase step x = %d, step y = %d.\n",
+		phase_step_x, phase_step_y);
+	CDBG("phase init x = %d, init y = %d.\n",
+		phase_init_x, phase_init_y);
+
+	msm_io_w(phase_step_x, vpe_device->vpebase +
+			VPE_SCALE_PHASEX_STEP_OFFSET);
+
+	msm_io_w(phase_step_y, vpe_device->vpebase +
+			VPE_SCALE_PHASEY_STEP_OFFSET);
+
+	msm_io_w(phase_init_x, vpe_device->vpebase +
+			VPE_SCALE_PHASEX_INIT_OFFSET);
+
+	msm_io_w(phase_init_y, vpe_device->vpebase +
+			VPE_SCALE_PHASEY_INIT_OFFSET);
+
+	return 1;
+}
+
+void msm_send_frame_to_vpe(uint32_t pyaddr, uint32_t pcbcraddr,
+		struct timespec *ts, int output_type)
+{
+	uint32_t temp_pyaddr = 0, temp_pcbcraddr = 0;
+
+	CDBG("vpe input, pyaddr = 0x%x, pcbcraddr = 0x%x\n",
+		pyaddr, pcbcraddr);
+	msm_io_w(pyaddr, vpe_device->vpebase + VPE_SRCP0_ADDR_OFFSET);
+	msm_io_w(pcbcraddr, vpe_device->vpebase + VPE_SRCP1_ADDR_OFFSET);
+
+	if (vpe_ctrl->state == VPE_STATE_ACTIVE)
+		CDBG(" =====VPE is busy!!!  Wrong!========\n");
+
+	if (output_type != OUTPUT_TYPE_ST_R)
+		vpe_ctrl->ts = *ts;
+
+	if (output_type == OUTPUT_TYPE_ST_L) {
+		vpe_ctrl->pcbcr_before_dis = msm_io_r(vpe_device->vpebase +
+			VPE_OUTP1_ADDR_OFFSET);
+		temp_pyaddr = msm_io_r(vpe_device->vpebase +
+			VPE_OUTP0_ADDR_OFFSET);
+		temp_pcbcraddr = temp_pyaddr + PAD_TO_2K(vpe_ctrl->out_w *
+			vpe_ctrl->out_h * 2, vpe_ctrl->pad_2k_bool);
+		msm_io_w(temp_pcbcraddr, vpe_device->vpebase +
+			VPE_OUTP1_ADDR_OFFSET);
+	}
+
+	if (vpe_ctrl->dis_en) {
+		/* Changing the VPE output CBCR address,
+		to make Y/CBCR continuous */
+		vpe_ctrl->pcbcr_before_dis = msm_io_r(vpe_device->vpebase +
+			VPE_OUTP1_ADDR_OFFSET);
+		temp_pyaddr = msm_io_r(vpe_device->vpebase +
+			VPE_OUTP0_ADDR_OFFSET);
+		temp_pcbcraddr = temp_pyaddr + vpe_ctrl->pcbcr_dis_offset;
+		msm_io_w(temp_pcbcraddr, vpe_device->vpebase +
+			VPE_OUTP1_ADDR_OFFSET);
+	}
+
+	vpe_ctrl->output_type = output_type;
+	vpe_ctrl->state = VPE_STATE_ACTIVE;
+	vpe_start();
+}
+
+static int vpe_proc_general(struct msm_vpe_cmd *cmd)
+{
+	int rc = 0;
+	uint32_t *cmdp = NULL;
+	struct msm_queue_cmd *qcmd = NULL;
+	struct msm_vpe_buf_info *vpe_buf;
+	int turbo_mode = 0;
+	struct msm_sync *sync = (struct msm_sync *)vpe_ctrl->syncdata;
+	CDBG("vpe_proc_general: cmdID = %s, length = %d\n",
+		vpe_general_cmd[cmd->id], cmd->length);
+	switch (cmd->id) {
+	case VPE_ENABLE:
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto vpe_proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto vpe_proc_general_done;
+		}
+		turbo_mode = *((int *)(cmd->value));
+		rc = turbo_mode ? vpe_enable(VPE_TURBO_MODE_CLOCK_RATE)
+			: vpe_enable(VPE_NORMAL_MODE_CLOCK_RATE);
+		break;
+	case VPE_DISABLE:
+		rc = vpe_disable();
+		break;
+	case VPE_RESET:
+	case VPE_ABORT:
+		rc = vpe_reset();
+		break;
+	case VPE_START:
+		rc = vpe_start();
+		break;
+
+	case VPE_INPUT_PLANE_CFG:
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto vpe_proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto vpe_proc_general_done;
+		}
+		vpe_input_plane_config(cmdp);
+		break;
+
+	case VPE_OPERATION_MODE_CFG:
+		CDBG("cmd->length = %d \n", cmd->length);
+		if (cmd->length != VPE_OPERATION_MODE_CFG_LEN) {
+			rc = -EINVAL;
+			goto vpe_proc_general_done;
+		}
+		cmdp = kmalloc(VPE_OPERATION_MODE_CFG_LEN,
+					GFP_ATOMIC);
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			VPE_OPERATION_MODE_CFG_LEN)) {
+			rc = -EFAULT;
+			goto vpe_proc_general_done;
+		}
+		rc = vpe_operation_config(cmdp);
+		CDBG("rc = %d \n", rc);
+		break;
+
+	case VPE_OUTPUT_PLANE_CFG:
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto vpe_proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto vpe_proc_general_done;
+		}
+		vpe_output_plane_config(cmdp);
+		break;
+
+	case VPE_SCALE_CFG_TYPE:
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto vpe_proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto vpe_proc_general_done;
+		}
+		vpe_update_scale_coef(cmdp);
+		break;
+
+	case VPE_CMD_DIS_OFFSET_CFG: {
+		struct msm_vfe_resp *vdata;
+		/* first get the dis offset and frame id. */
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto vpe_proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto vpe_proc_general_done;
+		}
+		/* get the offset. */
+		vpe_ctrl->dis_offset = *(struct dis_offset_type *)cmdp;
+		qcmd = msm_dequeue_vpe(&sync->vpe_q, list_vpe_frame);
+		if (!qcmd) {
+			pr_err("%s: no video frame.\n", __func__);
+			kfree(cmdp);
+			return -EAGAIN;
+		}
+		vdata = (struct msm_vfe_resp *)(qcmd->command);
+		vpe_buf = &vdata->vpe_bf;
+		vpe_update_scaler_with_dis(&(vpe_buf->vpe_crop),
+					&(vpe_ctrl->dis_offset));
+
+		msm_send_frame_to_vpe(vpe_buf->y_phy, vpe_buf->cbcr_phy,
+						&(vpe_buf->ts), OUTPUT_TYPE_V);
+
+		if (!qcmd || !atomic_read(&qcmd->on_heap)) {
+			kfree(cmdp);
+			return -EAGAIN;
+		}
+		if (!atomic_sub_return(1, &qcmd->on_heap))
+			kfree(qcmd);
+		break;
+	}
+
+	default:
+		break;
+	}
+vpe_proc_general_done:
+	kfree(cmdp);
+	return rc;
+}
+
+static void vpe_addr_convert(struct msm_vpe_phy_info *pinfo,
+	enum vpe_resp_msg type, void *data, void **ext, int32_t *elen)
+{
+	CDBG("In vpe_addr_convert type = %d\n", type);
+	switch (type) {
+	case VPE_MSG_OUTPUT_V:
+		pinfo->output_id = OUTPUT_TYPE_V;
+		break;
+	case VPE_MSG_OUTPUT_ST_R:
+		/* output_id will be used by user space only. */
+		pinfo->output_id = OUTPUT_TYPE_V;
+		break;
+	default:
+		break;
+	} /* switch */
+
+	CDBG("In vpe_addr_convert output_id = %d\n", pinfo->output_id);
+
+	pinfo->y_phy =
+		((struct vpe_message *)data)->_u.msgOut.yBuffer;
+	pinfo->cbcr_phy =
+		((struct vpe_message *)data)->_u.msgOut.cbcrBuffer;
+	*ext  = vpe_ctrl->extdata;
+	*elen = vpe_ctrl->extlen;
+}
+
+void vpe_proc_ops(uint8_t id, void *msg, size_t len)
+{
+	struct msm_vpe_resp *rp;
+
+	rp = vpe_ctrl->resp->vpe_alloc(sizeof(struct msm_vpe_resp),
+		vpe_ctrl->syncdata, GFP_ATOMIC);
+	if (!rp) {
+		CDBG("rp: cannot allocate buffer\n");
+		return;
+	}
+
+	CDBG("vpe_proc_ops, msgId = %d rp->evt_msg.msg_id = %d\n",
+		id, rp->evt_msg.msg_id);
+	rp->evt_msg.type   = MSM_CAMERA_MSG;
+	rp->evt_msg.msg_id = id;
+	rp->evt_msg.len    = len;
+	rp->evt_msg.data   = msg;
+
+	switch (rp->evt_msg.msg_id) {
+	case MSG_ID_VPE_OUTPUT_V:
+		rp->type = VPE_MSG_OUTPUT_V;
+		vpe_addr_convert(&(rp->phy), VPE_MSG_OUTPUT_V,
+			rp->evt_msg.data, &(rp->extdata),
+			&(rp->extlen));
+		break;
+
+	case MSG_ID_VPE_OUTPUT_ST_R:
+		rp->type = VPE_MSG_OUTPUT_ST_R;
+		vpe_addr_convert(&(rp->phy), VPE_MSG_OUTPUT_ST_R,
+			rp->evt_msg.data, &(rp->extdata),
+			&(rp->extlen));
+		break;
+
+	case MSG_ID_VPE_OUTPUT_ST_L:
+		rp->type = VPE_MSG_OUTPUT_ST_L;
+		break;
+
+	default:
+		rp->type = VPE_MSG_GENERAL;
+		break;
+	}
+	CDBG("%s: time = %ld\n",
+			__func__, vpe_ctrl->ts.tv_nsec);
+
+	vpe_ctrl->resp->vpe_resp(rp, MSM_CAM_Q_VPE_MSG,
+					vpe_ctrl->syncdata,
+					&(vpe_ctrl->ts), GFP_ATOMIC);
+}
+
+int vpe_config_axi(struct axidata *ad)
+{
+	uint32_t p1;
+	struct msm_pmem_region *regp1 = NULL;
+	CDBG("vpe_config_axi:bufnum1 = %d.\n", ad->bufnum1);
+
+	if (ad->bufnum1 != 1)
+		return -EINVAL;
+
+	regp1 = &(ad->region[0]);
+	/* for video  Y address */
+	p1 = (regp1->paddr + regp1->info.y_off);
+	msm_io_w(p1, vpe_device->vpebase + VPE_OUTP0_ADDR_OFFSET);
+	/* for video  CbCr address */
+	p1 = (regp1->paddr + regp1->info.cbcr_off);
+	msm_io_w(p1, vpe_device->vpebase + VPE_OUTP1_ADDR_OFFSET);
+
+	return 0;
+}
+
+int msm_vpe_config(struct msm_vpe_cfg_cmd *cmd, void *data)
+{
+	struct msm_vpe_cmd vpecmd;
+	int rc = 0;
+	if (copy_from_user(&vpecmd,
+			(void __user *)(cmd->value),
+			sizeof(vpecmd))) {
+		pr_err("%s %d: copy_from_user failed\n", __func__,
+				__LINE__);
+		return -EFAULT;
+	}
+	CDBG("%s: cmd_type %d\n", __func__, cmd->cmd_type);
+	switch (cmd->cmd_type) {
+	case CMD_VPE:
+		rc = vpe_proc_general(&vpecmd);
+		CDBG(" rc = %d\n", rc);
+		break;
+
+	case CMD_AXI_CFG_VPE:
+	case CMD_AXI_CFG_SNAP_VPE:
+	case CMD_AXI_CFG_SNAP_THUMB_VPE: {
+		struct axidata *axid;
+		axid = data;
+		if (!axid)
+			return -EFAULT;
+		vpe_config_axi(axid);
+		break;
+	}
+	default:
+		break;
+	}
+	CDBG("%s: rc = %d\n", __func__, rc);
+	return rc;
+}
+
+void msm_vpe_offset_update(int frame_pack, uint32_t pyaddr, uint32_t pcbcraddr,
+	struct timespec *ts, int output_id, struct msm_st_half st_half,
+	int frameid)
+{
+	struct msm_vpe_buf_info vpe_buf;
+	uint32_t input_stride;
+
+	vpe_buf.vpe_crop.in2_w = st_half.stCropInfo.in_w;
+	vpe_buf.vpe_crop.in2_h = st_half.stCropInfo.in_h;
+	vpe_buf.vpe_crop.out2_w = st_half.stCropInfo.out_w;
+	vpe_buf.vpe_crop.out2_h = st_half.stCropInfo.out_h;
+	vpe_ctrl->dis_offset.dis_offset_x = st_half.pix_x_off;
+	vpe_ctrl->dis_offset.dis_offset_y = st_half.pix_y_off;
+	vpe_ctrl->dis_offset.frame_id = frameid;
+	vpe_ctrl->frame_pack = frame_pack;
+	vpe_ctrl->output_type = output_id;
+
+	input_stride = (st_half.buf_cbcr_stride * (1<<16)) +
+		st_half.buf_y_stride;
+
+	msm_io_w(input_stride, vpe_device->vpebase + VPE_SRC_YSTRIDE1_OFFSET);
+
+	vpe_update_scaler_with_dis(&(vpe_buf.vpe_crop),
+		&(vpe_ctrl->dis_offset));
+
+	msm_send_frame_to_vpe(pyaddr, pcbcraddr, ts, output_id);
+}
+
+static void vpe_send_outmsg(uint8_t msgid, uint32_t pyaddr,
+	uint32_t pcbcraddr)
+{
+	struct vpe_message msg;
+	uint8_t outid;
+	msg._d = outid = msgid;
+	msg._u.msgOut.output_id   = msgid;
+	msg._u.msgOut.yBuffer     = pyaddr;
+	msg._u.msgOut.cbcrBuffer  = pcbcraddr;
+	vpe_proc_ops(outid, &msg, sizeof(struct vpe_message));
+	return;
+}
+
+int msm_vpe_reg(struct msm_vpe_callback *presp)
+{
+	if (presp && presp->vpe_resp)
+		vpe_ctrl->resp = presp;
+
+	return 0;
+}
+
+static void vpe_send_msg_no_payload(enum VPE_MESSAGE_ID id)
+{
+	struct vpe_message msg;
+
+	CDBG("vfe31_send_msg_no_payload\n");
+	msg._d = id;
+	vpe_proc_ops(id, &msg, 0);
+}
+
+static void vpe_do_tasklet(unsigned long data)
+{
+	unsigned long flags;
+	uint32_t pyaddr = 0, pcbcraddr = 0;
+	uint32_t src_y, src_cbcr, temp;
+
+	struct vpe_isr_queue_cmd_type *qcmd = NULL;
+
+	CDBG("=== vpe_do_tasklet start === \n");
+
+	spin_lock_irqsave(&vpe_ctrl->tasklet_lock, flags);
+	qcmd = list_first_entry(&vpe_ctrl->tasklet_q,
+		struct vpe_isr_queue_cmd_type, list);
+
+	if (!qcmd) {
+		spin_unlock_irqrestore(&vpe_ctrl->tasklet_lock, flags);
+		return;
+	}
+
+	list_del(&qcmd->list);
+	spin_unlock_irqrestore(&vpe_ctrl->tasklet_lock, flags);
+
+	/* interrupt to be processed,  *qcmd has the payload.  */
+	if (qcmd->irq_status & 0x1) {
+		if (vpe_ctrl->output_type == OUTPUT_TYPE_ST_L) {
+			CDBG("vpe left frame done.\n");
+			vpe_ctrl->output_type = 0;
+			CDBG("vpe send out msg.\n");
+			orig_src_y = msm_io_r(vpe_device->vpebase +
+				VPE_SRCP0_ADDR_OFFSET);
+			orig_src_cbcr = msm_io_r(vpe_device->vpebase +
+				VPE_SRCP1_ADDR_OFFSET);
+
+			pyaddr = msm_io_r(vpe_device->vpebase +
+				VPE_OUTP0_ADDR_OFFSET);
+			pcbcraddr = msm_io_r(vpe_device->vpebase +
+				VPE_OUTP1_ADDR_OFFSET);
+			CDBG("%s: out_w = %d, out_h = %d\n", __func__,
+				vpe_ctrl->out_w, vpe_ctrl->out_h);
+
+			if ((vpe_ctrl->frame_pack == TOP_DOWN_FULL) ||
+				(vpe_ctrl->frame_pack == TOP_DOWN_HALF)) {
+				msm_io_w(pyaddr + (vpe_ctrl->out_w *
+					vpe_ctrl->out_h), vpe_device->vpebase +
+					VPE_OUTP0_ADDR_OFFSET);
+				msm_io_w(pcbcraddr + (vpe_ctrl->out_w *
+					vpe_ctrl->out_h/2),
+					vpe_device->vpebase +
+					VPE_OUTP1_ADDR_OFFSET);
+			} else if ((vpe_ctrl->frame_pack ==
+				SIDE_BY_SIDE_HALF) || (vpe_ctrl->frame_pack ==
+				SIDE_BY_SIDE_FULL)) {
+				msm_io_w(pyaddr + vpe_ctrl->out_w,
+					vpe_device->vpebase +
+					VPE_OUTP0_ADDR_OFFSET);
+				msm_io_w(pcbcraddr + vpe_ctrl->out_w,
+					vpe_device->vpebase +
+					VPE_OUTP1_ADDR_OFFSET);
+			} else
+				CDBG("%s: Invalid packing = %d\n", __func__,
+					vpe_ctrl->frame_pack);
+
+			vpe_send_msg_no_payload(MSG_ID_VPE_OUTPUT_ST_L);
+			vpe_ctrl->state = VPE_STATE_INIT;
+			kfree(qcmd);
+			return;
+		} else if (vpe_ctrl->output_type == OUTPUT_TYPE_ST_R) {
+			src_y = orig_src_y;
+			src_cbcr = orig_src_cbcr;
+			CDBG("%s: out_w = %d, out_h = %d\n", __func__,
+				vpe_ctrl->out_w, vpe_ctrl->out_h);
+
+			if ((vpe_ctrl->frame_pack == TOP_DOWN_FULL) ||
+				(vpe_ctrl->frame_pack == TOP_DOWN_HALF)) {
+				pyaddr = msm_io_r(vpe_device->vpebase +
+					VPE_OUTP0_ADDR_OFFSET) -
+					(vpe_ctrl->out_w * vpe_ctrl->out_h);
+			} else if ((vpe_ctrl->frame_pack ==
+				SIDE_BY_SIDE_HALF) || (vpe_ctrl->frame_pack ==
+				SIDE_BY_SIDE_FULL)) {
+				pyaddr = msm_io_r(vpe_device->vpebase +
+				VPE_OUTP0_ADDR_OFFSET) - vpe_ctrl->out_w;
+			} else
+				CDBG("%s: Invalid packing = %d\n", __func__,
+					vpe_ctrl->frame_pack);
+
+			pcbcraddr = vpe_ctrl->pcbcr_before_dis;
+		} else {
+			src_y =	msm_io_r(vpe_device->vpebase +
+				VPE_SRCP0_ADDR_OFFSET);
+			src_cbcr = msm_io_r(vpe_device->vpebase +
+				VPE_SRCP1_ADDR_OFFSET);
+			pyaddr = msm_io_r(vpe_device->vpebase +
+				VPE_OUTP0_ADDR_OFFSET);
+			pcbcraddr = msm_io_r(vpe_device->vpebase +
+				VPE_OUTP1_ADDR_OFFSET);
+		}
+
+		if (vpe_ctrl->dis_en)
+			pcbcraddr = vpe_ctrl->pcbcr_before_dis;
+
+		msm_io_w(src_y,
+				vpe_device->vpebase + VPE_OUTP0_ADDR_OFFSET);
+		msm_io_w(src_cbcr,
+				vpe_device->vpebase + VPE_OUTP1_ADDR_OFFSET);
+
+		temp = msm_io_r(vpe_device->vpebase + VPE_OP_MODE_OFFSET) &
+			0xFFFFFFFC;
+		msm_io_w(temp, vpe_device->vpebase + VPE_OP_MODE_OFFSET);
+
+		/*  now pass this frame to msm_camera.c. */
+		if (vpe_ctrl->output_type == OUTPUT_TYPE_ST_R) {
+			CDBG("vpe send out R msg.\n");
+			vpe_send_outmsg(MSG_ID_VPE_OUTPUT_ST_R, pyaddr,
+				pcbcraddr);
+		} else if (vpe_ctrl->output_type == OUTPUT_TYPE_V) {
+			CDBG("vpe send out V msg.\n");
+			vpe_send_outmsg(MSG_ID_VPE_OUTPUT_V, pyaddr, pcbcraddr);
+		}
+
+		vpe_ctrl->output_type = 0;
+		vpe_ctrl->state = VPE_STATE_INIT;   /* put it back to idle. */
+
+	}
+	kfree(qcmd);
+}
+DECLARE_TASKLET(vpe_tasklet, vpe_do_tasklet, 0);
+
+static irqreturn_t vpe_parse_irq(int irq_num, void *data)
+{
+	unsigned long flags;
+	uint32_t irq_status = 0;
+	struct vpe_isr_queue_cmd_type *qcmd;
+
+	CDBG("vpe_parse_irq.\n");
+	/* read and clear back-to-back. */
+	irq_status = msm_io_r_mb(vpe_device->vpebase +
+							VPE_INTR_STATUS_OFFSET);
+	msm_io_w_mb(irq_status, vpe_device->vpebase +
+				VPE_INTR_CLEAR_OFFSET);
+
+	msm_io_w(0, vpe_device->vpebase + VPE_INTR_ENABLE_OFFSET);
+
+	if (irq_status == 0) {
+		pr_err("%s: irq_status = 0,Something is wrong!\n", __func__);
+		return IRQ_HANDLED;
+	}
+	irq_status &= 0x1;
+	/* apply mask. only interested in bit 0.  */
+	if (irq_status) {
+		qcmd = kzalloc(sizeof(struct vpe_isr_queue_cmd_type),
+			GFP_ATOMIC);
+		if (!qcmd) {
+			pr_err("%s: qcmd malloc failed!\n", __func__);
+			return IRQ_HANDLED;
+		}
+		/* must be 0x1 now. so in bottom half we don't really
+		need to check. */
+		qcmd->irq_status = irq_status & 0x1;
+		spin_lock_irqsave(&vpe_ctrl->tasklet_lock, flags);
+		list_add_tail(&qcmd->list, &vpe_ctrl->tasklet_q);
+		spin_unlock_irqrestore(&vpe_ctrl->tasklet_lock, flags);
+		tasklet_schedule(&vpe_tasklet);
+	}
+	return IRQ_HANDLED;
+}
+
+static int vpe_enable_irq(void)
+{
+	uint32_t   rc = 0;
+	rc = request_irq(vpe_device->vpeirq,
+				vpe_parse_irq,
+				IRQF_TRIGGER_HIGH, "vpe", 0);
+	return rc;
+}
+
+int msm_vpe_open(void)
+{
+	int rc = 0;
+
+	CDBG("%s: In \n", __func__);
+
+	vpe_ctrl = kzalloc(sizeof(struct vpe_ctrl_type), GFP_KERNEL);
+	if (!vpe_ctrl) {
+		pr_err("%s: no memory!\n", __func__);
+		return -ENOMEM;
+	}
+
+	spin_lock_init(&vpe_ctrl->ops_lock);
+	CDBG("%s: Out\n", __func__);
+
+	return rc;
+}
+
+int msm_vpe_release(void)
+{
+	/* clean up....*/
+	int rc = 0;
+	CDBG("%s: state %d\n", __func__, vpe_ctrl->state);
+	if (vpe_ctrl->state != VPE_STATE_IDLE)
+		rc = vpe_disable();
+
+	kfree(vpe_ctrl);
+	return rc;
+}
+
+
+int vpe_enable(uint32_t clk_rate)
+{
+	int rc = 0;
+	unsigned long flags = 0;
+	/* don't change the order of clock and irq.*/
+	CDBG("%s: enable_clock rate %u\n", __func__, clk_rate);
+	spin_lock_irqsave(&vpe_ctrl->ops_lock, flags);
+	if (vpe_ctrl->state != VPE_STATE_IDLE) {
+		CDBG("%s: VPE already enabled", __func__);
+		spin_unlock_irqrestore(&vpe_ctrl->ops_lock, flags);
+		return 0;
+	}
+	vpe_ctrl->state = VPE_STATE_INIT;
+	spin_unlock_irqrestore(&vpe_ctrl->ops_lock, flags);
+
+	rc = msm_camio_vpe_clk_enable(clk_rate);
+	if (rc < 0) {
+		pr_err("%s: msm_camio_vpe_clk_enable failed", __func__);
+		vpe_ctrl->state = VPE_STATE_IDLE;
+		return rc;
+	}
+
+	CDBG("%s: enable_irq\n", __func__);
+	vpe_enable_irq();
+
+	/* initialize the data structure - lock, queue etc. */
+	spin_lock_init(&vpe_ctrl->tasklet_lock);
+	INIT_LIST_HEAD(&vpe_ctrl->tasklet_q);
+
+	return rc;
+}
+
+int vpe_disable(void)
+{
+	int rc = 0;
+	unsigned long flags = 0;
+	CDBG("%s: called", __func__);
+	spin_lock_irqsave(&vpe_ctrl->ops_lock, flags);
+	if (vpe_ctrl->state == VPE_STATE_IDLE) {
+		CDBG("%s: VPE already disabled", __func__);
+		spin_unlock_irqrestore(&vpe_ctrl->ops_lock, flags);
+		return 0;
+	}
+	vpe_ctrl->state = VPE_STATE_IDLE;
+	spin_unlock_irqrestore(&vpe_ctrl->ops_lock, flags);
+	vpe_ctrl->out_y_addr = msm_io_r(vpe_device->vpebase +
+		VPE_OUTP0_ADDR_OFFSET);
+	vpe_ctrl->out_cbcr_addr = msm_io_r(vpe_device->vpebase +
+		VPE_OUTP1_ADDR_OFFSET);
+	free_irq(vpe_device->vpeirq, 0);
+	tasklet_kill(&vpe_tasklet);
+	rc = msm_camio_vpe_clk_disable();
+	return rc;
+}
+
+static int __msm_vpe_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct resource   *vpemem, *vpeirq, *vpeio;
+	void __iomem      *vpebase;
+
+	/* first allocate */
+
+	vpe_device = &vpe_device_data;
+	memset(vpe_device, 0, sizeof(struct vpe_device_type));
+
+	/* does the device exist? */
+	vpeirq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!vpeirq) {
+		pr_err("%s: no vpe irq resource.\n", __func__);
+		rc = -ENODEV;
+		goto vpe_free_device;
+	}
+	vpemem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!vpemem) {
+		pr_err("%s: no vpe mem resource!\n", __func__);
+		rc = -ENODEV;
+		goto vpe_free_device;
+	}
+	vpeio = request_mem_region(vpemem->start,
+			resource_size(vpemem), pdev->name);
+	if (!vpeio) {
+		pr_err("%s: VPE region already claimed.\n", __func__);
+		rc = -EBUSY;
+		goto vpe_free_device;
+	}
+
+	vpebase =
+		ioremap(vpemem->start,
+				(vpemem->end - vpemem->start) + 1);
+	if (!vpebase) {
+		pr_err("%s: vpe ioremap failed.\n", __func__);
+		rc = -ENOMEM;
+		goto vpe_release_mem_region;
+	}
+
+	/* Fall through, _probe is successful. */
+	vpe_device->vpeirq = vpeirq->start;
+	vpe_device->vpemem = vpemem;
+	vpe_device->vpeio = vpeio;
+	vpe_device->vpebase = vpebase;
+	return rc;  /* this rc should be zero.*/
+
+	iounmap(vpe_device->vpebase);  /* this path should never occur */
+
+/* from this part it is error handling. */
+vpe_release_mem_region:
+	release_mem_region(vpemem->start, (vpemem->end - vpemem->start) + 1);
+vpe_free_device:
+	return rc;  /* this rc should have error code. */
+}
+
+static int __msm_vpe_remove(struct platform_device *pdev)
+{
+	struct resource	*vpemem;
+	vpemem = vpe_device->vpemem;
+
+	iounmap(vpe_device->vpebase);
+	release_mem_region(vpemem->start,
+					(vpemem->end - vpemem->start) + 1);
+	return 0;
+}
+
+static struct platform_driver msm_vpe_driver = {
+	.probe = __msm_vpe_probe,
+	.remove = __msm_vpe_remove,
+	.driver = {
+		.name = "msm_vpe",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_vpe_init(void)
+{
+	return platform_driver_register(&msm_vpe_driver);
+}
+module_init(msm_vpe_init);
+
+static void __exit msm_vpe_exit(void)
+{
+	platform_driver_unregister(&msm_vpe_driver);
+}
+module_exit(msm_vpe_exit);
+
+MODULE_DESCRIPTION("msm vpe 1.0 driver");
+MODULE_VERSION("msm vpe driver 1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/msm_vpe1.h b/drivers/media/video/msm/msm_vpe1.h
new file mode 100644
index 0000000..ed7112e
--- /dev/null
+++ b/drivers/media/video/msm/msm_vpe1.h
@@ -0,0 +1,253 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef _msm_vpe1_h_
+#define _msm_vpe1_h_
+
+#include <mach/camera.h>
+
+/***********  start of register offset *********************/
+#define VPE_INTR_ENABLE_OFFSET                0x0020
+#define VPE_INTR_STATUS_OFFSET                0x0024
+#define VPE_INTR_CLEAR_OFFSET                 0x0028
+#define VPE_DL0_START_OFFSET                  0x0030
+#define VPE_HW_VERSION_OFFSET                 0x0070
+#define VPE_SW_RESET_OFFSET                   0x0074
+#define VPE_AXI_RD_ARB_CONFIG_OFFSET          0x0078
+#define VPE_SEL_CLK_OR_HCLK_TEST_BUS_OFFSET   0x007C
+#define VPE_CGC_EN_OFFSET                     0x0100
+#define VPE_CMD_STATUS_OFFSET                 0x10008
+#define VPE_PROFILE_EN_OFFSET                 0x10010
+#define VPE_PROFILE_COUNT_OFFSET              0x10014
+#define VPE_CMD_MODE_OFFSET                   0x10060
+#define VPE_SRC_SIZE_OFFSET                   0x10108
+#define VPE_SRCP0_ADDR_OFFSET                 0x1010C
+#define VPE_SRCP1_ADDR_OFFSET                 0x10110
+#define VPE_SRC_YSTRIDE1_OFFSET               0x1011C
+#define VPE_SRC_FORMAT_OFFSET                 0x10124
+#define VPE_SRC_UNPACK_PATTERN1_OFFSET        0x10128
+#define VPE_OP_MODE_OFFSET                    0x10138
+#define VPE_SCALE_PHASEX_INIT_OFFSET          0x1013C
+#define VPE_SCALE_PHASEY_INIT_OFFSET          0x10140
+#define VPE_SCALE_PHASEX_STEP_OFFSET          0x10144
+#define VPE_SCALE_PHASEY_STEP_OFFSET          0x10148
+#define VPE_OUT_FORMAT_OFFSET                 0x10150
+#define VPE_OUT_PACK_PATTERN1_OFFSET          0x10154
+#define VPE_OUT_SIZE_OFFSET                   0x10164
+#define VPE_OUTP0_ADDR_OFFSET                 0x10168
+#define VPE_OUTP1_ADDR_OFFSET                 0x1016C
+#define VPE_OUT_YSTRIDE1_OFFSET               0x10178
+#define VPE_OUT_XY_OFFSET                     0x1019C
+#define VPE_SRC_XY_OFFSET                     0x10200
+#define VPE_SRC_IMAGE_SIZE_OFFSET             0x10208
+#define VPE_SCALE_CONFIG_OFFSET               0x10230
+#define VPE_DEINT_STATUS_OFFSET               0x30000
+#define VPE_DEINT_DECISION_OFFSET             0x30004
+#define VPE_DEINT_COEFF0_OFFSET               0x30010
+#define VPE_SCALE_STATUS_OFFSET               0x50000
+#define VPE_SCALE_SVI_PARAM_OFFSET            0x50010
+#define VPE_SCALE_SHARPEN_CFG_OFFSET          0x50020
+#define VPE_SCALE_COEFF_LSP_0_OFFSET          0x50400
+#define VPE_SCALE_COEFF_MSP_0_OFFSET          0x50404
+
+#define VPE_AXI_ARB_2_OFFSET                  0x004C
+
+#define VPE_SCALE_COEFF_LSBn(n)	(0x50400 + 8 * (n))
+#define VPE_SCALE_COEFF_MSBn(n)	(0x50404 + 8 * (n))
+#define VPE_SCALE_COEFF_NUM			32
+
+/*********** end of register offset ********************/
+
+
+#define VPE_HARDWARE_VERSION          0x00080308
+#define VPE_SW_RESET_VALUE            0x00000010  /* bit 4 for PPP*/
+#define VPE_AXI_RD_ARB_CONFIG_VALUE   0x124924
+#define VPE_CMD_MODE_VALUE        0x1
+#define VPE_DEFAULT_OP_MODE_VALUE     0x40FC0004
+#define VPE_CGC_ENABLE_VALUE          0xffff
+#define VPE_DEFAULT_SCALE_CONFIG      0x3c
+
+#define VPE_NORMAL_MODE_CLOCK_RATE   150000000
+#define VPE_TURBO_MODE_CLOCK_RATE   200000000
+/**************************************************/
+/*********** Start of command id ******************/
+/**************************************************/
+enum VPE_CMD_ID_ENUM {
+	VPE_DUMMY_0 = 0,
+	VPE_SET_CLK,
+	VPE_RESET,
+	VPE_START,
+	VPE_ABORT,
+	VPE_OPERATION_MODE_CFG, /* 5 */
+	VPE_INPUT_PLANE_CFG,
+	VPE_OUTPUT_PLANE_CFG,
+	VPE_INPUT_PLANE_UPDATE,
+	VPE_SCALE_CFG_TYPE,
+	VPE_ROTATION_CFG_TYPE, /* 10 */
+	VPE_AXI_OUT_CFG,
+	VPE_CMD_DIS_OFFSET_CFG,
+	VPE_ENABLE,
+	VPE_DISABLE,
+};
+
+/* Length of each command.  In bytes.  (payload only) */
+#define VPE_OPERATION_MODE_CFG_LEN 8
+#define VPE_INPUT_PLANE_CFG_LEN    24
+#define VPE_OUTPUT_PLANE_CFG_LEN   20
+#define VPE_INPUT_PLANE_UPDATE_LEN 12
+#define VPE_SCALER_CONFIG_LEN      260
+#define VPE_DIS_OFFSET_CFG_LEN     12
+/**************************************************/
+/*********** End of command id ********************/
+/**************************************************/
+
+struct msm_vpe_cmd {
+	int32_t  id;
+	uint16_t length;
+	void     *value;
+};
+
+struct vpe_cmd_type {
+	uint16_t id;
+	uint32_t length;
+};
+
+struct vpe_isr_queue_cmd_type {
+	struct list_head            list;
+	uint32_t                    irq_status;
+};
+
+enum VPE_MESSAGE_ID {
+	MSG_ID_VPE_OUTPUT_V = 7, /* To match with that of VFE */
+	MSG_ID_VPE_OUTPUT_ST_L,
+	MSG_ID_VPE_OUTPUT_ST_R,
+};
+
+enum vpe_state {
+	VPE_STATE_IDLE,
+	VPE_STATE_INIT,
+	VPE_STATE_ACTIVE,
+};
+
+struct vpe_device_type {
+	/* device related. */
+	int   vpeirq;
+	void __iomem      *vpebase;
+	struct resource	  *vpemem;
+	struct resource   *vpeio;
+	void        *device_extdata;
+};
+
+struct dis_offset_type {
+	int32_t dis_offset_x;
+	int32_t dis_offset_y;
+	uint32_t frame_id;
+};
+
+struct vpe_ctrl_type {
+	spinlock_t        tasklet_lock;
+	spinlock_t        state_lock;
+	spinlock_t        ops_lock;
+
+	struct list_head  tasklet_q;
+	void              *syncdata;
+	uint16_t          op_mode;
+	void              *extdata;
+	uint32_t          extlen;
+	struct msm_vpe_callback *resp;
+	uint32_t          in_h_w;
+	uint32_t          out_h;  /* this is BEFORE rotation. */
+	uint32_t          out_w;  /* this is BEFORE rotation. */
+	uint32_t          dis_en;
+	struct timespec   ts;
+	struct dis_offset_type   dis_offset;
+	uint32_t          pcbcr_before_dis;
+	uint32_t          pcbcr_dis_offset;
+	int               output_type;
+	int               frame_pack;
+	uint8_t           pad_2k_bool;
+	enum vpe_state    state;
+	unsigned long     out_y_addr;
+	unsigned long     out_cbcr_addr;
+};
+
+/*
+* vpe_input_update
+*
+* Define the parameters for output plane
+*/
+/* this is the dimension of ROI.  width / height. */
+struct vpe_src_size_packed {
+	uint32_t        src_w;
+	uint32_t        src_h;
+};
+
+struct vpe_src_xy_packed {
+	uint32_t        src_x;
+	uint32_t        src_y;
+};
+
+struct vpe_input_plane_update_type {
+	struct vpe_src_size_packed             src_roi_size;
+	/* DIS updates this set. */
+	struct vpe_src_xy_packed               src_roi_offset;
+	/* input address*/
+	uint8_t                         *src_p0_addr;
+	uint8_t                         *src_p1_addr;
+};
+
+struct vpe_msg_stats{
+	uint32_t    buffer;
+	uint32_t    frameCounter;
+};
+
+struct vpe_msg_output {
+	uint8_t   output_id;
+	uint32_t  yBuffer;
+	uint32_t  cbcrBuffer;
+	uint32_t  frameCounter;
+};
+
+struct vpe_message {
+	uint8_t  _d;
+	union {
+		struct vpe_msg_output              msgOut;
+		struct vpe_msg_stats               msgStats;
+	} _u;
+};
+
+#define SCALER_PHASE_BITS 29
+#define HAL_MDP_PHASE_STEP_2P50    0x50000000
+#define HAL_MDP_PHASE_STEP_1P66    0x35555555
+#define HAL_MDP_PHASE_STEP_1P25    0x28000000
+
+struct phase_val_t {
+	int32_t phase_init_x;
+	int32_t phase_init_y;
+	int32_t phase_step_x;
+	int32_t phase_step_y;
+};
+
+extern struct vpe_ctrl_type *vpe_ctrl;
+
+int msm_vpe_open(void);
+int msm_vpe_release(void);
+int msm_vpe_reg(struct msm_vpe_callback *presp);
+void msm_send_frame_to_vpe(uint32_t pyaddr, uint32_t pcbcraddr,
+	struct timespec *ts, int output_id);
+int msm_vpe_config(struct msm_vpe_cfg_cmd *cmd, void *data);
+int msm_vpe_cfg_update(void *pinfo);
+void msm_vpe_offset_update(int frame_pack, uint32_t pyaddr, uint32_t pcbcraddr,
+	struct timespec *ts, int output_id, struct msm_st_half st_half,
+	int frameid);
+#endif /*_msm_vpe1_h_*/
+
diff --git a/drivers/media/video/msm/mt9d112.c b/drivers/media/video/msm/mt9d112.c
new file mode 100644
index 0000000..a7b5156
--- /dev/null
+++ b/drivers/media/video/msm/mt9d112.c
@@ -0,0 +1,845 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <media/msm_camera.h>
+#include <mach/gpio.h>
+#include "mt9d112.h"
+
+/* Micron MT9D112 Registers and their values */
+/* Sensor Core Registers */
+#define  REG_MT9D112_MODEL_ID 0x3000
+#define  MT9D112_MODEL_ID     0x1580
+
+/*  SOC Registers Page 1  */
+#define  REG_MT9D112_SENSOR_RESET     0x301A
+#define  REG_MT9D112_STANDBY_CONTROL  0x3202
+#define  REG_MT9D112_MCU_BOOT         0x3386
+
+#define SENSOR_DEBUG 0
+
+struct mt9d112_work {
+	struct work_struct work;
+};
+
+static struct  mt9d112_work *mt9d112_sensorw;
+static struct  i2c_client *mt9d112_client;
+
+struct mt9d112_ctrl {
+	const struct msm_camera_sensor_info *sensordata;
+};
+
+
+static struct mt9d112_ctrl *mt9d112_ctrl;
+
+static DECLARE_WAIT_QUEUE_HEAD(mt9d112_wait_queue);
+DEFINE_SEMAPHORE(mt9d112_sem);
+static int16_t mt9d112_effect = CAMERA_EFFECT_OFF;
+
+/*=============================================================
+	EXTERNAL DECLARATIONS
+==============================================================*/
+extern struct mt9d112_reg mt9d112_regs;
+
+
+/*=============================================================*/
+
+static int mt9d112_reset(const struct msm_camera_sensor_info *dev)
+{
+	int rc = 0;
+
+	rc = gpio_request(dev->sensor_reset, "mt9d112");
+
+	if (!rc) {
+		rc = gpio_direction_output(dev->sensor_reset, 0);
+		msleep(20);
+		gpio_set_value_cansleep(dev->sensor_reset, 1);
+		msleep(20);
+	}
+
+	return rc;
+}
+
+static int32_t mt9d112_i2c_txdata(unsigned short saddr,
+	unsigned char *txdata, int length)
+{
+	struct i2c_msg msg[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = length,
+			.buf = txdata,
+		},
+	};
+
+#if SENSOR_DEBUG
+	if (length == 2)
+		CDBG("msm_io_i2c_w: 0x%04x 0x%04x\n",
+			*(u16 *) txdata, *(u16 *) (txdata + 2));
+	else if (length == 4)
+		CDBG("msm_io_i2c_w: 0x%04x\n", *(u16 *) txdata);
+	else
+		CDBG("msm_io_i2c_w: length = %d\n", length);
+#endif
+	if (i2c_transfer(mt9d112_client->adapter, msg, 1) < 0) {
+		CDBG("mt9d112_i2c_txdata failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t mt9d112_i2c_write(unsigned short saddr,
+	unsigned short waddr, unsigned short wdata, enum mt9d112_width width)
+{
+	int32_t rc = -EIO;
+	unsigned char buf[4];
+
+	memset(buf, 0, sizeof(buf));
+	switch (width) {
+	case WORD_LEN: {
+		buf[0] = (waddr & 0xFF00)>>8;
+		buf[1] = (waddr & 0x00FF);
+		buf[2] = (wdata & 0xFF00)>>8;
+		buf[3] = (wdata & 0x00FF);
+
+		rc = mt9d112_i2c_txdata(saddr, buf, 4);
+	}
+		break;
+
+	case BYTE_LEN: {
+		buf[0] = waddr;
+		buf[1] = wdata;
+		rc = mt9d112_i2c_txdata(saddr, buf, 2);
+	}
+		break;
+
+	default:
+		break;
+	}
+
+	if (rc < 0)
+		CDBG(
+		"i2c_write failed, addr = 0x%x, val = 0x%x!\n",
+		waddr, wdata);
+
+	return rc;
+}
+
+static int32_t mt9d112_i2c_write_table(
+	struct mt9d112_i2c_reg_conf const *reg_conf_tbl,
+	int num_of_items_in_table)
+{
+	int i;
+	int32_t rc = -EIO;
+
+	for (i = 0; i < num_of_items_in_table; i++) {
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+			reg_conf_tbl->waddr, reg_conf_tbl->wdata,
+			reg_conf_tbl->width);
+		if (rc < 0)
+			break;
+		if (reg_conf_tbl->mdelay_time != 0)
+			mdelay(reg_conf_tbl->mdelay_time);
+		reg_conf_tbl++;
+	}
+
+	return rc;
+}
+
+static int mt9d112_i2c_rxdata(unsigned short saddr,
+	unsigned char *rxdata, int length)
+{
+	struct i2c_msg msgs[] = {
+	{
+		.addr   = saddr,
+		.flags = 0,
+		.len   = 2,
+		.buf   = rxdata,
+	},
+	{
+		.addr   = saddr,
+		.flags = I2C_M_RD,
+		.len   = length,
+		.buf   = rxdata,
+	},
+	};
+
+#if SENSOR_DEBUG
+	if (length == 2)
+		CDBG("msm_io_i2c_r: 0x%04x 0x%04x\n",
+			*(u16 *) rxdata, *(u16 *) (rxdata + 2));
+	else if (length == 4)
+		CDBG("msm_io_i2c_r: 0x%04x\n", *(u16 *) rxdata);
+	else
+		CDBG("msm_io_i2c_r: length = %d\n", length);
+#endif
+
+	if (i2c_transfer(mt9d112_client->adapter, msgs, 2) < 0) {
+		CDBG("mt9d112_i2c_rxdata failed!\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t mt9d112_i2c_read(unsigned short   saddr,
+	unsigned short raddr, unsigned short *rdata, enum mt9d112_width width)
+{
+	int32_t rc = 0;
+	unsigned char buf[4];
+
+	if (!rdata)
+		return -EIO;
+
+	memset(buf, 0, sizeof(buf));
+
+	switch (width) {
+	case WORD_LEN: {
+		buf[0] = (raddr & 0xFF00)>>8;
+		buf[1] = (raddr & 0x00FF);
+
+		rc = mt9d112_i2c_rxdata(saddr, buf, 2);
+		if (rc < 0)
+			return rc;
+
+		*rdata = buf[0] << 8 | buf[1];
+	}
+		break;
+
+	default:
+		break;
+	}
+
+	if (rc < 0)
+		CDBG("mt9d112_i2c_read failed!\n");
+
+	return rc;
+}
+
+static int32_t mt9d112_set_lens_roll_off(void)
+{
+	int32_t rc = 0;
+	rc = mt9d112_i2c_write_table(&mt9d112_regs.rftbl[0],
+								 mt9d112_regs.rftbl_size);
+	return rc;
+}
+
+static long mt9d112_reg_init(void)
+{
+	int32_t array_length;
+	int32_t i;
+	long rc;
+
+	/* PLL Setup Start */
+	rc = mt9d112_i2c_write_table(&mt9d112_regs.plltbl[0],
+					mt9d112_regs.plltbl_size);
+
+	if (rc < 0)
+		return rc;
+	/* PLL Setup End   */
+
+	array_length = mt9d112_regs.prev_snap_reg_settings_size;
+
+	/* Configure sensor for Preview mode and Snapshot mode */
+	for (i = 0; i < array_length; i++) {
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+		  mt9d112_regs.prev_snap_reg_settings[i].register_address,
+		  mt9d112_regs.prev_snap_reg_settings[i].register_value,
+		  WORD_LEN);
+
+		if (rc < 0)
+			return rc;
+	}
+
+	/* Configure for Noise Reduction, Saturation and Aperture Correction */
+	array_length = mt9d112_regs.noise_reduction_reg_settings_size;
+
+	for (i = 0; i < array_length; i++) {
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+			mt9d112_regs.noise_reduction_reg_settings[i].register_address,
+			mt9d112_regs.noise_reduction_reg_settings[i].register_value,
+			WORD_LEN);
+
+		if (rc < 0)
+			return rc;
+	}
+
+	/* Set Color Kill Saturation point to optimum value */
+	rc =
+	mt9d112_i2c_write(mt9d112_client->addr,
+	0x35A4,
+	0x0593,
+	WORD_LEN);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9d112_i2c_write_table(&mt9d112_regs.stbl[0],
+					mt9d112_regs.stbl_size);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9d112_set_lens_roll_off();
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+
+static long mt9d112_set_effect(int mode, int effect)
+{
+	uint16_t reg_addr;
+	uint16_t reg_val;
+	long rc = 0;
+
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		/* Context A Special Effects */
+		reg_addr = 0x2799;
+		break;
+
+	case SENSOR_RAW_SNAPSHOT_MODE:
+	case SENSOR_SNAPSHOT_MODE:
+		/* Context B Special Effects */
+		reg_addr = 0x279B;
+		break;
+
+	default:
+		reg_addr = 0x2799;
+		break;
+	}
+
+	switch (effect) {
+	case CAMERA_EFFECT_OFF: {
+		reg_val = 0x6440;
+
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+			0x338C, reg_addr, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+			0x3390, reg_val, WORD_LEN);
+		if (rc < 0)
+			return rc;
+	}
+			break;
+
+	case CAMERA_EFFECT_MONO: {
+		reg_val = 0x6441;
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+			0x338C, reg_addr, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+			0x3390, reg_val, WORD_LEN);
+		if (rc < 0)
+			return rc;
+	}
+		break;
+
+	case CAMERA_EFFECT_NEGATIVE: {
+		reg_val = 0x6443;
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+			0x338C, reg_addr, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+			0x3390, reg_val, WORD_LEN);
+		if (rc < 0)
+			return rc;
+	}
+		break;
+
+	case CAMERA_EFFECT_SOLARIZE: {
+		reg_val = 0x6445;
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+			0x338C, reg_addr, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+			0x3390, reg_val, WORD_LEN);
+		if (rc < 0)
+			return rc;
+	}
+		break;
+
+	case CAMERA_EFFECT_SEPIA: {
+		reg_val = 0x6442;
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+			0x338C, reg_addr, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+			0x3390, reg_val, WORD_LEN);
+		if (rc < 0)
+			return rc;
+	}
+		break;
+
+	default: {
+		reg_val = 0x6440;
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+			0x338C, reg_addr, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc = mt9d112_i2c_write(mt9d112_client->addr,
+			0x3390, reg_val, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		return -EINVAL;
+	}
+	}
+	mt9d112_effect = effect;
+	/* Refresh Sequencer */
+	rc = mt9d112_i2c_write(mt9d112_client->addr,
+		0x338C, 0xA103, WORD_LEN);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9d112_i2c_write(mt9d112_client->addr,
+		0x3390, 0x0005, WORD_LEN);
+
+	return rc;
+}
+
+static long mt9d112_set_sensor_mode(int mode)
+{
+	uint16_t clock;
+	long rc = 0;
+
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		rc =
+			mt9d112_i2c_write(mt9d112_client->addr,
+				0x338C, 0xA20C, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9d112_i2c_write(mt9d112_client->addr,
+				0x3390, 0x0004, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9d112_i2c_write(mt9d112_client->addr,
+				0x338C, 0xA215, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9d112_i2c_write(mt9d112_client->addr,
+				0x3390, 0x0004, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9d112_i2c_write(mt9d112_client->addr,
+				0x338C, 0xA20B, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9d112_i2c_write(mt9d112_client->addr,
+				0x3390, 0x0000, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		clock = 0x23C;
+
+		rc =
+			mt9d112_i2c_write(mt9d112_client->addr,
+				0x341C, clock, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9d112_i2c_write(mt9d112_client->addr,
+				0x338C, 0xA103, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9d112_i2c_write(mt9d112_client->addr,
+				0x3390, 0x0001, WORD_LEN);
+		if (rc < 0)
+			return rc;
+		mdelay(5);
+
+		break;
+
+	case SENSOR_SNAPSHOT_MODE:
+		/* Switch to lower fps for Snapshot */
+		rc =
+			mt9d112_i2c_write(mt9d112_client->addr,
+				0x341C, 0x0120, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9d112_i2c_write(mt9d112_client->addr,
+				0x338C, 0xA120, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		msleep(40);/*waiting for the delay of one frame*/
+		rc =
+			mt9d112_i2c_write(mt9d112_client->addr,
+				0x3390, 0x0002, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		msleep(80);/*waiting for the delay of two frames*/
+
+		rc =
+			mt9d112_i2c_write(mt9d112_client->addr,
+				0x338C, 0xA103, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		msleep(40);/*waiting for the delay of one frame*/
+		rc =
+			mt9d112_i2c_write(mt9d112_client->addr,
+				0x3390, 0x0002, WORD_LEN);
+		if (rc < 0)
+			return rc;
+		break;
+
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		/* Setting the effect to CAMERA_EFFECT_OFF */
+		rc =
+			mt9d112_i2c_write(mt9d112_client->addr,
+				0x338C, 0x279B, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9d112_i2c_write(mt9d112_client->addr,
+			0x3390, 0x6440, WORD_LEN);
+		if (rc < 0)
+			return rc;
+		msleep(40);/*waiting for the delay of one frame*/
+		/* Switch to lower fps for Snapshot */
+		rc =
+			mt9d112_i2c_write(mt9d112_client->addr,
+				0x341C, 0x0120, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9d112_i2c_write(mt9d112_client->addr,
+				0x338C, 0xA120, WORD_LEN);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9d112_i2c_write(mt9d112_client->addr,
+				0x3390, 0x0002, WORD_LEN);
+		if (rc < 0)
+			return rc;
+		msleep(80);/*waiting for the delay of two frames frame*/
+		rc =
+			mt9d112_i2c_write(mt9d112_client->addr,
+				0x338C, 0xA103, WORD_LEN);
+		if (rc < 0)
+			return rc;
+		msleep(40);/*waiting for the delay of one frame*/
+		rc =
+			mt9d112_i2c_write(mt9d112_client->addr,
+				0x3390, 0x0002, WORD_LEN);
+		if (rc < 0)
+			return rc;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int mt9d112_sensor_init_probe(const struct msm_camera_sensor_info *data)
+{
+	uint16_t model_id = 0;
+	int rc = 0;
+
+	CDBG("init entry \n");
+	rc = mt9d112_reset(data);
+	if (rc < 0) {
+		CDBG("reset failed!\n");
+		goto init_probe_fail;
+	}
+
+	msm_camio_clk_rate_set(24000000);
+	msleep(20);
+
+	/* Micron suggested Power up block Start:
+	* Put MCU into Reset - Stop MCU */
+	rc = mt9d112_i2c_write(mt9d112_client->addr,
+		REG_MT9D112_MCU_BOOT, 0x0501, WORD_LEN);
+	if (rc < 0)
+		goto init_probe_fail;
+
+	/* Pull MCU from Reset - Start MCU */
+	rc = mt9d112_i2c_write(mt9d112_client->addr,
+		REG_MT9D112_MCU_BOOT, 0x0500, WORD_LEN);
+	if (rc < 0)
+		goto init_probe_fail;
+
+	mdelay(5);
+
+	/* Micron Suggested - Power up block */
+	rc = mt9d112_i2c_write(mt9d112_client->addr,
+		REG_MT9D112_SENSOR_RESET, 0x0ACC, WORD_LEN);
+	if (rc < 0)
+		goto init_probe_fail;
+
+	rc = mt9d112_i2c_write(mt9d112_client->addr,
+		REG_MT9D112_STANDBY_CONTROL, 0x0008, WORD_LEN);
+	if (rc < 0)
+		goto init_probe_fail;
+
+	/* FUSED_DEFECT_CORRECTION */
+	rc = mt9d112_i2c_write(mt9d112_client->addr,
+		0x33F4, 0x031D, WORD_LEN);
+	if (rc < 0)
+		goto init_probe_fail;
+
+	mdelay(5);
+
+	/* Micron suggested Power up block End */
+	/* Read the Model ID of the sensor */
+	rc = mt9d112_i2c_read(mt9d112_client->addr,
+		REG_MT9D112_MODEL_ID, &model_id, WORD_LEN);
+	if (rc < 0)
+		goto init_probe_fail;
+
+	CDBG("mt9d112 model_id = 0x%x\n", model_id);
+
+	/* Check if it matches it with the value in Datasheet */
+	if (model_id != MT9D112_MODEL_ID) {
+		rc = -EINVAL;
+		goto init_probe_fail;
+	}
+
+	rc = mt9d112_reg_init();
+	if (rc < 0)
+		goto init_probe_fail;
+
+	return rc;
+
+init_probe_fail:
+	return rc;
+}
+
+int mt9d112_sensor_init(const struct msm_camera_sensor_info *data)
+{
+	int rc = 0;
+
+	mt9d112_ctrl = kzalloc(sizeof(struct mt9d112_ctrl), GFP_KERNEL);
+	if (!mt9d112_ctrl) {
+		CDBG("mt9d112_init failed!\n");
+		rc = -ENOMEM;
+		goto init_done;
+	}
+
+	if (data)
+		mt9d112_ctrl->sensordata = data;
+
+	/* Input MCLK = 24MHz */
+	msm_camio_clk_rate_set(24000000);
+	mdelay(5);
+
+	msm_camio_camif_pad_reg_reset();
+
+	rc = mt9d112_sensor_init_probe(data);
+	if (rc < 0) {
+		CDBG("mt9d112_sensor_init failed!\n");
+		goto init_fail;
+	}
+
+init_done:
+	return rc;
+
+init_fail:
+	kfree(mt9d112_ctrl);
+	return rc;
+}
+
+static int mt9d112_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&mt9d112_wait_queue);
+	return 0;
+}
+
+int mt9d112_sensor_config(void __user *argp)
+{
+	struct sensor_cfg_data cfg_data;
+	long   rc = 0;
+
+	if (copy_from_user(&cfg_data,
+			(void *)argp,
+			sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+
+	/* down(&mt9d112_sem); */
+
+	CDBG("mt9d112_ioctl, cfgtype = %d, mode = %d\n",
+		cfg_data.cfgtype, cfg_data.mode);
+
+		switch (cfg_data.cfgtype) {
+		case CFG_SET_MODE:
+			rc = mt9d112_set_sensor_mode(
+						cfg_data.mode);
+			break;
+
+		case CFG_SET_EFFECT:
+			rc = mt9d112_set_effect(cfg_data.mode,
+						cfg_data.cfg.effect);
+			break;
+
+		case CFG_GET_AF_MAX_STEPS:
+		default:
+			rc = -EINVAL;
+			break;
+		}
+
+	/* up(&mt9d112_sem); */
+
+	return rc;
+}
+
+int mt9d112_sensor_release(void)
+{
+	int rc = 0;
+
+	/* down(&mt9d112_sem); */
+	gpio_set_value_cansleep(mt9d112_ctrl->sensordata->sensor_reset, 0);
+	msleep(20);
+	gpio_free(mt9d112_ctrl->sensordata->sensor_reset);
+	kfree(mt9d112_ctrl);
+	/* up(&mt9d112_sem); */
+
+	return rc;
+}
+
+static int mt9d112_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int rc = 0;
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		rc = -ENOTSUPP;
+		goto probe_failure;
+	}
+
+	mt9d112_sensorw =
+		kzalloc(sizeof(struct mt9d112_work), GFP_KERNEL);
+
+	if (!mt9d112_sensorw) {
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, mt9d112_sensorw);
+	mt9d112_init_client(client);
+	mt9d112_client = client;
+
+	CDBG("mt9d112_probe succeeded!\n");
+
+	return 0;
+
+probe_failure:
+	kfree(mt9d112_sensorw);
+	mt9d112_sensorw = NULL;
+	CDBG("mt9d112_probe failed!\n");
+	return rc;
+}
+
+static const struct i2c_device_id mt9d112_i2c_id[] = {
+	{ "mt9d112", 0},
+	{ },
+};
+
+static struct i2c_driver mt9d112_i2c_driver = {
+	.id_table = mt9d112_i2c_id,
+	.probe  = mt9d112_i2c_probe,
+	.remove = __exit_p(mt9d112_i2c_remove),
+	.driver = {
+		.name = "mt9d112",
+	},
+};
+
+static int mt9d112_sensor_probe(const struct msm_camera_sensor_info *info,
+				struct msm_sensor_ctrl *s)
+{
+	int rc = i2c_add_driver(&mt9d112_i2c_driver);
+	if (rc < 0 || mt9d112_client == NULL) {
+		rc = -ENOTSUPP;
+		goto probe_done;
+	}
+
+	/* Input MCLK = 24MHz */
+	msm_camio_clk_rate_set(24000000);
+	mdelay(5);
+
+	rc = mt9d112_sensor_init_probe(info);
+	if (rc < 0) {
+		gpio_free(info->sensor_reset);
+		goto probe_done;
+	}
+	s->s_init = mt9d112_sensor_init;
+	s->s_release = mt9d112_sensor_release;
+	s->s_config  = mt9d112_sensor_config;
+	s->s_camera_type = FRONT_CAMERA_2D;
+	s->s_mount_angle  = 0;
+	gpio_set_value_cansleep(info->sensor_reset, 0);
+	msleep(20);
+	gpio_free(info->sensor_reset);
+
+probe_done:
+	CDBG("%s %s:%d\n", __FILE__, __func__, __LINE__);
+	return rc;
+}
+
+static int __mt9d112_probe(struct platform_device *pdev)
+{
+	return msm_camera_drv_start(pdev, mt9d112_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = __mt9d112_probe,
+	.driver = {
+		.name = "msm_camera_mt9d112",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init mt9d112_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(mt9d112_init);
diff --git a/drivers/media/video/msm/mt9d112.h b/drivers/media/video/msm/mt9d112.h
new file mode 100644
index 0000000..309fcec
--- /dev/null
+++ b/drivers/media/video/msm/mt9d112.h
@@ -0,0 +1,47 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#ifndef MT9D112_H
+#define MT9D112_H
+
+#include <linux/types.h>
+#include <mach/camera.h>
+
+extern struct mt9d112_reg mt9d112_regs;
+
+enum mt9d112_width {
+	WORD_LEN,
+	BYTE_LEN
+};
+
+struct mt9d112_i2c_reg_conf {
+	unsigned short waddr;
+	unsigned short wdata;
+	enum mt9d112_width width;
+	unsigned short mdelay_time;
+};
+
+struct mt9d112_reg {
+	const struct register_address_value_pair *prev_snap_reg_settings;
+	uint16_t prev_snap_reg_settings_size;
+	const struct register_address_value_pair *noise_reduction_reg_settings;
+	uint16_t noise_reduction_reg_settings_size;
+	const struct mt9d112_i2c_reg_conf *plltbl;
+	uint16_t plltbl_size;
+	const struct mt9d112_i2c_reg_conf *stbl;
+	uint16_t stbl_size;
+	const struct mt9d112_i2c_reg_conf *rftbl;
+	uint16_t rftbl_size;
+};
+
+#endif /* MT9D112_H */
diff --git a/drivers/media/video/msm/mt9d112_reg.c b/drivers/media/video/msm/mt9d112_reg.c
new file mode 100644
index 0000000..24edaf2
--- /dev/null
+++ b/drivers/media/video/msm/mt9d112_reg.c
@@ -0,0 +1,319 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include "mt9d112.h"
+
+
+struct register_address_value_pair const
+preview_snapshot_mode_reg_settings_array[] = {
+	{0x338C, 0x2703},
+	{0x3390, 800},    /* Output Width (P) = 640 */
+	{0x338C, 0x2705},
+	{0x3390, 600},    /* Output Height (P) = 480 */
+	{0x338C, 0x2707},
+	{0x3390, 0x0640}, /* Output Width (S) = 1600 */
+	{0x338C, 0x2709},
+	{0x3390, 0x04B0}, /* Output Height (S) = 1200 */
+	{0x338C, 0x270D},
+	{0x3390, 0x0000}, /* Row Start (P) = 0 */
+	{0x338C, 0x270F},
+	{0x3390, 0x0000}, /* Column Start (P) = 0 */
+	{0x338C, 0x2711},
+	{0x3390, 0x04BD}, /* Row End (P) = 1213 */
+	{0x338C, 0x2713},
+	{0x3390, 0x064D}, /* Column End (P) = 1613 */
+	{0x338C, 0x2715},
+	{0x3390, 0x0000}, /* Extra Delay (P) = 0 */
+	{0x338C, 0x2717},
+	{0x3390, 0x2111}, /* Row Speed (P) = 8465 */
+	{0x338C, 0x2719},
+	{0x3390, 0x046C}, /* Read Mode (P) = 1132 */
+	{0x338C, 0x271B},
+	{0x3390, 0x024F}, /* Sensor_Sample_Time_pck(P) = 591 */
+	{0x338C, 0x271D},
+	{0x3390, 0x0102}, /* Sensor_Fine_Correction(P) = 258 */
+	{0x338C, 0x271F},
+	{0x3390, 0x0279}, /* Sensor_Fine_IT_min(P) = 633 */
+	{0x338C, 0x2721},
+	{0x3390, 0x0155}, /* Sensor_Fine_IT_max_margin(P) = 341 */
+	{0x338C, 0x2723},
+	{0x3390, 659},    /* Frame Lines (P) = 679 */
+	{0x338C, 0x2725},
+	{0x3390, 0x061B}, /* Line Length (P) = 1563 */
+	{0x338C, 0x2727},
+	{0x3390, 0x2020},
+	{0x338C, 0x2729},
+	{0x3390, 0x2020},
+	{0x338C, 0x272B},
+	{0x3390, 0x1020},
+	{0x338C, 0x272D},
+	{0x3390, 0x2007},
+	{0x338C, 0x272F},
+	{0x3390, 0x0004}, /* Row Start(S) = 4 */
+	{0x338C, 0x2731},
+	{0x3390, 0x0004}, /* Column Start(S) = 4 */
+	{0x338C, 0x2733},
+	{0x3390, 0x04BB}, /* Row End(S) = 1211 */
+	{0x338C, 0x2735},
+	{0x3390, 0x064B}, /* Column End(S) = 1611 */
+	{0x338C, 0x2737},
+	{0x3390, 0x04CE}, /* Extra Delay(S) = 1230 */
+	{0x338C, 0x2739},
+	{0x3390, 0x2111}, /* Row Speed(S) = 8465 */
+	{0x338C, 0x273B},
+	{0x3390, 0x0024}, /* Read Mode(S) = 36 */
+	{0x338C, 0x273D},
+	{0x3390, 0x0120}, /* Sensor sample time pck(S) = 288 */
+	{0x338C, 0x2741},
+	{0x3390, 0x0169}, /* Sensor_Fine_IT_min(P) = 361 */
+	{0x338C, 0x2745},
+	{0x3390, 0x04FF}, /* Frame Lines(S) = 1279 */
+	{0x338C, 0x2747},
+	{0x3390, 0x0824}, /* Line Length(S) = 2084 */
+	{0x338C, 0x2751},
+	{0x3390, 0x0000}, /* Crop_X0(P) = 0 */
+	{0x338C, 0x2753},
+	{0x3390, 0x0320}, /* Crop_X1(P) = 800 */
+	{0x338C, 0x2755},
+	{0x3390, 0x0000}, /* Crop_Y0(P) = 0 */
+	{0x338C, 0x2757},
+	{0x3390, 0x0258}, /* Crop_Y1(P) = 600 */
+	{0x338C, 0x275F},
+	{0x3390, 0x0000}, /* Crop_X0(S) = 0 */
+	{0x338C, 0x2761},
+	{0x3390, 0x0640}, /* Crop_X1(S) = 1600 */
+	{0x338C, 0x2763},
+	{0x3390, 0x0000}, /* Crop_Y0(S) = 0 */
+	{0x338C, 0x2765},
+	{0x3390, 0x04B0}, /* Crop_Y1(S) = 1200 */
+	{0x338C, 0x222E},
+	{0x3390, 0x00A0}, /* R9 Step = 160 */
+	{0x338C, 0xA408},
+	{0x3390, 0x001F},
+	{0x338C, 0xA409},
+	{0x3390, 0x0021},
+	{0x338C, 0xA40A},
+	{0x3390, 0x0025},
+	{0x338C, 0xA40B},
+	{0x3390, 0x0027},
+	{0x338C, 0x2411},
+	{0x3390, 0x00A0},
+	{0x338C, 0x2413},
+	{0x3390, 0x00C0},
+	{0x338C, 0x2415},
+	{0x3390, 0x00A0},
+	{0x338C, 0x2417},
+	{0x3390, 0x00C0},
+	{0x338C, 0x2799},
+	{0x3390, 0x6408}, /* MODE_SPEC_EFFECTS(P) */
+	{0x338C, 0x279B},
+	{0x3390, 0x6408}, /* MODE_SPEC_EFFECTS(S) */
+};
+
+static struct register_address_value_pair const
+noise_reduction_reg_settings_array[] = {
+	{0x338C, 0xA76D},
+	{0x3390, 0x0003},
+	{0x338C, 0xA76E},
+	{0x3390, 0x0003},
+	{0x338C, 0xA76F},
+	{0x3390, 0},
+	{0x338C, 0xA770},
+	{0x3390, 21},
+	{0x338C, 0xA771},
+	{0x3390, 37},
+	{0x338C, 0xA772},
+	{0x3390, 63},
+	{0x338C, 0xA773},
+	{0x3390, 100},
+	{0x338C, 0xA774},
+	{0x3390, 128},
+	{0x338C, 0xA775},
+	{0x3390, 151},
+	{0x338C, 0xA776},
+	{0x3390, 169},
+	{0x338C, 0xA777},
+	{0x3390, 186},
+	{0x338C, 0xA778},
+	{0x3390, 199},
+	{0x338C, 0xA779},
+	{0x3390, 210},
+	{0x338C, 0xA77A},
+	{0x3390, 220},
+	{0x338C, 0xA77B},
+	{0x3390, 228},
+	{0x338C, 0xA77C},
+	{0x3390, 234},
+	{0x338C, 0xA77D},
+	{0x3390, 240},
+	{0x338C, 0xA77E},
+	{0x3390, 244},
+	{0x338C, 0xA77F},
+	{0x3390, 248},
+	{0x338C, 0xA780},
+	{0x3390, 252},
+	{0x338C, 0xA781},
+	{0x3390, 255},
+	{0x338C, 0xA782},
+	{0x3390, 0},
+	{0x338C, 0xA783},
+	{0x3390, 21},
+	{0x338C, 0xA784},
+	{0x3390, 37},
+	{0x338C, 0xA785},
+	{0x3390, 63},
+	{0x338C, 0xA786},
+	{0x3390, 100},
+	{0x338C, 0xA787},
+	{0x3390, 128},
+	{0x338C, 0xA788},
+	{0x3390, 151},
+	{0x338C, 0xA789},
+	{0x3390, 169},
+	{0x338C, 0xA78A},
+	{0x3390, 186},
+	{0x338C, 0xA78B},
+	{0x3390, 199},
+	{0x338C, 0xA78C},
+	{0x3390, 210},
+	{0x338C, 0xA78D},
+	{0x3390, 220},
+	{0x338C, 0xA78E},
+	{0x3390, 228},
+	{0x338C, 0xA78F},
+	{0x3390, 234},
+	{0x338C, 0xA790},
+	{0x3390, 240},
+	{0x338C, 0xA791},
+	{0x3390, 244},
+	{0x338C, 0xA793},
+	{0x3390, 252},
+	{0x338C, 0xA794},
+	{0x3390, 255},
+	{0x338C, 0xA103},
+	{0x3390, 6},
+};
+
+static const struct mt9d112_i2c_reg_conf const lens_roll_off_tbl[] = {
+	{ 0x34CE, 0x81A0, WORD_LEN, 0 },
+	{ 0x34D0, 0x6331, WORD_LEN, 0 },
+	{ 0x34D2, 0x3394, WORD_LEN, 0 },
+	{ 0x34D4, 0x9966, WORD_LEN, 0 },
+	{ 0x34D6, 0x4B25, WORD_LEN, 0 },
+	{ 0x34D8, 0x2670, WORD_LEN, 0 },
+	{ 0x34DA, 0x724C, WORD_LEN, 0 },
+	{ 0x34DC, 0xFFFD, WORD_LEN, 0 },
+	{ 0x34DE, 0x00CA, WORD_LEN, 0 },
+	{ 0x34E6, 0x00AC, WORD_LEN, 0 },
+	{ 0x34EE, 0x0EE1, WORD_LEN, 0 },
+	{ 0x34F6, 0x0D87, WORD_LEN, 0 },
+	{ 0x3500, 0xE1F7, WORD_LEN, 0 },
+	{ 0x3508, 0x1CF4, WORD_LEN, 0 },
+	{ 0x3510, 0x1D28, WORD_LEN, 0 },
+	{ 0x3518, 0x1F26, WORD_LEN, 0 },
+	{ 0x3520, 0x2220, WORD_LEN, 0 },
+	{ 0x3528, 0x333D, WORD_LEN, 0 },
+	{ 0x3530, 0x15D9, WORD_LEN, 0 },
+	{ 0x3538, 0xCFB8, WORD_LEN, 0 },
+	{ 0x354C, 0x05FE, WORD_LEN, 0 },
+	{ 0x3544, 0x05F8, WORD_LEN, 0 },
+	{ 0x355C, 0x0596, WORD_LEN, 0 },
+	{ 0x3554, 0x0611, WORD_LEN, 0 },
+	{ 0x34E0, 0x00F2, WORD_LEN, 0 },
+	{ 0x34E8, 0x00A8, WORD_LEN, 0 },
+	{ 0x34F0, 0x0F7B, WORD_LEN, 0 },
+	{ 0x34F8, 0x0CD7, WORD_LEN, 0 },
+	{ 0x3502, 0xFEDB, WORD_LEN, 0 },
+	{ 0x350A, 0x13E4, WORD_LEN, 0 },
+	{ 0x3512, 0x1F2C, WORD_LEN, 0 },
+	{ 0x351A, 0x1D20, WORD_LEN, 0 },
+	{ 0x3522, 0x2422, WORD_LEN, 0 },
+	{ 0x352A, 0x2925, WORD_LEN, 0 },
+	{ 0x3532, 0x1D04, WORD_LEN, 0 },
+	{ 0x353A, 0xFBF2, WORD_LEN, 0 },
+	{ 0x354E, 0x0616, WORD_LEN, 0 },
+	{ 0x3546, 0x0597, WORD_LEN, 0 },
+	{ 0x355E, 0x05CD, WORD_LEN, 0 },
+	{ 0x3556, 0x0529, WORD_LEN, 0 },
+	{ 0x34E4, 0x00B2, WORD_LEN, 0 },
+	{ 0x34EC, 0x005E, WORD_LEN, 0 },
+	{ 0x34F4, 0x0F43, WORD_LEN, 0 },
+	{ 0x34FC, 0x0E2F, WORD_LEN, 0 },
+	{ 0x3506, 0xF9FC, WORD_LEN, 0 },
+	{ 0x350E, 0x0CE4, WORD_LEN, 0 },
+	{ 0x3516, 0x1E1E, WORD_LEN, 0 },
+	{ 0x351E, 0x1B19, WORD_LEN, 0 },
+	{ 0x3526, 0x151B, WORD_LEN, 0 },
+	{ 0x352E, 0x1416, WORD_LEN, 0 },
+	{ 0x3536, 0x10FC, WORD_LEN, 0 },
+	{ 0x353E, 0xC018, WORD_LEN, 0 },
+	{ 0x3552, 0x06B4, WORD_LEN, 0 },
+	{ 0x354A, 0x0506, WORD_LEN, 0 },
+	{ 0x3562, 0x06AB, WORD_LEN, 0 },
+	{ 0x355A, 0x063A, WORD_LEN, 0 },
+	{ 0x34E2, 0x00E5, WORD_LEN, 0 },
+	{ 0x34EA, 0x008B, WORD_LEN, 0 },
+	{ 0x34F2, 0x0E4C, WORD_LEN, 0 },
+	{ 0x34FA, 0x0CA3, WORD_LEN, 0 },
+	{ 0x3504, 0x0907, WORD_LEN, 0 },
+	{ 0x350C, 0x1DFD, WORD_LEN, 0 },
+	{ 0x3514, 0x1E24, WORD_LEN, 0 },
+	{ 0x351C, 0x2529, WORD_LEN, 0 },
+	{ 0x3524, 0x1D20, WORD_LEN, 0 },
+	{ 0x352C, 0x2332, WORD_LEN, 0 },
+	{ 0x3534, 0x10E9, WORD_LEN, 0 },
+	{ 0x353C, 0x0BCB, WORD_LEN, 0 },
+	{ 0x3550, 0x04EF, WORD_LEN, 0 },
+	{ 0x3548, 0x0609, WORD_LEN, 0 },
+	{ 0x3560, 0x0580, WORD_LEN, 0 },
+	{ 0x3558, 0x05DD, WORD_LEN, 0 },
+	{ 0x3540, 0x0000, WORD_LEN, 0 },
+	{ 0x3542, 0x0000, WORD_LEN, 0 }
+};
+
+static const struct mt9d112_i2c_reg_conf const pll_setup_tbl[] = {
+	{ 0x341E, 0x8F09, WORD_LEN, 0 },
+	{ 0x341C, 0x0250, WORD_LEN, 0 },
+	{ 0x341E, 0x8F09, WORD_LEN, 5 },
+	{ 0x341E, 0x8F08, WORD_LEN, 0 }
+};
+
+/* Refresh Sequencer */
+static const struct mt9d112_i2c_reg_conf const sequencer_tbl[] = {
+	{ 0x338C, 0x2799, WORD_LEN, 0},
+	{ 0x3390, 0x6440, WORD_LEN, 5},
+	{ 0x338C, 0x279B, WORD_LEN, 0},
+	{ 0x3390, 0x6440, WORD_LEN, 5},
+	{ 0x338C, 0xA103, WORD_LEN, 0},
+	{ 0x3390, 0x0005, WORD_LEN, 5},
+	{ 0x338C, 0xA103, WORD_LEN, 0},
+	{ 0x3390, 0x0006, WORD_LEN, 5}
+};
+
+struct mt9d112_reg mt9d112_regs = {
+	.prev_snap_reg_settings = &preview_snapshot_mode_reg_settings_array[0],
+	.prev_snap_reg_settings_size = ARRAY_SIZE(
+		preview_snapshot_mode_reg_settings_array),
+	.noise_reduction_reg_settings = &noise_reduction_reg_settings_array[0],
+	.noise_reduction_reg_settings_size = ARRAY_SIZE(
+		noise_reduction_reg_settings_array),
+	.plltbl = pll_setup_tbl,
+	.plltbl_size = ARRAY_SIZE(pll_setup_tbl),
+	.stbl = sequencer_tbl,
+	.stbl_size = ARRAY_SIZE(sequencer_tbl),
+	.rftbl = lens_roll_off_tbl,
+	.rftbl_size = ARRAY_SIZE(lens_roll_off_tbl)
+};
+
+
+
diff --git a/drivers/media/video/msm/mt9d113.c b/drivers/media/video/msm/mt9d113.c
new file mode 100644
index 0000000..a6b6a28
--- /dev/null
+++ b/drivers/media/video/msm/mt9d113.c
@@ -0,0 +1,664 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <media/msm_camera.h>
+#include <mach/gpio.h>
+#include "mt9d113.h"
+
+/* Micron MT9D113 Registers and their values */
+#define  REG_MT9D113_MODEL_ID	0x0000
+#define  MT9D113_MODEL_ID		0x2580
+#define Q8						0x00000100
+
+struct mt9d113_work {
+	struct work_struct work;
+};
+
+static struct  mt9d113_work *mt9d113_sensorw;
+static struct  i2c_client *mt9d113_client;
+
+struct mt9d113_ctrl {
+	const struct msm_camera_sensor_info *sensordata;
+	uint32_t sensormode;
+	uint32_t fps_divider;/* init to 1 * 0x00000400 */
+	uint32_t pict_fps_divider;/* init to 1 * 0x00000400 */
+	uint16_t fps;
+	uint16_t curr_step_pos;
+	uint16_t my_reg_gain;
+	uint32_t my_reg_line_count;
+	uint16_t total_lines_per_frame;
+	uint16_t config_csi;
+	enum mt9d113_resolution_t prev_res;
+	enum mt9d113_resolution_t pict_res;
+	enum mt9d113_resolution_t curr_res;
+	enum mt9d113_test_mode_t  set_test;
+};
+
+static struct mt9d113_ctrl *mt9d113_ctrl;
+
+static DECLARE_WAIT_QUEUE_HEAD(mt9d113_wait_queue);
+DEFINE_MUTEX(mt9d113_mut);
+
+static int mt9d113_i2c_rxdata(unsigned short saddr,
+				unsigned char *rxdata, int length)
+{
+	struct i2c_msg msgs[] = {
+		{
+			.addr   = saddr,
+			.flags = 0,
+			.len   = 2,
+			.buf   = rxdata,
+		},
+		{
+			.addr   = saddr,
+			.flags = I2C_M_RD,
+			.len   = length,
+			.buf   = rxdata,
+		},
+	};
+	if (i2c_transfer(mt9d113_client->adapter, msgs, 2) < 0) {
+		CDBG("mt9d113_i2c_rxdata failed!\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+static int32_t mt9d113_i2c_read(unsigned short   saddr,
+				unsigned short raddr,
+				unsigned short *rdata,
+				enum mt9d113_width width)
+{
+	int32_t rc = 0;
+	unsigned char buf[4];
+	if (!rdata)
+		return -EIO;
+	memset(buf, 0, sizeof(buf));
+	switch (width) {
+	case WORD_LEN: {
+			buf[0] = (raddr & 0xFF00)>>8;
+			buf[1] = (raddr & 0x00FF);
+			rc = mt9d113_i2c_rxdata(saddr, buf, 2);
+			if (rc < 0)
+				return rc;
+			*rdata = buf[0] << 8 | buf[1];
+		}
+		break;
+	default:
+		break;
+	}
+	if (rc < 0)
+		CDBG("mt9d113_i2c_read failed !\n");
+	return rc;
+}
+
+static int32_t mt9d113_i2c_txdata(unsigned short saddr,
+				unsigned char *txdata, int length)
+{
+	struct i2c_msg msg[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = length,
+			.buf = txdata,
+		},
+	};
+	if (i2c_transfer(mt9d113_client->adapter, msg, 1) < 0) {
+		CDBG("mt9d113_i2c_txdata failed\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+static int32_t mt9d113_i2c_write(unsigned short saddr,
+				unsigned short waddr,
+				unsigned short wdata,
+				enum mt9d113_width width)
+{
+	int32_t rc = -EIO;
+	unsigned char buf[4];
+	memset(buf, 0, sizeof(buf));
+	switch (width) {
+	case WORD_LEN: {
+			buf[0] = (waddr & 0xFF00)>>8;
+			buf[1] = (waddr & 0x00FF);
+			buf[2] = (wdata & 0xFF00)>>8;
+			buf[3] = (wdata & 0x00FF);
+			rc = mt9d113_i2c_txdata(saddr, buf, 4);
+		}
+		break;
+	case BYTE_LEN: {
+			buf[0] = waddr;
+			buf[1] = wdata;
+			rc = mt9d113_i2c_txdata(saddr, buf, 2);
+		}
+		break;
+	default:
+		break;
+	}
+	if (rc < 0)
+		printk(KERN_ERR
+			"i2c_write failed, addr = 0x%x, val = 0x%x!\n",
+			waddr, wdata);
+	return rc;
+}
+
+static int32_t mt9d113_i2c_write_table(
+				struct mt9d113_i2c_reg_conf
+				const *reg_conf_tbl,
+				int num_of_items_in_table)
+{
+	int i;
+	int32_t rc = -EIO;
+	for (i = 0; i < num_of_items_in_table; i++) {
+		rc = mt9d113_i2c_write(mt9d113_client->addr,
+				reg_conf_tbl->waddr, reg_conf_tbl->wdata,
+				WORD_LEN);
+		if (rc < 0)
+			break;
+		reg_conf_tbl++;
+	}
+	return rc;
+}
+
+static long mt9d113_reg_init(void)
+{
+	uint16_t data = 0;
+	int32_t rc = 0;
+	int count = 0;
+	struct msm_camera_csi_params mt9d113_csi_params;
+	if (!mt9d113_ctrl->config_csi) {
+		mt9d113_csi_params.lane_cnt = 1;
+		mt9d113_csi_params.data_format = CSI_8BIT;
+		mt9d113_csi_params.lane_assign = 0xe4;
+		mt9d113_csi_params.dpcm_scheme = 0;
+		mt9d113_csi_params.settle_cnt = 0x14;
+		rc = msm_camio_csi_config(&mt9d113_csi_params);
+		mt9d113_ctrl->config_csi = 1;
+		msleep(50);
+	}
+	/* Disable parallel and enable mipi*/
+	rc = mt9d113_i2c_write(mt9d113_client->addr,
+				0x001A,
+				0x0051, WORD_LEN);
+	rc = mt9d113_i2c_write(mt9d113_client->addr,
+				0x001A,
+				0x0050,
+				WORD_LEN);
+	msleep(20);
+	rc = mt9d113_i2c_write(mt9d113_client->addr,
+				0x001A,
+				0x0058,
+				WORD_LEN);
+
+	/* Preset pll settings begin*/
+	rc = mt9d113_i2c_write_table(&mt9d113_regs.pll_tbl[0],
+				mt9d113_regs.pll_tbl_size);
+	if (rc < 0)
+		return rc;
+	rc = mt9d113_i2c_read(mt9d113_client->addr,
+				0x0014, &data, WORD_LEN);
+	data = data&0x8000;
+	/* Poll*/
+	while (data == 0x0000) {
+		data = 0;
+		rc = mt9d113_i2c_read(mt9d113_client->addr,
+				0x0014, &data, WORD_LEN);
+		data = data & 0x8000;
+		usleep_range(11000, 12000);
+		count++;
+		if (count == 100) {
+			CDBG(" Timeout:1\n");
+			break;
+		}
+	}
+	rc = mt9d113_i2c_write(mt9d113_client->addr,
+				0x0014,
+				0x20FA,
+				WORD_LEN);
+
+	/*Preset pll Ends*/
+	mt9d113_i2c_write(mt9d113_client->addr,
+				0x0018,
+				0x402D,
+				WORD_LEN);
+
+	mt9d113_i2c_write(mt9d113_client->addr,
+				0x0018,
+				0x402C,
+				WORD_LEN);
+	/*POLL_REG=0x0018,0x4000,!=0x0000,DELAY=10,TIMEOUT=100*/
+	data = 0;
+	rc = mt9d113_i2c_read(mt9d113_client->addr,
+		0x0018, &data, WORD_LEN);
+	data = data & 0x4000;
+	count = 0;
+	while (data != 0x0000) {
+		rc = mt9d113_i2c_read(mt9d113_client->addr,
+			0x0018, &data, WORD_LEN);
+		data = data & 0x4000;
+		CDBG(" data is %d\n" , data);
+		usleep_range(11000, 12000);
+		count++;
+		if (count == 100) {
+			CDBG(" Loop2 timeout: MT9D113\n");
+			break;
+		}
+		CDBG(" Not streaming\n");
+	}
+	CDBG("MT9D113: Start stream\n");
+	/*Preset Register Wizard Conf*/
+	rc = mt9d113_i2c_write_table(&mt9d113_regs.register_tbl[0],
+				mt9d113_regs.register_tbl_size);
+	if (rc < 0)
+		return rc;
+	rc = mt9d113_i2c_write_table(&mt9d113_regs.err_tbl[0],
+				mt9d113_regs.err_tbl_size);
+	if (rc < 0)
+		return rc;
+	rc = mt9d113_i2c_write_table(&mt9d113_regs.eeprom_tbl[0],
+				mt9d113_regs.eeprom_tbl_size);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9d113_i2c_write_table(&mt9d113_regs.low_light_tbl[0],
+				mt9d113_regs.low_light_tbl_size);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9d113_i2c_write_table(&mt9d113_regs.awb_tbl[0],
+				mt9d113_regs.awb_tbl_size);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9d113_i2c_write_table(&mt9d113_regs.patch_tbl[0],
+				mt9d113_regs.patch_tbl_size);
+	if (rc < 0)
+		return rc;
+
+	/*check patch load*/
+	mt9d113_i2c_write(mt9d113_client->addr,
+				0x098C,
+				0xA024,
+				WORD_LEN);
+	count = 0;
+	/*To check if patch is loaded properly
+	poll the register 0x990 till the condition is
+	met or till the timeout*/
+	data = 0;
+	rc = mt9d113_i2c_read(mt9d113_client->addr,
+				0x0990, &data, WORD_LEN);
+	while (data == 0) {
+		data = 0;
+		rc = mt9d113_i2c_read(mt9d113_client->addr,
+				0x0990, &data, WORD_LEN);
+		usleep_range(11000, 12000);
+		count++;
+		if (count == 100) {
+			CDBG("Timeout in patch loading\n");
+			break;
+		}
+	}
+		/*BITFIELD=0x0018, 0x0004, 0*/
+	/*Preset continue begin */
+	rc = mt9d113_i2c_write(mt9d113_client->addr, 0x0018, 0x0028,
+				WORD_LEN);
+	CDBG(" mt9d113 wait for seq done\n");
+	/* syncronize the FW with the sensor
+	MCU_ADDRESS [SEQ_CMD]*/
+	rc = mt9d113_i2c_write(mt9d113_client->addr,
+				0x098C, 0xA103, WORD_LEN);
+	rc = mt9d113_i2c_write(mt9d113_client->addr,
+				0x0990, 0x0006, WORD_LEN);
+		/*mt9d113 wait for seq done
+	 syncronize the FW with the sensor */
+	msleep(20);
+	/*Preset continue end */
+	CDBG(" MT9D113: Preset continue end\n");
+	rc = mt9d113_i2c_write(mt9d113_client->addr,
+				0x0012,
+				0x00F5,
+				WORD_LEN);
+	/*continue begin */
+	CDBG(" MT9D113: Preset continue begin\n");
+	rc = mt9d113_i2c_write(mt9d113_client->addr, 0x0018, 0x0028 ,
+				WORD_LEN);
+	/*mt9d113 wait for seq done
+	 syncronize the FW with the sensor
+	MCU_ADDRESS [SEQ_CMD]*/
+	msleep(20);
+	rc = mt9d113_i2c_write(mt9d113_client->addr,
+				0x098C, 0xA103, WORD_LEN);
+	/* MCU DATA */
+	rc = mt9d113_i2c_write(mt9d113_client->addr, 0x0990,
+				0x0006, WORD_LEN);
+	/*mt9d113 wait for seq done
+	syncronize the FW with the sensor */
+	/* MCU_ADDRESS [SEQ_CMD]*/
+	msleep(20);
+	/*Preset continue end*/
+	return rc;
+
+}
+
+static long mt9d113_set_sensor_mode(int mode)
+{
+	long rc = 0;
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		rc = mt9d113_reg_init();
+		CDBG("MT9D113: configure to preview begin\n");
+		rc =
+		mt9d113_i2c_write(mt9d113_client->addr,
+						0x098C, 0xA115, WORD_LEN);
+		if (rc < 0)
+			return rc;
+		rc =
+		mt9d113_i2c_write(mt9d113_client->addr,
+						0x0990, 0x0000, WORD_LEN);
+		if (rc < 0)
+			return rc;
+		rc =
+		mt9d113_i2c_write(mt9d113_client->addr,
+						0x098C, 0xA103, WORD_LEN);
+		if (rc < 0)
+			return rc;
+		rc =
+		mt9d113_i2c_write(mt9d113_client->addr,
+						0x098C, 0x0001, WORD_LEN);
+		if (rc < 0)
+			return rc;
+		break;
+	case SENSOR_SNAPSHOT_MODE:
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		rc =
+		mt9d113_i2c_write(mt9d113_client->addr,
+						0x098C, 0xA115, WORD_LEN);
+		rc =
+		mt9d113_i2c_write(mt9d113_client->addr,
+						0x098C, 0x0002, WORD_LEN);
+		rc =
+		mt9d113_i2c_write(mt9d113_client->addr,
+						0x098C, 0xA103, WORD_LEN);
+		rc =
+		mt9d113_i2c_write(mt9d113_client->addr,
+						0x098C, 0x0002, WORD_LEN);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int mt9d113_sensor_init_probe(const struct
+				msm_camera_sensor_info * data)
+{
+	uint16_t model_id = 0;
+	int rc = 0;
+	/* Read the Model ID of the sensor */
+	rc = mt9d113_i2c_read(mt9d113_client->addr,
+						REG_MT9D113_MODEL_ID,
+						&model_id, WORD_LEN);
+	if (rc < 0)
+		goto init_probe_fail;
+	/* Check if it matches it with the value in Datasheet */
+	if (model_id != MT9D113_MODEL_ID)
+		printk(KERN_INFO "mt9d113 model_id = 0x%x\n", model_id);
+	if (rc < 0)
+		goto init_probe_fail;
+	return rc;
+init_probe_fail:
+	printk(KERN_INFO "probe fail\n");
+	return rc;
+}
+
+static int mt9d113_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&mt9d113_wait_queue);
+	return 0;
+}
+
+int mt9d113_sensor_config(void __user *argp)
+{
+	struct sensor_cfg_data cfg_data;
+	long rc = 0;
+
+	if (copy_from_user(&cfg_data,
+					(void *)argp,
+					(sizeof(struct sensor_cfg_data))))
+		return -EFAULT;
+	mutex_lock(&mt9d113_mut);
+	CDBG("mt9d113_ioctl, cfgtype = %d, mode = %d\n",
+		 cfg_data.cfgtype, cfg_data.mode);
+	switch (cfg_data.cfgtype) {
+	case CFG_SET_MODE:
+		rc = mt9d113_set_sensor_mode(
+						cfg_data.mode);
+		break;
+	case CFG_SET_EFFECT:
+		return rc;
+	case CFG_GET_AF_MAX_STEPS:
+	default:
+		rc = -EINVAL;
+		break;
+	}
+	mutex_unlock(&mt9d113_mut);
+	return rc;
+}
+
+int mt9d113_sensor_release(void)
+{
+	int rc = 0;
+
+	mutex_lock(&mt9d113_mut);
+	gpio_set_value_cansleep(mt9d113_ctrl->sensordata->sensor_reset, 0);
+	msleep(20);
+	gpio_free(mt9d113_ctrl->sensordata->sensor_reset);
+	kfree(mt9d113_ctrl);
+	mutex_unlock(&mt9d113_mut);
+
+	return rc;
+}
+
+static int mt9d113_probe_init_done(const struct msm_camera_sensor_info
+				*data)
+{
+	gpio_free(data->sensor_reset);
+	return 0;
+}
+
+static int mt9d113_probe_init_sensor(const struct msm_camera_sensor_info
+				*data)
+{
+	int32_t rc = 0;
+	uint16_t chipid = 0;
+	rc = gpio_request(data->sensor_pwd, "mt9d113");
+	if (!rc) {
+		printk(KERN_INFO "sensor_reset = %d\n", rc);
+		gpio_direction_output(data->sensor_pwd, 0);
+		usleep_range(11000, 12000);
+	} else {
+		goto init_probe_done;
+	}
+	msleep(20);
+	rc = gpio_request(data->sensor_reset, "mt9d113");
+	printk(KERN_INFO " mt9d113_probe_init_sensor\n");
+	if (!rc) {
+		printk(KERN_INFO "sensor_reset = %d\n", rc);
+		gpio_direction_output(data->sensor_reset, 0);
+		usleep_range(11000, 12000);
+		gpio_set_value_cansleep(data->sensor_reset, 1);
+		usleep_range(11000, 12000);
+	} else
+		goto init_probe_done;
+	printk(KERN_INFO " mt9d113_probe_init_sensor called\n");
+	rc = mt9d113_i2c_read(mt9d113_client->addr, REG_MT9D113_MODEL_ID,
+						&chipid, 2);
+	if (rc < 0)
+		goto init_probe_fail;
+	/*Compare sensor ID to MT9D113 ID: */
+	if (chipid != MT9D113_MODEL_ID) {
+		printk(KERN_INFO "mt9d113_probe_init_sensor chip idis%d\n",
+			chipid);
+	}
+	CDBG("mt9d113_probe_init_sensor Success\n");
+	goto init_probe_done;
+init_probe_fail:
+	CDBG(" ov2720_probe_init_sensor fails\n");
+	gpio_set_value_cansleep(data->sensor_reset, 0);
+	mt9d113_probe_init_done(data);
+init_probe_done:
+	printk(KERN_INFO " mt9d113_probe_init_sensor finishes\n");
+	return rc;
+}
+
+static int mt9d113_i2c_probe(struct i2c_client *client,
+				const struct i2c_device_id *id)
+{
+	int rc = 0;
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		rc = -ENOTSUPP;
+		goto probe_failure;
+	}
+	mt9d113_sensorw =
+	kzalloc(sizeof(struct mt9d113_work), GFP_KERNEL);
+	if (!mt9d113_sensorw) {
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+	i2c_set_clientdata(client, mt9d113_sensorw);
+	mt9d113_init_client(client);
+	mt9d113_client = client;
+	CDBG("mt9d113_probe succeeded!\n");
+	return 0;
+probe_failure:
+	kfree(mt9d113_sensorw);
+	mt9d113_sensorw = NULL;
+	CDBG("mt9d113_probe failed!\n");
+	return rc;
+}
+
+static const struct i2c_device_id mt9d113_i2c_id[] = {
+	{ "mt9d113", 0},
+	{},
+};
+
+static struct i2c_driver mt9d113_i2c_driver = {
+	.id_table = mt9d113_i2c_id,
+	.probe  = mt9d113_i2c_probe,
+	.remove = __exit_p(mt9d113_i2c_remove),
+			  .driver = {
+		.name = "mt9d113",
+	},
+};
+
+int mt9d113_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc = 0;
+	mt9d113_ctrl = kzalloc(sizeof(struct mt9d113_ctrl), GFP_KERNEL);
+	if (!mt9d113_ctrl) {
+		printk(KERN_INFO "mt9d113_init failed!\n");
+		rc = -ENOMEM;
+		goto init_done;
+	}
+	mt9d113_ctrl->fps_divider = 1 * 0x00000400;
+	mt9d113_ctrl->pict_fps_divider = 1 * 0x00000400;
+	mt9d113_ctrl->set_test = TEST_OFF;
+	mt9d113_ctrl->config_csi = 0;
+	mt9d113_ctrl->prev_res = QTR_SIZE;
+	mt9d113_ctrl->pict_res = FULL_SIZE;
+	mt9d113_ctrl->curr_res = INVALID_SIZE;
+	if (data)
+		mt9d113_ctrl->sensordata = data;
+	if (rc < 0) {
+		printk(KERN_INFO "mt9d113_sensor_open_init fail\n");
+		return rc;
+	}
+		/* enable mclk first */
+		msm_camio_clk_rate_set(24000000);
+		msleep(20);
+		rc = mt9d113_probe_init_sensor(data);
+		if (rc < 0)
+			goto init_fail;
+		mt9d113_ctrl->fps = 30*Q8;
+		rc = mt9d113_sensor_init_probe(data);
+		if (rc < 0) {
+			gpio_set_value_cansleep(data->sensor_reset, 0);
+			goto init_fail;
+		} else
+			printk(KERN_ERR "%s: %d\n", __func__, __LINE__);
+		goto init_done;
+init_fail:
+		printk(KERN_INFO "init_fail\n");
+		mt9d113_probe_init_done(data);
+init_done:
+		CDBG("init_done\n");
+		return rc;
+}
+
+static int mt9d113_sensor_probe(const struct msm_camera_sensor_info
+				*info,
+				struct msm_sensor_ctrl *s)
+{
+	int rc = 0;
+	rc = i2c_add_driver(&mt9d113_i2c_driver);
+	if (rc < 0 || mt9d113_client == NULL) {
+		rc = -ENOTSUPP;
+		goto probe_fail;
+	}
+	msm_camio_clk_rate_set(24000000);
+	usleep_range(5000, 6000);
+	rc = mt9d113_probe_init_sensor(info);
+	if (rc < 0)
+		goto probe_fail;
+	s->s_init = mt9d113_sensor_open_init;
+	s->s_release = mt9d113_sensor_release;
+	s->s_config  = mt9d113_sensor_config;
+	s->s_camera_type = FRONT_CAMERA_2D;
+	s->s_mount_angle  = 0;
+	gpio_set_value_cansleep(info->sensor_reset, 0);
+	mt9d113_probe_init_done(info);
+	return rc;
+probe_fail:
+	printk(KERN_INFO "mt9d113_sensor_probe: SENSOR PROBE FAILS!\n");
+	return rc;
+}
+
+static int __mt9d113_probe(struct platform_device *pdev)
+{
+	return msm_camera_drv_start(pdev, mt9d113_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = __mt9d113_probe,
+	.driver = {
+		.name = "msm_camera_mt9d113",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init mt9d113_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(mt9d113_init);
+
+MODULE_DESCRIPTION("Micron 2MP YUV sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/mt9d113.h b/drivers/media/video/msm/mt9d113.h
new file mode 100644
index 0000000..f22f16c
--- /dev/null
+++ b/drivers/media/video/msm/mt9d113.h
@@ -0,0 +1,66 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#ifndef MT9D113_H
+#define MT9D113_H
+
+#include <linux/types.h>
+#include <mach/camera.h>
+
+extern struct mt9d113_reg mt9d113_regs;
+
+enum mt9d113_width {
+	WORD_LEN,
+	BYTE_LEN
+};
+
+struct mt9d113_i2c_reg_conf {
+	unsigned short waddr;
+	unsigned short wdata;
+};
+
+struct mt9d113_reg {
+	const struct mt9d113_i2c_reg_conf *pll_tbl;
+	uint16_t pll_tbl_size;
+	const struct mt9d113_i2c_reg_conf *register_tbl;
+	uint16_t register_tbl_size;
+	const struct mt9d113_i2c_reg_conf *err_tbl;
+	uint16_t err_tbl_size;
+	const struct mt9d113_i2c_reg_conf *low_light_tbl;
+	uint16_t low_light_tbl_size;
+	const struct mt9d113_i2c_reg_conf *awb_tbl;
+	uint16_t awb_tbl_size;
+	const struct mt9d113_i2c_reg_conf *patch_tbl;
+	uint16_t patch_tbl_size;
+	const struct mt9d113_i2c_reg_conf *eeprom_tbl ;
+	uint16_t eeprom_tbl_size ;
+};
+
+enum mt9d113_test_mode_t {
+	TEST_OFF,
+	TEST_1,
+	TEST_2,
+	TEST_3
+};
+
+enum mt9d113_resolution_t {
+	QTR_SIZE,
+	FULL_SIZE,
+	INVALID_SIZE
+};
+
+enum mt9d113_setting {
+	RES_PREVIEW,
+	RES_CAPTURE
+};
+#endif /* MT9D113_H */
diff --git a/drivers/media/video/msm/mt9d113_reg.c b/drivers/media/video/msm/mt9d113_reg.c
new file mode 100644
index 0000000..cd5be0f
--- /dev/null
+++ b/drivers/media/video/msm/mt9d113_reg.c
@@ -0,0 +1,455 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include "mt9d113.h"
+
+struct mt9d113_i2c_reg_conf const
+	pll_tbl_settings[] = {
+		{0x0014, 0x21F9 }, /*PLL control: BYPASS PLL = 8697*/
+		{0x0010, 0x0115 }, /*PLL Dividers = 277*/
+		{0x0012, 0x0F5  }, /*PLL P Dividers = 245*/
+		{0x0014, 0x21FB }, /*PLL control: PLL_ENABLE on = 8699*/
+		{0x0014, 0x20FB }, /*PLL control: SEL_LOCK_DET on = 8443*/
+};
+
+struct mt9d113_i2c_reg_conf const
+	register_wizard_settings[] = {
+		{0x098C, 0x2719},
+		{0x0990, 0x005A},
+		{0x098C, 0x271B},
+		{0x0990, 0x01BE},
+		{0x098C, 0x271D},
+		{0x0990, 0x0131},
+		{0x098C, 0x271F},
+		{0x0990, 0x02BB},
+		{0x098C, 0x2721},
+		{0x0990, 0x0888},
+		{0x098C, 0x272F},
+		{0x0990, 0x003A},
+		{0x098C, 0x2731},
+		{0x0990, 0x00F6},
+		{0x098C, 0x2733},
+		{0x0990, 0x008B},
+		{0x098C, 0x2735},
+		{0x0990, 0x0521},
+		{0x098C, 0x2737},
+		{0x0990, 0x0888},
+		{0x098C, 0x275F},
+		{0x0990, 0x0194},
+		{0x098C, 0x2761},
+		{0x0990, 0x0014},
+		{0x098C, 0xA765},
+		{0x0990, 0x0044},
+		{0x098C, 0xA24F},
+		{0x0990, 0x0028},
+		{0x098C, 0xA20E},
+		{0x0990, 0x00A0},
+		{0x098C, 0xA20C},
+		{0x0990, 0x000E},
+		{0x098C, 0x2222},
+		{0x0990, 0x00A0},
+		{0x098C, 0x2212},
+		{0x0990, 0x01EE},
+		{0x098C, 0xA408},
+		{0x0990, 0x0026},
+		{0x098C, 0xA409},
+		{0x0990, 0x0029},
+		{0x098C, 0xA40A},
+		{0x0990, 0x002E},
+		{0x098C, 0xA40B},
+		{0x0990, 0x0031},
+		{0x098C, 0x2411},
+		{0x0990, 0x00A0},
+		{0x098C, 0x2413},
+		{0x0990, 0x00C0},
+		{0x098C, 0x2415},
+		{0x0990, 0x00A0},
+		{0x098C, 0x2417},
+		{0x0990, 0x00C0},
+};
+
+struct mt9d113_i2c_reg_conf const
+	err_settings[] = {
+		{0x3084, 0x240C},
+		{0x3092, 0x0A4C},
+		{0x3094, 0x4C4C},
+		{0x3096, 0x4C54},
+};
+
+struct mt9d113_i2c_reg_conf const
+	patch_settings[] = {
+		{0x098C, 0x0415},    /* MCU_ADDRESS*/
+		{0x0990, 0xF601},
+		{0x0992, 0x42C1},
+		{0x0994, 0x0326},
+		{0x0996, 0x11F6},
+		{0x0998, 0x0143},
+		{0x099A, 0xC104},
+		{0x099C, 0x260A},
+		{0x099E, 0xCC04},
+		{0x098C, 0x0425},
+		{0x0990, 0x33BD},
+		{0x0992, 0xA362},
+		{0x0994, 0xBD04},
+		{0x0996, 0x3339},
+		{0x0998, 0xC6FF},
+		{0x099A, 0xF701},
+		{0x099C, 0x6439},
+		{0x099E, 0xFE01},
+		{0x098C, 0x0435},
+		{0x0990, 0x6918},
+		{0x0992, 0xCE03},
+		{0x0994, 0x25CC},
+		{0x0996, 0x0013},
+		{0x0998, 0xBDC2},
+		{0x099A, 0xB8CC},
+		{0x099C, 0x0489},
+		{0x099E, 0xFD03},
+		{0x098C, 0x0445},
+		{0x0990, 0x27CC},
+		{0x0992, 0x0325},
+		{0x0994, 0xFD01},
+		{0x0996, 0x69FE},
+		{0x0998, 0x02BD},
+		{0x099A, 0x18CE},
+		{0x099C, 0x0339},
+		{0x099E, 0xCC00},
+		{0x098C, 0x0455},
+		{0x0990, 0x11BD},
+		{0x0992, 0xC2B8},
+		{0x0994, 0xCC04},
+		{0x0996, 0xC8FD},
+		{0x0998, 0x0347},
+		{0x099A, 0xCC03},
+		{0x099C, 0x39FD},
+		{0x099E, 0x02BD},
+		{0x098C, 0x0465},
+		{0x0990, 0xDE00},
+		{0x0992, 0x18CE},
+		{0x0994, 0x00C2},
+		{0x0996, 0xCC00},
+		{0x0998, 0x37BD},
+		{0x099A, 0xC2B8},
+		{0x099C, 0xCC04},
+		{0x099E, 0xEFDD},
+		{0x098C, 0x0475},
+		{0x0990, 0xE6CC},
+		{0x0992, 0x00C2},
+		{0x0994, 0xDD00},
+		{0x0996, 0xC601},
+		{0x0998, 0xF701},
+		{0x099A, 0x64C6},
+		{0x099C, 0x03F7},
+		{0x099E, 0x0165},
+		{0x098C, 0x0485},
+		{0x0990, 0x7F01},
+		{0x0992, 0x6639},
+		{0x0994, 0x3C3C},
+		{0x0996, 0x3C34},
+		{0x0998, 0xCC32},
+		{0x099A, 0x3EBD},
+		{0x099C, 0xA558},
+		{0x099E, 0x30ED},
+		{0x098C, 0x0495},
+		{0x0990, 0x04BD},
+		{0x0992, 0xB2D7},
+		{0x0994, 0x30E7},
+		{0x0996, 0x06CC},
+		{0x0998, 0x323E},
+		{0x099A, 0xED00},
+		{0x099C, 0xEC04},
+		{0x099E, 0xBDA5},
+		{0x098C, 0x04A5},
+		{0x0990, 0x44CC},
+		{0x0992, 0x3244},
+		{0x0994, 0xBDA5},
+		{0x0996, 0x585F},
+		{0x0998, 0x30ED},
+		{0x099A, 0x02CC},
+		{0x099C, 0x3244},
+		{0x099E, 0xED00},
+		{0x098C, 0x04B5},
+		{0x0990, 0xF601},
+		{0x0992, 0xD54F},
+		{0x0994, 0xEA03},
+		{0x0996, 0xAA02},
+		{0x0998, 0xBDA5},
+		{0x099A, 0x4430},
+		{0x099C, 0xE606},
+		{0x099E, 0x3838},
+		{0x098C, 0x04C5},
+		{0x0990, 0x3831},
+		{0x0992, 0x39BD},
+		{0x0994, 0xD661},
+		{0x0996, 0xF602},
+		{0x0998, 0xF4C1},
+		{0x099A, 0x0126},
+		{0x099C, 0x0BFE},
+		{0x099E, 0x02BD},
+		{0x098C, 0x04D5},
+		{0x0990, 0xEE10},
+		{0x0992, 0xFC02},
+		{0x0994, 0xF5AD},
+		{0x0996, 0x0039},
+		{0x0998, 0xF602},
+		{0x099A, 0xF4C1},
+		{0x099C, 0x0226},
+		{0x099E, 0x0AFE},
+		{0x098C, 0x04E5},
+		{0x0990, 0x02BD},
+		{0x0992, 0xEE10},
+		{0x0994, 0xFC02},
+		{0x0996, 0xF7AD},
+		{0x0998, 0x0039},
+		{0x099A, 0x3CBD},
+		{0x099C, 0xB059},
+		{0x099E, 0xCC00},
+		{0x098C, 0x04F5},
+		{0x0990, 0x28BD},
+		{0x0992, 0xA558},
+		{0x0994, 0x8300},
+		{0x0996, 0x0027},
+		{0x0998, 0x0BCC},
+		{0x099A, 0x0026},
+		{0x099C, 0x30ED},
+		{0x099E, 0x00C6},
+		{0x098C, 0x0505},
+		{0x0990, 0x03BD},
+		{0x0992, 0xA544},
+		{0x0994, 0x3839},
+		{0x098C, 0x2006},
+		{0x0990, 0x0415},
+		{0x098C, 0xA005},
+		{0x0990, 0x0001},
+};
+
+struct mt9d113_i2c_reg_conf const
+	eeprom_settings[] = {
+		{0x3658, 0x0110},
+		{0x365A, 0x1B6D},
+		{0x365C, 0x01F2},
+		{0x365E, 0xFBCD},
+		{0x3660, 0x8C91},
+		{0x3680, 0xB9ED},
+		{0x3682, 0x0EE},
+		{0x3684, 0x256F},
+		{0x3686, 0x824F},
+		{0x3688, 0xD293},
+		{0x36A8, 0x5BF2},
+		{0x36AA, 0x1711},
+		{0x36AC, 0xA095},
+		{0x36AE, 0x642C},
+		{0x36B0, 0x0E38},
+		{0x36D0, 0x88B0},
+		{0x36D2, 0x2EB2},
+		{0x36D4, 0x4C74},
+		{0x36D6, 0x9F96},
+		{0x36D8, 0x9557},
+		{0x36F8, 0xCE51},
+		{0x36FA, 0xB354},
+		{0x36FC, 0x2817},
+		{0x36FE, 0x14B8},
+		{0x3700, 0xB019},
+		{0x364E, 0x0710},
+		{0x3650, 0x30ED},
+		{0x3652, 0x03F2},
+		{0x3654, 0xF12E},
+		{0x3656, 0x8492},
+		{0x3676, 0xD9AD},
+		{0x3678, 0x88D0},
+		{0x367A, 0x7DED},
+		{0x367C, 0x3E31},
+		{0x367E, 0x91B3},
+		{0x369E, 0x7032},
+		{0x36A0, 0x2791},
+		{0x36A2, 0xBB55},
+		{0x36A4, 0xAB32},
+		{0x36A6, 0x1A58},
+		{0x36C6, 0xB50F},
+		{0x36C8, 0x0011},
+		{0x36CA, 0x6DB4},
+		{0x36CC, 0x96F5},
+		{0x36CE, 0x9BB7},
+		{0x36EE, 0x9353},
+		{0x36F0, 0xDF74},
+		{0x36F2, 0x04F8},
+		{0x36F4, 0x0FD8},
+		{0x36F6, 0xA87A},
+		{0x3662, 0x0170},
+		{0x3664, 0x6F0C},
+		{0x3666, 0x0112},
+		{0x3668, 0xCBAB},
+		{0x366A, 0x9111},
+		{0x368A, 0xB38D},
+		{0x368C, 0xE96F},
+		{0x368E, 0xCC0F},
+		{0x3690, 0x5851},
+		{0x3692, 0xFDD2},
+		{0x36B2, 0x5F92},
+		{0x36B4, 0x33B2},
+		{0x36B6, 0x9815},
+		{0x36B8, 0x86F5},
+		{0x36BA, 0x0578},
+		{0x36DA, 0xCD90},
+		{0x36DC, 0x1131},
+		{0x36DE, 0x5275},
+		{0x36E0, 0xE855},
+		{0x36E2, 0xD037},
+		{0x3702, 0xAAD1},
+		{0x3704, 0xEB75},
+		{0x3706, 0x0CD7},
+		{0x3708, 0x2C79},
+		{0x370A, 0xE0B9},
+		{0x366C, 0x0190},
+		{0x366E, 0x1C8D},
+		{0x3670, 0x0052},
+		{0x3672, 0xD66E},
+		{0x3674, 0xF511},
+		{0x3694, 0xB54D},
+		{0x3696, 0x6E4E},
+		{0x3698, 0x142E},
+		{0x369A, 0xC190},
+		{0x369C, 0xA753},
+		{0x36BC, 0x70F2},
+		{0x36BE, 0x04F1},
+		{0x36C0, 0xBD95},
+		{0x36C2, 0x0CEE},
+		{0x36C4, 0x1BF8},
+		{0x36E4, 0x806F},
+		{0x36E6, 0x1672},
+		{0x36E8, 0x2DF4},
+		{0x36EA, 0x8F16},
+		{0x36EC, 0xF776},
+		{0x370C, 0xAD73},
+		{0x370E, 0xB534},
+		{0x3710, 0x0D18},
+		{0x3712, 0x6057},
+		{0x3714, 0xBD1A},
+		{0x3644, 0x0354},
+		{0x3642, 0x0234},
+		{0x3210, 0x01B8},
+};
+
+struct mt9d113_i2c_reg_conf const
+	awb_settings[] = {
+		{0x098C, 0x2306},
+		{0x0990, 0x0180},
+		{0x098C, 0x2308},
+		{0x0990, 0xFF00},
+		{0x098C, 0x230A},
+		{0x0990, 0x0080},
+		{0x098C, 0x230C},
+		{0x0990, 0xFF66},
+		{0x098C, 0x230E},
+		{0x0990, 0x0180},
+		{0x098C, 0x2310},
+		{0x0990, 0xFFEE},
+		{0x098C, 0x2312},
+		{0x0990, 0xFFCD},
+		{0x098C, 0x2314},
+		{0x0990, 0xFECD},
+		{0x098C, 0x2316},
+		{0x0990, 0x019A},
+		{0x098C, 0x2318},
+		{0x0990, 0x0020},
+		{0x098C, 0x231A},
+		{0x0990, 0x0033},
+		{0x098C, 0x231C},
+		{0x0990, 0x0100},
+		{0x098C, 0x231E},
+		{0x0990, 0xFF9A},
+		{0x098C, 0x2320},
+		{0x0990, 0x0000},
+		{0x098C, 0x2322},
+		{0x0990, 0x004D},
+		{0x098C, 0x2324},
+		{0x0990, 0xFFCD},
+		{0x098C, 0x2326},
+		{0x0990, 0xFFB8},
+		{0x098C, 0x2328},
+		{0x0990, 0x004D},
+		{0x098C, 0x232A},
+		{0x0990, 0x0080},
+		{0x098C, 0x232C},
+		{0x0990, 0xFF66},
+		{0x098C, 0x232E},
+		{0x0990, 0x0008},
+		{0x098C, 0x2330},
+		{0x0990, 0xFFF7},
+		{0x098C, 0xA363},
+		{0x0990, 0x00D2},
+		{0x098C, 0xA364},
+		{0x0990, 0x00EE},
+		{0x3244, 0x0328},
+		{0x323E, 0xC22C},
+};
+
+struct mt9d113_i2c_reg_conf const
+	low_light_setting[] = {
+		{0x098C, 0x2B28},
+		{0x0990, 0x35E8},
+		{0x098C, 0x2B2A},
+		{0x0990, 0xB3B0},
+		{0x098C, 0xAB20},
+		{0x0990, 0x004B},
+		{0x098C, 0xAB24},
+		{0x0990, 0x0000},
+		{0x098C, 0xAB25},
+		{0x0990, 0x00FF},
+		{0x098C, 0xAB30},
+		{0x0990, 0x00FF},
+		{0x098C, 0xAB31},
+		{0x0990, 0x00FF},
+		{0x098C, 0xAB32},
+		{0x0990, 0x00FF},
+		{0x098C, 0xAB33},
+		{0x0990, 0x0057},
+		{0x098C, 0xAB34},
+		{0x0990, 0x0080},
+		{0x098C, 0xAB35},
+		{0x0990, 0x00FF},
+		{0x098C, 0xAB36},
+		{0x0990, 0x0014},
+		{0x098C, 0xAB37},
+		{0x0990, 0x0003},
+		{0x098C, 0x2B38},
+		{0x0990, 0x32C8},
+		{0x098C, 0x2B3A},
+		{0x0990, 0x7918},
+		{0x098C, 0x2B62},
+		{0x0990, 0xFFFE},
+		{0x098C, 0x2B64},
+		{0x0990, 0xFFFF},
+};
+
+struct mt9d113_reg mt9d113_regs = {
+		.pll_tbl = pll_tbl_settings,
+		.pll_tbl_size = ARRAY_SIZE(
+			pll_tbl_settings),
+		.register_tbl = register_wizard_settings,
+		.register_tbl_size = ARRAY_SIZE(
+			register_wizard_settings),
+		.err_tbl = err_settings,
+		.err_tbl_size = ARRAY_SIZE(err_settings),
+		.low_light_tbl = low_light_setting,
+		.low_light_tbl_size = ARRAY_SIZE(low_light_setting),
+		.awb_tbl = awb_settings,
+		.awb_tbl_size = ARRAY_SIZE(awb_settings),
+		.patch_tbl = patch_settings,
+		.patch_tbl_size = ARRAY_SIZE(patch_settings),
+		.eeprom_tbl = eeprom_settings,
+		.eeprom_tbl_size = ARRAY_SIZE(eeprom_settings),
+};
+
+
+
diff --git a/drivers/media/video/msm/mt9e013.c b/drivers/media/video/msm/mt9e013.c
new file mode 100644
index 0000000..94546f4
--- /dev/null
+++ b/drivers/media/video/msm/mt9e013.c
@@ -0,0 +1,1140 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <media/msm_camera.h>
+#include <mach/gpio.h>
+#include <mach/camera.h>
+#include "mt9e013.h"
+/*=============================================================
+	SENSOR REGISTER DEFINES
+==============================================================*/
+#define REG_GROUPED_PARAMETER_HOLD		0x0104
+#define GROUPED_PARAMETER_HOLD_OFF		0x00
+#define GROUPED_PARAMETER_HOLD			0x01
+/* Integration Time */
+#define REG_COARSE_INTEGRATION_TIME		0x3012
+/* Gain */
+#define REG_GLOBAL_GAIN	0x305E
+/* PLL registers */
+#define REG_FRAME_LENGTH_LINES		0x0340
+/* Test Pattern */
+#define REG_TEST_PATTERN_MODE			0x0601
+#define REG_VCM_NEW_CODE			0x30F2
+
+/*============================================================================
+							 TYPE DECLARATIONS
+============================================================================*/
+
+/* 16bit address - 8 bit context register structure */
+#define Q8	0x00000100
+#define Q10	0x00000400
+#define MT9E013_MASTER_CLK_RATE 24000000
+
+/* AF Total steps parameters */
+#define MT9E013_TOTAL_STEPS_NEAR_TO_FAR    32
+
+uint16_t mt9e013_step_position_table[MT9E013_TOTAL_STEPS_NEAR_TO_FAR+1];
+uint16_t mt9e013_nl_region_boundary1;
+uint16_t mt9e013_nl_region_code_per_step1;
+uint16_t mt9e013_l_region_code_per_step = 4;
+uint16_t mt9e013_damping_threshold = 10;
+uint16_t mt9e013_sw_damping_time_wait = 1;
+
+struct mt9e013_work_t {
+	struct work_struct work;
+};
+
+static struct mt9e013_work_t *mt9e013_sensorw;
+static struct i2c_client *mt9e013_client;
+
+struct mt9e013_ctrl_t {
+	const struct  msm_camera_sensor_info *sensordata;
+
+	uint32_t sensormode;
+	uint32_t fps_divider;/* init to 1 * 0x00000400 */
+	uint32_t pict_fps_divider;/* init to 1 * 0x00000400 */
+	uint16_t fps;
+
+	uint16_t curr_lens_pos;
+	uint16_t curr_step_pos;
+	uint16_t my_reg_gain;
+	uint32_t my_reg_line_count;
+	uint16_t total_lines_per_frame;
+
+	enum mt9e013_resolution_t prev_res;
+	enum mt9e013_resolution_t pict_res;
+	enum mt9e013_resolution_t curr_res;
+	enum mt9e013_test_mode_t  set_test;
+};
+
+
+static bool CSI_CONFIG;
+static struct mt9e013_ctrl_t *mt9e013_ctrl;
+static DECLARE_WAIT_QUEUE_HEAD(mt9e013_wait_queue);
+DEFINE_MUTEX(mt9e013_mut);
+
+static int cam_debug_init(void);
+static struct dentry *debugfs_base;
+/*=============================================================*/
+
+static int mt9e013_i2c_rxdata(unsigned short saddr,
+	unsigned char *rxdata, int length)
+{
+	struct i2c_msg msgs[] = {
+		{
+			.addr  = saddr,
+			.flags = 0,
+			.len   = 2,
+			.buf   = rxdata,
+		},
+		{
+			.addr  = saddr,
+			.flags = I2C_M_RD,
+			.len   = 2,
+			.buf   = rxdata,
+		},
+	};
+	if (i2c_transfer(mt9e013_client->adapter, msgs, 2) < 0) {
+		CDBG("mt9e013_i2c_rxdata faild 0x%x\n", saddr);
+		return -EIO;
+	}
+	return 0;
+}
+
+static int32_t mt9e013_i2c_txdata(unsigned short saddr,
+				unsigned char *txdata, int length)
+{
+	struct i2c_msg msg[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = length,
+			.buf = txdata,
+		 },
+	};
+	if (i2c_transfer(mt9e013_client->adapter, msg, 1) < 0) {
+		CDBG("mt9e013_i2c_txdata faild 0x%x\n", saddr);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t mt9e013_i2c_read(unsigned short raddr,
+	unsigned short *rdata, int rlen)
+{
+	int32_t rc = 0;
+	unsigned char buf[2];
+	if (!rdata)
+		return -EIO;
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (raddr & 0xFF00) >> 8;
+	buf[1] = (raddr & 0x00FF);
+	rc = mt9e013_i2c_rxdata(mt9e013_client->addr<<1, buf, rlen);
+	if (rc < 0) {
+		CDBG("mt9e013_i2c_read 0x%x failed!\n", raddr);
+		return rc;
+	}
+	*rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]);
+	CDBG("mt9e013_i2c_read 0x%x val = 0x%x!\n", raddr, *rdata);
+	return rc;
+}
+
+static int32_t mt9e013_i2c_write_w_sensor(unsigned short waddr, uint16_t wdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[4];
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = (wdata & 0xFF00) >> 8;
+	buf[3] = (wdata & 0x00FF);
+	CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, wdata);
+	rc = mt9e013_i2c_txdata(mt9e013_client->addr<<1, buf, 4);
+	if (rc < 0) {
+		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+			waddr, wdata);
+	}
+	return rc;
+}
+
+static int32_t mt9e013_i2c_write_b_sensor(unsigned short waddr, uint8_t bdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[3];
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = bdata;
+	CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata);
+	rc = mt9e013_i2c_txdata(mt9e013_client->addr<<1, buf, 3);
+	if (rc < 0) {
+		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+			waddr, bdata);
+	}
+	return rc;
+}
+
+static int32_t mt9e013_i2c_write_w_table(struct mt9e013_i2c_reg_conf const
+					 *reg_conf_tbl, int num)
+{
+	int i;
+	int32_t rc = -EIO;
+	for (i = 0; i < num; i++) {
+		rc = mt9e013_i2c_write_w_sensor(reg_conf_tbl->waddr,
+			reg_conf_tbl->wdata);
+		if (rc < 0)
+			break;
+		reg_conf_tbl++;
+	}
+	return rc;
+}
+
+static void mt9e013_group_hold_on(void)
+{
+	mt9e013_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
+						GROUPED_PARAMETER_HOLD);
+}
+
+static void mt9e013_group_hold_off(void)
+{
+	mt9e013_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
+						GROUPED_PARAMETER_HOLD_OFF);
+}
+
+static void mt9e013_start_stream(void)
+{
+	mt9e013_i2c_write_w_sensor(0x301A, 0x8250);
+	mt9e013_i2c_write_w_sensor(0x301A, 0x8650);
+	mt9e013_i2c_write_w_sensor(0x301A, 0x8658);
+	mt9e013_i2c_write_b_sensor(0x0104, 0x00);
+	mt9e013_i2c_write_w_sensor(0x301A, 0x065C);
+}
+
+static void mt9e013_stop_stream(void)
+{
+	mt9e013_i2c_write_w_sensor(0x301A, 0x0058);
+	mt9e013_i2c_write_w_sensor(0x301A, 0x0050);
+	mt9e013_i2c_write_b_sensor(0x0104, 0x01);
+}
+
+static void mt9e013_get_pict_fps(uint16_t fps, uint16_t *pfps)
+{
+	/* input fps is preview fps in Q8 format */
+	uint32_t divider, d1, d2;
+
+	d1 = mt9e013_regs.reg_prev[E013_FRAME_LENGTH_LINES].wdata
+		* 0x00000400/
+		mt9e013_regs.reg_snap[E013_FRAME_LENGTH_LINES].wdata;
+	d2 = mt9e013_regs.reg_prev[E013_LINE_LENGTH_PCK].wdata
+		* 0x00000400/
+		mt9e013_regs.reg_snap[E013_LINE_LENGTH_PCK].wdata;
+	divider = d1 * d2 / 0x400;
+
+	/*Verify PCLK settings and frame sizes.*/
+	*pfps = (uint16_t) (fps * divider / 0x400);
+	/* 2 is the ratio of no.of snapshot channels
+	to number of preview channels */
+}
+
+static uint16_t mt9e013_get_prev_lines_pf(void)
+{
+	if (mt9e013_ctrl->prev_res == QTR_SIZE)
+		return mt9e013_regs.reg_prev[E013_FRAME_LENGTH_LINES].wdata;
+	else if (mt9e013_ctrl->prev_res == FULL_SIZE)
+		return mt9e013_regs.reg_snap[E013_FRAME_LENGTH_LINES].wdata;
+	else if (mt9e013_ctrl->prev_res == HFR_60FPS)
+		return mt9e013_regs.reg_60fps[E013_FRAME_LENGTH_LINES].wdata;
+	else if (mt9e013_ctrl->prev_res == HFR_90FPS)
+		return mt9e013_regs.reg_120fps[E013_FRAME_LENGTH_LINES].wdata;
+	else
+		return mt9e013_regs.reg_120fps[E013_FRAME_LENGTH_LINES].wdata;
+}
+
+static uint16_t mt9e013_get_prev_pixels_pl(void)
+{
+	if (mt9e013_ctrl->prev_res == QTR_SIZE)
+		return mt9e013_regs.reg_prev[E013_LINE_LENGTH_PCK].wdata;
+	else if (mt9e013_ctrl->prev_res == FULL_SIZE)
+		return mt9e013_regs.reg_snap[E013_LINE_LENGTH_PCK].wdata;
+	else if (mt9e013_ctrl->prev_res == HFR_60FPS)
+		return mt9e013_regs.reg_60fps[E013_LINE_LENGTH_PCK].wdata;
+	else if (mt9e013_ctrl->prev_res == HFR_90FPS)
+		return mt9e013_regs.reg_120fps[E013_LINE_LENGTH_PCK].wdata;
+	else
+		return mt9e013_regs.reg_120fps[E013_LINE_LENGTH_PCK].wdata;
+}
+
+static uint16_t mt9e013_get_pict_lines_pf(void)
+{
+	if (mt9e013_ctrl->pict_res == QTR_SIZE)
+		return mt9e013_regs.reg_prev[E013_FRAME_LENGTH_LINES].wdata;
+	else if (mt9e013_ctrl->pict_res == FULL_SIZE)
+		return mt9e013_regs.reg_snap[E013_FRAME_LENGTH_LINES].wdata;
+	else if (mt9e013_ctrl->pict_res == HFR_60FPS)
+		return mt9e013_regs.reg_60fps[E013_FRAME_LENGTH_LINES].wdata;
+	else if (mt9e013_ctrl->pict_res == HFR_90FPS)
+		return mt9e013_regs.reg_120fps[E013_FRAME_LENGTH_LINES].wdata;
+	else
+		return mt9e013_regs.reg_120fps[E013_FRAME_LENGTH_LINES].wdata;
+}
+
+static uint16_t mt9e013_get_pict_pixels_pl(void)
+{
+	if (mt9e013_ctrl->pict_res == QTR_SIZE)
+		return mt9e013_regs.reg_prev[E013_LINE_LENGTH_PCK].wdata;
+	else if (mt9e013_ctrl->pict_res == FULL_SIZE)
+		return mt9e013_regs.reg_snap[E013_LINE_LENGTH_PCK].wdata;
+	else if (mt9e013_ctrl->pict_res == HFR_60FPS)
+		return mt9e013_regs.reg_60fps[E013_LINE_LENGTH_PCK].wdata;
+	else if (mt9e013_ctrl->pict_res == HFR_90FPS)
+		return mt9e013_regs.reg_120fps[E013_LINE_LENGTH_PCK].wdata;
+	else
+		return mt9e013_regs.reg_120fps[E013_LINE_LENGTH_PCK].wdata;
+}
+
+static uint32_t mt9e013_get_pict_max_exp_lc(void)
+{
+	if (mt9e013_ctrl->pict_res == QTR_SIZE)
+		return mt9e013_regs.reg_prev[E013_FRAME_LENGTH_LINES].wdata
+			* 24;
+	else if (mt9e013_ctrl->pict_res == FULL_SIZE)
+		return mt9e013_regs.reg_snap[E013_FRAME_LENGTH_LINES].wdata
+			* 24;
+	else if (mt9e013_ctrl->pict_res == HFR_60FPS)
+		return mt9e013_regs.reg_60fps[E013_FRAME_LENGTH_LINES].wdata
+			* 24;
+	else if (mt9e013_ctrl->pict_res == HFR_90FPS)
+		return mt9e013_regs.reg_120fps[E013_FRAME_LENGTH_LINES].wdata
+			* 24;
+	else
+		return mt9e013_regs.reg_120fps[E013_FRAME_LENGTH_LINES].wdata
+			* 24;
+}
+
+static int32_t mt9e013_set_fps(struct fps_cfg   *fps)
+{
+	uint16_t total_lines_per_frame;
+	int32_t rc = 0;
+	if (mt9e013_ctrl->curr_res == QTR_SIZE)
+		total_lines_per_frame =
+		mt9e013_regs.reg_prev[E013_FRAME_LENGTH_LINES].wdata;
+	else if (mt9e013_ctrl->curr_res == FULL_SIZE)
+		total_lines_per_frame =
+		mt9e013_regs.reg_snap[E013_FRAME_LENGTH_LINES].wdata;
+	else if (mt9e013_ctrl->curr_res == HFR_60FPS)
+		total_lines_per_frame =
+		mt9e013_regs.reg_60fps[E013_FRAME_LENGTH_LINES].wdata;
+	else if (mt9e013_ctrl->curr_res == HFR_90FPS)
+		total_lines_per_frame =
+		mt9e013_regs.reg_120fps[E013_FRAME_LENGTH_LINES].wdata;
+	else
+		total_lines_per_frame =
+		mt9e013_regs.reg_120fps[E013_FRAME_LENGTH_LINES].wdata;
+
+	mt9e013_ctrl->fps_divider = fps->fps_div;
+	mt9e013_ctrl->pict_fps_divider = fps->pict_fps_div;
+
+	if (mt9e013_ctrl->curr_res == FULL_SIZE) {
+		total_lines_per_frame = (uint16_t)
+		(total_lines_per_frame * mt9e013_ctrl->pict_fps_divider/0x400);
+	} else {
+		total_lines_per_frame = (uint16_t)
+		(total_lines_per_frame * mt9e013_ctrl->fps_divider/0x400);
+	}
+
+	mt9e013_group_hold_on();
+	rc = mt9e013_i2c_write_w_sensor(REG_FRAME_LENGTH_LINES,
+							total_lines_per_frame);
+	mt9e013_group_hold_off();
+	return rc;
+}
+
+static int32_t mt9e013_write_exp_gain(uint16_t gain, uint32_t line)
+{
+	uint16_t max_legal_gain = 0xE7F;
+	int32_t rc = 0;
+	if (gain > max_legal_gain) {
+		CDBG("Max legal gain Line:%d\n", __LINE__);
+		gain = max_legal_gain;
+	}
+
+	if (mt9e013_ctrl->curr_res != FULL_SIZE) {
+		mt9e013_ctrl->my_reg_gain = gain;
+		mt9e013_ctrl->my_reg_line_count = (uint16_t) line;
+		line = (uint32_t) (line * mt9e013_ctrl->fps_divider /
+						   0x00000400);
+	} else {
+		line = (uint32_t) (line * mt9e013_ctrl->pict_fps_divider /
+						   0x00000400);
+	}
+
+	gain |= 0x1000;
+
+	mt9e013_group_hold_on();
+	rc = mt9e013_i2c_write_w_sensor(REG_GLOBAL_GAIN, gain);
+	rc = mt9e013_i2c_write_w_sensor(REG_COARSE_INTEGRATION_TIME, line);
+	mt9e013_group_hold_off();
+	return rc;
+}
+
+static int32_t mt9e013_set_pict_exp_gain(uint16_t gain, uint32_t line)
+{
+	int32_t rc = 0;
+	rc = mt9e013_write_exp_gain(gain, line);
+	mt9e013_i2c_write_w_sensor(0x301A, 0x065C|0x2);
+	return rc;
+}
+
+#define DIV_CEIL(x, y) (x/y + (x%y) ? 1 : 0)
+
+static int32_t mt9e013_move_focus(int direction,
+	int32_t num_steps)
+{
+	int16_t step_direction, dest_lens_position, dest_step_position;
+	int16_t target_dist, small_step, next_lens_position;
+	if (direction == MOVE_NEAR)
+		step_direction = 1;
+	else
+		step_direction = -1;
+
+	dest_step_position = mt9e013_ctrl->curr_step_pos
+						+ (step_direction * num_steps);
+
+	if (dest_step_position < 0)
+		dest_step_position = 0;
+	else if (dest_step_position > MT9E013_TOTAL_STEPS_NEAR_TO_FAR)
+		dest_step_position = MT9E013_TOTAL_STEPS_NEAR_TO_FAR;
+
+	if (dest_step_position == mt9e013_ctrl->curr_step_pos)
+		return 0;
+
+	dest_lens_position = mt9e013_step_position_table[dest_step_position];
+	target_dist = step_direction *
+		(dest_lens_position - mt9e013_ctrl->curr_lens_pos);
+
+	if (step_direction < 0 && (target_dist >=
+		mt9e013_step_position_table[mt9e013_damping_threshold])) {
+		small_step = DIV_CEIL(target_dist, 10);
+		mt9e013_sw_damping_time_wait = 10;
+	} else {
+		small_step = DIV_CEIL(target_dist, 4);
+		mt9e013_sw_damping_time_wait = 4;
+	}
+
+	for (next_lens_position = mt9e013_ctrl->curr_lens_pos
+		+ (step_direction * small_step);
+		(step_direction * next_lens_position) <=
+		(step_direction * dest_lens_position);
+		next_lens_position += (step_direction * small_step)) {
+		mt9e013_i2c_write_w_sensor(REG_VCM_NEW_CODE,
+		next_lens_position);
+		mt9e013_ctrl->curr_lens_pos = next_lens_position;
+		usleep(mt9e013_sw_damping_time_wait*50);
+	}
+
+	if (mt9e013_ctrl->curr_lens_pos != dest_lens_position) {
+		mt9e013_i2c_write_w_sensor(REG_VCM_NEW_CODE,
+		dest_lens_position);
+		usleep(mt9e013_sw_damping_time_wait*50);
+	}
+	mt9e013_ctrl->curr_lens_pos = dest_lens_position;
+	mt9e013_ctrl->curr_step_pos = dest_step_position;
+	return 0;
+}
+
+static int32_t mt9e013_set_default_focus(uint8_t af_step)
+{
+	int32_t rc = 0;
+	if (mt9e013_ctrl->curr_step_pos != 0) {
+		rc = mt9e013_move_focus(MOVE_FAR,
+		mt9e013_ctrl->curr_step_pos);
+	} else {
+		mt9e013_i2c_write_w_sensor(REG_VCM_NEW_CODE, 0x00);
+	}
+
+	mt9e013_ctrl->curr_lens_pos = 0;
+	mt9e013_ctrl->curr_step_pos = 0;
+
+	return rc;
+}
+
+static void mt9e013_init_focus(void)
+{
+	uint8_t i;
+	mt9e013_step_position_table[0] = 0;
+	for (i = 1; i <= MT9E013_TOTAL_STEPS_NEAR_TO_FAR; i++) {
+		if (i <= mt9e013_nl_region_boundary1) {
+			mt9e013_step_position_table[i] =
+				mt9e013_step_position_table[i-1]
+				+ mt9e013_nl_region_code_per_step1;
+		} else {
+			mt9e013_step_position_table[i] =
+				mt9e013_step_position_table[i-1]
+				+ mt9e013_l_region_code_per_step;
+		}
+
+		if (mt9e013_step_position_table[i] > 255)
+			mt9e013_step_position_table[i] = 255;
+	}
+}
+
+static int32_t mt9e013_test(enum mt9e013_test_mode_t mo)
+{
+	int32_t rc = 0;
+	if (mo == TEST_OFF)
+		return rc;
+	else {
+		/* REG_0x30D8[4] is TESBYPEN: 0: Normal Operation,
+		1: Bypass Signal Processing
+		REG_0x30D8[5] is EBDMASK: 0:
+		Output Embedded data, 1: No output embedded data */
+		if (mt9e013_i2c_write_b_sensor(REG_TEST_PATTERN_MODE,
+			(uint8_t) mo) < 0) {
+			return rc;
+		}
+	}
+	return rc;
+}
+
+static int32_t mt9e013_sensor_setting(int update_type, int rt)
+{
+
+	int32_t rc = 0;
+	struct msm_camera_csi_params mt9e013_csi_params;
+	uint8_t stored_af_step = 0;
+	CDBG("sensor_settings\n");
+	stored_af_step = mt9e013_ctrl->curr_step_pos;
+	mt9e013_set_default_focus(0);
+	mt9e013_stop_stream();
+	msleep(15);
+	if (update_type == REG_INIT) {
+		mt9e013_i2c_write_w_table(mt9e013_regs.reg_mipi,
+			mt9e013_regs.reg_mipi_size);
+		mt9e013_i2c_write_w_table(mt9e013_regs.rec_settings,
+			mt9e013_regs.rec_size);
+		cam_debug_init();
+		CSI_CONFIG = 0;
+	} else if (update_type == UPDATE_PERIODIC) {
+		if (rt == QTR_SIZE) {
+			mt9e013_i2c_write_w_table(mt9e013_regs.reg_pll,
+				mt9e013_regs.reg_pll_size);
+			mt9e013_i2c_write_w_table(mt9e013_regs.reg_prev,
+				mt9e013_regs.reg_prev_size);
+		} else if (rt == FULL_SIZE) {
+			mt9e013_i2c_write_w_table(mt9e013_regs.reg_pll,
+				mt9e013_regs.reg_pll_size);
+			mt9e013_i2c_write_w_table(mt9e013_regs.reg_snap,
+				mt9e013_regs.reg_snap_size);
+		} else if (rt == HFR_60FPS) {
+			mt9e013_i2c_write_w_table(mt9e013_regs.reg_pll_120fps,
+				mt9e013_regs.reg_pll_120fps_size);
+			mt9e013_i2c_write_w_sensor(0x0306, 0x0029);
+			mt9e013_i2c_write_w_table(mt9e013_regs.reg_120fps,
+				mt9e013_regs.reg_120fps_size);
+		} else if (rt == HFR_90FPS) {
+			mt9e013_i2c_write_w_table(mt9e013_regs.reg_pll_120fps,
+				mt9e013_regs.reg_pll_120fps_size);
+			mt9e013_i2c_write_w_sensor(0x0306, 0x003D);
+			mt9e013_i2c_write_w_table(mt9e013_regs.reg_120fps,
+				mt9e013_regs.reg_120fps_size);
+		} else if (rt == HFR_120FPS) {
+			msm_camio_vfe_clk_rate_set(266667000);
+			mt9e013_i2c_write_w_table(mt9e013_regs.reg_pll_120fps,
+				mt9e013_regs.reg_pll_120fps_size);
+			mt9e013_i2c_write_w_table(mt9e013_regs.reg_120fps,
+				mt9e013_regs.reg_120fps_size);
+		}
+		if (!CSI_CONFIG) {
+			msm_camio_vfe_clk_rate_set(192000000);
+			mt9e013_csi_params.data_format = CSI_10BIT;
+			mt9e013_csi_params.lane_cnt = 2;
+			mt9e013_csi_params.lane_assign = 0xe4;
+			mt9e013_csi_params.dpcm_scheme = 0;
+			mt9e013_csi_params.settle_cnt = 0x18;
+			rc = msm_camio_csi_config(&mt9e013_csi_params);
+			msleep(10);
+			CSI_CONFIG = 1;
+		}
+		mt9e013_move_focus(MOVE_NEAR, stored_af_step);
+		mt9e013_start_stream();
+	}
+	return rc;
+}
+
+static int32_t mt9e013_video_config(int mode)
+{
+
+	int32_t rc = 0;
+
+	CDBG("video config\n");
+	/* change sensor resolution if needed */
+	if (mt9e013_sensor_setting(UPDATE_PERIODIC,
+			mt9e013_ctrl->prev_res) < 0)
+		return rc;
+	if (mt9e013_ctrl->set_test) {
+		if (mt9e013_test(mt9e013_ctrl->set_test) < 0)
+			return  rc;
+	}
+
+	mt9e013_ctrl->curr_res = mt9e013_ctrl->prev_res;
+	mt9e013_ctrl->sensormode = mode;
+	return rc;
+}
+
+static int32_t mt9e013_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+	/*change sensor resolution if needed */
+	if (mt9e013_ctrl->curr_res != mt9e013_ctrl->pict_res) {
+		if (mt9e013_sensor_setting(UPDATE_PERIODIC,
+				mt9e013_ctrl->pict_res) < 0)
+			return rc;
+	}
+
+	mt9e013_ctrl->curr_res = mt9e013_ctrl->pict_res;
+	mt9e013_ctrl->sensormode = mode;
+	return rc;
+} /*end of mt9e013_snapshot_config*/
+
+static int32_t mt9e013_raw_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+	/* change sensor resolution if needed */
+	if (mt9e013_ctrl->curr_res != mt9e013_ctrl->pict_res) {
+		if (mt9e013_sensor_setting(UPDATE_PERIODIC,
+				mt9e013_ctrl->pict_res) < 0)
+			return rc;
+	}
+
+	mt9e013_ctrl->curr_res = mt9e013_ctrl->pict_res;
+	mt9e013_ctrl->sensormode = mode;
+	return rc;
+} /*end of mt9e013_raw_snapshot_config*/
+
+static int32_t mt9e013_set_sensor_mode(int mode,
+	int res)
+{
+	int32_t rc = 0;
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+	case SENSOR_HFR_60FPS_MODE:
+	case SENSOR_HFR_90FPS_MODE:
+	case SENSOR_HFR_120FPS_MODE:
+		mt9e013_ctrl->prev_res = res;
+		rc = mt9e013_video_config(mode);
+		break;
+	case SENSOR_SNAPSHOT_MODE:
+		mt9e013_ctrl->pict_res = res;
+		rc = mt9e013_snapshot_config(mode);
+		break;
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		mt9e013_ctrl->pict_res = res;
+		rc = mt9e013_raw_snapshot_config(mode);
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+static int32_t mt9e013_power_down(void)
+{
+	return 0;
+}
+
+static int mt9e013_probe_init_done(const struct msm_camera_sensor_info *data)
+{
+	CDBG("probe done\n");
+	gpio_free(data->sensor_reset);
+	return 0;
+}
+
+static int mt9e013_probe_init_sensor(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc = 0;
+	uint16_t chipid = 0;
+	CDBG("%s: %d\n", __func__, __LINE__);
+	rc = gpio_request(data->sensor_reset, "mt9e013");
+	CDBG(" mt9e013_probe_init_sensor\n");
+	if (!rc) {
+		CDBG("sensor_reset = %d\n", rc);
+		gpio_direction_output(data->sensor_reset, 0);
+		msleep(10);
+		gpio_set_value_cansleep(data->sensor_reset, 1);
+		msleep(10);
+	} else {
+		goto init_probe_done;
+	}
+
+	CDBG(" mt9e013_probe_init_sensor is called\n");
+	rc = mt9e013_i2c_read(0x0000, &chipid, 2);
+	CDBG("ID: %d\n", chipid);
+	/* 4. Compare sensor ID to MT9E013 ID: */
+	if (chipid != 0x4B00) {
+		rc = -ENODEV;
+		CDBG("mt9e013_probe_init_sensor fail chip id doesnot match\n");
+		goto init_probe_fail;
+	}
+
+	mt9e013_ctrl = kzalloc(sizeof(struct mt9e013_ctrl_t), GFP_KERNEL);
+	if (!mt9e013_ctrl) {
+		CDBG("mt9e013_init failed!\n");
+		rc = -ENOMEM;
+	}
+	mt9e013_ctrl->fps_divider = 1 * 0x00000400;
+	mt9e013_ctrl->pict_fps_divider = 1 * 0x00000400;
+	mt9e013_ctrl->set_test = TEST_OFF;
+	mt9e013_ctrl->prev_res = QTR_SIZE;
+	mt9e013_ctrl->pict_res = FULL_SIZE;
+
+	if (data)
+		mt9e013_ctrl->sensordata = data;
+
+	goto init_probe_done;
+init_probe_fail:
+	CDBG(" mt9e013_probe_init_sensor fails\n");
+	gpio_set_value_cansleep(data->sensor_reset, 0);
+	mt9e013_probe_init_done(data);
+init_probe_done:
+	CDBG(" mt9e013_probe_init_sensor finishes\n");
+	return rc;
+}
+/* camsensor_mt9e013_reset */
+
+int mt9e013_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc = 0;
+
+	CDBG("%s: %d\n", __func__, __LINE__);
+	CDBG("Calling mt9e013_sensor_open_init\n");
+
+	mt9e013_ctrl = kzalloc(sizeof(struct mt9e013_ctrl_t), GFP_KERNEL);
+	if (!mt9e013_ctrl) {
+		CDBG("mt9e013_init failed!\n");
+		rc = -ENOMEM;
+		goto init_done;
+	}
+	mt9e013_ctrl->fps_divider = 1 * 0x00000400;
+	mt9e013_ctrl->pict_fps_divider = 1 * 0x00000400;
+	mt9e013_ctrl->set_test = TEST_OFF;
+	mt9e013_ctrl->prev_res = QTR_SIZE;
+	mt9e013_ctrl->pict_res = FULL_SIZE;
+
+	if (data)
+		mt9e013_ctrl->sensordata = data;
+	if (rc < 0) {
+		CDBG("Calling mt9e013_sensor_open_init fail1\n");
+		return rc;
+	}
+	CDBG("%s: %d\n", __func__, __LINE__);
+	/* enable mclk first */
+	msm_camio_clk_rate_set(MT9E013_MASTER_CLK_RATE);
+	rc = mt9e013_probe_init_sensor(data);
+	if (rc < 0)
+		goto init_fail;
+
+	CDBG("init settings\n");
+	rc = mt9e013_sensor_setting(REG_INIT, mt9e013_ctrl->prev_res);
+	mt9e013_ctrl->fps = 30*Q8;
+	mt9e013_init_focus();
+	if (rc < 0) {
+		gpio_set_value_cansleep(data->sensor_reset, 0);
+		goto init_fail;
+	} else
+		goto init_done;
+init_fail:
+	CDBG("init_fail\n");
+	mt9e013_probe_init_done(data);
+init_done:
+	CDBG("init_done\n");
+	return rc;
+} /*endof mt9e013_sensor_open_init*/
+
+static int mt9e013_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&mt9e013_wait_queue);
+	return 0;
+}
+
+static const struct i2c_device_id mt9e013_i2c_id[] = {
+	{"mt9e013", 0},
+	{ }
+};
+
+static int mt9e013_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int rc = 0;
+	CDBG("mt9e013_probe called!\n");
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		CDBG("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	mt9e013_sensorw = kzalloc(sizeof(struct mt9e013_work_t), GFP_KERNEL);
+	if (!mt9e013_sensorw) {
+		CDBG("kzalloc failed.\n");
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, mt9e013_sensorw);
+	mt9e013_init_client(client);
+	mt9e013_client = client;
+
+
+	CDBG("mt9e013_probe successed! rc = %d\n", rc);
+	return 0;
+
+probe_failure:
+	CDBG("mt9e013_probe failed! rc = %d\n", rc);
+	return rc;
+}
+
+static int mt9e013_send_wb_info(struct wb_info_cfg *wb)
+{
+	return 0;
+
+} /*end of mt9e013_snapshot_config*/
+
+static int __exit mt9e013_remove(struct i2c_client *client)
+{
+	struct mt9e013_work_t_t *sensorw = i2c_get_clientdata(client);
+	free_irq(client->irq, sensorw);
+	mt9e013_client = NULL;
+	kfree(sensorw);
+	return 0;
+}
+
+static struct i2c_driver mt9e013_i2c_driver = {
+	.id_table = mt9e013_i2c_id,
+	.probe  = mt9e013_i2c_probe,
+	.remove = __exit_p(mt9e013_i2c_remove),
+	.driver = {
+		.name = "mt9e013",
+	},
+};
+
+int mt9e013_sensor_config(void __user *argp)
+{
+	struct sensor_cfg_data cdata;
+	long   rc = 0;
+	if (copy_from_user(&cdata,
+		(void *)argp,
+		sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+	mutex_lock(&mt9e013_mut);
+	CDBG("mt9e013_sensor_config: cfgtype = %d\n",
+	cdata.cfgtype);
+		switch (cdata.cfgtype) {
+		case CFG_GET_PICT_FPS:
+			mt9e013_get_pict_fps(
+				cdata.cfg.gfps.prevfps,
+				&(cdata.cfg.gfps.pictfps));
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PREV_L_PF:
+			cdata.cfg.prevl_pf =
+			mt9e013_get_prev_lines_pf();
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PREV_P_PL:
+			cdata.cfg.prevp_pl =
+				mt9e013_get_prev_pixels_pl();
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PICT_L_PF:
+			cdata.cfg.pictl_pf =
+				mt9e013_get_pict_lines_pf();
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PICT_P_PL:
+			cdata.cfg.pictp_pl =
+				mt9e013_get_pict_pixels_pl();
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PICT_MAX_EXP_LC:
+			cdata.cfg.pict_max_exp_lc =
+				mt9e013_get_pict_max_exp_lc();
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_SET_FPS:
+		case CFG_SET_PICT_FPS:
+			rc = mt9e013_set_fps(&(cdata.cfg.fps));
+			break;
+
+		case CFG_SET_EXP_GAIN:
+			rc =
+				mt9e013_write_exp_gain(
+					cdata.cfg.exp_gain.gain,
+					cdata.cfg.exp_gain.line);
+			break;
+
+		case CFG_SET_PICT_EXP_GAIN:
+			rc =
+				mt9e013_set_pict_exp_gain(
+				cdata.cfg.exp_gain.gain,
+				cdata.cfg.exp_gain.line);
+			break;
+
+		case CFG_SET_MODE:
+			rc = mt9e013_set_sensor_mode(cdata.mode,
+					cdata.rs);
+			break;
+
+		case CFG_PWR_DOWN:
+			rc = mt9e013_power_down();
+			break;
+
+		case CFG_MOVE_FOCUS:
+			rc =
+				mt9e013_move_focus(
+				cdata.cfg.focus.dir,
+				cdata.cfg.focus.steps);
+			break;
+
+		case CFG_SET_DEFAULT_FOCUS:
+			rc =
+				mt9e013_set_default_focus(
+				cdata.cfg.focus.steps);
+			break;
+
+		case CFG_GET_AF_MAX_STEPS:
+			cdata.max_steps = MT9E013_TOTAL_STEPS_NEAR_TO_FAR;
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_SET_EFFECT:
+			rc = mt9e013_set_default_focus(
+				cdata.cfg.effect);
+			break;
+
+
+		case CFG_SEND_WB_INFO:
+			rc = mt9e013_send_wb_info(
+				&(cdata.cfg.wb_info));
+			break;
+
+		default:
+			rc = -EFAULT;
+			break;
+		}
+
+	mutex_unlock(&mt9e013_mut);
+
+	return rc;
+}
+
+static int mt9e013_sensor_release(void)
+{
+	int rc = -EBADF;
+	mutex_lock(&mt9e013_mut);
+	mt9e013_power_down();
+	gpio_set_value_cansleep(mt9e013_ctrl->sensordata->sensor_reset, 0);
+	msleep(5);
+	gpio_free(mt9e013_ctrl->sensordata->sensor_reset);
+	kfree(mt9e013_ctrl);
+	mt9e013_ctrl = NULL;
+	CDBG("mt9e013_release completed\n");
+	mutex_unlock(&mt9e013_mut);
+
+	return rc;
+}
+
+static int mt9e013_sensor_probe(const struct msm_camera_sensor_info *info,
+		struct msm_sensor_ctrl *s)
+{
+	int rc = 0;
+	rc = i2c_add_driver(&mt9e013_i2c_driver);
+	if (rc < 0 || mt9e013_client == NULL) {
+		rc = -ENOTSUPP;
+		CDBG("I2C add driver failed");
+		goto probe_fail;
+	}
+	msm_camio_clk_rate_set(MT9E013_MASTER_CLK_RATE);
+	rc = mt9e013_probe_init_sensor(info);
+	if (rc < 0)
+		goto probe_fail;
+	s->s_init = mt9e013_sensor_open_init;
+	s->s_release = mt9e013_sensor_release;
+	s->s_config  = mt9e013_sensor_config;
+	s->s_mount_angle = info->sensor_platform_info->mount_angle;
+	gpio_set_value_cansleep(info->sensor_reset, 0);
+	mt9e013_probe_init_done(info);
+	return rc;
+
+probe_fail:
+	CDBG("mt9e013_sensor_probe: SENSOR PROBE FAILS!\n");
+	return rc;
+}
+
+static int __mt9e013_probe(struct platform_device *pdev)
+{
+	return msm_camera_drv_start(pdev, mt9e013_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = __mt9e013_probe,
+	.driver = {
+		.name = "msm_camera_mt9e013",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init mt9e013_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(mt9e013_init);
+void mt9e013_exit(void)
+{
+	i2c_del_driver(&mt9e013_i2c_driver);
+}
+MODULE_DESCRIPTION("Aptina 8 MP Bayer sensor driver");
+MODULE_LICENSE("GPL v2");
+
+static bool streaming = 1;
+
+static int mt9e013_focus_test(void *data, u64 *val)
+{
+	int i = 0;
+	mt9e013_set_default_focus(0);
+
+	for (i = 90; i < 256; i++) {
+		mt9e013_i2c_write_w_sensor(REG_VCM_NEW_CODE, i);
+		msleep(5000);
+	}
+	msleep(5000);
+	for (i = 255; i > 90; i--) {
+		mt9e013_i2c_write_w_sensor(REG_VCM_NEW_CODE, i);
+		msleep(5000);
+	}
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(cam_focus, mt9e013_focus_test,
+			NULL, "%lld\n");
+
+static int mt9e013_step_test(void *data, u64 *val)
+{
+	int i = 0;
+	mt9e013_set_default_focus(0);
+
+	for (i = 0; i < MT9E013_TOTAL_STEPS_NEAR_TO_FAR; i++) {
+		mt9e013_move_focus(MOVE_NEAR, 1);
+		msleep(5000);
+	}
+
+	mt9e013_move_focus(MOVE_FAR, MT9E013_TOTAL_STEPS_NEAR_TO_FAR);
+	msleep(5000);
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(cam_step, mt9e013_step_test,
+			NULL, "%lld\n");
+
+static int cam_debug_stream_set(void *data, u64 val)
+{
+	int rc = 0;
+
+	if (val) {
+		mt9e013_start_stream();
+		streaming = 1;
+	} else {
+		mt9e013_stop_stream();
+		streaming = 0;
+	}
+
+	return rc;
+}
+
+static int cam_debug_stream_get(void *data, u64 *val)
+{
+	*val = streaming;
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(cam_stream, cam_debug_stream_get,
+			cam_debug_stream_set, "%llu\n");
+
+
+static int cam_debug_init(void)
+{
+	struct dentry *cam_dir;
+	debugfs_base = debugfs_create_dir("sensor", NULL);
+	if (!debugfs_base)
+		return -ENOMEM;
+
+	cam_dir = debugfs_create_dir("mt9e013", debugfs_base);
+	if (!cam_dir)
+		return -ENOMEM;
+
+	if (!debugfs_create_file("focus", S_IRUGO | S_IWUSR, cam_dir,
+							 NULL, &cam_focus))
+		return -ENOMEM;
+	if (!debugfs_create_file("step", S_IRUGO | S_IWUSR, cam_dir,
+							 NULL, &cam_step))
+		return -ENOMEM;
+	if (!debugfs_create_file("stream", S_IRUGO | S_IWUSR, cam_dir,
+							 NULL, &cam_stream))
+		return -ENOMEM;
+
+	return 0;
+}
+
+
+
diff --git a/drivers/media/video/msm/mt9e013.h b/drivers/media/video/msm/mt9e013.h
new file mode 100644
index 0000000..9052a35
--- /dev/null
+++ b/drivers/media/video/msm/mt9e013.h
@@ -0,0 +1,174 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#ifndef MT9E013_H
+#define MT9E013_H
+#include <linux/types.h>
+#include <mach/board.h>
+extern struct mt9e013_reg mt9e013_regs;
+struct reg_struct_init {
+	uint8_t reg_0x0112;      /* 0x0112*/
+	uint8_t reg_0x0113;      /* 0x0113*/
+	uint8_t vt_pix_clk_div;  /* 0x0301*/
+	uint8_t pre_pll_clk_div; /* 0x0305*/
+	uint8_t pll_multiplier;  /* 0x0307*/
+	uint8_t op_pix_clk_div;  /* 0x0309*/
+	uint8_t reg_0x3030;      /*0x3030*/
+	uint8_t reg_0x0111;      /*0x0111*/
+	uint8_t reg_0x0b00;      /*0x0b00*/
+	uint8_t reg_0x3001;      /*0x3001*/
+	uint8_t reg_0x3004;      /*0x3004*/
+	uint8_t reg_0x3007;      /*0x3007*/
+	uint8_t reg_0x3016;      /*0x3016*/
+	uint8_t reg_0x301d;      /*0x301d*/
+	uint8_t reg_0x317e;      /*0x317E*/
+	uint8_t reg_0x317f;      /*0x317F*/
+	uint8_t reg_0x3400;      /*0x3400*/
+	uint8_t reg_0x0b06;      /*0x0b06*/
+	uint8_t reg_0x0b07;      /*0x0b07*/
+	uint8_t reg_0x0b08;      /*0x0b08*/
+	uint8_t reg_0x0b09;      /*0x0b09*/
+	uint8_t reg_0x0136;
+	uint8_t reg_0x0137;
+	/* Edof */
+	uint8_t reg_0x0b83;      /*0x0b83*/
+	uint8_t reg_0x0b84;      /*0x0b84*/
+	uint8_t reg_0x0b85;      /*0x0b85*/
+	uint8_t reg_0x0b88;      /*0x0b88*/
+	uint8_t reg_0x0b89;      /*0x0b89*/
+	uint8_t reg_0x0b8a;      /*0x0b8a*/
+	};
+struct reg_struct {
+	uint8_t coarse_integration_time_hi; /*REG_COARSE_INTEGRATION_TIME_HI*/
+	uint8_t coarse_integration_time_lo; /*REG_COARSE_INTEGRATION_TIME_LO*/
+	uint8_t analogue_gain_code_global;
+	uint8_t frame_length_lines_hi; /* 0x0340*/
+	uint8_t frame_length_lines_lo; /* 0x0341*/
+	uint8_t line_length_pck_hi;    /* 0x0342*/
+	uint8_t line_length_pck_lo;    /* 0x0343*/
+	uint8_t reg_0x3005;   /* 0x3005*/
+	uint8_t reg_0x3010;  /* 0x3010*/
+	uint8_t reg_0x3011;  /* 0x3011*/
+	uint8_t reg_0x301a;  /* 0x301a*/
+	uint8_t reg_0x3035;  /* 0x3035*/
+	uint8_t reg_0x3036;   /* 0x3036*/
+	uint8_t reg_0x3041;  /*0x3041*/
+	uint8_t reg_0x3042;  /*0x3042*/
+	uint8_t reg_0x3045;  /*0x3045*/
+	uint8_t reg_0x0b80;   /* 0x0b80*/
+	uint8_t reg_0x0900;   /*0x0900*/
+	uint8_t reg_0x0901;   /* 0x0901*/
+	uint8_t reg_0x0902;   /*0x0902*/
+	uint8_t reg_0x0383;   /*0x0383*/
+	uint8_t reg_0x0387;   /* 0x0387*/
+	uint8_t reg_0x034c;   /* 0x034c*/
+	uint8_t reg_0x034d;   /*0x034d*/
+	uint8_t reg_0x034e;   /* 0x034e*/
+	uint8_t reg_0x034f;   /* 0x034f*/
+	uint8_t reg_0x1716; /*0x1716*/
+	uint8_t reg_0x1717; /*0x1717*/
+	uint8_t reg_0x1718; /*0x1718*/
+	uint8_t reg_0x1719; /*0x1719*/
+	uint8_t reg_0x3210;/*0x3210*/
+	uint8_t reg_0x111; /*0x111*/
+	uint8_t reg_0x3410;  /*0x3410*/
+	uint8_t reg_0x3098;
+	uint8_t reg_0x309D;
+	uint8_t reg_0x0200;
+	uint8_t reg_0x0201;
+	};
+struct mt9e013_i2c_reg_conf {
+	unsigned short waddr;
+	unsigned short wdata;
+};
+
+enum mt9e013_test_mode_t {
+	TEST_OFF,
+	TEST_1,
+	TEST_2,
+	TEST_3
+};
+
+enum mt9e013_resolution_t {
+	QTR_SIZE,
+	FULL_SIZE,
+	HFR_60FPS,
+	HFR_90FPS,
+	HFR_120FPS,
+	INVALID_SIZE
+};
+enum mt9e013_setting {
+	RES_PREVIEW,
+	RES_CAPTURE
+};
+enum mt9e013_reg_update {
+	/* Sensor egisters that need to be updated during initialization */
+	REG_INIT,
+	/* Sensor egisters that needs periodic I2C writes */
+	UPDATE_PERIODIC,
+	/* All the sensor Registers will be updated */
+	UPDATE_ALL,
+	/* Not valid update */
+	UPDATE_INVALID
+};
+
+enum mt9e013_reg_pll {
+	E013_VT_PIX_CLK_DIV,
+	E013_VT_SYS_CLK_DIV,
+	E013_PRE_PLL_CLK_DIV,
+	E013_PLL_MULTIPLIER,
+	E013_OP_PIX_CLK_DIV,
+	E013_OP_SYS_CLK_DIV
+};
+
+enum mt9e013_reg_mode {
+	E013_X_ADDR_START,
+	E013_X_ADDR_END,
+	E013_Y_ADDR_START,
+	E013_Y_ADDR_END,
+	E013_X_OUTPUT_SIZE,
+	E013_Y_OUTPUT_SIZE,
+	E013_DATAPATH_SELECT,
+	E013_READ_MODE,
+	E013_ANALOG_CONTROL5,
+	E013_DAC_LD_4_5,
+	E013_SCALING_MODE,
+	E013_SCALE_M,
+	E013_LINE_LENGTH_PCK,
+	E013_FRAME_LENGTH_LINES,
+	E013_COARSE_INTEGRATION_TIME,
+	E013_FINE_INTEGRATION_TIME,
+	E013_FINE_CORRECTION
+};
+
+struct mt9e013_reg {
+	const struct mt9e013_i2c_reg_conf *reg_mipi;
+	const unsigned short reg_mipi_size;
+	const struct mt9e013_i2c_reg_conf *rec_settings;
+	const unsigned short rec_size;
+	const struct mt9e013_i2c_reg_conf *reg_pll;
+	const unsigned short reg_pll_size;
+	const struct mt9e013_i2c_reg_conf *reg_pll_60fps;
+	const unsigned short reg_pll_60fps_size;
+	const struct mt9e013_i2c_reg_conf *reg_pll_120fps;
+	const unsigned short reg_pll_120fps_size;
+	const struct mt9e013_i2c_reg_conf *reg_prev;
+	const unsigned short reg_prev_size;
+	const struct mt9e013_i2c_reg_conf *reg_snap;
+	const unsigned short reg_snap_size;
+	const struct mt9e013_i2c_reg_conf *reg_60fps;
+	const unsigned short reg_60fps_size;
+	const struct mt9e013_i2c_reg_conf *reg_120fps;
+	const unsigned short reg_120fps_size;
+};
+#endif /* MT9E013_H */
diff --git a/drivers/media/video/msm/mt9e013_reg.c b/drivers/media/video/msm/mt9e013_reg.c
new file mode 100644
index 0000000..9a4bd7e
--- /dev/null
+++ b/drivers/media/video/msm/mt9e013_reg.c
@@ -0,0 +1,234 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+
+#include "mt9e013.h"
+
+static struct mt9e013_i2c_reg_conf mipi_settings[] = {
+	/*Disable embedded data*/
+	{0x3064, 0x7800},/*SMIA_TEST*/
+	/*configure 2-lane MIPI*/
+	{0x31AE, 0x0202},/*SERIAL_FORMAT*/
+	{0x31B8, 0x0E3F},/*MIPI_TIMING_2*/
+	/*set data to RAW10 format*/
+	{0x0112, 0x0A0A},/*CCP_DATA_FORMAT*/
+	{0x30F0, 0x8000},/*VCM CONTROL*/
+};
+
+/*PLL Configuration
+(Ext=24MHz, vt_pix_clk=174MHz, op_pix_clk=69.6MHz)*/
+static struct mt9e013_i2c_reg_conf pll_settings[] = {
+	{0x0300, 0x0004},/*VT_PIX_CLK_DIV*/
+	{0x0302, 0x0001},/*VT_SYS_CLK_DIV*/
+	{0x0304, 0x0002},/*PRE_PLL_CLK_DIV*/
+	{0x0306, 0x003A},/*PLL_MULTIPLIER*/
+	{0x0308, 0x000A},/*OP_PIX_CLK_DIV*/
+	{0x030A, 0x0001},/*OP_SYS_CLK_DIV*/
+};
+
+static struct mt9e013_i2c_reg_conf prev_settings[] = {
+	/*Output Size (1632x1224)*/
+	{0x0344, 0x0008},/*X_ADDR_START*/
+	{0x0348, 0x0CC9},/*X_ADDR_END*/
+	{0x0346, 0x0008},/*Y_ADDR_START*/
+	{0x034A, 0x0999},/*Y_ADDR_END*/
+	{0x034C, 0x0660},/*X_OUTPUT_SIZE*/
+	{0x034E, 0x04C8},/*Y_OUTPUT_SIZE*/
+	{0x306E, 0xFCB0},/*DATAPATH_SELECT*/
+	{0x3040, 0x04C3},/*READ_MODE*/
+	{0x3178, 0x0000},/*ANALOG_CONTROL5*/
+	{0x3ED0, 0x1E24},/*DAC_LD_4_5*/
+	{0x0400, 0x0002},/*SCALING_MODE*/
+	{0x0404, 0x0010},/*SCALE_M*/
+	/*Timing configuration*/
+	{0x0342, 0x1018},/*LINE_LENGTH_PCK*/
+	{0x0340, 0x055B},/*FRAME_LENGTH_LINES*/
+	{0x0202, 0x0557},/*COARSE_INTEGRATION_TIME*/
+	{0x3014, 0x0846},/*FINE_INTEGRATION_TIME_*/
+	{0x3010, 0x0130},/*FINE_CORRECTION*/
+};
+
+static struct mt9e013_i2c_reg_conf snap_settings[] = {
+	/*Output Size (3264x2448)*/
+	{0x0344, 0x0008},/*X_ADDR_START */
+	{0x0348, 0x0CD7},/*X_ADDR_END*/
+	{0x0346, 0x0008},/*Y_ADDR_START */
+	{0x034A, 0x09A7},/*Y_ADDR_END*/
+	{0x034C, 0x0CD0},/*X_OUTPUT_SIZE*/
+	{0x034E, 0x09A0},/*Y_OUTPUT_SIZE*/
+	{0x306E, 0xFC80},/*DATAPATH_SELECT*/
+	{0x3040, 0x0041},/*READ_MODE*/
+	{0x3178, 0x0000},/*ANALOG_CONTROL5*/
+	{0x3ED0, 0x1E24},/*DAC_LD_4_5*/
+	{0x0400, 0x0000},/*SCALING_MODE*/
+	{0x0404, 0x0010},/*SCALE_M*/
+	/*Timing configuration*/
+	{0x0342, 0x13F8},/*LINE_LENGTH_PCK*/
+	{0x0340, 0x0A2F},/*FRAME_LENGTH_LINES*/
+	{0x0202, 0x0A1F},/*COARSE_INTEGRATION_TIME*/
+	{0x3014, 0x03F6},/*FINE_INTEGRATION_TIME_ */
+	{0x3010, 0x0078},/*FINE_CORRECTION*/
+};
+
+static struct mt9e013_i2c_reg_conf pll_settings_60fps[] = {
+	{0x0300, 0x0004},/*VT_PIX_CLK_DIV*/
+	{0x0302, 0x0001},/*VT_SYS_CLK_DIV*/
+	{0x0304, 0x0002},/*PRE_PLL_CLK_DIV*/
+	{0x0306, 0x0042},/*PLL_MULTIPLIER*/
+	{0x0308, 0x000A},/*OP_PIX_CLK_DIV*/
+	{0x030A, 0x0001},/*OP_SYS_CLK_DIV*/
+};
+
+static struct mt9e013_i2c_reg_conf prev_settings_60fps[] = {
+	/*Output Size (1632x1224)*/
+	{0x0344, 0x0008},/*X_ADDR_START*/
+	{0x0348, 0x0CC5},/*X_ADDR_END*/
+	{0x0346, 0x013a},/*Y_ADDR_START*/
+	{0x034A, 0x0863},/*Y_ADDR_END*/
+	{0x034C, 0x0660},/*X_OUTPUT_SIZE*/
+	{0x034E, 0x0396},/*Y_OUTPUT_SIZE*/
+	{0x306E, 0xFC80},/*DATAPATH_SELECT*/
+	{0x3040, 0x00C3},/*READ_MODE*/
+	{0x3178, 0x0000},/*ANALOG_CONTROL5*/
+	{0x3ED0, 0x1E24},/*DAC_LD_4_5*/
+	{0x0400, 0x0000},/*SCALING_MODE*/
+	{0x0404, 0x0010},/*SCALE_M*/
+	/*Timing configuration*/
+	{0x0342, 0x0BE8},/*LINE_LENGTH_PCK*/
+	{0x0340, 0x0425},/*FRAME_LENGTH_LINES*/
+	{0x0202, 0x0425},/*COARSE_INTEGRATION_TIME*/
+	{0x3014, 0x03F6},/*FINE_INTEGRATION_TIME_*/
+	{0x3010, 0x0078},/*FINE_CORRECTION*/
+};
+
+static struct mt9e013_i2c_reg_conf pll_settings_120fps[] = {
+	{0x0300, 0x0005},/*VT_PIX_CLK_DIV*/
+	{0x0302, 0x0001},/*VT_SYS_CLK_DIV*/
+	{0x0304, 0x0002},/*PRE_PLL_CLK_DIV*/
+	{0x0306, 0x0052},/*PLL_MULTIPLIER*/
+	{0x0308, 0x000A},/*OP_PIX_CLK_DIV*/
+	{0x030A, 0x0001},/*OP_SYS_CLK_DIV*/
+};
+
+static struct mt9e013_i2c_reg_conf prev_settings_120fps[] = {
+	{0x0344, 0x0008},/*X_ADDR_START*/
+	{0x0348, 0x0685},/*X_ADDR_END*/
+	{0x0346, 0x013a},/*Y_ADDR_START*/
+	{0x034A, 0x055B},/*Y_ADDR_END*/
+	{0x034C, 0x0340},/*X_OUTPUT_SIZE*/
+	{0x034E, 0x0212},/*Y_OUTPUT_SIZE*/
+	{0x306E, 0xFC80},/*DATAPATH_SELECT*/
+	{0x3040, 0x00C3},/*READ_MODE*/
+	{0x3178, 0x0000},/*ANALOG_CONTROL5*/
+	{0x3ED0, 0x1E24},/*DAC_LD_4_5*/
+	{0x0400, 0x0000},/*SCALING_MODE*/
+	{0x0404, 0x0010},/*SCALE_M*/
+	/*Timing configuration*/
+	{0x0342, 0x0970},/*LINE_LENGTH_PCK*/
+	{0x0340, 0x02A1},/*FRAME_LENGTH_LINES*/
+	{0x0202, 0x02A1},/*COARSE_INTEGRATION_TIME*/
+	{0x3014, 0x03F6},/*FINE_INTEGRATION_TIME_*/
+	{0x3010, 0x0078},/*FINE_CORRECTION*/
+};
+
+static struct mt9e013_i2c_reg_conf recommend_settings[] = {
+	{0x3044, 0x0590},
+	{0x306E, 0xFC80},
+	{0x30B2, 0xC000},
+	{0x30D6, 0x0800},
+	{0x316C, 0xB42F},
+	{0x316E, 0x869C},
+	{0x3170, 0x210E},
+	{0x317A, 0x010E},
+	{0x31E0, 0x1FB9},
+	{0x31E6, 0x07FC},
+	{0x37C0, 0x0000},
+	{0x37C2, 0x0000},
+	{0x37C4, 0x0000},
+	{0x37C6, 0x0000},
+	{0x3E02, 0x8801},
+	{0x3E04, 0x2301},
+	{0x3E06, 0x8449},
+	{0x3E08, 0x6841},
+	{0x3E0A, 0x400C},
+	{0x3E0C, 0x1001},
+	{0x3E0E, 0x2103},
+	{0x3E10, 0x4B41},
+	{0x3E12, 0x4B26},
+	{0x3E16, 0x8802},
+	{0x3E18, 0x84FF},
+	{0x3E1A, 0x8601},
+	{0x3E1C, 0x8401},
+	{0x3E1E, 0x840A},
+	{0x3E20, 0xFF00},
+	{0x3E22, 0x8401},
+	{0x3E24, 0x00FF},
+	{0x3E26, 0x0088},
+	{0x3E28, 0x2E8A},
+	{0x3E32, 0x8801},
+	{0x3E34, 0x4024},
+	{0x3E38, 0x8469},
+	{0x3E3C, 0x2301},
+	{0x3E3E, 0x3E25},
+	{0x3E40, 0x1C01},
+	{0x3E42, 0x8486},
+	{0x3E44, 0x8401},
+	{0x3E46, 0x00FF},
+	{0x3E48, 0x8401},
+	{0x3E4A, 0x8601},
+	{0x3E4C, 0x8402},
+	{0x3E4E, 0x00FF},
+	{0x3E50, 0x6623},
+	{0x3E52, 0x8340},
+	{0x3E54, 0x00FF},
+	{0x3E56, 0x4A42},
+	{0x3E58, 0x2203},
+	{0x3E5A, 0x674D},
+	{0x3E5C, 0x3F25},
+	{0x3E5E, 0x846A},
+	{0x3E60, 0x4C01},
+	{0x3E62, 0x8401},
+	{0x3E66, 0x3901},
+	{0x3ECC, 0x00EB},
+	{0x3ED0, 0x1E24},
+	{0x3ED4, 0xAFC4},
+	{0x3ED6, 0x909B},
+	{0x3ED8, 0x0006},
+	{0x3EDA, 0xCFC6},
+	{0x3EDC, 0x4FE4},
+	{0x3EE0, 0x2424},
+	{0x3EE2, 0x9797},
+	{0x3EE4, 0xC100},
+	{0x3EE6, 0x0540}
+};
+
+struct mt9e013_reg mt9e013_regs = {
+	.reg_mipi = &mipi_settings[0],
+	.reg_mipi_size = ARRAY_SIZE(mipi_settings),
+	.rec_settings = &recommend_settings[0],
+	.rec_size = ARRAY_SIZE(recommend_settings),
+	.reg_pll = &pll_settings[0],
+	.reg_pll_size = ARRAY_SIZE(pll_settings),
+	.reg_prev = &prev_settings[0],
+	.reg_pll_60fps = &pll_settings_60fps[0],
+	.reg_pll_60fps_size = ARRAY_SIZE(pll_settings_60fps),
+	.reg_pll_120fps = &pll_settings_120fps[0],
+	.reg_pll_120fps_size = ARRAY_SIZE(pll_settings_120fps),
+	.reg_prev_size = ARRAY_SIZE(prev_settings),
+	.reg_snap = &snap_settings[0],
+	.reg_snap_size = ARRAY_SIZE(snap_settings),
+	.reg_60fps = &prev_settings_60fps[0],
+	.reg_60fps_size = ARRAY_SIZE(prev_settings_60fps),
+	.reg_120fps = &prev_settings_120fps[0],
+	.reg_120fps_size = ARRAY_SIZE(prev_settings_120fps),
+};
diff --git a/drivers/media/video/msm/mt9p012.h b/drivers/media/video/msm/mt9p012.h
new file mode 100644
index 0000000..0579813
--- /dev/null
+++ b/drivers/media/video/msm/mt9p012.h
@@ -0,0 +1,59 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#ifndef MT9T012_H
+#define MT9T012_H
+
+#include <linux/types.h>
+
+extern struct mt9p012_reg mt9p012_regs;	/* from mt9p012_reg.c */
+
+struct reg_struct {
+	uint16_t vt_pix_clk_div;     /* 0x0300 */
+	uint16_t vt_sys_clk_div;     /* 0x0302 */
+	uint16_t pre_pll_clk_div;    /* 0x0304 */
+	uint16_t pll_multiplier;     /* 0x0306 */
+	uint16_t op_pix_clk_div;     /* 0x0308 */
+	uint16_t op_sys_clk_div;     /* 0x030A */
+	uint16_t scale_m;            /* 0x0404 */
+	uint16_t row_speed;          /* 0x3016 */
+	uint16_t x_addr_start;       /* 0x3004 */
+	uint16_t x_addr_end;         /* 0x3008 */
+	uint16_t y_addr_start;       /* 0x3002 */
+	uint16_t y_addr_end;         /* 0x3006 */
+	uint16_t read_mode;          /* 0x3040 */
+	uint16_t x_output_size ;     /* 0x034C */
+	uint16_t y_output_size;      /* 0x034E */
+	uint16_t line_length_pck;    /* 0x300C */
+	uint16_t frame_length_lines; /* 0x300A */
+	uint16_t coarse_int_time;    /* 0x3012 */
+	uint16_t fine_int_time;      /* 0x3014 */
+};
+
+
+struct mt9p012_i2c_reg_conf {
+	unsigned short waddr;
+	unsigned short wdata;
+};
+
+
+struct mt9p012_reg {
+	struct reg_struct const *reg_pat;
+	uint16_t reg_pat_size;
+	struct mt9p012_i2c_reg_conf const *ttbl;
+	uint16_t ttbl_size;
+	struct mt9p012_i2c_reg_conf const *rftbl;
+	uint16_t rftbl_size;
+};
+
+#endif /* MT9T012_H */
diff --git a/drivers/media/video/msm/mt9p012_bam.c b/drivers/media/video/msm/mt9p012_bam.c
new file mode 100644
index 0000000..9197380
--- /dev/null
+++ b/drivers/media/video/msm/mt9p012_bam.c
@@ -0,0 +1,1426 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <media/msm_camera.h>
+#include <mach/gpio.h>
+#include <mach/camera.h>
+#include "mt9p012.h"
+
+/*=============================================================
+    SENSOR REGISTER DEFINES
+==============================================================*/
+#define MT9P012_REG_MODEL_ID         0x0000
+#define MT9P012_MODEL_ID             0x2801
+#define REG_GROUPED_PARAMETER_HOLD   0x0104
+#define GROUPED_PARAMETER_HOLD       0x0100
+#define GROUPED_PARAMETER_UPDATE     0x0000
+#define REG_COARSE_INT_TIME          0x3012
+#define REG_VT_PIX_CLK_DIV           0x0300
+#define REG_VT_SYS_CLK_DIV           0x0302
+#define REG_PRE_PLL_CLK_DIV          0x0304
+#define REG_PLL_MULTIPLIER           0x0306
+#define REG_OP_PIX_CLK_DIV           0x0308
+#define REG_OP_SYS_CLK_DIV           0x030A
+#define REG_SCALE_M                  0x0404
+#define REG_FRAME_LENGTH_LINES       0x300A
+#define REG_LINE_LENGTH_PCK          0x300C
+#define REG_X_ADDR_START             0x3004
+#define REG_Y_ADDR_START             0x3002
+#define REG_X_ADDR_END               0x3008
+#define REG_Y_ADDR_END               0x3006
+#define REG_X_OUTPUT_SIZE            0x034C
+#define REG_Y_OUTPUT_SIZE            0x034E
+#define REG_FINE_INTEGRATION_TIME    0x3014
+#define REG_ROW_SPEED                0x3016
+#define MT9P012_REG_RESET_REGISTER   0x301A
+#define MT9P012_RESET_REGISTER_PWON  0x10CC
+#define MT9P012_RESET_REGISTER_PWOFF 0x10C8
+#define REG_READ_MODE                0x3040
+#define REG_GLOBAL_GAIN              0x305E
+#define REG_TEST_PATTERN_MODE        0x3070
+
+#define MT9P012_REV_7
+
+enum mt9p012_test_mode {
+	TEST_OFF,
+	TEST_1,
+	TEST_2,
+	TEST_3
+};
+
+enum mt9p012_resolution {
+	QTR_SIZE,
+	FULL_SIZE,
+	INVALID_SIZE
+};
+
+enum mt9p012_reg_update {
+	/* Sensor egisters that need to be updated during initialization */
+	REG_INIT,
+	/* Sensor egisters that needs periodic I2C writes */
+	UPDATE_PERIODIC,
+	/* All the sensor Registers will be updated */
+	UPDATE_ALL,
+	/* Not valid update */
+	UPDATE_INVALID
+};
+
+enum mt9p012_setting {
+	RES_PREVIEW,
+	RES_CAPTURE
+};
+
+/* actuator's Slave Address */
+#define MT9P012_AF_I2C_ADDR   0x0A
+
+/* AF Total steps parameters */
+#define MT9P012_STEPS_NEAR_TO_CLOSEST_INF  20
+#define MT9P012_TOTAL_STEPS_NEAR_TO_FAR    20
+
+#define MT9P012_MU5M0_PREVIEW_DUMMY_PIXELS 0
+#define MT9P012_MU5M0_PREVIEW_DUMMY_LINES  0
+
+/* Time in milisecs for waiting for the sensor to reset.*/
+#define MT9P012_RESET_DELAY_MSECS   66
+
+/* for 20 fps preview */
+#define MT9P012_DEFAULT_CLOCK_RATE  24000000
+#define MT9P012_DEFAULT_MAX_FPS     26	/* ???? */
+
+struct mt9p012_work {
+	struct work_struct work;
+};
+static struct mt9p012_work *mt9p012_sensorw;
+static struct i2c_client *mt9p012_client;
+
+struct mt9p012_ctrl {
+	const struct msm_camera_sensor_info *sensordata;
+
+	int sensormode;
+	uint32_t fps_divider;	/* init to 1 * 0x00000400 */
+	uint32_t pict_fps_divider;	/* init to 1 * 0x00000400 */
+
+	uint16_t curr_lens_pos;
+	uint16_t init_curr_lens_pos;
+	uint16_t my_reg_gain;
+	uint32_t my_reg_line_count;
+
+	enum mt9p012_resolution prev_res;
+	enum mt9p012_resolution pict_res;
+	enum mt9p012_resolution curr_res;
+	enum mt9p012_test_mode set_test;
+};
+
+static uint16_t bam_macro, bam_infinite;
+static uint16_t bam_step_lookup_table[MT9P012_TOTAL_STEPS_NEAR_TO_FAR + 1];
+static uint16_t update_type = UPDATE_PERIODIC;
+static struct mt9p012_ctrl *mt9p012_ctrl;
+static DECLARE_WAIT_QUEUE_HEAD(mt9p012_wait_queue);
+DEFINE_MUTEX(mt9p012_mut);
+
+/*=============================================================*/
+
+static int mt9p012_i2c_rxdata(unsigned short saddr, int slength,
+			      unsigned char *rxdata, int rxlength)
+{
+	struct i2c_msg msgs[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = slength,
+			.buf = rxdata,
+		},
+		{
+			.addr = saddr,
+			.flags = I2C_M_RD,
+			.len = rxlength,
+			.buf = rxdata,
+		},
+	};
+
+	if (i2c_transfer(mt9p012_client->adapter, msgs, 2) < 0) {
+		CDBG("mt9p012_i2c_rxdata failed!\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+static int32_t mt9p012_i2c_read_b(unsigned short saddr, unsigned char raddr,
+				  unsigned short *rdata)
+{
+	int32_t rc = 0;
+	if (!rdata)
+		return -EIO;
+	rc = mt9p012_i2c_rxdata(saddr, 1, &raddr, 1);
+	if (rc < 0)
+		return rc;
+	*rdata = raddr;
+	if (rc < 0)
+		CDBG("mt9p012_i2c_read_b failed!\n");
+	return rc;
+}
+
+static int32_t mt9p012_i2c_read_w(unsigned short saddr, unsigned short raddr,
+				  unsigned short *rdata)
+{
+	int32_t rc = 0;
+	unsigned char buf[4];
+
+	if (!rdata)
+		return -EIO;
+
+	memset(buf, 0, sizeof(buf));
+
+	buf[0] = (raddr & 0xFF00) >> 8;
+	buf[1] = (raddr & 0x00FF);
+
+	rc = mt9p012_i2c_rxdata(saddr, 2, buf, 2);
+	if (rc < 0)
+		return rc;
+
+	*rdata = buf[0] << 8 | buf[1];
+
+	if (rc < 0)
+		CDBG("mt9p012_i2c_read failed!\n");
+
+	return rc;
+}
+
+static int32_t mt9p012_i2c_txdata(unsigned short saddr, unsigned char *txdata,
+				  int length)
+{
+	struct i2c_msg msg[] = {
+		{
+		 .addr = saddr,
+		 .flags = 0,
+		 .len = length,
+		 .buf = txdata,
+		 },
+	};
+
+	if (i2c_transfer(mt9p012_client->adapter, msg, 1) < 0) {
+		CDBG("mt9p012_i2c_txdata failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t mt9p012_i2c_write_b(unsigned short saddr, unsigned short baddr,
+				   unsigned short bdata)
+{
+	int32_t rc = -EIO;
+	unsigned char buf[2];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = baddr;
+	buf[1] = bdata;
+	rc = mt9p012_i2c_txdata(saddr, buf, 2);
+
+	if (rc < 0)
+		CDBG("i2c_write failed, saddr = 0x%x addr = 0x%x, val =0x%x!\n",
+		     saddr, baddr, bdata);
+
+	return rc;
+}
+
+static int32_t mt9p012_i2c_write_w(unsigned short saddr, unsigned short waddr,
+				   unsigned short wdata)
+{
+	int32_t rc = -EIO;
+	unsigned char buf[4];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = (wdata & 0xFF00) >> 8;
+	buf[3] = (wdata & 0x00FF);
+
+	rc = mt9p012_i2c_txdata(saddr, buf, 4);
+
+	if (rc < 0)
+		CDBG("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n",
+		     waddr, wdata);
+
+	return rc;
+}
+
+static int32_t mt9p012_i2c_write_w_table(struct mt9p012_i2c_reg_conf const
+					 *reg_conf_tbl, int num)
+{
+	int i;
+	int32_t rc = -EIO;
+
+	for (i = 0; i < num; i++) {
+		rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+					 reg_conf_tbl->waddr,
+					 reg_conf_tbl->wdata);
+		if (rc < 0)
+			break;
+		reg_conf_tbl++;
+	}
+
+	return rc;
+}
+
+static int32_t mt9p012_test(enum mt9p012_test_mode mo)
+{
+	int32_t rc = 0;
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD);
+	if (rc < 0)
+		return rc;
+
+	if (mo == TEST_OFF)
+		return 0;
+	else {
+		rc = mt9p012_i2c_write_w_table(mt9p012_regs.ttbl,
+					       mt9p012_regs.ttbl_size);
+		if (rc < 0)
+			return rc;
+
+		rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+					 REG_TEST_PATTERN_MODE, (uint16_t) mo);
+		if (rc < 0)
+			return rc;
+	}
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE);
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+
+static int32_t mt9p012_lens_shading_enable(uint8_t is_enable)
+{
+	int32_t rc = 0;
+
+	CDBG("%s: entered. enable = %d\n", __func__, is_enable);
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x3780,
+				 ((uint16_t) is_enable) << 15);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE);
+
+	CDBG("%s: exiting. rc = %d\n", __func__, rc);
+	return rc;
+}
+
+static int32_t mt9p012_set_lc(void)
+{
+	int32_t rc;
+
+	rc = mt9p012_i2c_write_w_table(mt9p012_regs.rftbl,
+				       mt9p012_regs.rftbl_size);
+
+	return rc;
+}
+
+static void mt9p012_get_pict_fps(uint16_t fps, uint16_t *pfps)
+{
+	/* input fps is preview fps in Q8 format */
+	uint32_t divider;	/*Q10 */
+	uint32_t pclk_mult;	/*Q10 */
+
+	if (mt9p012_ctrl->prev_res == QTR_SIZE) {
+		divider = (uint32_t)
+		    (((mt9p012_regs.reg_pat[RES_PREVIEW].frame_length_lines *
+		       mt9p012_regs.reg_pat[RES_PREVIEW].line_length_pck) *
+		      0x00000400) /
+		     (mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines *
+		      mt9p012_regs.reg_pat[RES_CAPTURE].line_length_pck));
+
+		pclk_mult =
+		    (uint32_t) ((mt9p012_regs.reg_pat[RES_CAPTURE].
+				 pll_multiplier * 0x00000400) /
+				(mt9p012_regs.reg_pat[RES_PREVIEW].
+				 pll_multiplier));
+	} else {
+		/* full size resolution used for preview. */
+		divider = 0x00000400;	/*1.0 */
+		pclk_mult = 0x00000400;	/*1.0 */
+	}
+
+	/* Verify PCLK settings and frame sizes. */
+	*pfps = (uint16_t) (fps * divider * pclk_mult / 0x00000400 /
+			    0x00000400);
+}
+
+static uint16_t mt9p012_get_prev_lines_pf(void)
+{
+	if (mt9p012_ctrl->prev_res == QTR_SIZE)
+		return mt9p012_regs.reg_pat[RES_PREVIEW].frame_length_lines;
+	else
+		return mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines;
+}
+
+static uint16_t mt9p012_get_prev_pixels_pl(void)
+{
+	if (mt9p012_ctrl->prev_res == QTR_SIZE)
+		return mt9p012_regs.reg_pat[RES_PREVIEW].line_length_pck;
+	else
+		return mt9p012_regs.reg_pat[RES_CAPTURE].line_length_pck;
+}
+
+static uint16_t mt9p012_get_pict_lines_pf(void)
+{
+	return mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines;
+}
+
+static uint16_t mt9p012_get_pict_pixels_pl(void)
+{
+	return mt9p012_regs.reg_pat[RES_CAPTURE].line_length_pck;
+}
+
+static uint32_t mt9p012_get_pict_max_exp_lc(void)
+{
+	uint16_t snapshot_lines_per_frame;
+
+	if (mt9p012_ctrl->pict_res == QTR_SIZE)
+		snapshot_lines_per_frame =
+		    mt9p012_regs.reg_pat[RES_PREVIEW].frame_length_lines - 1;
+	else
+		snapshot_lines_per_frame =
+		    mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines - 1;
+
+	return snapshot_lines_per_frame * 24;
+}
+
+static int32_t mt9p012_set_fps(struct fps_cfg *fps)
+{
+	/* input is new fps in Q10 format */
+	int32_t rc = 0;
+	enum mt9p012_setting setting;
+
+	mt9p012_ctrl->fps_divider = fps->fps_div;
+	mt9p012_ctrl->pict_fps_divider = fps->pict_fps_div;
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD);
+	if (rc < 0)
+		return -EBUSY;
+
+	if (mt9p012_ctrl->sensormode == SENSOR_PREVIEW_MODE)
+		setting = RES_PREVIEW;
+	else
+		setting = RES_CAPTURE;
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+			REG_FRAME_LENGTH_LINES,
+			(mt9p012_regs.reg_pat[setting].frame_length_lines *
+			fps->fps_div / 0x00000400));
+	if (rc < 0)
+		return rc;
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE);
+
+	return rc;
+}
+
+static int32_t mt9p012_write_exp_gain(uint16_t gain, uint32_t line)
+{
+	uint16_t max_legal_gain = 0x01FF;
+	uint32_t line_length_ratio = 0x00000400;
+	enum mt9p012_setting setting;
+	int32_t rc = 0;
+
+	CDBG("Line:%d mt9p012_write_exp_gain \n", __LINE__);
+
+	if (mt9p012_ctrl->sensormode == SENSOR_PREVIEW_MODE) {
+		mt9p012_ctrl->my_reg_gain = gain;
+		mt9p012_ctrl->my_reg_line_count = (uint16_t) line;
+	}
+
+	if (gain > max_legal_gain) {
+		CDBG("Max legal gain Line:%d \n", __LINE__);
+		gain = max_legal_gain;
+	}
+
+	/* Verify no overflow */
+	if (mt9p012_ctrl->sensormode == SENSOR_PREVIEW_MODE) {
+		line = (uint32_t) (line * mt9p012_ctrl->fps_divider /
+				   0x00000400);
+		setting = RES_PREVIEW;
+	} else {
+		line = (uint32_t) (line * mt9p012_ctrl->pict_fps_divider /
+				   0x00000400);
+		setting = RES_CAPTURE;
+	}
+
+	/* Set digital gain to 1 */
+#ifdef MT9P012_REV_7
+	gain |= 0x1000;
+#else
+	gain |= 0x0200;
+#endif
+
+	if ((mt9p012_regs.reg_pat[setting].frame_length_lines - 1) < line) {
+		line_length_ratio = (uint32_t) (line * 0x00000400) /
+		    (mt9p012_regs.reg_pat[setting].frame_length_lines - 1);
+	} else
+		line_length_ratio = 0x00000400;
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr, REG_GLOBAL_GAIN, gain);
+	if (rc < 0) {
+		CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__);
+		return rc;
+	}
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_COARSE_INT_TIME, line);
+	if (rc < 0) {
+		CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__);
+		return rc;
+	}
+
+	CDBG("mt9p012_write_exp_gain: gain = %d, line = %d\n", gain, line);
+
+	return rc;
+}
+
+static int32_t mt9p012_set_pict_exp_gain(uint16_t gain, uint32_t line)
+{
+	int32_t rc = 0;
+
+	CDBG("Line:%d mt9p012_set_pict_exp_gain \n", __LINE__);
+
+	rc = mt9p012_write_exp_gain(gain, line);
+	if (rc < 0) {
+		CDBG("Line:%d mt9p012_set_pict_exp_gain failed... \n",
+		     __LINE__);
+		return rc;
+	}
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 MT9P012_REG_RESET_REGISTER, 0x10CC | 0x0002);
+	if (rc < 0) {
+		CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__);
+		return rc;
+	}
+
+	mdelay(5);
+
+	/* camera_timed_wait(snapshot_wait*exposure_ratio); */
+	return rc;
+}
+
+static int32_t mt9p012_setting(enum mt9p012_reg_update rupdate,
+			       enum mt9p012_setting rt)
+{
+	int32_t rc = 0;
+
+	switch (rupdate) {
+	case UPDATE_PERIODIC:
+		if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+			struct mt9p012_i2c_reg_conf ppc_tbl[] = {
+				{REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD},
+				{REG_ROW_SPEED,
+				 mt9p012_regs.reg_pat[rt].row_speed},
+				{REG_X_ADDR_START,
+				 mt9p012_regs.reg_pat[rt].x_addr_start},
+				{REG_X_ADDR_END,
+				 mt9p012_regs.reg_pat[rt].x_addr_end},
+				{REG_Y_ADDR_START,
+				 mt9p012_regs.reg_pat[rt].y_addr_start},
+				{REG_Y_ADDR_END,
+				 mt9p012_regs.reg_pat[rt].y_addr_end},
+				{REG_READ_MODE,
+				 mt9p012_regs.reg_pat[rt].read_mode},
+				{REG_SCALE_M, mt9p012_regs.reg_pat[rt].scale_m},
+				{REG_X_OUTPUT_SIZE,
+				 mt9p012_regs.reg_pat[rt].x_output_size},
+				{REG_Y_OUTPUT_SIZE,
+				 mt9p012_regs.reg_pat[rt].y_output_size},
+
+				{REG_LINE_LENGTH_PCK,
+				 mt9p012_regs.reg_pat[rt].line_length_pck},
+				{REG_FRAME_LENGTH_LINES,
+				 (mt9p012_regs.reg_pat[rt].frame_length_lines *
+				  mt9p012_ctrl->fps_divider / 0x00000400)},
+				{REG_COARSE_INT_TIME,
+				 mt9p012_regs.reg_pat[rt].coarse_int_time},
+				{REG_FINE_INTEGRATION_TIME,
+				 mt9p012_regs.reg_pat[rt].fine_int_time},
+				{REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE},
+			};
+			if (update_type == REG_INIT) {
+				update_type = rupdate;
+				return rc;
+			}
+			rc = mt9p012_i2c_write_w_table(&ppc_tbl[0],
+						ARRAY_SIZE(ppc_tbl));
+			if (rc < 0)
+				return rc;
+
+			rc = mt9p012_test(mt9p012_ctrl->set_test);
+			if (rc < 0)
+				return rc;
+
+			rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+						 MT9P012_REG_RESET_REGISTER,
+						 MT9P012_RESET_REGISTER_PWON |
+						 0x0002);
+			if (rc < 0)
+				return rc;
+
+			mdelay(5);	/* 15? wait for sensor to transition */
+
+			return rc;
+		}
+		break;		/* UPDATE_PERIODIC */
+
+	case REG_INIT:
+		if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+			struct mt9p012_i2c_reg_conf ipc_tbl1[] = {
+				{MT9P012_REG_RESET_REGISTER,
+				 MT9P012_RESET_REGISTER_PWOFF},
+				{REG_VT_PIX_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].vt_pix_clk_div},
+				{REG_VT_SYS_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].vt_sys_clk_div},
+				{REG_PRE_PLL_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].pre_pll_clk_div},
+				{REG_PLL_MULTIPLIER,
+				 mt9p012_regs.reg_pat[rt].pll_multiplier},
+				{REG_OP_PIX_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].op_pix_clk_div},
+				{REG_OP_SYS_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].op_sys_clk_div},
+#ifdef MT9P012_REV_7
+				{0x30B0, 0x0001},
+				{0x308E, 0xE060},
+				{0x3092, 0x0A52},
+				{0x3094, 0x4656},
+				{0x3096, 0x5652},
+				{0x30CA, 0x8006},
+				{0x312A, 0xDD02},
+				{0x312C, 0x00E4},
+				{0x3170, 0x299A},
+#endif
+				/* optimized settings for noise */
+				{0x3088, 0x6FF6},
+				{0x3154, 0x0282},
+				{0x3156, 0x0381},
+				{0x3162, 0x04CE},
+				{0x0204, 0x0010},
+				{0x0206, 0x0010},
+				{0x0208, 0x0010},
+				{0x020A, 0x0010},
+				{0x020C, 0x0010},
+				{MT9P012_REG_RESET_REGISTER,
+				 MT9P012_RESET_REGISTER_PWON},
+			};
+
+			struct mt9p012_i2c_reg_conf ipc_tbl2[] = {
+				{MT9P012_REG_RESET_REGISTER,
+				 MT9P012_RESET_REGISTER_PWOFF},
+				{REG_VT_PIX_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].vt_pix_clk_div},
+				{REG_VT_SYS_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].vt_sys_clk_div},
+				{REG_PRE_PLL_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].pre_pll_clk_div},
+				{REG_PLL_MULTIPLIER,
+				 mt9p012_regs.reg_pat[rt].pll_multiplier},
+				{REG_OP_PIX_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].op_pix_clk_div},
+				{REG_OP_SYS_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].op_sys_clk_div},
+#ifdef MT9P012_REV_7
+				{0x30B0, 0x0001},
+				{0x308E, 0xE060},
+				{0x3092, 0x0A52},
+				{0x3094, 0x4656},
+				{0x3096, 0x5652},
+				{0x30CA, 0x8006},
+				{0x312A, 0xDD02},
+				{0x312C, 0x00E4},
+				{0x3170, 0x299A},
+#endif
+				/* optimized settings for noise */
+				{0x3088, 0x6FF6},
+				{0x3154, 0x0282},
+				{0x3156, 0x0381},
+				{0x3162, 0x04CE},
+				{0x0204, 0x0010},
+				{0x0206, 0x0010},
+				{0x0208, 0x0010},
+				{0x020A, 0x0010},
+				{0x020C, 0x0010},
+				{MT9P012_REG_RESET_REGISTER,
+				 MT9P012_RESET_REGISTER_PWON},
+			};
+
+			struct mt9p012_i2c_reg_conf ipc_tbl3[] = {
+				{REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD},
+				/* Set preview or snapshot mode */
+				{REG_ROW_SPEED,
+				 mt9p012_regs.reg_pat[rt].row_speed},
+				{REG_X_ADDR_START,
+				 mt9p012_regs.reg_pat[rt].x_addr_start},
+				{REG_X_ADDR_END,
+				 mt9p012_regs.reg_pat[rt].x_addr_end},
+				{REG_Y_ADDR_START,
+				 mt9p012_regs.reg_pat[rt].y_addr_start},
+				{REG_Y_ADDR_END,
+				 mt9p012_regs.reg_pat[rt].y_addr_end},
+				{REG_READ_MODE,
+				 mt9p012_regs.reg_pat[rt].read_mode},
+				{REG_SCALE_M, mt9p012_regs.reg_pat[rt].scale_m},
+				{REG_X_OUTPUT_SIZE,
+				 mt9p012_regs.reg_pat[rt].x_output_size},
+				{REG_Y_OUTPUT_SIZE,
+				 mt9p012_regs.reg_pat[rt].y_output_size},
+				{REG_LINE_LENGTH_PCK,
+				 mt9p012_regs.reg_pat[rt].line_length_pck},
+				{REG_FRAME_LENGTH_LINES,
+				 mt9p012_regs.reg_pat[rt].frame_length_lines},
+				{REG_COARSE_INT_TIME,
+				 mt9p012_regs.reg_pat[rt].coarse_int_time},
+				{REG_FINE_INTEGRATION_TIME,
+				 mt9p012_regs.reg_pat[rt].fine_int_time},
+				{REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE},
+			};
+
+			/* reset fps_divider */
+			mt9p012_ctrl->fps_divider = 1 * 0x0400;
+
+			rc = mt9p012_i2c_write_w_table(&ipc_tbl1[0],
+						       ARRAY_SIZE(ipc_tbl1));
+			if (rc < 0)
+				return rc;
+
+			rc = mt9p012_i2c_write_w_table(&ipc_tbl2[0],
+						       ARRAY_SIZE(ipc_tbl2));
+			if (rc < 0)
+				return rc;
+
+			mdelay(5);
+
+			rc = mt9p012_i2c_write_w_table(&ipc_tbl3[0],
+						       ARRAY_SIZE(ipc_tbl3));
+			if (rc < 0)
+				return rc;
+
+			/* load lens shading */
+			rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+						 REG_GROUPED_PARAMETER_HOLD,
+						 GROUPED_PARAMETER_HOLD);
+			if (rc < 0)
+				return rc;
+
+			rc = mt9p012_set_lc();
+			if (rc < 0)
+				return rc;
+
+			rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+						 REG_GROUPED_PARAMETER_HOLD,
+						 GROUPED_PARAMETER_UPDATE);
+
+			if (rc < 0)
+				return rc;
+		}
+		update_type = rupdate;
+		break;		/* case REG_INIT: */
+
+	default:
+		rc = -EINVAL;
+		break;
+	}			/* switch (rupdate) */
+
+	return rc;
+}
+
+static int32_t mt9p012_video_config(int mode, int res)
+{
+	int32_t rc;
+
+	switch (res) {
+	case QTR_SIZE:
+		rc = mt9p012_setting(UPDATE_PERIODIC, RES_PREVIEW);
+		if (rc < 0)
+			return rc;
+
+		CDBG("mt9p012 sensor configuration done!\n");
+		break;
+
+	case FULL_SIZE:
+		rc = mt9p012_setting(UPDATE_PERIODIC, RES_CAPTURE);
+		if (rc < 0)
+			return rc;
+
+		break;
+
+	default:
+		return 0;
+	}			/* switch */
+
+	mt9p012_ctrl->prev_res = res;
+	mt9p012_ctrl->curr_res = res;
+	mt9p012_ctrl->sensormode = mode;
+
+	rc = mt9p012_write_exp_gain(mt9p012_ctrl->my_reg_gain,
+				    mt9p012_ctrl->my_reg_line_count);
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 MT9P012_REG_RESET_REGISTER, 0x10cc | 0x0002);
+
+	return rc;
+}
+
+static int32_t mt9p012_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+
+	rc = mt9p012_setting(UPDATE_PERIODIC, RES_CAPTURE);
+	if (rc < 0)
+		return rc;
+
+	mt9p012_ctrl->curr_res = mt9p012_ctrl->pict_res;
+
+	mt9p012_ctrl->sensormode = mode;
+
+	return rc;
+}
+
+static int32_t mt9p012_raw_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+
+	rc = mt9p012_setting(UPDATE_PERIODIC, RES_CAPTURE);
+	if (rc < 0)
+		return rc;
+
+	mt9p012_ctrl->curr_res = mt9p012_ctrl->pict_res;
+
+	mt9p012_ctrl->sensormode = mode;
+
+	return rc;
+}
+
+static int32_t mt9p012_power_down(void)
+{
+	int32_t rc = 0;
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 MT9P012_REG_RESET_REGISTER,
+				 MT9P012_RESET_REGISTER_PWOFF);
+
+	mdelay(5);
+	return rc;
+}
+
+static int32_t mt9p012_move_focus(int direction, int32_t num_steps)
+{
+	int32_t rc;
+	int16_t step_direction;
+	int16_t actual_step;
+	int16_t next_position;
+	uint8_t code_val;
+	uint8_t time_out;
+	uint8_t temp_pos;
+
+	uint16_t actual_position_target;
+	if (num_steps > MT9P012_TOTAL_STEPS_NEAR_TO_FAR)
+		num_steps = MT9P012_TOTAL_STEPS_NEAR_TO_FAR;
+	else if (num_steps == 0) {
+		CDBG("mt9p012_move_focus failed at line %d ...\n", __LINE__);
+		return -EINVAL;
+	}
+
+	if (direction == MOVE_NEAR)
+		step_direction = -1;
+	else if (direction == MOVE_FAR)
+		step_direction = 1;
+	else {
+		CDBG("mt9p012_move_focus failed at line %d ...\n", __LINE__);
+		return -EINVAL;
+	}
+
+	if (mt9p012_ctrl->curr_lens_pos < mt9p012_ctrl->init_curr_lens_pos)
+		mt9p012_ctrl->curr_lens_pos = mt9p012_ctrl->init_curr_lens_pos;
+
+	actual_step = (int16_t) (step_direction * (int16_t) num_steps);
+	next_position = (int16_t) (mt9p012_ctrl->curr_lens_pos + actual_step);
+
+	if (next_position > MT9P012_TOTAL_STEPS_NEAR_TO_FAR)
+		next_position = MT9P012_TOTAL_STEPS_NEAR_TO_FAR;
+	else if (next_position < 0)
+		next_position = 0;
+
+	if (num_steps >= 10)
+		time_out = 100;
+	else
+		time_out = 30;
+	code_val = next_position;
+	actual_position_target = bam_step_lookup_table[code_val];
+	rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x01, 0x29);
+	if (rc < 0)
+		return rc;
+	temp_pos = (uint8_t) (actual_position_target >> 8);
+	rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x05, temp_pos);
+	if (rc < 0)
+		return rc;
+	temp_pos = (uint8_t) (actual_position_target & 0x00FF);
+	/* code_val_lsb |= mode_mask; */
+	rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x06, temp_pos);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x0B, time_out);
+	if (rc < 0)
+		return rc;
+	rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x07, 0x27);
+	if (rc < 0)
+		return rc;
+
+	mdelay(time_out);
+
+	/* Storing the current lens Position */
+	mt9p012_ctrl->curr_lens_pos = next_position;
+
+	return rc;
+}
+
+static int32_t mt9p012_set_default_focus(void)
+{
+	int32_t rc = 0;
+
+	uint8_t temp_pos;
+
+	/* Write the digital code for current to the actuator */
+	rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x01, 0x29);
+	if (rc < 0)
+		return rc;
+	temp_pos = (uint8_t) (bam_infinite >> 8);
+
+	rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x05, temp_pos);
+	if (rc < 0)
+		return rc;
+	temp_pos = (uint8_t) (bam_infinite & 0x00FF);
+	rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x06, temp_pos);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x0B, 0x64);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x07, 0x27);
+	if (rc < 0)
+		return rc;
+
+	mdelay(140);
+
+	mt9p012_ctrl->curr_lens_pos = MT9P012_TOTAL_STEPS_NEAR_TO_FAR;
+
+	return rc;
+}
+
+static int mt9p012_probe_init_done(const struct msm_camera_sensor_info *data)
+{
+	gpio_direction_output(data->sensor_reset, 0);
+	gpio_free(data->sensor_reset);
+	return 0;
+}
+
+static int mt9p012_probe_init_sensor(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc;
+	uint16_t chipid;
+
+	rc = gpio_request(data->sensor_reset, "mt9p012");
+	if (!rc)
+		gpio_direction_output(data->sensor_reset, 1);
+	else
+		goto init_probe_done;
+
+	msleep(20);
+
+	/* RESET the sensor image part via I2C command */
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 MT9P012_REG_RESET_REGISTER, 0x10CC | 0x0001);
+	if (rc < 0) {
+		CDBG("sensor reset failed. rc = %d\n", rc);
+		goto init_probe_fail;
+	}
+
+	msleep(MT9P012_RESET_DELAY_MSECS);
+
+	/* 3. Read sensor Model ID: */
+	rc = mt9p012_i2c_read_w(mt9p012_client->addr,
+				MT9P012_REG_MODEL_ID, &chipid);
+	if (rc < 0)
+		goto init_probe_fail;
+
+	/* 4. Compare sensor ID to MT9T012VC ID: */
+	if (chipid != MT9P012_MODEL_ID) {
+		rc = -ENODEV;
+		goto init_probe_fail;
+	}
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x306E, 0x9000);
+	if (rc < 0) {
+		CDBG("REV_7 write failed. rc = %d\n", rc);
+		goto init_probe_fail;
+	}
+
+	/* RESET_REGISTER, enable parallel interface and disable serialiser */
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x301A, 0x10CC);
+	if (rc < 0) {
+		CDBG("enable parallel interface failed. rc = %d\n", rc);
+		goto init_probe_fail;
+	}
+
+	/* To disable the 2 extra lines */
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x3064, 0x0805);
+
+	if (rc < 0) {
+		CDBG("disable the 2 extra lines failed. rc = %d\n", rc);
+		goto init_probe_fail;
+	}
+
+	goto init_probe_done;
+
+init_probe_fail:
+	mt9p012_probe_init_done(data);
+init_probe_done:
+	return rc;
+}
+
+static int mt9p012_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc;
+	unsigned short temp_pos;
+	uint8_t i;
+	uint16_t temp;
+
+	mt9p012_ctrl = kzalloc(sizeof(struct mt9p012_ctrl), GFP_KERNEL);
+	if (!mt9p012_ctrl) {
+		CDBG("mt9p012_init failed!\n");
+		rc = -ENOMEM;
+		goto init_done;
+	}
+
+	mt9p012_ctrl->fps_divider = 1 * 0x00000400;
+	mt9p012_ctrl->pict_fps_divider = 1 * 0x00000400;
+	mt9p012_ctrl->set_test = TEST_OFF;
+	mt9p012_ctrl->prev_res = QTR_SIZE;
+	mt9p012_ctrl->pict_res = FULL_SIZE;
+
+	if (data)
+		mt9p012_ctrl->sensordata = data;
+
+	msm_camio_camif_pad_reg_reset();
+	mdelay(20);
+
+	rc = mt9p012_probe_init_sensor(data);
+	if (rc < 0)
+		goto init_fail1;
+
+	if (mt9p012_ctrl->prev_res == QTR_SIZE)
+		rc = mt9p012_setting(REG_INIT, RES_PREVIEW);
+	else
+		rc = mt9p012_setting(REG_INIT, RES_CAPTURE);
+
+	if (rc < 0) {
+		CDBG("mt9p012_setting failed. rc = %d\n", rc);
+		goto init_fail1;
+	}
+
+	/* sensor : output enable */
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 MT9P012_REG_RESET_REGISTER,
+				 MT9P012_RESET_REGISTER_PWON);
+	if (rc < 0) {
+		CDBG("sensor output enable failed. rc = %d\n", rc);
+		goto init_fail1;
+	}
+
+	/* enable AF actuator */
+	rc = gpio_request(mt9p012_ctrl->sensordata->vcm_pwd, "mt9p012");
+	if (!rc)
+		gpio_direction_output(mt9p012_ctrl->sensordata->vcm_pwd, 1);
+	else {
+		CDBG("mt9p012_ctrl gpio request failed!\n");
+		goto init_fail1;
+	}
+
+	mdelay(20);
+
+	bam_infinite = 0;
+	bam_macro = 0;
+	/*initialize AF actuator */
+	mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x01, 0x09);
+	mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x07, 0x2E);
+	mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x0A, 0x01);
+	mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x17, 0x06);
+	mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x16, 0x0A);
+
+	mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x01, 0x29);
+	mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x05, 0x00);
+	mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x06, 0x00);
+	mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x0B, 0x64);
+	mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x07, 0x27);
+	mdelay(140);
+	mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x01, 0x29);
+	mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x05, 0x03);
+	mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x06, 0xFF);
+	mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x0B, 0x64);
+	mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1, 0x07, 0x27);
+	mdelay(140);
+
+	if (mt9p012_i2c_read_b(MT9P012_AF_I2C_ADDR >> 1, 0x12, &temp_pos)
+	    >= 0) {
+		bam_infinite = (uint16_t) temp_pos;
+		if (mt9p012_i2c_read_b
+		    (MT9P012_AF_I2C_ADDR >> 1, 0x13, &temp_pos) >= 0)
+			bam_infinite =
+			    (bam_infinite << 8) | ((uint16_t) temp_pos);
+	} else {
+		bam_infinite = 100;
+	}
+
+	if (mt9p012_i2c_read_b(MT9P012_AF_I2C_ADDR >> 1, 0x14, &temp_pos)
+	    >= 0) {
+		bam_macro = (uint16_t) temp_pos;
+		if (mt9p012_i2c_read_b
+		    (MT9P012_AF_I2C_ADDR >> 1, 0x15, &temp_pos) >= 0)
+			bam_macro = (bam_macro << 8) | ((uint16_t) temp_pos);
+	}
+	temp = (bam_infinite - bam_macro) / MT9P012_TOTAL_STEPS_NEAR_TO_FAR;
+	for (i = 0; i < MT9P012_TOTAL_STEPS_NEAR_TO_FAR; i++)
+		bam_step_lookup_table[i] = bam_macro + temp * i;
+
+	bam_step_lookup_table[MT9P012_TOTAL_STEPS_NEAR_TO_FAR] = bam_infinite;
+
+	rc = mt9p012_set_default_focus();
+	if (rc >= 0)
+		goto init_done;
+
+init_fail1:
+	mt9p012_probe_init_done(data);
+	kfree(mt9p012_ctrl);
+init_done:
+	return rc;
+}
+
+static int mt9p012_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&mt9p012_wait_queue);
+	return 0;
+}
+
+static int32_t mt9p012_set_sensor_mode(int mode, int res)
+{
+	int32_t rc = 0;
+
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		rc = mt9p012_video_config(mode, res);
+		break;
+
+	case SENSOR_SNAPSHOT_MODE:
+		rc = mt9p012_snapshot_config(mode);
+		break;
+
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		rc = mt9p012_raw_snapshot_config(mode);
+		break;
+
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+int mt9p012_sensor_config(void __user *argp)
+{
+	struct sensor_cfg_data cdata;
+	int rc = 0;
+
+	if (copy_from_user(&cdata,
+			   (void *)argp, sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+
+	mutex_lock(&mt9p012_mut);
+
+	CDBG("%s: cfgtype = %d\n", __func__, cdata.cfgtype);
+	switch (cdata.cfgtype) {
+	case CFG_GET_PICT_FPS:
+		mt9p012_get_pict_fps(cdata.cfg.gfps.prevfps,
+				     &(cdata.cfg.gfps.pictfps));
+
+		if (copy_to_user((void *)argp, &cdata,
+				 sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PREV_L_PF:
+		cdata.cfg.prevl_pf = mt9p012_get_prev_lines_pf();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PREV_P_PL:
+		cdata.cfg.prevp_pl = mt9p012_get_prev_pixels_pl();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_L_PF:
+		cdata.cfg.pictl_pf = mt9p012_get_pict_lines_pf();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_P_PL:
+		cdata.cfg.pictp_pl = mt9p012_get_pict_pixels_pl();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_MAX_EXP_LC:
+		cdata.cfg.pict_max_exp_lc = mt9p012_get_pict_max_exp_lc();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_SET_FPS:
+	case CFG_SET_PICT_FPS:
+		rc = mt9p012_set_fps(&(cdata.cfg.fps));
+		break;
+
+	case CFG_SET_EXP_GAIN:
+		rc = mt9p012_write_exp_gain(cdata.cfg.exp_gain.gain,
+					    cdata.cfg.exp_gain.line);
+		break;
+
+	case CFG_SET_PICT_EXP_GAIN:
+		CDBG("Line:%d CFG_SET_PICT_EXP_GAIN \n", __LINE__);
+		rc = mt9p012_set_pict_exp_gain(cdata.cfg.exp_gain.gain,
+					       cdata.cfg.exp_gain.line);
+		break;
+
+	case CFG_SET_MODE:
+		rc = mt9p012_set_sensor_mode(cdata.mode, cdata.rs);
+		break;
+
+	case CFG_PWR_DOWN:
+		rc = mt9p012_power_down();
+		break;
+
+	case CFG_MOVE_FOCUS:
+		CDBG("mt9p012_ioctl: CFG_MOVE_FOCUS: dir=%d steps=%d\n",
+		     cdata.cfg.focus.dir, cdata.cfg.focus.steps);
+		rc = mt9p012_move_focus(cdata.cfg.focus.dir,
+					cdata.cfg.focus.steps);
+		break;
+
+	case CFG_SET_DEFAULT_FOCUS:
+		rc = mt9p012_set_default_focus();
+
+		break;
+
+	case CFG_SET_EFFECT:
+		rc = mt9p012_set_default_focus();
+		break;
+
+	case CFG_SET_LENS_SHADING:
+		CDBG("%s: CFG_SET_LENS_SHADING\n", __func__);
+		rc = mt9p012_lens_shading_enable(cdata.cfg.lens_shading);
+		break;
+
+	case CFG_GET_AF_MAX_STEPS:
+		cdata.max_steps = MT9P012_STEPS_NEAR_TO_CLOSEST_INF;
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	mutex_unlock(&mt9p012_mut);
+	return rc;
+}
+
+int mt9p012_sensor_release(void)
+{
+	int rc = -EBADF;
+
+	mutex_lock(&mt9p012_mut);
+
+	mt9p012_power_down();
+
+	gpio_direction_output(mt9p012_ctrl->sensordata->sensor_reset, 0);
+	gpio_free(mt9p012_ctrl->sensordata->sensor_reset);
+
+	gpio_direction_output(mt9p012_ctrl->sensordata->vcm_pwd, 0);
+	gpio_free(mt9p012_ctrl->sensordata->vcm_pwd);
+
+	kfree(mt9p012_ctrl);
+	mt9p012_ctrl = NULL;
+
+	CDBG("mt9p012_release completed\n");
+
+	mutex_unlock(&mt9p012_mut);
+	return rc;
+}
+
+static int mt9p012_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	int rc = 0;
+	CDBG("mt9p012_probe called!\n");
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		CDBG("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	mt9p012_sensorw = kzalloc(sizeof(struct mt9p012_work), GFP_KERNEL);
+	if (!mt9p012_sensorw) {
+		CDBG("kzalloc failed.\n");
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, mt9p012_sensorw);
+	mt9p012_init_client(client);
+	mt9p012_client = client;
+
+	mdelay(50);
+
+	CDBG("mt9p012_probe successed! rc = %d\n", rc);
+	return 0;
+
+probe_failure:
+	CDBG("mt9p012_probe failed! rc = %d\n", rc);
+	return rc;
+}
+
+static int __exit mt9p012_remove(struct i2c_client *client)
+{
+	struct mt9p012_work_t *sensorw = i2c_get_clientdata(client);
+	free_irq(client->irq, sensorw);
+	mt9p012_client = NULL;
+	kfree(sensorw);
+	return 0;
+}
+
+static const struct i2c_device_id mt9p012_i2c_id[] = {
+	{"mt9p012", 0}
+};
+
+static struct i2c_driver mt9p012_i2c_driver = {
+	.id_table = mt9p012_i2c_id,
+	.probe = mt9p012_i2c_probe,
+	.remove = __exit_p(mt9p012_i2c_remove),
+	.driver = {
+		.name = "mt9p012",
+	},
+};
+
+static int mt9p012_sensor_probe(const struct msm_camera_sensor_info *info,
+				struct msm_sensor_ctrl *s)
+{
+	int rc = i2c_add_driver(&mt9p012_i2c_driver);
+	if (rc < 0 || mt9p012_client == NULL) {
+		rc = -ENOTSUPP;
+		goto probe_done;
+	}
+
+	msm_camio_clk_rate_set(MT9P012_DEFAULT_CLOCK_RATE);
+	mdelay(20);
+
+	rc = mt9p012_probe_init_sensor(info);
+	if (rc < 0)
+		goto probe_done;
+
+	s->s_init = mt9p012_sensor_open_init;
+	s->s_release = mt9p012_sensor_release;
+	s->s_config = mt9p012_sensor_config;
+	s->s_mount_angle  = 0;
+	mt9p012_probe_init_done(info);
+
+probe_done:
+	CDBG("%s %s:%d\n", __FILE__, __func__, __LINE__);
+	return rc;
+}
+
+static int __mt9p012_probe(struct platform_device *pdev)
+{
+	return msm_camera_drv_start(pdev, mt9p012_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = __mt9p012_probe,
+	.driver = {
+		.name = "msm_camera_mt9p012",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init mt9p012_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(mt9p012_init);
+void mt9p012_exit(void)
+{
+	i2c_del_driver(&mt9p012_i2c_driver);
+}
diff --git a/drivers/media/video/msm/mt9p012_fox.c b/drivers/media/video/msm/mt9p012_fox.c
new file mode 100644
index 0000000..4a732f3
--- /dev/null
+++ b/drivers/media/video/msm/mt9p012_fox.c
@@ -0,0 +1,1345 @@
+/* Copyright (c) 2009, 2011 Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <media/msm_camera.h>
+#include <mach/gpio.h>
+#include <mach/camera.h>
+#include "mt9p012.h"
+
+/*=============================================================
+    SENSOR REGISTER DEFINES
+==============================================================*/
+#define MT9P012_REG_MODEL_ID         0x0000
+#define MT9P012_MODEL_ID             0x2801
+#define REG_GROUPED_PARAMETER_HOLD   0x0104
+#define GROUPED_PARAMETER_HOLD       0x0100
+#define GROUPED_PARAMETER_UPDATE     0x0000
+#define REG_COARSE_INT_TIME          0x3012
+#define REG_VT_PIX_CLK_DIV           0x0300
+#define REG_VT_SYS_CLK_DIV           0x0302
+#define REG_PRE_PLL_CLK_DIV          0x0304
+#define REG_PLL_MULTIPLIER           0x0306
+#define REG_OP_PIX_CLK_DIV           0x0308
+#define REG_OP_SYS_CLK_DIV           0x030A
+#define REG_SCALE_M                  0x0404
+#define REG_FRAME_LENGTH_LINES       0x300A
+#define REG_LINE_LENGTH_PCK          0x300C
+#define REG_X_ADDR_START             0x3004
+#define REG_Y_ADDR_START             0x3002
+#define REG_X_ADDR_END               0x3008
+#define REG_Y_ADDR_END               0x3006
+#define REG_X_OUTPUT_SIZE            0x034C
+#define REG_Y_OUTPUT_SIZE            0x034E
+#define REG_FINE_INTEGRATION_TIME    0x3014
+#define REG_ROW_SPEED                0x3016
+#define MT9P012_REG_RESET_REGISTER   0x301A
+#define MT9P012_RESET_REGISTER_PWON  0x10CC
+#define MT9P012_RESET_REGISTER_PWOFF 0x10C8
+#define REG_READ_MODE                0x3040
+#define REG_GLOBAL_GAIN              0x305E
+#define REG_TEST_PATTERN_MODE        0x3070
+
+#define MT9P012_REV_7
+
+enum mt9p012_test_mode {
+	TEST_OFF,
+	TEST_1,
+	TEST_2,
+	TEST_3
+};
+
+enum mt9p012_resolution {
+	QTR_SIZE,
+	FULL_SIZE,
+	INVALID_SIZE
+};
+
+enum mt9p012_reg_update {
+	/* Sensor egisters that need to be updated during initialization */
+	REG_INIT,
+	/* Sensor egisters that needs periodic I2C writes */
+	UPDATE_PERIODIC,
+	/* All the sensor Registers will be updated */
+	UPDATE_ALL,
+	/* Not valid update */
+	UPDATE_INVALID
+};
+
+enum mt9p012_setting {
+	RES_PREVIEW,
+	RES_CAPTURE
+};
+
+/* actuator's Slave Address */
+#define MT9P012_AF_I2C_ADDR   0x18
+
+/* AF Total steps parameters */
+#define MT9P012_STEPS_NEAR_TO_CLOSEST_INF  32
+#define MT9P012_TOTAL_STEPS_NEAR_TO_FAR    32
+
+#define MT9P012_MU5M0_PREVIEW_DUMMY_PIXELS 0
+#define MT9P012_MU5M0_PREVIEW_DUMMY_LINES  0
+
+/* Time in milisecs for waiting for the sensor to reset.*/
+#define MT9P012_RESET_DELAY_MSECS   66
+
+/* for 20 fps preview */
+#define MT9P012_DEFAULT_CLOCK_RATE  24000000
+#define MT9P012_DEFAULT_MAX_FPS     26	/* ???? */
+
+struct mt9p012_work {
+	struct work_struct work;
+};
+static struct mt9p012_work *mt9p012_sensorw;
+static struct i2c_client *mt9p012_client;
+
+struct mt9p012_ctrl {
+	const struct msm_camera_sensor_info *sensordata;
+
+	int sensormode;
+	uint32_t fps_divider;	/* init to 1 * 0x00000400 */
+	uint32_t pict_fps_divider;	/* init to 1 * 0x00000400 */
+
+	uint16_t curr_lens_pos;
+	uint16_t init_curr_lens_pos;
+	uint16_t my_reg_gain;
+	uint32_t my_reg_line_count;
+
+	enum mt9p012_resolution prev_res;
+	enum mt9p012_resolution pict_res;
+	enum mt9p012_resolution curr_res;
+	enum mt9p012_test_mode set_test;
+};
+static uint16_t update_type = UPDATE_PERIODIC;
+static struct mt9p012_ctrl *mt9p012_ctrl;
+static DECLARE_WAIT_QUEUE_HEAD(mt9p012_wait_queue);
+DEFINE_MUTEX(mt9p012_mut);
+
+
+/*=============================================================*/
+
+static int mt9p012_i2c_rxdata(unsigned short saddr, unsigned char *rxdata,
+			      int length)
+{
+	int retry_cnt = 0;
+	int rc;
+
+	struct i2c_msg msgs[] = {
+		{
+		 .addr = saddr,
+		 .flags = 0,
+		 .len = 2,
+		 .buf = rxdata,
+		 },
+		{
+		 .addr = saddr,
+		 .flags = I2C_M_RD,
+		 .len = length,
+		 .buf = rxdata,
+		 },
+	};
+
+	do {
+		rc = i2c_transfer(mt9p012_client->adapter, msgs, 2);
+		if (rc > 0)
+			break;
+		retry_cnt++;
+	} while (retry_cnt < 3);
+
+	if (rc < 0) {
+		pr_err("mt9p012_i2c_rxdata failed!:%d %d\n", rc, retry_cnt);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t mt9p012_i2c_read_w(unsigned short saddr, unsigned short raddr,
+				  unsigned short *rdata)
+{
+	int32_t rc = 0;
+	unsigned char buf[4];
+
+	if (!rdata)
+		return -EIO;
+
+	memset(buf, 0, sizeof(buf));
+
+	buf[0] = (raddr & 0xFF00) >> 8;
+	buf[1] = (raddr & 0x00FF);
+
+	rc = mt9p012_i2c_rxdata(saddr, buf, 2);
+	if (rc < 0)
+		return rc;
+
+	*rdata = buf[0] << 8 | buf[1];
+
+	if (rc < 0)
+		CDBG("mt9p012_i2c_read failed!\n");
+
+	return rc;
+}
+
+static int32_t mt9p012_i2c_txdata(unsigned short saddr, unsigned char *txdata,
+				  int length)
+{
+	int retry_cnt = 0;
+	int rc;
+
+	struct i2c_msg msg[] = {
+		{
+		 .addr = saddr,
+		 .flags = 0,
+		 .len = length,
+		 .buf = txdata,
+		 },
+	};
+
+	do {
+		rc = i2c_transfer(mt9p012_client->adapter, msg, 1);
+		if (rc > 0)
+			break;
+		retry_cnt++;
+	} while (retry_cnt < 3);
+
+	if (rc < 0) {
+		pr_err("mt9p012_i2c_txdata failed: %d %d\n", rc, retry_cnt);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t mt9p012_i2c_write_b(unsigned short saddr, unsigned short baddr,
+				   unsigned short bdata)
+{
+	int32_t rc = -EIO;
+	unsigned char buf[2];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = baddr;
+	buf[1] = bdata;
+	rc = mt9p012_i2c_txdata(saddr, buf, 2);
+
+	if (rc < 0)
+		CDBG("i2c_write failed, saddr = 0x%x addr = 0x%x, val =0x%x!\n",
+		     saddr, baddr, bdata);
+
+	return rc;
+}
+
+static int32_t mt9p012_i2c_write_w(unsigned short saddr, unsigned short waddr,
+				   unsigned short wdata)
+{
+	int32_t rc = -EIO;
+	unsigned char buf[4];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = (wdata & 0xFF00) >> 8;
+	buf[3] = (wdata & 0x00FF);
+
+	rc = mt9p012_i2c_txdata(saddr, buf, 4);
+
+	if (rc < 0)
+		CDBG("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n",
+		     waddr, wdata);
+
+	return rc;
+}
+
+static int32_t mt9p012_i2c_write_w_table(struct mt9p012_i2c_reg_conf const
+					 *reg_conf_tbl, int num)
+{
+	int i;
+	int32_t rc = -EIO;
+
+	for (i = 0; i < num; i++) {
+		rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+					 reg_conf_tbl->waddr,
+					 reg_conf_tbl->wdata);
+		if (rc < 0)
+			break;
+		reg_conf_tbl++;
+	}
+
+	return rc;
+}
+
+static int32_t mt9p012_test(enum mt9p012_test_mode mo)
+{
+	int32_t rc = 0;
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD);
+	if (rc < 0)
+		return rc;
+
+	if (mo == TEST_OFF)
+		return 0;
+	else {
+		rc = mt9p012_i2c_write_w_table(mt9p012_regs.ttbl,
+					       mt9p012_regs.ttbl_size);
+		if (rc < 0)
+			return rc;
+
+		rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+					 REG_TEST_PATTERN_MODE, (uint16_t) mo);
+		if (rc < 0)
+			return rc;
+	}
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE);
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+
+static int32_t mt9p012_lens_shading_enable(uint8_t is_enable)
+{
+	int32_t rc = 0;
+
+	CDBG("%s: entered. enable = %d\n", __func__, is_enable);
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x3780,
+				 ((uint16_t) is_enable) << 15);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE);
+
+	CDBG("%s: exiting. rc = %d\n", __func__, rc);
+	return rc;
+}
+
+static int32_t mt9p012_set_lc(void)
+{
+	int32_t rc;
+
+	rc = mt9p012_i2c_write_w_table(mt9p012_regs.rftbl,
+				       mt9p012_regs.rftbl_size);
+
+	return rc;
+}
+
+static void mt9p012_get_pict_fps(uint16_t fps, uint16_t *pfps)
+{
+	/* input fps is preview fps in Q8 format */
+	uint32_t divider;	/*Q10 */
+	uint32_t pclk_mult;	/*Q10 */
+	uint32_t d1;
+	uint32_t d2;
+
+	d1 =
+		(uint32_t)(
+		(mt9p012_regs.reg_pat[RES_PREVIEW].frame_length_lines *
+		0x00000400) /
+		mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines);
+
+	d2 =
+		(uint32_t)(
+		(mt9p012_regs.reg_pat[RES_PREVIEW].line_length_pck *
+		0x00000400) /
+		mt9p012_regs.reg_pat[RES_CAPTURE].line_length_pck);
+
+	divider = (uint32_t) (d1 * d2) / 0x00000400;
+
+	pclk_mult =
+		(uint32_t) ((mt9p012_regs.reg_pat[RES_CAPTURE].pll_multiplier *
+		0x00000400) /
+		(mt9p012_regs.reg_pat[RES_PREVIEW].pll_multiplier));
+
+	/* Verify PCLK settings and frame sizes. */
+	*pfps = (uint16_t) (fps * divider * pclk_mult / 0x00000400 /
+			    0x00000400);
+}
+
+static uint16_t mt9p012_get_prev_lines_pf(void)
+{
+	if (mt9p012_ctrl->prev_res == QTR_SIZE)
+		return mt9p012_regs.reg_pat[RES_PREVIEW].frame_length_lines;
+	else
+		return mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines;
+}
+
+static uint16_t mt9p012_get_prev_pixels_pl(void)
+{
+	if (mt9p012_ctrl->prev_res == QTR_SIZE)
+		return mt9p012_regs.reg_pat[RES_PREVIEW].line_length_pck;
+	else
+		return mt9p012_regs.reg_pat[RES_CAPTURE].line_length_pck;
+}
+
+static uint16_t mt9p012_get_pict_lines_pf(void)
+{
+	return mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines;
+}
+
+static uint16_t mt9p012_get_pict_pixels_pl(void)
+{
+	return mt9p012_regs.reg_pat[RES_CAPTURE].line_length_pck;
+}
+
+static uint32_t mt9p012_get_pict_max_exp_lc(void)
+{
+	uint16_t snapshot_lines_per_frame;
+
+	if (mt9p012_ctrl->pict_res == QTR_SIZE)
+		snapshot_lines_per_frame =
+		    mt9p012_regs.reg_pat[RES_PREVIEW].frame_length_lines - 1;
+	else
+		snapshot_lines_per_frame =
+		    mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines - 1;
+
+	return snapshot_lines_per_frame * 24;
+}
+
+static int32_t mt9p012_set_fps(struct fps_cfg *fps)
+{
+	/* input is new fps in Q10 format */
+	int32_t rc = 0;
+	enum mt9p012_setting setting;
+
+	mt9p012_ctrl->fps_divider = fps->fps_div;
+	mt9p012_ctrl->pict_fps_divider = fps->pict_fps_div;
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD);
+	if (rc < 0)
+		return -EBUSY;
+
+	if (mt9p012_ctrl->sensormode == SENSOR_PREVIEW_MODE)
+		setting = RES_PREVIEW;
+	else
+		setting = RES_CAPTURE;
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+		REG_FRAME_LENGTH_LINES,
+		(mt9p012_regs.reg_pat[setting].frame_length_lines *
+		fps->fps_div / 0x00000400));
+	if (rc < 0)
+		return rc;
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE);
+
+	return rc;
+}
+
+static int32_t mt9p012_write_exp_gain(uint16_t gain, uint32_t line)
+{
+	uint16_t max_legal_gain = 0x01FF;
+	uint32_t line_length_ratio = 0x00000400;
+	enum mt9p012_setting setting;
+	int32_t rc = 0;
+
+	CDBG("Line:%d mt9p012_write_exp_gain \n", __LINE__);
+
+	if (mt9p012_ctrl->sensormode == SENSOR_PREVIEW_MODE) {
+		mt9p012_ctrl->my_reg_gain = gain;
+		mt9p012_ctrl->my_reg_line_count = (uint16_t) line;
+	}
+
+	if (gain > max_legal_gain) {
+		CDBG("Max legal gain Line:%d \n", __LINE__);
+		gain = max_legal_gain;
+	}
+
+	/* Verify no overflow */
+	if (mt9p012_ctrl->sensormode == SENSOR_PREVIEW_MODE) {
+		line = (uint32_t) (line * mt9p012_ctrl->fps_divider /
+				   0x00000400);
+		setting = RES_PREVIEW;
+	} else {
+		line = (uint32_t) (line * mt9p012_ctrl->pict_fps_divider /
+				   0x00000400);
+		setting = RES_CAPTURE;
+	}
+
+	/* Set digital gain to 1 */
+#ifdef MT9P012_REV_7
+	gain |= 0x1000;
+#else
+	gain |= 0x0200;
+#endif
+
+	if ((mt9p012_regs.reg_pat[setting].frame_length_lines - 1) < line) {
+		line_length_ratio = (uint32_t) (line * 0x00000400) /
+		    (mt9p012_regs.reg_pat[setting].frame_length_lines - 1);
+	} else
+		line_length_ratio = 0x00000400;
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr, REG_GLOBAL_GAIN, gain);
+	if (rc < 0) {
+		CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__);
+		return rc;
+	}
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 REG_COARSE_INT_TIME, line);
+	if (rc < 0) {
+		CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__);
+		return rc;
+	}
+
+	CDBG("mt9p012_write_exp_gain: gain = %d, line = %d\n", gain, line);
+
+	return rc;
+}
+
+static int32_t mt9p012_set_pict_exp_gain(uint16_t gain, uint32_t line)
+{
+	int32_t rc = 0;
+
+	CDBG("Line:%d mt9p012_set_pict_exp_gain \n", __LINE__);
+
+	rc = mt9p012_write_exp_gain(gain, line);
+	if (rc < 0) {
+		CDBG("Line:%d mt9p012_set_pict_exp_gain failed... \n",
+		     __LINE__);
+		return rc;
+	}
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 MT9P012_REG_RESET_REGISTER, 0x10CC | 0x0002);
+	if (rc < 0) {
+		CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__);
+		return rc;
+	}
+
+	mdelay(5);
+
+	/* camera_timed_wait(snapshot_wait*exposure_ratio); */
+	return rc;
+}
+
+static int32_t mt9p012_setting(enum mt9p012_reg_update rupdate,
+			       enum mt9p012_setting rt)
+{
+	int32_t rc = 0;
+	switch (rupdate) {
+	case UPDATE_PERIODIC:
+		if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+			struct mt9p012_i2c_reg_conf ppc_tbl[] = {
+				{REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD},
+				{REG_ROW_SPEED,
+				 mt9p012_regs.reg_pat[rt].row_speed},
+				{REG_X_ADDR_START,
+				 mt9p012_regs.reg_pat[rt].x_addr_start},
+				{REG_X_ADDR_END,
+				 mt9p012_regs.reg_pat[rt].x_addr_end},
+				{REG_Y_ADDR_START,
+				 mt9p012_regs.reg_pat[rt].y_addr_start},
+				{REG_Y_ADDR_END,
+				 mt9p012_regs.reg_pat[rt].y_addr_end},
+				{REG_READ_MODE,
+				 mt9p012_regs.reg_pat[rt].read_mode},
+				{REG_SCALE_M, mt9p012_regs.reg_pat[rt].scale_m},
+				{REG_X_OUTPUT_SIZE,
+				 mt9p012_regs.reg_pat[rt].x_output_size},
+				{REG_Y_OUTPUT_SIZE,
+				 mt9p012_regs.reg_pat[rt].y_output_size},
+
+				{REG_LINE_LENGTH_PCK,
+				 mt9p012_regs.reg_pat[rt].line_length_pck},
+				{REG_FRAME_LENGTH_LINES,
+				 (mt9p012_regs.reg_pat[rt].frame_length_lines *
+				  mt9p012_ctrl->fps_divider / 0x00000400)},
+				{REG_COARSE_INT_TIME,
+				 mt9p012_regs.reg_pat[rt].coarse_int_time},
+				{REG_FINE_INTEGRATION_TIME,
+				 mt9p012_regs.reg_pat[rt].fine_int_time},
+				{REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE},
+			};
+			if (update_type == REG_INIT) {
+				update_type = rupdate;
+				return rc;
+			}
+			rc = mt9p012_i2c_write_w_table(&ppc_tbl[0],
+						ARRAY_SIZE(ppc_tbl));
+			if (rc < 0)
+				return rc;
+
+			rc = mt9p012_test(mt9p012_ctrl->set_test);
+			if (rc < 0)
+				return rc;
+
+			rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+						 MT9P012_REG_RESET_REGISTER,
+						 MT9P012_RESET_REGISTER_PWON |
+						 0x0002);
+			if (rc < 0)
+				return rc;
+
+			mdelay(5);	/* 15? wait for sensor to transition */
+
+			return rc;
+		}
+		break;		/* UPDATE_PERIODIC */
+
+	case REG_INIT:
+		if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+			struct mt9p012_i2c_reg_conf ipc_tbl1[] = {
+				{MT9P012_REG_RESET_REGISTER,
+				 MT9P012_RESET_REGISTER_PWOFF},
+				{REG_VT_PIX_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].vt_pix_clk_div},
+				{REG_VT_SYS_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].vt_sys_clk_div},
+				{REG_PRE_PLL_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].pre_pll_clk_div},
+				{REG_PLL_MULTIPLIER,
+				 mt9p012_regs.reg_pat[rt].pll_multiplier},
+				{REG_OP_PIX_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].op_pix_clk_div},
+				{REG_OP_SYS_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].op_sys_clk_div},
+#ifdef MT9P012_REV_7
+				{0x30B0, 0x0001},
+				{0x308E, 0xE060},
+				{0x3092, 0x0A52},
+				{0x3094, 0x4656},
+				{0x3096, 0x5652},
+				{0x30CA, 0x8006},
+				{0x312A, 0xDD02},
+				{0x312C, 0x00E4},
+				{0x3170, 0x299A},
+#endif
+				/* optimized settings for noise */
+				{0x3088, 0x6FF6},
+				{0x3154, 0x0282},
+				{0x3156, 0x0381},
+				{0x3162, 0x04CE},
+				{0x0204, 0x0010},
+				{0x0206, 0x0010},
+				{0x0208, 0x0010},
+				{0x020A, 0x0010},
+				{0x020C, 0x0010},
+				{MT9P012_REG_RESET_REGISTER,
+				 MT9P012_RESET_REGISTER_PWON},
+			};
+
+			struct mt9p012_i2c_reg_conf ipc_tbl2[] = {
+				{MT9P012_REG_RESET_REGISTER,
+				 MT9P012_RESET_REGISTER_PWOFF},
+				{REG_VT_PIX_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].vt_pix_clk_div},
+				{REG_VT_SYS_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].vt_sys_clk_div},
+				{REG_PRE_PLL_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].pre_pll_clk_div},
+				{REG_PLL_MULTIPLIER,
+				 mt9p012_regs.reg_pat[rt].pll_multiplier},
+				{REG_OP_PIX_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].op_pix_clk_div},
+				{REG_OP_SYS_CLK_DIV,
+				 mt9p012_regs.reg_pat[rt].op_sys_clk_div},
+#ifdef MT9P012_REV_7
+				{0x30B0, 0x0001},
+				{0x308E, 0xE060},
+				{0x3092, 0x0A52},
+				{0x3094, 0x4656},
+				{0x3096, 0x5652},
+				{0x30CA, 0x8006},
+				{0x312A, 0xDD02},
+				{0x312C, 0x00E4},
+				{0x3170, 0x299A},
+#endif
+				/* optimized settings for noise */
+				{0x3088, 0x6FF6},
+				{0x3154, 0x0282},
+				{0x3156, 0x0381},
+				{0x3162, 0x04CE},
+				{0x0204, 0x0010},
+				{0x0206, 0x0010},
+				{0x0208, 0x0010},
+				{0x020A, 0x0010},
+				{0x020C, 0x0010},
+				{MT9P012_REG_RESET_REGISTER,
+				 MT9P012_RESET_REGISTER_PWON},
+			};
+
+			struct mt9p012_i2c_reg_conf ipc_tbl3[] = {
+				{REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD},
+				/* Set preview or snapshot mode */
+				{REG_ROW_SPEED,
+				 mt9p012_regs.reg_pat[rt].row_speed},
+				{REG_X_ADDR_START,
+				 mt9p012_regs.reg_pat[rt].x_addr_start},
+				{REG_X_ADDR_END,
+				 mt9p012_regs.reg_pat[rt].x_addr_end},
+				{REG_Y_ADDR_START,
+				 mt9p012_regs.reg_pat[rt].y_addr_start},
+				{REG_Y_ADDR_END,
+				 mt9p012_regs.reg_pat[rt].y_addr_end},
+				{REG_READ_MODE,
+				 mt9p012_regs.reg_pat[rt].read_mode},
+				{REG_SCALE_M, mt9p012_regs.reg_pat[rt].scale_m},
+				{REG_X_OUTPUT_SIZE,
+				 mt9p012_regs.reg_pat[rt].x_output_size},
+				{REG_Y_OUTPUT_SIZE,
+				 mt9p012_regs.reg_pat[rt].y_output_size},
+				{REG_LINE_LENGTH_PCK,
+				 mt9p012_regs.reg_pat[rt].line_length_pck},
+				{REG_FRAME_LENGTH_LINES,
+				 mt9p012_regs.reg_pat[rt].frame_length_lines},
+				{REG_COARSE_INT_TIME,
+				 mt9p012_regs.reg_pat[rt].coarse_int_time},
+				{REG_FINE_INTEGRATION_TIME,
+				 mt9p012_regs.reg_pat[rt].fine_int_time},
+				{REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE},
+			};
+
+			/* reset fps_divider */
+			mt9p012_ctrl->fps_divider = 1 * 0x0400;
+
+			rc = mt9p012_i2c_write_w_table(&ipc_tbl1[0],
+						       ARRAY_SIZE(ipc_tbl1));
+			if (rc < 0)
+				return rc;
+
+			rc = mt9p012_i2c_write_w_table(&ipc_tbl2[0],
+						       ARRAY_SIZE(ipc_tbl2));
+			if (rc < 0)
+				return rc;
+
+			mdelay(5);
+
+			rc = mt9p012_i2c_write_w_table(&ipc_tbl3[0],
+						       ARRAY_SIZE(ipc_tbl3));
+			if (rc < 0)
+				return rc;
+
+			/* load lens shading */
+			rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+						 REG_GROUPED_PARAMETER_HOLD,
+						 GROUPED_PARAMETER_HOLD);
+			if (rc < 0)
+				return rc;
+
+			rc = mt9p012_set_lc();
+			if (rc < 0)
+				return rc;
+
+			rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+						 REG_GROUPED_PARAMETER_HOLD,
+						 GROUPED_PARAMETER_UPDATE);
+
+			if (rc < 0)
+				return rc;
+		}
+		update_type = rupdate;
+		break;		/* case REG_INIT: */
+
+	default:
+		rc = -EINVAL;
+		break;
+	}			/* switch (rupdate) */
+
+	return rc;
+}
+
+static int32_t mt9p012_video_config(int mode, int res)
+{
+	int32_t rc;
+
+	switch (res) {
+	case QTR_SIZE:
+		rc = mt9p012_setting(UPDATE_PERIODIC, RES_PREVIEW);
+		if (rc < 0)
+			return rc;
+
+		CDBG("mt9p012 sensor configuration done!\n");
+		break;
+
+	case FULL_SIZE:
+		rc = mt9p012_setting(UPDATE_PERIODIC, RES_CAPTURE);
+		if (rc < 0)
+			return rc;
+
+		break;
+
+	default:
+		return 0;
+	}			/* switch */
+
+	mt9p012_ctrl->prev_res = res;
+	mt9p012_ctrl->curr_res = res;
+	mt9p012_ctrl->sensormode = mode;
+
+	rc = mt9p012_write_exp_gain(mt9p012_ctrl->my_reg_gain,
+				    mt9p012_ctrl->my_reg_line_count);
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 MT9P012_REG_RESET_REGISTER, 0x10cc | 0x0002);
+
+	return rc;
+}
+
+static int32_t mt9p012_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+
+	rc = mt9p012_setting(UPDATE_PERIODIC, RES_CAPTURE);
+	if (rc < 0)
+		return rc;
+
+	mt9p012_ctrl->curr_res = mt9p012_ctrl->pict_res;
+
+	mt9p012_ctrl->sensormode = mode;
+
+	return rc;
+}
+
+static int32_t mt9p012_raw_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+
+	rc = mt9p012_setting(UPDATE_PERIODIC, RES_CAPTURE);
+	if (rc < 0)
+		return rc;
+
+	mt9p012_ctrl->curr_res = mt9p012_ctrl->pict_res;
+
+	mt9p012_ctrl->sensormode = mode;
+
+	return rc;
+}
+
+static int32_t mt9p012_power_down(void)
+{
+	int32_t rc = 0;
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 MT9P012_REG_RESET_REGISTER,
+				 MT9P012_RESET_REGISTER_PWOFF);
+
+	mdelay(5);
+	return rc;
+}
+
+static int32_t mt9p012_move_focus(int direction, int32_t num_steps)
+{
+	int16_t step_direction;
+	int16_t actual_step;
+	int16_t next_position;
+	uint8_t code_val_msb, code_val_lsb;
+
+	if (num_steps > MT9P012_TOTAL_STEPS_NEAR_TO_FAR)
+		num_steps = MT9P012_TOTAL_STEPS_NEAR_TO_FAR;
+	else if (num_steps == 0) {
+		CDBG("mt9p012_move_focus failed at line %d ...\n", __LINE__);
+		return -EINVAL;
+	}
+
+	if (direction == MOVE_NEAR)
+		step_direction = 16;	/* 10bit */
+	else if (direction == MOVE_FAR)
+		step_direction = -16;	/* 10 bit */
+	else {
+		CDBG("mt9p012_move_focus failed at line %d ...\n", __LINE__);
+		return -EINVAL;
+	}
+
+	if (mt9p012_ctrl->curr_lens_pos < mt9p012_ctrl->init_curr_lens_pos)
+		mt9p012_ctrl->curr_lens_pos = mt9p012_ctrl->init_curr_lens_pos;
+
+	actual_step = (int16_t) (step_direction * (int16_t) num_steps);
+	next_position = (int16_t) (mt9p012_ctrl->curr_lens_pos + actual_step);
+
+	if (next_position > 1023)
+		next_position = 1023;
+	else if (next_position < 0)
+		next_position = 0;
+
+	code_val_msb = next_position >> 4;
+	code_val_lsb = (next_position & 0x000F) << 4;
+	/* code_val_lsb |= mode_mask; */
+
+	/* Writing the digital code for current to the actuator */
+	if (mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1,
+				code_val_msb, code_val_lsb) < 0) {
+		CDBG("mt9p012_move_focus failed at line %d ...\n", __LINE__);
+		return -EBUSY;
+	}
+
+	/* Storing the current lens Position */
+	mt9p012_ctrl->curr_lens_pos = next_position;
+
+	return 0;
+}
+
+static int32_t mt9p012_set_default_focus(void)
+{
+	int32_t rc = 0;
+	uint8_t code_val_msb, code_val_lsb;
+
+	code_val_msb = 0x00;
+	code_val_lsb = 0x00;
+
+	/* Write the digital code for current to the actuator */
+	rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1,
+				 code_val_msb, code_val_lsb);
+
+	mt9p012_ctrl->curr_lens_pos = 0;
+	mt9p012_ctrl->init_curr_lens_pos = 0;
+
+	return rc;
+}
+
+static int mt9p012_probe_init_done(const struct msm_camera_sensor_info *data)
+{
+	gpio_direction_output(data->sensor_reset, 0);
+	gpio_free(data->sensor_reset);
+	return 0;
+}
+
+static int mt9p012_probe_init_sensor(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc;
+	uint16_t chipid;
+
+	rc = gpio_request(data->sensor_reset, "mt9p012");
+	if (!rc)
+		gpio_direction_output(data->sensor_reset, 1);
+	else
+		goto init_probe_done;
+
+	msleep(20);
+
+	/* RESET the sensor image part via I2C command */
+	CDBG("mt9p012_sensor_init(): reseting sensor.\n");
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 MT9P012_REG_RESET_REGISTER, 0x10CC | 0x0001);
+	if (rc < 0) {
+		CDBG("sensor reset failed. rc = %d\n", rc);
+		goto init_probe_fail;
+	}
+
+	msleep(MT9P012_RESET_DELAY_MSECS);
+
+	/* 3. Read sensor Model ID: */
+	rc = mt9p012_i2c_read_w(mt9p012_client->addr,
+				MT9P012_REG_MODEL_ID, &chipid);
+	if (rc < 0)
+		goto init_probe_fail;
+
+	/* 4. Compare sensor ID to MT9T012VC ID: */
+	if (chipid != MT9P012_MODEL_ID) {
+		CDBG("mt9p012 wrong model_id = 0x%x\n", chipid);
+		rc = -ENODEV;
+		goto init_probe_fail;
+	}
+
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x306E, 0x9000);
+	if (rc < 0) {
+		CDBG("REV_7 write failed. rc = %d\n", rc);
+		goto init_probe_fail;
+	}
+
+	/* RESET_REGISTER, enable parallel interface and disable serialiser */
+	CDBG("mt9p012_sensor_init(): enabling parallel interface.\n");
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x301A, 0x10CC);
+	if (rc < 0) {
+		CDBG("enable parallel interface failed. rc = %d\n", rc);
+		goto init_probe_fail;
+	}
+
+	/* To disable the 2 extra lines */
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x3064, 0x0805);
+
+	if (rc < 0) {
+		CDBG("disable the 2 extra lines failed. rc = %d\n", rc);
+		goto init_probe_fail;
+	}
+	goto init_probe_done;
+
+init_probe_fail:
+	mt9p012_probe_init_done(data);
+init_probe_done:
+	return rc;
+}
+
+static int mt9p012_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc;
+
+	mt9p012_ctrl = kzalloc(sizeof(struct mt9p012_ctrl), GFP_KERNEL);
+	if (!mt9p012_ctrl) {
+		CDBG("mt9p012_init failed!\n");
+		rc = -ENOMEM;
+		goto init_done;
+	}
+
+	mt9p012_ctrl->fps_divider = 1 * 0x00000400;
+	mt9p012_ctrl->pict_fps_divider = 1 * 0x00000400;
+	mt9p012_ctrl->set_test = TEST_OFF;
+	mt9p012_ctrl->prev_res = QTR_SIZE;
+	mt9p012_ctrl->pict_res = FULL_SIZE;
+
+	if (data)
+		mt9p012_ctrl->sensordata = data;
+
+	msm_camio_camif_pad_reg_reset();
+	mdelay(20);
+
+	rc = mt9p012_probe_init_sensor(data);
+	if (rc < 0)
+		goto init_fail1;
+
+	if (mt9p012_ctrl->prev_res == QTR_SIZE)
+		rc = mt9p012_setting(REG_INIT, RES_PREVIEW);
+	else
+		rc = mt9p012_setting(REG_INIT, RES_CAPTURE);
+
+	if (rc < 0) {
+		CDBG("mt9p012_setting failed. rc = %d\n", rc);
+		goto init_fail1;
+	}
+
+	/* sensor : output enable */
+	CDBG("mt9p012_sensor_open_init(): enabling output.\n");
+	rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+				 MT9P012_REG_RESET_REGISTER,
+				 MT9P012_RESET_REGISTER_PWON);
+	if (rc < 0) {
+		CDBG("sensor output enable failed. rc = %d\n", rc);
+		goto init_fail1;
+	}
+
+	/* enable AF actuator */
+	if (mt9p012_ctrl->sensordata->vcm_enable) {
+		CDBG("enable AF actuator, gpio = %d\n",
+			 mt9p012_ctrl->sensordata->vcm_pwd);
+		rc = gpio_request(mt9p012_ctrl->sensordata->vcm_pwd,
+						"mt9p012");
+		if (!rc)
+			gpio_direction_output(
+				mt9p012_ctrl->sensordata->vcm_pwd,
+				 1);
+		else {
+			CDBG("mt9p012_ctrl gpio request failed!\n");
+			goto init_fail1;
+		}
+		msleep(20);
+		rc = mt9p012_set_default_focus();
+		if (rc < 0) {
+			gpio_direction_output(mt9p012_ctrl->sensordata->vcm_pwd,
+								0);
+			gpio_free(mt9p012_ctrl->sensordata->vcm_pwd);
+		}
+	}
+	if (rc >= 0)
+		goto init_done;
+init_fail1:
+	mt9p012_probe_init_done(data);
+	kfree(mt9p012_ctrl);
+init_done:
+	return rc;
+}
+
+static int mt9p012_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&mt9p012_wait_queue);
+	return 0;
+}
+
+static int32_t mt9p012_set_sensor_mode(int mode, int res)
+{
+	int32_t rc = 0;
+
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		rc = mt9p012_video_config(mode, res);
+		break;
+
+	case SENSOR_SNAPSHOT_MODE:
+		rc = mt9p012_snapshot_config(mode);
+		break;
+
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		rc = mt9p012_raw_snapshot_config(mode);
+		break;
+
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+int mt9p012_sensor_config(void __user *argp)
+{
+	struct sensor_cfg_data cdata;
+	int rc = 0;
+
+	if (copy_from_user(&cdata,
+			   (void *)argp, sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+
+	mutex_lock(&mt9p012_mut);
+
+	CDBG("%s: cfgtype = %d\n", __func__, cdata.cfgtype);
+	switch (cdata.cfgtype) {
+	case CFG_GET_PICT_FPS:
+		mt9p012_get_pict_fps(cdata.cfg.gfps.prevfps,
+				     &(cdata.cfg.gfps.pictfps));
+
+		if (copy_to_user((void *)argp, &cdata,
+				 sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PREV_L_PF:
+		cdata.cfg.prevl_pf = mt9p012_get_prev_lines_pf();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PREV_P_PL:
+		cdata.cfg.prevp_pl = mt9p012_get_prev_pixels_pl();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_L_PF:
+		cdata.cfg.pictl_pf = mt9p012_get_pict_lines_pf();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_P_PL:
+		cdata.cfg.pictp_pl = mt9p012_get_pict_pixels_pl();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_MAX_EXP_LC:
+		cdata.cfg.pict_max_exp_lc = mt9p012_get_pict_max_exp_lc();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_SET_FPS:
+	case CFG_SET_PICT_FPS:
+		rc = mt9p012_set_fps(&(cdata.cfg.fps));
+		break;
+
+	case CFG_SET_EXP_GAIN:
+		rc = mt9p012_write_exp_gain(cdata.cfg.exp_gain.gain,
+					    cdata.cfg.exp_gain.line);
+		break;
+
+	case CFG_SET_PICT_EXP_GAIN:
+		CDBG("Line:%d CFG_SET_PICT_EXP_GAIN \n", __LINE__);
+		rc = mt9p012_set_pict_exp_gain(cdata.cfg.exp_gain.gain,
+					       cdata.cfg.exp_gain.line);
+		break;
+
+	case CFG_SET_MODE:
+		rc = mt9p012_set_sensor_mode(cdata.mode, cdata.rs);
+		break;
+
+	case CFG_PWR_DOWN:
+		rc = mt9p012_power_down();
+		break;
+
+	case CFG_MOVE_FOCUS:
+		CDBG("mt9p012_ioctl: CFG_MOVE_FOCUS: cdata.cfg.focus.dir=%d \
+				cdata.cfg.focus.steps=%d\n",
+				cdata.cfg.focus.dir, cdata.cfg.focus.steps);
+		rc = mt9p012_move_focus(cdata.cfg.focus.dir,
+					cdata.cfg.focus.steps);
+		break;
+
+	case CFG_SET_DEFAULT_FOCUS:
+		rc = mt9p012_set_default_focus();
+		break;
+
+	case CFG_SET_LENS_SHADING:
+		CDBG("%s: CFG_SET_LENS_SHADING\n", __func__);
+		rc = mt9p012_lens_shading_enable(cdata.cfg.lens_shading);
+		break;
+
+	case CFG_GET_AF_MAX_STEPS:
+		cdata.max_steps = MT9P012_STEPS_NEAR_TO_CLOSEST_INF;
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_SET_EFFECT:
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	mutex_unlock(&mt9p012_mut);
+	return rc;
+}
+
+int mt9p012_sensor_release(void)
+{
+	int rc = -EBADF;
+
+	mutex_lock(&mt9p012_mut);
+
+	mt9p012_power_down();
+
+	gpio_direction_output(mt9p012_ctrl->sensordata->sensor_reset, 0);
+	gpio_free(mt9p012_ctrl->sensordata->sensor_reset);
+
+	if (mt9p012_ctrl->sensordata->vcm_enable) {
+		gpio_direction_output(mt9p012_ctrl->sensordata->vcm_pwd, 0);
+		gpio_free(mt9p012_ctrl->sensordata->vcm_pwd);
+	}
+
+	kfree(mt9p012_ctrl);
+	mt9p012_ctrl = NULL;
+
+	CDBG("mt9p012_release completed\n");
+
+	mutex_unlock(&mt9p012_mut);
+	return rc;
+}
+
+static int mt9p012_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	int rc = 0;
+	CDBG("mt9p012_probe called!\n");
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		CDBG("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	mt9p012_sensorw = kzalloc(sizeof(struct mt9p012_work), GFP_KERNEL);
+	if (!mt9p012_sensorw) {
+		CDBG("kzalloc failed.\n");
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, mt9p012_sensorw);
+	mt9p012_init_client(client);
+	mt9p012_client = client;
+
+	mdelay(50);
+
+	CDBG("mt9p012_probe successed! rc = %d\n", rc);
+	return 0;
+
+probe_failure:
+	CDBG("mt9p012_probe failed! rc = %d\n", rc);
+	return rc;
+}
+
+static const struct i2c_device_id mt9p012_i2c_id[] = {
+	{"mt9p012", 0},
+	{}
+};
+
+static struct i2c_driver mt9p012_i2c_driver = {
+	.id_table = mt9p012_i2c_id,
+	.probe = mt9p012_i2c_probe,
+	.remove = __exit_p(mt9p012_i2c_remove),
+	.driver = {
+		   .name = "mt9p012",
+		   },
+};
+
+static int mt9p012_sensor_probe(const struct msm_camera_sensor_info *info,
+				struct msm_sensor_ctrl *s)
+{
+	int rc = i2c_add_driver(&mt9p012_i2c_driver);
+	if (rc < 0 || mt9p012_client == NULL) {
+		rc = -ENOTSUPP;
+		goto probe_done;
+	}
+
+	msm_camio_clk_rate_set(MT9P012_DEFAULT_CLOCK_RATE);
+	mdelay(20);
+
+	rc = mt9p012_probe_init_sensor(info);
+	if (rc < 0)
+		goto probe_done;
+
+	s->s_init = mt9p012_sensor_open_init;
+	s->s_release = mt9p012_sensor_release;
+	s->s_config = mt9p012_sensor_config;
+	s->s_mount_angle  = 0;
+	mt9p012_probe_init_done(info);
+
+probe_done:
+	CDBG("%s %s:%d\n", __FILE__, __func__, __LINE__);
+	return rc;
+}
+
+static int __mt9p012_probe(struct platform_device *pdev)
+{
+	return msm_camera_drv_start(pdev, mt9p012_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = __mt9p012_probe,
+	.driver = {
+		   .name = "msm_camera_mt9p012",
+		   .owner = THIS_MODULE,
+		   },
+};
+
+static int __init mt9p012_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(mt9p012_init);
diff --git a/drivers/media/video/msm/mt9p012_km.c b/drivers/media/video/msm/mt9p012_km.c
new file mode 100644
index 0000000..c20064c
--- /dev/null
+++ b/drivers/media/video/msm/mt9p012_km.c
@@ -0,0 +1,1295 @@
+/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <media/msm_camera.h>
+#include <mach/gpio.h>
+#include <mach/camera.h>
+#include "mt9p012_km.h"
+
+/*=============================================================
+    SENSOR REGISTER DEFINES
+==============================================================*/
+
+#define MT9P012_KM_REG_MODEL_ID      0x0000
+#define MT9P012_KM_MODEL_ID          0x2800
+#define REG_GROUPED_PARAMETER_HOLD   0x0104
+#define GROUPED_PARAMETER_HOLD       0x0100
+#define GROUPED_PARAMETER_UPDATE     0x0000
+#define REG_COARSE_INT_TIME          0x3012
+#define REG_VT_PIX_CLK_DIV           0x0300
+#define REG_VT_SYS_CLK_DIV           0x0302
+#define REG_PRE_PLL_CLK_DIV          0x0304
+#define REG_PLL_MULTIPLIER           0x0306
+#define REG_OP_PIX_CLK_DIV           0x0308
+#define REG_OP_SYS_CLK_DIV           0x030A
+#define REG_SCALE_M                  0x0404
+#define REG_FRAME_LENGTH_LINES       0x300A
+#define REG_LINE_LENGTH_PCK          0x300C
+#define REG_X_ADDR_START             0x3004
+#define REG_Y_ADDR_START             0x3002
+#define REG_X_ADDR_END               0x3008
+#define REG_Y_ADDR_END               0x3006
+#define REG_X_OUTPUT_SIZE            0x034C
+#define REG_Y_OUTPUT_SIZE            0x034E
+#define REG_FINE_INTEGRATION_TIME    0x3014
+#define REG_ROW_SPEED                0x3016
+#define MT9P012_KM_REG_RESET_REGISTER   0x301A
+#define MT9P012_KM_RESET_REGISTER_PWON  0x10CC
+#define MT9P012_KM_RESET_REGISTER_PWOFF 0x10C8
+#define REG_READ_MODE                0x3040
+#define REG_GLOBAL_GAIN              0x305E
+#define REG_TEST_PATTERN_MODE        0x3070
+
+enum mt9p012_km_test_mode {
+	TEST_OFF,
+	TEST_1,
+	TEST_2,
+	TEST_3
+};
+
+enum mt9p012_km_resolution {
+	QTR_SIZE,
+	FULL_SIZE,
+	INVALID_SIZE
+};
+
+enum mt9p012_km_reg_update {
+	/* Sensor egisters that need to be updated during initialization */
+	REG_INIT,
+	/* Sensor egisters that needs periodic I2C writes */
+	UPDATE_PERIODIC,
+	/* All the sensor Registers will be updated */
+	UPDATE_ALL,
+	/* Not valid update */
+	UPDATE_INVALID
+};
+
+enum mt9p012_km_setting {
+	RES_PREVIEW,
+	RES_CAPTURE
+};
+
+uint8_t mode_mask = 0x04;
+
+/* actuator's Slave Address */
+#define MT9P012_KM_AF_I2C_ADDR   (0x18 >> 1)
+
+/* AF Total steps parameters */
+#define MT9P012_KM_STEPS_NEAR_TO_CLOSEST_INF  30
+#define MT9P012_KM_TOTAL_STEPS_NEAR_TO_FAR    30
+
+/* Time in milisecs for waiting for the sensor to reset.*/
+#define MT9P012_KM_RESET_DELAY_MSECS   66
+
+/* for 20 fps preview */
+#define MT9P012_KM_DEFAULT_CLOCK_RATE  24000000
+
+struct mt9p012_km_work {
+	struct work_struct work;
+};
+static struct mt9p012_km_work *mt9p012_km_sensorw;
+static struct i2c_client *mt9p012_km_client;
+
+struct mt9p012_km_ctrl {
+	const struct msm_camera_sensor_info *sensordata;
+
+	int sensormode;
+	uint32_t fps_divider;	/* init to 1 * 0x00000400 */
+	uint32_t pict_fps_divider;	/* init to 1 * 0x00000400 */
+
+	uint16_t curr_lens_pos;
+	uint16_t init_curr_lens_pos;
+	uint16_t my_reg_gain;
+	uint32_t my_reg_line_count;
+
+	enum mt9p012_km_resolution prev_res;
+	enum mt9p012_km_resolution pict_res;
+	enum mt9p012_km_resolution curr_res;
+	enum mt9p012_km_test_mode set_test;
+};
+static uint16_t update_type = UPDATE_PERIODIC;
+static struct mt9p012_km_ctrl *mt9p012_km_ctrl;
+static DECLARE_WAIT_QUEUE_HEAD(mt9p012_km_wait_queue);
+DEFINE_MUTEX(mt9p012_km_mut);
+
+/*=============================================================*/
+
+static int mt9p012_km_i2c_rxdata(unsigned short saddr, unsigned char *rxdata,
+			int length)
+{
+	struct i2c_msg msgs[] = {
+		{
+			.addr = saddr << 1,
+			.flags = 0,
+			.len = 2,
+			.buf = rxdata,
+		},
+		{
+			.addr = saddr << 1,
+			.flags = I2C_M_RD,
+			.len = length,
+			.buf = rxdata,
+		},
+	};
+
+	if (i2c_transfer(mt9p012_km_client->adapter, msgs, 2) < 0) {
+		CDBG("mt9p012_km_i2c_rxdata failed!\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t mt9p012_km_i2c_read_w(unsigned short saddr, unsigned short raddr,
+				  unsigned short *rdata)
+{
+	int32_t rc = 0;
+	unsigned char buf[4];
+
+	if (!rdata)
+		return -EIO;
+
+	memset(buf, 0, sizeof(buf));
+
+	buf[0] = (raddr & 0xFF00) >> 8;
+	buf[1] = (raddr & 0x00FF);
+
+	rc = mt9p012_km_i2c_rxdata(saddr, buf, 2);
+	if (rc < 0)
+		return rc;
+
+	*rdata = buf[0] << 8 | buf[1];
+
+	if (rc < 0)
+		CDBG("mt9p012_km_i2c_read failed!\n");
+
+	return rc;
+}
+
+static int32_t mt9p012_km_i2c_txdata(unsigned short saddr,
+				  unsigned char *txdata,
+				  int length)
+{
+	struct i2c_msg msg[] = {
+		{
+		 .addr = saddr << 1,
+		 .flags = 0,
+		 .len = length,
+		 .buf = txdata,
+		 },
+	};
+
+	if (i2c_transfer(mt9p012_km_client->adapter, msg, 1) < 0) {
+		CDBG("mt9p012_km_i2c_txdata failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t mt9p012_km_i2c_write_b(unsigned short saddr,
+				   unsigned short baddr,
+				   unsigned short bdata)
+{
+	int32_t rc = -EIO;
+	unsigned char buf[2];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = baddr;
+	buf[1] = bdata;
+	rc = mt9p012_km_i2c_txdata(saddr, buf, 2);
+
+	if (rc < 0)
+		CDBG("i2c_write failed, saddr = 0x%x addr = 0x%x, val =0x%x!\n",
+		     saddr, baddr, bdata);
+
+	return rc;
+}
+
+static int32_t mt9p012_km_i2c_write_w(unsigned short saddr,
+				   unsigned short waddr,
+				   unsigned short wdata)
+{
+	int32_t rc = -EIO;
+	unsigned char buf[4];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = (wdata & 0xFF00) >> 8;
+	buf[3] = (wdata & 0x00FF);
+
+	rc = mt9p012_km_i2c_txdata(saddr, buf, 4);
+
+	if (rc < 0)
+		CDBG("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n",
+		     waddr, wdata);
+
+	return rc;
+}
+
+static int32_t mt9p012_km_i2c_write_w_table(struct mt9p012_km_i2c_reg_conf const
+					 *reg_conf_tbl, int num)
+{
+	int i;
+	int32_t rc = -EIO;
+
+	for (i = 0; i < num; i++) {
+		rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr,
+					 reg_conf_tbl->waddr,
+					 reg_conf_tbl->wdata);
+		if (rc < 0)
+			break;
+		reg_conf_tbl++;
+	}
+
+	return rc;
+}
+
+static int32_t mt9p012_km_test(enum mt9p012_km_test_mode mo)
+{
+	int32_t rc = 0;
+
+	rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD);
+	if (rc < 0)
+		return rc;
+
+	if (mo == TEST_OFF)
+		return 0;
+	else {
+		rc = mt9p012_km_i2c_write_w_table(mt9p012_km_regs.ttbl,
+					 mt9p012_km_regs.ttbl_size);
+		if (rc < 0)
+			return rc;
+
+		rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr,
+					 REG_TEST_PATTERN_MODE, (uint16_t) mo);
+		if (rc < 0)
+			return rc;
+	}
+
+	rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE);
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+
+static int32_t mt9p012_km_lens_shading_enable(uint8_t is_enable)
+{
+	int32_t rc = 0;
+
+	CDBG("%s: entered. enable = %d\n", __func__, is_enable);
+
+	rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, 0x3780,
+				 ((uint16_t) is_enable) << 15);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE);
+
+	CDBG("%s: exiting. rc = %d\n", __func__, rc);
+	return rc;
+}
+
+static int32_t mt9p012_km_set_lc(void)
+{
+	int32_t rc;
+
+	rc = mt9p012_km_i2c_write_w_table(mt9p012_km_regs.lctbl,
+				       mt9p012_km_regs.lctbl_size);
+
+	return rc;
+}
+
+static void mt9p012_km_get_pict_fps(uint16_t fps, uint16_t *pfps)
+{
+
+	/* input fps is preview fps in Q8 format */
+	uint32_t divider;   /*Q10 */
+	uint32_t pclk_mult; /*Q10 */
+	uint32_t d1;
+	uint32_t d2;
+
+	d1 =
+		(uint32_t)(
+		(mt9p012_km_regs.reg_pat[RES_PREVIEW].frame_length_lines *
+		0x00000400) /
+		mt9p012_km_regs.reg_pat[RES_CAPTURE].frame_length_lines);
+
+	d2 =
+		(uint32_t)(
+		(mt9p012_km_regs.reg_pat[RES_PREVIEW].line_length_pck *
+		0x00000400) /
+		mt9p012_km_regs.reg_pat[RES_CAPTURE].line_length_pck);
+
+	divider = (uint32_t) (d1 * d2) / 0x00000400;
+
+	pclk_mult =
+		(uint32_t) ((mt9p012_km_regs.reg_pat[RES_CAPTURE].
+		pll_multiplier * 0x00000400) /
+		(mt9p012_km_regs.reg_pat[RES_PREVIEW].pll_multiplier));
+
+
+	/* Verify PCLK settings and frame sizes. */
+	*pfps = (uint16_t)((((fps * pclk_mult) / 0x00000400) * divider)/
+				0x00000400);
+}
+
+static uint16_t mt9p012_km_get_prev_lines_pf(void)
+{
+	if (mt9p012_km_ctrl->prev_res == QTR_SIZE)
+		return  mt9p012_km_regs.reg_pat[RES_PREVIEW].frame_length_lines;
+	else
+		return  mt9p012_km_regs.reg_pat[RES_CAPTURE].frame_length_lines;
+}
+
+static uint16_t mt9p012_km_get_prev_pixels_pl(void)
+{
+	if (mt9p012_km_ctrl->prev_res == QTR_SIZE)
+		return  mt9p012_km_regs.reg_pat[RES_PREVIEW].line_length_pck;
+	else
+		return  mt9p012_km_regs.reg_pat[RES_CAPTURE].line_length_pck;
+}
+
+static uint16_t mt9p012_km_get_pict_lines_pf(void)
+{
+	return  mt9p012_km_regs.reg_pat[RES_CAPTURE].frame_length_lines;
+}
+
+static uint16_t mt9p012_km_get_pict_pixels_pl(void)
+{
+	return  mt9p012_km_regs.reg_pat[RES_CAPTURE].line_length_pck;
+}
+
+static uint32_t mt9p012_km_get_pict_max_exp_lc(void)
+{
+	uint16_t snapshot_lines_per_frame;
+
+	if (mt9p012_km_ctrl->pict_res == QTR_SIZE)
+		snapshot_lines_per_frame =
+	    mt9p012_km_regs.reg_pat[RES_PREVIEW].frame_length_lines - 1;
+	else
+		snapshot_lines_per_frame =
+	    mt9p012_km_regs.reg_pat[RES_CAPTURE].frame_length_lines - 1;
+
+	return snapshot_lines_per_frame * 24;
+}
+
+static int32_t mt9p012_km_set_fps(struct fps_cfg *fps)
+{
+	int32_t rc = 0;
+
+	mt9p012_km_ctrl->fps_divider = fps->fps_div;
+	mt9p012_km_ctrl->pict_fps_divider = fps->pict_fps_div;
+
+	rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD);
+	if (rc < 0)
+		return -EBUSY;
+
+	rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr,
+			REG_FRAME_LENGTH_LINES,
+			mt9p012_km_regs.reg_pat[mt9p012_km_ctrl->sensormode].
+			frame_length_lines *
+			mt9p012_km_ctrl->fps_divider / 0x00000400);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE);
+
+	return rc;
+}
+
+
+static int32_t mt9p012_km_write_exp_gain(uint16_t gain, uint32_t line)
+{
+	uint16_t max_legal_gain = 0x01FF;
+	uint32_t line_length_ratio = 0x00000400;
+	enum mt9p012_km_setting setting;
+	int32_t rc = 0;
+
+	CDBG("Line:%d mt9p012_km_write_exp_gain \n", __LINE__);
+
+	if (mt9p012_km_ctrl->sensormode == SENSOR_PREVIEW_MODE) {
+		mt9p012_km_ctrl->my_reg_gain = gain;
+		mt9p012_km_ctrl->my_reg_line_count = (uint16_t) line;
+	}
+
+	if (gain > max_legal_gain) {
+		CDBG("Max legal gain Line:%d \n", __LINE__);
+		gain = max_legal_gain;
+	}
+
+	/* Verify no overflow */
+	if (mt9p012_km_ctrl->sensormode == SENSOR_PREVIEW_MODE) {
+		line = (uint32_t) (line * mt9p012_km_ctrl->fps_divider /
+				   0x00000400);
+		setting = RES_PREVIEW;
+	} else {
+		line = (uint32_t) (line * mt9p012_km_ctrl->pict_fps_divider /
+				   0x00000400);
+		setting = RES_CAPTURE;
+	}
+
+	gain |= 0x0200;
+
+	if ((mt9p012_km_regs.reg_pat[setting].frame_length_lines - 1) < line) {
+		line_length_ratio = (uint32_t) (line * 0x00000400) /
+		    (mt9p012_km_regs.reg_pat[setting].frame_length_lines - 1);
+	} else
+		line_length_ratio = 0x00000400;
+
+	rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr,
+				REG_GROUPED_PARAMETER_HOLD,
+				GROUPED_PARAMETER_HOLD);
+	if (rc < 0) {
+		CDBG("mt9p012_km_i2c_write_w failed... Line:%d \n", __LINE__);
+		return rc;
+	}
+
+	rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr,
+				 REG_GLOBAL_GAIN, gain);
+	if (rc < 0) {
+		CDBG("mt9p012_km_i2c_write_w failed... Line:%d \n", __LINE__);
+		return rc;
+	}
+
+	rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr,
+				REG_LINE_LENGTH_PCK,
+			       (uint16_t) (mt9p012_km_regs.reg_pat[setting].
+			    line_length_pck * line_length_ratio / 0x00000400));
+	if (rc < 0)
+		return rc;
+
+	rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr,
+				 REG_COARSE_INT_TIME,
+				 (uint16_t) ((line * 0x00000400)/
+				 line_length_ratio));
+	if (rc < 0) {
+		CDBG("mt9p012_km_i2c_write_w failed... Line:%d \n", __LINE__);
+		return rc;
+	}
+
+	rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr,
+				 REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE);
+	if (rc < 0) {
+		CDBG("mt9p012_km_i2c_write_w failed... Line:%d \n", __LINE__);
+		return rc;
+	}
+
+	CDBG("mt9p012_km_write_exp_gain: gain = %d, line = %d\n", gain, line);
+
+	return rc;
+}
+
+static int32_t mt9p012_km_set_pict_exp_gain(uint16_t gain, uint32_t line)
+{
+	int32_t rc = 0;
+
+	CDBG("Line:%d mt9p012_km_set_pict_exp_gain \n", __LINE__);
+
+	rc = mt9p012_km_write_exp_gain(gain, line);
+	if (rc < 0) {
+		CDBG("Line:%d mt9p012_km_set_pict_exp_gain failed... \n",
+		     __LINE__);
+		return rc;
+	}
+
+	rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr,
+				 MT9P012_KM_REG_RESET_REGISTER,
+				 0x10CC | 0x0002);
+	if (rc < 0) {
+		CDBG("mt9p012_km_i2c_write_w failed... Line:%d \n", __LINE__);
+		return rc;
+	}
+
+	mdelay(5);
+
+	/* camera_timed_wait(snapshot_wait*exposure_ratio); */
+	return rc;
+}
+
+static int32_t mt9p012_km_setting(enum mt9p012_km_reg_update rupdate,
+				enum mt9p012_km_setting rt)
+{
+	int32_t rc = 0;
+
+	switch (rupdate) {
+	case UPDATE_PERIODIC:
+		if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+
+			struct mt9p012_km_i2c_reg_conf ppc_tbl[] = {
+				{REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD},
+				{REG_ROW_SPEED,
+				 mt9p012_km_regs.reg_pat[rt].row_speed},
+				{REG_X_ADDR_START,
+				 mt9p012_km_regs.reg_pat[rt].x_addr_start},
+				{REG_X_ADDR_END,
+				 mt9p012_km_regs.reg_pat[rt].x_addr_end},
+				{REG_Y_ADDR_START,
+				 mt9p012_km_regs.reg_pat[rt].y_addr_start},
+				{REG_Y_ADDR_END,
+				 mt9p012_km_regs.reg_pat[rt].y_addr_end},
+				{REG_READ_MODE,
+				 mt9p012_km_regs.reg_pat[rt].read_mode},
+				{REG_SCALE_M,
+				 mt9p012_km_regs.reg_pat[rt].scale_m},
+				{REG_X_OUTPUT_SIZE,
+				 mt9p012_km_regs.reg_pat[rt].x_output_size},
+				{REG_Y_OUTPUT_SIZE,
+				 mt9p012_km_regs.reg_pat[rt].y_output_size},
+				{REG_LINE_LENGTH_PCK,
+				 mt9p012_km_regs.reg_pat[rt].line_length_pck},
+				{REG_FRAME_LENGTH_LINES,
+			       (mt9p012_km_regs.reg_pat[rt].frame_length_lines *
+				mt9p012_km_ctrl->fps_divider / 0x00000400)},
+				{REG_COARSE_INT_TIME,
+				 mt9p012_km_regs.reg_pat[rt].coarse_int_time},
+				{REG_FINE_INTEGRATION_TIME,
+				 mt9p012_km_regs.reg_pat[rt].fine_int_time},
+				{REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE},
+			};
+
+			if (update_type == REG_INIT) {
+				update_type = rupdate;
+				return rc;
+			}
+
+			rc = mt9p012_km_i2c_write_w_table(&ppc_tbl[0],
+						ARRAY_SIZE(ppc_tbl));
+			if (rc < 0)
+				return rc;
+
+			rc = mt9p012_km_test(mt9p012_km_ctrl->set_test);
+			if (rc < 0)
+				return rc;
+
+			rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr,
+						 MT9P012_KM_REG_RESET_REGISTER,
+						 0x10cc |
+						 0x0002);
+			if (rc < 0)
+				return rc;
+
+			mdelay(15);	/* 15? wait for sensor to transition */
+
+			return rc;
+		}
+		break;	/* UPDATE_PERIODIC */
+
+	case REG_INIT:
+		if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+			struct mt9p012_km_i2c_reg_conf ipc_tbl1[] = {
+				{MT9P012_KM_REG_RESET_REGISTER,
+				 MT9P012_KM_RESET_REGISTER_PWOFF},
+				{REG_VT_PIX_CLK_DIV,
+				 mt9p012_km_regs.reg_pat[rt].vt_pix_clk_div},
+				{REG_VT_SYS_CLK_DIV,
+				 mt9p012_km_regs.reg_pat[rt].vt_sys_clk_div},
+				{REG_PRE_PLL_CLK_DIV,
+				 mt9p012_km_regs.reg_pat[rt].pre_pll_clk_div},
+				{REG_PLL_MULTIPLIER,
+				 mt9p012_km_regs.reg_pat[rt].pll_multiplier},
+				{REG_OP_PIX_CLK_DIV,
+				 mt9p012_km_regs.reg_pat[rt].op_pix_clk_div},
+				{REG_OP_SYS_CLK_DIV,
+				 mt9p012_km_regs.reg_pat[rt].op_sys_clk_div},
+				{MT9P012_KM_REG_RESET_REGISTER,
+				 MT9P012_KM_RESET_REGISTER_PWON},
+			};
+
+			struct mt9p012_km_i2c_reg_conf ipc_tbl2[] = {
+				{REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_HOLD},
+				/* Optimized register settings for
+				   Rev3 Silicon */
+				{0x308A, 0x6424},
+				{0x3092, 0x0A52},
+				{0x3094, 0x4656},
+				{0x3096, 0x5652},
+				{0x0204, 0x0010},
+				{0x0206, 0x0010},
+				{0x0208, 0x0010},
+				{0x020A, 0x0010},
+				{0x020C, 0x0010},
+				{0x3088, 0x6FF6},
+				{0x3154, 0x0282},
+				{0x3156, 0x0381},
+				{0x3162, 0x04CE},
+			};
+
+			struct mt9p012_km_i2c_reg_conf ipc_tbl3[] = {
+				/* Set preview or snapshot mode */
+				{REG_ROW_SPEED,
+				 mt9p012_km_regs.reg_pat[rt].row_speed},
+				{REG_X_ADDR_START,
+				 mt9p012_km_regs.reg_pat[rt].x_addr_start},
+				{REG_X_ADDR_END,
+				 mt9p012_km_regs.reg_pat[rt].x_addr_end},
+				{REG_Y_ADDR_START,
+				 mt9p012_km_regs.reg_pat[rt].y_addr_start},
+				{REG_Y_ADDR_END,
+				 mt9p012_km_regs.reg_pat[rt].y_addr_end},
+				{REG_READ_MODE,
+				 mt9p012_km_regs.reg_pat[rt].read_mode},
+				{REG_SCALE_M,
+				 mt9p012_km_regs.reg_pat[rt].scale_m},
+				{REG_X_OUTPUT_SIZE,
+				 mt9p012_km_regs.reg_pat[rt].x_output_size},
+				{REG_Y_OUTPUT_SIZE,
+				 mt9p012_km_regs.reg_pat[rt].y_output_size},
+				{REG_LINE_LENGTH_PCK,
+				 mt9p012_km_regs.reg_pat[rt].line_length_pck},
+				{REG_FRAME_LENGTH_LINES,
+				 mt9p012_km_regs.reg_pat[rt].
+				 frame_length_lines},
+				{REG_COARSE_INT_TIME,
+				 mt9p012_km_regs.reg_pat[rt].coarse_int_time},
+				{REG_FINE_INTEGRATION_TIME,
+				 mt9p012_km_regs.reg_pat[rt].fine_int_time},
+				{REG_GROUPED_PARAMETER_HOLD,
+				 GROUPED_PARAMETER_UPDATE},
+			};
+
+			/* reset fps_divider */
+			mt9p012_km_ctrl->fps_divider = 1 * 0x0400;
+
+			rc = mt9p012_km_i2c_write_w_table(&ipc_tbl1[0],
+							ARRAY_SIZE(ipc_tbl1));
+			if (rc < 0)
+				return rc;
+
+			mdelay(15);
+
+			rc = mt9p012_km_i2c_write_w_table(&ipc_tbl2[0],
+							ARRAY_SIZE(ipc_tbl2));
+			if (rc < 0)
+				return rc;
+
+			mdelay(5);
+
+			rc = mt9p012_km_i2c_write_w_table(&ipc_tbl3[0],
+						       ARRAY_SIZE(ipc_tbl3));
+			if (rc < 0)
+				return rc;
+
+			/* load lens shading */
+			rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr,
+						 REG_GROUPED_PARAMETER_HOLD,
+						 GROUPED_PARAMETER_HOLD);
+			if (rc < 0)
+				return rc;
+
+			rc = mt9p012_km_set_lc();
+			if (rc < 0)
+				return rc;
+
+			rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr,
+						 REG_GROUPED_PARAMETER_HOLD,
+						 GROUPED_PARAMETER_UPDATE);
+
+			if (rc < 0)
+				return rc;
+		}
+		update_type = rupdate;
+		break;		/* case REG_INIT: */
+
+	default:
+		rc = -EINVAL;
+		break;
+	}			/* switch (rupdate) */
+
+	return rc;
+}
+
+static int32_t mt9p012_km_video_config(int mode, int res)
+{
+	int32_t rc;
+
+	switch (res) {
+	case QTR_SIZE:
+		rc = mt9p012_km_setting(UPDATE_PERIODIC, RES_PREVIEW);
+		if (rc < 0)
+			return rc;
+
+		CDBG("mt9p012_km sensor configuration done!\n");
+		break;
+
+	case FULL_SIZE:
+		rc = mt9p012_km_setting(UPDATE_PERIODIC, RES_CAPTURE);
+		if (rc < 0)
+			return rc;
+
+		break;
+
+	default:
+		return 0;
+	}			/* switch */
+
+	mt9p012_km_ctrl->prev_res = res;
+	mt9p012_km_ctrl->curr_res = res;
+	mt9p012_km_ctrl->sensormode = mode;
+
+	rc = mt9p012_km_write_exp_gain(mt9p012_km_ctrl->my_reg_gain,
+				    mt9p012_km_ctrl->my_reg_line_count);
+
+	rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr,
+				 MT9P012_KM_REG_RESET_REGISTER,
+				 0x10cc | 0x0002);
+
+	mdelay(15);
+	return rc;
+}
+
+static int32_t mt9p012_km_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+
+	rc = mt9p012_km_setting(UPDATE_PERIODIC, RES_CAPTURE);
+	if (rc < 0)
+		return rc;
+
+	mt9p012_km_ctrl->curr_res = mt9p012_km_ctrl->pict_res;
+
+	mt9p012_km_ctrl->sensormode = mode;
+
+	return rc;
+}
+
+static int32_t mt9p012_km_raw_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+
+	rc = mt9p012_km_setting(UPDATE_PERIODIC, RES_CAPTURE);
+	if (rc < 0)
+		return rc;
+
+	mt9p012_km_ctrl->curr_res = mt9p012_km_ctrl->pict_res;
+
+	mt9p012_km_ctrl->sensormode = mode;
+
+	return rc;
+}
+
+static int32_t mt9p012_km_power_down(void)
+{
+	int32_t rc = 0;
+
+	rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr,
+				 MT9P012_KM_REG_RESET_REGISTER,
+				 MT9P012_KM_RESET_REGISTER_PWOFF);
+
+	mdelay(5);
+	return rc;
+}
+
+static int32_t mt9p012_km_move_focus(int direction, int32_t num_steps)
+{
+	int16_t step_direction;
+	int16_t actual_step;
+	int16_t next_position;
+	uint8_t code_val_msb, code_val_lsb;
+
+	if (num_steps > MT9P012_KM_TOTAL_STEPS_NEAR_TO_FAR)
+		num_steps = MT9P012_KM_TOTAL_STEPS_NEAR_TO_FAR;
+	else if (num_steps == 0) {
+		CDBG("mt9p012_km_move_focus failed at line %d ...\n", __LINE__);
+		return -EINVAL;
+	}
+
+	if (direction == MOVE_NEAR)
+		step_direction = 16;	/* 10bit */
+	else if (direction == MOVE_FAR)
+		step_direction = -16;	/* 10 bit */
+	else {
+		CDBG("mt9p012_km_move_focus failed at line %d ...\n", __LINE__);
+		return -EINVAL;
+	}
+
+	if (mt9p012_km_ctrl->curr_lens_pos <
+				mt9p012_km_ctrl->init_curr_lens_pos)
+		mt9p012_km_ctrl->curr_lens_pos =
+				mt9p012_km_ctrl->init_curr_lens_pos;
+
+	actual_step = (int16_t) (step_direction * (int16_t) num_steps);
+	next_position = (int16_t) (mt9p012_km_ctrl->curr_lens_pos +
+							actual_step);
+
+	if (next_position > 1023)
+		next_position = 1023;
+	else if (next_position < 0)
+		next_position = 0;
+
+	code_val_msb = next_position >> 4;
+	code_val_lsb = (next_position & 0x000F) << 4;
+	code_val_lsb |= mode_mask;
+
+	/* Writing the digital code for current to the actuator */
+	if (mt9p012_km_i2c_write_b(MT9P012_KM_AF_I2C_ADDR >> 1,
+				code_val_msb, code_val_lsb) < 0) {
+		CDBG("mt9p012_km_move_focus failed at line %d ...\n", __LINE__);
+		return -EBUSY;
+	}
+
+	/* Storing the current lens Position */
+	mt9p012_km_ctrl->curr_lens_pos = next_position;
+
+	return 0;
+}
+
+static int32_t mt9p012_km_set_default_focus(void)
+{
+	int32_t rc = 0;
+	uint8_t code_val_msb, code_val_lsb;
+
+	code_val_msb = 0x00;
+	code_val_lsb = 0x04;
+
+	/* Write the digital code for current to the actuator */
+	rc = mt9p012_km_i2c_write_b(MT9P012_KM_AF_I2C_ADDR >> 1,
+				 code_val_msb, code_val_lsb);
+
+	mt9p012_km_ctrl->curr_lens_pos = 0;
+	mt9p012_km_ctrl->init_curr_lens_pos = 0;
+
+	return rc;
+}
+
+static int mt9p012_km_probe_init_done(const struct msm_camera_sensor_info *data)
+{
+	gpio_direction_output(data->sensor_reset, 0);
+	gpio_free(data->sensor_reset);
+	return 0;
+}
+
+static int
+	mt9p012_km_probe_init_sensor(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc;
+	uint16_t chipid;
+
+	rc = gpio_request(data->sensor_reset, "mt9p012_km");
+	if (!rc)
+		gpio_direction_output(data->sensor_reset, 1);
+	else
+		goto init_probe_done;
+
+	msleep(20);
+
+	/* RESET the sensor image part via I2C command */
+	CDBG("mt9p012_km_sensor_init(): reseting sensor.\n");
+	rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr,
+				 MT9P012_KM_REG_RESET_REGISTER,
+				 0x10CC | 0x0001);
+	if (rc < 0) {
+		CDBG("sensor reset failed. rc = %d\n", rc);
+		goto init_probe_fail;
+	}
+
+		msleep(MT9P012_KM_RESET_DELAY_MSECS);
+
+	/* 3. Read sensor Model ID: */
+	rc = mt9p012_km_i2c_read_w(mt9p012_km_client->addr,
+				MT9P012_KM_REG_MODEL_ID, &chipid);
+	if (rc < 0)
+		goto init_probe_fail;
+
+	/* 4. Compare sensor ID to MT9T012VC ID: */
+	if (chipid != MT9P012_KM_MODEL_ID) {
+		CDBG("mt9p012_km wrong model_id = 0x%x\n", chipid);
+		rc = -ENODEV;
+		goto init_probe_fail;
+	}
+
+	rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, 0x306E, 0x9080);
+	if (rc < 0) {
+		CDBG("REV_7 write failed. rc = %d\n", rc);
+		goto init_probe_fail;
+	}
+
+	/* RESET_REGISTER, enable parallel interface and disable serialiser */
+	CDBG("mt9p012_km_sensor_init(): enabling parallel interface.\n");
+	rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, 0x301A, 0x10CC);
+	if (rc < 0) {
+		CDBG("enable parallel interface failed. rc = %d\n", rc);
+		goto init_probe_fail;
+	}
+
+	/* To disable the 2 extra lines */
+	rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr, 0x3064, 0x0805);
+
+	if (rc < 0) {
+		CDBG("disable the 2 extra lines failed. rc = %d\n", rc);
+		goto init_probe_fail;
+	}
+
+	goto init_probe_done;
+
+init_probe_fail:
+	mt9p012_km_probe_init_done(data);
+init_probe_done:
+	return rc;
+}
+
+static int
+	mt9p012_km_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc;
+
+	mt9p012_km_ctrl = kzalloc(sizeof(struct mt9p012_km_ctrl), GFP_KERNEL);
+	if (!mt9p012_km_ctrl) {
+		CDBG("mt9p012_km_init failed!\n");
+		rc = -ENOMEM;
+		goto init_done;
+	}
+
+	mt9p012_km_ctrl->fps_divider = 1 * 0x00000400;
+	mt9p012_km_ctrl->pict_fps_divider = 1 * 0x00000400;
+	mt9p012_km_ctrl->set_test = TEST_OFF;
+	mt9p012_km_ctrl->prev_res = QTR_SIZE;
+	mt9p012_km_ctrl->pict_res = FULL_SIZE;
+
+	if (data)
+		mt9p012_km_ctrl->sensordata = data;
+
+	msm_camio_camif_pad_reg_reset();
+	mdelay(20);
+
+	rc = mt9p012_km_probe_init_sensor(data);
+	if (rc < 0)
+		goto init_fail1;
+
+	if (mt9p012_km_ctrl->prev_res == QTR_SIZE)
+		rc = mt9p012_km_setting(REG_INIT, RES_PREVIEW);
+	else
+		rc = mt9p012_km_setting(REG_INIT, RES_CAPTURE);
+
+	if (rc < 0) {
+		CDBG("mt9p012_km_setting failed. rc = %d\n", rc);
+		goto init_fail1;
+	}
+
+	/* sensor : output enable */
+	CDBG("mt9p012_km_sensor_open_init(): enabling output.\n");
+	rc = mt9p012_km_i2c_write_w(mt9p012_km_client->addr,
+				 MT9P012_KM_REG_RESET_REGISTER,
+				 MT9P012_KM_RESET_REGISTER_PWON);
+	if (rc < 0) {
+		CDBG("sensor output enable failed. rc = %d\n", rc);
+		goto init_fail1;
+	}
+
+	if (rc >= 0)
+		goto init_done;
+
+init_fail1:
+	mt9p012_km_probe_init_done(data);
+	kfree(mt9p012_km_ctrl);
+init_done:
+	return rc;
+}
+
+static int mt9p012_km_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&mt9p012_km_wait_queue);
+	return 0;
+}
+
+static int32_t mt9p012_km_set_sensor_mode(int mode, int res)
+{
+	int32_t rc = 0;
+
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		rc = mt9p012_km_video_config(mode, res);
+		break;
+
+	case SENSOR_SNAPSHOT_MODE:
+		rc = mt9p012_km_snapshot_config(mode);
+		break;
+
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		rc = mt9p012_km_raw_snapshot_config(mode);
+		break;
+
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+int mt9p012_km_sensor_config(void __user *argp)
+{
+	struct sensor_cfg_data cdata;
+	int rc = 0;
+
+	if (copy_from_user(&cdata,
+			   (void *)argp, sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+
+	mutex_lock(&mt9p012_km_mut);
+
+	CDBG("%s: cfgtype = %d\n", __func__, cdata.cfgtype);
+	switch (cdata.cfgtype) {
+	case CFG_GET_PICT_FPS:
+		mt9p012_km_get_pict_fps(cdata.cfg.gfps.prevfps,
+				     &(cdata.cfg.gfps.pictfps));
+
+		if (copy_to_user((void *)argp, &cdata,
+				 sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PREV_L_PF:
+		cdata.cfg.prevl_pf = mt9p012_km_get_prev_lines_pf();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PREV_P_PL:
+		cdata.cfg.prevp_pl = mt9p012_km_get_prev_pixels_pl();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_L_PF:
+		cdata.cfg.pictl_pf = mt9p012_km_get_pict_lines_pf();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_P_PL:
+		cdata.cfg.pictp_pl = mt9p012_km_get_pict_pixels_pl();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_MAX_EXP_LC:
+		cdata.cfg.pict_max_exp_lc = mt9p012_km_get_pict_max_exp_lc();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_SET_FPS:
+	case CFG_SET_PICT_FPS:
+		rc = mt9p012_km_set_fps(&(cdata.cfg.fps));
+		break;
+
+	case CFG_SET_EXP_GAIN:
+		rc = mt9p012_km_write_exp_gain(cdata.cfg.exp_gain.gain,
+					    cdata.cfg.exp_gain.line);
+		break;
+
+	case CFG_SET_PICT_EXP_GAIN:
+		CDBG("Line:%d CFG_SET_PICT_EXP_GAIN \n", __LINE__);
+		rc = mt9p012_km_set_pict_exp_gain(cdata.cfg.exp_gain.gain,
+					       cdata.cfg.exp_gain.line);
+		break;
+
+	case CFG_SET_MODE:
+		rc = mt9p012_km_set_sensor_mode(cdata.mode, cdata.rs);
+		break;
+
+	case CFG_PWR_DOWN:
+		rc = mt9p012_km_power_down();
+		break;
+
+	case CFG_MOVE_FOCUS:
+		CDBG("mt9p012_km_ioctl: CFG_MOVE_FOCUS: cdata.cfg.focus.dir=%d \
+				cdata.cfg.focus.steps=%d\n",
+				cdata.cfg.focus.dir, cdata.cfg.focus.steps);
+		rc = mt9p012_km_move_focus(cdata.cfg.focus.dir,
+					cdata.cfg.focus.steps);
+		break;
+
+	case CFG_SET_DEFAULT_FOCUS:
+		rc = mt9p012_km_set_default_focus();
+		break;
+
+	case CFG_SET_LENS_SHADING:
+		CDBG("%s: CFG_SET_LENS_SHADING\n", __func__);
+		rc = mt9p012_km_lens_shading_enable(cdata.cfg.lens_shading);
+		break;
+
+	case CFG_GET_AF_MAX_STEPS:
+		cdata.max_steps = MT9P012_KM_STEPS_NEAR_TO_CLOSEST_INF;
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_SET_EFFECT:
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	mutex_unlock(&mt9p012_km_mut);
+	return rc;
+}
+
+int mt9p012_km_sensor_release(void)
+{
+	int rc = -EBADF;
+
+	mutex_lock(&mt9p012_km_mut);
+
+	mt9p012_km_power_down();
+
+	gpio_direction_output(mt9p012_km_ctrl->sensordata->sensor_reset, 0);
+	gpio_free(mt9p012_km_ctrl->sensordata->sensor_reset);
+
+	gpio_direction_output(mt9p012_km_ctrl->sensordata->vcm_pwd, 0);
+	gpio_free(mt9p012_km_ctrl->sensordata->vcm_pwd);
+
+	kfree(mt9p012_km_ctrl);
+	mt9p012_km_ctrl = NULL;
+
+	CDBG("mt9p012_km_release completed\n");
+
+	mutex_unlock(&mt9p012_km_mut);
+	return rc;
+}
+
+static int mt9p012_km_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	int rc = 0;
+	CDBG("mt9p012_km_probe called!\n");
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		CDBG("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	mt9p012_km_sensorw = kzalloc(sizeof(struct mt9p012_km_work),
+							GFP_KERNEL);
+	if (!mt9p012_km_sensorw) {
+		CDBG("kzalloc failed.\n");
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, mt9p012_km_sensorw);
+	mt9p012_km_init_client(client);
+	mt9p012_km_client = client;
+
+	mdelay(50);
+
+	CDBG("mt9p012_km_probe successed! rc = %d\n", rc);
+	return 0;
+
+probe_failure:
+	CDBG("mt9p012_km_probe failed! rc = %d\n", rc);
+	return rc;
+}
+
+static const struct i2c_device_id mt9p012_km_i2c_id[] = {
+	{"mt9p012_km", 0},
+	{}
+};
+
+static struct i2c_driver mt9p012_km_i2c_driver = {
+	.id_table = mt9p012_km_i2c_id,
+	.probe = mt9p012_km_i2c_probe,
+	.remove = __exit_p(mt9p012_km_i2c_remove),
+	.driver = {
+		   .name = "mt9p012_km",
+		   },
+};
+
+static int mt9p012_km_sensor_probe(const struct msm_camera_sensor_info *info,
+				struct msm_sensor_ctrl *s)
+{
+	int rc = i2c_add_driver(&mt9p012_km_i2c_driver);
+	if (rc < 0 || mt9p012_km_client == NULL) {
+		rc = -ENOTSUPP;
+		goto probe_done;
+	}
+
+	msm_camio_clk_rate_set(MT9P012_KM_DEFAULT_CLOCK_RATE);
+	mdelay(20);
+
+	rc = mt9p012_km_probe_init_sensor(info);
+	if (rc < 0)
+		goto probe_done;
+
+	s->s_init = mt9p012_km_sensor_open_init;
+	s->s_release = mt9p012_km_sensor_release;
+	s->s_config = mt9p012_km_sensor_config;
+	s->s_mount_angle  = 0;
+	mt9p012_km_probe_init_done(info);
+
+probe_done:
+	CDBG("%s %s:%d\n", __FILE__, __func__, __LINE__);
+	return rc;
+}
+
+static int __mt9p012_km_probe(struct platform_device *pdev)
+{
+	return msm_camera_drv_start(pdev, mt9p012_km_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = __mt9p012_km_probe,
+	.driver = {
+		   .name = "msm_camera_mt9p012_km",
+		   .owner = THIS_MODULE,
+		   },
+};
+
+static int __init mt9p012_km_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(mt9p012_km_init);
diff --git a/drivers/media/video/msm/mt9p012_km.h b/drivers/media/video/msm/mt9p012_km.h
new file mode 100644
index 0000000..aefabd4
--- /dev/null
+++ b/drivers/media/video/msm/mt9p012_km.h
@@ -0,0 +1,61 @@
+/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#ifndef MT9P012_KM_H
+#define MT9P012_KM_H
+
+#include <linux/types.h>
+
+extern struct mt9p012_km_reg mt9p012_km_regs;	/* from mt9p012_km_reg.c */
+
+struct reg_struct {
+	uint16_t vt_pix_clk_div;     /* 0x0300 */
+	uint16_t vt_sys_clk_div;     /* 0x0302 */
+	uint16_t pre_pll_clk_div;    /* 0x0304 */
+	uint16_t pll_multiplier;     /* 0x0306 */
+	uint16_t op_pix_clk_div;     /* 0x0308 */
+	uint16_t op_sys_clk_div;     /* 0x030A */
+	uint16_t scale_m;            /* 0x0404 */
+	uint16_t row_speed;          /* 0x3016 */
+	uint16_t x_addr_start;       /* 0x3004 */
+	uint16_t x_addr_end;         /* 0x3008 */
+	uint16_t y_addr_start;       /* 0x3002 */
+	uint16_t y_addr_end;         /* 0x3006 */
+	uint16_t read_mode;          /* 0x3040 */
+	uint16_t x_output_size ;     /* 0x034C */
+	uint16_t y_output_size;      /* 0x034E */
+	uint16_t line_length_pck;    /* 0x300C */
+	uint16_t frame_length_lines; /* 0x300A */
+	uint16_t coarse_int_time;    /* 0x3012 */
+	uint16_t fine_int_time;      /* 0x3014 */
+};
+
+
+struct mt9p012_km_i2c_reg_conf {
+	unsigned short waddr;
+	unsigned short wdata;
+};
+
+
+struct mt9p012_km_reg {
+	struct reg_struct const *reg_pat;
+	uint16_t reg_pat_size;
+	struct mt9p012_km_i2c_reg_conf const *ttbl;
+	uint16_t ttbl_size;
+	struct mt9p012_km_i2c_reg_conf const *lctbl;
+	uint16_t lctbl_size;
+	struct mt9p012_km_i2c_reg_conf const *rftbl;
+	uint16_t rftbl_size;
+};
+
+#endif /* MT9P012_KM_H */
diff --git a/drivers/media/video/msm/mt9p012_km_reg.c b/drivers/media/video/msm/mt9p012_km_reg.c
new file mode 100644
index 0000000..109930b
--- /dev/null
+++ b/drivers/media/video/msm/mt9p012_km_reg.c
@@ -0,0 +1,375 @@
+/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include "mt9p012_km.h"
+#include <linux/kernel.h>
+
+/*Micron settings from Applications for lower power consumption.*/
+struct reg_struct const mt9p012_km_reg_pat[2] = {
+	{ /* Preview */
+		/* vt_pix_clk_div          REG=0x0300 */
+		6,  /* 5 */
+
+		/* vt_sys_clk_div          REG=0x0302 */
+		1,
+
+		/* pre_pll_clk_div         REG=0x0304 */
+		2,
+
+		/* pll_multiplier          REG=0x0306 */
+		60,
+
+		/* op_pix_clk_div          REG=0x0308 */
+		8,  /* 10 */
+
+		/* op_sys_clk_div          REG=0x030A */
+		1,
+
+		/* scale_m                 REG=0x0404 */
+		16,
+
+		/* row_speed               REG=0x3016 */
+		0x0111,
+
+		/* x_addr_start            REG=0x3004 */
+		8,
+
+		/* x_addr_end              REG=0x3008 */
+		2597,
+
+		/* y_addr_start            REG=0x3002 */
+		8,
+
+		/* y_addr_end              REG=0x3006 */
+		1949,
+
+		/* read_mode               REG=0x3040
+		 * Preview 2x2 skipping */
+		0x006C,
+
+		/* x_output_size           REG=0x034C */
+		1296,
+
+		/* y_output_size           REG=0x034E */
+		972,
+
+		/* line_length_pck         REG=0x300C */
+		3783,
+
+		/* frame_length_lines      REG=0x300A */
+		1074,
+
+		/* coarse_integration_time REG=0x3012 */
+		16,
+
+		/* fine_integration_time   REG=0x3014 */
+		1764
+	},
+	{ /* Snapshot */
+		/* vt_pix_clk_div          REG=0x0300 */
+		6,
+
+		/* vt_sys_clk_div          REG=0x0302 */
+		1,
+
+		/* pre_pll_clk_div         REG=0x0304 */
+		2,
+
+		/* pll_multiplier          REG=0x0306
+		 * 39 for 10fps snapshot */
+		39,
+
+		/* op_pix_clk_div          REG=0x0308 */
+		8,
+
+		/* op_sys_clk_div          REG=0x030A */
+		1,
+
+		/* scale_m                 REG=0x0404 */
+		16,
+
+		/* row_speed               REG=0x3016 */
+		0x0111,
+
+		/* x_addr_start            REG=0x3004 */
+		8,
+
+		/* x_addr_end              REG=0x3008 */
+		2615,
+
+		/* y_addr_start            REG=0x3002 */
+		8,
+
+		/* y_addr_end              REG=0x3006 */
+		1967,
+
+		/* read_mode               REG=0x3040 */
+		0x0024,
+
+		/* x_output_size           REG=0x034C */
+		2608,
+
+		/* y_output_size           REG=0x034E */
+		1960,
+
+		/* line_length_pck         REG=0x300C */
+		3788,
+
+		/* frame_length_lines      REG=0x300A 10 fps snapshot */
+		2045,
+
+		/* coarse_integration_time REG=0x3012 */
+		16,
+
+		/* fine_integration_time   REG=0x3014 */
+		882
+	}
+};
+
+struct mt9p012_km_i2c_reg_conf const mt9p012_km_test_tbl[] = {
+	{0x3044, 0x0544 & 0xFBFF},
+	{0x30CA, 0x0004 | 0x0001},
+	{0x30D4, 0x9020 & 0x7FFF},
+	{0x31E0, 0x0003 & 0xFFFE},
+	{0x3180, 0x91FF & 0x7FFF},
+	{0x301A, (0x10CC | 0x8000) & 0xFFF7},
+	{0x301E, 0x0000},
+	{0x3780, 0x0000},
+};
+
+
+struct mt9p012_km_i2c_reg_conf const mt9p012_km_lc_tbl[] = {
+	{0x360A, 0x00F0},
+	{0x360C, 0x0B29},
+	{0x360E, 0x5ED1},
+	{0x3610, 0x890D},
+	{0x3612, 0x9871},
+	{0x364A, 0xAD2C},
+	{0x364C, 0x0A8C},
+	{0x364E, 0x91EC},
+	{0x3650, 0x94EC},
+	{0x3652, 0xC76B},
+	{0x368A, 0x5931},
+	{0x368C, 0x4FED},
+	{0x368E, 0x8A50},
+	{0x3690, 0x5C0F},
+	{0x3692, 0x8393},
+	{0x36CA, 0xDB8E},
+	{0x36CC, 0xCA4D},
+	{0x36CE, 0x146F},
+	{0x36D0, 0x618F},
+	{0x36D2, 0x014F},
+	{0x370A, 0x1FEE},
+	{0x370C, 0xDD50},
+	{0x370E, 0xDB54},
+	{0x3710, 0xCA92},
+	{0x3712, 0x1896},
+	{0x3600, 0x00F0},
+	{0x3602, 0xA04C},
+	{0x3604, 0x5711},
+	{0x3606, 0x5E6D},
+	{0x3608, 0xA971},
+	{0x3640, 0xDCCC},
+	{0x3642, 0x0529},
+	{0x3644, 0x96ED},
+	{0x3646, 0xF447},
+	{0x3648, 0x4AEE},
+	{0x3680, 0x2171},
+	{0x3682, 0x634F},
+	{0x3684, 0xCC91},
+	{0x3686, 0xA9CE},
+	{0x3688, 0x8751},
+	{0x36C0, 0x8B6D},
+	{0x36C2, 0xE20E},
+	{0x36C4, 0x750F},
+	{0x36C6, 0x0090},
+	{0x36C8, 0x9E91},
+	{0x3700, 0xEAAF},
+	{0x3702, 0xB8AF},
+	{0x3704, 0xE293},
+	{0x3706, 0xAB33},
+	{0x3708, 0x4595},
+	{0x3614, 0x00D0},
+	{0x3616, 0x8AAB},
+	{0x3618, 0x18B1},
+	{0x361A, 0x54AD},
+	{0x361C, 0x9DB0},
+	{0x3654, 0x11EB},
+	{0x3656, 0x332C},
+	{0x3658, 0x316D},
+	{0x365A, 0xF0EB},
+	{0x365C, 0xB4ED},
+	{0x3694, 0x0F31},
+	{0x3696, 0x08D0},
+	{0x3698, 0xA52F},
+	{0x369A, 0xE64F},
+	{0x369C, 0xC9D2},
+	{0x36D4, 0x8C2D},
+	{0x36D6, 0xAD6E},
+	{0x36D8, 0xE1CE},
+	{0x36DA, 0x1750},
+	{0x36DC, 0x8CAD},
+	{0x3714, 0x8CAF},
+	{0x3716, 0x8C11},
+	{0x3718, 0xE453},
+	{0x371A, 0x9693},
+	{0x371C, 0x38B5},
+	{0x361E, 0x00D0},
+	{0x3620, 0xB6CB},
+	{0x3622, 0x4811},
+	{0x3624, 0xB70C},
+	{0x3626, 0xA771},
+	{0x365E, 0xB5A9},
+	{0x3660, 0x05AA},
+	{0x3662, 0x00CF},
+	{0x3664, 0xB86B},
+	{0x3666, 0xA4AF},
+	{0x369E, 0x3E31},
+	{0x36A0, 0x902B},
+	{0x36A2, 0xD251},
+	{0x36A4, 0x5C2F},
+	{0x36A6, 0x8471},
+	{0x36DE, 0x2C6D},
+	{0x36E0, 0xECEE},
+	{0x36E2, 0xB650},
+	{0x36E4, 0x0210},
+	{0x36E6, 0xACAE},
+	{0x371E, 0xAC30},
+	{0x3720, 0x394E},
+	{0x3722, 0xFDD3},
+	{0x3724, 0xBCB2},
+	{0x3726, 0x5AD5},
+	{0x3782, 0x0508},
+	{0x3784, 0x03B4},
+	{0x3780, 0x8000},
+};
+
+struct mt9p012_km_i2c_reg_conf const mt9p012_km_rolloff_tbl[] = {
+	{0x360A, 0x00F0},
+	{0x360C, 0x0B29},
+	{0x360E, 0x5ED1},
+	{0x3610, 0x890D},
+	{0x3612, 0x9871},
+	{0x364A, 0xAD2C},
+	{0x364C, 0x0A8C},
+	{0x364E, 0x91EC},
+	{0x3650, 0x94EC},
+	{0x3652, 0xC76B},
+	{0x368A, 0x5931},
+	{0x368C, 0x4FED},
+	{0x368E, 0x8A50},
+	{0x3690, 0x5C0F},
+	{0x3692, 0x8393},
+	{0x36CA, 0xDB8E},
+	{0x36CC, 0xCA4D},
+	{0x36CE, 0x146F},
+	{0x36D0, 0x618F},
+	{0x36D2, 0x014F},
+	{0x370A, 0x1FEE},
+	{0x370C, 0xDD50},
+	{0x370E, 0xDB54},
+	{0x3710, 0xCA92},
+	{0x3712, 0x1896},
+	{0x3600, 0x00F0},
+	{0x3602, 0xA04C},
+	{0x3604, 0x5711},
+	{0x3606, 0x5E6D},
+	{0x3608, 0xA971},
+	{0x3640, 0xDCCC},
+	{0x3642, 0x0529},
+	{0x3644, 0x96ED},
+	{0x3646, 0xF447},
+	{0x3648, 0x4AEE},
+	{0x3680, 0x2171},
+	{0x3682, 0x634F},
+	{0x3684, 0xCC91},
+	{0x3686, 0xA9CE},
+	{0x3688, 0x8751},
+	{0x36C0, 0x8B6D},
+	{0x36C2, 0xE20E},
+	{0x36C4, 0x750F},
+	{0x36C6, 0x0090},
+	{0x36C8, 0x9E91},
+	{0x3700, 0xEAAF},
+	{0x3702, 0xB8AF},
+	{0x3704, 0xE293},
+	{0x3706, 0xAB33},
+	{0x3708, 0x4595},
+	{0x3614, 0x00D0},
+	{0x3616, 0x8AAB},
+	{0x3618, 0x18B1},
+	{0x361A, 0x54AD},
+	{0x361C, 0x9DB0},
+	{0x3654, 0x11EB},
+	{0x3656, 0x332C},
+	{0x3658, 0x316D},
+	{0x365A, 0xF0EB},
+	{0x365C, 0xB4ED},
+	{0x3694, 0x0F31},
+	{0x3696, 0x08D0},
+	{0x3698, 0xA52F},
+	{0x369A, 0xE64F},
+	{0x369C, 0xC9D2},
+	{0x36D4, 0x8C2D},
+	{0x36D6, 0xAD6E},
+	{0x36D8, 0xE1CE},
+	{0x36DA, 0x1750},
+	{0x36DC, 0x8CAD},
+	{0x3714, 0x8CAF},
+	{0x3716, 0x8C11},
+	{0x3718, 0xE453},
+	{0x371A, 0x9693},
+	{0x371C, 0x38B5},
+	{0x361E, 0x00D0},
+	{0x3620, 0xB6CB},
+	{0x3622, 0x4811},
+	{0x3624, 0xB70C},
+	{0x3626, 0xA771},
+	{0x365E, 0xB5A9},
+	{0x3660, 0x05AA},
+	{0x3662, 0x00CF},
+	{0x3664, 0xB86B},
+	{0x3666, 0xA4AF},
+	{0x369E, 0x3E31},
+	{0x36A0, 0x902B},
+	{0x36A2, 0xD251},
+	{0x36A4, 0x5C2F},
+	{0x36A6, 0x8471},
+	{0x36DE, 0x2C6D},
+	{0x36E0, 0xECEE},
+	{0x36E2, 0xB650},
+	{0x36E4, 0x0210},
+	{0x36E6, 0xACAE},
+	{0x371E, 0xAC30},
+	{0x3720, 0x394E},
+	{0x3722, 0xFDD3},
+	{0x3724, 0xBCB2},
+	{0x3726, 0x5AD5},
+	{0x3782, 0x0508},
+	{0x3784, 0x03B4},
+	{0x3780, 0x8000},
+};
+
+
+struct mt9p012_km_reg mt9p012_km_regs = {
+	.reg_pat = &mt9p012_km_reg_pat[0],
+	.reg_pat_size = ARRAY_SIZE(mt9p012_km_reg_pat),
+	.ttbl = &mt9p012_km_test_tbl[0],
+	.ttbl_size = ARRAY_SIZE(mt9p012_km_test_tbl),
+	.lctbl = &mt9p012_km_lc_tbl[0],
+	.lctbl_size = ARRAY_SIZE(mt9p012_km_lc_tbl),
+	.rftbl = &mt9p012_km_rolloff_tbl[0],
+	.rftbl_size = ARRAY_SIZE(mt9p012_km_rolloff_tbl)
+};
+
+
diff --git a/drivers/media/video/msm/mt9p012_reg.c b/drivers/media/video/msm/mt9p012_reg.c
new file mode 100644
index 0000000..06fe419
--- /dev/null
+++ b/drivers/media/video/msm/mt9p012_reg.c
@@ -0,0 +1,263 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include "mt9p012.h"
+#include <linux/kernel.h>
+
+/*Micron settings from Applications for lower power consumption.*/
+struct reg_struct const mt9p012_reg_pat[2] = {
+	{ /* Preview */
+		/* vt_pix_clk_div          REG=0x0300 */
+		6,  /* 5 */
+
+		/* vt_sys_clk_div          REG=0x0302 */
+		1,
+		/* pre_pll_clk_div         REG=0x0304 */
+		2,
+		/* pll_multiplier          REG=0x0306 */
+		60,
+
+		/* op_pix_clk_div          REG=0x0308 */
+		8,  /* 10 */
+
+		/* op_sys_clk_div          REG=0x030A */
+		1,
+
+		/* scale_m                 REG=0x0404 */
+		16,
+
+		/* row_speed               REG=0x3016 */
+		0x0111,
+
+		/* x_addr_start            REG=0x3004 */
+		8,
+
+		/* x_addr_end              REG=0x3008 */
+		2597,
+
+		/* y_addr_start            REG=0x3002 */
+		8,
+
+		/* y_addr_end              REG=0x3006 */
+		1949,
+
+		/* read_mode               REG=0x3040
+		 * Preview 2x2 skipping */
+		0x00C3,
+
+		/* x_output_size           REG=0x034C */
+		1296,
+
+		/* y_output_size           REG=0x034E */
+		972,
+
+		/* line_length_pck         REG=0x300C */
+		3659,
+
+		/* frame_length_lines      REG=0x300A */
+		1074,
+
+		/* coarse_integration_time REG=0x3012 */
+		16,
+
+		/* fine_integration_time   REG=0x3014 */
+		1764
+	},
+	{ /* Snapshot */
+		/* vt_pix_clk_div          REG=0x0300 */
+		6,
+
+		/* vt_sys_clk_div          REG=0x0302 */
+		1,
+
+		/* pre_pll_clk_div         REG=0x0304 */
+		2,
+
+		/* pll_multiplier          REG=0x0306
+		 * 60 for 10fps snapshot */
+		60,
+
+		/* op_pix_clk_div          REG=0x0308 */
+		8,
+
+		/* op_sys_clk_div          REG=0x030A */
+		1,
+
+		/* scale_m                 REG=0x0404 */
+		16,
+
+		/* row_speed               REG=0x3016 */
+		0x0111,
+
+		/* x_addr_start            REG=0x3004 */
+		8,
+
+		/* x_addr_end              REG=0x3008 */
+		2615,
+
+		/* y_addr_start            REG=0x3002 */
+		8,
+
+		/* y_addr_end              REG=0x3006 */
+		1967,
+
+		/* read_mode               REG=0x3040 */
+		0x0041,
+
+		/* x_output_size           REG=0x034C */
+		2608,
+
+		/* y_output_size           REG=0x034E */
+		1960,
+
+		/* line_length_pck         REG=0x300C */
+		3911,
+
+		/* frame_length_lines      REG=0x300A 10 fps snapshot */
+		2045,
+
+		/* coarse_integration_time REG=0x3012 */
+		16,
+
+		/* fine_integration_time   REG=0x3014 */
+		882
+	}
+};
+
+
+struct mt9p012_i2c_reg_conf const mt9p012_test_tbl[] = {
+	{0x3044, 0x0544 & 0xFBFF},
+	{0x30CA, 0x0004 | 0x0001},
+	{0x30D4, 0x9020 & 0x7FFF},
+	{0x31E0, 0x0003 & 0xFFFE},
+	{0x3180, 0x91FF & 0x7FFF},
+	{0x301A, (0x10CC | 0x8000) & 0xFFF7},
+	{0x301E, 0x0000},
+	{0x3780, 0x0000},
+};
+struct mt9p012_i2c_reg_conf const mt9p012_rolloff_tbl[] = {
+	{0x360A, 0x0110},
+	{0x360C, 0x270D},
+	{0x360E, 0x0071},
+	{0x3610, 0xA38D},
+	{0x3612, 0xA610},
+	{0x364A, 0x8F49},
+	{0x364C, 0x696A},
+	{0x364E, 0x0FCD},
+	{0x3650, 0x20ED},
+	{0x3652, 0x81ED},
+	{0x368A, 0x1031},
+	{0x368C, 0xBCAD},
+	{0x368E, 0x77AA},
+	{0x3690, 0xD10E},
+	{0x3692, 0xC133},
+	{0x36CA, 0x4F8D},
+	{0x36CC, 0xAC4D},
+	{0x36CE, 0xC8CE},
+	{0x36D0, 0x73AD},
+	{0x36D2, 0xC150},
+	{0x370A, 0xB590},
+	{0x370C, 0x9010},
+	{0x370E, 0xAC52},
+	{0x3710, 0x4D51},
+	{0x3712, 0x5670},
+	{0x3600, 0x00F0},
+	{0x3602, 0xCE4B},
+	{0x3604, 0x4270},
+	{0x3606, 0x8BC9},
+	{0x3608, 0xFA2F},
+	{0x3640, 0x9A09},
+	{0x3642, 0xB40C},
+	{0x3644, 0x4ECD},
+	{0x3646, 0x1BCC},
+	{0x3648, 0xD68E},
+	{0x3680, 0x1BF0},
+	{0x3682, 0xC94D},
+	{0x3684, 0x714F},
+	{0x3686, 0x1491},
+	{0x3688, 0xB8D3},
+	{0x36C0, 0x3E49},
+	{0x36C2, 0x7A6C},
+	{0x36C4, 0xEF2E},
+	{0x36C6, 0xE0EE},
+	{0x36C8, 0x570F},
+	{0x3700, 0xD6AF},
+	{0x3702, 0x2251},
+	{0x3704, 0x8A33},
+	{0x3706, 0xEFB3},
+	{0x3708, 0x1174},
+	{0x3614, 0x0150},
+	{0x3616, 0xA9AB},
+	{0x3618, 0x1770},
+	{0x361A, 0x8809},
+	{0x361C, 0xE3AE},
+	{0x3654, 0x5ACC},
+	{0x3656, 0x35EA},
+	{0x3658, 0x2DEC},
+	{0x365A, 0xB90B},
+	{0x365C, 0x250C},
+	{0x3694, 0x1630},
+	{0x3696, 0xD88C},
+	{0x3698, 0xBD0E},
+	{0x369A, 0x16D1},
+	{0x369C, 0xE492},
+	{0x36D4, 0x5D6D},
+	{0x36D6, 0x906E},
+	{0x36D8, 0x10AE},
+	{0x36DA, 0x7A8E},
+	{0x36DC, 0x9672},
+	{0x3714, 0x8D90},
+	{0x3716, 0x04F1},
+	{0x3718, 0x23F1},
+	{0x371A, 0xF313},
+	{0x371C, 0xE833},
+	{0x361E, 0x0490},
+	{0x3620, 0x14CD},
+	{0x3622, 0x38F0},
+	{0x3624, 0xBAED},
+	{0x3626, 0xFF6F},
+	{0x365E, 0x358C},
+	{0x3660, 0xA9E9},
+	{0x3662, 0x4A4E},
+	{0x3664, 0x398D},
+	{0x3666, 0x890F},
+	{0x369E, 0x2DF0},
+	{0x36A0, 0xF7CE},
+	{0x36A2, 0xB3CC},
+	{0x36A4, 0x118D},
+	{0x36A6, 0x9CB3},
+	{0x36DE, 0x462D},
+	{0x36E0, 0x74AA},
+	{0x36E2, 0xC8CF},
+	{0x36E4, 0x8DEF},
+	{0x36E6, 0xF130},
+	{0x371E, 0x9250},
+	{0x3720, 0x19CC},
+	{0x3722, 0xDFD1},
+	{0x3724, 0x5B70},
+	{0x3726, 0x34D2},
+	{0x3782, 0x0530},
+	{0x3784, 0x03C8},
+	{0x3780, 0x8000},
+};
+
+struct mt9p012_reg mt9p012_regs = {
+	.reg_pat = &mt9p012_reg_pat[0],
+	.reg_pat_size = ARRAY_SIZE(mt9p012_reg_pat),
+	.ttbl = &mt9p012_test_tbl[0],
+	.ttbl_size = ARRAY_SIZE(mt9p012_test_tbl),
+	.rftbl = &mt9p012_rolloff_tbl[0],
+	.rftbl_size = ARRAY_SIZE(mt9p012_rolloff_tbl)
+};
+
+
diff --git a/drivers/media/video/msm/mt9t013.c b/drivers/media/video/msm/mt9t013.c
new file mode 100644
index 0000000..e1f6167
--- /dev/null
+++ b/drivers/media/video/msm/mt9t013.c
@@ -0,0 +1,1503 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <media/msm_camera.h>
+#include <mach/gpio.h>
+#include <mach/camera.h>
+#include <asm/mach-types.h>
+#include "mt9t013.h"
+
+/*=============================================================
+	SENSOR REGISTER DEFINES
+==============================================================*/
+#define MT9T013_REG_MODEL_ID 		 0x0000
+#define MT9T013_MODEL_ID     		 0x2600
+#define REG_GROUPED_PARAMETER_HOLD   0x0104
+#define GROUPED_PARAMETER_HOLD       0x0100
+#define GROUPED_PARAMETER_UPDATE     0x0000
+#define REG_COARSE_INT_TIME          0x3012
+#define REG_VT_PIX_CLK_DIV           0x0300
+#define REG_VT_SYS_CLK_DIV           0x0302
+#define REG_PRE_PLL_CLK_DIV          0x0304
+#define REG_PLL_MULTIPLIER           0x0306
+#define REG_OP_PIX_CLK_DIV           0x0308
+#define REG_OP_SYS_CLK_DIV           0x030A
+#define REG_SCALE_M                  0x0404
+#define REG_FRAME_LENGTH_LINES       0x300A
+#define REG_LINE_LENGTH_PCK          0x300C
+#define REG_X_ADDR_START             0x3004
+#define REG_Y_ADDR_START             0x3002
+#define REG_X_ADDR_END               0x3008
+#define REG_Y_ADDR_END               0x3006
+#define REG_X_OUTPUT_SIZE            0x034C
+#define REG_Y_OUTPUT_SIZE            0x034E
+#define REG_FINE_INT_TIME            0x3014
+#define REG_ROW_SPEED                0x3016
+#define MT9T013_REG_RESET_REGISTER   0x301A
+#define MT9T013_RESET_REGISTER_PWON  0x10CC
+#define MT9T013_RESET_REGISTER_PWOFF 0x1008 /* 0x10C8 stop streaming*/
+#define MT9T013_RESET_FAST_TRANSITION 0x0002
+#define REG_READ_MODE                0x3040
+#define REG_GLOBAL_GAIN              0x305E
+#define REG_TEST_PATTERN_MODE        0x3070
+
+
+enum mt9t013_test_mode {
+	TEST_OFF,
+	TEST_1,
+	TEST_2,
+	TEST_3
+};
+
+enum mt9t013_resolution {
+	QTR_SIZE,
+	FULL_SIZE,
+	INVALID_SIZE
+};
+
+enum mt9t013_reg_update {
+	REG_INIT, /* registers that need to be updated during initialization */
+	UPDATE_PERIODIC, /* registers that needs periodic I2C writes */
+	UPDATE_ALL, /* all registers will be updated */
+	UPDATE_INVALID
+};
+
+enum mt9t013_setting {
+	RES_PREVIEW,
+	RES_CAPTURE
+};
+
+/* actuator's Slave Address */
+#define MT9T013_AF_I2C_ADDR   0x18
+
+/*
+* AF Total steps parameters
+*/
+#define MT9T013_TOTAL_STEPS_NEAR_TO_FAR    30
+
+/*
+ * Time in milisecs for waiting for the sensor to reset.
+ */
+#define MT9T013_RESET_DELAY_MSECS   66
+
+/* for 30 fps preview */
+#define MT9T013_DEFAULT_CLOCK_RATE  24000000
+#define MT9T013_DEFAULT_MAX_FPS     26
+
+
+/* FIXME: Changes from here */
+struct mt9t013_work {
+	struct work_struct work;
+};
+
+static struct  mt9t013_work *mt9t013_sensorw;
+static struct  i2c_client *mt9t013_client;
+
+struct mt9t013_ctrl {
+	const struct msm_camera_sensor_info *sensordata;
+
+	int sensormode;
+	uint32_t fps_divider; 		/* init to 1 * 0x00000400 */
+	uint32_t pict_fps_divider; 	/* init to 1 * 0x00000400 */
+
+	uint16_t curr_lens_pos;
+	uint16_t init_curr_lens_pos;
+	uint16_t my_reg_gain;
+	uint32_t my_reg_line_count;
+
+	enum mt9t013_resolution prev_res;
+	enum mt9t013_resolution pict_res;
+	enum mt9t013_resolution curr_res;
+	enum mt9t013_test_mode  set_test;
+
+	unsigned short imgaddr;
+};
+
+
+static struct mt9t013_ctrl *mt9t013_ctrl;
+static DECLARE_WAIT_QUEUE_HEAD(mt9t013_wait_queue);
+DEFINE_SEMAPHORE(mt9t013_sem);
+
+static int mt9t013_i2c_rxdata(unsigned short saddr,
+	unsigned char *rxdata, int length)
+{
+	struct i2c_msg msgs[] = {
+	{
+		.addr   = saddr,
+		.flags = 0,
+		.len   = 2,
+		.buf   = rxdata,
+	},
+	{
+		.addr  = saddr,
+		.flags = I2C_M_RD,
+		.len   = length,
+		.buf   = rxdata,
+	},
+	};
+
+	if (i2c_transfer(mt9t013_client->adapter, msgs, 2) < 0) {
+		pr_err("mt9t013_i2c_rxdata failed!\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t mt9t013_i2c_read_w(unsigned short saddr,
+	unsigned short raddr, unsigned short *rdata)
+{
+	int32_t rc = 0;
+	unsigned char buf[4];
+
+	if (!rdata)
+		return -EIO;
+
+	memset(buf, 0, sizeof(buf));
+
+	buf[0] = (raddr & 0xFF00)>>8;
+	buf[1] = (raddr & 0x00FF);
+
+	rc = mt9t013_i2c_rxdata(saddr, buf, 2);
+	if (rc < 0)
+		return rc;
+
+	*rdata = buf[0] << 8 | buf[1];
+
+	if (rc < 0)
+		pr_err("mt9t013_i2c_read failed!\n");
+
+	return rc;
+}
+
+static int32_t mt9t013_i2c_txdata(unsigned short saddr,
+	unsigned char *txdata, int length)
+{
+	struct i2c_msg msg[] = {
+	{
+		.addr = saddr,
+		.flags = 0,
+		.len = length,
+		.buf = txdata,
+	},
+	};
+
+	if (i2c_transfer(mt9t013_client->adapter, msg, 1) < 0) {
+		pr_err("mt9t013_i2c_txdata failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t mt9t013_i2c_write_b(unsigned short saddr,
+	unsigned short waddr, unsigned short wdata)
+{
+	int32_t rc = -EIO;
+	unsigned char buf[2];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = waddr;
+	buf[1] = wdata;
+	rc = mt9t013_i2c_txdata(saddr, buf, 2);
+
+	if (rc < 0)
+		pr_err("i2c_write failed, addr = 0x%x, val = 0x%x!\n",
+		waddr, wdata);
+
+	return rc;
+}
+
+static int32_t mt9t013_i2c_write_w(unsigned short saddr,
+	unsigned short waddr, unsigned short wdata)
+{
+	int32_t rc = -EIO;
+	unsigned char buf[4];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00)>>8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = (wdata & 0xFF00)>>8;
+	buf[3] = (wdata & 0x00FF);
+
+	rc = mt9t013_i2c_txdata(saddr, buf, 4);
+
+	if (rc < 0)
+		pr_err("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n",
+		waddr, wdata);
+
+	return rc;
+}
+
+static int32_t mt9t013_i2c_write_w_table(
+	struct mt9t013_i2c_reg_conf const *reg_conf_tbl,
+	int num_of_items_in_table)
+{
+	int i;
+	int32_t rc = -EIO;
+
+	for (i = 0; i < num_of_items_in_table; i++) {
+		rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+			reg_conf_tbl->waddr, reg_conf_tbl->wdata);
+		if (rc < 0)
+			break;
+		reg_conf_tbl++;
+	}
+
+	return rc;
+}
+
+static int32_t mt9t013_test(enum mt9t013_test_mode mo)
+{
+	int32_t rc = 0;
+
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+			REG_GROUPED_PARAMETER_HOLD,
+			GROUPED_PARAMETER_HOLD);
+	if (rc < 0)
+		return rc;
+
+	if (mo == TEST_OFF)
+		return 0;
+	else {
+		rc = mt9t013_i2c_write_w_table(mt9t013_regs.ttbl,
+				mt9t013_regs.ttbl_size);
+		if (rc < 0)
+			return rc;
+		rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_TEST_PATTERN_MODE, (uint16_t)mo);
+		if (rc < 0)
+			return rc;
+	}
+
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+			REG_GROUPED_PARAMETER_HOLD,
+			GROUPED_PARAMETER_UPDATE);
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+
+static int32_t mt9t013_set_lc(void)
+{
+	int32_t rc;
+
+	rc = mt9t013_i2c_write_w_table(mt9t013_regs.lctbl,
+		mt9t013_regs.lctbl_size);
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+
+static int32_t mt9t013_set_default_focus(uint8_t af_step)
+{
+	int32_t rc = 0;
+	uint8_t code_val_msb, code_val_lsb;
+	code_val_msb = 0x01;
+	code_val_lsb = af_step;
+
+	/* Write the digital code for current to the actuator */
+	rc = mt9t013_i2c_write_b(MT9T013_AF_I2C_ADDR>>1,
+			code_val_msb, code_val_lsb);
+
+	mt9t013_ctrl->curr_lens_pos = 0;
+	mt9t013_ctrl->init_curr_lens_pos = 0;
+	return rc;
+}
+
+static void mt9t013_get_pict_fps(uint16_t fps, uint16_t *pfps)
+{
+	/* input fps is preview fps in Q8 format */
+	uint32_t divider;   /*Q10 */
+	uint32_t pclk_mult; /*Q10 */
+	uint32_t d1;
+	uint32_t d2;
+
+	d1 =
+		(uint32_t)(
+		(mt9t013_regs.reg_pat[RES_PREVIEW].frame_length_lines *
+		0x00000400) /
+		mt9t013_regs.reg_pat[RES_CAPTURE].frame_length_lines);
+
+	d2 =
+		(uint32_t)(
+		(mt9t013_regs.reg_pat[RES_PREVIEW].line_length_pck *
+		0x00000400) /
+		mt9t013_regs.reg_pat[RES_CAPTURE].line_length_pck);
+
+	divider = (uint32_t) (d1 * d2) / 0x00000400;
+
+	pclk_mult =
+		(uint32_t) ((mt9t013_regs.reg_pat[RES_CAPTURE].pll_multiplier *
+		0x00000400) /
+		(mt9t013_regs.reg_pat[RES_PREVIEW].pll_multiplier));
+
+
+	/* Verify PCLK settings and frame sizes. */
+	*pfps =
+		(uint16_t) (fps * divider * pclk_mult /
+		0x00000400 / 0x00000400);
+}
+
+static uint16_t mt9t013_get_prev_lines_pf(void)
+{
+	if (mt9t013_ctrl->prev_res == QTR_SIZE)
+		return mt9t013_regs.reg_pat[RES_PREVIEW].frame_length_lines;
+	else
+		return mt9t013_regs.reg_pat[RES_CAPTURE].frame_length_lines;
+}
+
+static uint16_t mt9t013_get_prev_pixels_pl(void)
+{
+	if (mt9t013_ctrl->prev_res == QTR_SIZE)
+		return mt9t013_regs.reg_pat[RES_PREVIEW].line_length_pck;
+	else
+		return mt9t013_regs.reg_pat[RES_CAPTURE].line_length_pck;
+}
+
+static uint16_t mt9t013_get_pict_lines_pf(void)
+{
+	return mt9t013_regs.reg_pat[RES_CAPTURE].frame_length_lines;
+}
+
+static uint16_t mt9t013_get_pict_pixels_pl(void)
+{
+	return mt9t013_regs.reg_pat[RES_CAPTURE].line_length_pck;
+}
+
+static uint32_t mt9t013_get_pict_max_exp_lc(void)
+{
+	uint16_t snapshot_lines_per_frame;
+
+	if (mt9t013_ctrl->pict_res == QTR_SIZE) {
+		snapshot_lines_per_frame =
+		mt9t013_regs.reg_pat[RES_PREVIEW].frame_length_lines - 1;
+	} else  {
+		snapshot_lines_per_frame =
+		mt9t013_regs.reg_pat[RES_CAPTURE].frame_length_lines - 1;
+	}
+
+	return snapshot_lines_per_frame * 24;
+}
+
+static int32_t mt9t013_set_fps(struct fps_cfg *fps)
+{
+	/* input is new fps in Q8 format */
+	int32_t rc = 0;
+	enum mt9t013_setting setting;
+
+	mt9t013_ctrl->fps_divider = fps->fps_div;
+	mt9t013_ctrl->pict_fps_divider = fps->pict_fps_div;
+
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+			REG_GROUPED_PARAMETER_HOLD,
+			GROUPED_PARAMETER_HOLD);
+	if (rc < 0)
+		return -EBUSY;
+
+	CDBG("mt9t013_set_fps: fps_div is %d, f_mult is %d\n",
+			fps->fps_div, fps->f_mult);
+
+	if (mt9t013_ctrl->sensormode == SENSOR_PREVIEW_MODE)
+		setting = RES_PREVIEW;
+	else
+		setting = RES_CAPTURE;
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+			REG_FRAME_LENGTH_LINES,
+			(uint16_t) (
+			mt9t013_regs.reg_pat[setting].frame_length_lines *
+			fps->fps_div / 0x00000400));
+
+	if (rc < 0)
+		return rc;
+
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+			REG_GROUPED_PARAMETER_HOLD,
+			GROUPED_PARAMETER_UPDATE);
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+
+static int32_t mt9t013_write_exp_gain(uint16_t gain, uint32_t line)
+{
+	uint16_t max_legal_gain = 0x01FF;
+	int32_t rc = 0;
+
+	if (mt9t013_ctrl->sensormode == SENSOR_PREVIEW_MODE) {
+		mt9t013_ctrl->my_reg_gain = gain;
+		mt9t013_ctrl->my_reg_line_count = (uint16_t) line;
+	}
+
+	if (gain > max_legal_gain)
+		gain = max_legal_gain;
+
+	if (mt9t013_ctrl->sensormode != SENSOR_SNAPSHOT_MODE)
+		line = (uint32_t) (line * mt9t013_ctrl->fps_divider /
+				   0x00000400);
+	else
+		line = (uint32_t) (line * mt9t013_ctrl->pict_fps_divider /
+				   0x00000400);
+
+	/*Set digital gain to 1 */
+	gain |= 0x0200;
+
+	/* There used to be PARAMETER_HOLD register write before and
+	 * after REG_GLOBAL_GAIN & REG_COARSE_INIT_TIME. This causes
+	 * aec oscillation. Hence removed. */
+
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr, REG_GLOBAL_GAIN, gain);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+			REG_COARSE_INT_TIME, line);
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+
+static int32_t mt9t013_set_pict_exp_gain(uint16_t gain, uint32_t line)
+{
+	int32_t rc = 0;
+
+	rc = mt9t013_write_exp_gain(gain, line);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+			MT9T013_REG_RESET_REGISTER,
+			0x10CC | 0x0002);
+
+	mdelay(5);
+
+	return rc;
+}
+
+static int32_t mt9t013_setting(enum mt9t013_reg_update rupdate,
+	enum mt9t013_setting rt)
+{
+	int32_t rc = 0;
+
+	switch (rupdate) {
+	case UPDATE_PERIODIC: {
+
+	if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+#if 0
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				MT9T013_REG_RESET_REGISTER,
+				MT9T013_RESET_REGISTER_PWOFF);
+		if (rc < 0)
+			return rc;
+#endif
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_VT_PIX_CLK_DIV,
+				mt9t013_regs.reg_pat[rt].vt_pix_clk_div);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_VT_SYS_CLK_DIV,
+				mt9t013_regs.reg_pat[rt].vt_sys_clk_div);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_PRE_PLL_CLK_DIV,
+				mt9t013_regs.reg_pat[rt].pre_pll_clk_div);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_PLL_MULTIPLIER,
+				mt9t013_regs.reg_pat[rt].pll_multiplier);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_OP_PIX_CLK_DIV,
+				mt9t013_regs.reg_pat[rt].op_pix_clk_div);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_OP_SYS_CLK_DIV,
+				mt9t013_regs.reg_pat[rt].op_sys_clk_div);
+		if (rc < 0)
+			return rc;
+
+		mdelay(5);
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_GROUPED_PARAMETER_HOLD,
+				GROUPED_PARAMETER_HOLD);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_ROW_SPEED,
+				mt9t013_regs.reg_pat[rt].row_speed);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_X_ADDR_START,
+				mt9t013_regs.reg_pat[rt].x_addr_start);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_X_ADDR_END,
+				mt9t013_regs.reg_pat[rt].x_addr_end);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_Y_ADDR_START,
+				mt9t013_regs.reg_pat[rt].y_addr_start);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_Y_ADDR_END,
+				mt9t013_regs.reg_pat[rt].y_addr_end);
+		if (rc < 0)
+			return rc;
+
+		if (machine_is_sapphire()) {
+			if (rt == 0)
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+					REG_READ_MODE,
+					0x046F);
+			else
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+					REG_READ_MODE,
+					0x0027);
+		} else
+			rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+					REG_READ_MODE,
+					mt9t013_regs.reg_pat[rt].read_mode);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_SCALE_M,
+				mt9t013_regs.reg_pat[rt].scale_m);
+		if (rc < 0)
+			return rc;
+
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_X_OUTPUT_SIZE,
+				mt9t013_regs.reg_pat[rt].x_output_size);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_Y_OUTPUT_SIZE,
+				mt9t013_regs.reg_pat[rt].y_output_size);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_LINE_LENGTH_PCK,
+				mt9t013_regs.reg_pat[rt].line_length_pck);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+			REG_FRAME_LENGTH_LINES,
+			(mt9t013_regs.reg_pat[rt].frame_length_lines *
+			mt9t013_ctrl->fps_divider / 0x00000400));
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+			REG_COARSE_INT_TIME,
+			mt9t013_regs.reg_pat[rt].coarse_int_time);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+			REG_FINE_INT_TIME,
+			mt9t013_regs.reg_pat[rt].fine_int_time);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+			REG_GROUPED_PARAMETER_HOLD,
+			GROUPED_PARAMETER_UPDATE);
+		if (rc < 0)
+			return rc;
+
+		rc = mt9t013_test(mt9t013_ctrl->set_test);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+			MT9T013_REG_RESET_REGISTER,
+			MT9T013_RESET_REGISTER_PWON|
+			MT9T013_RESET_FAST_TRANSITION);
+		if (rc < 0)
+			return rc;
+
+		mdelay(5);
+
+		return rc;
+	}
+	}
+		break;
+
+	/*CAMSENSOR_REG_UPDATE_PERIODIC */
+	case REG_INIT: {
+	if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				MT9T013_REG_RESET_REGISTER,
+				MT9T013_RESET_REGISTER_PWOFF);
+		if (rc < 0)
+			/* MODE_SELECT, stop streaming */
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_VT_PIX_CLK_DIV,
+				mt9t013_regs.reg_pat[rt].vt_pix_clk_div);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_VT_SYS_CLK_DIV,
+				mt9t013_regs.reg_pat[rt].vt_sys_clk_div);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_PRE_PLL_CLK_DIV,
+				mt9t013_regs.reg_pat[rt].pre_pll_clk_div);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_PLL_MULTIPLIER,
+				mt9t013_regs.reg_pat[rt].pll_multiplier);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_OP_PIX_CLK_DIV,
+				mt9t013_regs.reg_pat[rt].op_pix_clk_div);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_OP_SYS_CLK_DIV,
+				mt9t013_regs.reg_pat[rt].op_sys_clk_div);
+		if (rc < 0)
+			return rc;
+
+		mdelay(5);
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_GROUPED_PARAMETER_HOLD,
+				GROUPED_PARAMETER_HOLD);
+		if (rc < 0)
+			return rc;
+
+		/* additional power saving mode ok around 38.2MHz */
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				0x3084, 0x2409);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				0x3092, 0x0A49);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				0x3094, 0x4949);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				0x3096, 0x4949);
+		if (rc < 0)
+			return rc;
+
+		/* Set preview or snapshot mode */
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_ROW_SPEED,
+				mt9t013_regs.reg_pat[rt].row_speed);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_X_ADDR_START,
+				mt9t013_regs.reg_pat[rt].x_addr_start);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_X_ADDR_END,
+				mt9t013_regs.reg_pat[rt].x_addr_end);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_Y_ADDR_START,
+				mt9t013_regs.reg_pat[rt].y_addr_start);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_Y_ADDR_END,
+				mt9t013_regs.reg_pat[rt].y_addr_end);
+		if (rc < 0)
+			return rc;
+
+		if (machine_is_sapphire()) {
+			if (rt == 0)
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+					REG_READ_MODE,
+					0x046F);
+			else
+				rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+					REG_READ_MODE,
+					0x0027);
+		} else
+			rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+					REG_READ_MODE,
+					mt9t013_regs.reg_pat[rt].read_mode);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_SCALE_M,
+				mt9t013_regs.reg_pat[rt].scale_m);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_X_OUTPUT_SIZE,
+				mt9t013_regs.reg_pat[rt].x_output_size);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_Y_OUTPUT_SIZE,
+				mt9t013_regs.reg_pat[rt].y_output_size);
+		if (rc < 0)
+			return 0;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_LINE_LENGTH_PCK,
+				mt9t013_regs.reg_pat[rt].line_length_pck);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_FRAME_LENGTH_LINES,
+				mt9t013_regs.reg_pat[rt].frame_length_lines);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_COARSE_INT_TIME,
+				mt9t013_regs.reg_pat[rt].coarse_int_time);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_FINE_INT_TIME,
+				mt9t013_regs.reg_pat[rt].fine_int_time);
+		if (rc < 0)
+			return rc;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_GROUPED_PARAMETER_HOLD,
+				GROUPED_PARAMETER_UPDATE);
+			if (rc < 0)
+				return rc;
+
+		/* load lens shading */
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_GROUPED_PARAMETER_HOLD,
+				GROUPED_PARAMETER_HOLD);
+		if (rc < 0)
+			return rc;
+
+		/* most likely needs to be written only once. */
+		rc = mt9t013_set_lc();
+		if (rc < 0)
+			return -EBUSY;
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_GROUPED_PARAMETER_HOLD,
+				GROUPED_PARAMETER_UPDATE);
+		if (rc < 0)
+			return rc;
+
+		rc = mt9t013_test(mt9t013_ctrl->set_test);
+		if (rc < 0)
+			return rc;
+
+		mdelay(5);
+
+		rc =
+			mt9t013_i2c_write_w(mt9t013_client->addr,
+				MT9T013_REG_RESET_REGISTER,
+				MT9T013_RESET_REGISTER_PWON);
+		if (rc < 0)
+			/* MODE_SELECT, stop streaming */
+			return rc;
+
+		CDBG("!!! mt9t013 !!! PowerOn is done!\n");
+		mdelay(5);
+		return rc;
+		}
+	} /* case CAMSENSOR_REG_INIT: */
+	break;
+
+	/*CAMSENSOR_REG_INIT */
+	default:
+		rc = -EINVAL;
+		break;
+	} /* switch (rupdate) */
+
+	return rc;
+}
+
+static int32_t mt9t013_video_config(int mode, int res)
+{
+	int32_t rc;
+
+	switch (res) {
+	case QTR_SIZE:
+		rc = mt9t013_setting(UPDATE_PERIODIC, RES_PREVIEW);
+		if (rc < 0)
+			return rc;
+		CDBG("sensor configuration done!\n");
+		break;
+
+	case FULL_SIZE:
+		rc = mt9t013_setting(UPDATE_PERIODIC, RES_CAPTURE);
+		if (rc < 0)
+			return rc;
+		break;
+
+	default:
+		return -EINVAL;
+	} /* switch */
+
+	mt9t013_ctrl->prev_res = res;
+	mt9t013_ctrl->curr_res = res;
+	mt9t013_ctrl->sensormode = mode;
+
+	rc = mt9t013_write_exp_gain(mt9t013_ctrl->my_reg_gain,
+			mt9t013_ctrl->my_reg_line_count);
+	if (rc < 0)
+		return rc;
+
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+		MT9T013_REG_RESET_REGISTER,
+		MT9T013_RESET_REGISTER_PWON|MT9T013_RESET_FAST_TRANSITION);
+	if (rc < 0)
+		return rc;
+
+	msleep(5);
+	return rc;
+}
+
+static int32_t mt9t013_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+
+	rc = mt9t013_setting(UPDATE_PERIODIC, RES_CAPTURE);
+	if (rc < 0)
+		return rc;
+
+	mt9t013_ctrl->curr_res = mt9t013_ctrl->pict_res;
+	mt9t013_ctrl->sensormode = mode;
+	return rc;
+}
+
+static int32_t mt9t013_raw_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+
+	rc = mt9t013_setting(UPDATE_PERIODIC, RES_CAPTURE);
+	if (rc < 0)
+		return rc;
+
+	mt9t013_ctrl->curr_res = mt9t013_ctrl->pict_res;
+	mt9t013_ctrl->sensormode = mode;
+	return rc;
+}
+
+static int32_t mt9t013_power_down(void)
+{
+	int32_t rc = 0;
+
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+			MT9T013_REG_RESET_REGISTER,
+			MT9T013_RESET_REGISTER_PWOFF);
+	if (rc >= 0)
+		mdelay(5);
+	return rc;
+}
+
+static int32_t mt9t013_move_focus(int direction, int32_t num_steps)
+{
+	int16_t step_direction;
+	int16_t actual_step;
+	int16_t next_position;
+	int16_t break_steps[4];
+	uint8_t code_val_msb, code_val_lsb;
+	int16_t i;
+
+	if (num_steps > MT9T013_TOTAL_STEPS_NEAR_TO_FAR)
+		num_steps = MT9T013_TOTAL_STEPS_NEAR_TO_FAR;
+	else if (num_steps == 0)
+		return -EINVAL;
+
+	if (direction == MOVE_NEAR)
+		step_direction = 4;
+	else if (direction == MOVE_FAR)
+		step_direction = -4;
+	else
+		return -EINVAL;
+
+	if (mt9t013_ctrl->curr_lens_pos < mt9t013_ctrl->init_curr_lens_pos)
+		mt9t013_ctrl->curr_lens_pos = mt9t013_ctrl->init_curr_lens_pos;
+
+	actual_step =
+		(int16_t) (step_direction *
+		(int16_t) num_steps);
+
+	for (i = 0; i < 4; i++)
+		break_steps[i] =
+			actual_step / 4 * (i + 1) - actual_step / 4 * i;
+
+	for (i = 0; i < 4; i++) {
+		next_position =
+		(int16_t)
+		(mt9t013_ctrl->curr_lens_pos + break_steps[i]);
+
+		if (next_position > 255)
+			next_position = 255;
+		else if (next_position < 0)
+			next_position = 0;
+
+		code_val_msb =
+		((next_position >> 4) << 2) |
+		((next_position << 4) >> 6);
+
+		code_val_lsb =
+		((next_position & 0x03) << 6);
+
+		/* Writing the digital code for current to the actuator */
+		if (mt9t013_i2c_write_b(MT9T013_AF_I2C_ADDR>>1,
+				code_val_msb, code_val_lsb) < 0)
+			return -EBUSY;
+
+		/* Storing the current lens Position */
+		mt9t013_ctrl->curr_lens_pos = next_position;
+
+		if (i < 3)
+			mdelay(1);
+	} /* for */
+
+	return 0;
+}
+
+static int mt9t013_sensor_init_done(const struct msm_camera_sensor_info *data)
+{
+	gpio_direction_output(data->sensor_reset, 0);
+	gpio_free(data->sensor_reset);
+	return 0;
+}
+
+static int mt9t013_probe_init_sensor(const struct msm_camera_sensor_info *data)
+{
+	int rc;
+	uint16_t chipid;
+
+	rc = gpio_request(data->sensor_reset, "mt9t013");
+	if (!rc)
+		gpio_direction_output(data->sensor_reset, 1);
+	else
+		goto init_probe_done;
+
+	mdelay(20);
+
+	/* RESET the sensor image part via I2C command */
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+		MT9T013_REG_RESET_REGISTER, 0x1009);
+	if (rc < 0)
+		goto init_probe_fail;
+
+	msleep(10);
+
+	/* 3. Read sensor Model ID: */
+	rc = mt9t013_i2c_read_w(mt9t013_client->addr,
+		MT9T013_REG_MODEL_ID, &chipid);
+
+	if (rc < 0)
+		goto init_probe_fail;
+
+	CDBG("mt9t013 model_id = 0x%x\n", chipid);
+
+	/* 4. Compare sensor ID to MT9T012VC ID: */
+	if (chipid != MT9T013_MODEL_ID) {
+		rc = -ENODEV;
+		goto init_probe_fail;
+	}
+
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+		0x3064, 0x0805);
+	if (rc < 0)
+		goto init_probe_fail;
+
+	mdelay(MT9T013_RESET_DELAY_MSECS);
+
+	goto init_probe_done;
+
+	/* sensor: output enable */
+#if 0
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+		MT9T013_REG_RESET_REGISTER,
+		MT9T013_RESET_REGISTER_PWON);
+
+	/* if this fails, the sensor is not the MT9T013 */
+	rc = mt9t013_set_default_focus(0);
+#endif
+
+init_probe_fail:
+	gpio_direction_output(data->sensor_reset, 0);
+	gpio_free(data->sensor_reset);
+init_probe_done:
+	return rc;
+}
+
+static int32_t mt9t013_poweron_af(void)
+{
+	int32_t rc = 0;
+
+	/* enable AF actuator */
+	CDBG("enable AF actuator, gpio = %d\n",
+			mt9t013_ctrl->sensordata->vcm_pwd);
+	rc = gpio_request(mt9t013_ctrl->sensordata->vcm_pwd, "mt9t013");
+	if (!rc) {
+		gpio_direction_output(mt9t013_ctrl->sensordata->vcm_pwd, 0);
+		mdelay(20);
+		rc = mt9t013_set_default_focus(0);
+	} else
+		pr_err("%s, gpio_request failed (%d)!\n", __func__, rc);
+	return rc;
+}
+
+static void mt9t013_poweroff_af(void)
+{
+	gpio_direction_output(mt9t013_ctrl->sensordata->vcm_pwd, 1);
+	gpio_free(mt9t013_ctrl->sensordata->vcm_pwd);
+}
+
+int mt9t013_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+	int32_t  rc;
+
+	mt9t013_ctrl = kzalloc(sizeof(struct mt9t013_ctrl), GFP_KERNEL);
+	if (!mt9t013_ctrl) {
+		pr_err("mt9t013_init failed!\n");
+		rc = -ENOMEM;
+		goto init_done;
+	}
+
+	mt9t013_ctrl->fps_divider = 1 * 0x00000400;
+	mt9t013_ctrl->pict_fps_divider = 1 * 0x00000400;
+	mt9t013_ctrl->set_test = TEST_OFF;
+	mt9t013_ctrl->prev_res = QTR_SIZE;
+	mt9t013_ctrl->pict_res = FULL_SIZE;
+
+	if (data)
+		mt9t013_ctrl->sensordata = data;
+
+	/* enable mclk first */
+	msm_camio_clk_rate_set(MT9T013_DEFAULT_CLOCK_RATE);
+	mdelay(20);
+
+	msm_camio_camif_pad_reg_reset();
+	mdelay(20);
+
+	rc = mt9t013_probe_init_sensor(data);
+	if (rc < 0)
+		goto init_fail;
+
+	if (mt9t013_ctrl->prev_res == QTR_SIZE)
+		rc = mt9t013_setting(REG_INIT, RES_PREVIEW);
+	else
+		rc = mt9t013_setting(REG_INIT, RES_CAPTURE);
+
+	if (rc >= 0)
+		if (machine_is_sapphire())
+			rc = mt9t013_poweron_af();
+
+	if (rc < 0)
+		goto init_fail;
+	else
+		goto init_done;
+
+init_fail:
+	kfree(mt9t013_ctrl);
+init_done:
+	return rc;
+}
+
+static int mt9t013_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&mt9t013_wait_queue);
+	return 0;
+}
+
+
+static int32_t mt9t013_set_sensor_mode(int mode, int res)
+{
+	int32_t rc = 0;
+	rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+			REG_GROUPED_PARAMETER_HOLD,
+			GROUPED_PARAMETER_HOLD);
+	if (rc < 0)
+		return rc;
+
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		rc = mt9t013_video_config(mode, res);
+		break;
+
+	case SENSOR_SNAPSHOT_MODE:
+		rc = mt9t013_snapshot_config(mode);
+		break;
+
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		rc = mt9t013_raw_snapshot_config(mode);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* FIXME: what should we do if rc < 0? */
+	if (rc >= 0)
+		return mt9t013_i2c_write_w(mt9t013_client->addr,
+				REG_GROUPED_PARAMETER_HOLD,
+				GROUPED_PARAMETER_UPDATE);
+	return rc;
+}
+
+int mt9t013_sensor_config(void __user *argp)
+{
+	struct sensor_cfg_data cdata;
+	long   rc = 0;
+
+	if (copy_from_user(&cdata, (void *)argp,
+			sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+
+	down(&mt9t013_sem);
+
+	CDBG("mt9t013_sensor_config: cfgtype = %d\n", cdata.cfgtype);
+	switch (cdata.cfgtype) {
+	case CFG_GET_PICT_FPS:
+		mt9t013_get_pict_fps(cdata.cfg.gfps.prevfps,
+				&(cdata.cfg.gfps.pictfps));
+		if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PREV_L_PF:
+		cdata.cfg.prevl_pf = mt9t013_get_prev_lines_pf();
+		if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PREV_P_PL:
+		cdata.cfg.prevp_pl = mt9t013_get_prev_pixels_pl();
+		if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_L_PF:
+		cdata.cfg.pictl_pf = mt9t013_get_pict_lines_pf();
+		if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_P_PL:
+		cdata.cfg.pictp_pl =
+			mt9t013_get_pict_pixels_pl();
+
+		if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_MAX_EXP_LC:
+		cdata.cfg.pict_max_exp_lc =
+			mt9t013_get_pict_max_exp_lc();
+
+		if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_SET_FPS:
+	case CFG_SET_PICT_FPS:
+		rc = mt9t013_set_fps(&(cdata.cfg.fps));
+		break;
+
+	case CFG_SET_EXP_GAIN:
+		rc = mt9t013_write_exp_gain(cdata.cfg.exp_gain.gain,
+				cdata.cfg.exp_gain.line);
+		break;
+
+	case CFG_SET_PICT_EXP_GAIN:
+		rc = mt9t013_set_pict_exp_gain(cdata.cfg.exp_gain.gain,
+				cdata.cfg.exp_gain.line);
+		break;
+
+	case CFG_SET_MODE:
+		rc = mt9t013_set_sensor_mode(cdata.mode, cdata.rs);
+		break;
+
+	case CFG_PWR_DOWN:
+		rc = mt9t013_power_down();
+		break;
+
+	case CFG_MOVE_FOCUS:
+		rc = mt9t013_move_focus(cdata.cfg.focus.dir,
+				cdata.cfg.focus.steps);
+		break;
+
+	case CFG_SET_DEFAULT_FOCUS:
+		rc = mt9t013_set_default_focus(cdata.cfg.focus.steps);
+		break;
+
+	case CFG_GET_AF_MAX_STEPS:
+		cdata.max_steps = MT9T013_TOTAL_STEPS_NEAR_TO_FAR;
+		if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_SET_EFFECT:
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	up(&mt9t013_sem);
+	return rc;
+}
+
+int mt9t013_sensor_release(void)
+{
+	int rc = -EBADF;
+
+	down(&mt9t013_sem);
+
+	if (machine_is_sapphire())
+		mt9t013_poweroff_af();
+	mt9t013_power_down();
+
+	gpio_direction_output(mt9t013_ctrl->sensordata->sensor_reset,
+			0);
+	gpio_free(mt9t013_ctrl->sensordata->sensor_reset);
+
+	kfree(mt9t013_ctrl);
+
+	up(&mt9t013_sem);
+	CDBG("mt9t013_release completed!\n");
+	return rc;
+}
+
+static int mt9t013_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int rc = 0;
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		rc = -ENOTSUPP;
+		goto probe_failure;
+	}
+
+	mt9t013_sensorw =
+		kzalloc(sizeof(struct mt9t013_work), GFP_KERNEL);
+
+	if (!mt9t013_sensorw) {
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, mt9t013_sensorw);
+	mt9t013_init_client(client);
+	mt9t013_client = client;
+	mt9t013_client->addr = mt9t013_client->addr >> 1;
+	mdelay(50);
+
+	CDBG("i2c probe ok\n");
+	return 0;
+
+probe_failure:
+	kfree(mt9t013_sensorw);
+	mt9t013_sensorw = NULL;
+	pr_err("i2c probe failure %d\n", rc);
+	return rc;
+}
+
+static const struct i2c_device_id mt9t013_i2c_id[] = {
+	{ "mt9t013", 0},
+	{ }
+};
+
+static struct i2c_driver mt9t013_i2c_driver = {
+	.id_table = mt9t013_i2c_id,
+	.probe  = mt9t013_i2c_probe,
+	.remove = __exit_p(mt9t013_i2c_remove),
+	.driver = {
+		.name = "mt9t013",
+	},
+};
+
+static int mt9t013_sensor_probe(
+		const struct msm_camera_sensor_info *info,
+		struct msm_sensor_ctrl *s)
+{
+	/* We expect this driver to match with the i2c device registered
+	 * in the board file immediately. */
+	int rc = i2c_add_driver(&mt9t013_i2c_driver);
+	if (rc < 0 || mt9t013_client == NULL) {
+		rc = -ENOTSUPP;
+		goto probe_done;
+	}
+
+	/* enable mclk first */
+	msm_camio_clk_rate_set(MT9T013_DEFAULT_CLOCK_RATE);
+	mdelay(20);
+
+	rc = mt9t013_probe_init_sensor(info);
+	if (rc < 0) {
+		i2c_del_driver(&mt9t013_i2c_driver);
+		goto probe_done;
+	}
+
+	s->s_init = mt9t013_sensor_open_init;
+	s->s_release = mt9t013_sensor_release;
+	s->s_config  = mt9t013_sensor_config;
+	s->s_mount_angle = 0;
+	mt9t013_sensor_init_done(info);
+
+probe_done:
+	return rc;
+}
+
+static int __mt9t013_probe(struct platform_device *pdev)
+{
+	return msm_camera_drv_start(pdev, mt9t013_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = __mt9t013_probe,
+	.driver = {
+		.name = "msm_camera_mt9t013",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init mt9t013_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(mt9t013_init);
diff --git a/drivers/media/video/msm/mt9t013.h b/drivers/media/video/msm/mt9t013.h
new file mode 100644
index 0000000..f6b7c28
--- /dev/null
+++ b/drivers/media/video/msm/mt9t013.h
@@ -0,0 +1,59 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#ifndef MT9T013_H
+#define MT9T013_H
+
+#include <linux/types.h>
+
+extern struct mt9t013_reg mt9t013_regs; /* from mt9t013_reg.c */
+
+struct reg_struct {
+	uint16_t vt_pix_clk_div;        /*  0x0300 */
+	uint16_t vt_sys_clk_div;        /*  0x0302 */
+	uint16_t pre_pll_clk_div;       /*  0x0304 */
+	uint16_t pll_multiplier;        /*  0x0306 */
+	uint16_t op_pix_clk_div;        /*  0x0308 */
+	uint16_t op_sys_clk_div;        /*  0x030A */
+	uint16_t scale_m;               /*  0x0404 */
+	uint16_t row_speed;             /*  0x3016 */
+	uint16_t x_addr_start;          /*  0x3004 */
+	uint16_t x_addr_end;            /*  0x3008 */
+	uint16_t y_addr_start;        	/*  0x3002 */
+	uint16_t y_addr_end;            /*  0x3006 */
+	uint16_t read_mode;             /*  0x3040 */
+	uint16_t x_output_size;         /*  0x034C */
+	uint16_t y_output_size;         /*  0x034E */
+	uint16_t line_length_pck;       /*  0x300C */
+	uint16_t frame_length_lines;	/*  0x300A */
+	uint16_t coarse_int_time; 		/*  0x3012 */
+	uint16_t fine_int_time;   		/*  0x3014 */
+};
+
+struct mt9t013_i2c_reg_conf {
+	unsigned short waddr;
+	unsigned short wdata;
+};
+
+struct mt9t013_reg {
+	struct reg_struct const *reg_pat;
+	uint16_t reg_pat_size;
+	struct mt9t013_i2c_reg_conf const *ttbl;
+	uint16_t ttbl_size;
+	struct mt9t013_i2c_reg_conf const *lctbl;
+	uint16_t lctbl_size;
+	struct mt9t013_i2c_reg_conf const *rftbl;
+	uint16_t rftbl_size;
+};
+
+#endif /* #define MT9T013_H */
diff --git a/drivers/media/video/msm/mt9t013_reg.c b/drivers/media/video/msm/mt9t013_reg.c
new file mode 100644
index 0000000..9a9867e
--- /dev/null
+++ b/drivers/media/video/msm/mt9t013_reg.c
@@ -0,0 +1,275 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include "mt9t013.h"
+#include <linux/kernel.h>
+
+struct reg_struct const mt9t013_reg_pat[2] = {
+	{ /* Preview 2x2 binning 20fps, pclk MHz, MCLK 24MHz */
+	/* vt_pix_clk_div:REG=0x0300 update get_snapshot_fps
+	* if this change */
+	8,
+
+	/* vt_sys_clk_div: REG=0x0302  update get_snapshot_fps
+	* if this change */
+	1,
+
+	/* pre_pll_clk_div REG=0x0304  update get_snapshot_fps
+	* if this change */
+	2,
+
+	/* pll_multiplier  REG=0x0306 60 for 30fps preview, 40
+	 * for 20fps preview
+	 * 46 for 30fps preview, try 47/48 to increase further */
+	46,
+
+	/* op_pix_clk_div        REG=0x0308 */
+	8,
+
+	/* op_sys_clk_div        REG=0x030A */
+	1,
+
+	/* scale_m       REG=0x0404 */
+	16,
+
+	/* row_speed     REG=0x3016 */
+	0x0111,
+
+	/* x_addr_start  REG=0x3004 */
+	8,
+
+	/* x_addr_end    REG=0x3008 */
+	2053,
+
+	/* y_addr_start  REG=0x3002 */
+	8,
+
+	/* y_addr_end    REG=0x3006 */
+	1541,
+
+	/* read_mode     REG=0x3040 */
+	0x046C,
+
+	/* x_output_size REG=0x034C */
+	1024,
+
+	/* y_output_size REG=0x034E */
+	768,
+
+	/* line_length_pck    REG=0x300C */
+	2616,
+
+	/* frame_length_lines REG=0x300A */
+	916,
+
+	/* coarse_int_time REG=0x3012 */
+	16,
+
+	/* fine_int_time   REG=0x3014 */
+	1461
+	},
+	{ /*Snapshot */
+	/* vt_pix_clk_div  REG=0x0300 update get_snapshot_fps
+	* if this change */
+	8,
+
+	/* vt_sys_clk_div  REG=0x0302 update get_snapshot_fps
+	* if this change */
+	1,
+
+	/* pre_pll_clk_div REG=0x0304 update get_snapshot_fps
+	 * if this change */
+	2,
+
+	/* pll_multiplier REG=0x0306 50 for 15fps snapshot,
+	 * 40 for 10fps snapshot
+	 * 46 for 30fps snapshot, try 47/48 to increase further */
+	46,
+
+	/* op_pix_clk_div        REG=0x0308 */
+	8,
+
+	/* op_sys_clk_div        REG=0x030A */
+	1,
+
+	/* scale_m       REG=0x0404 */
+	16,
+
+	/* row_speed     REG=0x3016 */
+	0x0111,
+
+	/* x_addr_start  REG=0x3004 */
+	8,
+
+	/* x_addr_end    REG=0x3008 */
+	2071,
+
+	/* y_addr_start  REG=0x3002 */
+	8,
+
+	/* y_addr_end    REG=0x3006 */
+	1551,
+
+	/* read_mode     REG=0x3040 */
+	0x0024,
+
+	/* x_output_size REG=0x034C */
+	2064,
+
+	/* y_output_size REG=0x034E */
+	1544,
+
+	/* line_length_pck REG=0x300C */
+	2952,
+
+	/* frame_length_lines    REG=0x300A */
+	1629,
+
+	/* coarse_int_time REG=0x3012 */
+	16,
+
+	/* fine_int_time REG=0x3014   */
+	733
+	}
+};
+
+struct mt9t013_i2c_reg_conf const mt9t013_test_tbl[] = {
+	{ 0x3044, 0x0544 & 0xFBFF },
+	{ 0x30CA, 0x0004 | 0x0001 },
+	{ 0x30D4, 0x9020 & 0x7FFF },
+	{ 0x31E0, 0x0003 & 0xFFFE },
+	{ 0x3180, 0x91FF & 0x7FFF },
+	{ 0x301A, (0x10CC | 0x8000) & 0xFFF7 },
+	{ 0x301E, 0x0000 },
+	{ 0x3780, 0x0000 },
+};
+
+/* [Lens shading 85 Percent TL84] */
+struct mt9t013_i2c_reg_conf const mt9t013_lc_tbl[] = {
+	{ 0x360A, 0x0290 }, /* P_RD_P0Q0 */
+	{ 0x360C, 0xC92D }, /* P_RD_P0Q1 */
+	{ 0x360E, 0x0771 }, /* P_RD_P0Q2 */
+	{ 0x3610, 0xE38C }, /* P_RD_P0Q3 */
+	{ 0x3612, 0xD74F }, /* P_RD_P0Q4 */
+	{ 0x364A, 0x168C }, /* P_RD_P1Q0 */
+	{ 0x364C, 0xCACB }, /* P_RD_P1Q1 */
+	{ 0x364E, 0x8C4C }, /* P_RD_P1Q2 */
+	{ 0x3650, 0x0BEA }, /* P_RD_P1Q3 */
+	{ 0x3652, 0xDC0F }, /* P_RD_P1Q4 */
+	{ 0x368A, 0x70B0 }, /* P_RD_P2Q0 */
+	{ 0x368C, 0x200B }, /* P_RD_P2Q1 */
+	{ 0x368E, 0x30B2 }, /* P_RD_P2Q2 */
+	{ 0x3690, 0xD04F }, /* P_RD_P2Q3 */
+	{ 0x3692, 0xACF5 }, /* P_RD_P2Q4 */
+	{ 0x36CA, 0xF7C9 }, /* P_RD_P3Q0 */
+	{ 0x36CC, 0x2AED }, /* P_RD_P3Q1 */
+	{ 0x36CE, 0xA652 }, /* P_RD_P3Q2 */
+	{ 0x36D0, 0x8192 }, /* P_RD_P3Q3 */
+	{ 0x36D2, 0x3A15 }, /* P_RD_P3Q4 */
+	{ 0x370A, 0xDA30 }, /* P_RD_P4Q0 */
+	{ 0x370C, 0x2E2F }, /* P_RD_P4Q1 */
+	{ 0x370E, 0xBB56 }, /* P_RD_P4Q2 */
+	{ 0x3710, 0x8195 }, /* P_RD_P4Q3 */
+	{ 0x3712, 0x02F9 }, /* P_RD_P4Q4 */
+	{ 0x3600, 0x0230 }, /* P_GR_P0Q0 */
+	{ 0x3602, 0x58AD }, /* P_GR_P0Q1 */
+	{ 0x3604, 0x18D1 }, /* P_GR_P0Q2 */
+	{ 0x3606, 0x260D }, /* P_GR_P0Q3 */
+	{ 0x3608, 0xF530 }, /* P_GR_P0Q4 */
+	{ 0x3640, 0x17EB }, /* P_GR_P1Q0 */
+	{ 0x3642, 0x3CAB }, /* P_GR_P1Q1 */
+	{ 0x3644, 0x87CE }, /* P_GR_P1Q2 */
+	{ 0x3646, 0xC02E }, /* P_GR_P1Q3 */
+	{ 0x3648, 0xF48F }, /* P_GR_P1Q4 */
+	{ 0x3680, 0x5350 }, /* P_GR_P2Q0 */
+	{ 0x3682, 0x7EAF }, /* P_GR_P2Q1 */
+	{ 0x3684, 0x4312 }, /* P_GR_P2Q2 */
+	{ 0x3686, 0xC652 }, /* P_GR_P2Q3 */
+	{ 0x3688, 0xBC15 }, /* P_GR_P2Q4 */
+	{ 0x36C0, 0xB8AD }, /* P_GR_P3Q0 */
+	{ 0x36C2, 0xBDCD }, /* P_GR_P3Q1 */
+	{ 0x36C4, 0xE4B2 }, /* P_GR_P3Q2 */
+	{ 0x36C6, 0xB50F }, /* P_GR_P3Q3 */
+	{ 0x36C8, 0x5B95 }, /* P_GR_P3Q4 */
+	{ 0x3700, 0xFC90 }, /* P_GR_P4Q0 */
+	{ 0x3702, 0x8C51 }, /* P_GR_P4Q1 */
+	{ 0x3704, 0xCED6 }, /* P_GR_P4Q2 */
+	{ 0x3706, 0xB594 }, /* P_GR_P4Q3 */
+	{ 0x3708, 0x0A39 }, /* P_GR_P4Q4 */
+	{ 0x3614, 0x0230 }, /* P_BL_P0Q0 */
+	{ 0x3616, 0x160D }, /* P_BL_P0Q1 */
+	{ 0x3618, 0x08D1 }, /* P_BL_P0Q2 */
+	{ 0x361A, 0x98AB }, /* P_BL_P0Q3 */
+	{ 0x361C, 0xEA50 }, /* P_BL_P0Q4 */
+	{ 0x3654, 0xB4EA }, /* P_BL_P1Q0 */
+	{ 0x3656, 0xEA6C }, /* P_BL_P1Q1 */
+	{ 0x3658, 0xFE08 }, /* P_BL_P1Q2 */
+	{ 0x365A, 0x2C6E }, /* P_BL_P1Q3 */
+	{ 0x365C, 0xEB0E }, /* P_BL_P1Q4 */
+	{ 0x3694, 0x6DF0 }, /* P_BL_P2Q0 */
+	{ 0x3696, 0x3ACF }, /* P_BL_P2Q1 */
+	{ 0x3698, 0x3E0F }, /* P_BL_P2Q2 */
+	{ 0x369A, 0xB2B1 }, /* P_BL_P2Q3 */
+	{ 0x369C, 0xC374 }, /* P_BL_P2Q4 */
+	{ 0x36D4, 0xF2AA }, /* P_BL_P3Q0 */
+	{ 0x36D6, 0x8CCC }, /* P_BL_P3Q1 */
+	{ 0x36D8, 0xDEF2 }, /* P_BL_P3Q2 */
+	{ 0x36DA, 0xFA11 }, /* P_BL_P3Q3 */
+	{ 0x36DC, 0x42F5 }, /* P_BL_P3Q4 */
+	{ 0x3714, 0xF4F1 }, /* P_BL_P4Q0 */
+	{ 0x3716, 0xF6F0 }, /* P_BL_P4Q1 */
+	{ 0x3718, 0x8FD6 }, /* P_BL_P4Q2 */
+	{ 0x371A, 0xEA14 }, /* P_BL_P4Q3 */
+	{ 0x371C, 0x6338 }, /* P_BL_P4Q4 */
+	{ 0x361E, 0x0350 }, /* P_GB_P0Q0 */
+	{ 0x3620, 0x91AE }, /* P_GB_P0Q1 */
+	{ 0x3622, 0x0571 }, /* P_GB_P0Q2 */
+	{ 0x3624, 0x100D }, /* P_GB_P0Q3 */
+	{ 0x3626, 0xCA70 }, /* P_GB_P0Q4 */
+	{ 0x365E, 0xE6CB }, /* P_GB_P1Q0 */
+	{ 0x3660, 0x50ED }, /* P_GB_P1Q1 */
+	{ 0x3662, 0x3DAE }, /* P_GB_P1Q2 */
+	{ 0x3664, 0xAA4F }, /* P_GB_P1Q3 */
+	{ 0x3666, 0xDC50 }, /* P_GB_P1Q4 */
+	{ 0x369E, 0x5470 }, /* P_GB_P2Q0 */
+	{ 0x36A0, 0x1F6E }, /* P_GB_P2Q1 */
+	{ 0x36A2, 0x6671 }, /* P_GB_P2Q2 */
+	{ 0x36A4, 0xC010 }, /* P_GB_P2Q3 */
+	{ 0x36A6, 0x8DF5 }, /* P_GB_P2Q4 */
+	{ 0x36DE, 0x0B0C }, /* P_GB_P3Q0 */
+	{ 0x36E0, 0x84CE }, /* P_GB_P3Q1 */
+	{ 0x36E2, 0x8493 }, /* P_GB_P3Q2 */
+	{ 0x36E4, 0xA610 }, /* P_GB_P3Q3 */
+	{ 0x36E6, 0x50B5 }, /* P_GB_P3Q4 */
+	{ 0x371E, 0x9651 }, /* P_GB_P4Q0 */
+	{ 0x3720, 0x1EAB }, /* P_GB_P4Q1 */
+	{ 0x3722, 0xAF76 }, /* P_GB_P4Q2 */
+	{ 0x3724, 0xE4F4 }, /* P_GB_P4Q3 */
+	{ 0x3726, 0x79F8 }, /* P_GB_P4Q4 */
+	{ 0x3782, 0x0410 }, /* POLY_ORIGIN_C */
+	{ 0x3784, 0x0320 }, /* POLY_ORIGIN_R  */
+	{ 0x3780, 0x8000 } /* POLY_SC_ENABLE */
+};
+
+struct mt9t013_reg mt9t013_regs = {
+	.reg_pat = &mt9t013_reg_pat[0],
+	.reg_pat_size = ARRAY_SIZE(mt9t013_reg_pat),
+	.ttbl = &mt9t013_test_tbl[0],
+	.ttbl_size = ARRAY_SIZE(mt9t013_test_tbl),
+	.lctbl = &mt9t013_lc_tbl[0],
+	.lctbl_size = ARRAY_SIZE(mt9t013_lc_tbl),
+	.rftbl = &mt9t013_lc_tbl[0],	/* &mt9t013_rolloff_tbl[0], */
+	.rftbl_size = ARRAY_SIZE(mt9t013_lc_tbl)
+};
+
+
diff --git a/drivers/media/video/msm/ov2720.c b/drivers/media/video/msm/ov2720.c
new file mode 100644
index 0000000..cfd6efa
--- /dev/null
+++ b/drivers/media/video/msm/ov2720.c
@@ -0,0 +1,598 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/types.h>
+#include <mach/camera.h>
+#include <mach/gpio.h>
+#include <media/msm_camera.h>
+#include "msm_sensor.h"
+#include "ov2720.h"
+#include "msm.h"
+#define SENSOR_NAME "ov2720"
+#define PLATFORM_DRIVER_NAME "msm_camera_ov2720"
+#define ov2720_obj ov2720_##obj
+
+DEFINE_MUTEX(ov2720_mut);
+static struct msm_sensor_ctrl_t ov2720_s_ctrl;
+
+struct msm_sensor_i2c_reg_conf ov2720_start_settings[] = {
+	{0x0100, 0x01},
+};
+
+struct msm_sensor_i2c_reg_conf ov2720_stop_settings[] = {
+	{0x0100, 0x00},
+};
+
+struct msm_sensor_i2c_reg_conf ov2720_groupon_settings[] = {
+	{0x3208, 0x00},
+};
+
+struct msm_sensor_i2c_reg_conf ov2720_groupoff_settings[] = {
+	{0x3208, 0x10},
+	{0x3208, 0xA0},
+};
+
+static struct msm_sensor_i2c_reg_conf ov2720_prev_settings[] = {
+	{0x3800, 0x00},
+	{0x3801, 0x0c},
+	{0x3802, 0x00},
+	{0x3803, 0x02},
+	{0x3804, 0x07},
+	{0x3805, 0x97},
+	{0x3806, 0x04},
+	{0x3807, 0x45},
+	{0x3808, 0x07},
+	{0x3809, 0x80},
+	{0x380a, 0x04},
+	{0x380b, 0x38},
+	{0x380c, 0x08},/*Line Length Pclk Hi*/
+	{0x380d, 0x5c},/*Line Length Pclk Lo*/
+	{0x380e, 0x04},/*Frame Length Line Hi*/
+	{0x380f, 0x60},/*Frame Length Line Lo*/
+	{0x3810, 0x00},
+	{0x3811, 0x05},
+	{0x3812, 0x00},
+	{0x3813, 0x06},
+	{0x3820, 0x80},
+	{0x3821, 0x06},
+	{0x3814, 0x11},
+	{0x3815, 0x11},
+	{0x3612, 0x0b},
+	{0x3618, 0x04},
+	{0x3a08, 0x01},
+	{0x3a09, 0x50},
+	{0x3a0a, 0x01},
+	{0x3a0b, 0x18},
+	{0x3a0d, 0x03},
+	{0x3a0e, 0x03},
+	{0x4520, 0x00},
+	{0x4837, 0x1b},
+	{0x3000, 0xff},
+	{0x3001, 0xff},
+	{0x3002, 0xf0},
+	{0x3600, 0x08},
+	{0x3621, 0xc0},
+	{0x3632, 0xd2},
+	{0x3633, 0x23},
+	{0x3634, 0x54},
+	{0x3f01, 0x0c},
+	{0x5001, 0xc1},
+	{0x3614, 0xf0},
+	{0x3630, 0x2d},
+	{0x370b, 0x62},
+	{0x3706, 0x61},
+	{0x4000, 0x02},
+	{0x4002, 0xc5},
+	{0x4005, 0x08},
+	{0x404f, 0x84},
+	{0x4051, 0x00},
+	{0x5000, 0xff},
+	{0x3a18, 0x00},
+	{0x3a19, 0x80},
+	{0x3503, 0x13},
+	{0x4521, 0x00},
+	{0x5183, 0xb0},
+	{0x5184, 0xb0},
+	{0x5185, 0xb0},
+	{0x370c, 0x0c},
+	{0x3035, 0x10},
+	{0x3036, 0x1e},
+	{0x3037, 0x21},
+	{0x303e, 0x19},
+	{0x3038, 0x06},
+	{0x3018, 0x04},
+	{0x3000, 0x00},
+	{0x3001, 0x00},
+	{0x3002, 0x00},
+	{0x3a0f, 0x40},
+	{0x3a10, 0x38},
+	{0x3a1b, 0x48},
+	{0x3a1e, 0x30},
+	{0x3a11, 0x90},
+	{0x3a1f, 0x10},
+	{0x4800, 0x24},
+};
+
+static struct msm_sensor_i2c_reg_conf ov2720_720_settings[] = {
+	{0x3800, 0x01},
+	{0x3801, 0x4a},
+	{0x3802, 0x00},
+	{0x3803, 0xba},
+	{0x3804, 0x06},
+	{0x3805, 0x51+32},
+	{0x3806, 0x03},
+	{0x3807, 0x8d+24},
+	{0x3808, 0x05},
+	{0x3809, 0x00+16},
+	{0x380a, 0x02},
+	{0x380b, 0x78},
+	{0x380c, 0x08},/*Line Length Pclk Hi*/
+	{0x380d, 0x5e},/*Line Length Pclk Lo*/
+	{0x380e, 0x04},/*Frame Length Line Hi*/
+	{0x380f, 0x60},/*Frame Length Line Lo*/
+	{0x3810, 0x00},
+	{0x3811, 0x05},
+	{0x3812, 0x00},
+	{0x3813, 0x02},
+	{0x3820, 0x80},
+	{0x3821, 0x06},
+	{0x3814, 0x11},
+	{0x3815, 0x11},
+	{0x3612, 0x0b},
+	{0x3618, 0x04},
+	{0x3a08, 0x01},
+	{0x3a09, 0x50},
+	{0x3a0a, 0x01},
+	{0x3a0b, 0x18},
+	{0x3a0d, 0x03},
+	{0x3a0e, 0x03},
+	{0x4520, 0x00},
+	{0x4837, 0x1b},
+	{0x3000, 0xff},
+	{0x3001, 0xff},
+	{0x3002, 0xf0},
+	{0x3600, 0x08},
+	{0x3621, 0xc0},
+	{0x3632, 0xd2},
+	{0x3633, 0x23},
+	{0x3634, 0x54},
+	{0x3f01, 0x0c},
+	{0x5001, 0xc1},
+	{0x3614, 0xf0},
+	{0x3630, 0x2d},
+	{0x370b, 0x62},
+	{0x3706, 0x61},
+	{0x4000, 0x02},
+	{0x4002, 0xc5},
+	{0x4005, 0x08},
+	{0x404f, 0x84},
+	{0x4051, 0x00},
+	{0x5000, 0xff},
+	{0x3a18, 0x00},
+	{0x3a19, 0x80},
+	{0x3503, 0x13},
+	{0x4521, 0x00},
+	{0x5183, 0xb0},
+	{0x5184, 0xb0},
+	{0x5185, 0xb0},
+	{0x370c, 0x0c},
+	{0x3035, 0x10},
+	{0x3036, 0x04},
+	{0x3037, 0x61},
+	{0x303e, 0x19},
+	{0x3038, 0x06},
+	{0x3018, 0x04},
+	{0x3000, 0x00},
+	{0x3001, 0x00},
+	{0x3002, 0x00},
+	{0x3a0f, 0x40},
+	{0x3a10, 0x38},
+	{0x3a1b, 0x48},
+	{0x3a1e, 0x30},
+	{0x3a11, 0x90},
+	{0x3a1f, 0x10},
+	{0x4800, 0x24},
+};
+
+static struct msm_sensor_i2c_reg_conf ov2720_vga_settings[] = {
+	{0x3800, 0x00},
+	{0x3801, 0x0c},
+	{0x3802, 0x00},
+	{0x3803, 0x02},
+	{0x3804, 0x07},
+	{0x3805, 0x97+32},
+	{0x3806, 0x04},
+	{0x3807, 0x45+24},
+	{0x3808, 0x02},
+	{0x3809, 0x88+16},
+	{0x380a, 0x01},
+	{0x380b, 0xe6+12},
+	{0x380c, 0x08},/*Line Length Pclk Hi*/
+	{0x380d, 0x5e},/*Line Length Pclk Lo*/
+	{0x380e, 0x04},/*Frame Length Line Hi*/
+	{0x380f, 0x68},/*Frame Length Line Lo*/
+	{0x3810, 0x00},
+	{0x3811, 0x03},
+	{0x3812, 0x00},
+	{0x3813, 0x03},
+	{0x3820, 0x80},
+	{0x3821, 0x06},
+	{0x3814, 0x11},
+	{0x3815, 0x11},
+	{0x3612, 0x0b},
+	{0x3618, 0x04},
+	{0x3a08, 0x01},
+	{0x3a09, 0x50},
+	{0x3a0a, 0x01},
+	{0x3a0b, 0x18},
+	{0x3a0d, 0x03},
+	{0x3a0e, 0x03},
+	{0x4520, 0x00},
+	{0x4837, 0x1b},
+	{0x3000, 0xff},
+	{0x3001, 0xff},
+	{0x3002, 0xf0},
+	{0x3600, 0x08},
+	{0x3621, 0xc0},
+	{0x3632, 0xd2},
+	{0x3633, 0x23},
+	{0x3634, 0x54},
+	{0x3f01, 0x0c},
+	{0x5001, 0xc1},
+	{0x3614, 0xf0},
+	{0x3630, 0x2d},
+	{0x370b, 0x62},
+	{0x3706, 0x61},
+	{0x4000, 0x02},
+	{0x4002, 0xc5},
+	{0x4005, 0x08},
+	{0x404f, 0x84},
+	{0x4051, 0x00},
+	{0x5000, 0xff},
+	{0x3a18, 0x00},
+	{0x3a19, 0x80},
+	{0x3503, 0x13},
+	{0x4521, 0x00},
+	{0x5183, 0xb0},
+	{0x5184, 0xb0},
+	{0x5185, 0xb0},
+	{0x370c, 0x0c},
+	{0x3035, 0x10},
+	{0x3036, 0x04},
+	{0x3037, 0x61},
+	{0x303e, 0x19},
+	{0x3038, 0x06},
+	{0x3018, 0x04},
+	{0x3000, 0x00},
+	{0x3001, 0x00},
+	{0x3002, 0x00},
+	{0x3a0f, 0x40},
+	{0x3a10, 0x38},
+	{0x3a1b, 0x48},
+	{0x3a1e, 0x30},
+	{0x3a11, 0x90},
+	{0x3a1f, 0x10},
+	{0x4800, 0x24},
+	{0x3500, 0x00},
+	{0x3501, 0x17},
+	{0x3502, 0xf0},
+	{0x3508, 0x00},
+	{0x3509, 0x20},
+};
+
+static struct msm_sensor_i2c_reg_conf ov2720_recommend_settings[] = {
+	{0x0103, 0x01},
+	{0x3718, 0x10},
+	{0x3702, 0x24},
+	{0x373a, 0x60},
+	{0x3715, 0x01},
+	{0x3703, 0x2e},
+	{0x3705, 0x10},
+	{0x3730, 0x30},
+	{0x3704, 0x62},
+	{0x3f06, 0x3a},
+	{0x371c, 0x00},
+	{0x371d, 0xc4},
+	{0x371e, 0x01},
+	{0x371f, 0x0d},
+	{0x3708, 0x61},
+	{0x3709, 0x12},
+};
+
+static struct msm_camera_csi_params ov2720_csi_params = {
+	.lane_cnt = 2,
+	.data_format = CSI_10BIT,
+	.lane_assign = 0xe4,
+	.dpcm_scheme = 0,
+	.settle_cnt = 0x18,
+};
+
+static struct v4l2_subdev_info ov2720_subdev_info[] = {
+	{
+	.code   = V4L2_MBUS_FMT_SBGGR10_1X10,
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	.fmt    = 1,
+	.order    = 0,
+	},
+	/* more can be supported, to be added later */
+};
+
+static struct msm_sensor_i2c_conf_array ov2720_init_conf[] = {
+	{&ov2720_recommend_settings[0],
+	ARRAY_SIZE(ov2720_recommend_settings), 0}
+};
+
+static struct msm_sensor_i2c_conf_array ov2720_confs[] = {
+	{&ov2720_prev_settings[0], ARRAY_SIZE(ov2720_prev_settings), 0},
+	{&ov2720_vga_settings[0], ARRAY_SIZE(ov2720_vga_settings), 0},
+	{&ov2720_720_settings[0], ARRAY_SIZE(ov2720_720_settings), 0},
+};
+
+static int32_t ov2720_write_exp_gain(struct msm_sensor_ctrl_t *s_ctrl,
+		uint16_t gain, uint32_t line)
+{
+	uint32_t fl_lines, offset;
+	fl_lines =
+		(s_ctrl->curr_frame_length_lines * s_ctrl->fps_divider) / Q10;
+	offset = s_ctrl->vert_offset;
+	if (line > (fl_lines - offset))
+		fl_lines = line + offset;
+
+	pr_err("LINE: 0x%x\n", line);
+	s_ctrl->func_tbl.sensor_group_hold_on(s_ctrl);
+	msm_sensor_i2c_waddr_write_w(s_ctrl,
+			s_ctrl->frame_length_lines_addr, fl_lines);
+	msm_sensor_i2c_waddr_write_b(s_ctrl,
+			s_ctrl->coarse_int_time_addr-1, line >> 12);
+	msm_sensor_i2c_waddr_write_w(s_ctrl,
+			s_ctrl->coarse_int_time_addr, ((line << 4) & 0xFFFF));
+	msm_sensor_i2c_waddr_write_w(s_ctrl,
+			s_ctrl->global_gain_addr, gain);
+	s_ctrl->func_tbl.sensor_group_hold_off(s_ctrl);
+	return 0;
+}
+
+static int32_t ov2720_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl,
+				int update_type, int rt)
+{
+	struct msm_camera_csid_params ov2720_csid_params;
+	struct msm_camera_csiphy_params ov2720_csiphy_params;
+	int32_t rc = 0;
+	s_ctrl->func_tbl.sensor_stop_stream(s_ctrl);
+	msleep(30);
+	if (update_type == MSM_SENSOR_REG_INIT) {
+		s_ctrl->config_csi_flag = 1;
+		msm_sensor_enable_debugfs(s_ctrl);
+		msm_sensor_write_b_init_settings(s_ctrl);
+	} else if (update_type == MSM_SENSOR_UPDATE_PERIODIC) {
+		msm_sensor_write_b_res_settings(s_ctrl, rt);
+		if (s_ctrl->config_csi_flag) {
+			struct msm_camera_csid_vc_cfg ov2720_vccfg[] = {
+				{0, CSI_RAW10, CSI_DECODE_10BIT},
+				{1, CSI_EMBED_DATA, CSI_DECODE_8BIT},
+			};
+			ov2720_csid_params.lane_cnt = 2;
+			ov2720_csid_params.lane_assign = 0xe4;
+			ov2720_csid_params.lut_params.num_cid =
+				ARRAY_SIZE(ov2720_vccfg);
+			ov2720_csid_params.lut_params.vc_cfg =
+				&ov2720_vccfg[0];
+			ov2720_csiphy_params.lane_cnt = 2;
+			ov2720_csiphy_params.settle_cnt = 0x1B;
+			rc = msm_camio_csid_config(&ov2720_csid_params);
+			v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev,
+						NOTIFY_CID_CHANGE, NULL);
+			mb();
+			rc = msm_camio_csiphy_config(&ov2720_csiphy_params);
+			mb();
+			msleep(20);
+			s_ctrl->config_csi_flag = 0;
+		}
+		s_ctrl->func_tbl.sensor_start_stream(s_ctrl);
+		msleep(30);
+	}
+	return rc;
+}
+
+static int ov2720_sensor_config(void __user *argp)
+{
+	return (int) msm_sensor_config(&ov2720_s_ctrl, argp);
+}
+
+static int ov2720_power_down(const struct msm_camera_sensor_info *data)
+{
+	pr_err("%s\n", __func__);
+	gpio_set_value_cansleep(data->sensor_reset, 0);
+	gpio_free(data->sensor_reset);
+	return 0;
+}
+
+static int ov2720_power_up(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc = 0;
+	pr_err("%s: %d\n", __func__, __LINE__);
+	msm_camio_clk_rate_set(MSM_SENSOR_MCLK_24HZ);
+	rc = gpio_request(data->sensor_reset, "SENSOR_NAME");
+	if (rc < 0)
+		goto gpio_request_fail;
+
+	pr_err("%s: reset sensor\n", __func__);
+	gpio_direction_output(data->sensor_reset, 0);
+	msleep(50);
+	gpio_set_value_cansleep(data->sensor_reset, 1);
+	msleep(50);
+
+	rc = msm_sensor_match_id(&ov2720_s_ctrl);
+	if (rc < 0)
+		goto init_probe_fail;
+
+	goto init_probe_done;
+gpio_request_fail:
+	pr_err("%s: gpio request fail\n", __func__);
+	return rc;
+init_probe_fail:
+	pr_err(" %s fails\n", __func__);
+	ov2720_power_down(data);
+	return rc;
+init_probe_done:
+	pr_err("%s finishes\n", __func__);
+	return rc;
+}
+
+static int ov2720_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc = 0;
+	pr_err("%s: %d\n", __func__, __LINE__);
+	ov2720_s_ctrl.fps = 30*Q8;
+	ov2720_s_ctrl.fps_divider = 1 * 0x00000400;
+	ov2720_s_ctrl.cam_mode = MSM_SENSOR_MODE_INVALID;
+
+	if (data)
+		ov2720_s_ctrl.sensordata = data;
+
+	rc = ov2720_power_up(data);
+	if (rc < 0)
+		goto init_done;
+
+	goto init_done;
+init_done:
+	pr_err("%s finishes\n", __func__);
+	return rc;
+}
+
+static int ov2720_sensor_release(void)
+{
+	mutex_lock(ov2720_s_ctrl.msm_sensor_mutex);
+	gpio_set_value_cansleep(ov2720_s_ctrl.sensordata->sensor_reset, 0);
+	msleep(20);
+	gpio_free(ov2720_s_ctrl.sensordata->sensor_reset);
+	mutex_unlock(ov2720_s_ctrl.msm_sensor_mutex);
+	pr_err("%s completed\n", __func__);
+	return 0;
+}
+
+static const struct i2c_device_id ov2720_i2c_id[] = {
+	{SENSOR_NAME, (kernel_ulong_t)&ov2720_s_ctrl},
+	{ }
+};
+
+static struct i2c_driver ov2720_i2c_driver = {
+	.id_table = ov2720_i2c_id,
+	.probe  = msm_sensor_i2c_probe,
+	.driver = {
+		.name = SENSOR_NAME,
+	},
+};
+
+static int ov2720_sensor_v4l2_probe(const struct msm_camera_sensor_info *info,
+	struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s)
+{
+	return msm_sensor_v4l2_probe(&ov2720_s_ctrl, info, sdev, s);
+}
+
+static int ov2720_probe(struct platform_device *pdev)
+{
+	return msm_sensor_register(pdev, ov2720_sensor_v4l2_probe);
+}
+
+struct platform_driver ov2720_driver = {
+	.probe = ov2720_probe,
+	.driver = {
+		.name = PLATFORM_DRIVER_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_sensor_init_module(void)
+{
+	return platform_driver_register(&ov2720_driver);
+}
+
+static struct v4l2_subdev_core_ops ov2720_subdev_core_ops;
+static struct v4l2_subdev_video_ops ov2720_subdev_video_ops = {
+	.enum_mbus_fmt = msm_sensor_v4l2_enum_fmt,
+};
+
+static struct v4l2_subdev_ops ov2720_subdev_ops = {
+	.core = &ov2720_subdev_core_ops,
+	.video  = &ov2720_subdev_video_ops,
+};
+
+static struct msm_sensor_ctrl_t ov2720_s_ctrl = {
+	.msm_sensor_reg = {
+		.start_stream_conf = ov2720_start_settings,
+		.start_stream_conf_size = ARRAY_SIZE(ov2720_start_settings),
+		.stop_stream_conf = ov2720_stop_settings,
+		.stop_stream_conf_size = ARRAY_SIZE(ov2720_stop_settings),
+		.group_hold_on_conf = ov2720_groupon_settings,
+		.group_hold_on_conf_size = ARRAY_SIZE(ov2720_groupon_settings),
+		.group_hold_off_conf = ov2720_groupoff_settings,
+		.group_hold_off_conf_size =
+			ARRAY_SIZE(ov2720_groupoff_settings),
+		.init_settings = &ov2720_init_conf[0],
+		.init_size = ARRAY_SIZE(ov2720_init_conf),
+		.res_settings = &ov2720_confs[0],
+		.num_conf = ARRAY_SIZE(ov2720_confs),
+	},
+	.sensor_id_addr = 0x300A,
+	.sensor_id = 0x2720,
+	.frame_length_lines_addr = 0x380e,
+	.coarse_int_time_addr = 0x3501,
+	.global_gain_addr = 0x3508,
+	.line_length_pck_addr = 0x380c,
+	.frame_length_lines_array_addr = 14,
+	.line_length_pck_array_addr = 12,
+	.vert_offset = 6,
+	.cam_mode = MSM_SENSOR_MODE_INVALID,
+	.camera_type = FRONT_CAMERA_2D,
+	.config_csi_flag = 1,
+	.csi_params = &ov2720_csi_params,
+	.msm_sensor_mutex = &ov2720_mut,
+	.msm_sensor_i2c_driver = &ov2720_i2c_driver,
+	.sensor_v4l2_subdev_info = ov2720_subdev_info,
+	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov2720_subdev_info),
+	.sensor_v4l2_subdev_ops = &ov2720_subdev_ops,
+
+	.func_tbl = {
+		.sensor_start_stream = msm_sensor_start_stream,
+		.sensor_stop_stream = msm_sensor_stop_stream,
+		.sensor_group_hold_on = msm_sensor_group_hold_on,
+		.sensor_group_hold_off = msm_sensor_group_hold_off,
+		.sensor_get_prev_lines_pf = msm_sensor_get_prev_lines_pf,
+		.sensor_get_prev_pixels_pl = msm_sensor_get_prev_pixels_pl,
+		.sensor_get_pict_lines_pf = msm_sensor_get_pict_lines_pf,
+		.sensor_get_pict_pixels_pl = msm_sensor_get_pict_pixels_pl,
+		.sensor_get_pict_max_exp_lc = msm_sensor_get_pict_max_exp_lc,
+		.sensor_get_pict_fps = msm_sensor_get_pict_fps,
+		.sensor_set_fps = msm_sensor_set_fps,
+		.sensor_write_exp_gain = ov2720_write_exp_gain,
+		.sensor_setting = ov2720_sensor_setting,
+		.sensor_set_sensor_mode = msm_sensor_set_sensor_mode_b,
+		.sensor_mode_init = msm_sensor_mode_init_bdata,
+		.sensor_config = ov2720_sensor_config,
+		.sensor_open_init = ov2720_sensor_open_init,
+		.sensor_release = ov2720_sensor_release,
+		.sensor_power_up = ov2720_power_up,
+		.sensor_power_down = ov2720_power_down,
+		.sensor_probe = msm_sensor_probe,
+	},
+};
+
+module_init(msm_sensor_init_module);
+MODULE_DESCRIPTION("Omnivision 2MP Bayer sensor driver");
+MODULE_LICENSE("GPL v2");
+
+
diff --git a/drivers/media/video/msm/ov2720.h b/drivers/media/video/msm/ov2720.h
new file mode 100644
index 0000000..7077a7d
--- /dev/null
+++ b/drivers/media/video/msm/ov2720.h
@@ -0,0 +1,16 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <mach/board.h>
+extern struct platform_driver ov2720_driver;
+
diff --git a/drivers/media/video/msm/ov2720_reg.c b/drivers/media/video/msm/ov2720_reg.c
new file mode 100644
index 0000000..bf094a5
--- /dev/null
+++ b/drivers/media/video/msm/ov2720_reg.c
@@ -0,0 +1,123 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include "ov2720.h"
+
+struct ov2720_i2c_reg_conf ov2720_prev_settings[] = {
+	{0x3800, 0x00},
+	{0x3801, 0x0c},
+	{0x3802, 0x00},
+	{0x3803, 0x02},
+	{0x3804, 0x07},
+	{0x3805, 0x97},
+	{0x3806, 0x04},
+	{0x3807, 0x45},
+	{0x3808, 0x07},
+	{0x3809, 0x80},
+	{0x380a, 0x04},
+	{0x380b, 0x38},
+	{0x380c, 0x08},/*Line Length Pclk Hi*/
+	{0x380d, 0x5c},/*Line Length Pclk Lo*/
+	{0x380e, 0x04},/*Frame Length Line Hi*/
+	{0x380f, 0x60},/*Frame Length Line Lo*/
+	{0x3810, 0x00},
+	{0x3811, 0x05},
+	{0x3812, 0x00},
+	{0x3813, 0x06},
+	{0x3820, 0x80},
+	{0x3821, 0x06},
+	{0x3814, 0x11},
+	{0x3815, 0x11},
+	{0x3612, 0x0b},
+	{0x3618, 0x04},
+	{0x3a08, 0x01},
+	{0x3a09, 0x50},
+	{0x3a0a, 0x01},
+	{0x3a0b, 0x18},
+	{0x3a0d, 0x03},
+	{0x3a0e, 0x03},
+	{0x4520, 0x00},
+	{0x4837, 0x1b},
+	{0x3000, 0xff},
+	{0x3001, 0xff},
+	{0x3002, 0xf0},
+	{0x3600, 0x08},
+	{0x3621, 0xc0},
+	{0x3632, 0xd2},
+	{0x3633, 0x23},
+	{0x3634, 0x54},
+	{0x3f01, 0x0c},
+	{0x5001, 0xc1},
+	{0x3614, 0xf0},
+	{0x3630, 0x2d},
+	{0x370b, 0x62},
+	{0x3706, 0x61},
+	{0x4000, 0x02},
+	{0x4002, 0xc5},
+	{0x4005, 0x08},
+	{0x404f, 0x84},
+	{0x4051, 0x00},
+	{0x5000, 0xff},
+	{0x3a18, 0x00},
+	{0x3a19, 0x80},
+	{0x3503, 0x00},
+	{0x4521, 0x00},
+	{0x5183, 0xb0},
+	{0x5184, 0xb0},
+	{0x5185, 0xb0},
+	{0x370c, 0x0c},
+};
+
+struct ov2720_i2c_reg_conf ov2720_recommend_settings[] = {
+	{0x0103, 0x01},
+	{0x3718, 0x10},
+	{0x3702, 0x24},
+	{0x373a, 0x60},
+	{0x3715, 0x01},
+	{0x3703, 0x2e},
+	{0x3705, 0x10},
+	{0x3730, 0x30},
+	{0x3704, 0x62},
+	{0x3f06, 0x3a},
+	{0x371c, 0x00},
+	{0x371d, 0xc4},
+	{0x371e, 0x01},
+	{0x371f, 0x0d},
+	{0x3708, 0x61},
+	{0x3709, 0x12},
+	{0x3035, 0x10},
+	{0x3036, 0x1e},
+	{0x3037, 0x21},
+	{0x303e, 0x19},
+	{0x3038, 0x06},
+	{0x3018, 0x04},
+	{0x3000, 0x00},
+	{0x3001, 0x00},
+	{0x3002, 0x00},
+	{0x3a0f, 0x40},
+	{0x3a10, 0x38},
+	{0x3a1b, 0x48},
+	{0x3a1e, 0x30},
+	{0x3a11, 0x90},
+	{0x3a1f, 0x10},
+};
+
+struct ov2720_i2c_conf_array ov2720_confs[] = {
+	{&ov2720_prev_settings[0], ARRAY_SIZE(ov2720_prev_settings)},
+};
+
+struct ov2720_reg ov2720_regs = {
+	.rec_settings = &ov2720_recommend_settings[0],
+	.rec_size = ARRAY_SIZE(ov2720_recommend_settings),
+	.conf_array = &ov2720_confs[0],
+};
diff --git a/drivers/media/video/msm/ov7692.c b/drivers/media/video/msm/ov7692.c
new file mode 100644
index 0000000..7372156
--- /dev/null
+++ b/drivers/media/video/msm/ov7692.c
@@ -0,0 +1,595 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <media/msm_camera.h>
+#include <mach/camera.h>
+#include "ov7692.h"
+
+/*=============================================================
+	SENSOR REGISTER DEFINES
+==============================================================*/
+#define Q8    0x00000100
+
+/* Omnivision8810 product ID register address */
+#define REG_OV7692_MODEL_ID_MSB                       0x0A
+#define REG_OV7692_MODEL_ID_LSB                       0x0B
+
+#define OV7692_MODEL_ID                       0x7692
+/* Omnivision8810 product ID */
+
+/* Time in milisecs for waiting for the sensor to reset */
+#define OV7692_RESET_DELAY_MSECS    66
+#define OV7692_DEFAULT_CLOCK_RATE   24000000
+/* Registers*/
+
+/* Color bar pattern selection */
+#define OV7692_COLOR_BAR_PATTERN_SEL_REG     0x82
+/* Color bar enabling control */
+#define OV7692_COLOR_BAR_ENABLE_REG           0x601
+/* Time in milisecs for waiting for the sensor to reset*/
+#define OV7692_RESET_DELAY_MSECS    66
+
+/*============================================================================
+							DATA DECLARATIONS
+============================================================================*/
+/*  96MHz PCLK @ 24MHz MCLK */
+struct reg_addr_val_pair_struct ov7692_init_settings_array[] = {
+    {0x12, 0x80},
+    {0x0e, 0x08},
+    {0x69, 0x52},
+    {0x1e, 0xb3},
+    {0x48, 0x42},
+    {0xff, 0x01},
+    {0xae, 0xa0},
+    {0xa8, 0x26},
+    {0xb4, 0xc0},
+    {0xb5, 0x40},
+    {0xff, 0x00},
+    {0x0c, 0x00},
+    {0x62, 0x10},
+    {0x12, 0x00},
+    {0x17, 0x65},
+    {0x18, 0xa4},
+    {0x19, 0x0a},
+    {0x1a, 0xf6},
+    {0x3e, 0x30},
+    {0x64, 0x0a},
+    {0xff, 0x01},
+    {0xb4, 0xc0},
+    {0xff, 0x00},
+    {0x67, 0x20},
+    {0x81, 0x3f},
+    {0xcc, 0x02},
+    {0xcd, 0x80},
+    {0xce, 0x01},
+    {0xcf, 0xe0},
+    {0xc8, 0x02},
+    {0xc9, 0x80},
+    {0xca, 0x01},
+    {0xcb, 0xe0},
+    {0xd0, 0x48},
+    {0x82, 0x03},
+    {0x0e, 0x00},
+    {0x70, 0x00},
+    {0x71, 0x34},
+    {0x74, 0x28},
+    {0x75, 0x98},
+    {0x76, 0x00},
+    {0x77, 0x64},
+    {0x78, 0x01},
+    {0x79, 0xc2},
+    {0x7a, 0x4e},
+    {0x7b, 0x1f},
+    {0x7c, 0x00},
+    {0x11, 0x00},
+    {0x20, 0x00},
+    {0x21, 0x23},
+    {0x50, 0x9a},
+    {0x51, 0x80},
+    {0x4c, 0x7d},
+    {0x0e, 0x00},
+    {0x80, 0x7f},
+    {0x85, 0x10},
+    {0x86, 0x00},
+    {0x87, 0x00},
+    {0x88, 0x00},
+    {0x89, 0x2a},
+    {0x8a, 0x26},
+    {0x8b, 0x22},
+    {0xbb, 0x7a},
+    {0xbc, 0x69},
+    {0xbd, 0x11},
+    {0xbe, 0x13},
+    {0xbf, 0x81},
+    {0xc0, 0x96},
+    {0xc1, 0x1e},
+    {0xb7, 0x05},
+    {0xb8, 0x09},
+    {0xb9, 0x00},
+    {0xba, 0x18},
+    {0x5a, 0x1f},
+    {0x5b, 0x9f},
+    {0x5c, 0x6a},
+    {0x5d, 0x42},
+    {0x24, 0x78},
+    {0x25, 0x68},
+    {0x26, 0xb3},
+    {0xa3, 0x0b},
+    {0xa4, 0x15},
+    {0xa5, 0x2a},
+    {0xa6, 0x51},
+    {0xa7, 0x63},
+    {0xa8, 0x74},
+    {0xa9, 0x83},
+    {0xaa, 0x91},
+    {0xab, 0x9e},
+    {0xac, 0xaa},
+    {0xad, 0xbe},
+    {0xae, 0xce},
+    {0xaf, 0xe5},
+    {0xb0, 0xf3},
+    {0xb1, 0xfb},
+    {0xb2, 0x06},
+    {0x8c, 0x5c},
+    {0x8d, 0x11},
+    {0x8e, 0x12},
+    {0x8f, 0x19},
+    {0x90, 0x50},
+    {0x91, 0x20},
+    {0x92, 0x96},
+    {0x93, 0x80},
+    {0x94, 0x13},
+    {0x95, 0x1b},
+    {0x96, 0xff},
+    {0x97, 0x00},
+    {0x98, 0x3d},
+    {0x99, 0x36},
+    {0x9a, 0x51},
+    {0x9b, 0x43},
+    {0x9c, 0xf0},
+    {0x9d, 0xf0},
+    {0x9e, 0xf0},
+    {0x9f, 0xff},
+    {0xa0, 0x68},
+    {0xa1, 0x62},
+    {0xa2, 0x0e},
+};
+
+static bool OV7692_CSI_CONFIG;
+/* 816x612, 24MHz MCLK 96MHz PCLK */
+uint32_t OV7692_FULL_SIZE_WIDTH        = 640;
+uint32_t OV7692_FULL_SIZE_HEIGHT       = 480;
+
+uint32_t OV7692_QTR_SIZE_WIDTH         = 640;
+uint32_t OV7692_QTR_SIZE_HEIGHT        = 480;
+
+uint32_t OV7692_HRZ_FULL_BLK_PIXELS    = 16;
+uint32_t OV7692_VER_FULL_BLK_LINES     = 12;
+uint32_t OV7692_HRZ_QTR_BLK_PIXELS     = 16;
+uint32_t OV7692_VER_QTR_BLK_LINES      = 12;
+
+struct ov7692_work_t {
+	struct work_struct work;
+};
+static struct  ov7692_work_t *ov7692_sensorw;
+static struct  i2c_client *ov7692_client;
+struct ov7692_ctrl_t {
+	const struct  msm_camera_sensor_info *sensordata;
+	uint32_t sensormode;
+	uint32_t fps_divider;		/* init to 1 * 0x00000400 */
+	uint32_t pict_fps_divider;	/* init to 1 * 0x00000400 */
+	uint32_t fps;
+	int32_t  curr_lens_pos;
+	uint32_t curr_step_pos;
+	uint32_t my_reg_gain;
+	uint32_t my_reg_line_count;
+	uint32_t total_lines_per_frame;
+	enum ov7692_resolution_t prev_res;
+	enum ov7692_resolution_t pict_res;
+	enum ov7692_resolution_t curr_res;
+	enum ov7692_test_mode_t  set_test;
+	unsigned short imgaddr;
+};
+static struct ov7692_ctrl_t *ov7692_ctrl;
+static DECLARE_WAIT_QUEUE_HEAD(ov7692_wait_queue);
+DEFINE_MUTEX(ov7692_mut);
+
+/*=============================================================*/
+
+static int ov7692_i2c_rxdata(unsigned short saddr,
+	unsigned char *rxdata, int length)
+{
+	struct i2c_msg msgs[] = {
+		{
+			.addr  = saddr,
+			.flags = 0,
+			.len   = 1,
+			.buf   = rxdata,
+		},
+		{
+			.addr  = saddr,
+			.flags = I2C_M_RD,
+			.len   = 1,
+			.buf   = rxdata,
+		},
+	};
+	if (i2c_transfer(ov7692_client->adapter, msgs, 2) < 0) {
+		CDBG("ov7692_i2c_rxdata failed!\n");
+		return -EIO;
+	}
+	return 0;
+}
+static int32_t ov7692_i2c_txdata(unsigned short saddr,
+				unsigned char *txdata, int length)
+{
+	struct i2c_msg msg[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = 2,
+			.buf = txdata,
+		 },
+	};
+	if (i2c_transfer(ov7692_client->adapter, msg, 1) < 0) {
+		CDBG("ov7692_i2c_txdata faild 0x%x\n", ov7692_client->addr);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t ov7692_i2c_read(uint8_t raddr,
+	uint8_t *rdata, int rlen)
+{
+	int32_t rc = 0;
+	unsigned char buf[1];
+	if (!rdata)
+		return -EIO;
+	memset(buf, 0, sizeof(buf));
+	buf[0] = raddr;
+	rc = ov7692_i2c_rxdata(ov7692_client->addr >> 1, buf, rlen);
+	if (rc < 0) {
+		CDBG("ov7692_i2c_read 0x%x failed!\n", raddr);
+		return rc;
+	}
+	*rdata = buf[0];
+	return rc;
+}
+static int32_t ov7692_i2c_write_b_sensor(uint8_t waddr, uint8_t bdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[2];
+	memset(buf, 0, sizeof(buf));
+	buf[0] = waddr;
+	buf[1] = bdata;
+	CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata);
+	rc = ov7692_i2c_txdata(ov7692_client->addr >> 1, buf, 2);
+	if (rc < 0)
+		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+			waddr, bdata);
+	return rc;
+}
+
+static int32_t ov7692_sensor_setting(int update_type, int rt)
+{
+	int32_t i, array_length;
+	int32_t rc = 0;
+	struct msm_camera_csi_params ov7692_csi_params;
+	switch (update_type) {
+	case REG_INIT:
+		OV7692_CSI_CONFIG = 0;
+		ov7692_i2c_write_b_sensor(0x0e, 0x08);
+		return rc;
+		break;
+	case UPDATE_PERIODIC:
+		if (!OV7692_CSI_CONFIG) {
+			ov7692_csi_params.lane_cnt = 1;
+			ov7692_csi_params.data_format = CSI_8BIT;
+			ov7692_csi_params.lane_assign = 0xe4;
+			ov7692_csi_params.dpcm_scheme = 0;
+			ov7692_csi_params.settle_cnt = 0x14;
+
+			rc = msm_camio_csi_config(&ov7692_csi_params);
+			msleep(10);
+			array_length = sizeof(ov7692_init_settings_array) /
+				sizeof(ov7692_init_settings_array[0]);
+			for (i = 0; i < array_length; i++) {
+				rc = ov7692_i2c_write_b_sensor(
+					ov7692_init_settings_array[i].reg_addr,
+					ov7692_init_settings_array[i].reg_val);
+				if (rc < 0)
+					return rc;
+			}
+			OV7692_CSI_CONFIG = 1;
+			msleep(20);
+			return rc;
+		}
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+static int32_t ov7692_video_config(int mode)
+{
+	int32_t rc = 0;
+	int rt;
+	/* change sensor resolution if needed */
+	rt = RES_PREVIEW;
+
+	if (ov7692_sensor_setting(UPDATE_PERIODIC, rt) < 0)
+		return rc;
+	ov7692_ctrl->curr_res = ov7692_ctrl->prev_res;
+	ov7692_ctrl->sensormode = mode;
+	return rc;
+}
+
+static int32_t ov7692_set_sensor_mode(int mode,
+	int res)
+{
+	int32_t rc = 0;
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		rc = ov7692_video_config(mode);
+		break;
+	case SENSOR_SNAPSHOT_MODE:
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+static int32_t ov7692_power_down(void)
+{
+	return 0;
+}
+
+static int ov7692_probe_init_sensor(const struct msm_camera_sensor_info *data)
+{
+	uint8_t model_id_msb, model_id_lsb = 0;
+	uint16_t model_id;
+	int32_t rc = 0;
+	/*The reset pin is not physically connected to the sensor.
+	The standby pin will do the reset hence there is no need
+	to request the gpio reset*/
+
+	/* Read sensor Model ID: */
+	rc = ov7692_i2c_read(REG_OV7692_MODEL_ID_MSB, &model_id_msb, 1);
+	if (rc < 0)
+		goto init_probe_fail;
+	rc = ov7692_i2c_read(REG_OV7692_MODEL_ID_LSB, &model_id_lsb, 1);
+	if (rc < 0)
+		goto init_probe_fail;
+	model_id = (model_id_msb << 8) | ((model_id_lsb & 0x00FF)) ;
+	CDBG("ov7692 model_id = 0x%x, 0x%x, 0x%x\n",
+		 model_id, model_id_msb, model_id_lsb);
+	/* 4. Compare sensor ID to OV7692 ID: */
+	if (model_id != OV7692_MODEL_ID) {
+		rc = -ENODEV;
+		goto init_probe_fail;
+	}
+	goto init_probe_done;
+init_probe_fail:
+	pr_warning(" ov7692_probe_init_sensor fails\n");
+init_probe_done:
+	CDBG(" ov7692_probe_init_sensor finishes\n");
+	return rc;
+}
+
+int ov7692_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc = 0;
+
+	CDBG("%s: %d\n", __func__, __LINE__);
+	CDBG("Calling ov7692_sensor_open_init\n");
+	ov7692_ctrl = kzalloc(sizeof(struct ov7692_ctrl_t), GFP_KERNEL);
+	if (!ov7692_ctrl) {
+		CDBG("ov7692_init failed!\n");
+		rc = -ENOMEM;
+		goto init_done;
+	}
+	ov7692_ctrl->fps_divider = 1 * 0x00000400;
+	ov7692_ctrl->pict_fps_divider = 1 * 0x00000400;
+	ov7692_ctrl->fps = 30 * Q8;
+	ov7692_ctrl->set_test = TEST_OFF;
+	ov7692_ctrl->prev_res = QTR_SIZE;
+	ov7692_ctrl->pict_res = FULL_SIZE;
+	ov7692_ctrl->curr_res = INVALID_SIZE;
+
+	if (data)
+		ov7692_ctrl->sensordata = data;
+
+	/* enable mclk first */
+
+	msm_camio_clk_rate_set(24000000);
+	msleep(20);
+
+	rc = ov7692_probe_init_sensor(data);
+	if (rc < 0) {
+		CDBG("Calling ov7692_sensor_open_init fail\n");
+		goto init_fail;
+	}
+
+	rc = ov7692_sensor_setting(REG_INIT, RES_PREVIEW);
+	if (rc < 0)
+		goto init_fail;
+	else
+		goto init_done;
+
+init_fail:
+	CDBG(" ov7692_sensor_open_init fail\n");
+	kfree(ov7692_ctrl);
+init_done:
+	CDBG("ov7692_sensor_open_init done\n");
+	return rc;
+}
+
+static int ov7692_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&ov7692_wait_queue);
+	return 0;
+}
+
+static const struct i2c_device_id ov7692_i2c_id[] = {
+	{"ov7692", 0},
+	{ }
+};
+
+static int ov7692_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int rc = 0;
+	CDBG("ov7692_i2c_probe called!\n");
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		CDBG("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	ov7692_sensorw = kzalloc(sizeof(struct ov7692_work_t), GFP_KERNEL);
+	if (!ov7692_sensorw) {
+		CDBG("kzalloc failed.\n");
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, ov7692_sensorw);
+	ov7692_init_client(client);
+	ov7692_client = client;
+
+	CDBG("ov7692_i2c_probe success! rc = %d\n", rc);
+	return 0;
+
+probe_failure:
+	CDBG("ov7692_i2c_probe failed! rc = %d\n", rc);
+	return rc;
+}
+
+static int __exit ov7692_remove(struct i2c_client *client)
+{
+	struct ov7692_work_t_t *sensorw = i2c_get_clientdata(client);
+	free_irq(client->irq, sensorw);
+	ov7692_client = NULL;
+	kfree(sensorw);
+	return 0;
+}
+
+static struct i2c_driver ov7692_i2c_driver = {
+	.id_table = ov7692_i2c_id,
+	.probe  = ov7692_i2c_probe,
+	.remove = __exit_p(ov7692_i2c_remove),
+	.driver = {
+		.name = "ov7692",
+	},
+};
+
+int ov7692_sensor_config(void __user *argp)
+{
+	struct sensor_cfg_data cdata;
+	long   rc = 0;
+	if (copy_from_user(&cdata,
+		(void *)argp,
+		sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+	mutex_lock(&ov7692_mut);
+	CDBG("ov7692_sensor_config: cfgtype = %d\n",
+	cdata.cfgtype);
+	switch (cdata.cfgtype) {
+	case CFG_SET_MODE:
+		rc = ov7692_set_sensor_mode(cdata.mode,
+			cdata.rs);
+		break;
+	case CFG_PWR_DOWN:
+		rc = ov7692_power_down();
+		break;
+	default:
+		rc = -EFAULT;
+		break;
+	}
+
+	mutex_unlock(&ov7692_mut);
+
+	return rc;
+}
+static int ov7692_sensor_release(void)
+{
+	int rc = -EBADF;
+	mutex_lock(&ov7692_mut);
+	ov7692_power_down();
+	kfree(ov7692_ctrl);
+	ov7692_ctrl = NULL;
+	CDBG("ov7692_release completed\n");
+	mutex_unlock(&ov7692_mut);
+
+	return rc;
+}
+
+static int ov7692_sensor_probe(const struct msm_camera_sensor_info *info,
+		struct msm_sensor_ctrl *s)
+{
+	int rc = 0;
+	rc = i2c_add_driver(&ov7692_i2c_driver);
+	if (rc < 0 || ov7692_client == NULL) {
+		rc = -ENOTSUPP;
+		goto probe_fail;
+	}
+	msm_camio_clk_rate_set(24000000);
+	rc = ov7692_probe_init_sensor(info);
+	if (rc < 0)
+		goto probe_fail;
+	s->s_init = ov7692_sensor_open_init;
+	s->s_release = ov7692_sensor_release;
+	s->s_config  = ov7692_sensor_config;
+	s->s_camera_type = FRONT_CAMERA_2D;
+	s->s_mount_angle = 0;
+	return rc;
+
+probe_fail:
+	CDBG("ov7692_sensor_probe: SENSOR PROBE FAILS!\n");
+	i2c_del_driver(&ov7692_i2c_driver);
+	return rc;
+}
+
+static int __ov7692_probe(struct platform_device *pdev)
+{
+
+	return msm_camera_drv_start(pdev, ov7692_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = __ov7692_probe,
+	.driver = {
+		.name = "msm_camera_ov7692",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init ov7692_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(ov7692_init);
+
+MODULE_DESCRIPTION("OMNI VGA YUV sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/ov7692.h b/drivers/media/video/msm/ov7692.h
new file mode 100644
index 0000000..e43a17d
--- /dev/null
+++ b/drivers/media/video/msm/ov7692.h
@@ -0,0 +1,50 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+#ifndef OV7692_H
+#define OV7692_H
+#include <linux/types.h>
+#include <mach/board.h>
+
+struct reg_addr_val_pair_struct {
+	uint8_t	reg_addr;
+	uint8_t	reg_val;
+};
+
+enum ov7692_test_mode_t {
+	TEST_OFF,
+	TEST_1,
+	TEST_2,
+	TEST_3
+};
+
+enum ov7692_resolution_t {
+	QTR_SIZE,
+	FULL_SIZE,
+	INVALID_SIZE
+};
+
+enum ov7692_setting {
+	RES_PREVIEW,
+	RES_CAPTURE
+};
+enum ov7692_reg_update {
+	/* Sensor egisters that need to be updated during initialization */
+	REG_INIT,
+	/* Sensor egisters that needs periodic I2C writes */
+	UPDATE_PERIODIC,
+	/* All the sensor Registers will be updated */
+	UPDATE_ALL,
+	/* Not valid update */
+	UPDATE_INVALID
+};
+#endif
+
diff --git a/drivers/media/video/msm/ov9726.c b/drivers/media/video/msm/ov9726.c
new file mode 100644
index 0000000..fc04558
--- /dev/null
+++ b/drivers/media/video/msm/ov9726.c
@@ -0,0 +1,792 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <media/msm_camera.h>
+#include <mach/gpio.h>
+#include <mach/camera.h>
+#include "ov9726.h"
+
+/*=============================================================
+	SENSOR REGISTER DEFINES
+==============================================================*/
+#define OV9726_Q8				0x00000100
+#define OV9726_Q8Shift				8
+#define OV9726_Q10				0x00000400
+#define OV9726_Q10Shift				10
+
+/* Omnivision8810 product ID register address */
+#define	OV9726_PIDH_REG				0x0000
+#define	OV9726_PIDL_REG				0x0001
+/* Omnivision8810 product ID */
+#define	OV9726_PID				0x97
+/* Omnivision8810 version */
+#define	OV9726_VER				0x26
+/* Time in milisecs for waiting for the sensor to reset */
+#define	OV9726_RESET_DELAY_MSECS		66
+#define	OV9726_DEFAULT_CLOCK_RATE		24000000
+/* Registers*/
+#define	OV9726_GAIN				0x3000
+#define	OV9726_AEC_MSB				0x3002
+#define	OV9726_AEC_LSB				0x3003
+
+/* Color bar pattern selection */
+#define OV9726_COLOR_BAR_PATTERN_SEL_REG	0x600
+/* Color bar enabling control */
+#define OV9726_COLOR_BAR_ENABLE_REG		0x601
+/* Time in milisecs for waiting for the sensor to reset*/
+#define OV9726_RESET_DELAY_MSECS		66
+/* I2C Address of the Sensor */
+/*============================================================================
+		DATA DECLARATIONS
+============================================================================*/
+#define OV9726_FULL_SIZE_DUMMY_PIXELS		0
+#define OV9726_FULL_SIZE_DUMMY_LINES		0
+#define OV9726_QTR_SIZE_DUMMY_PIXELS		0
+#define OV9726_QTR_SIZE_DUMMY_LINES		0
+
+#define OV9726_FULL_SIZE_WIDTH			1296
+#define OV9726_FULL_SIZE_HEIGHT			808
+
+#define OV9726_QTR_SIZE_WIDTH			1296
+#define OV9726_QTR_SIZE_HEIGHT			808
+
+#define OV9726_HRZ_FULL_BLK_PIXELS		368
+#define OV9726_VER_FULL_BLK_LINES		32
+#define OV9726_HRZ_QTR_BLK_PIXELS		368
+#define OV9726_VER_QTR_BLK_LINES		32
+
+#define OV9726_MSB_MASK			0xFF00
+#define OV9726_LSB_MASK			0x00FF
+
+struct ov9726_work_t {
+	struct work_struct work;
+};
+static struct ov9726_work_t *ov9726_sensorw;
+static struct i2c_client *ov9726_client;
+struct ov9726_ctrl_t {
+	const struct  msm_camera_sensor_info *sensordata;
+	uint32_t sensormode;
+	uint32_t fps_divider;		/* init to 1 * 0x00000400 */
+	uint32_t pict_fps_divider;	/* init to 1 * 0x00000400 */
+	uint16_t fps;
+	int16_t curr_lens_pos;
+	uint16_t curr_step_pos;
+	uint16_t my_reg_gain;
+	uint32_t my_reg_line_count;
+	uint16_t total_lines_per_frame;
+	enum ov9726_resolution_t prev_res;
+	enum ov9726_resolution_t pict_res;
+	enum ov9726_resolution_t curr_res;
+	enum ov9726_test_mode_t  set_test;
+	unsigned short imgaddr;
+};
+static struct ov9726_ctrl_t *ov9726_ctrl;
+static int8_t config_not_set = 1;
+static DECLARE_WAIT_QUEUE_HEAD(ov9726_wait_queue);
+DEFINE_MUTEX(ov9726_mut);
+
+/*=============================================================*/
+static int ov9726_i2c_rxdata(unsigned short saddr,
+	unsigned char *rxdata, int length)
+{
+	struct i2c_msg msgs[] = {
+	{
+		.addr  = saddr,
+		.flags = 0,
+		.len   = 2,
+		.buf   = rxdata,
+	},
+	{
+		.addr  = saddr,
+		.flags = I2C_M_RD,
+		.len   = length,
+		.buf   = rxdata,
+	},
+	};
+
+	if (i2c_transfer(ov9726_client->adapter, msgs, 2) < 0) {
+		CDBG("ov9726_i2c_rxdata failed!\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t ov9726_i2c_txdata(unsigned short saddr,
+				unsigned char *txdata, int length)
+{
+	struct i2c_msg msg[] = {
+		{
+		 .addr = saddr ,
+		 .flags = 0,
+		 .len = length,
+		 .buf = txdata,
+		 },
+	};
+
+	if (i2c_transfer(ov9726_client->adapter, msg, 1) < 0) {
+		CDBG("ov9726_i2c_txdata faild 0x%x\n", ov9726_client->addr);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t ov9726_i2c_read(unsigned short raddr,
+				unsigned short *rdata, int rlen)
+{
+	int32_t rc = 0;
+	unsigned char buf[2];
+
+	if (!rdata)
+		return -EIO;
+
+	buf[0] = (raddr & OV9726_MSB_MASK) >> 8;
+	buf[1] = (raddr & OV9726_LSB_MASK);
+
+	rc = ov9726_i2c_rxdata(ov9726_client->addr, buf, rlen);
+
+	if (rc < 0) {
+		CDBG("ov9726_i2c_read 0x%x failed!\n", raddr);
+		return rc;
+	}
+
+	*rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]);
+	return rc;
+}
+
+static int32_t ov9726_i2c_write_b(unsigned short saddr,
+	unsigned short waddr, uint8_t bdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[3];
+
+	buf[0] = (waddr & OV9726_MSB_MASK) >> 8;
+	buf[1] = (waddr & OV9726_LSB_MASK);
+	buf[2] = bdata;
+
+	CDBG("i2c_write_b addr = 0x%x, val = 0x%xd\n", waddr, bdata);
+	rc = ov9726_i2c_txdata(saddr, buf, 3);
+
+	if (rc < 0) {
+		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+			 waddr, bdata);
+	}
+
+	return rc;
+}
+
+static void ov9726_get_pict_fps(uint16_t fps, uint16_t *pfps)
+{
+	uint32_t divider;	/*Q10 */
+	uint32_t d1;
+	uint32_t d2;
+	uint16_t snapshot_height, preview_height, preview_width, snapshot_width;
+	if (ov9726_ctrl->prev_res == QTR_SIZE) {
+		preview_width = OV9726_QTR_SIZE_WIDTH +
+			OV9726_HRZ_QTR_BLK_PIXELS ;
+		preview_height = OV9726_QTR_SIZE_HEIGHT +
+			OV9726_VER_QTR_BLK_LINES ;
+	} else {
+		/* full size resolution used for preview. */
+		preview_width = OV9726_FULL_SIZE_WIDTH +
+			OV9726_HRZ_FULL_BLK_PIXELS ;
+		preview_height = OV9726_FULL_SIZE_HEIGHT +
+			OV9726_VER_FULL_BLK_LINES ;
+	}
+	if (ov9726_ctrl->pict_res == QTR_SIZE) {
+		snapshot_width  = OV9726_QTR_SIZE_WIDTH +
+			OV9726_HRZ_QTR_BLK_PIXELS ;
+		snapshot_height = OV9726_QTR_SIZE_HEIGHT +
+			OV9726_VER_QTR_BLK_LINES ;
+	} else {
+		snapshot_width  = OV9726_FULL_SIZE_WIDTH +
+			OV9726_HRZ_FULL_BLK_PIXELS;
+		snapshot_height = OV9726_FULL_SIZE_HEIGHT +
+			OV9726_VER_FULL_BLK_LINES;
+	}
+
+	d1 = (uint32_t)(((uint32_t)preview_height <<
+		OV9726_Q10Shift) /
+		snapshot_height);
+
+	d2 = (uint32_t)(((uint32_t)preview_width <<
+		OV9726_Q10Shift) /
+		 snapshot_width);
+
+	divider = (uint32_t) (d1 * d2) >> OV9726_Q10Shift;
+	*pfps = (uint16_t)((uint32_t)(fps * divider) >> OV9726_Q10Shift);
+}
+
+static uint16_t ov9726_get_prev_lines_pf(void)
+{
+	if (ov9726_ctrl->prev_res == QTR_SIZE)
+		return OV9726_QTR_SIZE_HEIGHT + OV9726_VER_QTR_BLK_LINES;
+	else
+		return OV9726_FULL_SIZE_HEIGHT + OV9726_VER_FULL_BLK_LINES;
+}
+
+static uint16_t ov9726_get_prev_pixels_pl(void)
+{
+	if (ov9726_ctrl->prev_res == QTR_SIZE)
+		return OV9726_QTR_SIZE_WIDTH + OV9726_HRZ_QTR_BLK_PIXELS;
+	else
+		return OV9726_FULL_SIZE_WIDTH + OV9726_HRZ_FULL_BLK_PIXELS;
+}
+
+static uint16_t ov9726_get_pict_lines_pf(void)
+{
+	if (ov9726_ctrl->pict_res == QTR_SIZE)
+		return OV9726_QTR_SIZE_HEIGHT + OV9726_VER_QTR_BLK_LINES;
+	else
+		return OV9726_FULL_SIZE_HEIGHT + OV9726_VER_FULL_BLK_LINES;
+}
+
+static uint16_t ov9726_get_pict_pixels_pl(void)
+{
+	if (ov9726_ctrl->pict_res == QTR_SIZE)
+		return OV9726_QTR_SIZE_WIDTH + OV9726_HRZ_QTR_BLK_PIXELS;
+	else
+		return OV9726_FULL_SIZE_WIDTH + OV9726_HRZ_FULL_BLK_PIXELS;
+}
+
+static uint32_t ov9726_get_pict_max_exp_lc(void)
+{
+	if (ov9726_ctrl->pict_res == QTR_SIZE)
+		return (OV9726_QTR_SIZE_HEIGHT + OV9726_VER_QTR_BLK_LINES)*24;
+	else
+		return (OV9726_FULL_SIZE_HEIGHT + OV9726_VER_FULL_BLK_LINES)*24;
+}
+
+static int32_t ov9726_set_fps(struct fps_cfg	*fps)
+{
+	int32_t rc = 0;
+	CDBG("%s: fps->fps_div = %d\n", __func__, fps->fps_div);
+	/* TODO: Passing of fps_divider from user space has issues. */
+	/* ov9726_ctrl->fps_divider = fps->fps_div; */
+	ov9726_ctrl->fps_divider = 1 * 0x400;
+	CDBG("%s: ov9726_ctrl->fps_divider = %d\n", __func__,
+		ov9726_ctrl->fps_divider);
+	ov9726_ctrl->pict_fps_divider = fps->pict_fps_div;
+	ov9726_ctrl->fps = fps->f_mult;
+	return rc;
+}
+
+static int32_t ov9726_write_exp_gain(uint16_t gain, uint32_t line)
+{
+	static uint16_t max_legal_gain = 0x00FF;
+	uint8_t gain_msb, gain_lsb;
+	uint8_t intg_time_msb, intg_time_lsb;
+	uint8_t ov9726_offset = 6;
+	uint8_t line_length_pck_msb, line_length_pck_lsb;
+	uint16_t line_length_pck, frame_length_lines;
+	uint32_t line_length_ratio = 1 << OV9726_Q8Shift;
+	int32_t rc = -1;
+	CDBG("%s: gain = %d	line = %d", __func__, gain, line);
+
+	if (ov9726_ctrl->sensormode != SENSOR_SNAPSHOT_MODE) {
+		if (ov9726_ctrl->curr_res == QTR_SIZE) {
+			frame_length_lines = OV9726_QTR_SIZE_HEIGHT +
+			 OV9726_VER_QTR_BLK_LINES;
+			line_length_pck = OV9726_QTR_SIZE_WIDTH	+
+			 OV9726_HRZ_QTR_BLK_PIXELS;
+		} else {
+			frame_length_lines = OV9726_FULL_SIZE_HEIGHT +
+				OV9726_VER_FULL_BLK_LINES;
+			line_length_pck = OV9726_FULL_SIZE_WIDTH +
+				OV9726_HRZ_FULL_BLK_PIXELS;
+		}
+		if (line > (frame_length_lines - ov9726_offset))
+			ov9726_ctrl->fps = (uint16_t) (((uint32_t)30 <<
+				OV9726_Q8Shift) *
+				(frame_length_lines - ov9726_offset) / line);
+		else
+			ov9726_ctrl->fps = (uint16_t) ((uint32_t)30 <<
+				OV9726_Q8Shift);
+	} else {
+		frame_length_lines = OV9726_FULL_SIZE_HEIGHT +
+			OV9726_VER_FULL_BLK_LINES;
+		line_length_pck = OV9726_FULL_SIZE_WIDTH +
+			OV9726_HRZ_FULL_BLK_PIXELS;
+	}
+
+	if (ov9726_ctrl->sensormode != SENSOR_SNAPSHOT_MODE) {
+		line = (uint32_t) (line * ov9726_ctrl->fps_divider) >>
+			OV9726_Q10Shift;
+	} else {
+		line = (uint32_t) (line * ov9726_ctrl->pict_fps_divider) >>
+			OV9726_Q10Shift;
+	}
+
+	/* calculate line_length_ratio */
+	if (line > (frame_length_lines - ov9726_offset)) {
+		line_length_ratio = (line << OV9726_Q8Shift) /
+			(frame_length_lines - ov9726_offset);
+		line = frame_length_lines - ov9726_offset;
+	} else
+		line_length_ratio = (uint32_t)1 << OV9726_Q8Shift;
+
+	if (gain > max_legal_gain) {
+		/* range:	0	to 224 */
+		gain = max_legal_gain;
+	}
+	/* update	gain registers */
+	gain_msb = (uint8_t) ((gain & 0xFF00) >> 8);
+	gain_lsb = (uint8_t) (gain & 0x00FF);
+	/* linear	AFR	horizontal stretch */
+	line_length_pck = (uint16_t) ((line_length_pck *
+		line_length_ratio) >> OV9726_Q8Shift);
+	line_length_pck_msb = (uint8_t) ((line_length_pck & 0xFF00) >> 8);
+	line_length_pck_lsb = (uint8_t) (line_length_pck & 0x00FF);
+	/* update	line count registers */
+	intg_time_msb = (uint8_t) ((line & 0xFF00) >> 8);
+	intg_time_lsb = (uint8_t) (line	& 0x00FF);
+
+	rc = ov9726_i2c_write_b(ov9726_client->addr, 0x104, 0x1);
+	if (rc < 0)
+		return rc;
+
+	rc = ov9726_i2c_write_b(ov9726_client->addr, 0x204, gain_msb);
+	if (rc < 0)
+		return rc;
+
+	rc = ov9726_i2c_write_b(ov9726_client->addr, 0x205, gain_lsb);
+	if (rc < 0)
+		return rc;
+
+	rc = ov9726_i2c_write_b(ov9726_client->addr, 0x342,
+		line_length_pck_msb);
+	if (rc < 0)
+		return rc;
+
+	rc = ov9726_i2c_write_b(ov9726_client->addr, 0x343,
+		line_length_pck_lsb);
+	if (rc < 0)
+		return rc;
+
+	rc = ov9726_i2c_write_b(ov9726_client->addr, 0x0202, intg_time_msb);
+	if (rc < 0)
+		return rc;
+
+	rc = ov9726_i2c_write_b(ov9726_client->addr, 0x0203, intg_time_lsb);
+	if (rc < 0)
+		return rc;
+
+	rc = ov9726_i2c_write_b(ov9726_client->addr, 0x104, 0x0);
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+
+static int32_t ov9726_set_pict_exp_gain(uint16_t gain, uint32_t line)
+{
+	int32_t rc = 0;
+	rc = ov9726_write_exp_gain(gain, line);
+	return rc;
+}
+
+static int32_t initialize_ov9726_registers(void)
+{
+	int32_t i;
+	int32_t rc = 0;
+	ov9726_ctrl->sensormode = SENSOR_PREVIEW_MODE ;
+	/* Configure sensor for Preview mode and Snapshot mode */
+	CDBG("Initialize_ov9726_registers\n");
+	for (i = 0; i < ov9726_array_length; i++) {
+		rc = ov9726_i2c_write_b(ov9726_client->addr,
+			ov9726_init_settings_array[i].reg_addr,
+			ov9726_init_settings_array[i].reg_val);
+	if (rc < 0)
+		return rc;
+	}
+	return rc;
+}
+
+static int32_t ov9726_video_config(int mode)
+{
+	int32_t rc = 0;
+
+	ov9726_ctrl->sensormode = mode;
+
+	if (config_not_set) {
+		struct msm_camera_csi_params ov9726_csi_params;
+
+		/* sensor in standby */
+		ov9726_i2c_write_b(ov9726_client->addr, 0x100, 0);
+		msleep(5);
+		/* Initialize Sensor registers */
+		ov9726_csi_params.data_format = CSI_10BIT;
+		ov9726_csi_params.lane_cnt = 1;
+		ov9726_csi_params.lane_assign = 0xe4;
+		ov9726_csi_params.dpcm_scheme = 0;
+		ov9726_csi_params.settle_cnt = 7;
+
+		rc = msm_camio_csi_config(&ov9726_csi_params);
+		rc = initialize_ov9726_registers();
+		config_not_set = 0;
+	}
+	return rc;
+}
+
+static int32_t ov9726_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+	ov9726_ctrl->sensormode = mode;
+	return rc;
+}
+
+static int32_t ov9726_raw_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+	ov9726_ctrl->sensormode = mode;
+	return rc;
+}
+
+static int32_t ov9726_set_sensor_mode(int  mode,
+			int  res)
+{
+	int32_t rc = 0;
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		rc = ov9726_video_config(mode);
+		break;
+	case SENSOR_SNAPSHOT_MODE:
+		rc = ov9726_snapshot_config(mode);
+		break;
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		rc = ov9726_raw_snapshot_config(mode);
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+static int ov9726_probe_init_sensor(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc = 0;
+	uint16_t  chipidl, chipidh;
+
+	if (data->sensor_reset_enable) {
+		rc = gpio_request(data->sensor_reset, "ov9726");
+		if (!rc) {
+			gpio_direction_output(data->sensor_reset, 0);
+			gpio_set_value_cansleep(data->sensor_reset, 1);
+			msleep(20);
+		} else
+			goto init_probe_done;
+	}
+	/* 3. Read sensor Model ID: */
+	rc = ov9726_i2c_read(OV9726_PIDH_REG, &chipidh, 1);
+	if (rc < 0)
+		goto init_probe_fail;
+	rc = ov9726_i2c_read(OV9726_PIDL_REG, &chipidl, 1);
+	if (rc < 0)
+		goto init_probe_fail;
+	CDBG("kov9726 model_id = 0x%x  0x%x\n", chipidh, chipidl);
+	/* 4. Compare sensor ID to OV9726 ID: */
+	if (chipidh != OV9726_PID) {
+		rc = -ENODEV;
+		printk(KERN_INFO "Probeinit fail\n");
+		goto init_probe_fail;
+	}
+	CDBG("chipidh == OV9726_PID\n");
+	msleep(OV9726_RESET_DELAY_MSECS);
+	CDBG("after delay\n");
+	goto init_probe_done;
+
+init_probe_fail:
+	if (data->sensor_reset_enable) {
+		gpio_direction_output(data->sensor_reset, 0);
+		gpio_free(data->sensor_reset);
+	}
+init_probe_done:
+	printk(KERN_INFO " ov9726_probe_init_sensor finishes\n");
+	return rc;
+}
+
+int ov9726_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+	int32_t  rc;
+
+	CDBG("Calling ov9726_sensor_open_init\n");
+	ov9726_ctrl = kzalloc(sizeof(struct ov9726_ctrl_t), GFP_KERNEL);
+	if (!ov9726_ctrl) {
+		CDBG("ov9726_init failed!\n");
+		rc = -ENOMEM;
+		goto init_done;
+	}
+	ov9726_ctrl->curr_lens_pos = -1;
+	ov9726_ctrl->fps_divider = 1 << OV9726_Q10Shift;
+	ov9726_ctrl->pict_fps_divider = 1 << OV9726_Q10Shift;
+	ov9726_ctrl->set_test = TEST_OFF;
+	ov9726_ctrl->prev_res = FULL_SIZE;
+	ov9726_ctrl->pict_res = FULL_SIZE;
+	ov9726_ctrl->curr_res = INVALID_SIZE;
+	config_not_set = 1;
+	if (data)
+		ov9726_ctrl->sensordata = data;
+	/* enable mclk first */
+	msm_camio_clk_rate_set(OV9726_DEFAULT_CLOCK_RATE);
+	msleep(20);
+	rc = ov9726_probe_init_sensor(data);
+	if (rc < 0)
+		goto init_fail;
+
+	ov9726_ctrl->fps = (uint16_t)(30 << OV9726_Q8Shift);
+	/* generate test pattern */
+	if (rc < 0)
+		goto init_fail;
+	else
+		goto init_done;
+	/* reset the driver state */
+init_fail:
+	CDBG(" init_fail\n");
+	kfree(ov9726_ctrl);
+init_done:
+	CDBG("init_done\n");
+	return rc;
+}
+
+static int ov9726_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&ov9726_wait_queue);
+	return 0;
+}
+
+static const struct i2c_device_id ov9726_i2c_id[] = {
+	{ "ov9726", 0},
+	{ }
+};
+
+static int ov9726_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int rc = 0;
+	CDBG("ov9726_probe called!\n");
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		CDBG("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+	ov9726_sensorw = kzalloc(sizeof(struct ov9726_work_t), GFP_KERNEL);
+	if (!ov9726_sensorw) {
+		CDBG("kzalloc failed.\n");
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+	i2c_set_clientdata(client, ov9726_sensorw);
+	ov9726_init_client(client);
+	ov9726_client = client;
+	msleep(50);
+	CDBG("ov9726_probe successed! rc = %d\n", rc);
+	return 0;
+probe_failure:
+	CDBG("ov9726_probe failed! rc = %d\n", rc);
+	return rc;
+}
+
+static int __exit ov9726_remove(struct i2c_client *client)
+{
+	struct ov9726_work_t_t *sensorw = i2c_get_clientdata(client);
+	free_irq(client->irq, sensorw);
+	ov9726_client = NULL;
+	kfree(sensorw);
+	return 0;
+}
+
+static struct i2c_driver ov9726_i2c_driver = {
+	.id_table = ov9726_i2c_id,
+	.probe	= ov9726_i2c_probe,
+	.remove = __exit_p(ov9726_i2c_remove),
+	.driver = {
+		.name = "ov9726",
+	},
+};
+
+int ov9726_sensor_config(void __user *argp)
+{
+	struct sensor_cfg_data cdata;
+	long   rc = 0;
+
+	if (copy_from_user(&cdata,
+				(void *)argp,
+				sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+	mutex_lock(&ov9726_mut);
+	CDBG("ov9726_sensor_config: cfgtype = %d\n",
+		cdata.cfgtype);
+	switch (cdata.cfgtype) {
+	case CFG_GET_PICT_FPS:
+		ov9726_get_pict_fps(cdata.cfg.gfps.prevfps,
+				&(cdata.cfg.gfps.pictfps));
+		if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+			break;
+	case CFG_GET_PREV_L_PF:
+		cdata.cfg.prevl_pf = ov9726_get_prev_lines_pf();
+		if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+	case CFG_GET_PREV_P_PL:
+		cdata.cfg.prevp_pl = ov9726_get_prev_pixels_pl();
+		if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+	case CFG_GET_PICT_L_PF:
+		cdata.cfg.pictl_pf = ov9726_get_pict_lines_pf();
+		if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+	case CFG_GET_PICT_P_PL:
+		cdata.cfg.pictp_pl =
+				ov9726_get_pict_pixels_pl();
+		if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+	case CFG_GET_PICT_MAX_EXP_LC:
+		cdata.cfg.pict_max_exp_lc = ov9726_get_pict_max_exp_lc();
+		if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+	case CFG_SET_FPS:
+	case CFG_SET_PICT_FPS:
+		rc = ov9726_set_fps(&(cdata.cfg.fps));
+		break;
+	case CFG_SET_EXP_GAIN:
+		rc = ov9726_write_exp_gain(
+					cdata.cfg.exp_gain.gain,
+					cdata.cfg.exp_gain.line);
+		break;
+	case CFG_SET_PICT_EXP_GAIN:
+		rc = ov9726_set_pict_exp_gain(
+					cdata.cfg.exp_gain.gain,
+					cdata.cfg.exp_gain.line);
+		break;
+	case CFG_SET_MODE:
+		rc = ov9726_set_sensor_mode(cdata.mode,
+						cdata.rs);
+		break;
+	case CFG_PWR_DOWN:
+	case CFG_MOVE_FOCUS:
+	case CFG_SET_DEFAULT_FOCUS:
+		rc = 0;
+		break;
+	case CFG_SET_EFFECT:
+	default:
+		rc = -EFAULT;
+		break;
+	}
+	mutex_unlock(&ov9726_mut);
+	return rc;
+}
+
+static int ov9726_probe_init_done(const struct msm_camera_sensor_info *data)
+{
+	if (data->sensor_reset_enable) {
+		gpio_direction_output(data->sensor_reset, 0);
+		gpio_free(data->sensor_reset);
+	}
+	return 0;
+}
+
+static int ov9726_sensor_release(void)
+{
+	int rc = -EBADF;
+	mutex_lock(&ov9726_mut);
+	gpio_direction_output(ov9726_ctrl->sensordata->sensor_reset,
+		0);
+	gpio_free(ov9726_ctrl->sensordata->sensor_reset);
+	kfree(ov9726_ctrl);
+	ov9726_ctrl = NULL;
+	CDBG("ov9726_release completed\n");
+	mutex_unlock(&ov9726_mut);
+	return rc;
+}
+
+static int ov9726_sensor_probe(const struct msm_camera_sensor_info *info,
+		struct msm_sensor_ctrl *s)
+{
+	int rc = 0;
+
+	rc = i2c_add_driver(&ov9726_i2c_driver);
+	if (rc < 0 || ov9726_client == NULL) {
+		rc = -ENOTSUPP;
+		goto probe_fail;
+	}
+	msm_camio_clk_rate_set(24000000);
+	msleep(20);
+	rc = ov9726_probe_init_sensor(info);
+	if (rc < 0)
+		goto probe_fail;
+
+	s->s_init = ov9726_sensor_open_init;
+	s->s_release = ov9726_sensor_release;
+	s->s_config  = ov9726_sensor_config;
+	s->s_camera_type = FRONT_CAMERA_2D;
+	s->s_mount_angle = info->sensor_platform_info->mount_angle;
+	ov9726_probe_init_done(info);
+
+	return rc;
+
+probe_fail:
+	CDBG("SENSOR PROBE FAILS!\n");
+	return rc;
+}
+
+static int __ov9726_probe(struct platform_device *pdev)
+{
+	return msm_camera_drv_start(pdev, ov9726_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = __ov9726_probe,
+	.driver = {
+		.name = "msm_camera_ov9726",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init ov9726_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(ov9726_init);
+void ov9726_exit(void)
+{
+	i2c_del_driver(&ov9726_i2c_driver);
+}
+
+MODULE_DESCRIPTION("OMNI VGA Bayer sensor driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/media/video/msm/ov9726.h b/drivers/media/video/msm/ov9726.h
new file mode 100644
index 0000000..56d3da6
--- /dev/null
+++ b/drivers/media/video/msm/ov9726.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef OV9726_H
+#define OV9726_H
+#include <linux/types.h>
+#include <mach/board.h>
+
+/* 16bit address - 8 bit context register structure */
+struct reg_struct_type {
+	uint16_t	reg_addr;
+	unsigned char	reg_val;
+};
+
+enum ov9726_test_mode_t {
+	TEST_OFF,
+	TEST_1,
+	TEST_2,
+	TEST_3
+};
+
+enum ov9726_resolution_t {
+	QTR_SIZE,
+	FULL_SIZE,
+	INVALID_SIZE
+};
+extern struct reg_struct_type ov9726_init_settings_array[];
+extern int32_t ov9726_array_length;
+#endif
+
diff --git a/drivers/media/video/msm/ov9726_reg.c b/drivers/media/video/msm/ov9726_reg.c
new file mode 100644
index 0000000..54afbe8
--- /dev/null
+++ b/drivers/media/video/msm/ov9726_reg.c
@@ -0,0 +1,101 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include "ov9726.h"
+struct reg_struct_type ov9726_init_settings_array[] = {
+	{0x0103, 0x01}, /* SOFTWARE_RESET */
+	{0x3026, 0x00}, /* OUTPUT_SELECT01 */
+	{0x3027, 0x00}, /* OUTPUT_SELECT02 */
+	{0x3002, 0xe8}, /* IO_CTRL00 */
+	{0x3004, 0x03}, /* IO_CTRL01 */
+	{0x3005, 0xff}, /* IO_CTRL02 */
+	{0x3703, 0x42},
+	{0x3704, 0x10},
+	{0x3705, 0x45},
+	{0x3603, 0xaa},
+	{0x3632, 0x2f},
+	{0x3620, 0x66},
+	{0x3621, 0xc0},
+	{0x0340, 0x03}, /* FRAME_LENGTH_LINES_HI */
+	{0x0341, 0xC1}, /* FRAME_LENGTH_LINES_LO */
+	{0x0342, 0x06}, /* LINE_LENGTH_PCK_HI */
+	{0x0343, 0x80}, /* LINE_LENGTH_PCK_LO */
+	{0x0202, 0x03}, /* COARSE_INTEGRATION_TIME_HI */
+	{0x0203, 0x43}, /* COARSE_INTEGRATION_TIME_LO */
+	{0x3833, 0x04},
+	{0x3835, 0x02},
+	{0x4702, 0x04},
+	{0x4704, 0x00}, /* DVP_CTRL01 */
+	{0x4706, 0x08},
+	{0x5052, 0x01},
+	{0x3819, 0x6e},
+	{0x3817, 0x94},
+	{0x3a18, 0x00}, /* AEC_GAIN_CEILING_HI */
+	{0x3a19, 0x7f}, /* AEC_GAIN_CEILING_LO */
+	{0x404e, 0x7e},
+	{0x3631, 0x52},
+	{0x3633, 0x50},
+	{0x3630, 0xd2},
+	{0x3604, 0x08},
+	{0x3601, 0x40},
+	{0x3602, 0x14},
+	{0x3610, 0xa0},
+	{0x3612, 0x20},
+	{0x034c, 0x05}, /* X_OUTPUT_SIZE_HI */
+	{0x034d, 0x10}, /* X_OUTPUT_SIZE_LO */
+	{0x034e, 0x03}, /* Y_OUTPUT_SIZE_HI */
+	{0x034f, 0x28}, /* Y_OUTPUT_SIZE_LO */
+	{0x0340, 0x03}, /* FRAME_LENGTH_LINES_HI */
+	{0x0341, 0xC1}, /* FRAME_LENGTH_LINES_LO */
+	{0x0342, 0x06}, /* LINE_LENGTH_PCK_HI */
+	{0x0343, 0x80}, /* LINE_LENGTH_PCK_LO */
+	{0x0202, 0x03}, /* COARSE_INTEGRATION_TIME_HI */
+	{0x0203, 0x43}, /* COARSE_INTEGRATION_TIME_LO */
+	{0x0303, 0x01}, /* VT_SYS_CLK_DIV_LO */
+	{0x3002, 0x00}, /* IO_CTRL00 */
+	{0x3004, 0x00}, /* IO_CTRL01 */
+	{0x3005, 0x00}, /* IO_CTRL02 */
+	{0x4801, 0x0f}, /* MIPI_CTRL01 */
+	{0x4803, 0x05}, /* MIPI_CTRL03 */
+	{0x4601, 0x16}, /* VFIFO_READ_CONTROL */
+	{0x3014, 0x05}, /* SC_CMMN_MIPI / SC_CTRL00 */
+	{0x3104, 0x80},
+	{0x0305, 0x04}, /* PRE_PLL_CLK_DIV_LO */
+	{0x0307, 0x64}, /* PLL_MULTIPLIER_LO */
+	{0x300c, 0x02},
+	{0x300d, 0x20},
+	{0x300e, 0x01},
+	{0x3010, 0x01},
+	{0x460e, 0x81}, /* VFIFO_CONTROL00 */
+	{0x0101, 0x01}, /* IMAGE_ORIENTATION */
+	{0x3707, 0x14},
+	{0x3622, 0x9f},
+	{0x5047, 0x3D}, /* ISP_CTRL47 */
+	{0x4002, 0x45}, /* BLC_CTRL02 */
+	{0x5000, 0x06}, /* ISP_CTRL0 */
+	{0x5001, 0x00}, /* ISP_CTRL1 */
+	{0x3406, 0x00}, /* AWB_MANUAL_CTRL */
+	{0x3503, 0x13}, /* AEC_ENABLE */
+	{0x4005, 0x18}, /* BLC_CTRL05 */
+	{0x4837, 0x21},
+	{0x0100, 0x01}, /* MODE_SELECT */
+	{0x3a0f, 0x64}, /* AEC_CTRL0F */
+	{0x3a10, 0x54}, /* AEC_CTRL10 */
+	{0x3a11, 0xc2}, /* AEC_CTRL11 */
+	{0x3a1b, 0x64}, /* AEC_CTRL1B */
+	{0x3a1e, 0x54}, /* AEC_CTRL1E */
+	{0x3a1a, 0x05}, /* AEC_DIFF_MAX */
+};
+int32_t ov9726_array_length = sizeof(ov9726_init_settings_array) /
+	sizeof(ov9726_init_settings_array[0]);
+
diff --git a/drivers/media/video/msm/qs_s5k4e1.c b/drivers/media/video/msm/qs_s5k4e1.c
new file mode 100644
index 0000000..d6bb51d
--- /dev/null
+++ b/drivers/media/video/msm/qs_s5k4e1.c
@@ -0,0 +1,1663 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <media/msm_camera.h>
+#include <mach/gpio.h>
+#include <mach/camera.h>
+#include "qs_s5k4e1.h"
+/*=============================================================
+	SENSOR REGISTER DEFINES
+==============================================================*/
+#define REG_GROUPED_PARAMETER_HOLD		0x0104
+#define GROUPED_PARAMETER_HOLD_OFF		0x00
+#define GROUPED_PARAMETER_HOLD			0x01
+/* Integration Time */
+#define REG_COARSE_INTEGRATION_TIME		0x0202
+/* Gain */
+#define REG_GLOBAL_GAIN					0x0204
+#define REG_GR_GAIN					0x020E
+#define REG_R_GAIN					0x0210
+#define REG_B_GAIN					0x0212
+#define REG_GB_GAIN					0x0214
+/* PLL registers */
+#define REG_FRAME_LENGTH_LINES			0x0340
+#define REG_LINE_LENGTH_PCK				0x0342
+/* Test Pattern */
+#define REG_TEST_PATTERN_MODE			0x0601
+#define REG_VCM_NEW_CODE				0x30F2
+#define AF_ADDR							0x18
+#define BRIDGE_ADDR						0x80
+/*============================================================================
+			 TYPE DECLARATIONS
+============================================================================*/
+
+/* 16bit address - 8 bit context register structure */
+#define Q8  0x00000100
+#define Q10 0x00000400
+#define QS_S5K4E1_MASTER_CLK_RATE 24000000
+#define QS_S5K4E1_OFFSET			8
+
+/* AF Total steps parameters */
+#define QS_S5K4E1_TOTAL_STEPS_NEAR_TO_FAR    32
+
+uint16_t qs_s5k4e1_step_position_table[QS_S5K4E1_TOTAL_STEPS_NEAR_TO_FAR+1];
+uint16_t qs_s5k4e1_nl_region_boundary1;
+uint16_t qs_s5k4e1_nl_region_code_per_step1 = 190;
+uint16_t qs_s5k4e1_l_region_code_per_step = 8;
+uint16_t qs_s5k4e1_damping_threshold = 10;
+uint16_t qs_s5k4e1_sw_damping_time_wait = 8;
+uint16_t qs_s5k4e1_af_mode = 4;
+int16_t qs_s5k4e1_af_initial_code = 190;
+int16_t qs_s5k4e1_af_right_adjust;
+
+struct qs_s5k4e1_work_t {
+	struct work_struct work;
+};
+
+static struct qs_s5k4e1_work_t *qs_s5k4e1_sensorw;
+static struct i2c_client *qs_s5k4e1_client;
+static char lens_eeprom_data[864];
+static bool cali_data_status;
+struct qs_s5k4e1_ctrl_t {
+	const struct  msm_camera_sensor_info *sensordata;
+
+	uint32_t sensormode;
+	uint32_t fps_divider;/* init to 1 * 0x00000400 */
+	uint32_t pict_fps_divider;/* init to 1 * 0x00000400 */
+	uint16_t fps;
+
+	uint16_t curr_lens_pos;
+	uint16_t curr_step_pos;
+	uint16_t my_reg_gain;
+	uint32_t my_reg_line_count;
+	uint16_t total_lines_per_frame;
+
+	enum qs_s5k4e1_resolution_t prev_res;
+	enum qs_s5k4e1_resolution_t pict_res;
+	enum qs_s5k4e1_resolution_t curr_res;
+	enum qs_s5k4e1_test_mode_t  set_test;
+	enum qs_s5k4e1_cam_mode_t cam_mode;
+};
+
+static uint16_t prev_line_length_pck;
+static uint16_t prev_frame_length_lines;
+static uint16_t snap_line_length_pck;
+static uint16_t snap_frame_length_lines;
+
+static bool CSI_CONFIG, LENS_SHADE_CONFIG, default_lens_shade;
+static struct qs_s5k4e1_ctrl_t *qs_s5k4e1_ctrl;
+static DECLARE_WAIT_QUEUE_HEAD(qs_s5k4e1_wait_queue);
+DEFINE_MUTEX(qs_s5k4e1_mut);
+
+static int cam_debug_init(void);
+static struct dentry *debugfs_base;
+/*=============================================================*/
+
+static int qs_s5k4e1_i2c_rxdata(unsigned short saddr,
+	unsigned char *rxdata, int length)
+{
+	struct i2c_msg msgs[] = {
+		{
+			.addr  = saddr,
+			.flags = 0,
+			.len   = 2,
+			.buf   = rxdata,
+		},
+		{
+			.addr  = saddr,
+			.flags = I2C_M_RD,
+			.len   = length,
+			.buf   = rxdata,
+		},
+	};
+	if (i2c_transfer(qs_s5k4e1_client->adapter, msgs, 2) < 0) {
+		CDBG("qs_s5k4e1_i2c_rxdata faild 0x%x\n", saddr);
+		return -EIO;
+	}
+	return 0;
+}
+
+static int32_t qs_s5k4e1_i2c_txdata(unsigned short saddr,
+				unsigned char *txdata, int length)
+{
+	struct i2c_msg msg[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = length,
+			.buf = txdata,
+		 },
+	};
+	if (i2c_transfer(qs_s5k4e1_client->adapter, msg, 1) < 0) {
+		CDBG("qs_s5k4e1_i2c_txdata faild 0x%x\n", saddr);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t qs_s5k4e1_i2c_read(unsigned short raddr,
+	unsigned short *rdata, int rlen)
+{
+	int32_t rc = 0;
+	unsigned char buf[2];
+	if (!rdata)
+		return -EIO;
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (raddr & 0xFF00) >> 8;
+	buf[1] = (raddr & 0x00FF);
+	rc = qs_s5k4e1_i2c_rxdata(qs_s5k4e1_client->addr>>1, buf, rlen);
+	if (rc < 0) {
+		CDBG("qs_s5k4e1_i2c_read 0x%x failed!\n", raddr);
+		return rc;
+	}
+	*rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]);
+	CDBG("qs_s5k4e1_i2c_read 0x%x val = 0x%x!\n", raddr, *rdata);
+	return rc;
+}
+
+static int32_t qs_s5k4e1_i2c_write_w_sensor(unsigned short waddr,
+	 uint16_t wdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[4];
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = (wdata & 0xFF00) >> 8;
+	buf[3] = (wdata & 0x00FF);
+	CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, wdata);
+	rc = qs_s5k4e1_i2c_txdata(qs_s5k4e1_client->addr>>1, buf, 4);
+	if (rc < 0) {
+		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+			waddr, wdata);
+	}
+	return rc;
+}
+
+static int32_t qs_s5k4e1_i2c_write_b_sensor(unsigned short waddr, uint8_t bdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[3];
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = bdata;
+	CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata);
+	rc = qs_s5k4e1_i2c_txdata(qs_s5k4e1_client->addr>>1, buf, 3);
+	if (rc < 0) {
+		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+			waddr, bdata);
+	}
+	return rc;
+}
+
+static int32_t qs_s5k4e1_i2c_write_b_table(struct qs_s5k4e1_i2c_reg_conf const
+					 *reg_conf_tbl, int num)
+{
+	int i;
+	int32_t rc = -EIO;
+	for (i = 0; i < num; i++) {
+		rc = qs_s5k4e1_i2c_write_b_sensor(reg_conf_tbl->waddr,
+			reg_conf_tbl->wdata);
+		if (rc < 0)
+			break;
+		reg_conf_tbl++;
+	}
+	return rc;
+}
+
+static int32_t qs_s5k4e1_i2c_write_seq_sensor(unsigned short waddr,
+		unsigned char *seq_data, int len)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[len+2];
+	int i = 0;
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	for (i = 0; i < len; i++)
+		buf[i+2] = seq_data[i];
+	rc = qs_s5k4e1_i2c_txdata(qs_s5k4e1_client->addr>>1, buf, len+2);
+	return rc;
+}
+
+static int32_t af_i2c_write_b_sensor(unsigned short baddr, uint8_t bdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[2];
+	memset(buf, 0, sizeof(buf));
+	buf[0] = baddr;
+	buf[1] = bdata;
+	CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", baddr, bdata);
+	rc = qs_s5k4e1_i2c_txdata(AF_ADDR>>1, buf, 2);
+	if (rc < 0) {
+		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+			baddr, bdata);
+	}
+	return rc;
+}
+
+static int32_t bridge_i2c_write_w(unsigned short waddr, uint16_t wdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[4];
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = (wdata & 0xFF00) >> 8;
+	buf[3] = (wdata & 0x00FF);
+	CDBG("bridge_i2c_write_w addr = 0x%x, val = 0x%x\n", waddr, wdata);
+	rc = qs_s5k4e1_i2c_txdata(BRIDGE_ADDR>>1, buf, 4);
+	if (rc < 0) {
+		CDBG("bridge_i2c_write_w failed, addr = 0x%x, val = 0x%x!\n",
+			waddr, wdata);
+	}
+	return rc;
+}
+
+static int32_t bridge_i2c_read(unsigned short raddr,
+	unsigned short *rdata, int rlen)
+{
+	int32_t rc = 0;
+	unsigned char buf[2];
+	if (!rdata)
+		return -EIO;
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (raddr & 0xFF00) >> 8;
+	buf[1] = (raddr & 0x00FF);
+	rc = qs_s5k4e1_i2c_rxdata(BRIDGE_ADDR>>1, buf, rlen);
+	if (rc < 0) {
+		CDBG("bridge_i2c_read 0x%x failed!\n", raddr);
+		return rc;
+	}
+	*rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]);
+	CDBG("bridge_i2c_read 0x%x val = 0x%x!\n", raddr, *rdata);
+	return rc;
+}
+
+static int32_t qs_s5k4e1_eeprom_i2c_read(unsigned short raddr,
+	unsigned char *rdata, int rlen)
+{
+	int32_t rc = 0;
+	unsigned short i2caddr = 0xA0 >> 1;
+	unsigned char buf[rlen];
+	int i = 0;
+	if (!rdata)
+		return -EIO;
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (raddr & 0xFF00) >> 8;
+	buf[1] = (raddr & 0x00FF);
+	rc = qs_s5k4e1_i2c_rxdata(i2caddr, buf, rlen);
+	if (rc < 0) {
+		CDBG("qs_s5k4e1_eeprom_i2c_read 0x%x failed!\n", raddr);
+		return rc;
+	}
+	for (i = 0; i < rlen; i++) {
+		rdata[i] = buf[i];
+		CDBG("qs_s5k4e1_eeprom_i2c_read 0x%x index: %d val = 0x%x!\n",
+			raddr, i, buf[i]);
+	}
+	return rc;
+}
+
+static int32_t qs_s5k4e1_eeprom_i2c_read_b(unsigned short raddr,
+	unsigned short *rdata, int rlen)
+{
+	int32_t rc = 0;
+	unsigned char buf[2];
+	rc = qs_s5k4e1_eeprom_i2c_read(raddr, &buf[0], rlen);
+	*rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]);
+	CDBG("qs_s5k4e1_eeprom_i2c_read 0x%x val = 0x%x!\n", raddr, *rdata);
+	return rc;
+}
+
+static int32_t qs_s5k4e1_get_calibration_data(
+	struct sensor_3d_cali_data_t *cdata)
+{
+	int32_t rc = 0;
+	cali_data_status = 1;
+	rc = qs_s5k4e1_eeprom_i2c_read(0x0,
+		&(cdata->left_p_matrix[0][0][0]), 96);
+	if (rc < 0)
+		goto fail;
+	rc = qs_s5k4e1_eeprom_i2c_read(0x60,
+		&(cdata->right_p_matrix[0][0][0]), 96);
+	if (rc < 0)
+		goto fail;
+	rc = qs_s5k4e1_eeprom_i2c_read(0xC0, &(cdata->square_len[0]), 8);
+	if (rc < 0)
+		goto fail;
+	rc = qs_s5k4e1_eeprom_i2c_read(0xC8, &(cdata->focal_len[0]), 8);
+	if (rc < 0)
+		goto fail;
+	rc = qs_s5k4e1_eeprom_i2c_read(0xD0, &(cdata->pixel_pitch[0]), 8);
+	if (rc < 0)
+		goto fail;
+	rc = qs_s5k4e1_eeprom_i2c_read_b(0x100, &(cdata->left_r), 1);
+	if (rc < 0)
+		goto fail;
+	rc = qs_s5k4e1_eeprom_i2c_read_b(0x101, &(cdata->right_r), 1);
+	if (rc < 0)
+		goto fail;
+	rc = qs_s5k4e1_eeprom_i2c_read_b(0x102, &(cdata->left_b), 1);
+	if (rc < 0)
+		goto fail;
+	rc = qs_s5k4e1_eeprom_i2c_read_b(0x103, &(cdata->right_b), 1);
+	if (rc < 0)
+		goto fail;
+	rc = qs_s5k4e1_eeprom_i2c_read_b(0x104, &(cdata->left_gb), 1);
+	if (rc < 0)
+		goto fail;
+	rc = qs_s5k4e1_eeprom_i2c_read_b(0x105, &(cdata->right_gb), 1);
+	if (rc < 0)
+		goto fail;
+	rc = qs_s5k4e1_eeprom_i2c_read_b(0x110, &(cdata->left_af_far), 2);
+	if (rc < 0)
+		goto fail;
+	rc = qs_s5k4e1_eeprom_i2c_read_b(0x112, &(cdata->right_af_far), 2);
+	if (rc < 0)
+		goto fail;
+	rc = qs_s5k4e1_eeprom_i2c_read_b(0x114, &(cdata->left_af_mid), 2);
+	if (rc < 0)
+		goto fail;
+	rc = qs_s5k4e1_eeprom_i2c_read_b(0x116, &(cdata->right_af_mid), 2);
+	if (rc < 0)
+		goto fail;
+	rc = qs_s5k4e1_eeprom_i2c_read_b(0x118, &(cdata->left_af_short), 2);
+	if (rc < 0)
+		goto fail;
+	rc = qs_s5k4e1_eeprom_i2c_read_b(0x11A, &(cdata->right_af_short), 2);
+	if (rc < 0)
+		goto fail;
+	rc = qs_s5k4e1_eeprom_i2c_read_b(0x11C, &(cdata->left_af_5um), 2);
+	if (rc < 0)
+		goto fail;
+	rc = qs_s5k4e1_eeprom_i2c_read_b(0x11E, &(cdata->right_af_5um), 2);
+	if (rc < 0)
+		goto fail;
+	rc = qs_s5k4e1_eeprom_i2c_read_b(0x120, &(cdata->left_af_50up), 2);
+	if (rc < 0)
+		goto fail;
+	rc = qs_s5k4e1_eeprom_i2c_read_b(0x122, &(cdata->right_af_50up), 2);
+	if (rc < 0)
+		goto fail;
+	rc = qs_s5k4e1_eeprom_i2c_read_b(0x124, &(cdata->left_af_50down), 2);
+	if (rc < 0)
+		goto fail;
+	rc = qs_s5k4e1_eeprom_i2c_read_b(0x126, &(cdata->right_af_50down), 2);
+	if (rc < 0)
+		goto fail;
+
+	return 0;
+
+fail:
+	cali_data_status = 0;
+	return -EIO;
+
+}
+static int32_t qs_s5k4e1_write_left_lsc(char *left_lsc, int rt)
+{
+	struct qs_s5k4e1_i2c_reg_conf *ptr = (struct qs_s5k4e1_i2c_reg_conf *)
+		(qs_s5k4e1_regs.reg_lens + rt);
+	bridge_i2c_write_w(0x06, 0x02);
+	if (!LENS_SHADE_CONFIG) {
+		qs_s5k4e1_i2c_write_b_sensor(0x3096, 0x40);
+		qs_s5k4e1_i2c_write_b_table(ptr, qs_s5k4e1_regs.reg_lens_size);
+		if (default_lens_shade)
+			qs_s5k4e1_i2c_write_b_table(qs_s5k4e1_regs.
+			reg_default_lens, qs_s5k4e1_regs.reg_default_lens_size);
+		else {
+			qs_s5k4e1_i2c_write_seq_sensor(0x3200,
+				&left_lsc[0], 216);
+			qs_s5k4e1_i2c_write_seq_sensor(0x32D8,
+				&left_lsc[216], 216);
+		}
+		qs_s5k4e1_i2c_write_b_sensor(0x3096, 0x60);
+		qs_s5k4e1_i2c_write_b_sensor(0x3096, 0x40);
+	} else
+		qs_s5k4e1_i2c_write_b_table(ptr, qs_s5k4e1_regs.reg_lens_size);
+	return 0;
+}
+
+static int32_t qs_s5k4e1_write_right_lsc(char *right_lsc, int rt)
+{
+	struct qs_s5k4e1_i2c_reg_conf *ptr = (struct qs_s5k4e1_i2c_reg_conf *)
+		(qs_s5k4e1_regs.reg_lens + rt);
+	bridge_i2c_write_w(0x06, 0x01);
+	if (!LENS_SHADE_CONFIG) {
+		qs_s5k4e1_i2c_write_b_sensor(0x3096, 0x40);
+		qs_s5k4e1_i2c_write_b_table(ptr, qs_s5k4e1_regs.reg_lens_size);
+		if (default_lens_shade)
+			qs_s5k4e1_i2c_write_b_table(qs_s5k4e1_regs.
+			reg_default_lens, qs_s5k4e1_regs.reg_default_lens_size);
+		else {
+			qs_s5k4e1_i2c_write_seq_sensor(0x3200,
+				&right_lsc[0], 216);
+			qs_s5k4e1_i2c_write_seq_sensor(0x32D8,
+				&right_lsc[216], 216);
+		}
+		qs_s5k4e1_i2c_write_b_sensor(0x3096, 0x60);
+		qs_s5k4e1_i2c_write_b_sensor(0x3096, 0x40);
+	} else
+		qs_s5k4e1_i2c_write_b_table(ptr, qs_s5k4e1_regs.reg_lens_size);
+	return 0;
+}
+
+static int32_t qs_s5k4e1_write_lsc(char *lsc, int rt)
+{
+	if (qs_s5k4e1_ctrl->cam_mode == MODE_3D) {
+		qs_s5k4e1_write_left_lsc(&lsc[0], rt);
+		qs_s5k4e1_write_right_lsc(&lsc[432], rt);
+		bridge_i2c_write_w(0x06, 0x03);
+	} else if (qs_s5k4e1_ctrl->cam_mode == MODE_2D_LEFT)
+		qs_s5k4e1_write_left_lsc(&lsc[0], rt);
+	else if (qs_s5k4e1_ctrl->cam_mode == MODE_2D_RIGHT)
+		qs_s5k4e1_write_right_lsc(&lsc[432], rt);
+	return 0;
+}
+
+static int32_t qs_s5k4e1_read_left_lsc(char *left_lsc)
+{
+	qs_s5k4e1_eeprom_i2c_read(0x200, &left_lsc[0], 216);
+	qs_s5k4e1_eeprom_i2c_read(0x2D8, &left_lsc[216], 216);
+	return 0;
+}
+
+static int32_t qs_s5k4e1_read_right_lsc(char *right_lsc)
+{
+	qs_s5k4e1_eeprom_i2c_read(0x3B0, &right_lsc[0], 216);
+	qs_s5k4e1_eeprom_i2c_read(0x488, &right_lsc[216], 216);
+	return 0;
+}
+
+static int32_t qs_s5k4e1_read_lsc(char *lsc)
+{
+	qs_s5k4e1_read_left_lsc(&lsc[0]);
+	qs_s5k4e1_read_right_lsc(&lsc[432]);
+	return 0;
+}
+
+static int32_t qs_s5k4e1_bridge_reset(void){
+	unsigned short RegData = 0, GPIOInState = 0;
+	int32_t rc = 0;
+	rc = bridge_i2c_write_w(0x50, 0x00);
+	if (rc < 0)
+		goto bridge_fail;
+	rc = bridge_i2c_write_w(0x53, 0x00);
+	if (rc < 0)
+		goto bridge_fail;
+	msleep(30);
+	rc = bridge_i2c_write_w(0x53, 0x01);
+	if (rc < 0)
+		goto bridge_fail;
+	msleep(30);
+	rc = bridge_i2c_write_w(0x0E, 0xFFFF);
+	if (rc < 0)
+		goto err;
+	rc = bridge_i2c_read(0x54, &RegData, 2);
+	if (rc < 0)
+		goto err;
+	rc = bridge_i2c_write_w(0x54, (RegData | 0x1));
+	if (rc < 0)
+		goto err;
+	msleep(30);
+	rc = bridge_i2c_read(0x54, &RegData, 2);
+	if (rc < 0)
+		goto err;
+	rc = bridge_i2c_write_w(0x54, (RegData | 0x4));
+	if (rc < 0)
+		goto err;
+	rc = bridge_i2c_read(0x55, &GPIOInState, 2);
+	if (rc < 0)
+		goto err;
+	rc = bridge_i2c_write_w(0x55, (GPIOInState | 0x1));
+	if (rc < 0)
+		goto err;
+	msleep(30);
+	rc = bridge_i2c_read(0x55, &GPIOInState, 2);
+	if (rc < 0)
+		goto err;
+	rc = bridge_i2c_write_w(0x55, (GPIOInState | 0x4));
+	if (rc < 0)
+		goto err;
+	msleep(30);
+	rc = bridge_i2c_read(0x55, &GPIOInState, 2);
+	if (rc < 0)
+		goto err;
+	GPIOInState = ((GPIOInState >> 4) & 0x1);
+
+	rc = bridge_i2c_read(0x08, &GPIOInState, 2);
+	if (rc < 0)
+		goto err;
+	rc = bridge_i2c_write_w(0x08, GPIOInState | 0x4000);
+	if (rc < 0)
+		goto err;
+	return rc;
+
+err:
+	bridge_i2c_write_w(0x53, 0x00);
+	msleep(30);
+
+bridge_fail:
+	return rc;
+
+}
+
+static void qs_s5k4e1_bridge_config(int mode, int rt)
+{
+	unsigned short RegData = 0;
+	if (mode == MODE_3D) {
+		bridge_i2c_read(0x54, &RegData, 2);
+		bridge_i2c_write_w(0x54, (RegData | 0x2));
+		bridge_i2c_write_w(0x54, (RegData | 0xa));
+		bridge_i2c_read(0x55, &RegData, 2);
+		bridge_i2c_write_w(0x55, (RegData | 0x2));
+		bridge_i2c_write_w(0x55, (RegData | 0xa));
+		bridge_i2c_write_w(0x14, 0x0C);
+		msleep(20);
+		bridge_i2c_write_w(0x16, 0x00);
+		bridge_i2c_write_w(0x51, 0x3);
+		bridge_i2c_write_w(0x52, 0x1);
+		bridge_i2c_write_w(0x06, 0x03);
+		bridge_i2c_write_w(0x04, 0x2018);
+		bridge_i2c_write_w(0x50, 0x00);
+	} else if (mode == MODE_2D_RIGHT) {
+		bridge_i2c_read(0x54, &RegData, 2);
+		RegData |= 0x2;
+		bridge_i2c_write_w(0x54, RegData);
+		bridge_i2c_write_w(0x54, (RegData & ~(0x8)));
+		bridge_i2c_read(0x55, &RegData, 2);
+		RegData |= 0x2;
+		bridge_i2c_write_w(0x55, RegData);
+		bridge_i2c_write_w(0x55, (RegData & ~(0x8)));
+		bridge_i2c_write_w(0x14, 0x04);
+		msleep(20);
+		bridge_i2c_write_w(0x51, 0x3);
+		bridge_i2c_write_w(0x06, 0x01);
+		bridge_i2c_write_w(0x04, 0x2018);
+		bridge_i2c_write_w(0x50, 0x01);
+	} else if (mode == MODE_2D_LEFT) {
+		bridge_i2c_read(0x54, &RegData, 2);
+		RegData |= 0x8;
+		bridge_i2c_write_w(0x54, RegData);
+		bridge_i2c_write_w(0x54, (RegData & ~(0x2)));
+		bridge_i2c_read(0x55, &RegData, 2);
+		RegData |= 0x8;
+		bridge_i2c_write_w(0x55, RegData);
+		bridge_i2c_write_w(0x55, (RegData & ~(0x2)));
+		bridge_i2c_write_w(0x14, 0x08);
+		msleep(20);
+		bridge_i2c_write_w(0x51, 0x3);
+		bridge_i2c_write_w(0x06, 0x02);
+		bridge_i2c_write_w(0x04, 0x2018);
+		bridge_i2c_write_w(0x50, 0x02);
+	}
+}
+
+static void qs_s5k4e1_group_hold_on(void)
+{
+	qs_s5k4e1_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
+						GROUPED_PARAMETER_HOLD);
+}
+
+static void qs_s5k4e1_group_hold_off(void)
+{
+	qs_s5k4e1_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
+						GROUPED_PARAMETER_HOLD_OFF);
+}
+
+static void qs_s5k4e1_start_stream(void)
+{
+	qs_s5k4e1_i2c_write_b_sensor(0x0100, 0x01);
+}
+
+static void qs_s5k4e1_stop_stream(void)
+{
+	qs_s5k4e1_i2c_write_b_sensor(0x0100, 0x00);
+}
+
+static void qs_s5k4e1_get_pict_fps(uint16_t fps, uint16_t *pfps)
+{
+	/* input fps is preview fps in Q8 format */
+	uint32_t divider, d1, d2;
+
+	d1 = prev_frame_length_lines * 0x00000400 / snap_frame_length_lines;
+	d2 = prev_line_length_pck * 0x00000400 / snap_line_length_pck;
+	divider = d1 * d2 / 0x400;
+
+	/*Verify PCLK settings and frame sizes.*/
+	*pfps = (uint16_t) (fps * divider / 0x400);
+	/* 2 is the ratio of no.of snapshot channels
+	to number of preview channels */
+}
+
+static uint16_t qs_s5k4e1_get_prev_lines_pf(void)
+{
+
+	return prev_frame_length_lines;
+
+}
+
+static uint16_t qs_s5k4e1_get_prev_pixels_pl(void)
+{
+	return prev_line_length_pck;
+
+}
+
+static uint16_t qs_s5k4e1_get_pict_lines_pf(void)
+{
+	return snap_frame_length_lines;
+}
+
+static uint16_t qs_s5k4e1_get_pict_pixels_pl(void)
+{
+	return snap_line_length_pck;
+}
+
+
+static uint32_t qs_s5k4e1_get_pict_max_exp_lc(void)
+{
+	return snap_frame_length_lines  * 24;
+}
+
+static int32_t qs_s5k4e1_set_fps(struct fps_cfg   *fps)
+{
+	uint16_t total_line_length_pclk;
+	int32_t rc = 0;
+	qs_s5k4e1_ctrl->fps_divider = fps->fps_div;
+	qs_s5k4e1_ctrl->pict_fps_divider = fps->pict_fps_div;
+	if (qs_s5k4e1_ctrl->sensormode == SENSOR_PREVIEW_MODE) {
+		total_line_length_pclk = (uint16_t)
+		((prev_line_length_pck) * qs_s5k4e1_ctrl->fps_divider/0x400);
+	} else {
+		total_line_length_pclk = (uint16_t)
+		((snap_line_length_pck) *
+			qs_s5k4e1_ctrl->pict_fps_divider/0x400);
+	}
+	qs_s5k4e1_group_hold_on();
+	rc = qs_s5k4e1_i2c_write_w_sensor(REG_LINE_LENGTH_PCK,
+							total_line_length_pclk);
+	qs_s5k4e1_group_hold_off();
+	return rc;
+}
+
+static int32_t qs_s5k4e1_write_exp_gain(struct sensor_3d_exp_cfg exp_cfg)
+{
+	uint16_t max_legal_gain = 0x0200;
+	uint16_t min_ll_pck = 0x0AB2;
+	uint32_t ll_pck, fl_lines;
+	uint16_t gain = exp_cfg.gain;
+	uint32_t line = exp_cfg.line;
+	uint32_t ll_ratio;
+	int32_t rc = 0;
+	if (gain > max_legal_gain) {
+		CDBG("Max legal gain Line:%d\n", __LINE__);
+		gain = max_legal_gain;
+	}
+	CDBG("qs_s5k4e1_write_exp_gain : gain = %d line = %d\n", gain, line);
+
+	if (qs_s5k4e1_ctrl->sensormode == SENSOR_PREVIEW_MODE) {
+		qs_s5k4e1_ctrl->my_reg_gain = gain;
+		qs_s5k4e1_ctrl->my_reg_line_count = (uint16_t) line;
+		ll_ratio = (uint32_t)(qs_s5k4e1_ctrl->fps_divider);
+		fl_lines = prev_frame_length_lines;
+		ll_pck = prev_line_length_pck;
+	} else {
+		ll_ratio = (uint32_t)(qs_s5k4e1_ctrl->pict_fps_divider);
+		fl_lines = snap_frame_length_lines;
+		ll_pck = snap_line_length_pck;
+	}
+	if (((fl_lines * ll_ratio / 0x400) - QS_S5K4E1_OFFSET) < line) {
+		ll_ratio = ll_ratio * line / (fl_lines - QS_S5K4E1_OFFSET);
+		line = fl_lines - QS_S5K4E1_OFFSET;
+	}
+	ll_pck = ll_pck * ll_ratio / 0x400;
+	if (ll_pck < min_ll_pck)
+		ll_pck = min_ll_pck;
+	qs_s5k4e1_group_hold_on();
+	rc = qs_s5k4e1_i2c_write_w_sensor(REG_GLOBAL_GAIN, gain);
+	rc = qs_s5k4e1_i2c_write_w_sensor(REG_LINE_LENGTH_PCK, ll_pck);
+	rc = qs_s5k4e1_i2c_write_w_sensor(REG_COARSE_INTEGRATION_TIME, line);
+	if ((qs_s5k4e1_ctrl->cam_mode == MODE_3D) && (cali_data_status == 1)) {
+		bridge_i2c_write_w(0x06, 0x01);
+		rc = qs_s5k4e1_i2c_write_w_sensor(REG_GLOBAL_GAIN,
+			 exp_cfg.gain_adjust);
+		rc = qs_s5k4e1_i2c_write_w_sensor(REG_GR_GAIN, exp_cfg.gr_gain);
+		rc = qs_s5k4e1_i2c_write_w_sensor(REG_R_GAIN,
+				exp_cfg.r_gain);
+		rc = qs_s5k4e1_i2c_write_w_sensor(REG_B_GAIN,
+				exp_cfg.b_gain);
+		rc = qs_s5k4e1_i2c_write_w_sensor(REG_GB_GAIN,
+				exp_cfg.gb_gain);
+		bridge_i2c_write_w(0x06, 0x03);
+	}
+	qs_s5k4e1_group_hold_off();
+	return rc;
+}
+
+static int32_t qs_s5k4e1_set_pict_exp_gain(struct sensor_3d_exp_cfg exp_cfg)
+{
+	int32_t rc = 0;
+	rc = qs_s5k4e1_write_exp_gain(exp_cfg);
+	return rc;
+}
+
+static int32_t qs_s5k4e1_write_focus_value(uint16_t code_value)
+{
+	uint8_t code_val_msb, code_val_lsb;
+	if ((qs_s5k4e1_ctrl->cam_mode == MODE_2D_LEFT) ||
+		(qs_s5k4e1_ctrl->cam_mode == MODE_3D)) {
+		/* Left */
+		bridge_i2c_write_w(0x06, 0x02);
+		CDBG("%s: Left Lens Position: %d\n", __func__,
+			code_value);
+		code_val_msb = code_value >> 4;
+		code_val_lsb = (code_value & 0x000F) << 4;
+		code_val_lsb |= qs_s5k4e1_af_mode;
+		if (af_i2c_write_b_sensor(code_val_msb, code_val_lsb) < 0) {
+			CDBG("move_focus failed at line %d ...\n", __LINE__);
+			return -EBUSY;
+		}
+	}
+
+	if ((qs_s5k4e1_ctrl->cam_mode == MODE_2D_RIGHT) ||
+		(qs_s5k4e1_ctrl->cam_mode == MODE_3D)) {
+		/* Right */
+		bridge_i2c_write_w(0x06, 0x01);
+		code_value += qs_s5k4e1_af_right_adjust;
+		CDBG("%s: Right Lens Position: %d\n", __func__,
+			code_value);
+		code_val_msb = code_value >> 4;
+		code_val_lsb = (code_value & 0x000F) << 4;
+		code_val_lsb |= qs_s5k4e1_af_mode;
+		if (af_i2c_write_b_sensor(code_val_msb, code_val_lsb) < 0) {
+			CDBG("move_focus failed at line %d ...\n", __LINE__);
+			return -EBUSY;
+		}
+	}
+
+	if (qs_s5k4e1_ctrl->cam_mode == MODE_3D) {
+		/* 3D Mode */
+		bridge_i2c_write_w(0x06, 0x03);
+	}
+	usleep(qs_s5k4e1_sw_damping_time_wait*50);
+	return 0;
+}
+
+static int32_t qs_s5k4e1_move_focus(int direction,
+	int32_t num_steps)
+{
+	int16_t step_direction, actual_step, dest_lens_position,
+		dest_step_position;
+	CDBG("Inside %s\n", __func__);
+	if (direction == MOVE_NEAR)
+		step_direction = 1;
+	else
+		step_direction = -1;
+
+	actual_step = (int16_t) (step_direction * (int16_t) num_steps);
+	dest_step_position = (int16_t) (qs_s5k4e1_ctrl->curr_step_pos +
+		actual_step);
+
+	if (dest_step_position > QS_S5K4E1_TOTAL_STEPS_NEAR_TO_FAR)
+		dest_step_position = QS_S5K4E1_TOTAL_STEPS_NEAR_TO_FAR;
+	else if (dest_step_position < 0)
+		dest_step_position = 0;
+
+	if (dest_step_position == qs_s5k4e1_ctrl->curr_step_pos) {
+		CDBG("%s cur and dest pos are same\n", __func__);
+		CDBG("%s cur_step_pos:%d\n", __func__,
+			qs_s5k4e1_ctrl->curr_step_pos);
+		return 0;
+	}
+
+	dest_lens_position = qs_s5k4e1_step_position_table[dest_step_position];
+	CDBG("%s: Step Position: %d\n", __func__, dest_step_position);
+
+	if (step_direction < 0) {
+		if (num_steps >= 20) {
+			/* sweeping towards all the way in infinity direction */
+			qs_s5k4e1_af_mode = 2;
+			qs_s5k4e1_sw_damping_time_wait = 8;
+		} else if (num_steps <= 4) {
+			/* reverse search during macro mode */
+			qs_s5k4e1_af_mode = 4;
+			qs_s5k4e1_sw_damping_time_wait = 16;
+		} else {
+			qs_s5k4e1_af_mode = 3;
+			qs_s5k4e1_sw_damping_time_wait = 12;
+		}
+	} else {
+		/* coarse search towards macro direction */
+		qs_s5k4e1_af_mode = 4;
+		qs_s5k4e1_sw_damping_time_wait = 16;
+	}
+
+	if (qs_s5k4e1_ctrl->curr_lens_pos != dest_lens_position) {
+		if (qs_s5k4e1_write_focus_value(dest_lens_position) < 0) {
+			CDBG("move_focus failed at line %d ...\n", __LINE__);
+			return -EBUSY;
+		}
+	}
+
+	qs_s5k4e1_ctrl->curr_step_pos = dest_step_position;
+	qs_s5k4e1_ctrl->curr_lens_pos = dest_lens_position;
+	return 0;
+}
+
+static int32_t qs_s5k4e1_set_default_focus(uint8_t af_step)
+{
+	int32_t rc = 0;
+	if (qs_s5k4e1_ctrl->curr_step_pos) {
+		rc = qs_s5k4e1_move_focus(MOVE_FAR,
+			qs_s5k4e1_ctrl->curr_step_pos);
+		if (rc < 0)
+			return rc;
+	} else {
+		rc = qs_s5k4e1_write_focus_value(
+			qs_s5k4e1_step_position_table[0]);
+		if (rc < 0)
+			return rc;
+		qs_s5k4e1_ctrl->curr_lens_pos =
+			qs_s5k4e1_step_position_table[0];
+	}
+	CDBG("%s\n", __func__);
+	return 0;
+}
+
+static void qs_s5k4e1_init_focus(void)
+{
+	uint8_t i;
+	int32_t rc = 0;
+	int16_t af_far_data = 0;
+	qs_s5k4e1_af_initial_code = 190;
+	/* Read the calibration data from left and right sensors if available */
+	rc = qs_s5k4e1_eeprom_i2c_read_b(0x110, &af_far_data, 2);
+	if (rc == 0) {
+		CDBG("%s: Left Far data - %d\n", __func__, af_far_data);
+		qs_s5k4e1_af_initial_code = af_far_data;
+	}
+
+	rc = qs_s5k4e1_eeprom_i2c_read_b(0x112, &af_far_data, 2);
+	if (rc == 0) {
+		CDBG("%s: Right Far data - %d\n", __func__, af_far_data);
+		qs_s5k4e1_af_right_adjust = af_far_data -
+			qs_s5k4e1_af_initial_code;
+	}
+
+	qs_s5k4e1_step_position_table[0] = qs_s5k4e1_af_initial_code;
+	for (i = 1; i <= QS_S5K4E1_TOTAL_STEPS_NEAR_TO_FAR; i++) {
+		if (i <= qs_s5k4e1_nl_region_boundary1) {
+			qs_s5k4e1_step_position_table[i] =
+				qs_s5k4e1_step_position_table[i-1]
+				+ qs_s5k4e1_nl_region_code_per_step1;
+		} else {
+			qs_s5k4e1_step_position_table[i] =
+				qs_s5k4e1_step_position_table[i-1]
+				+ qs_s5k4e1_l_region_code_per_step;
+		}
+
+		if (qs_s5k4e1_step_position_table[i] > 1023)
+			qs_s5k4e1_step_position_table[i] = 1023;
+	}
+	qs_s5k4e1_ctrl->curr_step_pos = 0;
+}
+
+static int32_t qs_s5k4e1_test(enum qs_s5k4e1_test_mode_t mo)
+{
+	int32_t rc = 0;
+	if (mo == TEST_OFF)
+		return rc;
+	else {
+		/* REG_0x30D8[4] is TESBYPEN: 0: Normal Operation,
+		1: Bypass Signal Processing
+		REG_0x30D8[5] is EBDMASK: 0:
+		Output Embedded data, 1: No output embedded data */
+		if (qs_s5k4e1_i2c_write_b_sensor(REG_TEST_PATTERN_MODE,
+			(uint8_t) mo) < 0) {
+			return rc;
+		}
+	}
+	return rc;
+}
+
+static int32_t qs_s5k4e1_sensor_setting(int update_type, int rt)
+{
+
+	int32_t rc = 0;
+	struct msm_camera_csi_params qs_s5k4e1_csi_params;
+
+	qs_s5k4e1_stop_stream();
+	msleep(80);
+	bridge_i2c_write_w(0x53, 0x00);
+	msleep(80);
+	if (update_type == REG_INIT) {
+		CSI_CONFIG = 0;
+		LENS_SHADE_CONFIG = 0;
+		default_lens_shade = 1;
+		bridge_i2c_write_w(0x53, 0x01);
+		msleep(30);
+		qs_s5k4e1_bridge_config(qs_s5k4e1_ctrl->cam_mode, rt);
+		msleep(30);
+		qs_s5k4e1_i2c_write_b_table(qs_s5k4e1_regs.rec_settings,
+				qs_s5k4e1_regs.rec_size);
+		msleep(30);
+	} else if (update_type == UPDATE_PERIODIC) {
+		qs_s5k4e1_write_lsc(lens_eeprom_data, rt);
+		msleep(100);
+		if (!CSI_CONFIG) {
+			if (qs_s5k4e1_ctrl->cam_mode == MODE_3D) {
+				qs_s5k4e1_csi_params.lane_cnt = 4;
+				qs_s5k4e1_csi_params.data_format = CSI_8BIT;
+			} else {
+				qs_s5k4e1_csi_params.lane_cnt = 2;
+				qs_s5k4e1_csi_params.data_format = CSI_10BIT;
+			}
+			qs_s5k4e1_csi_params.lane_assign = 0xe4;
+			qs_s5k4e1_csi_params.dpcm_scheme = 0;
+			qs_s5k4e1_csi_params.settle_cnt = 24;
+			rc = msm_camio_csi_config(&qs_s5k4e1_csi_params);
+			msleep(10);
+			cam_debug_init();
+			CSI_CONFIG = 1;
+		}
+		bridge_i2c_write_w(0x53, 0x01);
+		msleep(50);
+		qs_s5k4e1_i2c_write_b_table(qs_s5k4e1_regs.conf_array[rt].conf,
+			qs_s5k4e1_regs.conf_array[rt].size);
+		msleep(50);
+		qs_s5k4e1_start_stream();
+		msleep(80);
+	}
+	return rc;
+}
+
+static int32_t qs_s5k4e1_video_config(int mode)
+{
+
+	int32_t rc = 0;
+	/* change sensor resolution if needed */
+	if (qs_s5k4e1_sensor_setting(UPDATE_PERIODIC,
+			qs_s5k4e1_ctrl->prev_res) < 0)
+		return rc;
+	if (qs_s5k4e1_ctrl->set_test) {
+		if (qs_s5k4e1_test(qs_s5k4e1_ctrl->set_test) < 0)
+			return  rc;
+	}
+
+	qs_s5k4e1_ctrl->curr_res = qs_s5k4e1_ctrl->prev_res;
+	qs_s5k4e1_ctrl->sensormode = mode;
+	return rc;
+}
+
+static int32_t qs_s5k4e1_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+	/*change sensor resolution if needed */
+	if (qs_s5k4e1_ctrl->curr_res != qs_s5k4e1_ctrl->pict_res) {
+		if (qs_s5k4e1_sensor_setting(UPDATE_PERIODIC,
+				qs_s5k4e1_ctrl->pict_res) < 0)
+			return rc;
+	}
+
+	qs_s5k4e1_ctrl->curr_res = qs_s5k4e1_ctrl->pict_res;
+	qs_s5k4e1_ctrl->sensormode = mode;
+	return rc;
+} /*end of qs_s5k4e1_snapshot_config*/
+
+static int32_t qs_s5k4e1_raw_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+	/* change sensor resolution if needed */
+	if (qs_s5k4e1_ctrl->curr_res != qs_s5k4e1_ctrl->pict_res) {
+		if (qs_s5k4e1_sensor_setting(UPDATE_PERIODIC,
+				qs_s5k4e1_ctrl->pict_res) < 0)
+			return rc;
+	}
+
+	qs_s5k4e1_ctrl->curr_res = qs_s5k4e1_ctrl->pict_res;
+	qs_s5k4e1_ctrl->sensormode = mode;
+	return rc;
+} /*end of qs_s5k4e1_raw_snapshot_config*/
+
+static int32_t qs_s5k4e1_mode_init(int mode, struct sensor_init_cfg init_info)
+{
+	int32_t rc = 0;
+	if (mode != qs_s5k4e1_ctrl->cam_mode) {
+		qs_s5k4e1_ctrl->prev_res = init_info.prev_res;
+		qs_s5k4e1_ctrl->pict_res = init_info.pict_res;
+		qs_s5k4e1_ctrl->cam_mode = mode;
+
+		prev_frame_length_lines =
+		((qs_s5k4e1_regs.conf_array[qs_s5k4e1_ctrl->prev_res]\
+			.conf[QS_S5K4E1_FRAME_LENGTH_LINES_H].wdata << 8)
+			| qs_s5k4e1_regs.conf_array[qs_s5k4e1_ctrl->prev_res]\
+			.conf[QS_S5K4E1_FRAME_LENGTH_LINES_L].wdata);
+		prev_line_length_pck =
+		(qs_s5k4e1_regs.conf_array[qs_s5k4e1_ctrl->prev_res]\
+			.conf[QS_S5K4E1_LINE_LENGTH_PCK_H].wdata << 8)
+			| qs_s5k4e1_regs.conf_array[qs_s5k4e1_ctrl->prev_res]\
+			.conf[QS_S5K4E1_LINE_LENGTH_PCK_L].wdata;
+		snap_frame_length_lines =
+		(qs_s5k4e1_regs.conf_array[qs_s5k4e1_ctrl->pict_res]\
+			.conf[QS_S5K4E1_FRAME_LENGTH_LINES_H].wdata << 8)
+			| qs_s5k4e1_regs.conf_array[qs_s5k4e1_ctrl->pict_res]\
+			.conf[QS_S5K4E1_FRAME_LENGTH_LINES_L].wdata;
+		snap_line_length_pck =
+		(qs_s5k4e1_regs.conf_array[qs_s5k4e1_ctrl->pict_res]\
+			.conf[QS_S5K4E1_LINE_LENGTH_PCK_H].wdata << 8)
+			| qs_s5k4e1_regs.conf_array[qs_s5k4e1_ctrl->pict_res]\
+			.conf[QS_S5K4E1_LINE_LENGTH_PCK_L].wdata;
+
+	rc = qs_s5k4e1_sensor_setting(REG_INIT,
+		qs_s5k4e1_ctrl->prev_res);
+	}
+	return rc;
+}
+static int32_t qs_s5k4e1_set_sensor_mode(int mode,
+	int res)
+{
+	int32_t rc = 0;
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		qs_s5k4e1_ctrl->prev_res = res;
+		rc = qs_s5k4e1_video_config(mode);
+		break;
+	case SENSOR_SNAPSHOT_MODE:
+		qs_s5k4e1_ctrl->pict_res = res;
+		rc = qs_s5k4e1_snapshot_config(mode);
+		break;
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		qs_s5k4e1_ctrl->pict_res = res;
+		rc = qs_s5k4e1_raw_snapshot_config(mode);
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+static int32_t qs_s5k4e1_power_down(void)
+{
+	qs_s5k4e1_stop_stream();
+	msleep(30);
+	qs_s5k4e1_af_mode = 2;
+	qs_s5k4e1_af_right_adjust = 0;
+	qs_s5k4e1_write_focus_value(0);
+	msleep(100);
+	/* Set AF actutator to PowerDown */
+	af_i2c_write_b_sensor(0x80, 00);
+	return 0;
+}
+
+static int qs_s5k4e1_probe_init_done(const struct msm_camera_sensor_info *data)
+{
+	CDBG("probe done\n");
+	gpio_free(data->sensor_reset);
+	return 0;
+}
+
+static int
+	qs_s5k4e1_probe_init_sensor(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc = 0;
+	uint16_t chipid = 0;
+	CDBG("%s: %d\n", __func__, __LINE__);
+	rc = gpio_request(data->sensor_reset, "qs_s5k4e1");
+	CDBG(" qs_s5k4e1_probe_init_sensor\n");
+	if (!rc) {
+		CDBG("sensor_reset = %d\n", rc);
+		gpio_direction_output(data->sensor_reset, 0);
+		msleep(50);
+		gpio_set_value_cansleep(data->sensor_reset, 1);
+		msleep(13);
+	} else {
+		goto init_probe_done;
+	}
+	msleep(70);
+	rc = qs_s5k4e1_bridge_reset();
+	if (rc < 0)
+		goto init_probe_fail;
+	qs_s5k4e1_bridge_config(MODE_3D, RES_PREVIEW);
+	msleep(30);
+
+	CDBG(" qs_s5k4e1_probe_init_sensor is called\n");
+	rc = qs_s5k4e1_i2c_read(0x0000, &chipid, 2);
+	CDBG("ID: %d\n", chipid);
+	/* 4. Compare sensor ID to QS_S5K4E1 ID: */
+	if (chipid != 0x4e10) {
+		rc = -ENODEV;
+		CDBG("qs_s5k4e1_probe_init_sensor fail chip id mismatch\n");
+		goto init_probe_fail;
+	}
+	goto init_probe_done;
+init_probe_fail:
+	CDBG(" qs_s5k4e1_probe_init_sensor fails\n");
+	gpio_set_value_cansleep(data->sensor_reset, 0);
+	qs_s5k4e1_probe_init_done(data);
+init_probe_done:
+	CDBG(" qs_s5k4e1_probe_init_sensor finishes\n");
+	return rc;
+}
+/* camsensor_qs_s5k4e1_reset */
+
+int qs_s5k4e1_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc = 0;
+	CDBG("%s: %d\n", __func__, __LINE__);
+	CDBG("Calling qs_s5k4e1_sensor_open_init\n");
+
+	qs_s5k4e1_ctrl = kzalloc(sizeof(struct qs_s5k4e1_ctrl_t), GFP_KERNEL);
+	if (!qs_s5k4e1_ctrl) {
+		CDBG("qs_s5k4e1_init failed!\n");
+		rc = -ENOMEM;
+		goto init_done;
+	}
+	qs_s5k4e1_ctrl->fps_divider = 1 * 0x00000400;
+	qs_s5k4e1_ctrl->pict_fps_divider = 1 * 0x00000400;
+	qs_s5k4e1_ctrl->set_test = TEST_OFF;
+	qs_s5k4e1_ctrl->cam_mode = MODE_INVALID;
+
+	if (data)
+		qs_s5k4e1_ctrl->sensordata = data;
+	if (rc < 0) {
+		CDBG("Calling qs_s5k4e1_sensor_open_init fail1\n");
+		return rc;
+	}
+	CDBG("%s: %d\n", __func__, __LINE__);
+	/* enable mclk first */
+	msm_camio_clk_rate_set(QS_S5K4E1_MASTER_CLK_RATE);
+	rc = qs_s5k4e1_probe_init_sensor(data);
+	if (rc < 0)
+		goto init_fail;
+/*Default mode is 3D*/
+	memcpy(lens_eeprom_data, data->eeprom_data, 864);
+	qs_s5k4e1_ctrl->fps = 30*Q8;
+	qs_s5k4e1_init_focus();
+	if (rc < 0) {
+		gpio_set_value_cansleep(data->sensor_reset, 0);
+		goto init_fail;
+	} else
+		goto init_done;
+init_fail:
+	CDBG("init_fail\n");
+	qs_s5k4e1_probe_init_done(data);
+init_done:
+	CDBG("init_done\n");
+	return rc;
+} /*endof qs_s5k4e1_sensor_open_init*/
+
+static int qs_s5k4e1_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&qs_s5k4e1_wait_queue);
+	return 0;
+}
+
+static const struct i2c_device_id qs_s5k4e1_i2c_id[] = {
+	{"qs_s5k4e1", 0},
+	{ }
+};
+
+static int qs_s5k4e1_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int rc = 0;
+	CDBG("qs_s5k4e1_probe called!\n");
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		CDBG("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	qs_s5k4e1_sensorw = kzalloc(sizeof(struct qs_s5k4e1_work_t),
+		 GFP_KERNEL);
+	if (!qs_s5k4e1_sensorw) {
+		CDBG("kzalloc failed.\n");
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, qs_s5k4e1_sensorw);
+	qs_s5k4e1_init_client(client);
+	qs_s5k4e1_client = client;
+
+	msleep(50);
+
+	CDBG("qs_s5k4e1_probe successed! rc = %d\n", rc);
+	return 0;
+
+probe_failure:
+	CDBG("qs_s5k4e1_probe failed! rc = %d\n", rc);
+	return rc;
+}
+
+static int qs_s5k4e1_send_wb_info(struct wb_info_cfg *wb)
+{
+	return 0;
+
+} /*end of qs_s5k4e1_snapshot_config*/
+
+static int __exit qs_s5k4e1_remove(struct i2c_client *client)
+{
+	struct qs_s5k4e1_work_t_t *sensorw = i2c_get_clientdata(client);
+	free_irq(client->irq, sensorw);
+	qs_s5k4e1_client = NULL;
+	kfree(sensorw);
+	return 0;
+}
+
+static struct i2c_driver qs_s5k4e1_i2c_driver = {
+	.id_table = qs_s5k4e1_i2c_id,
+	.probe  = qs_s5k4e1_i2c_probe,
+	.remove = __exit_p(qs_s5k4e1_i2c_remove),
+	.driver = {
+		.name = "qs_s5k4e1",
+	},
+};
+
+int qs_s5k4e1_3D_sensor_config(void __user *argp)
+{
+	struct sensor_large_data cdata;
+	long rc;
+	if (copy_from_user(&cdata,
+		(void *)argp,
+		sizeof(struct sensor_large_data)))
+		return -EFAULT;
+	mutex_lock(&qs_s5k4e1_mut);
+	rc = qs_s5k4e1_get_calibration_data
+		(&cdata.data.sensor_3d_cali_data);
+	if (rc < 0)
+		goto fail;
+	if (copy_to_user((void *)argp,
+		&cdata,
+		sizeof(struct sensor_large_data)))
+		rc = -EFAULT;
+fail:
+	mutex_unlock(&qs_s5k4e1_mut);
+	return rc;
+}
+
+int qs_s5k4e1_2D_sensor_config(void __user *argp)
+{
+	struct sensor_cfg_data cdata;
+	long   rc = 0;
+	if (copy_from_user(&cdata,
+		(void *)argp,
+		sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+	mutex_lock(&qs_s5k4e1_mut);
+	CDBG("qs_s5k4e1_sensor_config: cfgtype = %d\n",
+	cdata.cfgtype);
+		switch (cdata.cfgtype) {
+		case CFG_GET_PICT_FPS:
+			qs_s5k4e1_get_pict_fps(
+				cdata.cfg.gfps.prevfps,
+				&(cdata.cfg.gfps.pictfps));
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PREV_L_PF:
+			cdata.cfg.prevl_pf =
+			qs_s5k4e1_get_prev_lines_pf();
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PREV_P_PL:
+			cdata.cfg.prevp_pl =
+				qs_s5k4e1_get_prev_pixels_pl();
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PICT_L_PF:
+			cdata.cfg.pictl_pf =
+				qs_s5k4e1_get_pict_lines_pf();
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PICT_P_PL:
+			cdata.cfg.pictp_pl =
+				qs_s5k4e1_get_pict_pixels_pl();
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PICT_MAX_EXP_LC:
+			cdata.cfg.pict_max_exp_lc =
+				qs_s5k4e1_get_pict_max_exp_lc();
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_SET_FPS:
+		case CFG_SET_PICT_FPS:
+			rc = qs_s5k4e1_set_fps(&(cdata.cfg.fps));
+			break;
+
+		case CFG_SET_EXP_GAIN:
+			rc =
+				qs_s5k4e1_write_exp_gain(
+					cdata.cfg.sensor_3d_exp);
+			break;
+
+		case CFG_SET_PICT_EXP_GAIN:
+			rc =
+				qs_s5k4e1_set_pict_exp_gain(
+				cdata.cfg.sensor_3d_exp);
+			break;
+
+		case CFG_SET_MODE:
+			rc = qs_s5k4e1_set_sensor_mode(cdata.mode,
+					cdata.rs);
+			break;
+
+		case CFG_PWR_DOWN:
+			rc = qs_s5k4e1_power_down();
+			break;
+
+		case CFG_MOVE_FOCUS:
+			rc =
+				qs_s5k4e1_move_focus(
+				cdata.cfg.focus.dir,
+				cdata.cfg.focus.steps);
+			break;
+
+		case CFG_SET_DEFAULT_FOCUS:
+			rc =
+				qs_s5k4e1_set_default_focus(
+				cdata.cfg.focus.steps);
+			break;
+
+		case CFG_GET_AF_MAX_STEPS:
+			cdata.max_steps = QS_S5K4E1_TOTAL_STEPS_NEAR_TO_FAR;
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_SET_EFFECT:
+			rc = qs_s5k4e1_set_default_focus(
+				cdata.cfg.effect);
+			break;
+
+
+		case CFG_SEND_WB_INFO:
+			rc = qs_s5k4e1_send_wb_info(
+				&(cdata.cfg.wb_info));
+			break;
+
+		case CFG_SENSOR_INIT:
+			rc = qs_s5k4e1_mode_init(cdata.mode,
+					cdata.cfg.init_info);
+			break;
+
+		default:
+			rc = -EFAULT;
+			break;
+		}
+
+	mutex_unlock(&qs_s5k4e1_mut);
+
+	return rc;
+}
+
+int qs_s5k4e1_sensor_config(void __user *argp)
+{
+	int cfgtype;
+	long rc;
+	if (copy_from_user(&cfgtype,
+		(void *)argp,
+		sizeof(int)))
+		return -EFAULT;
+	if (cfgtype != CFG_GET_3D_CALI_DATA)
+		rc = qs_s5k4e1_2D_sensor_config(argp);
+	else
+		rc = qs_s5k4e1_3D_sensor_config(argp);
+	return rc;
+}
+
+static int qs_s5k4e1_sensor_release(void)
+{
+	int rc = -EBADF;
+	mutex_lock(&qs_s5k4e1_mut);
+	qs_s5k4e1_power_down();
+	bridge_i2c_write_w(0x53, 0x00);
+	msleep(20);
+	gpio_set_value_cansleep(qs_s5k4e1_ctrl->sensordata->sensor_reset, 0);
+	msleep(5);
+	gpio_free(qs_s5k4e1_ctrl->sensordata->sensor_reset);
+	kfree(qs_s5k4e1_ctrl);
+	qs_s5k4e1_ctrl = NULL;
+	CDBG("qs_s5k4e1_release completed\n");
+	mutex_unlock(&qs_s5k4e1_mut);
+
+	return rc;
+}
+
+static int qs_s5k4e1_sensor_probe(const struct msm_camera_sensor_info *info,
+		struct msm_sensor_ctrl *s)
+{
+	int rc = 0;
+	rc = i2c_add_driver(&qs_s5k4e1_i2c_driver);
+	if (rc < 0 || qs_s5k4e1_client == NULL) {
+		rc = -ENOTSUPP;
+		CDBG("I2C add driver failed");
+		goto probe_fail;
+	}
+	msm_camio_clk_rate_set(QS_S5K4E1_MASTER_CLK_RATE);
+	rc = qs_s5k4e1_probe_init_sensor(info);
+	if (rc < 0)
+		goto probe_fail;
+	qs_s5k4e1_read_lsc(info->eeprom_data); /*Default mode is 3D*/
+	s->s_init = qs_s5k4e1_sensor_open_init;
+	s->s_release = qs_s5k4e1_sensor_release;
+	s->s_config  = qs_s5k4e1_sensor_config;
+	s->s_mount_angle = 0;
+	s->s_camera_type = BACK_CAMERA_3D;
+	s->s_video_packing = SIDE_BY_SIDE_HALF;
+	s->s_snap_packing = SIDE_BY_SIDE_FULL;
+	bridge_i2c_write_w(0x53, 0x00);
+	msleep(20);
+	gpio_set_value_cansleep(info->sensor_reset, 0);
+	qs_s5k4e1_probe_init_done(info);
+	return rc;
+
+probe_fail:
+	CDBG("qs_s5k4e1_sensor_probe: SENSOR PROBE FAILS!\n");
+	return rc;
+}
+
+static bool streaming = 1;
+
+static int qs_s5k4e1_focus_test(void *data, u64 *val)
+{
+	int i = 0;
+	qs_s5k4e1_set_default_focus(0);
+
+	for (i = 0; i < QS_S5K4E1_TOTAL_STEPS_NEAR_TO_FAR; i++) {
+		qs_s5k4e1_move_focus(MOVE_NEAR, 1);
+		msleep(2000);
+	}
+	msleep(5000);
+	for ( ; i > 0; i--) {
+		qs_s5k4e1_move_focus(MOVE_FAR, 1);
+		msleep(2000);
+	}
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(cam_focus, qs_s5k4e1_focus_test,
+			NULL, "%lld\n");
+
+static int qs_s5k4e1_step_test(void *data, u64 *val)
+{
+	int rc = 0;
+	struct sensor_large_data cdata;
+	rc = qs_s5k4e1_get_calibration_data
+		(&cdata.data.sensor_3d_cali_data);
+	if (rc < 0)
+		CDBG("%s: Calibration data read fail.\n", __func__);
+
+	return 0;
+}
+
+static int qs_s5k4e1_set_step(void *data, u64 val)
+{
+	qs_s5k4e1_l_region_code_per_step = val & 0xFF;
+	qs_s5k4e1_af_mode = (val >> 8) & 0xFF;
+	qs_s5k4e1_nl_region_code_per_step1 = (val >> 16) & 0xFFFF;
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(cam_step, qs_s5k4e1_step_test,
+			qs_s5k4e1_set_step, "%lld\n");
+
+static int cam_debug_stream_set(void *data, u64 val)
+{
+	int rc = 0;
+
+	if (val) {
+		qs_s5k4e1_start_stream();
+		streaming = 1;
+	} else {
+		qs_s5k4e1_stop_stream();
+		streaming = 0;
+	}
+
+	return rc;
+}
+
+static int cam_debug_stream_get(void *data, u64 *val)
+{
+	*val = streaming;
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(cam_stream, cam_debug_stream_get,
+			cam_debug_stream_set, "%llu\n");
+
+static uint16_t qs_s5k4e1_step_val = QS_S5K4E1_TOTAL_STEPS_NEAR_TO_FAR;
+static uint8_t qs_s5k4e1_step_dir = MOVE_NEAR;
+static int qs_s5k4e1_af_step_config(void *data, u64 val)
+{
+	qs_s5k4e1_step_val = val & 0xFFFF;
+	qs_s5k4e1_step_dir = (val >> 16) & 0x1;
+	CDBG("%s\n", __func__);
+	return 0;
+}
+
+static int qs_s5k4e1_af_step(void *data, u64 *val)
+{
+	int i = 0;
+	int dir = MOVE_NEAR;
+	CDBG("%s\n", __func__);
+	qs_s5k4e1_set_default_focus(0);
+	msleep(5000);
+	if (qs_s5k4e1_step_dir == 1)
+		dir = MOVE_FAR;
+
+	for (i = 0; i < qs_s5k4e1_step_val; i += 4) {
+		qs_s5k4e1_move_focus(dir, 4);
+		msleep(1000);
+	}
+	qs_s5k4e1_set_default_focus(0);
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(af_step, qs_s5k4e1_af_step,
+			qs_s5k4e1_af_step_config, "%llu\n");
+
+static int cam_debug_init(void)
+{
+	struct dentry *cam_dir;
+	debugfs_base = debugfs_create_dir("sensor", NULL);
+	if (!debugfs_base)
+		return -ENOMEM;
+
+	cam_dir = debugfs_create_dir("qs_s5k4e1", debugfs_base);
+	if (!cam_dir)
+		return -ENOMEM;
+
+	if (!debugfs_create_file("focus", S_IRUGO | S_IWUSR, cam_dir,
+							 NULL, &cam_focus))
+		return -ENOMEM;
+	if (!debugfs_create_file("step", S_IRUGO | S_IWUSR, cam_dir,
+							 NULL, &cam_step))
+		return -ENOMEM;
+	if (!debugfs_create_file("stream", S_IRUGO | S_IWUSR, cam_dir,
+							 NULL, &cam_stream))
+		return -ENOMEM;
+	if (!debugfs_create_file("af_step", S_IRUGO | S_IWUSR, cam_dir,
+							 NULL, &af_step))
+		return -ENOMEM;
+	return 0;
+}
+
+static int __qs_s5k4e1_probe(struct platform_device *pdev)
+{
+	return msm_camera_drv_start(pdev, qs_s5k4e1_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = __qs_s5k4e1_probe,
+	.driver = {
+		.name = "msm_camera_qs_s5k4e1",
+	.owner = THIS_MODULE,
+	},
+};
+
+static int __init qs_s5k4e1_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(qs_s5k4e1_init);
+void qs_s5k4e1_exit(void)
+{
+	i2c_del_driver(&qs_s5k4e1_i2c_driver);
+}
+MODULE_DESCRIPTION("Samsung 5MP Bayer sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/qs_s5k4e1.h b/drivers/media/video/msm/qs_s5k4e1.h
new file mode 100644
index 0000000..f9c4c3f
--- /dev/null
+++ b/drivers/media/video/msm/qs_s5k4e1.h
@@ -0,0 +1,89 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#ifndef QS_S5K4E1_H
+#define QS_S5K4E1_H
+#include <linux/types.h>
+#include <mach/board.h>
+extern struct qs_s5k4e1_reg qs_s5k4e1_regs;
+
+#define LENS_SHADE_TABLE 16
+
+struct qs_s5k4e1_i2c_reg_conf {
+	unsigned short waddr;
+	unsigned short wdata;
+};
+
+struct qs_s5k4e1_i2c_conf_array {
+       struct qs_s5k4e1_i2c_reg_conf *conf;
+       unsigned short size;
+};
+
+enum qs_s5k4e1_test_mode_t {
+	TEST_OFF,
+	TEST_1,
+	TEST_2,
+	TEST_3
+};
+
+enum qs_s5k4e1_resolution_t {
+	QTR_2D_SIZE,
+	FULL_2D_SIZE,
+	QTR_3D_SIZE,
+	FULL_3D_SIZE,
+	INVALID_SIZE
+};
+enum qs_s5k4e1_setting {
+	RES_PREVIEW,
+	RES_CAPTURE,
+	RES_3D_PREVIEW,
+	RES_3D_CAPTURE
+};
+enum qs_s5k4e1_cam_mode_t {
+    MODE_2D_RIGHT,
+	MODE_2D_LEFT,
+	MODE_3D,
+	MODE_INVALID
+};
+enum qs_s5k4e1_reg_update {
+	/* Sensor egisters that need to be updated during initialization */
+	REG_INIT,
+	/* Sensor egisters that needs periodic I2C writes */
+	UPDATE_PERIODIC,
+	/* All the sensor Registers will be updated */
+	UPDATE_ALL,
+	/* Not valid update */
+	UPDATE_INVALID
+};
+
+enum qs_s5k4e1_reg_mode {
+	QS_S5K4E1_FRAME_LENGTH_LINES_H = 1,
+	QS_S5K4E1_FRAME_LENGTH_LINES_L,
+	QS_S5K4E1_LINE_LENGTH_PCK_H,
+	QS_S5K4E1_LINE_LENGTH_PCK_L,
+};
+
+struct qs_s5k4e1_reg {
+	const struct qs_s5k4e1_i2c_reg_conf *rec_settings;
+	const unsigned short rec_size;
+	const struct qs_s5k4e1_i2c_reg_conf *reg_prev;
+	const unsigned short reg_prev_size;
+	const struct qs_s5k4e1_i2c_reg_conf *reg_snap;
+	const unsigned short reg_snap_size;
+	const struct qs_s5k4e1_i2c_reg_conf (*reg_lens)[LENS_SHADE_TABLE];
+	const unsigned short reg_lens_size;
+	const struct qs_s5k4e1_i2c_reg_conf *reg_default_lens;
+	const unsigned short reg_default_lens_size;
+	const struct qs_s5k4e1_i2c_conf_array *conf_array;
+};
+#endif /* QS_S5K4E1_H */
diff --git a/drivers/media/video/msm/qs_s5k4e1_reg.c b/drivers/media/video/msm/qs_s5k4e1_reg.c
new file mode 100644
index 0000000..22876de
--- /dev/null
+++ b/drivers/media/video/msm/qs_s5k4e1_reg.c
@@ -0,0 +1,799 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+
+#include "qs_s5k4e1.h"
+
+struct qs_s5k4e1_i2c_reg_conf qs_s5k4e1_prev_settings_3d[] = {
+	{0x0100, 0x00},
+	/*Frame Length*/
+	{0x0340, 0x04},
+	{0x0341, 0x90},
+	/*Line Length*/
+	{0x0342, 0x0A},
+	{0x0343, 0xB2},
+	{0x3030, 0x06},
+	{0x3017, 0xA4},
+	{0x301B, 0x88},
+	{0x30BC, 0x90},
+	{0x301C, 0x04},
+	{0x0202, 0x04},
+	{0x0203, 0x12},
+	{0x0204, 0x00},
+	{0x0205, 0x80},
+	{0x0306, 0x00},
+	{0x0307, 0x60},
+	{0x30F1, 0x70},
+/*MIPI Size Setting*/
+	{0x30A9, 0x02},
+	{0x300E, 0xE8},
+	{0x0387, 0x01},
+	{0x0344, 0x01},
+	{0x0345, 0x18},
+	{0x0348, 0x09},
+	{0x0349, 0x17},
+	{0x0346, 0x01},
+	{0x0347, 0x94},
+	{0x034A, 0x06},
+	{0x034B, 0x13},
+	{0x0380, 0x00},
+	{0x0381, 0x01},
+	{0x0382, 0x00},
+	{0x0383, 0x01},
+	{0x0384, 0x00},
+	{0x0385, 0x01},
+	{0x0386, 0x00},
+	{0x0387, 0x01},
+	{0x034C, 0x04},
+	{0x034D, 0x00},
+	{0x034E, 0x04},
+	{0x034F, 0x80},
+	{0x30BF, 0xAA},
+	{0x30C0, 0x40},
+	{0x30C8, 0x04},
+	{0x30C9, 0x00},
+};
+
+struct qs_s5k4e1_i2c_reg_conf qs_s5k4e1_prev_settings_2d[] = {
+	{0x0100, 0x00},
+	{0x0340, 0x03},
+	{0x0341, 0xe0},
+	{0x0342, 0x0A},
+	{0x0343, 0xB2},
+	{0x3030, 0x06},
+	{0x301B, 0x83},
+	{0x30BC, 0x98},
+	{0x301C, 0x04},
+	{0x0202, 0x01},
+	{0x0203, 0xFD},
+	{0x0204, 0x00},
+	{0x0205, 0x80},
+	{0x0306, 0x00},
+	{0x0307, 0x64},
+	{0x30F1, 0xa0},
+	{0x30A9, 0x02},
+	{0x300E, 0xEB},
+	{0x0387, 0x03},
+	{0x0344, 0x00},
+	{0x0345, 0x00},
+	{0x0348, 0x0A},
+	{0x0349, 0x2F},
+	{0x0346, 0x00},
+	{0x0347, 0x00},
+	{0x034A, 0x07},
+	{0x034B, 0xA7},
+	{0x0380, 0x00},
+	{0x0381, 0x01},
+	{0x0382, 0x00},
+	{0x0383, 0x01},
+	{0x0384, 0x00},
+	{0x0385, 0x01},
+	{0x0386, 0x00},
+	{0x0387, 0x03},
+	{0x034C, 0x05},
+	{0x034D, 0x10},
+	{0x034E, 0x03},
+	{0x034F, 0xd4},
+	{0x30BF, 0xAB},
+	{0x30C0, 0xc0},
+	{0x30C8, 0x06},
+	{0x30C9, 0x54},
+};
+
+struct qs_s5k4e1_i2c_reg_conf qs_s5k4e1_snap_settings_2d[] = {
+	{0x0100, 0x00},
+	{0x0340, 0x07},
+	{0x0341, 0xb4},
+	{0x0342, 0x0A},
+	{0x0343, 0xB2},
+	{0x3030, 0x06}, /*shut streaming off*/
+	{0x300E, 0xE8},
+	{0x301B, 0x75},
+	{0x301C, 0x04},
+	{0x30BC, 0x98},
+	{0x0202, 0x04},
+	{0x0203, 0x12},
+	{0x0204, 0x00},
+	{0x0205, 0x80},
+	{0x0306, 0x00},
+	{0x0307, 0x64},
+	{0x30F1, 0xa0},
+	{0x30A9, 0x03},/*Horizontal Binning Off*/
+	{0x300E, 0xE8},/*Vertical Binning Off*/
+	{0x0387, 0x01},/*y_odd_inc*/
+	{0x034C, 0x0A},/*x_output size*/
+	{0x034D, 0x30},
+	{0x034E, 0x07},/*y_output size*/
+	{0x034F, 0xA8},
+	{0x30BF, 0xAB},/*outif_enable[7], data_type[5:0](2Bh = bayer 10bit)*/
+	{0x30C0, 0x86},/*video_offset[7:4] 3260%12*/
+	{0x30C8, 0x0C},/*video_data_length 3260 = 2608 * 1.25*/
+	{0x30C9, 0xBC},
+
+};
+
+struct qs_s5k4e1_i2c_reg_conf qs_s5k4e1_snap_settings_3d[] = {
+	{0x0100, 0x00},
+
+/* Frame Length*/
+	{0x0340, 0x09},
+	{0x0341, 0x20},
+/* Line Length*/
+	{0x0342, 0x0A},
+	{0x0343, 0xB2},
+	{0x3030, 0x06},/*shut streaming off*/
+/*Analog Setting*/
+	{0x3017, 0xA4},
+	{0x301B, 0x88},
+	{0x30BC, 0x90},
+	{0x301C, 0x04},
+/*Integration setting ... */
+	{0x0202, 0x04},
+	{0x0203, 0x12},
+	{0x0204, 0x00},
+	{0x0205, 0x80},
+/*PLL setting ...*/
+	{0x0306, 0x00},
+	{0x0307, 0x60},
+	{0x30F1, 0x70},
+/*MIPI Size Setting*/
+	{0x30A9, 0x01},
+	{0x300E, 0xE8},
+	{0x0387, 0x01},
+	{0x0344, 0x01},/*x_addr_start*/
+	{0x0345, 0x14},
+	{0x0348, 0x09},/*x_addr_end*/
+	{0x0349, 0x17},
+	{0x0346, 0x01},/*y_addr_start*/
+	{0x0347, 0x94},
+	{0x034A, 0x06},/*y_addr_end*/
+	{0x034B, 0x13},
+	{0x0380, 0x00},/*x_even_inc 1*/
+	{0x0381, 0x01},
+	{0x0382, 0x00},/*x_odd_inc 1*/
+	{0x0383, 0x01},
+	{0x0384, 0x00},/*y_even_inc 1*/
+	{0x0385, 0x01},
+	{0x0386, 0x00},/*y_odd_inc 1*/
+	{0x0387, 0x01},
+	{0x034C, 0x08},/*x_output size*/
+	{0x034D, 0x00},
+	{0x034E, 0x04},/*y_output size*/
+	{0x034F, 0x80},
+	{0x30BF, 0xAA},/*outif_enable[7], data_type[5:0](2Bh = bayer 8bit)*/
+	{0x30C0, 0x80},/*video_offset[7:4]*/
+	{0x30C8, 0x08},/*video_data_length*/
+	{0x30C9, 0x00},
+
+};
+
+struct qs_s5k4e1_i2c_reg_conf qs_s5k4e1_recommend_settings[] = {
+	{0x0100, 0x00},
+
+	{0x3030, 0x06},/*shut streaming*/
+/*Analog Setting*/
+	{0x3000, 0x05},
+	{0x3001, 0x03},
+	{0x3002, 0x08},
+	{0x3003, 0x09},
+	{0x3004, 0x2E},
+	{0x3005, 0x06},
+	{0x3006, 0x34},
+	{0x3007, 0x00},
+	{0x3008, 0x3C},
+	{0x3009, 0x3C},
+	{0x300A, 0x28},
+	{0x300B, 0x04},
+	{0x300C, 0x0A},
+	{0x300D, 0x02},
+	{0x300F, 0x82},
+	{0x3010, 0x00},
+	{0x3011, 0x4C},
+	{0x3012, 0x30},
+	{0x3013, 0xC0},
+	{0x3014, 0x00},
+	{0x3015, 0x00},
+	{0x3016, 0x2C},
+	{0x3017, 0x94},
+	{0x3018, 0x78},
+	{0x301D, 0xD4},
+	{0x3021, 0x02},
+	{0x3022, 0x24},
+	{0x3024, 0x40},
+	{0x3027, 0x08},
+	{0x3029, 0xC6},
+	{0x302B, 0x01},
+	{0x30D8, 0x3F},
+/* ADLC setting ...*/
+	{0x3070, 0x5F},
+	{0x3071, 0x00},
+	{0x3080, 0x04},
+	{0x3081, 0x38},
+
+/*MIPI setting*/
+	{0x30BD, 0x00},/*SEL_CCP[0]*/
+	{0x3084, 0x15},/*SYNC Mode*/
+	{0x30BE, 0x1A},/*M_PCLKDIV_AUTO[4], M_DIV_PCLK[3:0]*/
+	{0x30C1, 0x01},/*pack video enable [0]*/
+	{0x30EE, 0x02},/*DPHY enable [1]*/
+	{0x3111, 0x86},/*Embedded data off [5]*/
+/*For MIPI T8 T9*/
+	{0x30E3, 0x38},
+	{0x30E4, 0x40},
+	{0x3113, 0x70},
+	{0x3114, 0x80},
+	{0x3115, 0x7B},
+	{0x3116, 0xC0},
+	{0x30EE, 0x12},
+
+/*PLL setting ...*/
+	{0x0305, 0x06},
+	{0x30B5, 0x01},
+	{0x30E2, 0x02},/*num lanes[1:0] = 1*/
+
+};
+static struct qs_s5k4e1_i2c_reg_conf qs_s5k4e1_default_lenshading_settings[] = {
+
+	{0x3200, 0x00},
+	{0x3201, 0x9a},
+	{0x3202, 0x56},
+	{0x3203, 0xf },
+	{0x3204, 0xd8},
+	{0x3205, 0x94},
+	{0x3206, 0x0 },
+	{0x3207, 0x10},
+	{0x3208, 0x71},
+	{0x3209, 0x0 },
+	{0x320a, 0x9 },
+	{0x320b, 0xc1},
+	{0x320c, 0xf },
+	{0x320d, 0xf1},
+	{0x320e, 0x3d},
+	{0x320f, 0x0 },
+	{0x3210, 0xa },
+	{0x3211, 0x93},
+	{0x3212, 0xf },
+	{0x3213, 0xc9},
+	{0x3214, 0xa1},
+	{0x3215, 0x0 },
+	{0x3216, 0x10},
+	{0x3217, 0x89},
+	{0x3218, 0xf },
+	{0x3219, 0xfb},
+	{0x321a, 0xf3},
+	{0x321b, 0xf },
+	{0x321c, 0xf8},
+	{0x321d, 0xfc},
+	{0x321e, 0x0 },
+	{0x321f, 0x4 },
+	{0x3220, 0xe3},
+	{0x3221, 0xf },
+	{0x3222, 0xfe},
+	{0x3223, 0x94},
+	{0x3224, 0x0 },
+	{0x3225, 0x24},
+	{0x3226, 0x59},
+	{0x3227, 0xf },
+	{0x3228, 0xe9},
+	{0x3229, 0x68},
+	{0x322a, 0xf },
+	{0x322b, 0xfa},
+	{0x322c, 0x7f},
+	{0x322d, 0x0 },
+	{0x322e, 0x13},
+	{0x322f, 0xe1},
+	{0x3230, 0x0 },
+	{0x3231, 0x3 },
+	{0x3232, 0xbc},
+	{0x3233, 0xf },
+	{0x3234, 0xf0},
+	{0x3235, 0xa1},
+	{0x3236, 0xf },
+	{0x3237, 0xf4},
+	{0x3238, 0xc9},
+	{0x3239, 0x0 },
+	{0x323a, 0x11},
+	{0x323b, 0x4b},
+	{0x323c, 0x0 },
+	{0x323d, 0x12},
+	{0x323e, 0xc5},
+	{0x323f, 0xf },
+	{0x3240, 0xe3},
+	{0x3241, 0xb },
+	{0x3242, 0xf },
+	{0x3243, 0xf8},
+	{0x3244, 0x4f},
+	{0x3245, 0x0 },
+	{0x3246, 0x13},
+	{0x3247, 0xac},
+	{0x3248, 0x0 },
+	{0x3249, 0x0 },
+	{0x324a, 0x7c},
+	{0x324b, 0xf },
+	{0x324c, 0xfe},
+	{0x324d, 0xdd},
+	{0x324e, 0xf },
+	{0x324f, 0xf2},
+	{0x3250, 0x96},
+	{0x3251, 0x0 },
+	{0x3252, 0x8 },
+	{0x3253, 0xef},
+	{0x3254, 0x0 },
+	{0x3255, 0x6 },
+	{0x3256, 0xa4},
+	{0x3257, 0x0 },
+	{0x3258, 0x2 },
+	{0x3259, 0x4b},
+	{0x325a, 0x0 },
+	{0x325b, 0x6 },
+	{0x325c, 0x85},
+	{0x325d, 0xf },
+	{0x325e, 0xf8},
+	{0x325f, 0x6a},
+	{0x3260, 0xf },
+	{0x3261, 0xfd},
+	{0x3262, 0x70},
+	{0x3263, 0x0 },
+	{0x3264, 0xd },
+	{0x3265, 0xa9},
+	{0x3266, 0xf },
+	{0x3267, 0xfd},
+	{0x3268, 0xf8},
+	{0x3269, 0xf },
+	{0x326a, 0xec},
+	{0x326b, 0xfc},
+	{0x326c, 0x0 },
+	{0x326d, 0xa7},
+	{0x326e, 0x5 },
+	{0x326f, 0xf },
+	{0x3270, 0xd6},
+	{0x3271, 0x19},
+	{0x3272, 0x0 },
+	{0x3273, 0xa },
+	{0x3274, 0xe8},
+	{0x3275, 0x0 },
+	{0x3276, 0x17},
+	{0x3277, 0x1 },
+	{0x3278, 0xf },
+	{0x3279, 0xe7},
+	{0x327a, 0xa0},
+	{0x327b, 0x0 },
+	{0x327c, 0xb },
+	{0x327d, 0xc3},
+	{0x327e, 0xf },
+	{0x327f, 0xc0},
+	{0x3280, 0xe3},
+	{0x3281, 0x0 },
+	{0x3282, 0x15},
+	{0x3283, 0x5a},
+	{0x3284, 0xf },
+	{0x3285, 0xf9},
+	{0x3286, 0xa0},
+	{0x3287, 0xf },
+	{0x3288, 0xf4},
+	{0x3289, 0xce},
+	{0x328a, 0x0 },
+	{0x328b, 0xb },
+	{0x328c, 0x72},
+	{0x328d, 0xf },
+	{0x328e, 0xfb},
+	{0x328f, 0xb5},
+	{0x3290, 0x0 },
+	{0x3291, 0x2f},
+	{0x3292, 0xb },
+	{0x3293, 0xf },
+	{0x3294, 0xde},
+	{0x3295, 0xc0},
+	{0x3296, 0x0 },
+	{0x3297, 0x0 },
+	{0x3298, 0x58},
+	{0x3299, 0x0 },
+	{0x329a, 0x1b},
+	{0x329b, 0x5 },
+	{0x329c, 0xf },
+	{0x329d, 0xf9},
+	{0x329e, 0x23},
+	{0x329f, 0xf },
+	{0x32a0, 0xf3},
+	{0x32a1, 0x94},
+	{0x32a2, 0xf },
+	{0x32a3, 0xe7},
+	{0x32a4, 0xc2},
+	{0x32a5, 0x0 },
+	{0x32a6, 0x1d},
+	{0x32a7, 0xe5},
+	{0x32a8, 0x0 },
+	{0x32a9, 0x5 },
+	{0x32aa, 0xaf},
+	{0x32ab, 0xf },
+	{0x32ac, 0xe3},
+	{0x32ad, 0xb7},
+	{0x32ae, 0xf },
+	{0x32af, 0xf8},
+	{0x32b0, 0x34},
+	{0x32b1, 0x0 },
+	{0x32b2, 0x1c},
+	{0x32b3, 0x3d},
+	{0x32b4, 0x0 },
+	{0x32b5, 0x10},
+	{0x32b6, 0x4a},
+	{0x32b7, 0xf },
+	{0x32b8, 0xfa},
+	{0x32b9, 0x7 },
+	{0x32ba, 0xf },
+	{0x32bb, 0xff},
+	{0x32bc, 0x16},
+	{0x32bd, 0x0 },
+	{0x32be, 0x5 },
+	{0x32bf, 0x4e},
+	{0x32c0, 0x0 },
+	{0x32c1, 0xc },
+	{0x32c2, 0x1b},
+	{0x32c3, 0xf },
+	{0x32c4, 0xf1},
+	{0x32c5, 0xdb},
+	{0x32c6, 0xf },
+	{0x32c7, 0xfc},
+	{0x32c8, 0xf8},
+	{0x32c9, 0xf },
+	{0x32ca, 0xf4},
+	{0x32cb, 0xad},
+	{0x32cc, 0xf },
+	{0x32cd, 0xfb},
+	{0x32ce, 0x59},
+	{0x32cf, 0x0 },
+	{0x32d0, 0x9 },
+	{0x32d1, 0xf7},
+	{0x32d2, 0x0 },
+	{0x32d3, 0x0 },
+	{0x32d4, 0xc1},
+	{0x32d5, 0xf },
+	{0x32d6, 0xf5},
+	{0x32d7, 0x30},
+	{0x32d8, 0x0 },
+	{0x32d9, 0x83},
+	{0x32da, 0x1d},
+	{0x32db, 0xf },
+	{0x32dc, 0xe3},
+	{0x32dd, 0x3c},
+	{0x32de, 0x0 },
+	{0x32df, 0xa },
+	{0x32e0, 0x10},
+	{0x32e1, 0x0 },
+	{0x32e2, 0x7 },
+	{0x32e3, 0x65},
+	{0x32e4, 0xf },
+	{0x32e5, 0xfe},
+	{0x32e6, 0x79},
+	{0x32e7, 0xf },
+	{0x32e8, 0xfd},
+	{0x32e9, 0x57},
+	{0x32ea, 0xf },
+	{0x32eb, 0xd6},
+	{0x32ec, 0x8f},
+	{0x32ed, 0x0 },
+	{0x32ee, 0x3 },
+	{0x32ef, 0x93},
+	{0x32f0, 0x0 },
+	{0x32f1, 0x6 },
+	{0x32f2, 0xa },
+	{0x32f3, 0xf },
+	{0x32f4, 0xfa},
+	{0x32f5, 0x6c},
+	{0x32f6, 0xf },
+	{0x32f7, 0xf1},
+	{0x32f8, 0x1e},
+	{0x32f9, 0x0 },
+	{0x32fa, 0x14},
+	{0x32fb, 0xe7},
+	{0x32fc, 0x0 },
+	{0x32fd, 0x1f},
+	{0x32fe, 0x2d},
+	{0x32ff, 0x0 },
+	{0x3300, 0x7 },
+	{0x3301, 0x5e},
+	{0x3302, 0xf },
+	{0x3303, 0xe0},
+	{0x3304, 0x55},
+	{0x3305, 0x0 },
+	{0x3306, 0x20},
+	{0x3307, 0x93},
+	{0x3308, 0x0 },
+	{0x3309, 0xf },
+	{0x330a, 0x20},
+	{0x330b, 0xf },
+	{0x330c, 0xd7},
+	{0x330d, 0xf5},
+	{0x330e, 0xf },
+	{0x330f, 0xef},
+	{0x3310, 0xb8},
+	{0x3311, 0xf },
+	{0x3312, 0xf0},
+	{0x3313, 0x29},
+	{0x3314, 0x0 },
+	{0x3315, 0x27},
+	{0x3316, 0x5e},
+	{0x3317, 0xf },
+	{0x3318, 0xda},
+	{0x3319, 0x14},
+	{0x331a, 0xf },
+	{0x331b, 0xef},
+	{0x331c, 0x93},
+	{0x331d, 0x0 },
+	{0x331e, 0x2c},
+	{0x331f, 0xdc},
+	{0x3320, 0x0 },
+	{0x3321, 0xe },
+	{0x3322, 0x2d},
+	{0x3323, 0x0 },
+	{0x3324, 0x6 },
+	{0x3325, 0xcf},
+	{0x3326, 0xf },
+	{0x3327, 0xfb},
+	{0x3328, 0x26},
+	{0x3329, 0x0 },
+	{0x332a, 0x3 },
+	{0x332b, 0x5 },
+	{0x332c, 0x0 },
+	{0x332d, 0x6 },
+	{0x332e, 0xa6},
+	{0x332f, 0xf },
+	{0x3330, 0xf7},
+	{0x3331, 0x7b},
+	{0x3332, 0xf },
+	{0x3333, 0xf9},
+	{0x3334, 0xb },
+	{0x3335, 0x0 },
+	{0x3336, 0x7 },
+	{0x3337, 0x5a},
+	{0x3338, 0xf },
+	{0x3339, 0xe4},
+	{0x333a, 0x7a},
+	{0x333b, 0x0 },
+	{0x333c, 0x1b},
+	{0x333d, 0xb0},
+	{0x333e, 0x0 },
+	{0x333f, 0x2 },
+	{0x3340, 0xa7},
+	{0x3341, 0xf },
+	{0x3342, 0xe9},
+	{0x3343, 0x3a},
+	{0x3344, 0x0 },
+	{0x3345, 0x95},
+	{0x3346, 0x42},
+	{0x3347, 0xf },
+	{0x3348, 0xda},
+	{0x3349, 0x45},
+	{0x334a, 0x0 },
+	{0x334b, 0x16},
+	{0x334c, 0x7a},
+	{0x334d, 0xf },
+	{0x334e, 0xfb},
+	{0x334f, 0x32},
+	{0x3350, 0x0 },
+	{0x3351, 0x6 },
+	{0x3352, 0x35},
+	{0x3353, 0xf },
+	{0x3354, 0xfc},
+	{0x3355, 0x8f},
+	{0x3356, 0xf },
+	{0x3357, 0xca},
+	{0x3358, 0xd5},
+	{0x3359, 0x0 },
+	{0x335a, 0x11},
+	{0x335b, 0x59},
+	{0x335c, 0xf },
+	{0x335d, 0xfa},
+	{0x335e, 0xaa},
+	{0x335f, 0xf },
+	{0x3360, 0xfe},
+	{0x3361, 0x84},
+	{0x3362, 0xf },
+	{0x3363, 0xf6},
+	{0x3364, 0x8f},
+	{0x3365, 0x0 },
+	{0x3366, 0xb },
+	{0x3367, 0x70},
+	{0x3368, 0x0 },
+	{0x3369, 0x25},
+	{0x336a, 0x83},
+	{0x336b, 0xf },
+	{0x336c, 0xe7},
+	{0x336d, 0x27},
+	{0x336e, 0xf },
+	{0x336f, 0xf1},
+	{0x3370, 0x72},
+	{0x3371, 0x0 },
+	{0x3372, 0x21},
+	{0x3373, 0x6d},
+	{0x3374, 0x0 },
+	{0x3375, 0x2 },
+	{0x3376, 0xc3},
+	{0x3377, 0xf },
+	{0x3378, 0xe8},
+	{0x3379, 0x5a},
+	{0x337a, 0xf },
+	{0x337b, 0xf2},
+	{0x337c, 0x73},
+	{0x337d, 0x0 },
+	{0x337e, 0x19},
+	{0x337f, 0xa5},
+	{0x3380, 0x0 },
+	{0x3381, 0x1a},
+	{0x3382, 0x81},
+	{0x3383, 0xf },
+	{0x3384, 0xd0},
+	{0x3385, 0x31},
+	{0x3386, 0xf },
+	{0x3387, 0xfb},
+	{0x3388, 0xff},
+	{0x3389, 0x0 },
+	{0x338a, 0x1e},
+	{0x338b, 0xe1},
+	{0x338c, 0x0 },
+	{0x338d, 0x5 },
+	{0x338e, 0xe1},
+	{0x338f, 0xf },
+	{0x3390, 0xee},
+	{0x3391, 0xe2},
+	{0x3392, 0xf },
+	{0x3393, 0xf6},
+	{0x3394, 0xcf},
+	{0x3395, 0x0 },
+	{0x3396, 0x13},
+	{0x3397, 0x8f},
+	{0x3398, 0x0 },
+	{0x3399, 0x3 },
+	{0x339a, 0x61},
+	{0x339b, 0xf },
+	{0x339c, 0xf8},
+	{0x339d, 0xf7},
+	{0x339e, 0x0 },
+	{0x339f, 0x0 },
+	{0x33a0, 0xb5},
+	{0x33a1, 0x0 },
+	{0x33a2, 0x5 },
+	{0x33a3, 0x78},
+	{0x33a4, 0xf },
+	{0x33a5, 0xf4},
+	{0x33a6, 0x5 },
+	{0x33a7, 0x0 },
+	{0x33a8, 0xc },
+	{0x33a9, 0xe },
+	{0x33aa, 0x0 },
+	{0x33ab, 0x3 },
+	{0x33ac, 0x53},
+	{0x33ad, 0xf },
+	{0x33ae, 0xec},
+	{0x33af, 0xbd},
+};
+
+const struct
+qs_s5k4e1_i2c_reg_conf qs_s5k4e1_lenshading_settings[4][LENS_SHADE_TABLE] = {
+	{/*2D Preview*/
+		{0x3097, 0x52},/*sh4ch_blk_width = 82*/
+		{0x3098, 0x3e},/*sh4ch_blk_height = 62*/
+		{0x3099, 0x03},/*sh4ch_step_x msb (sh4ch_step_x = 799)*/
+		{0x309a, 0x1f},/*sh4ch_step_x lsb*/
+		{0x309b, 0x04},/*sh4ch_step_y msb (sh4ch_step_y = 1057)*/
+		{0x309c, 0x21},/*sh4ch_step_y lsb*/
+		{0x309d, 0x00},/*sh4ch_start_blk_cnt_x = 0*/
+		{0x309e, 0x00},/*sh4ch_start_int_cnt_x = 0*/
+		{0x309f, 0x00},/*sh4ch_start_frac_cnt_x msb (0)*/
+		{0x30a0, 0x00},/*sh4ch_start_frac_cnt_x lsb*/
+		{0x30a1, 0x00},/*sh4ch_start_blk_cnt_y = 0*/
+		{0x30a2, 0x00},/*sh4ch_start_int_cnt_y = 0*/
+		{0x30a3, 0x00},/*sh4ch_start_frac_cnt_y msb (0)*/
+		{0x30a4, 0x00},/*sh4ch_start_frac_cnt_y lsb*/
+		{0x30a5, 0x01},
+		{0x30a6, 0x00},/*gs_pedestal	= 64*/
+	},
+	{/*2D Snapshot*/
+		{0x3097, 0x52},/*sh4ch_blk_width = 82*/
+		{0x3098, 0x7b},/*sh4ch_blk_height = 123*/
+		{0x3099, 0x03},/*sh4ch_step_x msb (sh4ch_step_x = 799)*/
+		{0x309a, 0x1f},/*sh4ch_step_x lsb*/
+		{0x309b, 0x02},/*sh4ch_step_y msb (sh4ch_step_y = 533)*/
+		{0x309c, 0x15},/*sh4ch_step_y lsb*/
+		{0x309d, 0x00},/*sh4ch_start_blk_cnt_x = 0*/
+		{0x309e, 0x00},/*sh4ch_start_int_cnt_x = 0*/
+		{0x309f, 0x00},/*sh4ch_start_frac_cnt_x msb (0)*/
+		{0x30a0, 0x00},/*sh4ch_start_frac_cnt_x lsb*/
+		{0x30a1, 0x00},/*sh4ch_start_blk_cnt_y = 0*/
+		{0x30a2, 0x00},/*sh4ch_start_int_cnt_y = 0*/
+		{0x30a3, 0x00},/*sh4ch_start_frac_cnt_y msb (0)*/
+		{0x30a4, 0x00},/*sh4ch_start_frac_cnt_y lsb*/
+		{0x30a5, 0x01},
+		{0x30a6, 0x00},/*gs_pedestal	= 64*/
+	},
+
+	{/*3D Preview*/
+		{0x3097, 0x52},/*sh4ch_blk_width = 82*/
+		{0x3098, 0x7b},/*sh4ch_blk_height = 123*/
+		{0x3099, 0x03},/*sh4ch_step_x msb (sh4ch_step_x = 799)*/
+		{0x309a, 0x1f},/*sh4ch_step_x lsb*/
+		{0x309b, 0x02},/*sh4ch_step_y msb (sh4ch_step_y = 533)*/
+		{0x309c, 0x15},/*sh4ch_step_y lsb*/
+		{0x309d, 0x3a},/*sh4ch_start_blk_cnt_x = 58*/
+		{0x309e, 0x01},/*sh4ch_start_int_cnt_x = 1*/
+		{0x309f, 0xb5},/*sh4ch_start_frac_cnt_x msb (46342)*/
+		{0x30a0, 0x06},/*sh4ch_start_frac_cnt_x lsb*/
+		{0x30a1, 0x23},/*sh4ch_start_blk_cnt_y = 35*/
+		{0x30a2, 0x03},/*sh4ch_start_int_cnt_y = 3*/
+		{0x30a3, 0x48},/*sh4ch_start_frac_cnt_y msb (46342)*/
+		{0x30a4, 0xdf},/*sh4ch_start_frac_cnt_y lsb*/
+		{0x30a5, 0x01},
+		{0x30a6, 0x00},/*gs_pedestal	= 64*/
+	},
+
+	{/*3D Snapshot*/
+		{0x3097, 0x52},/*sh4ch_blk_width = 82*/
+		{0x3098, 0x7b},/*sh4ch_blk_height = 123*/
+		{0x3099, 0x03},/*sh4ch_step_x msb (sh4ch_step_x = 799)*/
+		{0x309a, 0x1f},/*sh4ch_step_x lsb*/
+		{0x309b, 0x02},/*sh4ch_step_y msb (sh4ch_step_y = 533)*/
+		{0x309c, 0x15},/*sh4ch_step_y lsb*/
+		{0x309d, 0x38},/*sh4ch_start_blk_cnt_x = 56*/
+		{0x309e, 0x01},/*sh4ch_start_int_cnt_x = 1*/
+		{0x309f, 0xae},/*sh4ch_start_frac_cnt_x msb (44744)*/
+		{0x30a0, 0xc8},/*sh4ch_start_frac_cnt_x lsb*/
+		{0x30a1, 0x23},/*sh4ch_start_blk_cnt_y = 35*/
+		{0x30a2, 0x03},/*sh4ch_start_int_cnt_y = 3*/
+		{0x30a3, 0x48},/*sh4ch_start_frac_cnt_y msb (44744)*/
+		{0x30a4, 0xdf},/*sh4ch_start_frac_cnt_y lsb*/
+		{0x30a5, 0x01},
+		{0x30a6, 0x00},/*gs_pedestal	= 64*/
+	},
+
+};
+
+struct qs_s5k4e1_i2c_conf_array qs_s5k4e1_confs[] = {
+	{&qs_s5k4e1_prev_settings_2d[0], \
+		ARRAY_SIZE(qs_s5k4e1_prev_settings_2d)},
+	{&qs_s5k4e1_snap_settings_2d[0], \
+		ARRAY_SIZE(qs_s5k4e1_snap_settings_2d)},
+	{&qs_s5k4e1_prev_settings_3d[0], \
+		ARRAY_SIZE(qs_s5k4e1_prev_settings_3d)},
+	{&qs_s5k4e1_snap_settings_3d[0], \
+		ARRAY_SIZE(qs_s5k4e1_snap_settings_3d)},
+};
+struct qs_s5k4e1_reg qs_s5k4e1_regs = {
+	.rec_settings = &qs_s5k4e1_recommend_settings[0],
+	.rec_size = ARRAY_SIZE(qs_s5k4e1_recommend_settings),
+	.reg_lens = &qs_s5k4e1_lenshading_settings[0],
+	.reg_lens_size = ARRAY_SIZE(qs_s5k4e1_lenshading_settings[0]),
+	.reg_default_lens = &qs_s5k4e1_default_lenshading_settings[0],
+	.reg_default_lens_size =
+		ARRAY_SIZE(qs_s5k4e1_default_lenshading_settings),
+	.conf_array = &qs_s5k4e1_confs[0],
+};
diff --git a/drivers/media/video/msm/s5k3e2fx.c b/drivers/media/video/msm/s5k3e2fx.c
new file mode 100644
index 0000000..178a080
--- /dev/null
+++ b/drivers/media/video/msm/s5k3e2fx.c
@@ -0,0 +1,1386 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <media/msm_camera.h>
+#include <mach/gpio.h>
+#include <mach/camera.h>
+#include "s5k3e2fx.h"
+
+#define S5K3E2FX_REG_MODEL_ID   0x0000
+#define S5K3E2FX_MODEL_ID       0x3E2F
+
+/* PLL Registers */
+#define REG_PRE_PLL_CLK_DIV           0x0305
+#define REG_PLL_MULTIPLIER_MSB        0x0306
+#define REG_PLL_MULTIPLIER_LSB        0x0307
+#define REG_VT_PIX_CLK_DIV            0x0301
+#define REG_VT_SYS_CLK_DIV            0x0303
+#define REG_OP_PIX_CLK_DIV            0x0309
+#define REG_OP_SYS_CLK_DIV            0x030B
+
+/* Data Format Registers */
+#define REG_CCP_DATA_FORMAT_MSB       0x0112
+#define REG_CCP_DATA_FORMAT_LSB       0x0113
+
+/* Output Size */
+#define REG_X_OUTPUT_SIZE_MSB         0x034C
+#define REG_X_OUTPUT_SIZE_LSB         0x034D
+#define REG_Y_OUTPUT_SIZE_MSB         0x034E
+#define REG_Y_OUTPUT_SIZE_LSB         0x034F
+
+/* Binning */
+#define REG_X_EVEN_INC                0x0381
+#define REG_X_ODD_INC                 0x0383
+#define REG_Y_EVEN_INC                0x0385
+#define REG_Y_ODD_INC                 0x0387
+/*Reserved register */
+#define REG_BINNING_ENABLE            0x3014
+
+/* Frame Fotmat */
+#define REG_FRAME_LENGTH_LINES_MSB    0x0340
+#define REG_FRAME_LENGTH_LINES_LSB    0x0341
+#define REG_LINE_LENGTH_PCK_MSB       0x0342
+#define REG_LINE_LENGTH_PCK_LSB       0x0343
+
+/* MSR setting */
+/* Reserved registers */
+#define REG_SHADE_CLK_ENABLE          0x30AC
+#define REG_SEL_CCP                   0x30C4
+#define REG_VPIX                      0x3024
+#define REG_CLAMP_ON                  0x3015
+#define REG_OFFSET                    0x307E
+
+/* CDS timing settings */
+/* Reserved registers */
+#define REG_LD_START                  0x3000
+#define REG_LD_END                    0x3001
+#define REG_SL_START                  0x3002
+#define REG_SL_END                    0x3003
+#define REG_RX_START                  0x3004
+#define REG_S1_START                  0x3005
+#define REG_S1_END                    0x3006
+#define REG_S1S_START                 0x3007
+#define REG_S1S_END                   0x3008
+#define REG_S3_START                  0x3009
+#define REG_S3_END                    0x300A
+#define REG_CMP_EN_START              0x300B
+#define REG_CLP_SL_START              0x300C
+#define REG_CLP_SL_END                0x300D
+#define REG_OFF_START                 0x300E
+#define REG_RMP_EN_START              0x300F
+#define REG_TX_START                  0x3010
+#define REG_TX_END                    0x3011
+#define REG_STX_WIDTH                 0x3012
+#define REG_TYPE1_AF_ENABLE           0x3130
+#define DRIVER_ENABLED                0x0001
+#define AUTO_START_ENABLED            0x0010
+#define REG_NEW_POSITION              0x3131
+#define REG_3152_RESERVED             0x3152
+#define REG_315A_RESERVED             0x315A
+#define REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB 0x0204
+#define REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB 0x0205
+#define REG_FINE_INTEGRATION_TIME         0x0200
+#define REG_COARSE_INTEGRATION_TIME       0x0202
+#define REG_COARSE_INTEGRATION_TIME_LSB   0x0203
+
+/* Mode select register */
+#define S5K3E2FX_REG_MODE_SELECT      0x0100
+#define S5K3E2FX_MODE_SELECT_STREAM     0x01   /* start streaming */
+#define S5K3E2FX_MODE_SELECT_SW_STANDBY 0x00   /* software standby */
+#define S5K3E2FX_REG_SOFTWARE_RESET   0x0103
+#define S5K3E2FX_SOFTWARE_RESET         0x01
+#define REG_TEST_PATTERN_MODE         0x0601
+
+struct reg_struct {
+  uint8_t pre_pll_clk_div;               /* 0x0305 */
+  uint8_t pll_multiplier_msb;            /* 0x0306 */
+  uint8_t pll_multiplier_lsb;            /* 0x0307 */
+  uint8_t vt_pix_clk_div;                /* 0x0301 */
+  uint8_t vt_sys_clk_div;                /* 0x0303 */
+  uint8_t op_pix_clk_div;                /* 0x0309 */
+  uint8_t op_sys_clk_div;                /* 0x030B */
+  uint8_t ccp_data_format_msb;           /* 0x0112 */
+  uint8_t ccp_data_format_lsb;           /* 0x0113 */
+  uint8_t x_output_size_msb;             /* 0x034C */
+  uint8_t x_output_size_lsb;             /* 0x034D */
+  uint8_t y_output_size_msb;             /* 0x034E */
+  uint8_t y_output_size_lsb;             /* 0x034F */
+  uint8_t x_even_inc;                    /* 0x0381 */
+  uint8_t x_odd_inc;                     /* 0x0383 */
+  uint8_t y_even_inc;                    /* 0x0385 */
+  uint8_t y_odd_inc;                     /* 0x0387 */
+  uint8_t binning_enable;                /* 0x3014 */
+  uint8_t frame_length_lines_msb;        /* 0x0340 */
+  uint8_t frame_length_lines_lsb;        /* 0x0341 */
+  uint8_t line_length_pck_msb;           /* 0x0342 */
+  uint8_t line_length_pck_lsb;           /* 0x0343 */
+  uint8_t shade_clk_enable ;             /* 0x30AC */
+  uint8_t sel_ccp;                       /* 0x30C4 */
+  uint8_t vpix;                          /* 0x3024 */
+  uint8_t clamp_on;                      /* 0x3015 */
+  uint8_t offset;                        /* 0x307E */
+  uint8_t ld_start;                      /* 0x3000 */
+  uint8_t ld_end;                        /* 0x3001 */
+  uint8_t sl_start;                      /* 0x3002 */
+  uint8_t sl_end;                        /* 0x3003 */
+  uint8_t rx_start;                      /* 0x3004 */
+  uint8_t s1_start;                      /* 0x3005 */
+  uint8_t s1_end;                        /* 0x3006 */
+  uint8_t s1s_start;                     /* 0x3007 */
+  uint8_t s1s_end;                       /* 0x3008 */
+  uint8_t s3_start;                      /* 0x3009 */
+  uint8_t s3_end;                        /* 0x300A */
+  uint8_t cmp_en_start;                  /* 0x300B */
+  uint8_t clp_sl_start;                  /* 0x300C */
+  uint8_t clp_sl_end;                    /* 0x300D */
+  uint8_t off_start;                     /* 0x300E */
+  uint8_t rmp_en_start;                  /* 0x300F */
+  uint8_t tx_start;                      /* 0x3010 */
+  uint8_t tx_end;                        /* 0x3011 */
+  uint8_t stx_width;                     /* 0x3012 */
+  uint8_t reg_3152_reserved;             /* 0x3152 */
+  uint8_t reg_315A_reserved;             /* 0x315A */
+  uint8_t analogue_gain_code_global_msb; /* 0x0204 */
+  uint8_t analogue_gain_code_global_lsb; /* 0x0205 */
+  uint8_t fine_integration_time;         /* 0x0200 */
+  uint8_t coarse_integration_time;       /* 0x0202 */
+  uint32_t  size_h;
+  uint32_t  blk_l;
+  uint32_t  size_w;
+  uint32_t  blk_p;
+};
+
+struct reg_struct s5k3e2fx_reg_pat[2] =  {
+  {	/* Preview */
+    0x06,  /* pre_pll_clk_div       REG=0x0305 */
+    0x00,  /* pll_multiplier_msb    REG=0x0306 */
+    0x88,  /* pll_multiplier_lsb    REG=0x0307 */
+    0x0a,  /* vt_pix_clk_div        REG=0x0301 */
+    0x01,  /* vt_sys_clk_div        REG=0x0303 */
+    0x0a,  /* op_pix_clk_div        REG=0x0309 */
+    0x01,  /* op_sys_clk_div        REG=0x030B */
+    0x0a,  /* ccp_data_format_msb   REG=0x0112 */
+    0x0a,  /* ccp_data_format_lsb   REG=0x0113 */
+    0x05,  /* x_output_size_msb     REG=0x034C */
+    0x10,  /* x_output_size_lsb     REG=0x034D */
+    0x03,  /* y_output_size_msb     REG=0x034E */
+    0xcc,  /* y_output_size_lsb     REG=0x034F */
+
+    /* enable binning for preview */
+    0x01,  /* x_even_inc             REG=0x0381 */
+    0x01,  /* x_odd_inc              REG=0x0383 */
+    0x01,  /* y_even_inc             REG=0x0385 */
+    0x03,  /* y_odd_inc              REG=0x0387 */
+    0x06,  /* binning_enable         REG=0x3014 */
+
+    0x03,  /* frame_length_lines_msb        REG=0x0340 */
+    0xde,  /* frame_length_lines_lsb        REG=0x0341 */
+    0x0a,  /* line_length_pck_msb           REG=0x0342 */
+    0xac,  /* line_length_pck_lsb           REG=0x0343 */
+    0x81,  /* shade_clk_enable              REG=0x30AC */
+    0x01,  /* sel_ccp                       REG=0x30C4 */
+    0x04,  /* vpix                          REG=0x3024 */
+    0x00,  /* clamp_on                      REG=0x3015 */
+    0x02,  /* offset                        REG=0x307E */
+    0x03,  /* ld_start                      REG=0x3000 */
+    0x9c,  /* ld_end                        REG=0x3001 */
+    0x02,  /* sl_start                      REG=0x3002 */
+    0x9e,  /* sl_end                        REG=0x3003 */
+    0x05,  /* rx_start                      REG=0x3004 */
+    0x0f,  /* s1_start                      REG=0x3005 */
+    0x24,  /* s1_end                        REG=0x3006 */
+    0x7c,  /* s1s_start                     REG=0x3007 */
+    0x9a,  /* s1s_end                       REG=0x3008 */
+    0x10,  /* s3_start                      REG=0x3009 */
+    0x14,  /* s3_end                        REG=0x300A */
+    0x10,  /* cmp_en_start                  REG=0x300B */
+    0x04,  /* clp_sl_start                  REG=0x300C */
+    0x26,  /* clp_sl_end                    REG=0x300D */
+    0x02,  /* off_start                     REG=0x300E */
+    0x0e,  /* rmp_en_start                  REG=0x300F */
+    0x30,  /* tx_start                      REG=0x3010 */
+    0x4e,  /* tx_end                        REG=0x3011 */
+    0x1E,  /* stx_width                     REG=0x3012 */
+    0x08,  /* reg_3152_reserved             REG=0x3152 */
+    0x10,  /* reg_315A_reserved             REG=0x315A */
+    0x00,  /* analogue_gain_code_global_msb REG=0x0204 */
+    0x80,  /* analogue_gain_code_global_lsb REG=0x0205 */
+    0x02,  /* fine_integration_time         REG=0x0200 */
+    0x03,  /* coarse_integration_time       REG=0x0202 */
+		972,
+		18,
+		1296,
+		1436
+  },
+  { /* Snapshot */
+    0x06,  /* pre_pll_clk_div               REG=0x0305 */
+    0x00,  /* pll_multiplier_msb            REG=0x0306 */
+    0x88,  /* pll_multiplier_lsb            REG=0x0307 */
+    0x0a,  /* vt_pix_clk_div                REG=0x0301 */
+    0x01,  /* vt_sys_clk_div                REG=0x0303 */
+    0x0a,  /* op_pix_clk_div                REG=0x0309 */
+    0x01,  /* op_sys_clk_div                REG=0x030B */
+    0x0a,  /* ccp_data_format_msb           REG=0x0112 */
+    0x0a,  /* ccp_data_format_lsb           REG=0x0113 */
+    0x0a,  /* x_output_size_msb             REG=0x034C */
+    0x30,  /* x_output_size_lsb             REG=0x034D */
+    0x07,  /* y_output_size_msb             REG=0x034E */
+    0xa8,  /* y_output_size_lsb             REG=0x034F */
+
+    /* disable binning for snapshot */
+    0x01,  /* x_even_inc                    REG=0x0381 */
+    0x01,  /* x_odd_inc                     REG=0x0383 */
+    0x01,  /* y_even_inc                    REG=0x0385 */
+    0x01,  /* y_odd_inc                     REG=0x0387 */
+    0x00,  /* binning_enable                REG=0x3014 */
+
+    0x07,  /* frame_length_lines_msb        REG=0x0340 */
+    0xb6,  /* frame_length_lines_lsb        REG=0x0341 */
+    0x0a,  /* line_length_pck_msb           REG=0x0342 */
+    0xac,  /* line_length_pck_lsb           REG=0x0343 */
+    0x81,  /* shade_clk_enable              REG=0x30AC */
+    0x01,  /* sel_ccp                       REG=0x30C4 */
+    0x04,  /* vpix                          REG=0x3024 */
+    0x00,  /* clamp_on                      REG=0x3015 */
+    0x02,  /* offset                        REG=0x307E */
+    0x03,  /* ld_start                      REG=0x3000 */
+    0x9c,  /* ld_end                        REG=0x3001 */
+    0x02,  /* sl_start                      REG=0x3002 */
+    0x9e,  /* sl_end                        REG=0x3003 */
+    0x05,  /* rx_start                      REG=0x3004 */
+    0x0f,  /* s1_start                      REG=0x3005 */
+    0x24,  /* s1_end                        REG=0x3006 */
+    0x7c,  /* s1s_start                     REG=0x3007 */
+    0x9a,  /* s1s_end                       REG=0x3008 */
+    0x10,  /* s3_start                      REG=0x3009 */
+    0x14,  /* s3_end                        REG=0x300A */
+    0x10,  /* cmp_en_start                  REG=0x300B */
+    0x04,  /* clp_sl_start                  REG=0x300C */
+    0x26,  /* clp_sl_end                    REG=0x300D */
+    0x02,  /* off_start                     REG=0x300E */
+    0x0e,  /* rmp_en_start                  REG=0x300F */
+    0x30,  /* tx_start                      REG=0x3010 */
+    0x4e,  /* tx_end                        REG=0x3011 */
+    0x1E,  /* stx_width                     REG=0x3012 */
+    0x08,  /* reg_3152_reserved             REG=0x3152 */
+    0x10,  /* reg_315A_reserved             REG=0x315A */
+    0x00,  /* analogue_gain_code_global_msb REG=0x0204 */
+    0x80,  /* analogue_gain_code_global_lsb REG=0x0205 */
+    0x02,  /* fine_integration_time         REG=0x0200 */
+    0x03,  /* coarse_integration_time       REG=0x0202 */
+		1960,
+		14,
+		2608,
+		124
+	}
+};
+
+struct s5k3e2fx_work {
+	struct work_struct work;
+};
+static struct s5k3e2fx_work *s5k3e2fx_sensorw;
+static struct i2c_client *s5k3e2fx_client;
+
+struct s5k3e2fx_ctrl {
+	const struct msm_camera_sensor_info *sensordata;
+
+	int sensormode;
+	uint32_t fps_divider; /* init to 1 * 0x00000400 */
+	uint32_t pict_fps_divider; /* init to 1 * 0x00000400 */
+
+	uint16_t curr_lens_pos;
+	uint16_t init_curr_lens_pos;
+	uint16_t my_reg_gain;
+	uint32_t my_reg_line_count;
+
+	enum msm_s_resolution prev_res;
+	enum msm_s_resolution pict_res;
+	enum msm_s_resolution curr_res;
+	enum msm_s_test_mode  set_test;
+};
+
+struct s5k3e2fx_i2c_reg_conf {
+	unsigned short waddr;
+	unsigned char  bdata;
+};
+
+static struct s5k3e2fx_ctrl *s5k3e2fx_ctrl;
+static DECLARE_WAIT_QUEUE_HEAD(s5k3e2fx_wait_queue);
+DEFINE_MUTEX(s5k3e2fx_mutex);
+
+static int s5k3e2fx_i2c_rxdata(unsigned short saddr, unsigned char *rxdata,
+	int length)
+{
+	struct i2c_msg msgs[] = {
+		{
+			.addr   = saddr,
+			.flags = 0,
+			.len   = 2,
+			.buf   = rxdata,
+		},
+		{
+			.addr   = saddr,
+			.flags = I2C_M_RD,
+			.len   = length,
+			.buf   = rxdata,
+		},
+	};
+
+	if (i2c_transfer(s5k3e2fx_client->adapter, msgs, 2) < 0) {
+		CDBG("s5k3e2fx_i2c_rxdata failed!\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t s5k3e2fx_i2c_txdata(unsigned short saddr,
+	unsigned char *txdata, int length)
+{
+	struct i2c_msg msg[] = {
+		{
+		.addr  = saddr,
+		.flags = 0,
+		.len = length,
+		.buf = txdata,
+		},
+	};
+
+	if (i2c_transfer(s5k3e2fx_client->adapter, msg, 1) < 0) {
+		CDBG("s5k3e2fx_i2c_txdata failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t s5k3e2fx_i2c_write_b(unsigned short saddr, unsigned short waddr,
+	unsigned char bdata)
+{
+	int32_t rc = -EIO;
+	unsigned char buf[4];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00)>>8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = bdata;
+
+	rc = s5k3e2fx_i2c_txdata(saddr, buf, 3);
+
+	if (rc < 0)
+		CDBG("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n",
+			waddr, bdata);
+
+	return rc;
+}
+
+static int32_t s5k3e2fx_i2c_write_table(
+	struct s5k3e2fx_i2c_reg_conf *reg_cfg_tbl, int num)
+{
+	int i;
+	int32_t rc = -EIO;
+	for (i = 0; i < num; i++) {
+		rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+			reg_cfg_tbl->waddr, reg_cfg_tbl->bdata);
+		if (rc < 0)
+			break;
+		reg_cfg_tbl++;
+	}
+
+	return rc;
+}
+
+static int32_t s5k3e2fx_i2c_read_w(unsigned short saddr, unsigned short raddr,
+	unsigned short *rdata)
+{
+	int32_t rc = 0;
+	unsigned char buf[4];
+
+	if (!rdata)
+		return -EIO;
+
+	memset(buf, 0, sizeof(buf));
+
+	buf[0] = (raddr & 0xFF00)>>8;
+	buf[1] = (raddr & 0x00FF);
+
+	rc = s5k3e2fx_i2c_rxdata(saddr, buf, 2);
+	if (rc < 0)
+		return rc;
+
+	*rdata = buf[0] << 8 | buf[1];
+
+	if (rc < 0)
+		CDBG("s5k3e2fx_i2c_read failed!\n");
+
+	return rc;
+}
+
+static int s5k3e2fx_probe_init_done(const struct msm_camera_sensor_info *data)
+{
+	gpio_direction_output(data->sensor_reset, 0);
+	gpio_free(data->sensor_reset);
+	return 0;
+}
+
+static int s5k3e2fx_probe_init_sensor(const struct msm_camera_sensor_info *data)
+{
+	int32_t  rc;
+	uint16_t chipid = 0;
+
+	rc = gpio_request(data->sensor_reset, "s5k3e2fx");
+	if (!rc)
+		gpio_direction_output(data->sensor_reset, 1);
+	else
+		goto init_probe_done;
+
+	mdelay(20);
+
+	CDBG("s5k3e2fx_sensor_init(): reseting sensor.\n");
+
+	rc = s5k3e2fx_i2c_read_w(s5k3e2fx_client->addr,
+		S5K3E2FX_REG_MODEL_ID, &chipid);
+	if (rc < 0)
+		goto init_probe_fail;
+
+	if (chipid != S5K3E2FX_MODEL_ID) {
+		CDBG("S5K3E2FX wrong model_id = 0x%x\n", chipid);
+		rc = -ENODEV;
+		goto init_probe_fail;
+	}
+
+	goto init_probe_done;
+
+init_probe_fail:
+	s5k3e2fx_probe_init_done(data);
+init_probe_done:
+	return rc;
+}
+
+static int s5k3e2fx_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&s5k3e2fx_wait_queue);
+	return 0;
+}
+
+static const struct i2c_device_id s5k3e2fx_i2c_id[] = {
+	{ "s5k3e2fx", 0},
+	{ }
+};
+
+static int s5k3e2fx_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int rc = 0;
+	CDBG("s5k3e2fx_probe called!\n");
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		CDBG("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	s5k3e2fx_sensorw = kzalloc(sizeof(struct s5k3e2fx_work), GFP_KERNEL);
+	if (!s5k3e2fx_sensorw) {
+		CDBG("kzalloc failed.\n");
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, s5k3e2fx_sensorw);
+	s5k3e2fx_init_client(client);
+	s5k3e2fx_client = client;
+
+	mdelay(50);
+
+	CDBG("s5k3e2fx_probe successed! rc = %d\n", rc);
+	return 0;
+
+probe_failure:
+	CDBG("s5k3e2fx_probe failed! rc = %d\n", rc);
+	return rc;
+}
+
+static struct i2c_driver s5k3e2fx_i2c_driver = {
+	.id_table = s5k3e2fx_i2c_id,
+	.probe  = s5k3e2fx_i2c_probe,
+	.remove = __exit_p(s5k3e2fx_i2c_remove),
+	.driver = {
+		.name = "s5k3e2fx",
+	},
+};
+
+static int32_t s5k3e2fx_test(enum msm_s_test_mode mo)
+{
+	int32_t rc = 0;
+
+	if (mo == S_TEST_OFF)
+		rc = 0;
+	else
+		rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+			REG_TEST_PATTERN_MODE, (uint16_t)mo);
+
+	return rc;
+}
+
+static int32_t s5k3e2fx_setting(enum msm_s_reg_update rupdate,
+	enum msm_s_setting rt)
+{
+	int32_t rc = 0;
+  uint16_t num_lperf;
+
+	switch (rupdate) {
+	case S_UPDATE_PERIODIC:
+	if (rt == S_RES_PREVIEW || rt == S_RES_CAPTURE) {
+
+		struct s5k3e2fx_i2c_reg_conf tbl_1[] = {
+			{REG_CCP_DATA_FORMAT_MSB,
+				s5k3e2fx_reg_pat[rt].ccp_data_format_msb},
+			{REG_CCP_DATA_FORMAT_LSB,
+				s5k3e2fx_reg_pat[rt].ccp_data_format_lsb},
+			{REG_X_OUTPUT_SIZE_MSB,
+				s5k3e2fx_reg_pat[rt].x_output_size_msb},
+			{REG_X_OUTPUT_SIZE_LSB,
+				s5k3e2fx_reg_pat[rt].x_output_size_lsb},
+			{REG_Y_OUTPUT_SIZE_MSB,
+				s5k3e2fx_reg_pat[rt].y_output_size_msb},
+			{REG_Y_OUTPUT_SIZE_LSB,
+				s5k3e2fx_reg_pat[rt].y_output_size_lsb},
+			{REG_X_EVEN_INC,
+				s5k3e2fx_reg_pat[rt].x_even_inc},
+			{REG_X_ODD_INC,
+				s5k3e2fx_reg_pat[rt].x_odd_inc},
+			{REG_Y_EVEN_INC,
+				s5k3e2fx_reg_pat[rt].y_even_inc},
+			{REG_Y_ODD_INC,
+				s5k3e2fx_reg_pat[rt].y_odd_inc},
+			{REG_BINNING_ENABLE,
+				s5k3e2fx_reg_pat[rt].binning_enable},
+		};
+
+		struct s5k3e2fx_i2c_reg_conf tbl_2[] = {
+			{REG_FRAME_LENGTH_LINES_MSB, 0},
+			{REG_FRAME_LENGTH_LINES_LSB, 0},
+			{REG_LINE_LENGTH_PCK_MSB,
+				s5k3e2fx_reg_pat[rt].line_length_pck_msb},
+			{REG_LINE_LENGTH_PCK_LSB,
+				s5k3e2fx_reg_pat[rt].line_length_pck_lsb},
+			{REG_SHADE_CLK_ENABLE,
+				s5k3e2fx_reg_pat[rt].shade_clk_enable},
+			{REG_SEL_CCP, s5k3e2fx_reg_pat[rt].sel_ccp},
+			{REG_VPIX, s5k3e2fx_reg_pat[rt].vpix},
+			{REG_CLAMP_ON, s5k3e2fx_reg_pat[rt].clamp_on},
+			{REG_OFFSET, s5k3e2fx_reg_pat[rt].offset},
+			{REG_LD_START, s5k3e2fx_reg_pat[rt].ld_start},
+			{REG_LD_END, s5k3e2fx_reg_pat[rt].ld_end},
+			{REG_SL_START, s5k3e2fx_reg_pat[rt].sl_start},
+			{REG_SL_END, s5k3e2fx_reg_pat[rt].sl_end},
+			{REG_RX_START, s5k3e2fx_reg_pat[rt].rx_start},
+			{REG_S1_START, s5k3e2fx_reg_pat[rt].s1_start},
+			{REG_S1_END, s5k3e2fx_reg_pat[rt].s1_end},
+			{REG_S1S_START, s5k3e2fx_reg_pat[rt].s1s_start},
+			{REG_S1S_END, s5k3e2fx_reg_pat[rt].s1s_end},
+			{REG_S3_START, s5k3e2fx_reg_pat[rt].s3_start},
+			{REG_S3_END, s5k3e2fx_reg_pat[rt].s3_end},
+			{REG_CMP_EN_START, s5k3e2fx_reg_pat[rt].cmp_en_start},
+			{REG_CLP_SL_START, s5k3e2fx_reg_pat[rt].clp_sl_start},
+			{REG_CLP_SL_END, s5k3e2fx_reg_pat[rt].clp_sl_end},
+			{REG_OFF_START, s5k3e2fx_reg_pat[rt].off_start},
+			{REG_RMP_EN_START, s5k3e2fx_reg_pat[rt].rmp_en_start},
+			{REG_TX_START, s5k3e2fx_reg_pat[rt].tx_start},
+			{REG_TX_END, s5k3e2fx_reg_pat[rt].tx_end},
+			{REG_STX_WIDTH, s5k3e2fx_reg_pat[rt].stx_width},
+			{REG_3152_RESERVED,
+				s5k3e2fx_reg_pat[rt].reg_3152_reserved},
+			{REG_315A_RESERVED,
+				s5k3e2fx_reg_pat[rt].reg_315A_reserved},
+			{REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB,
+				s5k3e2fx_reg_pat[rt].
+				analogue_gain_code_global_msb},
+			{REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB,
+				s5k3e2fx_reg_pat[rt].
+				analogue_gain_code_global_lsb},
+			{REG_FINE_INTEGRATION_TIME,
+				s5k3e2fx_reg_pat[rt].fine_integration_time},
+			{REG_COARSE_INTEGRATION_TIME,
+				s5k3e2fx_reg_pat[rt].coarse_integration_time},
+			{S5K3E2FX_REG_MODE_SELECT, S5K3E2FX_MODE_SELECT_STREAM},
+		};
+
+		rc = s5k3e2fx_i2c_write_table(&tbl_1[0],
+			ARRAY_SIZE(tbl_1));
+		if (rc < 0)
+			return rc;
+
+		num_lperf = (uint16_t)
+			((s5k3e2fx_reg_pat[rt].frame_length_lines_msb << 8)
+			& 0xFF00)
+			+ s5k3e2fx_reg_pat[rt].frame_length_lines_lsb;
+
+		num_lperf = num_lperf * s5k3e2fx_ctrl->fps_divider / 0x0400;
+
+		tbl_2[0] = (struct s5k3e2fx_i2c_reg_conf)
+			{REG_FRAME_LENGTH_LINES_MSB, (num_lperf & 0xFF00) >> 8};
+		tbl_2[1] = (struct s5k3e2fx_i2c_reg_conf)
+			{REG_FRAME_LENGTH_LINES_LSB, (num_lperf & 0x00FF)};
+
+		rc = s5k3e2fx_i2c_write_table(&tbl_2[0],
+			ARRAY_SIZE(tbl_2));
+		if (rc < 0)
+			return rc;
+
+		mdelay(5);
+
+		rc = s5k3e2fx_test(s5k3e2fx_ctrl->set_test);
+		if (rc < 0)
+			return rc;
+	  }
+    break; /* UPDATE_PERIODIC */
+
+	case S_REG_INIT:
+	if (rt == S_RES_PREVIEW || rt == S_RES_CAPTURE) {
+
+		struct s5k3e2fx_i2c_reg_conf tbl_3[] = {
+			{S5K3E2FX_REG_SOFTWARE_RESET, S5K3E2FX_SOFTWARE_RESET},
+			{S5K3E2FX_REG_MODE_SELECT,
+				S5K3E2FX_MODE_SELECT_SW_STANDBY},
+			/* PLL setting */
+			{REG_PRE_PLL_CLK_DIV,
+				s5k3e2fx_reg_pat[rt].pre_pll_clk_div},
+			{REG_PLL_MULTIPLIER_MSB,
+				s5k3e2fx_reg_pat[rt].pll_multiplier_msb},
+			{REG_PLL_MULTIPLIER_LSB,
+				s5k3e2fx_reg_pat[rt].pll_multiplier_lsb},
+			{REG_VT_PIX_CLK_DIV,
+				s5k3e2fx_reg_pat[rt].vt_pix_clk_div},
+			{REG_VT_SYS_CLK_DIV,
+				s5k3e2fx_reg_pat[rt].vt_sys_clk_div},
+			{REG_OP_PIX_CLK_DIV,
+				s5k3e2fx_reg_pat[rt].op_pix_clk_div},
+			{REG_OP_SYS_CLK_DIV,
+				s5k3e2fx_reg_pat[rt].op_sys_clk_div},
+			/*Data Format */
+			{REG_CCP_DATA_FORMAT_MSB,
+				s5k3e2fx_reg_pat[rt].ccp_data_format_msb},
+			{REG_CCP_DATA_FORMAT_LSB,
+				s5k3e2fx_reg_pat[rt].ccp_data_format_lsb},
+			/*Output Size */
+			{REG_X_OUTPUT_SIZE_MSB,
+				s5k3e2fx_reg_pat[rt].x_output_size_msb},
+			{REG_X_OUTPUT_SIZE_LSB,
+				s5k3e2fx_reg_pat[rt].x_output_size_lsb},
+			{REG_Y_OUTPUT_SIZE_MSB,
+				s5k3e2fx_reg_pat[rt].y_output_size_msb},
+			{REG_Y_OUTPUT_SIZE_LSB,
+				s5k3e2fx_reg_pat[rt].y_output_size_lsb},
+			/* Binning */
+			{REG_X_EVEN_INC, s5k3e2fx_reg_pat[rt].x_even_inc},
+			{REG_X_ODD_INC, s5k3e2fx_reg_pat[rt].x_odd_inc },
+			{REG_Y_EVEN_INC, s5k3e2fx_reg_pat[rt].y_even_inc},
+			{REG_Y_ODD_INC, s5k3e2fx_reg_pat[rt].y_odd_inc},
+			{REG_BINNING_ENABLE,
+				s5k3e2fx_reg_pat[rt].binning_enable},
+			/* Frame format */
+			{REG_FRAME_LENGTH_LINES_MSB,
+				s5k3e2fx_reg_pat[rt].frame_length_lines_msb},
+			{REG_FRAME_LENGTH_LINES_LSB,
+				s5k3e2fx_reg_pat[rt].frame_length_lines_lsb},
+			{REG_LINE_LENGTH_PCK_MSB,
+				s5k3e2fx_reg_pat[rt].line_length_pck_msb},
+			{REG_LINE_LENGTH_PCK_LSB,
+				s5k3e2fx_reg_pat[rt].line_length_pck_lsb},
+			/* MSR setting */
+			{REG_SHADE_CLK_ENABLE,
+				s5k3e2fx_reg_pat[rt].shade_clk_enable},
+			{REG_SEL_CCP, s5k3e2fx_reg_pat[rt].sel_ccp},
+			{REG_VPIX, s5k3e2fx_reg_pat[rt].vpix},
+			{REG_CLAMP_ON, s5k3e2fx_reg_pat[rt].clamp_on},
+			{REG_OFFSET, s5k3e2fx_reg_pat[rt].offset},
+			/* CDS timing setting */
+			{REG_LD_START, s5k3e2fx_reg_pat[rt].ld_start},
+			{REG_LD_END, s5k3e2fx_reg_pat[rt].ld_end},
+			{REG_SL_START, s5k3e2fx_reg_pat[rt].sl_start},
+			{REG_SL_END, s5k3e2fx_reg_pat[rt].sl_end},
+			{REG_RX_START, s5k3e2fx_reg_pat[rt].rx_start},
+			{REG_S1_START, s5k3e2fx_reg_pat[rt].s1_start},
+			{REG_S1_END, s5k3e2fx_reg_pat[rt].s1_end},
+			{REG_S1S_START, s5k3e2fx_reg_pat[rt].s1s_start},
+			{REG_S1S_END, s5k3e2fx_reg_pat[rt].s1s_end},
+			{REG_S3_START, s5k3e2fx_reg_pat[rt].s3_start},
+			{REG_S3_END, s5k3e2fx_reg_pat[rt].s3_end},
+			{REG_CMP_EN_START, s5k3e2fx_reg_pat[rt].cmp_en_start},
+			{REG_CLP_SL_START, s5k3e2fx_reg_pat[rt].clp_sl_start},
+			{REG_CLP_SL_END, s5k3e2fx_reg_pat[rt].clp_sl_end},
+			{REG_OFF_START, s5k3e2fx_reg_pat[rt].off_start},
+			{REG_RMP_EN_START, s5k3e2fx_reg_pat[rt].rmp_en_start},
+			{REG_TX_START, s5k3e2fx_reg_pat[rt].tx_start},
+			{REG_TX_END, s5k3e2fx_reg_pat[rt].tx_end},
+			{REG_STX_WIDTH, s5k3e2fx_reg_pat[rt].stx_width},
+			{REG_3152_RESERVED,
+				s5k3e2fx_reg_pat[rt].reg_3152_reserved},
+			{REG_315A_RESERVED,
+				s5k3e2fx_reg_pat[rt].reg_315A_reserved},
+			{REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB,
+				s5k3e2fx_reg_pat[rt].
+				analogue_gain_code_global_msb},
+			{REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB,
+				s5k3e2fx_reg_pat[rt].
+				analogue_gain_code_global_lsb},
+			{REG_FINE_INTEGRATION_TIME,
+				s5k3e2fx_reg_pat[rt].fine_integration_time},
+			{REG_COARSE_INTEGRATION_TIME,
+				s5k3e2fx_reg_pat[rt].coarse_integration_time},
+			{S5K3E2FX_REG_MODE_SELECT, S5K3E2FX_MODE_SELECT_STREAM},
+		};
+
+		/* reset fps_divider */
+		s5k3e2fx_ctrl->fps_divider = 1 * 0x0400;
+		rc = s5k3e2fx_i2c_write_table(&tbl_3[0],
+			ARRAY_SIZE(tbl_3));
+		if (rc < 0)
+			return rc;
+		}
+		break; /* case REG_INIT: */
+
+	default:
+		rc = -EINVAL;
+		break;
+	} /* switch (rupdate) */
+
+	return rc;
+}
+
+static int s5k3e2fx_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+	int32_t  rc;
+
+	s5k3e2fx_ctrl = kzalloc(sizeof(struct s5k3e2fx_ctrl), GFP_KERNEL);
+	if (!s5k3e2fx_ctrl) {
+		CDBG("s5k3e2fx_init failed!\n");
+		rc = -ENOMEM;
+		goto init_done;
+	}
+
+	s5k3e2fx_ctrl->fps_divider = 1 * 0x00000400;
+	s5k3e2fx_ctrl->pict_fps_divider = 1 * 0x00000400;
+	s5k3e2fx_ctrl->set_test = S_TEST_OFF;
+	s5k3e2fx_ctrl->prev_res = S_QTR_SIZE;
+	s5k3e2fx_ctrl->pict_res = S_FULL_SIZE;
+
+	if (data)
+		s5k3e2fx_ctrl->sensordata = data;
+
+	/* enable mclk first */
+	msm_camio_clk_rate_set(24000000);
+	mdelay(20);
+
+	msm_camio_camif_pad_reg_reset();
+	mdelay(20);
+
+	rc = s5k3e2fx_probe_init_sensor(data);
+	if (rc < 0)
+		goto init_fail1;
+
+	if (s5k3e2fx_ctrl->prev_res == S_QTR_SIZE)
+		rc = s5k3e2fx_setting(S_REG_INIT, S_RES_PREVIEW);
+	else
+		rc = s5k3e2fx_setting(S_REG_INIT, S_RES_CAPTURE);
+
+	if (rc < 0) {
+		CDBG("s5k3e2fx_setting failed. rc = %d\n", rc);
+		goto init_fail1;
+	}
+
+	/* initialize AF */
+	rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+			0x3146, 0x3A);
+	if (rc < 0)
+		goto init_fail1;
+
+	rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+			0x3130, 0x03);
+	if (rc < 0)
+		goto init_fail1;
+
+	goto init_done;
+
+init_fail1:
+	s5k3e2fx_probe_init_done(data);
+	kfree(s5k3e2fx_ctrl);
+init_done:
+	return rc;
+}
+
+static int32_t s5k3e2fx_power_down(void)
+{
+	int32_t rc = 0;
+	return rc;
+}
+
+static int s5k3e2fx_sensor_release(void)
+{
+	int rc = -EBADF;
+
+	mutex_lock(&s5k3e2fx_mutex);
+
+	s5k3e2fx_power_down();
+
+	gpio_direction_output(s5k3e2fx_ctrl->sensordata->sensor_reset,
+		0);
+	gpio_free(s5k3e2fx_ctrl->sensordata->sensor_reset);
+
+	kfree(s5k3e2fx_ctrl);
+	s5k3e2fx_ctrl = NULL;
+
+	CDBG("s5k3e2fx_release completed\n");
+
+	mutex_unlock(&s5k3e2fx_mutex);
+	return rc;
+}
+
+static void s5k3e2fx_get_pict_fps(uint16_t fps, uint16_t *pfps)
+{
+	/* input fps is preview fps in Q8 format */
+	uint32_t divider;   /* Q10 */
+
+	divider = (uint32_t)
+		((s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h +
+			s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l) *
+		 (s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w +
+			s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_p)) * 0x00000400 /
+		((s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h +
+			s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l) *
+		 (s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w +
+			s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p));
+
+	/* Verify PCLK settings and frame sizes. */
+	*pfps = (uint16_t)(fps * divider / 0x00000400);
+}
+
+static uint16_t s5k3e2fx_get_prev_lines_pf(void)
+{
+	return s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h +
+		s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l;
+}
+
+static uint16_t s5k3e2fx_get_prev_pixels_pl(void)
+{
+	return s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w +
+		s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_p;
+}
+
+static uint16_t s5k3e2fx_get_pict_lines_pf(void)
+{
+	return s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h +
+		s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l;
+}
+
+static uint16_t s5k3e2fx_get_pict_pixels_pl(void)
+{
+	return s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w +
+		s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p;
+}
+
+static uint32_t s5k3e2fx_get_pict_max_exp_lc(void)
+{
+	uint32_t snapshot_lines_per_frame;
+
+	if (s5k3e2fx_ctrl->pict_res == S_QTR_SIZE)
+		snapshot_lines_per_frame =
+		s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h +
+		s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l;
+	else
+		snapshot_lines_per_frame = 3961 * 3;
+
+	return snapshot_lines_per_frame;
+}
+
+static int32_t s5k3e2fx_set_fps(struct fps_cfg *fps)
+{
+	/* input is new fps in Q10 format */
+	int32_t rc = 0;
+	enum msm_s_setting setting;
+
+	s5k3e2fx_ctrl->fps_divider = fps->fps_div;
+
+	if (s5k3e2fx_ctrl->sensormode == SENSOR_PREVIEW_MODE)
+		setting = S_RES_PREVIEW;
+	else
+		setting = S_RES_CAPTURE;
+
+  rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+		REG_FRAME_LENGTH_LINES_MSB,
+		(((s5k3e2fx_reg_pat[setting].size_h +
+			s5k3e2fx_reg_pat[setting].blk_l) *
+			s5k3e2fx_ctrl->fps_divider / 0x400) & 0xFF00) >> 8);
+	if (rc < 0)
+		goto set_fps_done;
+
+  rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+		REG_FRAME_LENGTH_LINES_LSB,
+		(((s5k3e2fx_reg_pat[setting].size_h +
+			s5k3e2fx_reg_pat[setting].blk_l) *
+			s5k3e2fx_ctrl->fps_divider / 0x400) & 0x00FF));
+
+set_fps_done:
+	return rc;
+}
+
+static int32_t s5k3e2fx_write_exp_gain(uint16_t gain, uint32_t line)
+{
+	int32_t rc = 0;
+
+	uint16_t max_legal_gain = 0x0200;
+	uint32_t ll_ratio; /* Q10 */
+	uint32_t ll_pck, fl_lines;
+	uint16_t offset = 4;
+	uint32_t  gain_msb, gain_lsb;
+	uint32_t  intg_t_msb, intg_t_lsb;
+	uint32_t  ll_pck_msb, ll_pck_lsb;
+
+	struct s5k3e2fx_i2c_reg_conf tbl[2];
+
+	CDBG("Line:%d s5k3e2fx_write_exp_gain \n", __LINE__);
+
+	if (s5k3e2fx_ctrl->sensormode == SENSOR_PREVIEW_MODE) {
+
+		s5k3e2fx_ctrl->my_reg_gain = gain;
+		s5k3e2fx_ctrl->my_reg_line_count = (uint16_t)line;
+
+		fl_lines = s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h +
+			s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l;
+
+		ll_pck = s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w +
+			s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_p;
+
+	} else {
+
+		fl_lines = s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h +
+			s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l;
+
+		ll_pck = s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w +
+			s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p;
+	}
+
+	if (gain > max_legal_gain)
+		gain = max_legal_gain;
+
+	/* in Q10 */
+	line = (line * s5k3e2fx_ctrl->fps_divider);
+
+	if (fl_lines < (line / 0x400))
+		ll_ratio = (line / (fl_lines - offset));
+	else
+		ll_ratio = 0x400;
+
+	/* update gain registers */
+	gain_msb = (gain & 0xFF00) >> 8;
+	gain_lsb = gain & 0x00FF;
+	tbl[0].waddr = REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB;
+	tbl[0].bdata = gain_msb;
+	tbl[1].waddr = REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB;
+	tbl[1].bdata = gain_lsb;
+	rc = s5k3e2fx_i2c_write_table(&tbl[0], ARRAY_SIZE(tbl));
+	if (rc < 0)
+		goto write_gain_done;
+
+	ll_pck = ll_pck * ll_ratio;
+	ll_pck_msb = ((ll_pck / 0x400) & 0xFF00) >> 8;
+	ll_pck_lsb = (ll_pck / 0x400) & 0x00FF;
+	tbl[0].waddr = REG_LINE_LENGTH_PCK_MSB;
+	tbl[0].bdata = ll_pck_msb;
+	tbl[1].waddr = REG_LINE_LENGTH_PCK_LSB;
+	tbl[1].bdata = ll_pck_lsb;
+	rc = s5k3e2fx_i2c_write_table(&tbl[0], ARRAY_SIZE(tbl));
+	if (rc < 0)
+		goto write_gain_done;
+
+	line = line / ll_ratio;
+	intg_t_msb = (line & 0xFF00) >> 8;
+	intg_t_lsb = (line & 0x00FF);
+	tbl[0].waddr = REG_COARSE_INTEGRATION_TIME;
+	tbl[0].bdata = intg_t_msb;
+	tbl[1].waddr = REG_COARSE_INTEGRATION_TIME_LSB;
+	tbl[1].bdata = intg_t_lsb;
+	rc = s5k3e2fx_i2c_write_table(&tbl[0], ARRAY_SIZE(tbl));
+
+write_gain_done:
+	return rc;
+}
+
+static int32_t s5k3e2fx_set_pict_exp_gain(uint16_t gain, uint32_t line)
+{
+	int32_t rc = 0;
+
+	CDBG("Line:%d s5k3e2fx_set_pict_exp_gain \n", __LINE__);
+
+	rc =
+		s5k3e2fx_write_exp_gain(gain, line);
+
+	return rc;
+}
+
+static int32_t s5k3e2fx_video_config(int mode, int res)
+{
+	int32_t rc;
+
+	switch (res) {
+	case S_QTR_SIZE:
+		rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_PREVIEW);
+		if (rc < 0)
+			return rc;
+
+		CDBG("s5k3e2fx sensor configuration done!\n");
+		break;
+
+	case S_FULL_SIZE:
+		rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_CAPTURE);
+		if (rc < 0)
+			return rc;
+
+		break;
+
+	default:
+		return 0;
+	} /* switch */
+
+	s5k3e2fx_ctrl->prev_res = res;
+	s5k3e2fx_ctrl->curr_res = res;
+	s5k3e2fx_ctrl->sensormode = mode;
+
+	rc =
+		s5k3e2fx_write_exp_gain(s5k3e2fx_ctrl->my_reg_gain,
+			s5k3e2fx_ctrl->my_reg_line_count);
+
+	return rc;
+}
+
+static int32_t s5k3e2fx_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+
+	rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_CAPTURE);
+	if (rc < 0)
+		return rc;
+
+	s5k3e2fx_ctrl->curr_res = s5k3e2fx_ctrl->pict_res;
+	s5k3e2fx_ctrl->sensormode = mode;
+
+	return rc;
+}
+
+static int32_t s5k3e2fx_raw_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+
+	rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_CAPTURE);
+	if (rc < 0)
+		return rc;
+
+	s5k3e2fx_ctrl->curr_res = s5k3e2fx_ctrl->pict_res;
+	s5k3e2fx_ctrl->sensormode = mode;
+
+	return rc;
+}
+
+static int32_t s5k3e2fx_set_sensor_mode(int mode, int res)
+{
+	int32_t rc = 0;
+
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		rc = s5k3e2fx_video_config(mode, res);
+		break;
+
+	case SENSOR_SNAPSHOT_MODE:
+		rc = s5k3e2fx_snapshot_config(mode);
+		break;
+
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		rc = s5k3e2fx_raw_snapshot_config(mode);
+		break;
+
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+static int32_t s5k3e2fx_set_default_focus(void)
+{
+	int32_t rc = 0;
+
+  rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+		0x3131, 0);
+	if (rc < 0)
+		return rc;
+
+  rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+		0x3132, 0);
+	if (rc < 0)
+		return rc;
+
+	s5k3e2fx_ctrl->curr_lens_pos = 0;
+
+	return rc;
+}
+
+static int32_t s5k3e2fx_move_focus(int direction, int32_t num_steps)
+{
+	int32_t rc = 0;
+	int32_t i;
+	int16_t step_direction;
+	int16_t actual_step;
+	int16_t next_pos, pos_offset;
+	int16_t init_code = 50;
+	uint8_t next_pos_msb, next_pos_lsb;
+	int16_t s_move[5];
+	uint32_t gain; /* Q10 format */
+
+	if (direction == MOVE_NEAR)
+		step_direction = 20;
+	else if (direction == MOVE_FAR)
+		step_direction = -20;
+	else {
+		CDBG("s5k3e2fx_move_focus failed at line %d ...\n", __LINE__);
+		return -EINVAL;
+	}
+
+	actual_step = step_direction * (int16_t)num_steps;
+	pos_offset = init_code + s5k3e2fx_ctrl->curr_lens_pos;
+	gain = actual_step * 0x400 / 5;
+
+	for (i = 0; i <= 4; i++) {
+		if (actual_step >= 0)
+			s_move[i] = (((i+1)*gain+0x200)-(i*gain+0x200))/0x400;
+		else
+			s_move[i] = (((i+1)*gain-0x200)-(i*gain-0x200))/0x400;
+	}
+
+	/* Ring Damping Code */
+	for (i = 0; i <= 4; i++) {
+		next_pos = (int16_t)(pos_offset + s_move[i]);
+
+		if (next_pos > (738 + init_code))
+			next_pos = 738 + init_code;
+		else if (next_pos < 0)
+			next_pos = 0;
+
+		CDBG("next_position in damping mode = %d\n", next_pos);
+		/* Writing the Values to the actuator */
+		if (next_pos == init_code)
+			next_pos = 0x00;
+
+		next_pos_msb = next_pos >> 8;
+		next_pos_lsb = next_pos & 0x00FF;
+
+		rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+			0x3131, next_pos_msb);
+		if (rc < 0)
+			break;
+
+		rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+			0x3132, next_pos_lsb);
+		if (rc < 0)
+			break;
+
+		pos_offset = next_pos;
+		s5k3e2fx_ctrl->curr_lens_pos = pos_offset - init_code;
+		if (i < 4)
+			mdelay(3);
+	}
+
+	return rc;
+}
+
+static int s5k3e2fx_sensor_config(void __user *argp)
+{
+	struct sensor_cfg_data cdata;
+	long   rc = 0;
+
+	if (copy_from_user(&cdata,
+			(void *)argp,
+			sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+
+	mutex_lock(&s5k3e2fx_mutex);
+
+	CDBG("%s: cfgtype = %d\n", __func__, cdata.cfgtype);
+	switch (cdata.cfgtype) {
+	case CFG_GET_PICT_FPS:
+		s5k3e2fx_get_pict_fps(cdata.cfg.gfps.prevfps,
+			&(cdata.cfg.gfps.pictfps));
+
+		if (copy_to_user((void *)argp, &cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PREV_L_PF:
+		cdata.cfg.prevl_pf = s5k3e2fx_get_prev_lines_pf();
+
+		if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PREV_P_PL:
+		cdata.cfg.prevp_pl = s5k3e2fx_get_prev_pixels_pl();
+
+		if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_L_PF:
+		cdata.cfg.pictl_pf = s5k3e2fx_get_pict_lines_pf();
+
+		if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_P_PL:
+		cdata.cfg.pictp_pl = s5k3e2fx_get_pict_pixels_pl();
+
+		if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_MAX_EXP_LC:
+		cdata.cfg.pict_max_exp_lc =
+			s5k3e2fx_get_pict_max_exp_lc();
+
+		if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_SET_FPS:
+	case CFG_SET_PICT_FPS:
+		rc = s5k3e2fx_set_fps(&(cdata.cfg.fps));
+		break;
+
+	case CFG_SET_EXP_GAIN:
+		rc =
+			s5k3e2fx_write_exp_gain(cdata.cfg.exp_gain.gain,
+				cdata.cfg.exp_gain.line);
+		break;
+
+	case CFG_SET_PICT_EXP_GAIN:
+		CDBG("Line:%d CFG_SET_PICT_EXP_GAIN \n", __LINE__);
+		rc =
+			s5k3e2fx_set_pict_exp_gain(
+				cdata.cfg.exp_gain.gain,
+				cdata.cfg.exp_gain.line);
+		break;
+
+	case CFG_SET_MODE:
+		rc =
+			s5k3e2fx_set_sensor_mode(
+			cdata.mode, cdata.rs);
+		break;
+
+	case CFG_PWR_DOWN:
+		rc = s5k3e2fx_power_down();
+		break;
+
+	case CFG_MOVE_FOCUS:
+		rc =
+			s5k3e2fx_move_focus(
+			cdata.cfg.focus.dir,
+			cdata.cfg.focus.steps);
+		break;
+
+	case CFG_SET_DEFAULT_FOCUS:
+		rc =
+			s5k3e2fx_set_default_focus();
+		break;
+
+	case CFG_GET_AF_MAX_STEPS:
+	case CFG_SET_EFFECT:
+	case CFG_SET_LENS_SHADING:
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	mutex_unlock(&s5k3e2fx_mutex);
+	return rc;
+}
+
+static int s5k3e2fx_sensor_probe(const struct msm_camera_sensor_info *info,
+		struct msm_sensor_ctrl *s)
+{
+	int rc = 0;
+
+	rc = i2c_add_driver(&s5k3e2fx_i2c_driver);
+	if (rc < 0 || s5k3e2fx_client == NULL) {
+		rc = -ENOTSUPP;
+		goto probe_fail;
+	}
+
+	msm_camio_clk_rate_set(24000000);
+	mdelay(20);
+
+	rc = s5k3e2fx_probe_init_sensor(info);
+	if (rc < 0)
+		goto probe_fail;
+
+	s->s_init = s5k3e2fx_sensor_open_init;
+	s->s_release = s5k3e2fx_sensor_release;
+	s->s_config  = s5k3e2fx_sensor_config;
+	s->s_mount_angle  = 0;
+	s5k3e2fx_probe_init_done(info);
+
+	return rc;
+
+probe_fail:
+	CDBG("SENSOR PROBE FAILS!\n");
+	return rc;
+}
+
+static int __s5k3e2fx_probe(struct platform_device *pdev)
+{
+	return msm_camera_drv_start(pdev, s5k3e2fx_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = __s5k3e2fx_probe,
+	.driver = {
+		.name = "msm_camera_s5k3e2fx",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init s5k3e2fx_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(s5k3e2fx_init);
+
diff --git a/drivers/media/video/msm/s5k3e2fx.h b/drivers/media/video/msm/s5k3e2fx.h
new file mode 100644
index 0000000..cf3f881
--- /dev/null
+++ b/drivers/media/video/msm/s5k3e2fx.h
@@ -0,0 +1,18 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#ifndef CAMSENSOR_S5K3E2FX
+#define CAMSENSOR_S5K3E2FX
+
+#include <mach/board.h>
+#endif /* CAMSENSOR_S5K3E2FX */
diff --git a/drivers/media/video/msm/s5k4e1.c b/drivers/media/video/msm/s5k4e1.c
new file mode 100644
index 0000000..9cdd44c
--- /dev/null
+++ b/drivers/media/video/msm/s5k4e1.c
@@ -0,0 +1,1086 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/bitops.h>
+#include <mach/camera.h>
+#include <media/msm_camera.h>
+#include "s5k4e1.h"
+
+/* 16bit address - 8 bit context register structure */
+#define Q8	0x00000100
+#define Q10	0x00000400
+
+/* MCLK */
+#define S5K4E1_MASTER_CLK_RATE 24000000
+
+/* AF Total steps parameters */
+#define S5K4E1_TOTAL_STEPS_NEAR_TO_FAR	32
+
+#define S5K4E1_REG_PREV_FRAME_LEN_1	31
+#define S5K4E1_REG_PREV_FRAME_LEN_2	32
+#define S5K4E1_REG_PREV_LINE_LEN_1	33
+#define S5K4E1_REG_PREV_LINE_LEN_2	34
+
+#define S5K4E1_REG_SNAP_FRAME_LEN_1	15
+#define S5K4E1_REG_SNAP_FRAME_LEN_2	16
+#define  S5K4E1_REG_SNAP_LINE_LEN_1	17
+#define S5K4E1_REG_SNAP_LINE_LEN_2	18
+#define MSB                             1
+#define LSB                             0
+
+struct s5k4e1_work_t {
+	struct work_struct work;
+};
+
+static struct s5k4e1_work_t *s5k4e1_sensorw;
+static struct s5k4e1_work_t *s5k4e1_af_sensorw;
+static struct i2c_client *s5k4e1_af_client;
+static struct i2c_client *s5k4e1_client;
+
+struct s5k4e1_ctrl_t {
+	const struct  msm_camera_sensor_info *sensordata;
+
+	uint32_t sensormode;
+	uint32_t fps_divider;/* init to 1 * 0x00000400 */
+	uint32_t pict_fps_divider;/* init to 1 * 0x00000400 */
+	uint16_t fps;
+
+	uint16_t curr_lens_pos;
+	uint16_t curr_step_pos;
+	uint16_t my_reg_gain;
+	uint32_t my_reg_line_count;
+	uint16_t total_lines_per_frame;
+
+	enum s5k4e1_resolution_t prev_res;
+	enum s5k4e1_resolution_t pict_res;
+	enum s5k4e1_resolution_t curr_res;
+	enum s5k4e1_test_mode_t  set_test;
+};
+
+static bool CSI_CONFIG;
+static struct s5k4e1_ctrl_t *s5k4e1_ctrl;
+
+static DECLARE_WAIT_QUEUE_HEAD(s5k4e1_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD(s5k4e1_af_wait_queue);
+DEFINE_MUTEX(s5k4e1_mut);
+
+static uint16_t prev_line_length_pck;
+static uint16_t prev_frame_length_lines;
+static uint16_t snap_line_length_pck;
+static uint16_t snap_frame_length_lines;
+
+static int s5k4e1_i2c_rxdata(unsigned short saddr,
+		unsigned char *rxdata, int length)
+{
+	struct i2c_msg msgs[] = {
+		{
+			.addr  = saddr,
+			.flags = 0,
+			.len   = 1,
+			.buf   = rxdata,
+		},
+		{
+			.addr  = saddr,
+			.flags = I2C_M_RD,
+			.len   = 1,
+			.buf   = rxdata,
+		},
+	};
+	if (i2c_transfer(s5k4e1_client->adapter, msgs, 2) < 0) {
+		CDBG("s5k4e1_i2c_rxdata faild 0x%x\n", saddr);
+		return -EIO;
+	}
+	return 0;
+}
+
+static int32_t s5k4e1_i2c_txdata(unsigned short saddr,
+		unsigned char *txdata, int length)
+{
+	struct i2c_msg msg[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = length,
+			.buf = txdata,
+		},
+	};
+	if (i2c_transfer(s5k4e1_client->adapter, msg, 1) < 0) {
+		CDBG("s5k4e1_i2c_txdata faild 0x%x\n", saddr);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t s5k4e1_i2c_read(unsigned short raddr,
+		unsigned short *rdata, int rlen)
+{
+	int32_t rc = 0;
+	unsigned char buf[2];
+
+	if (!rdata)
+		return -EIO;
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (raddr & 0xFF00) >> 8;
+	buf[1] = (raddr & 0x00FF);
+	rc = s5k4e1_i2c_rxdata(s5k4e1_client->addr, buf, rlen);
+	if (rc < 0) {
+		CDBG("s5k4e1_i2c_read 0x%x failed!\n", raddr);
+		return rc;
+	}
+	*rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]);
+	CDBG("s5k4e1_i2c_read 0x%x val = 0x%x!\n", raddr, *rdata);
+
+	return rc;
+}
+
+static int32_t s5k4e1_i2c_write_b_sensor(unsigned short waddr, uint8_t bdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[3];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = bdata;
+	CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata);
+	rc = s5k4e1_i2c_txdata(s5k4e1_client->addr, buf, 3);
+	if (rc < 0) {
+		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+				waddr, bdata);
+	}
+	return rc;
+}
+
+static int32_t s5k4e1_i2c_write_b_table(struct s5k4e1_i2c_reg_conf const
+		*reg_conf_tbl, int num)
+{
+	int i;
+	int32_t rc = -EIO;
+
+	for (i = 0; i < num; i++) {
+		rc = s5k4e1_i2c_write_b_sensor(reg_conf_tbl->waddr,
+				reg_conf_tbl->wdata);
+		if (rc < 0)
+			break;
+		reg_conf_tbl++;
+	}
+	return rc;
+}
+
+static int32_t s5k4e1_af_i2c_txdata(unsigned short saddr,
+		unsigned char *txdata, int length)
+{
+	struct i2c_msg msg[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = length,
+			.buf = txdata,
+		},
+	};
+	if (i2c_transfer(s5k4e1_af_client->adapter, msg, 1) < 0) {
+		pr_err("s5k4e1_af_i2c_txdata faild 0x%x\n", saddr);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t s5k4e1_af_i2c_write_b_sensor(uint8_t waddr, uint8_t bdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[2];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = waddr;
+	buf[1] = bdata;
+	CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata);
+	rc = s5k4e1_af_i2c_txdata(s5k4e1_af_client->addr << 1, buf, 2);
+	if (rc < 0) {
+		pr_err("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+				waddr, bdata);
+	}
+	return rc;
+}
+
+static void s5k4e1_start_stream(void)
+{
+	s5k4e1_i2c_write_b_sensor(0x0100, 0x01);/* streaming on */
+}
+
+static void s5k4e1_stop_stream(void)
+{
+	s5k4e1_i2c_write_b_sensor(0x0100, 0x00);/* streaming off */
+}
+
+static void s5k4e1_group_hold_on(void)
+{
+	s5k4e1_i2c_write_b_sensor(0x0104, 0x01);
+}
+
+static void s5k4e1_group_hold_off(void)
+{
+	s5k4e1_i2c_write_b_sensor(0x0104, 0x0);
+}
+
+static void s5k4e1_get_pict_fps(uint16_t fps, uint16_t *pfps)
+{
+	/* input fps is preview fps in Q8 format */
+	uint32_t divider, d1, d2;
+
+	d1 = (prev_frame_length_lines * 0x00000400) / snap_frame_length_lines;
+	d2 = (prev_line_length_pck * 0x00000400) / snap_line_length_pck;
+	divider = (d1 * d2) / 0x400;
+
+	/*Verify PCLK settings and frame sizes.*/
+	*pfps = (uint16_t) (fps * divider / 0x400);
+}
+
+static uint16_t s5k4e1_get_prev_lines_pf(void)
+{
+	if (s5k4e1_ctrl->prev_res == QTR_SIZE)
+		return prev_frame_length_lines;
+	else
+		return snap_frame_length_lines;
+}
+
+static uint16_t s5k4e1_get_prev_pixels_pl(void)
+{
+	if (s5k4e1_ctrl->prev_res == QTR_SIZE)
+		return prev_line_length_pck;
+	else
+		return snap_line_length_pck;
+}
+
+static uint16_t s5k4e1_get_pict_lines_pf(void)
+{
+	if (s5k4e1_ctrl->pict_res == QTR_SIZE)
+		return prev_frame_length_lines;
+	else
+		return snap_frame_length_lines;
+}
+
+static uint16_t s5k4e1_get_pict_pixels_pl(void)
+{
+	if (s5k4e1_ctrl->pict_res == QTR_SIZE)
+		return prev_line_length_pck;
+	else
+		return snap_line_length_pck;
+}
+
+static uint32_t s5k4e1_get_pict_max_exp_lc(void)
+{
+	return snap_frame_length_lines * 24;
+}
+
+static int32_t s5k4e1_set_fps(struct fps_cfg   *fps)
+{
+	uint16_t total_lines_per_frame;
+	int32_t rc = 0;
+
+	s5k4e1_ctrl->fps_divider = fps->fps_div;
+	s5k4e1_ctrl->pict_fps_divider = fps->pict_fps_div;
+
+	if (s5k4e1_ctrl->sensormode == SENSOR_PREVIEW_MODE) {
+		total_lines_per_frame = (uint16_t)
+		((prev_frame_length_lines * s5k4e1_ctrl->fps_divider) / 0x400);
+	} else {
+		total_lines_per_frame = (uint16_t)
+		((snap_frame_length_lines * s5k4e1_ctrl->fps_divider) / 0x400);
+	}
+
+	s5k4e1_group_hold_on();
+	rc = s5k4e1_i2c_write_b_sensor(0x0340,
+			((total_lines_per_frame & 0xFF00) >> 8));
+	rc = s5k4e1_i2c_write_b_sensor(0x0341,
+			(total_lines_per_frame & 0x00FF));
+	s5k4e1_group_hold_off();
+
+	return rc;
+}
+
+static inline uint8_t s5k4e1_byte(uint16_t word, uint8_t offset)
+{
+	return word >> (offset * BITS_PER_BYTE);
+}
+
+static int32_t s5k4e1_write_exp_gain(uint16_t gain, uint32_t line)
+{
+	uint16_t max_legal_gain = 0x0200;
+	int32_t rc = 0;
+	static uint32_t fl_lines;
+
+	if (gain > max_legal_gain) {
+		pr_debug("Max legal gain Line:%d\n", __LINE__);
+		gain = max_legal_gain;
+	}
+	/* Analogue Gain */
+	s5k4e1_i2c_write_b_sensor(0x0204, s5k4e1_byte(gain, MSB));
+	s5k4e1_i2c_write_b_sensor(0x0205, s5k4e1_byte(gain, LSB));
+
+	if (line > (prev_frame_length_lines - 4)) {
+		fl_lines = line+4;
+		s5k4e1_group_hold_on();
+		s5k4e1_i2c_write_b_sensor(0x0340, s5k4e1_byte(fl_lines, MSB));
+		s5k4e1_i2c_write_b_sensor(0x0341, s5k4e1_byte(fl_lines, LSB));
+		/* Coarse Integration Time */
+		s5k4e1_i2c_write_b_sensor(0x0202, s5k4e1_byte(line, MSB));
+		s5k4e1_i2c_write_b_sensor(0x0203, s5k4e1_byte(line, LSB));
+		s5k4e1_group_hold_off();
+	} else if (line < (fl_lines - 4)) {
+		fl_lines = line+4;
+		if (fl_lines < prev_frame_length_lines)
+			fl_lines = prev_frame_length_lines;
+
+		s5k4e1_group_hold_on();
+		/* Coarse Integration Time */
+		s5k4e1_i2c_write_b_sensor(0x0202, s5k4e1_byte(line, MSB));
+		s5k4e1_i2c_write_b_sensor(0x0203, s5k4e1_byte(line, LSB));
+		s5k4e1_i2c_write_b_sensor(0x0340, s5k4e1_byte(fl_lines, MSB));
+		s5k4e1_i2c_write_b_sensor(0x0341, s5k4e1_byte(fl_lines, LSB));
+		s5k4e1_group_hold_off();
+	} else {
+		fl_lines = line+4;
+		s5k4e1_group_hold_on();
+		/* Coarse Integration Time */
+		s5k4e1_i2c_write_b_sensor(0x0202, s5k4e1_byte(line, MSB));
+		s5k4e1_i2c_write_b_sensor(0x0203, s5k4e1_byte(line, LSB));
+		s5k4e1_group_hold_off();
+	}
+	return rc;
+}
+
+static int32_t s5k4e1_set_pict_exp_gain(uint16_t gain, uint32_t line)
+{
+	uint16_t max_legal_gain = 0x0200;
+	uint16_t min_ll_pck = 0x0AB2;
+	uint32_t ll_pck, fl_lines;
+	uint32_t ll_ratio;
+	int32_t rc = 0;
+	uint8_t gain_msb, gain_lsb;
+	uint8_t intg_time_msb, intg_time_lsb;
+	uint8_t ll_pck_msb, ll_pck_lsb;
+
+	if (gain > max_legal_gain) {
+		pr_debug("Max legal gain Line:%d\n", __LINE__);
+		gain = max_legal_gain;
+	}
+
+	pr_debug("s5k4e1_write_exp_gain : gain = %d line = %d\n", gain, line);
+	line = (uint32_t) (line * s5k4e1_ctrl->pict_fps_divider);
+	fl_lines = snap_frame_length_lines;
+	ll_pck = snap_line_length_pck;
+
+	if (fl_lines < (line / 0x400))
+		ll_ratio = (line / (fl_lines - 4));
+	else
+		ll_ratio = 0x400;
+
+	ll_pck = ll_pck * ll_ratio / 0x400;
+	line = line / ll_ratio;
+	if (ll_pck < min_ll_pck)
+		ll_pck = min_ll_pck;
+
+	gain_msb = (uint8_t) ((gain & 0xFF00) >> 8);
+	gain_lsb = (uint8_t) (gain & 0x00FF);
+
+	intg_time_msb = (uint8_t) ((line & 0xFF00) >> 8);
+	intg_time_lsb = (uint8_t) (line & 0x00FF);
+
+	ll_pck_msb = (uint8_t) ((ll_pck & 0xFF00) >> 8);
+	ll_pck_lsb = (uint8_t) (ll_pck & 0x00FF);
+
+	s5k4e1_group_hold_on();
+	s5k4e1_i2c_write_b_sensor(0x0204, gain_msb); /* Analogue Gain */
+	s5k4e1_i2c_write_b_sensor(0x0205, gain_lsb);
+
+	s5k4e1_i2c_write_b_sensor(0x0342, ll_pck_msb);
+	s5k4e1_i2c_write_b_sensor(0x0343, ll_pck_lsb);
+
+	/* Coarse Integration Time */
+	s5k4e1_i2c_write_b_sensor(0x0202, intg_time_msb);
+	s5k4e1_i2c_write_b_sensor(0x0203, intg_time_lsb);
+	s5k4e1_group_hold_off();
+
+	return rc;
+}
+
+static int32_t s5k4e1_move_focus(int direction,
+		int32_t num_steps)
+{
+	int16_t step_direction, actual_step, next_position;
+	uint8_t code_val_msb, code_val_lsb;
+
+	if (direction == MOVE_NEAR)
+		step_direction = 16;
+	else
+		step_direction = -16;
+
+	actual_step = (int16_t) (step_direction * num_steps);
+	next_position = (int16_t) (s5k4e1_ctrl->curr_lens_pos + actual_step);
+
+	if (next_position > 1023)
+		next_position = 1023;
+	else if (next_position < 0)
+		next_position = 0;
+
+	code_val_msb = next_position >> 4;
+	code_val_lsb = (next_position & 0x000F) << 4;
+
+	if (s5k4e1_af_i2c_write_b_sensor(code_val_msb, code_val_lsb) < 0) {
+		pr_err("move_focus failed at line %d ...\n", __LINE__);
+		return -EBUSY;
+	}
+
+	s5k4e1_ctrl->curr_lens_pos = next_position;
+	return 0;
+}
+
+static int32_t s5k4e1_set_default_focus(uint8_t af_step)
+{
+	int32_t rc = 0;
+
+	if (s5k4e1_ctrl->curr_step_pos != 0) {
+		rc = s5k4e1_move_focus(MOVE_FAR,
+				s5k4e1_ctrl->curr_step_pos);
+	} else {
+		s5k4e1_af_i2c_write_b_sensor(0x00, 0x00);
+	}
+
+	s5k4e1_ctrl->curr_lens_pos = 0;
+	s5k4e1_ctrl->curr_step_pos = 0;
+
+	return rc;
+}
+
+static int32_t s5k4e1_test(enum s5k4e1_test_mode_t mo)
+{
+	int32_t rc = 0;
+
+	if (mo != TEST_OFF)
+		rc = s5k4e1_i2c_write_b_sensor(0x0601, (uint8_t) mo);
+
+	return rc;
+}
+
+static void s5k4e1_reset_sensor(void)
+{
+	s5k4e1_i2c_write_b_sensor(0x103, 0x1);
+}
+
+static int32_t s5k4e1_sensor_setting(int update_type, int rt)
+{
+
+	int32_t rc = 0;
+	struct msm_camera_csi_params s5k4e1_csi_params;
+
+	s5k4e1_stop_stream();
+	msleep(30);
+
+	if (update_type == REG_INIT) {
+		s5k4e1_reset_sensor();
+		s5k4e1_i2c_write_b_table(s5k4e1_regs.reg_mipi,
+				s5k4e1_regs.reg_mipi_size);
+		s5k4e1_i2c_write_b_table(s5k4e1_regs.rec_settings,
+				s5k4e1_regs.rec_size);
+		s5k4e1_i2c_write_b_table(s5k4e1_regs.reg_pll_p,
+				s5k4e1_regs.reg_pll_p_size);
+		CSI_CONFIG = 0;
+	} else if (update_type == UPDATE_PERIODIC) {
+		if (rt == RES_PREVIEW)
+			s5k4e1_i2c_write_b_table(s5k4e1_regs.reg_prev,
+					s5k4e1_regs.reg_prev_size);
+		else
+			s5k4e1_i2c_write_b_table(s5k4e1_regs.reg_snap,
+					s5k4e1_regs.reg_snap_size);
+		msleep(20);
+		if (!CSI_CONFIG) {
+			msm_camio_vfe_clk_rate_set(192000000);
+			s5k4e1_csi_params.data_format = CSI_10BIT;
+			s5k4e1_csi_params.lane_cnt = 1;
+			s5k4e1_csi_params.lane_assign = 0xe4;
+			s5k4e1_csi_params.dpcm_scheme = 0;
+			s5k4e1_csi_params.settle_cnt = 24;
+			rc = msm_camio_csi_config(&s5k4e1_csi_params);
+			msleep(20);
+			CSI_CONFIG = 1;
+		}
+		s5k4e1_start_stream();
+		msleep(30);
+	}
+	return rc;
+}
+
+static int32_t s5k4e1_video_config(int mode)
+{
+
+	int32_t rc = 0;
+	int rt;
+	CDBG("video config\n");
+	/* change sensor resolution if needed */
+	if (s5k4e1_ctrl->prev_res == QTR_SIZE)
+		rt = RES_PREVIEW;
+	else
+		rt = RES_CAPTURE;
+	if (s5k4e1_sensor_setting(UPDATE_PERIODIC, rt) < 0)
+		return rc;
+	if (s5k4e1_ctrl->set_test) {
+		if (s5k4e1_test(s5k4e1_ctrl->set_test) < 0)
+			return  rc;
+	}
+
+	s5k4e1_ctrl->curr_res = s5k4e1_ctrl->prev_res;
+	s5k4e1_ctrl->sensormode = mode;
+	return rc;
+}
+
+static int32_t s5k4e1_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+	int rt;
+
+	/*change sensor resolution if needed */
+	if (s5k4e1_ctrl->curr_res != s5k4e1_ctrl->pict_res) {
+		if (s5k4e1_ctrl->pict_res == QTR_SIZE)
+			rt = RES_PREVIEW;
+		else
+			rt = RES_CAPTURE;
+		if (s5k4e1_sensor_setting(UPDATE_PERIODIC, rt) < 0)
+			return rc;
+	}
+
+	s5k4e1_ctrl->curr_res = s5k4e1_ctrl->pict_res;
+	s5k4e1_ctrl->sensormode = mode;
+	return rc;
+}
+
+static int32_t s5k4e1_raw_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+	int rt;
+
+	/* change sensor resolution if needed */
+	if (s5k4e1_ctrl->curr_res != s5k4e1_ctrl->pict_res) {
+		if (s5k4e1_ctrl->pict_res == QTR_SIZE)
+			rt = RES_PREVIEW;
+		else
+			rt = RES_CAPTURE;
+		if (s5k4e1_sensor_setting(UPDATE_PERIODIC, rt) < 0)
+			return rc;
+	}
+
+	s5k4e1_ctrl->curr_res = s5k4e1_ctrl->pict_res;
+	s5k4e1_ctrl->sensormode = mode;
+	return rc;
+}
+
+static int32_t s5k4e1_set_sensor_mode(int mode,
+		int res)
+{
+	int32_t rc = 0;
+
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		rc = s5k4e1_video_config(mode);
+		break;
+	case SENSOR_SNAPSHOT_MODE:
+		rc = s5k4e1_snapshot_config(mode);
+		break;
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		rc = s5k4e1_raw_snapshot_config(mode);
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+static int32_t s5k4e1_power_down(void)
+{
+	s5k4e1_stop_stream();
+	return 0;
+}
+
+static int s5k4e1_probe_init_done(const struct msm_camera_sensor_info *data)
+{
+	CDBG("probe done\n");
+	gpio_free(data->sensor_reset);
+	return 0;
+}
+
+static int s5k4e1_probe_init_sensor(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc = 0;
+	uint16_t regaddress1 = 0x0000;
+	uint16_t regaddress2 = 0x0001;
+	uint16_t chipid1 = 0;
+	uint16_t chipid2 = 0;
+
+	CDBG("%s: %d\n", __func__, __LINE__);
+	CDBG(" s5k4e1_probe_init_sensor is called\n");
+
+	rc = gpio_request(data->sensor_reset, "s5k4e1");
+	CDBG(" s5k4e1_probe_init_sensor\n");
+	if (!rc) {
+		CDBG("sensor_reset = %d\n", rc);
+		gpio_direction_output(data->sensor_reset, 0);
+		msleep(50);
+		gpio_set_value_cansleep(data->sensor_reset, 1);
+		msleep(20);
+	} else {
+		goto init_probe_done;
+	}
+	msleep(20);
+
+	s5k4e1_i2c_read(regaddress1, &chipid1, 1);
+	if (chipid1 != 0x4E) {
+		rc = -ENODEV;
+		CDBG("s5k4e1_probe_init_sensor fail chip id doesnot match\n");
+		goto init_probe_fail;
+	}
+
+	s5k4e1_i2c_read(regaddress2, &chipid2 , 1);
+	if (chipid2 != 0x10) {
+		rc = -ENODEV;
+		CDBG("s5k4e1_probe_init_sensor fail chip id doesnot match\n");
+		goto init_probe_fail;
+	}
+
+	CDBG("ID: %d\n", chipid1);
+	CDBG("ID: %d\n", chipid1);
+
+
+	goto init_probe_done;
+init_probe_fail:
+	CDBG(" s5k4e1_probe_init_sensor fails\n");
+	s5k4e1_probe_init_done(data);
+init_probe_done:
+	CDBG(" s5k4e1_probe_init_sensor finishes\n");
+	return rc;
+}
+
+int s5k4e1_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc = 0;
+
+	CDBG("%s: %d\n", __func__, __LINE__);
+	CDBG("Calling s5k4e1_sensor_open_init\n");
+
+	s5k4e1_ctrl = kzalloc(sizeof(struct s5k4e1_ctrl_t), GFP_KERNEL);
+	if (!s5k4e1_ctrl) {
+		CDBG("s5k4e1_init failed!\n");
+		rc = -ENOMEM;
+		goto init_done;
+	}
+	s5k4e1_ctrl->fps_divider = 1 * 0x00000400;
+	s5k4e1_ctrl->pict_fps_divider = 1 * 0x00000400;
+	s5k4e1_ctrl->set_test = TEST_OFF;
+	s5k4e1_ctrl->prev_res = QTR_SIZE;
+	s5k4e1_ctrl->pict_res = FULL_SIZE;
+
+	if (data)
+		s5k4e1_ctrl->sensordata = data;
+
+	prev_frame_length_lines =
+	((s5k4e1_regs.reg_prev[S5K4E1_REG_PREV_FRAME_LEN_1].wdata << 8) |
+		s5k4e1_regs.reg_prev[S5K4E1_REG_PREV_FRAME_LEN_2].wdata);
+
+	prev_line_length_pck =
+	(s5k4e1_regs.reg_prev[S5K4E1_REG_PREV_LINE_LEN_1].wdata << 8) |
+		s5k4e1_regs.reg_prev[S5K4E1_REG_PREV_LINE_LEN_2].wdata;
+
+	snap_frame_length_lines =
+	(s5k4e1_regs.reg_snap[S5K4E1_REG_SNAP_FRAME_LEN_1].wdata << 8) |
+		s5k4e1_regs.reg_snap[S5K4E1_REG_SNAP_FRAME_LEN_2].wdata;
+
+	snap_line_length_pck =
+	(s5k4e1_regs.reg_snap[S5K4E1_REG_SNAP_LINE_LEN_1].wdata << 8) |
+		s5k4e1_regs.reg_snap[S5K4E1_REG_SNAP_LINE_LEN_1].wdata;
+
+	/* enable mclk first */
+	msm_camio_clk_rate_set(S5K4E1_MASTER_CLK_RATE);
+	rc = s5k4e1_probe_init_sensor(data);
+	if (rc < 0)
+		goto init_fail;
+
+	CDBG("init settings\n");
+	if (s5k4e1_ctrl->prev_res == QTR_SIZE)
+		rc = s5k4e1_sensor_setting(REG_INIT, RES_PREVIEW);
+	else
+		rc = s5k4e1_sensor_setting(REG_INIT, RES_CAPTURE);
+	s5k4e1_ctrl->fps = 30 * Q8;
+
+	/* enable AF actuator */
+	if (s5k4e1_ctrl->sensordata->vcm_enable) {
+		CDBG("enable AF actuator, gpio = %d\n",
+			 s5k4e1_ctrl->sensordata->vcm_pwd);
+		rc = gpio_request(s5k4e1_ctrl->sensordata->vcm_pwd,
+						"s5k4e1_af");
+		if (!rc)
+			gpio_direction_output(
+				s5k4e1_ctrl->sensordata->vcm_pwd,
+				 1);
+		else {
+			pr_err("s5k4e1_ctrl gpio request failed!\n");
+			goto init_fail;
+		}
+		msleep(20);
+		rc = s5k4e1_set_default_focus(0);
+		if (rc < 0) {
+			gpio_direction_output(s5k4e1_ctrl->sensordata->vcm_pwd,
+								0);
+			gpio_free(s5k4e1_ctrl->sensordata->vcm_pwd);
+		}
+	}
+	if (rc < 0)
+		goto init_fail;
+	else
+		goto init_done;
+init_fail:
+	CDBG("init_fail\n");
+	s5k4e1_probe_init_done(data);
+init_done:
+	CDBG("init_done\n");
+	return rc;
+}
+
+static int s5k4e1_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&s5k4e1_wait_queue);
+	return 0;
+}
+
+static int s5k4e1_af_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&s5k4e1_af_wait_queue);
+	return 0;
+}
+
+static const struct i2c_device_id s5k4e1_af_i2c_id[] = {
+	{"s5k4e1_af", 0},
+	{ }
+};
+
+static int s5k4e1_af_i2c_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	int rc = 0;
+	CDBG("s5k4e1_af_probe called!\n");
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		CDBG("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	s5k4e1_af_sensorw = kzalloc(sizeof(struct s5k4e1_work_t), GFP_KERNEL);
+	if (!s5k4e1_af_sensorw) {
+		CDBG("kzalloc failed.\n");
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, s5k4e1_af_sensorw);
+	s5k4e1_af_init_client(client);
+	s5k4e1_af_client = client;
+
+	msleep(50);
+
+	CDBG("s5k4e1_af_probe successed! rc = %d\n", rc);
+	return 0;
+
+probe_failure:
+	CDBG("s5k4e1_af_probe failed! rc = %d\n", rc);
+	return rc;
+}
+
+static const struct i2c_device_id s5k4e1_i2c_id[] = {
+	{"s5k4e1", 0},
+	{ }
+};
+
+static int s5k4e1_i2c_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	int rc = 0;
+	CDBG("s5k4e1_probe called!\n");
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		CDBG("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	s5k4e1_sensorw = kzalloc(sizeof(struct s5k4e1_work_t), GFP_KERNEL);
+	if (!s5k4e1_sensorw) {
+		CDBG("kzalloc failed.\n");
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, s5k4e1_sensorw);
+	s5k4e1_init_client(client);
+	s5k4e1_client = client;
+
+	msleep(50);
+
+	CDBG("s5k4e1_probe successed! rc = %d\n", rc);
+	return 0;
+
+probe_failure:
+	CDBG("s5k4e1_probe failed! rc = %d\n", rc);
+	return rc;
+}
+
+static int __devexit s5k4e1_remove(struct i2c_client *client)
+{
+	struct s5k4e1_work_t *sensorw = i2c_get_clientdata(client);
+	free_irq(client->irq, sensorw);
+	s5k4e1_client = NULL;
+	kfree(sensorw);
+	return 0;
+}
+
+static int __devexit s5k4e1_af_remove(struct i2c_client *client)
+{
+	struct s5k4e1_work_t *s5k4e1_af = i2c_get_clientdata(client);
+	free_irq(client->irq, s5k4e1_af);
+	s5k4e1_af_client = NULL;
+	kfree(s5k4e1_af);
+	return 0;
+}
+
+static struct i2c_driver s5k4e1_i2c_driver = {
+	.id_table = s5k4e1_i2c_id,
+	.probe  = s5k4e1_i2c_probe,
+	.remove = __exit_p(s5k4e1_i2c_remove),
+	.driver = {
+		.name = "s5k4e1",
+	},
+};
+
+static struct i2c_driver s5k4e1_af_i2c_driver = {
+	.id_table = s5k4e1_af_i2c_id,
+	.probe  = s5k4e1_af_i2c_probe,
+	.remove = __exit_p(s5k4e1_af_i2c_remove),
+	.driver = {
+		.name = "s5k4e1_af",
+	},
+};
+
+int s5k4e1_sensor_config(void __user *argp)
+{
+	struct sensor_cfg_data cdata;
+	long   rc = 0;
+	if (copy_from_user(&cdata,
+				(void *)argp,
+				sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+	mutex_lock(&s5k4e1_mut);
+	CDBG("s5k4e1_sensor_config: cfgtype = %d\n",
+			cdata.cfgtype);
+	switch (cdata.cfgtype) {
+	case CFG_GET_PICT_FPS:
+		s5k4e1_get_pict_fps(
+			cdata.cfg.gfps.prevfps,
+			&(cdata.cfg.gfps.pictfps));
+
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+	case CFG_GET_PREV_L_PF:
+		cdata.cfg.prevl_pf =
+			s5k4e1_get_prev_lines_pf();
+
+		if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+	case CFG_GET_PREV_P_PL:
+		cdata.cfg.prevp_pl =
+			s5k4e1_get_prev_pixels_pl();
+
+		if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+	case CFG_GET_PICT_L_PF:
+		cdata.cfg.pictl_pf =
+			s5k4e1_get_pict_lines_pf();
+
+		if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+	case CFG_GET_PICT_P_PL:
+		cdata.cfg.pictp_pl =
+			s5k4e1_get_pict_pixels_pl();
+		if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+	case CFG_GET_PICT_MAX_EXP_LC:
+		cdata.cfg.pict_max_exp_lc =
+			s5k4e1_get_pict_max_exp_lc();
+
+		if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+	case CFG_SET_FPS:
+	case CFG_SET_PICT_FPS:
+		rc = s5k4e1_set_fps(&(cdata.cfg.fps));
+		break;
+	case CFG_SET_EXP_GAIN:
+		rc = s5k4e1_write_exp_gain(cdata.cfg.exp_gain.gain,
+				cdata.cfg.exp_gain.line);
+		break;
+	case CFG_SET_PICT_EXP_GAIN:
+		rc = s5k4e1_set_pict_exp_gain(cdata.cfg.exp_gain.gain,
+				cdata.cfg.exp_gain.line);
+		break;
+	case CFG_SET_MODE:
+		rc = s5k4e1_set_sensor_mode(cdata.mode, cdata.rs);
+		break;
+	case CFG_PWR_DOWN:
+		rc = s5k4e1_power_down();
+		break;
+	case CFG_MOVE_FOCUS:
+		rc = s5k4e1_move_focus(cdata.cfg.focus.dir,
+				cdata.cfg.focus.steps);
+		break;
+	case CFG_SET_DEFAULT_FOCUS:
+		rc = s5k4e1_set_default_focus(cdata.cfg.focus.steps);
+		break;
+	case CFG_GET_AF_MAX_STEPS:
+		cdata.max_steps = S5K4E1_TOTAL_STEPS_NEAR_TO_FAR;
+		if (copy_to_user((void *)argp,
+					&cdata,
+				sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+	case CFG_SET_EFFECT:
+		rc = s5k4e1_set_default_focus(cdata.cfg.effect);
+		break;
+	default:
+		rc = -EFAULT;
+		break;
+	}
+	mutex_unlock(&s5k4e1_mut);
+
+	return rc;
+}
+
+static int s5k4e1_sensor_release(void)
+{
+	int rc = -EBADF;
+
+	mutex_lock(&s5k4e1_mut);
+	s5k4e1_power_down();
+	msleep(20);
+	gpio_set_value_cansleep(s5k4e1_ctrl->sensordata->sensor_reset, 0);
+	usleep_range(5000, 5100);
+	gpio_free(s5k4e1_ctrl->sensordata->sensor_reset);
+	if (s5k4e1_ctrl->sensordata->vcm_enable) {
+		gpio_direction_output(s5k4e1_ctrl->sensordata->vcm_pwd, 0);
+		gpio_free(s5k4e1_ctrl->sensordata->vcm_pwd);
+	}
+	kfree(s5k4e1_ctrl);
+	s5k4e1_ctrl = NULL;
+	CDBG("s5k4e1_release completed\n");
+	mutex_unlock(&s5k4e1_mut);
+
+	return rc;
+}
+
+static int s5k4e1_sensor_probe(const struct msm_camera_sensor_info *info,
+		struct msm_sensor_ctrl *s)
+{
+	int rc = 0;
+
+	rc = i2c_add_driver(&s5k4e1_i2c_driver);
+	if (rc < 0 || s5k4e1_client == NULL) {
+		rc = -ENOTSUPP;
+		CDBG("I2C add driver failed");
+		goto probe_fail_1;
+	}
+
+	rc = i2c_add_driver(&s5k4e1_af_i2c_driver);
+	if (rc < 0 || s5k4e1_af_client == NULL) {
+		rc = -ENOTSUPP;
+		CDBG("I2C add driver failed");
+		goto probe_fail_2;
+	}
+
+	msm_camio_clk_rate_set(S5K4E1_MASTER_CLK_RATE);
+
+	rc = s5k4e1_probe_init_sensor(info);
+	if (rc < 0)
+		goto probe_fail_3;
+
+	s->s_init = s5k4e1_sensor_open_init;
+	s->s_release = s5k4e1_sensor_release;
+	s->s_config  = s5k4e1_sensor_config;
+	s->s_mount_angle = info->sensor_platform_info->mount_angle;
+	gpio_set_value_cansleep(info->sensor_reset, 0);
+	s5k4e1_probe_init_done(info);
+
+	return rc;
+
+probe_fail_3:
+	i2c_del_driver(&s5k4e1_af_i2c_driver);
+probe_fail_2:
+	i2c_del_driver(&s5k4e1_i2c_driver);
+probe_fail_1:
+	CDBG("s5k4e1_sensor_probe: SENSOR PROBE FAILS!\n");
+	return rc;
+}
+
+static int __devinit s5k4e1_probe(struct platform_device *pdev)
+{
+	return msm_camera_drv_start(pdev, s5k4e1_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = s5k4e1_probe,
+	.driver = {
+		.name = "msm_camera_s5k4e1",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init s5k4e1_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(s5k4e1_init);
+MODULE_DESCRIPTION("Samsung 5 MP Bayer sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/s5k4e1.h b/drivers/media/video/msm/s5k4e1.h
new file mode 100644
index 0000000..7f60332
--- /dev/null
+++ b/drivers/media/video/msm/s5k4e1.h
@@ -0,0 +1,94 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef S5K4E1_H
+#define S5K4E1_H
+#include <linux/types.h>
+#include <mach/board.h>
+extern struct s5k4e1_reg s5k4e1_regs;
+
+struct s5k4e1_i2c_reg_conf {
+	unsigned short waddr;
+	unsigned short wdata;
+};
+
+enum s5k4e1_test_mode_t {
+	TEST_OFF,
+	TEST_1,
+	TEST_2,
+	TEST_3
+};
+
+enum s5k4e1_resolution_t {
+	QTR_SIZE,
+	FULL_SIZE,
+	INVALID_SIZE
+};
+enum s5k4e1_setting {
+	RES_PREVIEW,
+	RES_CAPTURE
+};
+enum s5k4e1_reg_update {
+	/* Sensor egisters that need to be updated during initialization */
+	REG_INIT,
+	/* Sensor egisters that needs periodic I2C writes */
+	UPDATE_PERIODIC,
+	/* All the sensor Registers will be updated */
+	UPDATE_ALL,
+	/* Not valid update */
+	UPDATE_INVALID
+};
+
+enum s5k4e1_reg_pll {
+	E013_VT_PIX_CLK_DIV,
+	E013_VT_SYS_CLK_DIV,
+	E013_PRE_PLL_CLK_DIV,
+	E013_PLL_MULTIPLIER,
+	E013_OP_PIX_CLK_DIV,
+	E013_OP_SYS_CLK_DIV
+};
+
+enum s5k4e1_reg_mode {
+	E013_X_ADDR_START,
+	E013_X_ADDR_END,
+	E013_Y_ADDR_START,
+	E013_Y_ADDR_END,
+	E013_X_OUTPUT_SIZE,
+	E013_Y_OUTPUT_SIZE,
+	E013_DATAPATH_SELECT,
+	E013_READ_MODE,
+	E013_ANALOG_CONTROL5,
+	E013_DAC_LD_4_5,
+	E013_SCALING_MODE,
+	E013_SCALE_M,
+	E013_LINE_LENGTH_PCK,
+	E013_FRAME_LENGTH_LINES,
+	E013_COARSE_INTEGRATION_TIME,
+	E013_FINE_INTEGRATION_TIME,
+	E013_FINE_CORRECTION
+};
+
+struct s5k4e1_reg {
+	const struct s5k4e1_i2c_reg_conf *reg_mipi;
+	const unsigned short reg_mipi_size;
+	const struct s5k4e1_i2c_reg_conf *rec_settings;
+	const unsigned short rec_size;
+	const struct s5k4e1_i2c_reg_conf *reg_pll_p;
+	const unsigned short reg_pll_p_size;
+	const struct s5k4e1_i2c_reg_conf *reg_pll_s;
+	const unsigned short reg_pll_s_size;
+	const struct s5k4e1_i2c_reg_conf *reg_prev;
+	const unsigned short reg_prev_size;
+	const struct s5k4e1_i2c_reg_conf *reg_snap;
+	const unsigned short reg_snap_size;
+};
+#endif /* S5K4E1_H */
diff --git a/drivers/media/video/msm/s5k4e1_reg.c b/drivers/media/video/msm/s5k4e1_reg.c
new file mode 100644
index 0000000..59bb1c8
--- /dev/null
+++ b/drivers/media/video/msm/s5k4e1_reg.c
@@ -0,0 +1,169 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+
+#include "s5k4e1.h"
+
+struct s5k4e1_i2c_reg_conf s5k4e1_mipi_settings[] = {
+	{0x30BD, 0x00},/* SEL_CCP[0] */
+	{0x3084, 0x15},/* SYNC Mode */
+	{0x30BE, 0x1A},/* M_PCLKDIV_AUTO[4], M_DIV_PCLK[3:0] */
+	{0x30C1, 0x01},/* pack video enable [0] */
+	{0x30EE, 0x02},/* DPHY enable [ 1] */
+	{0x3111, 0x86},/* Embedded data off [5] */
+};
+
+/* PLL Configuration */
+struct s5k4e1_i2c_reg_conf s5k4e1_pll_preview_settings[] = {
+	{0x0305, 0x04},
+	{0x0306, 0x00},
+	{0x0307, 0x44},
+	{0x30B5, 0x00},
+	{0x30E2, 0x01},/* num lanes[1:0] = 2 */
+	{0x30F1, 0xB0},
+};
+
+struct s5k4e1_i2c_reg_conf s5k4e1_pll_snap_settings[] = {
+	{0x0305, 0x04},
+	{0x0306, 0x00},
+	{0x0307, 0x44},
+	{0x30B5, 0x00},
+	{0x30E2, 0x01},/* num lanes[1:0] = 2 */
+	{0x30F1, 0xB0},
+};
+
+struct s5k4e1_i2c_reg_conf s5k4e1_prev_settings[] = {
+	/* output size (1304 x 980) */
+	{0x30A9, 0x02},/* Horizontal Binning On */
+	{0x300E, 0xEB},/* Vertical Binning On */
+	{0x0387, 0x03},/* y_odd_inc 03(10b AVG) */
+	{0x0344, 0x00},/* x_addr_start 0 */
+	{0x0345, 0x00},
+	{0x0348, 0x0A},/* x_addr_end 2607 */
+	{0x0349, 0x2F},
+	{0x0346, 0x00},/* y_addr_start 0 */
+	{0x0347, 0x00},
+	{0x034A, 0x07},/* y_addr_end 1959 */
+	{0x034B, 0xA7},
+	{0x0380, 0x00},/* x_even_inc 1 */
+	{0x0381, 0x01},
+	{0x0382, 0x00},/* x_odd_inc 1 */
+	{0x0383, 0x01},
+	{0x0384, 0x00},/* y_even_inc 1 */
+	{0x0385, 0x01},
+	{0x0386, 0x00},/* y_odd_inc 3 */
+	{0x0387, 0x03},
+	{0x034C, 0x05},/* x_output_size 1304 */
+	{0x034D, 0x18},
+	{0x034E, 0x03},/* y_output_size 980 */
+	{0x034F, 0xd4},
+	{0x30BF, 0xAB},/* outif_enable[7], data_type[5:0](2Bh = bayer 10bit} */
+	{0x30C0, 0xA0},/* video_offset[7:4] 3260%12 */
+	{0x30C8, 0x06},/* video_data_length 1600 = 1304 * 1.25 */
+	{0x30C9, 0x5E},
+	/* Timing Configuration */
+	{0x0202, 0x03},
+	{0x0203, 0x14},
+	{0x0204, 0x00},
+	{0x0205, 0x80},
+	{0x0340, 0x03},/* Frame Length */
+	{0x0341, 0xE0},
+	{0x0342, 0x0A},/* 2738  Line Length */
+	{0x0343, 0xB2},
+};
+
+struct s5k4e1_i2c_reg_conf s5k4e1_snap_settings[] = {
+	/*Output Size (2608x1960)*/
+	{0x30A9, 0x03},/* Horizontal Binning Off */
+	{0x300E, 0xE8},/* Vertical Binning Off */
+	{0x0387, 0x01},/* y_odd_inc */
+	{0x034C, 0x0A},/* x_output size */
+	{0x034D, 0x30},
+	{0x034E, 0x07},/* y_output size */
+	{0x034F, 0xA8},
+	{0x30BF, 0xAB},/* outif_enable[7], data_type[5:0](2Bh = bayer 10bit} */
+	{0x30C0, 0x80},/* video_offset[7:4] 3260%12 */
+	{0x30C8, 0x0C},/* video_data_length 3260 = 2608 * 1.25 */
+	{0x30C9, 0xBC},
+	/*Timing configuration*/
+	{0x0202, 0x06},
+	{0x0203, 0x28},
+	{0x0204, 0x00},
+	{0x0205, 0x80},
+	{0x0340, 0x07},/* Frame Length */
+	{0x0341, 0xB4},
+	{0x0342, 0x0A},/* 2738 Line Length */
+	{0x0343, 0xB2},
+};
+
+struct s5k4e1_i2c_reg_conf s5k4e1_recommend_settings[] = {
+	/*CDS timing setting ... */
+	{0x3000, 0x05},
+	{0x3001, 0x03},
+	{0x3002, 0x08},
+	{0x3003, 0x0A},
+	{0x3004, 0x50},
+	{0x3005, 0x0E},
+	{0x3006, 0x5E},
+	{0x3007, 0x00},
+	{0x3008, 0x78},
+	{0x3009, 0x78},
+	{0x300A, 0x50},
+	{0x300B, 0x08},
+	{0x300C, 0x14},
+	{0x300D, 0x00},
+	{0x300E, 0xE8},
+	{0x300F, 0x82},
+	{0x301B, 0x77},
+
+	/* CDS option setting ... */
+	{0x3010, 0x00},
+	{0x3011, 0x3A},
+	{0x3029, 0x04},
+	{0x3012, 0x30},
+	{0x3013, 0xA0},
+	{0x3014, 0x00},
+	{0x3015, 0x00},
+	{0x3016, 0x30},
+	{0x3017, 0x94},
+	{0x3018, 0x70},
+	{0x301D, 0xD4},
+	{0x3021, 0x02},
+	{0x3022, 0x24},
+	{0x3024, 0x40},
+	{0x3027, 0x08},
+
+	/* Pixel option setting ...   */
+	{0x301C, 0x04},
+	{0x30D8, 0x3F},
+	{0x302B, 0x01},
+
+	{0x3070, 0x5F},
+	{0x3071, 0x00},
+	{0x3080, 0x04},
+	{0x3081, 0x38},
+};
+
+struct s5k4e1_reg s5k4e1_regs = {
+	.reg_mipi = &s5k4e1_mipi_settings[0],
+	.reg_mipi_size = ARRAY_SIZE(s5k4e1_mipi_settings),
+	.rec_settings = &s5k4e1_recommend_settings[0],
+	.rec_size = ARRAY_SIZE(s5k4e1_recommend_settings),
+	.reg_pll_p = &s5k4e1_pll_preview_settings[0],
+	.reg_pll_p_size = ARRAY_SIZE(s5k4e1_pll_preview_settings),
+	.reg_pll_s = &s5k4e1_pll_snap_settings[0],
+	.reg_pll_s_size = ARRAY_SIZE(s5k4e1_pll_snap_settings),
+	.reg_prev = &s5k4e1_prev_settings[0],
+	.reg_prev_size = ARRAY_SIZE(s5k4e1_prev_settings),
+	.reg_snap = &s5k4e1_snap_settings[0],
+	.reg_snap_size = ARRAY_SIZE(s5k4e1_snap_settings),
+};
diff --git a/drivers/media/video/msm/sn12m0pz.c b/drivers/media/video/msm/sn12m0pz.c
new file mode 100644
index 0000000..affa581
--- /dev/null
+++ b/drivers/media/video/msm/sn12m0pz.c
@@ -0,0 +1,1850 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <media/msm_camera.h>
+#include <mach/gpio.h>
+#include <mach/camera.h>
+#include <linux/slab.h>
+#include "sn12m0pz.h"
+
+
+#define	Q8					0x00000100
+#define	REG_GROUPED_PARAMETER_HOLD		0x0104
+#define	GROUPED_PARAMETER_HOLD_OFF		0x00
+#define	GROUPED_PARAMETER_HOLD			0x01
+#define	REG_MODE_SELECT				0x0100
+#define	MODE_SELECT_STANDBY_MODE		0x00
+#define	MODE_SELECT_STREAM			0x01
+
+/* Integration Time */
+#define	REG_COARSE_INTEGRATION_TIME_MSB		0x0202
+#define	REG_COARSE_INTEGRATION_TIME_LSB		0x0203
+
+/* Gain */
+#define	REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB	0x0204
+#define	REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB	0x0205
+
+/* PLL Register Defines */
+#define	REG_PLL_MULTIPLIER			0x0307
+#define	REG_0x302B				0x302B
+
+/* MIPI Enable Settings */
+#define	REG_0x30E5				0x30E5
+#define	REG_0x3300				0x3300
+
+/* Global Setting */
+#define	REG_IMAGE_ORIENTATION			0x0101
+
+#define	REG_0x300A				0x300A
+#define	REG_0x3014				0x3014
+#define	REG_0x3015				0x3015
+#define	REG_0x3017				0x3017
+#define	REG_0x301C				0x301C
+#define	REG_0x3031				0x3031
+#define	REG_0x3040				0x3040
+#define	REG_0x3041				0x3041
+#define	REG_0x3051				0x3051
+#define	REG_0x3053				0x3053
+#define	REG_0x3055				0x3055
+#define	REG_0x3057				0x3057
+#define	REG_0x3060				0x3060
+#define	REG_0x3065				0x3065
+#define	REG_0x30AA				0x30AA
+#define	REG_0x30AB				0x30AB
+#define	REG_0x30B0				0x30B0
+#define	REG_0x30B2				0x30B2
+#define	REG_0x30D3				0x30D3
+
+#define	REG_0x3106				0x3106
+#define	REG_0x3108				0x3108
+#define	REG_0x310A				0x310A
+#define	REG_0x310C				0x310C
+#define	REG_0x310E				0x310E
+#define	REG_0x3126				0x3126
+#define	REG_0x312E				0x312E
+#define	REG_0x313C				0x313C
+#define	REG_0x313E				0x313E
+#define	REG_0x3140				0x3140
+#define	REG_0x3142				0x3142
+#define	REG_0x3144				0x3144
+#define	REG_0x3148				0x3148
+#define	REG_0x314A				0x314A
+#define	REG_0x3166				0x3166
+#define	REG_0x3168				0x3168
+#define	REG_0x316F				0x316F
+#define	REG_0x3171				0x3171
+#define	REG_0x3173				0x3173
+#define	REG_0x3175				0x3175
+#define	REG_0x3177				0x3177
+#define	REG_0x3179				0x3179
+#define	REG_0x317B				0x317B
+#define	REG_0x317D				0x317D
+#define	REG_0x317F			0x317F
+#define	REG_0x3181			0x3181
+#define	REG_0x3184			0x3184
+#define	REG_0x3185			0x3185
+#define	REG_0x3187			0x3187
+
+#define	REG_0x31A4			0x31A4
+#define	REG_0x31A6			0x31A6
+#define	REG_0x31AC			0x31AC
+#define	REG_0x31AE			0x31AE
+#define	REG_0x31B4			0x31B4
+#define	REG_0x31B6			0x31B6
+
+#define	REG_0x3254			0x3254
+#define	REG_0x3256			0x3256
+#define	REG_0x3258			0x3258
+#define	REG_0x325A			0x325A
+#define	REG_0x3260			0x3260
+#define	REG_0x3262			0x3262
+
+
+#define	REG_0x3304			0x3304
+#define	REG_0x3305			0x3305
+#define	REG_0x3306			0x3306
+#define	REG_0x3307			0x3307
+#define	REG_0x3308			0x3308
+#define	REG_0x3309			0x3309
+#define	REG_0x330A			0x330A
+#define	REG_0x330B			0x330B
+#define	REG_0x330C			0x330C
+#define	REG_0x330D			0x330D
+
+/* Mode Setting */
+#define	REG_FRAME_LENGTH_LINES_MSB	0x0340
+#define	REG_FRAME_LENGTH_LINES_LSB	0x0341
+#define	REG_LINE_LENGTH_PCK_MSB		0x0342
+#define	REG_LINE_LENGTH_PCK_LSB		0x0343
+#define	REG_X_OUTPUT_SIZE_MSB		0x034C
+#define	REG_X_OUTPUT_SIZE_LSB		0x034D
+#define	REG_Y_OUTPUT_SIZE_MSB		0x034E
+#define	REG_Y_OUTPUT_SIZE_LSB		0x034F
+#define	REG_X_EVEN_INC_LSB		0x0381
+#define	REG_X_ODD_INC_LSB		0x0383
+#define	REG_Y_EVEN_INC_LSB		0x0385
+#define	REG_Y_ODD_INC_LSB		0x0387
+#define	REG_0x3016			0x3016
+#define	REG_0x30E8			0x30E8
+#define	REG_0x3301			0x3301
+/* for 120fps support */
+#define	REG_0x0344			0x0344
+#define	REG_0x0345			0x0345
+#define	REG_0x0346			0x0346
+#define	REG_0x0347			0x0347
+#define	REG_0x0348			0x0348
+#define	REG_0x0349			0x0349
+#define	REG_0x034A			0x034A
+#define	REG_0x034B			0x034B
+
+/* Test Pattern */
+#define	REG_0x30D8			0x30D8
+#define	REG_TEST_PATTERN_MODE		0x0601
+
+/* Solid Color Test Pattern */
+#define	REG_TEST_DATA_RED_MSB		0x0603
+#define	REG_TEST_DATA_RED_LSB		0x0603
+#define	REG_TEST_DATA_GREENR_MSB	0x0604
+#define	REG_TEST_DATA_GREENR_LSB	0x0605
+#define	REG_TEST_DATA_BLUE_MSB		0x0606
+#define	REG_TEST_DATA_BLUE_LSB		0x0607
+#define	REG_TEST_DATA_GREENB_MSB	0x0608
+#define	REG_TEST_DATA_GREENB_LSB	0x0609
+#define	SN12M0PZ_AF_I2C_SLAVE_ID	0xE4
+#define	SN12M0PZ_STEPS_NEAR_TO_CLOSEST_INF	42
+#define	SN12M0PZ_TOTAL_STEPS_NEAR_TO_FAR	42
+
+
+/* TYPE DECLARATIONS */
+
+
+enum mipi_config_type {
+	IU060F_SN12M0PZ_STMIPID01,
+	IU060F_SN12M0PZ_STMIPID02
+};
+
+enum sn12m0pz_test_mode_t {
+	TEST_OFF,
+	TEST_1,
+	TEST_2,
+	TEST_3
+};
+
+enum sn12m0pz_resolution_t {
+	QTR_SIZE,
+	FULL_SIZE,
+	INVALID_SIZE,
+	QVGA_SIZE,
+};
+
+enum sn12m0pz_setting {
+	RES_PREVIEW,
+	RES_CAPTURE,
+	RES_VIDEO_120FPS,
+};
+
+enum mt9p012_reg_update {
+	/* Sensor egisters that need to be updated during initialization */
+	REG_INIT,
+	/* Sensor egisters that needs periodic I2C writes */
+	UPDATE_PERIODIC,
+	/* All the sensor Registers will be updated */
+	UPDATE_ALL,
+	/* Not valid update */
+	UPDATE_INVALID
+};
+
+/* 816x612, 24MHz MCLK 96MHz PCLK */
+#define	IU060F_SN12M0PZ_OFFSET			3
+/* Time in milisecs for waiting for the sensor to reset.*/
+#define	SN12M0PZ_RESET_DELAY_MSECS		66
+#define	SN12M0PZ_WIDTH				4032
+#define	SN12M0PZ_HEIGHT				3024
+#define	SN12M0PZ_FULL_SIZE_WIDTH		4032
+#define	SN12M0PZ_FULL_SIZE_HEIGHT		3024
+#define	SN12M0PZ_HRZ_FULL_BLK_PIXELS		176
+#define	SN12M0PZ_VER_FULL_BLK_LINES		50
+#define	SN12M0PZ_QTR_SIZE_WIDTH			2016
+#define	SN12M0PZ_QTR_SIZE_HEIGHT		1512
+#define	SN12M0PZ_HRZ_QTR_BLK_PIXELS		2192
+#define	SN12M0PZ_VER_QTR_BLK_LINES		26
+
+/* 120fps mode */
+#define	SN12M0PZ_QVGA_SIZE_WIDTH		4032
+#define	SN12M0PZ_QVGA_SIZE_HEIGHT		249
+#define	SN12M0PZ_HRZ_QVGA_BLK_PIXELS		176
+#define	SN12M0PZ_VER_QVGA_BLK_LINES		9
+#define	SN12M0PZ_DEFAULT_CLOCK_RATE		24000000
+
+static uint32_t IU060F_SN12M0PZ_DELAY_MSECS = 30;
+static enum mipi_config_type mipi_config = IU060F_SN12M0PZ_STMIPID02;
+/* AF Tuning Parameters */
+static int16_t enable_single_D02_lane;
+static int16_t fullsize_cropped_at_8mp;
+
+struct sn12m0pz_work_t {
+	struct work_struct work;
+};
+
+static struct sn12m0pz_work_t *sn12m0pz_sensorw;
+static struct i2c_client *sn12m0pz_client;
+
+struct sn12m0pz_ctrl_t {
+	const struct msm_camera_sensor_info *sensordata;
+	uint32_t sensormode;
+	uint32_t fps_divider;/* init to 1 * 0x00000400 */
+	uint32_t pict_fps_divider;/* init to 1 * 0x00000400 */
+	uint16_t fps;
+	int16_t curr_lens_pos;
+	uint16_t curr_step_pos;
+	uint16_t my_reg_gain;
+	uint32_t my_reg_line_count;
+	uint16_t total_lines_per_frame;
+	enum sn12m0pz_resolution_t prev_res;
+	enum sn12m0pz_resolution_t pict_res;
+	enum sn12m0pz_resolution_t curr_res;
+	enum sn12m0pz_test_mode_t  set_test;
+	unsigned short imgaddr;
+};
+
+static struct sn12m0pz_ctrl_t *sn12m0pz_ctrl;
+static DECLARE_WAIT_QUEUE_HEAD(sn12m0pz_wait_queue);
+DEFINE_MUTEX(sn12m0pz_mut);
+
+
+static int sn12m0pz_i2c_rxdata(unsigned short saddr,
+	unsigned char *rxdata, int length)
+{
+	struct i2c_msg msgs[] = {
+		{
+			.addr  = saddr,
+			.flags = 0,
+			.len   = 2,
+			.buf   = rxdata,
+		},
+		{
+			.addr  = saddr,
+			.flags = I2C_M_RD,
+			.len   = 2,
+			.buf   = rxdata,
+		},
+	};
+
+	if (i2c_transfer(sn12m0pz_client->adapter, msgs, 2) < 0) {
+		CDBG("sn12m0pz_i2c_rxdata failed!");
+		return -EIO;
+	}
+
+	return 0;
+}
+static int32_t sn12m0pz_i2c_txdata(unsigned short saddr,
+				unsigned char *txdata, int length)
+{
+
+	struct i2c_msg msg[] = {
+		{
+			.addr  = saddr,
+			.flags = 0,
+			.len	 = length,
+			.buf	 = txdata,
+		},
+	};
+
+	if (i2c_transfer(sn12m0pz_client->adapter, msg, 1) < 0) {
+		CDBG("sn12m0pz_i2c_txdata faild 0x%x", sn12m0pz_client->addr);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t sn12m0pz_i2c_read(unsigned short raddr,
+				unsigned short *rdata, int rlen)
+{
+	int32_t rc;
+	unsigned char buf[2];
+	if (!rdata)
+		return -EIO;
+
+	memset(buf, 0, sizeof(buf));
+
+	buf[0] = (raddr & 0xFF00) >> 8;
+	buf[1] = (raddr & 0x00FF);
+
+	rc = sn12m0pz_i2c_rxdata(sn12m0pz_client->addr, buf, rlen);
+
+	if (rc < 0) {
+		CDBG("sn12m0pz_i2c_read 0x%x failed!", raddr);
+		return rc;
+	}
+
+	*rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]);
+
+	return rc;
+}
+
+static int32_t sn12m0pz_i2c_write_b_sensor(unsigned short waddr, uint8_t bdata)
+{
+	int32_t rc;
+	unsigned char buf[3];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = bdata;
+	udelay(90);
+	CDBG("i2c_write_b addr = %x, val = %x\n", waddr, bdata);
+	rc = sn12m0pz_i2c_txdata(sn12m0pz_client->addr, buf, 3);
+
+	if (rc < 0) {
+		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!",
+			waddr, bdata);
+	}
+
+	return rc;
+}
+
+static int16_t sn12m0pz_i2c_write_b_af(unsigned short saddr,
+				unsigned short baddr, unsigned short bdata)
+{
+	int16_t rc;
+	unsigned char buf[2];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = baddr;
+	buf[1] = bdata;
+	rc = sn12m0pz_i2c_txdata(saddr, buf, 2);
+
+	if (rc < 0)
+		CDBG("i2c_write failed, saddr = 0x%x addr = 0x%x, val =0x%x!",
+			saddr, baddr, bdata);
+
+	return rc;
+}
+
+static int32_t sn12m0pz_i2c_write_byte_bridge(unsigned short saddr,
+				unsigned short waddr, uint8_t bdata)
+{
+	int32_t rc;
+	unsigned char buf[3];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = bdata;
+
+	CDBG("i2c_write_b addr = %x, val = %x", waddr, bdata);
+	rc = sn12m0pz_i2c_txdata(saddr, buf, 3);
+
+	if (rc < 0)
+		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!",
+			waddr, bdata);
+
+	return rc;
+}
+
+static int32_t sn12m0pz_stmipid01_config(void)
+{
+	int32_t rc = 0;
+	/* Initiate I2C for D01: */
+	/* MIPI Bridge configuration */
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0002, 0x19) < 0)
+		return rc; /* enable clock lane*/
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0003, 0x00) < 0)
+		return rc;
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0004, 0x3E) < 0)
+		return rc; /* mipi mode clock*/
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0005, 0x01) < 0)
+		return rc; /* enable data line*/
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0006, 0x0F) < 0)
+		return rc; /* mipi mode data 0x01*/
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0009, 0x00) < 0)
+		return rc; /* Data_Lane1_Reg1*/
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x000D, 0x92) < 0)
+		return rc; /* CCPRxRegisters*/
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x000E, 0x28) < 0)
+		return rc; /* 10 bits for pixel width input for CCP rx.*/
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0014, 0xC0) < 0)
+		return rc; /* no bypass, no decomp, 1Lane System,CSIstreaming*/
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0015, 0x48) < 0)
+		return rc; /* ModeControlRegisters-- Don't reset error flag*/
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0017, 0x2B) < 0)
+		return rc; /* Data_ID_Rreg*/
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0018, 0x2B) < 0)
+		return rc; /* Data_ID_Rreg_emb*/
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0019, 0x0C) < 0)
+		return rc;
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x001E, 0x0A) < 0)
+		return rc;
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x001F, 0x0A) < 0)
+		return rc;
+
+	return rc;
+}
+static int32_t sn12m0pz_stmipid02_config(void)
+{
+	int32_t rc = 0;
+
+	/* Main Camera Clock Lane 1 (CLHP1, CLKN1)*/
+	/* Enable Clock Lane 1 (CLHP1, CLKN1), 0x15 for 400MHz */
+	if (enable_single_D02_lane) {
+		if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0002, 0x19) < 0)
+			return rc;
+		/* Main Camera Data Lane 1.1 (DATA2P1, DATA2N1) */
+		if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0009, 0x00) < 0)
+			return rc;/* Enable Data Lane 1.2 (DATA2P1, DATA2N1) */
+		if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x000A, 0x00) < 0)
+			return rc; /*CSIMode on Data Lane1.2(DATA2P1,DATA2N1)*/
+		/* Mode Control */
+		/* Enable single lane for qtr preview */
+		if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0014, 0xC0) < 0)
+			return rc; /*set 0xC0 - left justified on upper bits)*/
+		/* bit 1 set to 0 i.e. 1 lane system for qtr size preview */
+	} else {
+		if (sn12m0pz_ctrl->prev_res == QVGA_SIZE) {
+			if (sn12m0pz_i2c_write_byte_bridge(0x28>>1,
+				0x0002, 0x19) < 0)
+				return rc;
+		} else {
+			if (sn12m0pz_i2c_write_byte_bridge(0x28>>1,
+				0x0002, 0x21) < 0)
+				return rc;
+		}
+		/* Main Camera Data Lane 1.1 (DATA2P1, DATA2N1) */
+		if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0009, 0x01) < 0)
+			return rc; /* Enable Data Lane 1.2 (DATA2P1, DATA2N1) */
+		if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x000A, 0x01) < 0)
+			return rc; /* CSI Mode Data Lane1.2(DATA2P1, DATA2N1)*/
+
+		/* Mode Control */
+		/* Enable two lanes for full size preview/ snapshot */
+		if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0014, 0xC2) < 0)
+			return rc; /* No decompression, CSI dual lane */
+	}
+
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0004, 0x1E) < 0)
+		return rc;
+
+	/* Main Camera Data Lane 1.1 (DATA1P1, DATA1N1) */
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0005, 0x03) < 0)
+		return rc; /* Enable Data Lane 1.1 (DATA1P1, DATA1N1) */
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0006, 0x0f) < 0)
+		return rc; /* CSI Mode on Data Lane 1.1 (DATA1P1, DATA1N1) */
+
+	/* Tristated Output, continuous clock, */
+	/*polarity of clock is inverted and sync signals not inverted*/
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0015, 0x08) < 0)
+		return rc;
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0036, 0x20) < 0)
+		return rc; /* Enable compensation macro, main camera */
+
+	/* Data type: 0x2B Raw 10 */
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0017, 0x2B) < 0)
+		return rc;
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0018, 0x2B) < 0)
+		return rc; /* Data type of embedded data: 0x2B Raw 10 */
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0019, 0x0C) < 0)
+		return rc; /* Data type and pixel width programmed 0x0C*/
+
+	/* Decompression Mode */
+
+	/* Pixel Width and Decompression ON/OFF */
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x001E, 0x0A) < 0)
+		return rc; /* Image data not compressed: 0x0A for 10 bits */
+	if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x001F, 0x0A) < 0)
+		return rc; /* Embedded data not compressed: 0x0A for 10 bits */
+	return rc;
+}
+
+static int16_t sn12m0pz_af_init(void)
+{
+	int16_t rc;
+	/* Initialize waveform */
+	rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x01, 0xA9);
+
+	rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x02, 0xD2);
+
+	rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x03, 0x0C);
+
+	rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x04, 0x14);
+
+	rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x05, 0xB6);
+
+	rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x06, 0x4F);
+
+	rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x07, 0x00);
+
+	return rc;
+}
+
+static int32_t sn12m0pz_move_focus(int direction,
+	int32_t num_steps)
+{
+	int8_t step_direction, dest_step_position, bit_mask;
+	int32_t rc = 0;
+	uint16_t sn12m0pz_l_region_code_per_step = 3;
+
+	if (num_steps == 0)
+		return rc;
+
+	if (direction == MOVE_NEAR) {
+		step_direction = 1;
+		bit_mask = 0x80;
+	} else if (direction == MOVE_FAR) {
+		step_direction = -1;
+		bit_mask = 0x00;
+	} else {
+		CDBG("sn12m0pz_move_focus: Illegal focus direction");
+		return -EINVAL;
+	}
+
+	dest_step_position = sn12m0pz_ctrl->curr_step_pos +
+		(step_direction * num_steps);
+
+	if (dest_step_position < 0)
+		dest_step_position = 0;
+	else if (dest_step_position > SN12M0PZ_TOTAL_STEPS_NEAR_TO_FAR)
+		dest_step_position = SN12M0PZ_TOTAL_STEPS_NEAR_TO_FAR;
+
+	rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x00,
+		((num_steps * sn12m0pz_l_region_code_per_step) | bit_mask));
+
+	sn12m0pz_ctrl->curr_step_pos = dest_step_position;
+
+	return rc;
+}
+static int32_t sn12m0pz_set_default_focus(uint8_t af_step)
+{
+	int32_t rc;
+
+	/* Initialize to infinity */
+
+	rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x00, 0x7F);
+
+	rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x00, 0x7F);
+
+	sn12m0pz_ctrl->curr_step_pos = 0;
+
+	return rc;
+}
+static void sn12m0pz_get_pict_fps(uint16_t fps, uint16_t *pfps)
+{
+	/* input fps is preview fps in Q8 format */
+	uint16_t preview_frame_length_lines, snapshot_frame_length_lines;
+	uint16_t preview_line_length_pck, snapshot_line_length_pck;
+	uint32_t divider, pclk_mult, d1, d2;
+
+	/* Total frame_length_lines and line_length_pck for preview */
+	CDBG("sn12m0pz_get_pict_fps prev_res %d", sn12m0pz_ctrl->prev_res);
+	if (sn12m0pz_ctrl->prev_res == QVGA_SIZE) {
+		preview_frame_length_lines = SN12M0PZ_QVGA_SIZE_HEIGHT +
+			SN12M0PZ_VER_QVGA_BLK_LINES;
+		preview_line_length_pck = SN12M0PZ_QVGA_SIZE_WIDTH +
+			SN12M0PZ_HRZ_QVGA_BLK_PIXELS;
+	} else {
+		preview_frame_length_lines = SN12M0PZ_QTR_SIZE_HEIGHT +
+			SN12M0PZ_VER_QTR_BLK_LINES;
+		preview_line_length_pck = SN12M0PZ_QTR_SIZE_WIDTH +
+			SN12M0PZ_HRZ_QTR_BLK_PIXELS;
+	}
+	/* Total frame_length_lines and line_length_pck for snapshot */
+	snapshot_frame_length_lines = SN12M0PZ_FULL_SIZE_HEIGHT
+				+ SN12M0PZ_HRZ_FULL_BLK_PIXELS;
+	snapshot_line_length_pck = SN12M0PZ_FULL_SIZE_WIDTH
+				+ SN12M0PZ_HRZ_FULL_BLK_PIXELS;
+	d1 = preview_frame_length_lines *
+				0x00000400 / snapshot_frame_length_lines;
+	d2 = preview_line_length_pck *
+				0x00000400/snapshot_line_length_pck;
+	divider = d1 * d2 / 0x400;
+	pclk_mult =
+		(uint32_t)
+		(sn12m0pz_regs.reg_pat[RES_CAPTURE].pll_multiplier_lsb *
+		0x400) / (uint32_t)
+		sn12m0pz_regs.reg_pat[RES_PREVIEW].pll_multiplier_lsb;
+	*pfps = (uint16_t) (((fps * divider) / 0x400 * pclk_mult) / 0x400);
+}
+
+static uint16_t sn12m0pz_get_prev_lines_pf(void)
+{
+	if (sn12m0pz_ctrl->prev_res == QTR_SIZE)
+		return SN12M0PZ_QTR_SIZE_HEIGHT +
+			SN12M0PZ_VER_QTR_BLK_LINES;
+	else if (sn12m0pz_ctrl->prev_res == QVGA_SIZE)
+		return SN12M0PZ_QVGA_SIZE_HEIGHT +
+			SN12M0PZ_VER_QVGA_BLK_LINES;
+
+	else
+		return SN12M0PZ_FULL_SIZE_HEIGHT +
+			SN12M0PZ_VER_FULL_BLK_LINES;
+}
+
+static uint16_t sn12m0pz_get_prev_pixels_pl(void)
+{
+	if (sn12m0pz_ctrl->prev_res == QTR_SIZE)
+		return SN12M0PZ_QTR_SIZE_WIDTH +
+			SN12M0PZ_HRZ_QTR_BLK_PIXELS;
+	else
+		return SN12M0PZ_FULL_SIZE_WIDTH +
+			SN12M0PZ_HRZ_FULL_BLK_PIXELS;
+}
+
+static uint16_t sn12m0pz_get_pict_lines_pf(void)
+{
+	if (sn12m0pz_ctrl->pict_res == QTR_SIZE)
+		return SN12M0PZ_QTR_SIZE_HEIGHT +
+			SN12M0PZ_VER_QTR_BLK_LINES;
+	else
+		return SN12M0PZ_FULL_SIZE_HEIGHT +
+			SN12M0PZ_VER_FULL_BLK_LINES;
+}
+
+static uint16_t sn12m0pz_get_pict_pixels_pl(void)
+{
+	if (sn12m0pz_ctrl->pict_res == QTR_SIZE)
+		return SN12M0PZ_QTR_SIZE_WIDTH +
+			SN12M0PZ_HRZ_QTR_BLK_PIXELS;
+	else
+		return SN12M0PZ_FULL_SIZE_WIDTH +
+			SN12M0PZ_HRZ_FULL_BLK_PIXELS;
+}
+
+static uint32_t sn12m0pz_get_pict_max_exp_lc(void)
+{
+	if (sn12m0pz_ctrl->pict_res == QTR_SIZE)
+		return (SN12M0PZ_QTR_SIZE_HEIGHT +
+			SN12M0PZ_VER_QTR_BLK_LINES) * 24;
+	else
+		return (SN12M0PZ_FULL_SIZE_HEIGHT +
+			SN12M0PZ_VER_FULL_BLK_LINES) * 24;
+}
+
+static int32_t sn12m0pz_set_fps(struct fps_cfg	*fps)
+{
+	uint16_t total_lines_per_frame;
+	int32_t rc = 0;
+
+	total_lines_per_frame = (uint16_t)((SN12M0PZ_QTR_SIZE_HEIGHT +
+				SN12M0PZ_VER_QTR_BLK_LINES) *
+				sn12m0pz_ctrl->fps_divider / 0x400);
+
+	if (sn12m0pz_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_MSB,
+				((total_lines_per_frame & 0xFF00) >> 8)) < 0)
+		return rc;
+
+	if (sn12m0pz_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_LSB,
+				(total_lines_per_frame & 0x00FF)) < 0)
+		return rc;
+
+	return rc;
+}
+
+static int32_t sn12m0pz_write_exp_gain(uint16_t gain, uint32_t line)
+{
+	static uint16_t max_legal_gain = 0x00E0;
+	uint8_t gain_msb, gain_lsb;
+	uint8_t intg_time_msb, intg_time_lsb;
+	uint8_t line_length_pck_msb, line_length_pck_lsb;
+	uint16_t line_length_pck, frame_length_lines, temp_lines;
+	uint32_t line_length_ratio = 1 * Q8;
+	int32_t rc = 0;
+	CDBG("sn12m0pz_write_exp_gain : gain = %d line = %d", gain, line);
+
+	if (sn12m0pz_ctrl->sensormode != SENSOR_SNAPSHOT_MODE) {
+		if (sn12m0pz_ctrl->prev_res == QVGA_SIZE) {
+			frame_length_lines = SN12M0PZ_QVGA_SIZE_HEIGHT +
+						SN12M0PZ_VER_QVGA_BLK_LINES;
+			line_length_pck = SN12M0PZ_QVGA_SIZE_WIDTH +
+						SN12M0PZ_HRZ_QVGA_BLK_PIXELS;
+			if (line > (frame_length_lines -
+					IU060F_SN12M0PZ_OFFSET))
+				line = frame_length_lines -
+						IU060F_SN12M0PZ_OFFSET;
+			sn12m0pz_ctrl->fps = (uint16_t) (120 * Q8);
+		} else {
+			if (sn12m0pz_ctrl->curr_res  == QTR_SIZE) {
+				frame_length_lines = SN12M0PZ_QTR_SIZE_HEIGHT +
+						SN12M0PZ_VER_QTR_BLK_LINES;
+				line_length_pck = SN12M0PZ_QTR_SIZE_WIDTH +
+						SN12M0PZ_HRZ_QTR_BLK_PIXELS;
+			} else {
+				frame_length_lines = SN12M0PZ_HEIGHT +
+						SN12M0PZ_VER_FULL_BLK_LINES;
+				line_length_pck = SN12M0PZ_WIDTH +
+						SN12M0PZ_HRZ_FULL_BLK_PIXELS;
+			}
+			if (line > (frame_length_lines -
+						IU060F_SN12M0PZ_OFFSET))
+				sn12m0pz_ctrl->fps = (uint16_t) (30 * Q8 *
+			(frame_length_lines - IU060F_SN12M0PZ_OFFSET) / line);
+			else
+				sn12m0pz_ctrl->fps = (uint16_t) (30 * Q8);
+		}
+	} else {
+		if (sn12m0pz_ctrl->curr_res  == QTR_SIZE) {
+			frame_length_lines = SN12M0PZ_QTR_SIZE_HEIGHT +
+						SN12M0PZ_VER_QTR_BLK_LINES;
+			line_length_pck = SN12M0PZ_QTR_SIZE_WIDTH +
+						SN12M0PZ_HRZ_QTR_BLK_PIXELS;
+		} else {
+			frame_length_lines = SN12M0PZ_HEIGHT +
+						SN12M0PZ_VER_FULL_BLK_LINES;
+			line_length_pck = SN12M0PZ_WIDTH +
+						SN12M0PZ_HRZ_FULL_BLK_PIXELS;
+		}
+	}
+	if (gain > max_legal_gain)
+		/* range: 0 to 224 */
+		gain = max_legal_gain;
+	temp_lines = line;
+	/* calculate line_length_ratio */
+	if (line > (frame_length_lines - IU060F_SN12M0PZ_OFFSET)) {
+		line_length_ratio = (line * Q8) / (frame_length_lines -
+					IU060F_SN12M0PZ_OFFSET);
+		temp_lines = frame_length_lines - IU060F_SN12M0PZ_OFFSET;
+		if (line_length_ratio == 0)
+			line_length_ratio = 1 * Q8;
+	} else
+		line_length_ratio = 1 * Q8;
+
+	line = (uint32_t) (line * sn12m0pz_ctrl->fps_divider/0x400);
+
+	/* update gain registers */
+	gain_msb = (uint8_t) ((gain & 0xFF00) >> 8);
+	gain_lsb = (uint8_t) (gain & 0x00FF);
+
+	/* linear AFR horizontal stretch */
+	line_length_pck = (uint16_t) (line_length_pck * line_length_ratio / Q8);
+	line_length_pck_msb = (uint8_t) ((line_length_pck & 0xFF00) >> 8);
+	line_length_pck_lsb = (uint8_t) (line_length_pck & 0x00FF);
+
+	/* update line count registers */
+	intg_time_msb = (uint8_t) ((temp_lines & 0xFF00) >> 8);
+	intg_time_lsb = (uint8_t) (temp_lines & 0x00FF);
+
+
+	if (sn12m0pz_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
+			GROUPED_PARAMETER_HOLD) < 0)
+		return rc;
+
+	if (sn12m0pz_i2c_write_b_sensor(REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB,
+			gain_msb) < 0)
+		return rc;
+
+	if (sn12m0pz_i2c_write_b_sensor(REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB,
+			gain_lsb) < 0)
+		return rc;
+
+	if (sn12m0pz_i2c_write_b_sensor(REG_LINE_LENGTH_PCK_MSB,
+			line_length_pck_msb) < 0)
+		return rc;
+
+	if (sn12m0pz_i2c_write_b_sensor(REG_LINE_LENGTH_PCK_LSB,
+			line_length_pck_lsb) < 0)
+		return rc;
+
+	if (sn12m0pz_i2c_write_b_sensor(REG_COARSE_INTEGRATION_TIME_MSB,
+			intg_time_msb) < 0)
+		return rc;
+
+	if (sn12m0pz_i2c_write_b_sensor(REG_COARSE_INTEGRATION_TIME_LSB,
+			intg_time_lsb) < 0)
+		return rc;
+
+	if (sn12m0pz_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
+			GROUPED_PARAMETER_HOLD_OFF) < 0)
+		return rc;
+
+	return rc;
+}
+
+
+static int32_t sn12m0pz_set_pict_exp_gain(uint16_t gain, uint32_t line)
+{
+	int32_t rc;
+	rc = sn12m0pz_write_exp_gain(gain, line);
+	return rc;
+}
+
+static int32_t sn12m0pz_test(enum sn12m0pz_test_mode_t mo)
+{
+	uint8_t test_data_val_msb = 0x07;
+	uint8_t test_data_val_lsb = 0xFF;
+	int32_t rc = 0;
+	if (mo == TEST_OFF)
+		return rc;
+	else {
+		/* REG_0x30D8[4] is TESBYPEN: 0: Normal Operation,
+		 1: Bypass Signal Processing. REG_0x30D8[5] is EBDMASK:
+		 0: Output Embedded data, 1: No output embedded data */
+
+		if (sn12m0pz_i2c_write_b_sensor(REG_0x30D8, 0x10) < 0)
+			return rc;
+
+		if (sn12m0pz_i2c_write_b_sensor(REG_TEST_PATTERN_MODE,
+			(uint8_t) mo) < 0)
+			return rc;
+
+		/* Solid Color Test Pattern */
+
+		if (mo == TEST_1) {
+			if (sn12m0pz_i2c_write_b_sensor(REG_TEST_DATA_RED_MSB,
+				test_data_val_msb) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_TEST_DATA_RED_LSB,
+				test_data_val_lsb) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(
+						REG_TEST_DATA_GREENR_MSB,
+						test_data_val_msb) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(
+						REG_TEST_DATA_GREENR_LSB,
+						test_data_val_lsb) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_TEST_DATA_BLUE_MSB,
+				test_data_val_msb) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_TEST_DATA_BLUE_LSB,
+				test_data_val_lsb) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(
+						REG_TEST_DATA_GREENB_MSB,
+						test_data_val_msb) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(
+						REG_TEST_DATA_GREENB_LSB,
+						test_data_val_lsb) < 0)
+				return rc;
+		}
+
+	}
+
+	return rc;
+}
+
+static int32_t sn12m0pz_reset(void)
+{
+	int32_t rc = 0;
+	/* register 0x0002 is Port 2, CAM_XCLRO */
+	gpio_direction_output(sn12m0pz_ctrl->
+		sensordata->sensor_reset,
+		0);
+	msleep(50);
+	gpio_direction_output(sn12m0pz_ctrl->
+		sensordata->sensor_reset,
+		1);
+	msleep(13);
+	return rc;
+}
+
+static int32_t sn12m0pz_sensor_setting(int update_type, int rt)
+{
+	uint16_t total_lines_per_frame;
+	int32_t rc = 0;
+
+	switch (update_type) {
+	case UPDATE_PERIODIC:
+		/* Put Sensor into sofware standby mode	*/
+		if (sn12m0pz_i2c_write_b_sensor(REG_MODE_SELECT,
+				MODE_SELECT_STANDBY_MODE) <  0)
+			return rc;
+		msleep(5);
+		/* Hardware reset D02, lane config between full size/qtr size*/
+		rc = sn12m0pz_reset();
+		if (rc < 0)
+			return rc;
+
+		if (sn12m0pz_stmipid02_config() < 0)
+			return rc;
+	case REG_INIT:
+		if (rt == RES_PREVIEW || rt == RES_CAPTURE
+				|| rt == RES_VIDEO_120FPS) {
+			/* reset fps_divider */
+			sn12m0pz_ctrl->fps_divider = 1 * 0x400;
+
+			/* PLL settings */
+			if (sn12m0pz_i2c_write_b_sensor(REG_PLL_MULTIPLIER,
+			sn12m0pz_regs.reg_pat[rt].pll_multiplier_lsb) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x302B,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x302B) < 0)
+				return rc;
+
+			/* MIPI Enable Settings */
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x30E5,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x30E5) < 0)
+				return rc;
+
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3300,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3300) < 0)
+				return rc;
+
+			/* Global Setting */
+			if (
+				sn12m0pz_i2c_write_b_sensor(
+				REG_IMAGE_ORIENTATION,
+				sn12m0pz_regs.reg_pat_init[0].image_orient) < 0)
+				return rc;
+			if (
+				sn12m0pz_i2c_write_b_sensor(
+				REG_COARSE_INTEGRATION_TIME_MSB,
+				sn12m0pz_regs.reg_pat[rt].coarse_integ_time_msb)
+				< 0)
+				return rc;
+			if (
+				sn12m0pz_i2c_write_b_sensor(
+				REG_COARSE_INTEGRATION_TIME_LSB,
+				sn12m0pz_regs.reg_pat[rt].coarse_integ_time_lsb)
+				 < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x300A,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x300A) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3014,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3014) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3015,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3015) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3017,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3017) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x301C,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x301C) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3031,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3031) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3040,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3040) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3041,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3041) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3051,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3051) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3053,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3053) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3055,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3055) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3057,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3057) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3060,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3060) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3065,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3065) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x30AA,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x30AA) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x30AB,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x30AB) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x30B0,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x30B0) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x30B2,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x30B2) < 0)
+				return rc;
+
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x30D3,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x30D3) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x30D8,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x30D8) < 0)
+				return rc;
+
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3106,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3106) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3108,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3108) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x310A,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x310A) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x310C,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x310C) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x310E,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x310E) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3126,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3126) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x312E,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x312E) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x313C,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x313C) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x313E,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x313E) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3140,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3140) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3142,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3142) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3144,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3144) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3148,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3148) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x314A,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x314A) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3166,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3166) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3168,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3168) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x316F,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x316F) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3171,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3171) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3173,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3173) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3175,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3175) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3177,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3177) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3179,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3179) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x317B,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x317B) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x317D,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x317D) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x317F,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x317F) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3181,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3181) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3184,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3184) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3185,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3185) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3187,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3187) < 0)
+				return rc;
+
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x31A4,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x31A4) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x31A6,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x31A6) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x31AC,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x31AC) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x31AE,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x31AE) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x31B4,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x31B4) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x31B6,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x31B6) < 0)
+				return rc;
+
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3254,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3254) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3256,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3256) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3258,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3258) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x325A,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x325A) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3260,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3260) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3262,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3262) < 0)
+				return rc;
+
+
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3304,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3304) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3305,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3305) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3306,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3306) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3307,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3307) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3308,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3308) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3309,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x3309) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x330A,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x330A) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x330B,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x330B) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x330C,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x330C) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x330D,
+				sn12m0pz_regs.reg_pat_init[0].reg_0x330D) < 0)
+				return rc;
+
+			/* Mode setting */
+			/* Update registers with correct
+				 frame_length_line value for AFR */
+			total_lines_per_frame = (uint16_t)(
+			(sn12m0pz_regs.reg_pat[rt].frame_length_lines_msb << 8)
+			& 0xFF00) +
+			sn12m0pz_regs.reg_pat[rt].frame_length_lines_lsb;
+			total_lines_per_frame = total_lines_per_frame *
+					sn12m0pz_ctrl->fps_divider / 0x400;
+
+			if (sn12m0pz_i2c_write_b_sensor(
+					REG_FRAME_LENGTH_LINES_MSB,
+					(total_lines_per_frame & 0xFF00) >> 8)
+					< 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(
+					REG_FRAME_LENGTH_LINES_LSB,
+					(total_lines_per_frame & 0x00FF)) < 0)
+				return rc;
+
+			if (sn12m0pz_i2c_write_b_sensor(REG_LINE_LENGTH_PCK_MSB,
+				sn12m0pz_regs.reg_pat[rt].line_length_pck_msb) <
+				0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_LINE_LENGTH_PCK_LSB,
+				sn12m0pz_regs.reg_pat[rt].line_length_pck_lsb) <
+				0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_X_OUTPUT_SIZE_MSB,
+				sn12m0pz_regs.reg_pat[rt].x_output_size_msb) <
+				0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_X_OUTPUT_SIZE_LSB,
+				sn12m0pz_regs.reg_pat[rt].x_output_size_lsb) <
+				0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_Y_OUTPUT_SIZE_MSB,
+				sn12m0pz_regs.reg_pat[rt].y_output_size_msb) <
+				0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_Y_OUTPUT_SIZE_LSB,
+				sn12m0pz_regs.reg_pat[rt].y_output_size_lsb) <
+				0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_X_EVEN_INC_LSB,
+				sn12m0pz_regs.reg_pat[rt].x_even_inc_lsb) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_X_ODD_INC_LSB,
+				sn12m0pz_regs.reg_pat[rt].x_odd_inc_lsb) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_Y_EVEN_INC_LSB,
+				sn12m0pz_regs.reg_pat[rt].y_even_inc_lsb) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_Y_ODD_INC_LSB,
+				sn12m0pz_regs.reg_pat[rt].y_odd_inc_lsb) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3016,
+				sn12m0pz_regs.reg_pat[rt].reg_0x3016) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x30E8,
+				sn12m0pz_regs.reg_pat[rt].reg_0x30E8) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x3301,
+				sn12m0pz_regs.reg_pat[rt].reg_0x3301) < 0)
+				return rc;
+
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x0344,
+				sn12m0pz_regs.reg_pat[rt].reg_0x0344) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x0345,
+				sn12m0pz_regs.reg_pat[rt].reg_0x0345) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x0346,
+				sn12m0pz_regs.reg_pat[rt].reg_0x0346) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x0347,
+				sn12m0pz_regs.reg_pat[rt].reg_0x0347) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x0348,
+				sn12m0pz_regs.reg_pat[rt].reg_0x0348) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x0349,
+				sn12m0pz_regs.reg_pat[rt].reg_0x0349) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x034A,
+				sn12m0pz_regs.reg_pat[rt].reg_0x034A) < 0)
+				return rc;
+			if (sn12m0pz_i2c_write_b_sensor(REG_0x034B,
+				sn12m0pz_regs.reg_pat[rt].reg_0x034B) < 0)
+				return rc;
+
+			if ((rt == RES_CAPTURE) && fullsize_cropped_at_8mp) {
+				/* x address end */
+				if (sn12m0pz_i2c_write_b_sensor(0x0348,
+								0x0C) < 0)
+					return rc;
+				if (sn12m0pz_i2c_write_b_sensor(0x0349,
+								0x0CF) < 0)
+					return rc;
+				/* y address end */
+				if (sn12m0pz_i2c_write_b_sensor(0x034A,
+								0x09) < 0)
+					return rc;
+				if (sn12m0pz_i2c_write_b_sensor(0x034B,
+								0x9F) < 0)
+					return rc;
+			}
+
+			if (mipi_config == IU060F_SN12M0PZ_STMIPID01) {
+				if (sn12m0pz_i2c_write_b_sensor(
+						REG_PLL_MULTIPLIER, 0x43) < 0)
+					return rc;
+				if (rt == RES_CAPTURE) {
+					if (sn12m0pz_i2c_write_b_sensor(
+						REG_0x3301, 0x01) < 0)
+						return rc;
+				if (sn12m0pz_i2c_write_b_sensor(
+						REG_0x3017, 0xE0) < 0)
+					return rc;
+				}
+			}
+
+			if (sn12m0pz_i2c_write_b_sensor(REG_MODE_SELECT,
+						MODE_SELECT_STREAM) < 0)
+				return rc;
+
+			msleep(IU060F_SN12M0PZ_DELAY_MSECS);
+
+			if (sn12m0pz_test(sn12m0pz_ctrl->set_test) < 0)
+				return rc;
+
+			if (mipi_config == IU060F_SN12M0PZ_STMIPID02)
+				CDBG("%s,%d", __func__, __LINE__);
+			return rc;
+		}
+	default:
+		return rc;
+		}
+}
+
+
+static int32_t sn12m0pz_video_config(int mode)
+{
+
+	int32_t rc = 0;
+	int rt;
+
+
+	if (mode == SENSOR_HFR_120FPS_MODE)
+		sn12m0pz_ctrl->prev_res = QVGA_SIZE;
+
+	/* change sensor resolution if needed */
+	if (sn12m0pz_ctrl->curr_res != sn12m0pz_ctrl->prev_res) {
+		if (sn12m0pz_ctrl->prev_res == QTR_SIZE) {
+			rt = RES_PREVIEW;
+			IU060F_SN12M0PZ_DELAY_MSECS = 35; /*measured on scope*/
+			enable_single_D02_lane = 1;
+		} else if (sn12m0pz_ctrl->prev_res == QVGA_SIZE) {
+			rt = RES_VIDEO_120FPS;
+			IU060F_SN12M0PZ_DELAY_MSECS = 35; /*measured on scope*/
+			enable_single_D02_lane = 0;
+		} else {
+			rt = RES_CAPTURE;
+			enable_single_D02_lane = 0;
+		}
+
+		if (sn12m0pz_sensor_setting(UPDATE_PERIODIC, rt) < 0)
+			return rc;
+	}
+
+	sn12m0pz_ctrl->curr_res = sn12m0pz_ctrl->prev_res;
+	sn12m0pz_ctrl->sensormode = mode;
+
+	return rc;
+}
+static int32_t sn12m0pz_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+	int rt;
+	/* change sensor resolution if needed */
+	if (sn12m0pz_ctrl->curr_res != sn12m0pz_ctrl->pict_res) {
+		if (sn12m0pz_ctrl->pict_res == QTR_SIZE) {
+			rt = RES_PREVIEW;
+			enable_single_D02_lane = 1;
+		} else {
+			rt = RES_CAPTURE;
+			IU060F_SN12M0PZ_DELAY_MSECS = 100;/*measured on scope*/
+			enable_single_D02_lane = 0;
+		}
+
+		if (sn12m0pz_sensor_setting(UPDATE_PERIODIC, rt) < 0)
+			return rc;
+	}
+
+	sn12m0pz_ctrl->curr_res = sn12m0pz_ctrl->pict_res;
+	sn12m0pz_ctrl->sensormode = mode;
+	return rc;
+}
+
+static int32_t sn12m0pz_raw_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+	int rt;
+	/* change sensor resolution if needed */
+	if (sn12m0pz_ctrl->curr_res != sn12m0pz_ctrl->pict_res) {
+		if (sn12m0pz_ctrl->pict_res == QTR_SIZE) {
+			rt = RES_PREVIEW;
+			enable_single_D02_lane = 1;
+		} else {
+			rt = RES_CAPTURE;
+			IU060F_SN12M0PZ_DELAY_MSECS = 100;/*measured on scope*/
+			enable_single_D02_lane = 0;
+		}
+		if (sn12m0pz_sensor_setting(UPDATE_PERIODIC, rt) < 0)
+			return rc;
+		}
+	sn12m0pz_ctrl->curr_res = sn12m0pz_ctrl->pict_res;
+	sn12m0pz_ctrl->sensormode = mode;
+	return rc;
+}
+static int32_t sn12m0pz_set_sensor_mode(int  mode,
+	int  res)
+{
+	int32_t rc;
+
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+	case SENSOR_HFR_120FPS_MODE:
+		rc = sn12m0pz_video_config(mode);
+		break;
+
+	case SENSOR_SNAPSHOT_MODE:
+		rc = sn12m0pz_snapshot_config(mode);
+		break;
+
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		rc = sn12m0pz_raw_snapshot_config(mode);
+		break;
+
+	default:
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+static int32_t sn12m0pz_power_down(void)
+{
+	return 0;
+}
+
+
+static int sn12m0pz_probe_init_done(const struct msm_camera_sensor_info *data)
+{
+
+	gpio_direction_output(data->sensor_reset, 0);
+	gpio_free(data->sensor_reset);
+	gpio_direction_output(data->vcm_pwd, 0);
+	gpio_free(data->vcm_pwd);
+	return 0;
+}
+
+static int sn12m0pz_probe_init_sensor(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc;
+	unsigned short chipidl, chipidh;
+	CDBG("Requesting gpio");
+	rc = gpio_request(data->sensor_reset, "sn12m0pz");
+	CDBG(" sn12m0pz_probe_init_sensor");
+	if (!rc) {
+		gpio_direction_output(data->sensor_reset, 0);
+		msleep(20);
+		gpio_direction_output(data->sensor_reset, 1);
+		msleep(13);
+	} else {
+		goto init_probe_done;
+	}
+	CDBG("Requestion gpio");
+	rc = gpio_request(data->vcm_pwd, "sn12m0pz");
+	CDBG(" sn12m0pz_probe_init_sensor");
+
+	if (!rc) {
+		gpio_direction_output(data->vcm_pwd, 0);
+		msleep(20);
+		gpio_direction_output(data->vcm_pwd, 1);
+		msleep(13);
+	} else {
+		gpio_direction_output(data->sensor_reset, 0);
+		gpio_free(data->sensor_reset);
+		goto init_probe_done;
+	}
+
+	msleep(20);
+
+	/* 3. Read sensor Model ID: */
+	rc = sn12m0pz_i2c_read(0x0000, &chipidh, 1);
+	if (rc < 0) {
+		CDBG(" sn12m0pz_probe_init_sensor3");
+		goto init_probe_fail;
+	}
+	rc = sn12m0pz_i2c_read(0x0001, &chipidl, 1);
+	if (rc < 0) {
+		CDBG(" sn12m0pz_probe_init_sensor4");
+		goto init_probe_fail;
+	}
+
+	/* 4. Compare sensor ID to SN12M0PZ ID: */
+	if (chipidh != 0x00 || chipidl != 0x60) {
+		rc = -ENODEV;
+		CDBG("sn12m0pz_probe_init_sensor fail chip id doesnot match");
+		goto init_probe_fail;
+	}
+
+	msleep(SN12M0PZ_RESET_DELAY_MSECS);
+
+	goto init_probe_done;
+
+init_probe_fail:
+	CDBG(" sn12m0pz_probe_init_sensor fails");
+	sn12m0pz_probe_init_done(data);
+
+init_probe_done:
+	CDBG(" sn12m0pz_probe_init_sensor finishes");
+	return rc;
+}
+
+int sn12m0pz_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc = 0;
+	CDBG("Calling sn12m0pz_sensor_open_init");
+
+	sn12m0pz_ctrl = kzalloc(sizeof(struct sn12m0pz_ctrl_t), GFP_KERNEL);
+	if (!sn12m0pz_ctrl) {
+		CDBG("sn12m0pz_init failed!");
+		rc = -ENOMEM;
+		goto init_done;
+	}
+
+	sn12m0pz_ctrl->fps_divider      = 1 * 0x00000400;
+	sn12m0pz_ctrl->pict_fps_divider = 1 * 0x00000400;
+	sn12m0pz_ctrl->set_test = TEST_OFF;
+	sn12m0pz_ctrl->prev_res = QTR_SIZE;
+	sn12m0pz_ctrl->pict_res = FULL_SIZE;
+	sn12m0pz_ctrl->curr_res = INVALID_SIZE;
+	if (data)
+		sn12m0pz_ctrl->sensordata = data;
+
+	if (rc < 0)
+		return rc;
+
+	/* enable mclk first */
+	msm_camio_clk_rate_set(SN12M0PZ_DEFAULT_CLOCK_RATE);
+	msleep(20);
+	msm_camio_camif_pad_reg_reset();
+	msleep(20);
+	CDBG("Calling sn12m0pz_sensor_open_init");
+	rc = sn12m0pz_probe_init_sensor(data);
+
+	if (rc < 0)
+		goto init_fail;
+	/* send reset signal */
+	if (mipi_config == IU060F_SN12M0PZ_STMIPID01) {
+		if (sn12m0pz_stmipid01_config() < 0) {
+			CDBG("Calling sn12m0pz_sensor_open_init fail");
+			return rc;
+		}
+	} else {
+		if (sn12m0pz_ctrl->prev_res  == QTR_SIZE)
+			enable_single_D02_lane = 1;
+		else /* FULL_SIZE */
+			enable_single_D02_lane = 0;
+
+		if (sn12m0pz_stmipid02_config() < 0) {
+			CDBG("Calling sn12m0pz_sensor_open_init fail");
+			return rc;
+		}
+	}
+
+
+	if (sn12m0pz_ctrl->prev_res == QTR_SIZE) {
+		if (sn12m0pz_sensor_setting(REG_INIT, RES_PREVIEW) < 0)
+			return rc;
+	} else if (sn12m0pz_ctrl->prev_res == QVGA_SIZE) {
+		if (sn12m0pz_sensor_setting(REG_INIT, RES_VIDEO_120FPS) < 0)
+			return rc;
+	} else {
+		if (sn12m0pz_sensor_setting(REG_INIT, RES_CAPTURE) < 0)
+			return rc;
+	}
+
+	if (sn12m0pz_af_init() < 0)
+		return rc;
+	sn12m0pz_ctrl->fps = 30*Q8;
+	if (rc < 0)
+		goto init_fail;
+	else
+		goto init_done;
+init_fail:
+	CDBG(" init_fail");
+	sn12m0pz_probe_init_done(data);
+	kfree(sn12m0pz_ctrl);
+init_done:
+	CDBG("init_done");
+	return rc;
+}
+static int __init sn12m0pz_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&sn12m0pz_wait_queue);
+	return 0;
+}
+
+static const struct i2c_device_id sn12m0pz_i2c_id[] = {
+	{ "sn12m0pz", 0},
+	{ }
+};
+
+static int sn12m0pz_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int rc = 0;
+	CDBG("sn12m0pz_probe called!");
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		CDBG("i2c_check_functionality failed");
+		goto probe_failure;
+	}
+
+	sn12m0pz_sensorw = kzalloc(sizeof(struct sn12m0pz_work_t), GFP_KERNEL);
+	if (!sn12m0pz_sensorw) {
+		CDBG("kzalloc failed");
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, sn12m0pz_sensorw);
+	sn12m0pz_init_client(client);
+	sn12m0pz_client = client;
+
+	msleep(50);
+
+	CDBG("sn12m0pz_probe successed! rc = %d", rc);
+	return 0;
+
+probe_failure:
+	CDBG("sn12m0pz_probe failed! rc = %d", rc);
+	return rc;
+}
+
+static int __exit sn12m0pz_remove(struct i2c_client *client)
+{
+	struct sn12m0pz_work_t_t *sensorw = i2c_get_clientdata(client);
+	free_irq(client->irq, sensorw);
+	sn12m0pz_client = NULL;
+	kfree(sensorw);
+	return 0;
+}
+
+static struct i2c_driver sn12m0pz_i2c_driver = {
+	.id_table = sn12m0pz_i2c_id,
+	.probe	= sn12m0pz_i2c_probe,
+	.remove = __exit_p(sn12m0pz_i2c_remove),
+	.driver = {
+		.name = "sn12m0pz",
+	},
+};
+
+int sn12m0pz_sensor_config(void __user *argp)
+{
+	struct sensor_cfg_data cdata;
+	int32_t rc = 0;
+	if (copy_from_user(&cdata,
+				(void *)argp,
+				sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+
+	mutex_lock(&sn12m0pz_mut);
+
+	CDBG("sn12m0pz_sensor_config: cfgtype = %d",
+		cdata.cfgtype);
+	switch (cdata.cfgtype) {
+	case CFG_GET_PICT_FPS:
+		sn12m0pz_get_pict_fps(cdata.cfg.gfps.prevfps,
+					&(cdata.cfg.gfps.pictfps));
+
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PREV_L_PF:
+		cdata.cfg.prevl_pf =
+			sn12m0pz_get_prev_lines_pf();
+
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PREV_P_PL:
+		cdata.cfg.prevp_pl =
+			sn12m0pz_get_prev_pixels_pl();
+
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_L_PF:
+		cdata.cfg.pictl_pf =
+			sn12m0pz_get_pict_lines_pf();
+
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_P_PL:
+		cdata.cfg.pictp_pl =
+			sn12m0pz_get_pict_pixels_pl();
+
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_MAX_EXP_LC:
+		cdata.cfg.pict_max_exp_lc =
+			sn12m0pz_get_pict_max_exp_lc();
+
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_SET_FPS:
+	case CFG_SET_PICT_FPS:
+		rc = sn12m0pz_set_fps(&(cdata.cfg.fps));
+		break;
+
+	case CFG_SET_EXP_GAIN:
+		rc =
+			sn12m0pz_write_exp_gain(
+				cdata.cfg.exp_gain.gain,
+				cdata.cfg.exp_gain.line);
+		break;
+	case CFG_SET_PICT_EXP_GAIN:
+		rc =
+			sn12m0pz_set_pict_exp_gain(
+				cdata.cfg.exp_gain.gain,
+				cdata.cfg.exp_gain.line);
+		break;
+
+	case CFG_SET_MODE:
+		rc = sn12m0pz_set_sensor_mode(cdata.mode,
+					cdata.rs);
+		break;
+
+	case CFG_PWR_DOWN:
+		rc = sn12m0pz_power_down();
+		break;
+
+	case CFG_MOVE_FOCUS:
+		rc = sn12m0pz_move_focus(cdata.cfg.focus.dir,
+					cdata.cfg.focus.steps);
+		break;
+
+	case CFG_SET_DEFAULT_FOCUS:
+		rc = sn12m0pz_set_default_focus(cdata.cfg.focus.steps);
+		break;
+
+	case CFG_SET_EFFECT:
+		rc = 0;
+		break;
+	case CFG_SET_LENS_SHADING:
+		rc = 0;
+		break;
+	default:
+		rc = -EFAULT;
+		break;
+	}
+
+	mutex_unlock(&sn12m0pz_mut);
+
+	return rc;
+}
+
+static int sn12m0pz_sensor_release(void)
+{
+	int rc = -EBADF;
+
+	mutex_lock(&sn12m0pz_mut);
+
+	sn12m0pz_power_down();
+
+	gpio_direction_output(sn12m0pz_ctrl->sensordata->sensor_reset,
+		0);
+	gpio_free(sn12m0pz_ctrl->sensordata->sensor_reset);
+
+	gpio_direction_output(sn12m0pz_ctrl->sensordata->vcm_pwd,
+		0);
+	gpio_free(sn12m0pz_ctrl->sensordata->vcm_pwd);
+
+	kfree(sn12m0pz_ctrl);
+	sn12m0pz_ctrl = NULL;
+
+	CDBG("sn12m0pz_release completed");
+
+
+	mutex_unlock(&sn12m0pz_mut);
+
+	return rc;
+}
+
+static int sn12m0pz_sensor_probe(const struct msm_camera_sensor_info *info,
+		struct msm_sensor_ctrl *s)
+{
+	int rc;
+
+	rc = i2c_add_driver(&sn12m0pz_i2c_driver);
+	if (rc < 0 || sn12m0pz_client == NULL) {
+		rc = -ENOTSUPP;
+		goto probe_fail;
+	}
+
+	msm_camio_clk_rate_set(SN12M0PZ_DEFAULT_CLOCK_RATE);
+	msleep(20);
+
+	rc = sn12m0pz_probe_init_sensor(info);
+	if (rc < 0)
+		goto probe_fail;
+
+	s->s_init = sn12m0pz_sensor_open_init;
+	s->s_release = sn12m0pz_sensor_release;
+	s->s_config  = sn12m0pz_sensor_config;
+	s->s_mount_angle  = 0;
+	sn12m0pz_probe_init_done(info);
+
+	return rc;
+
+probe_fail:
+	CDBG("SENSOR PROBE FAILS!");
+	i2c_del_driver(&sn12m0pz_i2c_driver);
+	return rc;
+}
+
+static int __sn12m0pz_probe(struct platform_device *pdev)
+{
+	return msm_camera_drv_start(pdev, sn12m0pz_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = __sn12m0pz_probe,
+	.driver = {
+		.name = "msm_camera_sn12m0pz",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init sn12m0pz_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(sn12m0pz_init);
+
+MODULE_DESCRIPTION("Sony 12M MP Bayer sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/sn12m0pz.h b/drivers/media/video/msm/sn12m0pz.h
new file mode 100644
index 0000000..f2abc47
--- /dev/null
+++ b/drivers/media/video/msm/sn12m0pz.h
@@ -0,0 +1,138 @@
+
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+#ifndef SN12M0PZ_H
+#define SN12M0PZ_H
+
+#include <linux/types.h>
+extern struct sn12m0pz_reg sn12m0pz_regs; /* from mt9t013_reg.c */
+struct reg_struct{
+	uint8_t pll_multiplier_lsb;            /* 0x0307*/
+	uint8_t coarse_integ_time_msb;   /* 0x0202*/
+	uint8_t coarse_integ_time_lsb;   /* 0x0203*/
+	uint8_t frame_length_lines_msb;        /* 0x0340*/
+	uint8_t frame_length_lines_lsb;        /* 0x0341*/
+	uint8_t line_length_pck_msb;           /* 0x0342*/
+	uint8_t line_length_pck_lsb;           /* 0x0343*/
+	uint8_t x_output_size_msb;             /* 0x034C*/
+	uint8_t x_output_size_lsb;             /* 0x034D*/
+	uint8_t y_output_size_msb;             /* 0x034E*/
+	uint8_t y_output_size_lsb;             /* 0x034F*/
+	uint8_t x_even_inc_lsb;                /* 0x0381*/
+	uint8_t x_odd_inc_lsb;                 /* 0x0383*/
+	uint8_t y_even_inc_lsb;                /* 0x0385*/
+	uint8_t y_odd_inc_lsb;                 /* 0x0387*/
+	uint8_t reg_0x3016;                    /* 0x3016 VMODEADD*/
+	uint8_t reg_0x30E8;                    /* 0x30E8 HADDAVE*/
+	uint8_t reg_0x3301;                    /* 0x3301 RGLANESEL*/
+	/*added for 120fps support */
+	uint8_t reg_0x0344;
+	uint8_t reg_0x0345;
+	uint8_t reg_0x0346;
+	uint8_t reg_0x0347;
+	uint8_t reg_0x0348;
+	uint8_t reg_0x0349;
+	uint8_t reg_0x034A;
+	uint8_t reg_0x034B;
+};
+struct reg_struct_init{
+	uint8_t reg_0x302B;/* 0x302B*/
+
+	uint8_t reg_0x30E5;/* 0x30E5*/
+	uint8_t reg_0x3300;   /* 0x3300*/
+
+	uint8_t image_orient;   /* 0x0101*/
+
+	uint8_t reg_0x300A;   /* 0x300A*/
+	uint8_t reg_0x3014;   /* 0x3014*/
+	uint8_t reg_0x3015;   /* 0x3015*/
+	uint8_t reg_0x3017;   /* 0x3017*/
+	uint8_t reg_0x301C;   /* 0x301C*/
+	uint8_t reg_0x3031;   /* 0x3031*/
+	uint8_t reg_0x3040;   /* 0x3040*/
+	uint8_t reg_0x3041;   /* 0x3041*/
+	uint8_t reg_0x3051;   /* 0x3051*/
+	uint8_t reg_0x3053;   /* 0x3053*/
+	uint8_t reg_0x3055;   /* 0x3055*/
+	uint8_t reg_0x3057;   /* 0x3057*/
+	uint8_t reg_0x3060;   /* 0x3060*/
+	uint8_t reg_0x3065;   /* 0x3065*/
+	uint8_t reg_0x30AA;   /* 0x30AA*/
+	uint8_t reg_0x30AB;   /* 0x30AB*/
+	uint8_t reg_0x30B0;   /* 0x30B0*/
+	uint8_t reg_0x30B2;   /* 0x30B2*/
+
+	uint8_t reg_0x30D3;   /* 0X30D3*/
+	uint8_t reg_0x30D8;   /* 0X30D8*/
+
+	uint8_t reg_0x3106;   /* 0x3106*/
+	uint8_t reg_0x3108;   /* 0x3108*/
+	uint8_t reg_0x310A;   /* 0x310A*/
+	uint8_t reg_0x310C;   /* 0x310C*/
+	uint8_t reg_0x310E;   /* 0x310E*/
+	uint8_t reg_0x3126;   /* 0x3126*/
+	uint8_t reg_0x312E;   /* 0x312E*/
+	uint8_t reg_0x313C;   /* 0x313C*/
+	uint8_t reg_0x313E;   /* 0x313E*/
+	uint8_t reg_0x3140;   /* 0x3140*/
+	uint8_t reg_0x3142;   /* 0x3142*/
+	uint8_t reg_0x3144;   /* 0x3144*/
+	uint8_t reg_0x3148;   /* 0x3148*/
+	uint8_t reg_0x314A;   /* 0x314A*/
+	uint8_t reg_0x3166;   /* 0x3166*/
+	uint8_t reg_0x3168;   /* 0x3168*/
+	uint8_t reg_0x316F;   /* 0x316F*/
+	uint8_t reg_0x3171;   /* 0x3171*/
+	uint8_t reg_0x3173;   /* 0x3173*/
+	uint8_t reg_0x3175;   /* 0x3175*/
+	uint8_t reg_0x3177;   /* 0x3177*/
+	uint8_t reg_0x3179;   /* 0x3179*/
+	uint8_t reg_0x317B;   /* 0x317B*/
+	uint8_t reg_0x317D;   /* 0x317D*/
+	uint8_t reg_0x317F;   /* 0x317F*/
+	uint8_t reg_0x3181;   /* 0x3181*/
+	uint8_t reg_0x3184;   /* 0x3184*/
+	uint8_t reg_0x3185;   /* 0x3185*/
+	uint8_t reg_0x3187;   /* 0x3187*/
+
+	uint8_t reg_0x31A4;   /* 0x31A4*/
+	uint8_t reg_0x31A6;   /* 0x31A6*/
+	uint8_t reg_0x31AC;   /* 0x31AC*/
+	uint8_t reg_0x31AE;   /* 0x31AE*/
+	uint8_t reg_0x31B4;   /* 0x31B4*/
+	uint8_t reg_0x31B6;   /* 0x31B6*/
+
+	uint8_t reg_0x3254;   /* 0x3254*/
+	uint8_t reg_0x3256;   /* 0x3256*/
+	uint8_t reg_0x3258;   /* 0x3258*/
+	uint8_t reg_0x325A;   /* 0x325A*/
+	uint8_t reg_0x3260;   /* 0x3260*/
+	uint8_t reg_0x3262;   /* 0x3262*/
+
+	uint8_t reg_0x3304;   /* 0x3304*/
+	uint8_t reg_0x3305;   /* 0x3305*/
+	uint8_t reg_0x3306;   /* 0x3306*/
+	uint8_t reg_0x3307;   /* 0x3307*/
+	uint8_t reg_0x3308;   /* 0x3308*/
+	uint8_t reg_0x3309;   /* 0x3309*/
+	uint8_t reg_0x330A;   /* 0x330A*/
+	uint8_t reg_0x330B;   /* 0x330B*/
+	uint8_t reg_0x330C;   /* 0x330C*/
+	uint8_t reg_0x330D;   /* 0x330D*/
+
+};
+struct sn12m0pz_reg{
+	const struct reg_struct  *reg_pat;
+	const struct reg_struct_init  *reg_pat_init;
+};
+#endif
diff --git a/drivers/media/video/msm/sn12m0pz_reg.c b/drivers/media/video/msm/sn12m0pz_reg.c
new file mode 100644
index 0000000..d21eac1
--- /dev/null
+++ b/drivers/media/video/msm/sn12m0pz_reg.c
@@ -0,0 +1,213 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include "sn12m0pz.h"
+/* Initialisation settings */
+
+const struct reg_struct_init iu060f_reg_pat_init[1] = {{
+	/* PLL setting */
+	0x4B, /* reg 0x302B*/
+	/* MIPI Enable Setting */
+	0x04, /* reg 0x30E5*/
+	0x00, /* reg 0x3300*/
+	/* Global Setting */
+	0x00, /* image_orientation*/
+	0x80, /* reg 0x300A*/
+	0x08, /* reg 0x3014*/
+	0x37, /* reg 0x3015*/
+	0x60, /* reg 0x3017*/
+	0x01, /* reg 0x301C*/
+	0x28, /* reg 0x3031*/
+	0x00, /* reg 0x3040*/
+	0x60, /* reg 0x3041*/
+	0x24, /* reg 0x3051*/
+	0x34, /* reg 0x3053*/
+	0x3B, /* reg 0x3055*/
+	0xC0, /* reg 0x3057*/
+	0x30, /* reg 0x3060*/
+	0x00, /* reg 0x3065*/
+	0x88, /* reg 0x30AA*/
+	0x1C, /* reg 0x30AB*/
+	0x32, /* reg 0x30B0*/
+	0x83, /* reg 0x30B2*/
+	0x04, /* reg 0x30D3*/
+	0xC0, /* reg 0x30D8*/
+	0x50, /* reg 0x3106*/
+	0xA5, /* reg 0x3108*/
+	0xA9, /* reg 0x310A*/
+	0x0C, /* reg 0x310C*/
+	0x55, /* reg 0x310E*/
+	0xCC, /* reg 0x3126*/
+	0x83, /* reg 0x312E*/
+	0xC7, /* reg 0x313C*/
+	0x07, /* reg 0x313E*/
+	0x32, /* reg 0x3140*/
+	0x35, /* reg 0x3142*/
+	0x35, /* reg 0x3144*/
+	0x73, /* reg 0x3148*/
+	0x80, /* reg 0x314A*/
+	0xBE, /* reg 0x3166*/
+	0xBD, /* reg 0x3168*/
+	0x82, /* reg 0x316F*/
+	0xBC, /* reg 0x3171*/
+	0x82, /* reg 0x3173*/
+	0xBC, /* reg 0x3175*/
+	0x0C, /* reg 0x3177*/
+	0x2C, /* reg 0x3179*/
+	0x83, /* reg 0x317B*/
+	0xAF, /* reg 0x317D*/
+	0x83, /* reg 0x317F*/
+	0xAF, /* reg 0x3181*/
+	0x06, /* reg 0x3184*/
+	0xBA, /* reg 0x3185*/
+	0xBE, /* reg 0x3187*/
+	0xD8, /* reg 0x31A4*/
+	0x17, /* reg 0x31A6*/
+	0xCF, /* reg 0x31AC*/
+	0xF1, /* reg 0x31AE*/
+	0xD8, /* reg 0x31B4*/
+	0x17, /* reg 0x31B6*/
+	0x09, /* reg 0x3254 */
+	0xC5, /* reg 0x3256 */
+	0x84, /* reg 0x3258 */
+	0x6C, /* reg 0x325A */
+	0x0B, /* reg 0x3260 */
+	0x09, /* reg 0x3262 */
+	0x05, /* reg 0x3304*/
+	0x04, /* reg 0x3305*/
+	0x15, /* reg 0x3306*/
+	0x03, /* reg 0x3307*/
+	0x13, /* reg 0x3308*/
+	0x05, /* reg 0x3309*/
+	0x0B, /* reg 0x330A*/
+	0x04, /* reg 0x330B*/
+	0x0B, /* reg 0x330C*/
+	0x06  /* reg 0x330D*/
+}
+};
+
+/* Preview / Snapshot register settings */
+const struct reg_struct iu060f_reg_pat[3] = {
+	{ /* Preview */
+		0x22, /*0x1b*/ /* fps*/
+
+		/* Global Setting */
+		0x01, /* coarse_integration_time_msb*/
+		0xFF, /* coarse_integration_time_lsb*/
+
+		/* Mode Setting */
+		/* V: 1/2 V-addition (1,3),
+		H: 1/2 H-averaging (1,3) */
+
+		0x06, /* frame_length_lines_msb     0x0340*/
+		0x02, /* frame_length_lines_lsb     0x0341*/
+		0x10, /* line_length_pck_msb        0x0342*/
+		0x70, /* line_length_pck_lsb        0x0343*/
+		0x07, /* x_output_size_msb          0x034C*/
+		0xe0, /* x_output_size_lsb          0x034D*/
+		0x05, /* y_output_size_msb          0x034E*/
+		0xe8, /* y_output_size_lsb          0x034F*/
+		0x01, /* x_even_inc_lsb             0x0381*/
+		0x03, /* x_odd_inc_lsb              0x0383*/
+		0x01, /* y_even_inc_lsb             0x0385*/
+		0x03, /* y_odd_inc_lsb              0x0387*/
+		0x46, /* reg 0x3016 VMODEADD        0x3016*/
+		0x86, /* reg 0x30E8 HADDAVE         0x30E8*/
+		0x01, /* reg 0x3301 RGLANESEL       0x3301*/
+
+		0x00,  /* 0x0344 */
+		0x00,  /* 0x0345 */
+		0x00,  /* 0x0346 */
+		0x00,  /* 0x0347 */
+		0x0F,  /* 0x0348 */
+		0xBF,  /* 0x0349 */
+		0x0B,  /* 0x034A */
+		0xCF,  /* 0x034B */
+	},
+	{ /* Snapshot */
+		0x14, /* pll_multiplier_lsb    // 20/10 fps*/
+		/* 0x14 for pclk 96MHz at 7.5 fps */
+
+		/* Global Setting */
+		0x0B, /* coarse_integration_time_msb*/
+		0xFF, /* coarse_integration_time_lsb*/
+
+		/* Mode Setting */
+		/* Full */
+		0x0C,/*frame_length_lines_msb 0x0340*/
+		0x02,/*frame_length_lines_lsb 0x0341*/
+		0x10,/*line_length_pck_msb 0x0342*/
+		0x70,/* line_length_pck_lsb 0x0343*/
+		0x0F,/* x_output_size_msb   0x034C*/
+		0xC0, /* x_output_size_lsb  0x034D*/
+		0x0B, /* y_output_size_msb  0x034E*/
+		0xD0, /* y_output_size_lsb  0x034F*/
+		0x01, /* x_even_inc_lsb     0x0381*/
+		0x01, /* x_odd_inc_lsb      0x0383*/
+		0x01, /* y_even_inc_lsb                     0x0385*/
+		0x01, /* y_odd_inc_lsb                      0x0387*/
+		0x06, /* reg 0x3016 VMODEADD                0x3016*/
+		0x06, /* reg 0x30E8 HADDAVE                 0x30E8*/
+		0x00, /* reg 0x3301 RGLANESEL               0x3301*/
+
+		0x00,  /* 0x0344 */
+		0x00,  /* 0x0345 */
+		0x00,  /* 0x0346 */
+		0x00,  /* 0x0347 */
+		0x0F,  /* 0x0348 */
+		0xBF,  /* 0x0349 */
+		0x0B,  /* 0x034A */
+		0xCF,  /* 0x034B */
+	},
+	/* 120 fps settings */
+	{
+		0x1B, /*0x1B fps*/
+		/* Global Setting */
+		0x00, /* coarse_integration_time_msb*/
+		0xFE, /* coarse_integration_time_lsb*/
+
+		/* Mode Setting */
+		/* V: 1/8 V-addition (9,7),
+		H: Full */
+
+		0x01, /* frame_length_lines_msb     0x0340*/
+		0x01, /* frame_length_lines_lsb     0x0341*/
+		0x10, /* line_length_pck_msb        0x0342*/
+		0x70, /* line_length_pck_lsb        0x0343*/
+		0x0f, /* x_output_size_msb          0x034C*/
+		0xc0, /* x_output_size_lsb          0x034D*/
+		0x00, /* y_output_size_msb          0x034E*/
+		0xF8, /* y_output_size_lsb          0x034F*/
+		0x01, /* x_even_inc_lsb             0x0381*/
+		0x01, /* x_odd_inc_lsb              0x0383*/
+		0x09, /* y_even_inc_lsb             0x0385*/
+		0x07, /* y_odd_inc_lsb              0x0387*/
+		0x46, /* reg 0x3016 VMODEADD        0x3016*/
+		0x86, /* reg 0x30E8 HADDAVE         0x30E8*/
+		0x00, /* reg 0x3301 RGLANESEL       0x3301*/
+		/* add for 120fps support */
+		0x00, /* 0x0344*/
+		0x00, /* 0x0345*/
+		0x02, /* 0x0346*/
+		0x10, /* 0x0347*/
+		0x0F, /* 0x0348*/
+		0xBF, /* 0x0349*/
+		0x09, /* 0x034A*/
+		0xCF, /* 0x034B*/
+	}
+};
+struct sn12m0pz_reg sn12m0pz_regs = {
+	.reg_pat = &iu060f_reg_pat[0],
+	.reg_pat_init = &iu060f_reg_pat_init[0],
+};
+
diff --git a/drivers/media/video/msm/vb6801.c b/drivers/media/video/msm/vb6801.c
new file mode 100644
index 0000000..fa82570
--- /dev/null
+++ b/drivers/media/video/msm/vb6801.c
@@ -0,0 +1,1616 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <media/msm_camera.h>
+#include <mach/gpio.h>
+#include <mach/camera.h>
+#include "vb6801.h"
+
+/*=============================================================
+	SENSOR REGISTER DEFINES
+==============================================================*/
+enum {
+	REG_HOLD = 0x0104,
+	RELEASE_HOLD = 0x0000,
+	HOLD = 0x0001,
+	STANDBY_MODE = 0x0000,
+	REG_COARSE_INTEGRATION_TIME = 0x0202,
+	REG_ANALOGUE_GAIN_CODE_GLOBAL = 0x0204,
+	REG_RAMP_SCALE = 0x3116,
+	REG_POWER_MAN_ENABLE_3 = 0x3142,
+	REG_POWER_MAN_ENABLE_4 = 0x3143,
+	REG_POWER_MAN_ENABLE_5 = 0x3144,
+	REG_CCP2_DATA_FORMAT = 0x0112,
+	REG_PRE_PLL_CLK_DIV = 0x0304,
+	REG_PLL_MULTIPLIER = 0x0306,
+	REG_VT_SYS_CLK_DIV = 0x0302,
+	REG_VT_PIX_CLK_DIV = 0x0300,
+	REG_OP_SYS_CLK_DIV = 0x030A,
+	REG_OP_PIX_CLK_DIV = 0x0308,
+	REG_VT_LINE_LENGTH_PCK = 0x0342,
+	REG_X_OUTPUT_SIZE = 0x034C,
+	REG_Y_OUTPUT_SIZE = 0x034E,
+	REG_X_ODD_INC = 0x0382,
+	REG_Y_ODD_INC = 0x0386,
+	REG_VT_FRAME_LENGTH_LINES = 0x0340,
+	REG_ANALOG_TIMING_MODES_2 = 0x3113,
+	REG_BRUCE_ENABLE = 0x37B0,
+	REG_OP_CODER_SYNC_CLK_SETUP = 0x3400,
+	REG_OP_CODER_ENABLE = 0x3401,
+	REG_OP_CODER_SLOW_PAD_EN = 0x3402,
+	REG_OP_CODER_AUTO_STARTUP = 0x3414,
+	REG_SCYTHE_ENABLE = 0x3204,
+	REG_SCYTHE_WEIGHT = 0x3206,
+	REG_FRAME_COUNT = 0x0005,
+	REG_MODE_SELECT = 0x0100,
+	REG_CCP2_CHANNEL_IDENTIFIER = 0x0110,
+	REG_CCP2_SIGNALLING_MODE = 0x0111,
+	REG_BTL_LEVEL_SETUP = 0x311B,
+	REG_OP_CODER_AUTOMATIC_MODE_ENABLE = 0x3403,
+	REG_PLL_CTRL = 0x3801,
+	REG_VCM_DAC_CODE = 0x3860,
+	REG_VCM_DAC_STROBE = 0x3868,
+	REG_VCM_DAC_ENABLE = 0x386C,
+	REG_NVM_T1_ADDR_00 = 0x3600,
+	REG_NVM_T1_ADDR_01 = 0x3601,
+	REG_NVM_T1_ADDR_02 = 0x3602,
+	REG_NVM_T1_ADDR_03 = 0x3603,
+	REG_NVM_T1_ADDR_04 = 0x3604,
+	REG_NVM_T1_ADDR_05 = 0x3605,
+	REG_NVM_T1_ADDR_06 = 0x3606,
+	REG_NVM_T1_ADDR_07 = 0x3607,
+	REG_NVM_T1_ADDR_08 = 0x3608,
+	REG_NVM_T1_ADDR_09 = 0x3609,
+	REG_NVM_T1_ADDR_0A = 0x360A,
+	REG_NVM_T1_ADDR_0B = 0x360B,
+	REG_NVM_T1_ADDR_0C = 0x360C,
+	REG_NVM_T1_ADDR_0D = 0x360D,
+	REG_NVM_T1_ADDR_0E = 0x360E,
+	REG_NVM_T1_ADDR_0F = 0x360F,
+	REG_NVM_T1_ADDR_10 = 0x3610,
+	REG_NVM_T1_ADDR_11 = 0x3611,
+	REG_NVM_T1_ADDR_12 = 0x3612,
+	REG_NVM_T1_ADDR_13 = 0x3613,
+	REG_NVM_CTRL = 0x3680,
+	REG_NVM_PDN = 0x3681,
+	REG_NVM_PULSE_WIDTH = 0x368B,
+};
+
+#define VB6801_LINES_PER_FRAME_PREVIEW   800
+#define VB6801_LINES_PER_FRAME_SNAPSHOT 1600
+#define VB6801_PIXELS_PER_LINE_PREVIEW  2500
+#define VB6801_PIXELS_PER_LINE_SNAPSHOT 2500
+
+/* AF constant */
+#define VB6801_TOTAL_STEPS_NEAR_TO_FAR    25
+#define VB6801_STEPS_NEAR_TO_CLOSEST_INF  25
+
+/* for 30 fps preview */
+#define VB6801_DEFAULT_CLOCK_RATE    12000000
+
+enum vb6801_test_mode_t {
+	TEST_OFF,
+	TEST_1,
+	TEST_2,
+	TEST_3
+};
+
+enum vb6801_resolution_t {
+	QTR_SIZE,
+	FULL_SIZE,
+	INVALID_SIZE
+};
+
+enum vb6801_setting_t {
+	RES_PREVIEW,
+	RES_CAPTURE
+};
+
+struct vb6801_work_t {
+	struct work_struct work;
+};
+
+struct sensor_dynamic_params_t {
+	uint16_t preview_pixelsPerLine;
+	uint16_t preview_linesPerFrame;
+	uint16_t snapshot_pixelsPerLine;
+	uint16_t snapshot_linesPerFrame;
+	uint8_t snapshot_changed_fps;
+	uint32_t pclk;
+};
+
+struct vb6801_sensor_info {
+	/* Sensor Configuration Input Parameters */
+	uint32_t ext_clk_freq_mhz;
+	uint32_t target_frame_rate_fps;
+	uint32_t target_vt_pix_clk_freq_mhz;
+	uint32_t sub_sampling_factor;
+	uint32_t analog_binning_allowed;
+	uint32_t raw_mode;
+	uint32_t capture_mode;
+
+	/* Image Readout Registers */
+	uint32_t x_odd_inc;	/* x pixel array addressing odd increment */
+	uint32_t y_odd_inc;	/* y pixel array addressing odd increment */
+	uint32_t x_output_size;	/* width of output image  */
+	uint32_t y_output_size;	/* height of output image */
+
+	/* Declare data format */
+	uint32_t ccp2_data_format;
+
+	/* Clock Tree Registers */
+	uint32_t pre_pll_clk_div;
+	uint32_t pll_multiplier;
+	uint32_t vt_sys_clk_div;
+	uint32_t vt_pix_clk_div;
+	uint32_t op_sys_clk_div;
+	uint32_t op_pix_clk_div;
+
+	/* Video Timing Registers */
+	uint32_t vt_line_length_pck;
+	uint32_t vt_frame_length_lines;
+
+	/* Analogue Binning Registers */
+	uint8_t vtiming_major;
+	uint8_t analog_timing_modes_4;
+
+	/* Fine (pixel) Integration Time Registers */
+	uint32_t fine_integration_time;
+
+	/* Coarse (lines) Integration Time Limit Registers */
+	uint32_t coarse_integration_time_max;
+
+	/* Coarse (lines) Integration Timit Register (16-bit) */
+	uint32_t coarse_integration_time;
+
+	/* Analogue Gain Code Global Registers */
+	uint32_t analogue_gain_code_global;
+
+	/* Digital Gain Code Registers */
+	uint32_t digital_gain_code;
+
+	/* Overall gain (analogue & digital) code
+	 * Note that this is not a real register but just
+	 * an abstraction for the combination of analogue
+	 * and digital gain */
+	uint32_t gain_code;
+
+	/* FMT Test Information */
+	uint32_t pass_fail;
+	uint32_t day;
+	uint32_t month;
+	uint32_t year;
+	uint32_t tester;
+	uint32_t part_number;
+
+	/* Autofocus controls */
+	uint32_t vcm_dac_code;
+	int vcm_max_dac_code_step;
+	int vcm_proportional_factor;
+	int vcm_dac_code_spacing_ms;
+
+	/* VCM NVM Characterisation Information */
+	uint32_t vcm_dac_code_infinity_dn;
+	uint32_t vcm_dac_code_macro_up;
+	uint32_t vcm_dac_code_up_dn_delta;
+
+	/* Internal Variables */
+	uint32_t min_vt_frame_length_lines;
+};
+
+struct vb6801_work_t *vb6801_sensorw;
+struct i2c_client *vb6801_client;
+
+struct vb6801_ctrl_t {
+	const struct msm_camera_sensor_info *sensordata;
+
+	int sensormode;
+	uint32_t factor_fps;	/* init to 1 * 0x00000400 */
+	uint16_t curr_fps;
+	uint16_t max_fps;
+	int8_t pict_exp_update;
+	int8_t reducel;
+	uint16_t curr_lens_pos;
+	uint16_t init_curr_lens_pos;
+	enum vb6801_resolution_t prev_res;
+	enum vb6801_resolution_t pict_res;
+	enum vb6801_resolution_t curr_res;
+	enum vb6801_test_mode_t set_test;
+
+	struct vb6801_sensor_info s_info;
+	struct sensor_dynamic_params_t s_dynamic_params;
+};
+
+static struct vb6801_ctrl_t *vb6801_ctrl;
+static DECLARE_WAIT_QUEUE_HEAD(vb6801_wait_queue);
+DEFINE_MUTEX(vb6801_mut);
+
+static int vb6801_i2c_rxdata(unsigned short saddr,
+			     unsigned char *rxdata, int length)
+{
+	struct i2c_msg msgs[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = 2,
+			.buf = rxdata,
+		},
+		{
+			.addr = saddr,
+			.flags = I2C_M_RD,
+			.len = 2,
+			.buf = rxdata,
+		},
+	};
+
+	if (i2c_transfer(vb6801_client->adapter, msgs, 2) < 0) {
+		CDBG("vb6801_i2c_rxdata failed!\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t vb6801_i2c_read(unsigned short raddr,
+			       unsigned short *rdata, int rlen)
+{
+	int32_t rc = 0;
+	unsigned char buf[2];
+
+	if (!rdata)
+		return -EIO;
+
+	memset(buf, 0, sizeof(buf));
+
+	buf[0] = (raddr & 0xFF00) >> 8;
+	buf[1] = (raddr & 0x00FF);
+
+	rc = vb6801_i2c_rxdata(vb6801_client->addr, buf, rlen);
+
+	if (rc < 0) {
+		CDBG("vb6801_i2c_read 0x%x failed!\n", raddr);
+		return rc;
+	}
+
+	*rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]);
+
+	return rc;
+}
+
+static int32_t vb6801_i2c_read_table(struct vb6801_i2c_reg_conf_t *regs,
+				     int items)
+{
+	int i;
+	int32_t rc = -EFAULT;
+
+	for (i = 0; i < items; i++) {
+		unsigned short *buf =
+		    regs->dlen == D_LEN_BYTE ?
+		    (unsigned short *)&regs->bdata :
+		    (unsigned short *)&regs->wdata;
+		rc = vb6801_i2c_read(regs->waddr, buf, regs->dlen + 1);
+
+		if (rc < 0) {
+			CDBG("vb6801_i2c_read_table Failed!!!\n");
+			break;
+		}
+
+		regs++;
+	}
+
+	return rc;
+}
+
+static int32_t vb6801_i2c_txdata(unsigned short saddr,
+				 unsigned char *txdata, int length)
+{
+	struct i2c_msg msg[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = length,
+			.buf = txdata,
+		},
+	};
+
+	if (i2c_transfer(vb6801_client->adapter, msg, 1) < 0) {
+		CDBG("vb6801_i2c_txdata faild 0x%x\n", vb6801_client->addr);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t vb6801_i2c_write_b(unsigned short waddr, uint8_t bdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[3];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = bdata;
+
+	CDBG("i2c_write_b addr = %d, val = %d\n", waddr, bdata);
+	rc = vb6801_i2c_txdata(vb6801_client->addr, buf, 3);
+
+	if (rc < 0) {
+		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+		     waddr, bdata);
+	}
+
+	return rc;
+}
+
+static int32_t vb6801_i2c_write_w(unsigned short waddr, unsigned short wdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[4];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = (wdata & 0xFF00) >> 8;
+	buf[3] = (wdata & 0x00FF);
+
+	CDBG("i2c_write_w addr = %d, val = %d, buf[2] = 0x%x, buf[3] = 0x%x\n",
+	     waddr, wdata, buf[2], buf[3]);
+
+	rc = vb6801_i2c_txdata(vb6801_client->addr, buf, 4);
+	if (rc < 0) {
+		CDBG("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n",
+		     waddr, wdata);
+	}
+
+	return rc;
+}
+
+static int32_t vb6801_i2c_write_table(struct vb6801_i2c_reg_conf_t *regs,
+				      int items)
+{
+	int i;
+	int32_t rc = -EFAULT;
+
+	for (i = 0; i < items; i++) {
+		rc = ((regs->dlen == D_LEN_BYTE) ?
+		      vb6801_i2c_write_b(regs->waddr, regs->bdata) :
+		      vb6801_i2c_write_w(regs->waddr, regs->wdata));
+
+		if (rc < 0) {
+			CDBG("vb6801_i2c_write_table Failed!!!\n");
+			break;
+		}
+
+		regs++;
+	}
+
+	return rc;
+}
+
+static int32_t vb6801_reset(const struct msm_camera_sensor_info *data)
+{
+	int rc;
+
+	rc = gpio_request(data->sensor_reset, "vb6801");
+	if (!rc) {
+		CDBG("sensor_reset SUcceeded\n");
+		gpio_direction_output(data->sensor_reset, 0);
+		mdelay(50);
+		gpio_direction_output(data->sensor_reset, 1);
+		mdelay(13);
+	} else
+		CDBG("sensor_reset FAiled\n");
+
+	return rc;
+}
+
+static int32_t vb6801_set_default_focus(void)
+{
+	int32_t rc = 0;
+
+	/* FIXME: Default focus not supported */
+
+	return rc;
+}
+
+static void vb6801_get_pict_fps(uint16_t fps, uint16_t *pfps)
+{
+	/* input fps is preview fps in Q8 format */
+	uint32_t divider; /*Q10 */
+	uint32_t pclk_mult; /*Q10 */
+	uint32_t d1;
+	uint32_t d2;
+
+	d1 =
+		(uint32_t)(
+		(vb6801_ctrl->s_dynamic_params.preview_linesPerFrame *
+		0x00000400) /
+		vb6801_ctrl->s_dynamic_params.snapshot_linesPerFrame);
+
+	d2 =
+		(uint32_t)(
+		(vb6801_ctrl->s_dynamic_params.preview_pixelsPerLine *
+		0x00000400) /
+		vb6801_ctrl->s_dynamic_params.snapshot_pixelsPerLine);
+
+
+	divider = (uint32_t) (d1 * d2) / 0x00000400;
+
+	pclk_mult = (48 * 0x400) / 60;
+
+	/* Verify PCLK settings and frame sizes. */
+	*pfps = (uint16_t)((((fps * pclk_mult) / 0x00000400) * divider)/
+				0x00000400);
+}
+
+static uint16_t vb6801_get_prev_lines_pf(void)
+{
+	if (vb6801_ctrl->prev_res == QTR_SIZE)
+		return vb6801_ctrl->s_dynamic_params.preview_linesPerFrame;
+	else
+		return vb6801_ctrl->s_dynamic_params.snapshot_linesPerFrame;
+}
+
+static uint16_t vb6801_get_prev_pixels_pl(void)
+{
+	if (vb6801_ctrl->prev_res == QTR_SIZE)
+		return vb6801_ctrl->s_dynamic_params.preview_pixelsPerLine;
+	else
+		return vb6801_ctrl->s_dynamic_params.snapshot_pixelsPerLine;
+}
+
+static uint16_t vb6801_get_pict_lines_pf(void)
+{
+	return vb6801_ctrl->s_dynamic_params.snapshot_linesPerFrame;
+}
+
+static uint16_t vb6801_get_pict_pixels_pl(void)
+{
+	return vb6801_ctrl->s_dynamic_params.snapshot_pixelsPerLine;
+}
+
+static uint32_t vb6801_get_pict_max_exp_lc(void)
+{
+	uint16_t snapshot_lines_per_frame;
+
+	if (vb6801_ctrl->pict_res == QTR_SIZE) {
+		snapshot_lines_per_frame =
+		    vb6801_ctrl->s_dynamic_params.preview_linesPerFrame - 3;
+	} else {
+		snapshot_lines_per_frame =
+		    vb6801_ctrl->s_dynamic_params.snapshot_linesPerFrame - 3;
+	}
+
+	return snapshot_lines_per_frame;
+}
+
+static int32_t vb6801_set_fps(struct fps_cfg *fps)
+{
+	int32_t rc = 0;
+
+	/* input is new fps in Q8 format */
+	switch (fps->fps_div) {
+	case 7680:		/* 30 * Q8 */
+		vb6801_ctrl->factor_fps = 1;
+		break;
+
+	case 3840:		/* 15 * Q8 */
+		vb6801_ctrl->factor_fps = 2;
+		break;
+
+	case 2560:		/* 10 * Q8 */
+		vb6801_ctrl->factor_fps = 3;
+		break;
+
+	case 1920:		/* 7.5 * Q8 */
+		vb6801_ctrl->factor_fps = 4;
+		break;
+
+	default:
+		rc = -ENODEV;
+		break;
+	}
+
+	return rc;
+}
+
+static int32_t vb6801_write_exp_gain(uint16_t gain, uint32_t line)
+{
+	int32_t rc = 0;
+	uint16_t lpf;
+
+	if (vb6801_ctrl->curr_res == SENSOR_FULL_SIZE)
+		lpf = VB6801_LINES_PER_FRAME_SNAPSHOT;
+	else
+		lpf = VB6801_LINES_PER_FRAME_PREVIEW;
+
+	/* hold */
+	rc = vb6801_i2c_write_w(REG_HOLD, HOLD);
+	if (rc < 0)
+		goto exp_gain_done;
+
+	if ((vb6801_ctrl->curr_fps <
+	     vb6801_ctrl->max_fps / vb6801_ctrl->factor_fps) &&
+	    (!vb6801_ctrl->pict_exp_update)) {
+
+		if (vb6801_ctrl->reducel) {
+
+			rc = vb6801_i2c_write_w(REG_VT_FRAME_LENGTH_LINES,
+						lpf * vb6801_ctrl->factor_fps);
+
+			vb6801_ctrl->curr_fps =
+			    vb6801_ctrl->max_fps / vb6801_ctrl->factor_fps;
+
+		} else if (!vb6801_ctrl->reducel) {
+
+			rc = vb6801_i2c_write_w(REG_COARSE_INTEGRATION_TIME,
+						line * vb6801_ctrl->factor_fps);
+
+			vb6801_ctrl->reducel = 1;
+		}
+	} else if ((vb6801_ctrl->curr_fps >
+		    vb6801_ctrl->max_fps / vb6801_ctrl->factor_fps) &&
+		   (!vb6801_ctrl->pict_exp_update)) {
+
+		rc = vb6801_i2c_write_w(REG_VT_FRAME_LENGTH_LINES,
+					lpf * vb6801_ctrl->factor_fps);
+
+		vb6801_ctrl->curr_fps =
+		    vb6801_ctrl->max_fps / vb6801_ctrl->factor_fps;
+
+	} else {
+		/* analogue_gain_code_global */
+		rc = vb6801_i2c_write_w(REG_ANALOGUE_GAIN_CODE_GLOBAL, gain);
+		if (rc < 0)
+			goto exp_gain_done;
+
+		/* coarse_integration_time */
+		rc = vb6801_i2c_write_w(REG_COARSE_INTEGRATION_TIME,
+					line * vb6801_ctrl->factor_fps);
+		if (rc < 0)
+			goto exp_gain_done;
+
+		vb6801_ctrl->pict_exp_update = 1;
+	}
+
+	rc = vb6801_i2c_write_w(REG_HOLD, RELEASE_HOLD);
+
+exp_gain_done:
+	return rc;
+}
+
+static int32_t vb6801_set_pict_exp_gain(uint16_t gain, uint32_t line)
+{
+	vb6801_ctrl->pict_exp_update = 1;
+	return vb6801_write_exp_gain(gain, line);
+}
+
+static int32_t vb6801_power_down(void)
+{
+	int32_t rc = 0;
+	rc = vb6801_i2c_write_b(REG_NVM_PDN, 0);
+
+	mdelay(5);
+	return rc;
+}
+
+static int32_t vb6801_go_to_position(uint32_t target_vcm_dac_code,
+				     struct vb6801_sensor_info *ps)
+{
+	/* Prior to running this function the following values must
+	 * be initialised in the sensor data structure, PS
+	 * ps->vcm_dac_code
+	 * ps->vcm_max_dac_code_step
+	 * ps->vcm_dac_code_spacing_ms */
+
+	int32_t rc = 0;
+
+	ps->vcm_dac_code = target_vcm_dac_code;
+
+	/* Restore Strobe to zero state */
+	rc = vb6801_i2c_write_b(REG_VCM_DAC_STROBE, 0x00);
+	if (rc < 0)
+		return rc;
+
+	/* Write 9-bit VCM DAC Code */
+	rc = vb6801_i2c_write_w(REG_VCM_DAC_CODE, ps->vcm_dac_code);
+	if (rc < 0)
+		return rc;
+
+	/* Generate a rising edge on the dac_strobe to latch
+	 * new DAC value */
+
+	rc = vb6801_i2c_write_w(REG_VCM_DAC_STROBE, 0x01);
+
+	return rc;
+}
+
+static int32_t vb6801_move_focus(int direction, int32_t num_steps)
+{
+	int16_t step_direction;
+	int16_t actual_step;
+	int16_t next_position;
+	uint32_t step_size;
+	int16_t small_move[4];
+	uint16_t i;
+	int32_t rc = 0;
+
+	step_size = (vb6801_ctrl->s_info.vcm_dac_code_macro_up -
+		     vb6801_ctrl->s_info.vcm_dac_code_infinity_dn) /
+	    VB6801_TOTAL_STEPS_NEAR_TO_FAR;
+
+	if (num_steps > VB6801_TOTAL_STEPS_NEAR_TO_FAR)
+		num_steps = VB6801_TOTAL_STEPS_NEAR_TO_FAR;
+	else if (num_steps == 0)
+		return -EINVAL;
+
+	if (direction == MOVE_NEAR)
+		step_direction = 4;
+	else if (direction == MOVE_FAR)
+		step_direction = -4;
+	else
+		return -EINVAL;
+
+	/* need to decide about default position and power supplied
+	 * at start up and reset */
+	if (vb6801_ctrl->curr_lens_pos < vb6801_ctrl->init_curr_lens_pos)
+		vb6801_ctrl->curr_lens_pos = vb6801_ctrl->init_curr_lens_pos;
+
+	actual_step = (step_direction * num_steps);
+
+	next_position = vb6801_ctrl->curr_lens_pos;
+
+	for (i = 0; i < 4; i++) {
+		if (actual_step >= 0)
+			small_move[i] =
+			    (i + 1) * actual_step / 4 - i * actual_step / 4;
+
+		if (actual_step < 0)
+			small_move[i] =
+			    (i + 1) * actual_step / 4 - i * actual_step / 4;
+	}
+
+	if (next_position > 511)
+		next_position = 511;
+	else if (next_position < 0)
+		next_position = 0;
+
+	/* for damping */
+	for (i = 0; i < 4; i++) {
+		next_position =
+		    (int16_t) (vb6801_ctrl->curr_lens_pos + small_move[i]);
+
+		/* Writing the digital code for current to the actuator */
+		CDBG("next_position in damping mode = %d\n", next_position);
+
+		rc = vb6801_go_to_position(next_position, &vb6801_ctrl->s_info);
+		if (rc < 0) {
+			CDBG("go_to_position Failed!!!\n");
+			return rc;
+		}
+
+		vb6801_ctrl->curr_lens_pos = next_position;
+		if (i < 3)
+			mdelay(5);
+	}
+
+	return rc;
+}
+
+static int vb6801_read_nvm_data(struct vb6801_sensor_info *ps)
+{
+	/* +--------+------+------+----------------+---------------+
+	 * | Index | NVM | NVM | Name | Description |
+	 * | | Addr | Byte | | |
+	 * +--------+------+------+----------------+---------------+
+	 * | 0x3600 | 0 | 3 | nvm_t1_addr_00 | {PF[2:0]:Day[4:0]} |
+	 * | 0x3601 | 0 | 2 | nvm_t1_addr_01 | {Month[3:0]:Year[3:0]} |
+	 * | 0x3602 | 0 | 1 | nvm_t1_addr_02 | Tester[7:0] |
+	 * | 0x3603 | 0 | 0 | nvm_t1_addr_03 | Part[15:8] |
+	 * +--------+------+------+----------------+---------------+
+	 * | 0x3604 | 1 | 3 | nvm_t1_addr_04 | Part[7:0] |
+	 * | 0x3605 | 1 | 2 | nvm_t1_addr_05 | StartWPM[7:0] |
+	 * | 0x3606 | 1 | 1 | nvm_t1_addr_06 | Infinity[7:0] |
+	 * | 0x3607 | 1 | 0 | nvm_t1_addr_07 | Macro[7:0] |
+	 * +--------+------+------+----------------+---------------+
+	 * | 0x3608 | 2 | 3 | nvm_t1_addr_08 | Reserved |
+	 * | 0x3609 | 2 | 2 | nvm_t1_addr_09 | Reserved |
+	 * | 0x360A | 2 | 1 | nvm_t1_addr_0A | UpDown[7:0] |
+	 * | 0x360B | 2 | 0 | nvm_t1_addr_0B | Reserved |
+	 * +--------+------+------+----------------+---------------+
+	 * | 0x360C | 3 | 3 | nvm_t1_addr_0C | Reserved |
+	 * | 0x360D | 3 | 2 | nvm_t1_addr_0D | Reserved |
+	 * | 0x360E | 3 | 1 | nvm_t1_addr_0E | Reserved |
+	 * | 0x360F | 3 | 0 | nvm_t1_addr_0F | Reserved |
+	 * +--------+------+------+----------------+---------------+
+	 * | 0x3610 | 4 | 3 | nvm_t1_addr_10 | Reserved |
+	 * | 0x3611 | 4 | 2 | nvm_t1_addr_11 | Reserved |
+	 * | 0x3612 | 4 | 1 | nvm_t1_addr_12 | Reserved |
+	 * | 0x3613 | 4 | 0 | nvm_t1_addr_13 | Reserved |
+	 * +--------+------+------+----------------+---------------+*/
+
+	int32_t rc;
+	struct vb6801_i2c_reg_conf_t rreg[] = {
+		{REG_NVM_T1_ADDR_00, 0, 0, D_LEN_BYTE},
+		{REG_NVM_T1_ADDR_01, 0, 0, D_LEN_BYTE},
+		{REG_NVM_T1_ADDR_02, 0, 0, D_LEN_BYTE},
+		{REG_NVM_T1_ADDR_03, 0, 0, D_LEN_BYTE},
+		{REG_NVM_T1_ADDR_04, 0, 0, D_LEN_BYTE},
+		{REG_NVM_T1_ADDR_05, 0, 0, D_LEN_BYTE},
+		{REG_NVM_T1_ADDR_06, 0, 0, D_LEN_BYTE},
+		{REG_NVM_T1_ADDR_07, 0, 0, D_LEN_BYTE},
+		{REG_NVM_T1_ADDR_08, 0, 0, D_LEN_BYTE},
+		{REG_NVM_T1_ADDR_09, 0, 0, D_LEN_BYTE},
+		{REG_NVM_T1_ADDR_0A, 0, 0, D_LEN_BYTE},
+		{REG_NVM_T1_ADDR_0B, 0, 0, D_LEN_BYTE},
+		{REG_NVM_T1_ADDR_0C, 0, 0, D_LEN_BYTE},
+		{REG_NVM_T1_ADDR_0D, 0, 0, D_LEN_BYTE},
+		{REG_NVM_T1_ADDR_0E, 0, 0, D_LEN_BYTE},
+		{REG_NVM_T1_ADDR_0F, 0, 0, D_LEN_BYTE},
+		{REG_NVM_T1_ADDR_10, 0, 0, D_LEN_BYTE},
+		{REG_NVM_T1_ADDR_11, 0, 0, D_LEN_BYTE},
+		{REG_NVM_T1_ADDR_12, 0, 0, D_LEN_BYTE},
+		{REG_NVM_T1_ADDR_13, 0, 0, D_LEN_BYTE},
+	};
+
+	struct vb6801_i2c_reg_conf_t wreg[] = {
+		/* Enable NVM for Direct Reading */
+		{REG_NVM_CTRL, 0, 2, D_LEN_BYTE},
+
+		/* Power up NVM */
+		{REG_NVM_PDN, 0, 1, D_LEN_BYTE},
+	};
+
+	rc = vb6801_i2c_write_table(wreg, ARRAY_SIZE(wreg));
+	if (rc < 0) {
+		CDBG("I2C Write Table FAILED!!!\n");
+		return rc;
+	}
+
+	/* NVM Read Pulse Width
+	 * ====================
+	 * nvm_pulse_width_us = nvm_pulse_width_ext_clk / ext_clk_freq_mhz
+	 * Valid Range for Read Pulse Width = 400ns -> 3.0us
+	 * Min ext_clk_freq_mhz = 6MHz  => 3.0 *  6  = 18
+	 * Max ext_clk_freq_mhz = 27MHz => 0.4 * 27 = 10.8
+	 * Choose 15 as a common value
+	 *  - 15 /  6.0 = 2.5000us
+	 *  - 15 / 12.0 = 1.2500us
+	 *  - 15 / 27.0 = 0.5555us */
+	rc = vb6801_i2c_write_w(REG_NVM_PULSE_WIDTH, 15);
+	if (rc < 0) {
+		rc = -EBUSY;
+		goto nv_shutdown;
+	}
+
+	rc = vb6801_i2c_read_table(rreg, ARRAY_SIZE(rreg));
+	if (rc < 0) {
+		CDBG("I2C Read Table FAILED!!!\n");
+		rc = -EBUSY;
+		goto nv_shutdown;
+	}
+
+	/* Decode and Save FMT Info */
+	ps->pass_fail = (rreg[0].bdata & 0x00E0) >> 5;
+	ps->day = (rreg[0].bdata & 0x001F);
+	ps->month = (rreg[1].bdata & 0x00F0) >> 4;
+	ps->year = (rreg[1].bdata & 0x000F) + 2000;
+	ps->tester = rreg[2].bdata;
+	ps->part_number = (rreg[3].bdata << 8) + rreg[4].bdata;
+
+	/* Decode and Save VCM Dac Values in data structure */
+	ps->vcm_dac_code_infinity_dn = rreg[6].bdata;
+	ps->vcm_dac_code_macro_up = rreg[7].bdata << 1;
+	ps->vcm_dac_code_up_dn_delta = rreg[10].bdata;
+
+nv_shutdown:
+	/* Power Down NVM to extend life time */
+	rc = vb6801_i2c_write_b(REG_NVM_PDN, 0);
+
+	return rc;
+}
+
+static int vb6801_config_sensor(int32_t ext_clk_freq_mhz,
+				int32_t target_frame_rate_fps,
+				int32_t target_vt_pix_clk_freq_mhz,
+				uint32_t sub_sampling_factor,
+				uint32_t analog_binning_allowed,
+				uint32_t raw_mode, int capture_mode,
+				enum vb6801_resolution_t res)
+{
+	uint32_t rc;
+	/* ext_clk_freq_mhz      = 6.0 -> 27.0 MHz
+	 * target_frame_rate_fps  = 15 fps
+	 * target_vt_pix_clk_freq_mhz = 24.0 -> 64.0MHz
+	 * sub_sampling factor   = 1, 2, 3, or 4
+	 * raw_mode factor       = 10
+	 *
+	 * capture_mode, 0 = CCP1
+	 * capture_mode, 1 = CCP2
+	 * capture_mode, 2 = 10-bit parallel + hsync + vsync */
+
+	/* Declare data format */
+	uint32_t ccp2_data_format = 0x0A0A;
+
+	/*  Declare clock tree variables */
+	int32_t min_pll_ip_freq_mhz = 6;
+	int32_t max_pll_op_freq_mhz = 640;
+	uint32_t pre_pll_clk_div = 1;
+	int32_t pll_ip_freq_mhz = 6;
+	uint32_t pll_multiplier = 100;
+	int32_t pll_op_freq_mhz = 600;
+	uint32_t vt_sys_clk_div = 1;
+	int32_t vt_sys_clk_freq_mhz = 600;
+	uint32_t vt_pix_clk_div = 10;
+	int32_t vt_pix_clk_freq_mhz = 60;
+	uint32_t op_sys_clk_div = 1;
+	int32_t op_sys_clk_freq_mhz = 60;
+	uint32_t op_pix_clk_div = 10;
+	int32_t op_pix_clk_freq_mhz = 60;
+
+	/* Declare pixel array and frame timing variables */
+	uint32_t x_pixel_array = 2064;
+	uint32_t y_pixel_array = 1544;
+	uint32_t x_even_inc = 1;
+	uint32_t x_odd_inc = 1;
+	uint32_t y_even_inc = 1;
+	uint32_t y_odd_inc = 1;
+	uint32_t x_output_size = 2064;
+	uint32_t y_output_size = 1544;
+	uint32_t additional_rows = 2;
+	uint32_t min_vt_frame_blanking_lines = 16;
+	uint32_t vt_line_length_pck = 2500;
+	uint32_t vt_line_length_us = 0;
+	uint32_t min_vt_frame_length_lines = 1562;
+	uint32_t vt_frame_length_lines = 1600;
+	uint32_t target_vt_frame_length_ms;	/* 200 * 0x0001000 / 3; */
+	uint32_t vt_frame_length_ms;	/* 200 * 0x0001000 / 3; */
+	uint32_t frame_rate_fps = 15;
+
+	/* Coarse intergration time */
+	uint32_t coarse_integration_time = 1597;
+	uint32_t coarse_integration_time_max_margin = 3;
+	uint16_t frame_count;
+	int timeout;
+
+	struct vb6801_sensor_info *pinfo = &vb6801_ctrl->s_info;
+
+	struct vb6801_i2c_reg_conf_t rreg[] = {
+		{REG_PRE_PLL_CLK_DIV, 0, 0, D_LEN_WORD},
+		{REG_PLL_MULTIPLIER, 0, 0, D_LEN_WORD},
+		{REG_VT_SYS_CLK_DIV, 0, 0, D_LEN_WORD},
+		{REG_VT_PIX_CLK_DIV, 0, 0, D_LEN_WORD},
+		{REG_OP_SYS_CLK_DIV, 0, 0, D_LEN_WORD},
+		{REG_OP_PIX_CLK_DIV, 0, 0, D_LEN_WORD},
+		{REG_FRAME_COUNT, 0, 0, D_LEN_BYTE},
+	};
+
+	struct vb6801_i2c_reg_conf_t wreg2[] = {
+		{REG_POWER_MAN_ENABLE_3, 0, 95, D_LEN_BYTE},
+		{REG_POWER_MAN_ENABLE_4, 0, 142, D_LEN_BYTE},
+		{REG_POWER_MAN_ENABLE_5, 0, 7, D_LEN_BYTE},
+	};
+
+	/* VIDEO TIMING CALCULATIONS
+	 * ========================= */
+
+	/* Pixel Array Size */
+	x_pixel_array = 2064;
+	y_pixel_array = 1544;
+
+	/* set current resolution */
+	vb6801_ctrl->curr_res = res;
+
+	/* Analogue binning setup */
+	if (pinfo->analog_binning_allowed > 0 &&
+	    pinfo->sub_sampling_factor == 4) {
+
+		pinfo->vtiming_major = 1;
+		pinfo->analog_timing_modes_4 = 32;
+	} else if (pinfo->analog_binning_allowed > 0 &&
+		   pinfo->sub_sampling_factor == 2) {
+
+		pinfo->vtiming_major = 1;
+		pinfo->analog_timing_modes_4 = 0;
+	} else {
+
+		pinfo->vtiming_major = 0;
+		pinfo->analog_timing_modes_4 = 0;
+	}
+
+	/* Sub-Sampling X & Y Odd Increments: valid values 1, 3, 5, 7 */
+	x_even_inc = 1;
+	y_even_inc = 1;
+	x_odd_inc = (sub_sampling_factor << 1) - x_even_inc;
+	y_odd_inc = (sub_sampling_factor << 1) - y_even_inc;
+
+	/* Output image size
+	 * Must always be a multiple of 2 - round down */
+	x_output_size = ((x_pixel_array / sub_sampling_factor) >> 1) << 1;
+	y_output_size = ((y_pixel_array / sub_sampling_factor) >> 1) << 1;
+
+	/* Output data format */
+	ccp2_data_format = (raw_mode << 8) + raw_mode;
+
+	/* Pre PLL clock divider : valid values 1, 2 or 4
+	 * The 1st step is to ensure that PLL input frequency is as close
+	 * as possible to the min allowed PLL input frequency.
+	 * This yields the smallest step size in the PLL output frequency. */
+	pre_pll_clk_div =
+	    ((int)(ext_clk_freq_mhz / min_pll_ip_freq_mhz) >> 1) << 1;
+	if (pre_pll_clk_div < 2)
+		pre_pll_clk_div = 1;
+
+	pll_ip_freq_mhz = ext_clk_freq_mhz / pre_pll_clk_div;
+
+	/* Video Timing System Clock divider: valid values 1, 2, 4
+	 * Now need to work backwards through the clock tree to determine the
+	 * 1st pass estimates for vt_sys_clk_freq_mhz and then the PLL output
+	 * frequency.*/
+	vt_sys_clk_freq_mhz = vt_pix_clk_div * target_vt_pix_clk_freq_mhz;
+	vt_sys_clk_div = max_pll_op_freq_mhz / vt_sys_clk_freq_mhz;
+	if (vt_sys_clk_div < 2)
+		vt_sys_clk_div = 1;
+
+	/* PLL Mulitplier: min , max 106 */
+	pll_op_freq_mhz = vt_sys_clk_div * vt_sys_clk_freq_mhz;
+	pll_multiplier = (pll_op_freq_mhz * 0x0001000) / pll_ip_freq_mhz;
+
+	/* Calculate the acutal pll output frequency
+	 * - the pll_multiplier calculation introduces a quantisation error
+	 *   due the integer nature of the pll multiplier */
+	pll_op_freq_mhz = (pll_ip_freq_mhz * pll_multiplier) / 0x0001000;
+
+	/* Re-calculate video timing clock frequencies based
+	 * on actual PLL freq */
+	vt_sys_clk_freq_mhz = pll_op_freq_mhz / vt_sys_clk_div;
+	vt_pix_clk_freq_mhz = ((vt_sys_clk_freq_mhz * 0x0001000) /
+				vt_pix_clk_div)/0x0001000;
+
+	/* Output System Clock Divider: valid value 1, 2, 4, 6, 8
+	 * op_sys_clk_div = vt_sys_clk_div;*/
+	op_sys_clk_div = (vt_sys_clk_div * sub_sampling_factor);
+	if (op_sys_clk_div < 2)
+		op_sys_clk_div = 1;
+
+	/* Calculate output timing clock frequencies */
+	op_sys_clk_freq_mhz = pll_op_freq_mhz / op_sys_clk_div;
+	op_pix_clk_freq_mhz =
+	    (op_sys_clk_freq_mhz * 0x0001000) / (op_pix_clk_div * 0x0001000);
+
+	/* Line length in pixels and us */
+	vt_line_length_pck = 2500;
+	vt_line_length_us =
+	    vt_line_length_pck * 0x0001000 / vt_pix_clk_freq_mhz;
+
+	/* Target vt_frame_length_ms */
+	target_vt_frame_length_ms = (1000 * 0x0001000 / target_frame_rate_fps);
+
+	/* Frame length in lines */
+	min_vt_frame_length_lines =
+	    additional_rows + y_output_size + min_vt_frame_blanking_lines;
+
+	vt_frame_length_lines =
+	    ((1000 * target_vt_frame_length_ms) / vt_line_length_us);
+
+	if (vt_frame_length_lines <= min_vt_frame_length_lines)
+		vt_frame_length_lines = min_vt_frame_length_lines;
+
+	/* Calcuate the actual frame length in ms */
+	vt_frame_length_ms = (vt_frame_length_lines * vt_line_length_us / 1000);
+
+	/* Frame Rate in fps */
+	frame_rate_fps = (1000 * 0x0001000 / vt_frame_length_ms);
+
+	/* Set coarse integration to max */
+	coarse_integration_time =
+	    vt_frame_length_lines - coarse_integration_time_max_margin;
+
+	CDBG("SENSOR VIDEO TIMING SUMMARY:\n");
+	CDBG(" ============================\n");
+	CDBG("ext_clk_freq_mhz      = %d\n", ext_clk_freq_mhz);
+	CDBG("pre_pll_clk_div       = %d\n", pre_pll_clk_div);
+	CDBG("pll_ip_freq_mhz       = %d\n", pll_ip_freq_mhz);
+	CDBG("pll_multiplier        = %d\n", pll_multiplier);
+	CDBG("pll_op_freq_mhz       = %d\n", pll_op_freq_mhz);
+	CDBG("vt_sys_clk_div        = %d\n", vt_sys_clk_div);
+	CDBG("vt_sys_clk_freq_mhz   = %d\n", vt_sys_clk_freq_mhz);
+	CDBG("vt_pix_clk_div        = %d\n", vt_pix_clk_div);
+	CDBG("vt_pix_clk_freq_mhz   = %d\n", vt_pix_clk_freq_mhz);
+	CDBG("op_sys_clk_div        = %d\n", op_sys_clk_div);
+	CDBG("op_sys_clk_freq_mhz   = %d\n", op_sys_clk_freq_mhz);
+	CDBG("op_pix_clk_div        = %d\n", op_pix_clk_div);
+	CDBG("op_pix_clk_freq_mhz   = %d\n", op_pix_clk_freq_mhz);
+	CDBG("vt_line_length_pck    = %d\n", vt_line_length_pck);
+	CDBG("vt_line_length_us     = %d\n", vt_line_length_us/0x0001000);
+	CDBG("vt_frame_length_lines = %d\n", vt_frame_length_lines);
+	CDBG("vt_frame_length_ms    = %d\n", vt_frame_length_ms/0x0001000);
+	CDBG("frame_rate_fps        = %d\n", frame_rate_fps);
+	CDBG("ccp2_data_format = %d\n", ccp2_data_format);
+	CDBG("x_output_size = %d\n", x_output_size);
+	CDBG("y_output_size = %d\n", y_output_size);
+	CDBG("x_odd_inc = %d\n", x_odd_inc);
+	CDBG("y_odd_inc = %d\n", y_odd_inc);
+	CDBG("(vt_frame_length_lines * frame_rate_factor ) = %d\n",
+	    (vt_frame_length_lines * vb6801_ctrl->factor_fps));
+	CDBG("coarse_integration_time = %d\n", coarse_integration_time);
+	CDBG("pinfo->vcm_dac_code = %d\n", pinfo->vcm_dac_code);
+	CDBG("capture_mode = %d\n", capture_mode);
+
+	/* RE-CONFIGURE SENSOR WITH NEW TIMINGS
+	 * ====================================
+	 * Enter Software Standby Mode */
+	rc = vb6801_i2c_write_b(REG_MODE_SELECT, 0);
+	if (rc < 0) {
+		CDBG("I2C vb6801_i2c_write_b FAILED!!!\n");
+		return rc;
+	}
+
+	/* Wait 100ms */
+	mdelay(100);
+
+	if (capture_mode == 0) {
+
+		rc = vb6801_i2c_write_b(REG_CCP2_CHANNEL_IDENTIFIER, 0);
+		rc = vb6801_i2c_write_b(REG_CCP2_SIGNALLING_MODE, 0);
+	} else if (capture_mode == 1) {
+
+		rc = vb6801_i2c_write_b(REG_CCP2_CHANNEL_IDENTIFIER, 0);
+		rc = vb6801_i2c_write_b(REG_CCP2_SIGNALLING_MODE, 1);
+	}
+
+	{
+		struct vb6801_i2c_reg_conf_t wreg[] = {
+			/* Re-configure Sensor */
+			{REG_CCP2_DATA_FORMAT, ccp2_data_format, 0,
+			 D_LEN_WORD},
+			{REG_ANALOGUE_GAIN_CODE_GLOBAL, 128, 0, D_LEN_WORD},
+			{REG_PRE_PLL_CLK_DIV, pre_pll_clk_div, 0, D_LEN_WORD},
+			{REG_VT_SYS_CLK_DIV, vt_sys_clk_div, 0, D_LEN_WORD},
+			{REG_VT_PIX_CLK_DIV, vt_pix_clk_div, 0, D_LEN_WORD},
+			{REG_OP_SYS_CLK_DIV, vt_sys_clk_div, 0, D_LEN_WORD},
+			{REG_OP_PIX_CLK_DIV, vt_pix_clk_div, 0, D_LEN_WORD},
+			{REG_VT_LINE_LENGTH_PCK, vt_line_length_pck, 0,
+			 D_LEN_WORD},
+			{REG_X_OUTPUT_SIZE, x_output_size, 0, D_LEN_WORD},
+			{REG_Y_OUTPUT_SIZE, y_output_size, 0, D_LEN_WORD},
+			{REG_X_ODD_INC, x_odd_inc, 0, D_LEN_WORD},
+			{REG_Y_ODD_INC, y_odd_inc, 0, D_LEN_WORD},
+			{REG_VT_FRAME_LENGTH_LINES,
+			 vt_frame_length_lines * vb6801_ctrl->factor_fps, 0,
+			 D_LEN_WORD},
+			{REG_COARSE_INTEGRATION_TIME,
+			 coarse_integration_time, 0, D_LEN_WORD},
+			/* Analogue Settings */
+			{REG_ANALOG_TIMING_MODES_2, 0, 132, D_LEN_BYTE},
+			{REG_RAMP_SCALE, 0, 5, D_LEN_BYTE},
+			{REG_BTL_LEVEL_SETUP, 0, 11, D_LEN_BYTE},
+			/* Enable Defect Correction */
+			{REG_SCYTHE_ENABLE, 0, 1, D_LEN_BYTE},
+			{REG_SCYTHE_WEIGHT, 0, 16, D_LEN_BYTE},
+			{REG_BRUCE_ENABLE, 0, 1, D_LEN_BYTE},
+			/* Auto Focus Configuration
+			 * Please note that the DAC Code is a written as a
+			 * 16-bit value 0 = infinity (no DAC current) */
+			{REG_VCM_DAC_CODE, pinfo->vcm_dac_code, 0, D_LEN_WORD},
+			{REG_VCM_DAC_STROBE, 0, 0, D_LEN_BYTE},
+			{REG_VCM_DAC_ENABLE, 0, 1, D_LEN_BYTE},
+		};
+
+		rc = vb6801_i2c_write_table(wreg, ARRAY_SIZE(wreg));
+		if (rc < 0) {
+			CDBG("I2C Write Table FAILED!!!\n");
+			return rc;
+		}
+	}
+	/* Parallel Interface Configuration */
+	if (capture_mode >= 2) {
+		struct vb6801_i2c_reg_conf_t wreg1[] = {
+			{REG_OP_CODER_SYNC_CLK_SETUP, 0, 15, D_LEN_BYTE},
+			{REG_OP_CODER_ENABLE, 0, 3, D_LEN_BYTE},
+			{REG_OP_CODER_SLOW_PAD_EN, 0, 1, D_LEN_BYTE},
+			{REG_OP_CODER_AUTOMATIC_MODE_ENABLE, 0, 3, D_LEN_BYTE},
+			{REG_OP_CODER_AUTO_STARTUP, 0, 2, D_LEN_BYTE},
+		};
+
+		rc = vb6801_i2c_write_table(wreg1, ARRAY_SIZE(wreg1));
+		if (rc < 0) {
+			CDBG("I2C Write Table FAILED!!!\n");
+			return rc;
+		}
+	}
+
+	/* Enter Streaming Mode */
+	rc = vb6801_i2c_write_b(REG_MODE_SELECT, 1);
+	if (rc < 0) {
+		CDBG("I2C Write Table FAILED!!!\n");
+		return rc;
+	}
+
+	/* Wait until the sensor starts streaming
+	 * Poll until the reported frame_count value is != 0xFF */
+	frame_count = 0xFF;
+	timeout = 2000;
+	while (frame_count == 0xFF && timeout > 0) {
+		rc = vb6801_i2c_read(REG_FRAME_COUNT, &frame_count, 1);
+		if (rc < 0)
+			return rc;
+
+		CDBG("REG_FRAME_COUNT  = 0x%x\n", frame_count);
+		timeout--;
+	}
+
+	/* Post Streaming Configuration */
+
+	rc = vb6801_i2c_write_table(wreg2, ARRAY_SIZE(wreg2));
+	if (rc < 0) {
+		CDBG("I2C Write Table FAILED!!!\n");
+		return rc;
+	}
+
+	rc = vb6801_i2c_read_table(rreg, ARRAY_SIZE(rreg));
+	if (rc < 0) {
+		CDBG("I2C Read Table FAILED!!!\n");
+		return rc;
+	}
+
+	CDBG("REG_PRE_PLL_CLK_DIV = 0x%x\n", rreg[0].wdata);
+	CDBG("REG_PLL_MULTIPLIER  = 0x%x\n", rreg[1].wdata);
+	CDBG("REG_VT_SYS_CLK_DIV  = 0x%x\n", rreg[2].wdata);
+	CDBG("REG_VT_PIX_CLK_DIV  = 0x%x\n", rreg[3].wdata);
+	CDBG("REG_OP_SYS_CLK_DIV  = 0x%x\n", rreg[4].wdata);
+	CDBG("REG_OP_PIX_CLK_DIV  = 0x%x\n", rreg[5].wdata);
+	CDBG("REG_FRAME_COUNT  = 0x%x\n", rreg[6].bdata);
+
+	mdelay(50);
+	frame_count = 0;
+	rc = vb6801_i2c_read(REG_FRAME_COUNT, &frame_count, 1);
+	CDBG("REG_FRAME_COUNT1  = 0x%x\n", frame_count);
+
+	mdelay(150);
+	frame_count = 0;
+	rc = vb6801_i2c_read(REG_FRAME_COUNT, &frame_count, 1);
+	CDBG("REG_FRAME_COUNT2  = 0x%x\n", frame_count);
+
+	mdelay(100);
+	frame_count = 0;
+	rc = vb6801_i2c_read(REG_FRAME_COUNT, &frame_count, 1);
+	CDBG("REG_FRAME_COUNT3  = 0x%x\n", frame_count);
+
+	mdelay(250);
+	frame_count = 0;
+	rc = vb6801_i2c_read(REG_FRAME_COUNT, &frame_count, 1);
+	CDBG("REG_FRAME_COUNT4  = 0x%x\n", frame_count);
+
+	return rc;
+}
+
+static int vb6801_sensor_init_done(const struct msm_camera_sensor_info *data)
+{
+	gpio_direction_output(data->sensor_reset, 0);
+	gpio_free(data->sensor_reset);
+	return 0;
+}
+
+static int vb6801_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&vb6801_wait_queue);
+	return 0;
+}
+
+static int32_t vb6801_video_config(int mode, int res)
+{
+	int32_t rc = 0;
+
+	vb6801_ctrl->prev_res = res;
+	vb6801_ctrl->curr_res = res;
+	vb6801_ctrl->sensormode = mode;
+
+	rc = vb6801_config_sensor(12, 30, 60, 2, 1, 10, 2, RES_PREVIEW);
+	if (rc < 0)
+		return rc;
+
+	rc = vb6801_i2c_read(REG_VT_LINE_LENGTH_PCK,
+			     &vb6801_ctrl->s_dynamic_params.
+			     preview_pixelsPerLine, 2);
+	if (rc < 0)
+		return rc;
+
+	rc = vb6801_i2c_read(REG_VT_LINE_LENGTH_PCK,
+			     &vb6801_ctrl->s_dynamic_params.
+			     preview_linesPerFrame, 2);
+
+	return rc;
+}
+
+static int32_t vb6801_snapshot_config(int mode, int res)
+{
+	int32_t rc = 0;
+
+	vb6801_ctrl->curr_res = vb6801_ctrl->pict_res;
+	vb6801_ctrl->sensormode = mode;
+
+	rc = vb6801_config_sensor(12, 12, 48, 1, 1, 10, 2, RES_CAPTURE);
+	if (rc < 0)
+		return rc;
+
+	rc = vb6801_i2c_read(REG_VT_LINE_LENGTH_PCK,
+			     &vb6801_ctrl->s_dynamic_params.
+			     snapshot_pixelsPerLine, 2);
+	if (rc < 0)
+		return rc;
+
+	rc = vb6801_i2c_read(REG_VT_LINE_LENGTH_PCK,
+			     &vb6801_ctrl->s_dynamic_params.
+			     snapshot_linesPerFrame, 2);
+
+	return rc;
+}
+
+static int32_t vb6801_set_sensor_mode(int mode, int res)
+{
+	int32_t rc = 0;
+
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		rc = vb6801_video_config(mode, res);
+		break;
+
+	case SENSOR_SNAPSHOT_MODE:
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		rc = vb6801_snapshot_config(mode, res);
+		break;
+
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+int vb6801_sensor_config(void __user *argp)
+{
+	struct sensor_cfg_data cdata;
+	long rc = 0;
+
+	if (copy_from_user(&cdata,
+			   (void *)argp, sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+
+	mutex_lock(&vb6801_mut);
+
+	CDBG("vb6801_sensor_config, cfgtype = %d\n", cdata.cfgtype);
+
+	switch (cdata.cfgtype) {
+	case CFG_GET_PICT_FPS:
+		vb6801_get_pict_fps(cdata.cfg.gfps.prevfps,
+				    &(cdata.cfg.gfps.pictfps));
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PREV_L_PF:
+		cdata.cfg.prevl_pf = vb6801_get_prev_lines_pf();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PREV_P_PL:
+		cdata.cfg.prevp_pl = vb6801_get_prev_pixels_pl();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_L_PF:
+		cdata.cfg.pictl_pf = vb6801_get_pict_lines_pf();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_P_PL:
+		cdata.cfg.pictp_pl = vb6801_get_pict_pixels_pl();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_GET_PICT_MAX_EXP_LC:
+		cdata.cfg.pict_max_exp_lc = vb6801_get_pict_max_exp_lc();
+
+		if (copy_to_user((void *)argp,
+				 &cdata, sizeof(struct sensor_cfg_data)))
+			rc = -EFAULT;
+		break;
+
+	case CFG_SET_FPS:
+	case CFG_SET_PICT_FPS:
+		rc = vb6801_set_fps(&(cdata.cfg.fps));
+		break;
+
+	case CFG_SET_EXP_GAIN:
+		rc = vb6801_write_exp_gain(cdata.cfg.exp_gain.gain,
+					   cdata.cfg.exp_gain.line);
+		break;
+
+	case CFG_SET_PICT_EXP_GAIN:
+		rc = vb6801_set_pict_exp_gain(cdata.cfg.exp_gain.gain,
+					      cdata.cfg.exp_gain.line);
+		break;
+
+	case CFG_SET_MODE:
+		rc = vb6801_set_sensor_mode(cdata.mode, cdata.rs);
+		break;
+
+	case CFG_PWR_DOWN:
+		rc = vb6801_power_down();
+		break;
+
+	case CFG_MOVE_FOCUS:
+		rc = vb6801_move_focus(cdata.cfg.focus.dir,
+				       cdata.cfg.focus.steps);
+		break;
+
+	case CFG_SET_DEFAULT_FOCUS:
+		rc = vb6801_set_default_focus();
+		break;
+
+	default:
+		rc = -EFAULT;
+		break;
+	}
+
+	mutex_unlock(&vb6801_mut);
+
+	return rc;
+}
+
+static int vb6801_sensor_release(void)
+{
+	int rc = -EBADF;
+
+	mutex_lock(&vb6801_mut);
+
+	vb6801_power_down();
+	vb6801_sensor_init_done(vb6801_ctrl->sensordata);
+	kfree(vb6801_ctrl);
+	mutex_unlock(&vb6801_mut);
+
+	return rc;
+}
+
+static int vb6801_i2c_probe(struct i2c_client *client,
+			    const struct i2c_device_id *id)
+{
+	int rc = 0;
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		rc = -ENOTSUPP;
+		goto probe_failure;
+	}
+
+	vb6801_sensorw = kzalloc(sizeof(struct vb6801_work_t), GFP_KERNEL);
+
+	if (!vb6801_sensorw) {
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, vb6801_sensorw);
+	vb6801_init_client(client);
+	vb6801_client = client;
+	vb6801_client->addr = vb6801_client->addr >> 1;
+
+	return 0;
+
+probe_failure:
+	if (vb6801_sensorw != NULL) {
+		kfree(vb6801_sensorw);
+		vb6801_sensorw = NULL;
+	}
+	return rc;
+}
+
+static int __exit vb6801_i2c_remove(struct i2c_client *client)
+{
+	struct vb6801_work_t *sensorw = i2c_get_clientdata(client);
+	free_irq(client->irq, sensorw);
+	vb6801_client = NULL;
+	kfree(sensorw);
+	return 0;
+}
+
+static const struct i2c_device_id vb6801_i2c_id[] = {
+	{"vb6801", 0},
+	{}
+};
+
+static struct i2c_driver vb6801_i2c_driver = {
+	.id_table = vb6801_i2c_id,
+	.probe = vb6801_i2c_probe,
+	.remove = __exit_p(vb6801_i2c_remove),
+	.driver = {
+		   .name = "vb6801",
+		   },
+};
+
+static int vb6801_probe_init_sensor(const struct msm_camera_sensor_info *data)
+{
+	int rc;
+
+	struct vb6801_i2c_reg_conf_t rreg[] = {
+		{0x0000, 0, 0, D_LEN_BYTE},
+		{0x0001, 0, 0, D_LEN_BYTE},
+	};
+
+	rc = vb6801_reset(data);
+	if (rc < 0)
+		goto init_probe_done;
+
+	mdelay(20);
+
+	rc = vb6801_i2c_read_table(rreg, ARRAY_SIZE(rreg));
+	if (rc < 0) {
+		CDBG("I2C Read Table FAILED!!!\n");
+		goto init_probe_fail;
+	}
+
+	/* 4. Compare sensor ID to VB6801 ID: */
+	if (rreg[0].bdata != 0x03 || rreg[1].bdata != 0x53) {
+		CDBG("vb6801_sensor_init: sensor ID don't match!\n");
+		goto init_probe_fail;
+	}
+
+	goto init_probe_done;
+
+init_probe_fail:
+	vb6801_sensor_init_done(data);
+init_probe_done:
+	return rc;
+}
+
+int vb6801_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc;
+	struct vb6801_i2c_reg_conf_t wreg[] = {
+		{REG_MODE_SELECT, 0, STANDBY_MODE, D_LEN_BYTE},
+		{0x0113, 0, 0x0A, D_LEN_BYTE},
+	};
+
+	vb6801_ctrl = kzalloc(sizeof(struct vb6801_ctrl_t), GFP_KERNEL);
+	if (!vb6801_ctrl) {
+		rc = -ENOMEM;
+		goto open_init_fail1;
+	}
+
+	vb6801_ctrl->factor_fps = 1 /** 0x00000400*/ ;
+	vb6801_ctrl->curr_fps = 7680; /* 30 * Q8 */ ;
+	vb6801_ctrl->max_fps = 7680; /* 30 * Q8 */ ;
+	vb6801_ctrl->pict_exp_update = 0; /* 30 * Q8 */ ;
+	vb6801_ctrl->reducel = 0; /* 30 * Q8 */ ;
+
+	vb6801_ctrl->set_test = TEST_OFF;
+	vb6801_ctrl->prev_res = QTR_SIZE;
+	vb6801_ctrl->pict_res = FULL_SIZE;
+
+	vb6801_ctrl->s_dynamic_params.preview_linesPerFrame =
+	    VB6801_LINES_PER_FRAME_PREVIEW;
+	vb6801_ctrl->s_dynamic_params.preview_pixelsPerLine =
+	    VB6801_PIXELS_PER_LINE_PREVIEW;
+	vb6801_ctrl->s_dynamic_params.snapshot_linesPerFrame =
+	    VB6801_LINES_PER_FRAME_SNAPSHOT;
+	vb6801_ctrl->s_dynamic_params.snapshot_pixelsPerLine =
+	    VB6801_PIXELS_PER_LINE_SNAPSHOT;
+
+	if (data)
+		vb6801_ctrl->sensordata = data;
+
+	/* enable mclk first */
+	msm_camio_clk_rate_set(VB6801_DEFAULT_CLOCK_RATE);
+	mdelay(20);
+
+	rc = vb6801_reset(data);
+	if (rc < 0)
+		goto open_init_fail1;
+
+	rc = vb6801_i2c_write_table(wreg, ARRAY_SIZE(wreg));
+	if (rc < 0) {
+		CDBG("I2C Write Table FAILED!!!\n");
+		goto open_init_fail2;
+	}
+
+	rc = vb6801_read_nvm_data(&vb6801_ctrl->s_info);
+	if (rc < 0) {
+		CDBG("vb6801_read_nvm_data FAILED!!!\n");
+		goto open_init_fail2;
+	}
+	mdelay(66);
+
+	rc = vb6801_config_sensor(12, 30, 60, 2, 1, 10, 2, RES_PREVIEW);
+	if (rc < 0)
+		goto open_init_fail2;
+
+	goto open_init_done;
+
+open_init_fail2:
+	vb6801_sensor_init_done(data);
+open_init_fail1:
+	kfree(vb6801_ctrl);
+open_init_done:
+	return rc;
+}
+
+static int vb6801_sensor_probe(const struct msm_camera_sensor_info *info,
+			       struct msm_sensor_ctrl *s)
+{
+	int rc = i2c_add_driver(&vb6801_i2c_driver);
+	if (rc < 0 || vb6801_client == NULL) {
+		rc = -ENOTSUPP;
+		goto probe_done;
+	}
+
+	/* enable mclk first */
+	msm_camio_clk_rate_set(VB6801_DEFAULT_CLOCK_RATE);
+	mdelay(20);
+
+	rc = vb6801_probe_init_sensor(info);
+	if (rc < 0)
+		goto probe_done;
+
+	s->s_init = vb6801_sensor_open_init;
+	s->s_release = vb6801_sensor_release;
+	s->s_config = vb6801_sensor_config;
+	s->s_mount_angle  = 0;
+	vb6801_sensor_init_done(info);
+
+probe_done:
+	return rc;
+}
+
+static int __vb6801_probe(struct platform_device *pdev)
+{
+	return msm_camera_drv_start(pdev, vb6801_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = __vb6801_probe,
+	.driver = {
+		   .name = "msm_camera_vb6801",
+		   .owner = THIS_MODULE,
+		   },
+};
+
+static int __init vb6801_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(vb6801_init);
+void vb6801_exit(void)
+{
+	i2c_del_driver(&vb6801_i2c_driver);
+}
diff --git a/drivers/media/video/msm/vb6801.h b/drivers/media/video/msm/vb6801.h
new file mode 100644
index 0000000..8248f8d
--- /dev/null
+++ b/drivers/media/video/msm/vb6801.h
@@ -0,0 +1,66 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#ifndef VB6801_H
+#define VB6801_H
+
+#include <mach/board.h>
+
+extern struct vb6801_reg_t vb6801_regs;	/* from vb6801_reg.c */
+
+struct reg_struct {
+	uint16_t vt_pix_clk_div;	/*  0x0300 */
+	uint16_t vt_sys_clk_div;	/*  0x0302 */
+	uint16_t pre_pll_clk_div;	/*  0x0304 */
+	uint16_t pll_multiplier;	/*  0x0306 */
+	uint16_t op_pix_clk_div;	/*  0x0308 */
+	uint16_t op_sys_clk_div;	/*  0x030A */
+	uint16_t scale_m;	/*  0x0404 */
+	uint16_t row_speed;	/*  0x3016 */
+	uint16_t x_addr_start;	/*  0x3004 */
+	uint16_t x_addr_end;	/*  0x3008 */
+	uint16_t y_addr_start;	/*  0x3002 */
+	uint16_t y_addr_end;	/*  0x3006 */
+	uint16_t read_mode;	/*  0x3040 */
+	uint16_t x_output_size;	/*  0x034C */
+	uint16_t y_output_size;	/*  0x034E */
+	uint16_t line_length_pck;	/*  0x300C */
+	uint16_t frame_length_lines;	/*  0x300A */
+	uint16_t coarse_int_time;	/*  0x3012 */
+	uint16_t fine_int_time;	/*  0x3014 */
+};
+
+enum i2c_data_len {
+	D_LEN_BYTE,
+	D_LEN_WORD
+};
+
+struct vb6801_i2c_reg_conf_t {
+	unsigned short waddr;
+	unsigned short wdata;
+	uint8_t bdata;
+	enum i2c_data_len dlen;
+};
+
+struct vb6801_reg_t {
+	struct reg_struct const *reg_pat;
+	uint16_t reg_pat_size;
+	struct vb6801_i2c_reg_conf_t const *ttbl;
+	uint16_t ttbl_size;
+	struct vb6801_i2c_reg_conf_t const *lctbl;
+	uint16_t lctbl_size;
+	struct vb6801_i2c_reg_conf_t const *rftbl;
+	uint16_t rftbl_size;
+};
+
+#endif /* VB6801_H */
diff --git a/drivers/media/video/msm/vx6953.c b/drivers/media/video/msm/vx6953.c
new file mode 100644
index 0000000..17e5e2e
--- /dev/null
+++ b/drivers/media/video/msm/vx6953.c
@@ -0,0 +1,3666 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <media/msm_camera.h>
+#include <mach/gpio.h>
+#include <mach/camera.h>
+#include <linux/slab.h>
+#include "vx6953.h"
+
+/*=============================================================
+	SENSOR REGISTER DEFINES
+==============================================================*/
+
+#define REG_GROUPED_PARAMETER_HOLD			0x0104
+#define GROUPED_PARAMETER_HOLD_OFF			0x00
+#define GROUPED_PARAMETER_HOLD				0x01
+#define REG_MODE_SELECT					0x0100
+#define MODE_SELECT_STANDBY_MODE			0x00
+#define MODE_SELECT_STREAM				0x01
+/* Integration Time */
+#define REG_COARSE_INTEGRATION_TIME_HI			0x0202
+#define REG_COARSE_INTEGRATION_TIME_LO			0x0203
+/* Gain */
+#define REG_ANALOGUE_GAIN_CODE_GLOBAL_HI		0x0204
+#define REG_ANALOGUE_GAIN_CODE_GLOBAL_LO		0x0205
+/* Digital Gain */
+#define REG_DIGITAL_GAIN_GREEN_R_HI			0x020E
+#define REG_DIGITAL_GAIN_GREEN_R_LO			0x020F
+#define REG_DIGITAL_GAIN_RED_HI				0x0210
+#define REG_DIGITAL_GAIN_RED_LO				0x0211
+#define REG_DIGITAL_GAIN_BLUE_HI			0x0212
+#define REG_DIGITAL_GAIN_BLUE_LO			0x0213
+#define REG_DIGITAL_GAIN_GREEN_B_HI			0x0214
+#define REG_DIGITAL_GAIN_GREEN_B_LO			0x0215
+/* output bits setting */
+#define REG_0x0112					0x0112
+#define REG_0x0113					0x0113
+/* PLL registers */
+#define REG_VT_PIX_CLK_DIV				0x0301
+#define REG_PRE_PLL_CLK_DIV				0x0305
+#define REG_PLL_MULTIPLIER				0x0307
+#define REG_OP_PIX_CLK_DIV				0x0309
+#define REG_0x034c					0x034c
+#define REG_0x034d					0x034d
+#define REG_0x034e					0x034e
+#define REG_0x034f					0x034f
+#define REG_0x0387					0x0387
+#define REG_0x0383					0x0383
+#define REG_FRAME_LENGTH_LINES_HI			0x0340
+#define REG_FRAME_LENGTH_LINES_LO			0x0341
+#define REG_LINE_LENGTH_PCK_HI				0x0342
+#define REG_LINE_LENGTH_PCK_LO				0x0343
+#define REG_0x3030					0x3030
+#define REG_0x0111					0x0111
+#define REG_0x0136					0x0136
+#define REG_0x0137					0x0137
+#define REG_0x0b00					0x0b00
+#define REG_0x3001					0x3001
+#define REG_0x3004					0x3004
+#define REG_0x3007					0x3007
+#define REG_0x301a					0x301a
+#define REG_0x3101					0x3101
+#define REG_0x3364					0x3364
+#define REG_0x3365					0x3365
+#define REG_0x0b83					0x0b83
+#define REG_0x0b84					0x0b84
+#define REG_0x0b85					0x0b85
+#define REG_0x0b88					0x0b88
+#define REG_0x0b89					0x0b89
+#define REG_0x0b8a					0x0b8a
+#define REG_0x3005					0x3005
+#define REG_0x3010					0x3010
+#define REG_0x3036					0x3036
+#define REG_0x3041					0x3041
+#define REG_0x0b80					0x0b80
+#define REG_0x0900					0x0900
+#define REG_0x0901					0x0901
+#define REG_0x0902					0x0902
+#define REG_0x3016					0x3016
+#define REG_0x301d					0x301d
+#define REG_0x317e					0x317e
+#define REG_0x317f					0x317f
+#define REG_0x3400					0x3400
+#define REG_0x303a					0x303a
+#define REG_0x1716					0x1716
+#define REG_0x1717					0x1717
+#define REG_0x1718					0x1718
+#define REG_0x1719					0x1719
+#define REG_0x3006					0x3006
+#define REG_0x301b					0x301b
+#define REG_0x3098					0x3098
+#define REG_0x309d					0x309d
+#define REG_0x3011					0x3011
+#define REG_0x3035					0x3035
+#define REG_0x3045					0x3045
+#define REG_0x3210					0x3210
+#define	REG_0x0111					0x0111
+#define REG_0x3410					0x3410
+#define REG_0x0b06					0x0b06
+#define REG_0x0b07					0x0b07
+#define REG_0x0b08					0x0b08
+#define REG_0x0b09					0x0b09
+#define REG_0x3640					0x3640
+/* Test Pattern */
+#define REG_TEST_PATTERN_MODE				0x0601
+
+/*============================================================================
+							 TYPE DECLARATIONS
+============================================================================*/
+
+/* 16bit address - 8 bit context register structure */
+#define	VX6953_STM5M0EDOF_OFFSET	9
+#define	Q8		0x00000100
+#define	Q10		0x00000400
+#define	VX6953_STM5M0EDOF_MAX_SNAPSHOT_EXPOSURE_LINE_COUNT	2922
+#define	VX6953_STM5M0EDOF_DEFAULT_MASTER_CLK_RATE	24000000
+#define	VX6953_STM5M0EDOF_OP_PIXEL_CLOCK_RATE	79800000
+#define	VX6953_STM5M0EDOF_VT_PIXEL_CLOCK_RATE	88670000
+/* Full	Size */
+#define	VX6953_FULL_SIZE_WIDTH	2608
+#define	VX6953_FULL_SIZE_HEIGHT		1960
+#define	VX6953_FULL_SIZE_DUMMY_PIXELS	1
+#define	VX6953_FULL_SIZE_DUMMY_LINES	0
+/* Quarter Size	*/
+#define	VX6953_QTR_SIZE_WIDTH	1304
+#define	VX6953_QTR_SIZE_HEIGHT		980
+#define	VX6953_QTR_SIZE_DUMMY_PIXELS	1
+#define	VX6953_QTR_SIZE_DUMMY_LINES		0
+/* Blanking	as measured	on the scope */
+/* Full	Size */
+#define	VX6953_HRZ_FULL_BLK_PIXELS	348
+#define	VX6953_VER_FULL_BLK_LINES	40
+/* Quarter Size	*/
+#define	VX6953_HRZ_QTR_BLK_PIXELS	1628
+#define	VX6953_VER_QTR_BLK_LINES	28
+#define	MAX_LINE_LENGTH_PCK		8190
+#define	MAX_FRAME_LENGTH_LINES	16383
+#define	VX6953_REVISION_NUMBER_CUT2	0x10/*revision number	for	Cut2.0*/
+#define	VX6953_REVISION_NUMBER_CUT3	0x20/*revision number	for	Cut3.0*/
+/* FIXME: Changes from here */
+struct vx6953_work_t {
+	struct work_struct work;
+};
+
+static struct vx6953_work_t *vx6953_sensorw;
+static struct i2c_client *vx6953_client;
+
+struct vx6953_ctrl_t {
+	const struct  msm_camera_sensor_info *sensordata;
+
+	uint32_t sensormode;
+	uint32_t fps_divider;   	/* init to 1 * 0x00000400 */
+	uint32_t pict_fps_divider;  /* init to 1 * 0x00000400 */
+	uint16_t fps;
+
+	int16_t curr_lens_pos;
+	uint16_t curr_step_pos;
+	uint16_t my_reg_gain;
+	uint32_t my_reg_line_count;
+	uint16_t total_lines_per_frame;
+
+	enum vx6953_resolution_t prev_res;
+	enum vx6953_resolution_t pict_res;
+	enum vx6953_resolution_t curr_res;
+	enum vx6953_test_mode_t  set_test;
+	enum sensor_revision_t sensor_type;
+
+	enum edof_mode_t edof_mode;
+
+	unsigned short imgaddr;
+};
+
+
+static uint8_t vx6953_stm5m0edof_delay_msecs_stdby;
+static uint16_t vx6953_stm5m0edof_delay_msecs_stream = 20;
+static uint8_t count;
+static struct vx6953_ctrl_t *vx6953_ctrl;
+static DECLARE_WAIT_QUEUE_HEAD(vx6953_wait_queue);
+DEFINE_MUTEX(vx6953_mut);
+static struct vx6953_i2c_reg_conf patch_tbl_cut2[] = {
+	{0xFB94, 0},	/*intialise Data Xfer Status reg*/
+	{0xFB95, 0},	/*gain 1	  (0x00)*/
+	{0xFB96, 0},	/*gain 1.07   (0x10)*/
+	{0xFB97, 0},	/*gain 1.14   (0x20)*/
+	{0xFB98, 0},	/*gain 1.23   (0x30)*/
+	{0xFB99, 0},	/*gain 1.33   (0x40)*/
+	{0xFB9A, 0},	/*gain 1.45   (0x50)*/
+	{0xFB9B, 0},	/*gain 1.6    (0x60)*/
+	{0xFB9C, 0},	/*gain 1.78   (0x70)*/
+	{0xFB9D, 2},	/*gain 2	  (0x80)*/
+	{0xFB9E, 2},	/*gain 2.29   (0x90)*/
+	{0xFB9F, 3},	/*gain 2.67   (0xA0)*/
+	{0xFBA0, 3},	/*gain 3.2    (0xB0)*/
+	{0xFBA1, 4},	/*gain 4	  (0xC0)*/
+	{0xFBA2, 7},	/*gain 5.33   (0xD0)*/
+	{0xFBA3, 10},	/*gain 8	  (0xE0)*/
+	{0xFBA4, 11},	/*gain 9.14   (0xE4)*/
+	{0xFBA5, 13},	/*gain 10.67  (0xE8)*/
+	{0xFBA6, 15},	/*gain 12.8   (0xEC)*/
+	{0xFBA7, 19},	/*gain 16     (0xF0)*/
+	{0xF800, 0x12},
+	{0xF801, 0x06},
+	{0xF802, 0xf7},
+	{0xF803, 0x90},
+	{0xF804, 0x02},
+	{0xF805, 0x05},
+	{0xF806, 0xe0},
+	{0xF807, 0xff},
+	{0xF808, 0x65},
+	{0xF809, 0x7d},
+	{0xF80A, 0x70},
+	{0xF80B, 0x03},
+	{0xF80C, 0x02},
+	{0xF80D, 0xf9},
+	{0xF80E, 0x1c},
+	{0xF80F, 0x8f},
+	{0xF810, 0x7d},
+	{0xF811, 0xe4},
+	{0xF812, 0xf5},
+	{0xF813, 0x7a},
+	{0xF814, 0x75},
+	{0xF815, 0x78},
+	{0xF816, 0x30},
+	{0xF817, 0x75},
+	{0xF818, 0x79},
+	{0xF819, 0x53},
+	{0xF81A, 0x85},
+	{0xF81B, 0x79},
+	{0xF81C, 0x82},
+	{0xF81D, 0x85},
+	{0xF81E, 0x78},
+	{0xF81F, 0x83},
+	{0xF820, 0xe0},
+	{0xF821, 0xc3},
+	{0xF822, 0x95},
+	{0xF823, 0x7b},
+	{0xF824, 0xf0},
+	{0xF825, 0x74},
+	{0xF826, 0x02},
+	{0xF827, 0x25},
+	{0xF828, 0x79},
+	{0xF829, 0xf5},
+	{0xF82A, 0x79},
+	{0xF82B, 0xe4},
+	{0xF82C, 0x35},
+	{0xF82D, 0x78},
+	{0xF82E, 0xf5},
+	{0xF82F, 0x78},
+	{0xF830, 0x05},
+	{0xF831, 0x7a},
+	{0xF832, 0xe5},
+	{0xF833, 0x7a},
+	{0xF834, 0xb4},
+	{0xF835, 0x08},
+	{0xF836, 0xe3},
+	{0xF837, 0xe5},
+	{0xF838, 0x7d},
+	{0xF839, 0x70},
+	{0xF83A, 0x04},
+	{0xF83B, 0xff},
+	{0xF83C, 0x02},
+	{0xF83D, 0xf8},
+	{0xF83E, 0xe4},
+	{0xF83F, 0xe5},
+	{0xF840, 0x7d},
+	{0xF841, 0xb4},
+	{0xF842, 0x10},
+	{0xF843, 0x05},
+	{0xF844, 0x7f},
+	{0xF845, 0x01},
+	{0xF846, 0x02},
+	{0xF847, 0xf8},
+	{0xF848, 0xe4},
+	{0xF849, 0xe5},
+	{0xF84A, 0x7d},
+	{0xF84B, 0xb4},
+	{0xF84C, 0x20},
+	{0xF84D, 0x05},
+	{0xF84E, 0x7f},
+	{0xF84F, 0x02},
+	{0xF850, 0x02},
+	{0xF851, 0xf8},
+	{0xF852, 0xe4},
+	{0xF853, 0xe5},
+	{0xF854, 0x7d},
+	{0xF855, 0xb4},
+	{0xF856, 0x30},
+	{0xF857, 0x05},
+	{0xF858, 0x7f},
+	{0xF859, 0x03},
+	{0xF85A, 0x02},
+	{0xF85B, 0xf8},
+	{0xF85C, 0xe4},
+	{0xF85D, 0xe5},
+	{0xF85E, 0x7d},
+	{0xF85F, 0xb4},
+	{0xF860, 0x40},
+	{0xF861, 0x04},
+	{0xF862, 0x7f},
+	{0xF863, 0x04},
+	{0xF864, 0x80},
+	{0xF865, 0x7e},
+	{0xF866, 0xe5},
+	{0xF867, 0x7d},
+	{0xF868, 0xb4},
+	{0xF869, 0x50},
+	{0xF86A, 0x04},
+	{0xF86B, 0x7f},
+	{0xF86C, 0x05},
+	{0xF86D, 0x80},
+	{0xF86E, 0x75},
+	{0xF86F, 0xe5},
+	{0xF870, 0x7d},
+	{0xF871, 0xb4},
+	{0xF872, 0x60},
+	{0xF873, 0x04},
+	{0xF874, 0x7f},
+	{0xF875, 0x06},
+	{0xF876, 0x80},
+	{0xF877, 0x6c},
+	{0xF878, 0xe5},
+	{0xF879, 0x7d},
+	{0xF87A, 0xb4},
+	{0xF87B, 0x70},
+	{0xF87C, 0x04},
+	{0xF87D, 0x7f},
+	{0xF87E, 0x07},
+	{0xF87F, 0x80},
+	{0xF880, 0x63},
+	{0xF881, 0xe5},
+	{0xF882, 0x7d},
+	{0xF883, 0xb4},
+	{0xF884, 0x80},
+	{0xF885, 0x04},
+	{0xF886, 0x7f},
+	{0xF887, 0x08},
+	{0xF888, 0x80},
+	{0xF889, 0x5a},
+	{0xF88A, 0xe5},
+	{0xF88B, 0x7d},
+	{0xF88C, 0xb4},
+	{0xF88D, 0x90},
+	{0xF88E, 0x04},
+	{0xF88F, 0x7f},
+	{0xF890, 0x09},
+	{0xF891, 0x80},
+	{0xF892, 0x51},
+	{0xF893, 0xe5},
+	{0xF894, 0x7d},
+	{0xF895, 0xb4},
+	{0xF896, 0xa0},
+	{0xF897, 0x04},
+	{0xF898, 0x7f},
+	{0xF899, 0x0a},
+	{0xF89A, 0x80},
+	{0xF89B, 0x48},
+	{0xF89C, 0xe5},
+	{0xF89D, 0x7d},
+	{0xF89E, 0xb4},
+	{0xF89F, 0xb0},
+	{0xF8A0, 0x04},
+	{0xF8A1, 0x7f},
+	{0xF8A2, 0x0b},
+	{0xF8A3, 0x80},
+	{0xF8A4, 0x3f},
+	{0xF8A5, 0xe5},
+	{0xF8A6, 0x7d},
+	{0xF8A7, 0xb4},
+	{0xF8A8, 0xc0},
+	{0xF8A9, 0x04},
+	{0xF8AA, 0x7f},
+	{0xF8AB, 0x0c},
+	{0xF8AC, 0x80},
+	{0xF8AD, 0x36},
+	{0xF8AE, 0xe5},
+	{0xF8AF, 0x7d},
+	{0xF8B0, 0xb4},
+	{0xF8B1, 0xd0},
+	{0xF8B2, 0x04},
+	{0xF8B3, 0x7f},
+	{0xF8B4, 0x0d},
+	{0xF8B5, 0x80},
+	{0xF8B6, 0x2d},
+	{0xF8B7, 0xe5},
+	{0xF8B8, 0x7d},
+	{0xF8B9, 0xb4},
+	{0xF8BA, 0xe0},
+	{0xF8BB, 0x04},
+	{0xF8BC, 0x7f},
+	{0xF8BD, 0x0e},
+	{0xF8BE, 0x80},
+	{0xF8BF, 0x24},
+	{0xF8C0, 0xe5},
+	{0xF8C1, 0x7d},
+	{0xF8C2, 0xb4},
+	{0xF8C3, 0xe4},
+	{0xF8C4, 0x04},
+	{0xF8C5, 0x7f},
+	{0xF8C6, 0x0f},
+	{0xF8C7, 0x80},
+	{0xF8C8, 0x1b},
+	{0xF8C9, 0xe5},
+	{0xF8CA, 0x7d},
+	{0xF8CB, 0xb4},
+	{0xF8CC, 0xe8},
+	{0xF8CD, 0x04},
+	{0xF8CE, 0x7f},
+	{0xF8CF, 0x10},
+	{0xF8D0, 0x80},
+	{0xF8D1, 0x12},
+	{0xF8D2, 0xe5},
+	{0xF8D3, 0x7d},
+	{0xF8D4, 0xb4},
+	{0xF8D5, 0xec},
+	{0xF8D6, 0x04},
+	{0xF8D7, 0x7f},
+	{0xF8D8, 0x11},
+	{0xF8D9, 0x80},
+	{0xF8DA, 0x09},
+	{0xF8DB, 0xe5},
+	{0xF8DC, 0x7d},
+	{0xF8DD, 0x7f},
+	{0xF8DE, 0x00},
+	{0xF8DF, 0xb4},
+	{0xF8E0, 0xf0},
+	{0xF8E1, 0x02},
+	{0xF8E2, 0x7f},
+	{0xF8E3, 0x12},
+	{0xF8E4, 0x8f},
+	{0xF8E5, 0x7c},
+	{0xF8E6, 0xef},
+	{0xF8E7, 0x24},
+	{0xF8E8, 0x95},
+	{0xF8E9, 0xff},
+	{0xF8EA, 0xe4},
+	{0xF8EB, 0x34},
+	{0xF8EC, 0xfb},
+	{0xF8ED, 0x8f},
+	{0xF8EE, 0x82},
+	{0xF8EF, 0xf5},
+	{0xF8F0, 0x83},
+	{0xF8F1, 0xe4},
+	{0xF8F2, 0x93},
+	{0xF8F3, 0xf5},
+	{0xF8F4, 0x7c},
+	{0xF8F5, 0xf5},
+	{0xF8F6, 0x7b},
+	{0xF8F7, 0xe4},
+	{0xF8F8, 0xf5},
+	{0xF8F9, 0x7a},
+	{0xF8FA, 0x75},
+	{0xF8FB, 0x78},
+	{0xF8FC, 0x30},
+	{0xF8FD, 0x75},
+	{0xF8FE, 0x79},
+	{0xF8FF, 0x53},
+	{0xF900, 0x85},
+	{0xF901, 0x79},
+	{0xF902, 0x82},
+	{0xF903, 0x85},
+	{0xF904, 0x78},
+	{0xF905, 0x83},
+	{0xF906, 0xe0},
+	{0xF907, 0x25},
+	{0xF908, 0x7c},
+	{0xF909, 0xf0},
+	{0xF90A, 0x74},
+	{0xF90B, 0x02},
+	{0xF90C, 0x25},
+	{0xF90D, 0x79},
+	{0xF90E, 0xf5},
+	{0xF90F, 0x79},
+	{0xF910, 0xe4},
+	{0xF911, 0x35},
+	{0xF912, 0x78},
+	{0xF913, 0xf5},
+	{0xF914, 0x78},
+	{0xF915, 0x05},
+	{0xF916, 0x7a},
+	{0xF917, 0xe5},
+	{0xF918, 0x7a},
+	{0xF919, 0xb4},
+	{0xF91A, 0x08},
+	{0xF91B, 0xe4},
+	{0xF91C, 0x02},
+	{0xF91D, 0x18},
+	{0xF91E, 0x32},
+	{0xF91F, 0x22},
+	{0xF920, 0xf0},
+	{0xF921, 0x90},
+	{0xF922, 0xa0},
+	{0xF923, 0xf8},
+	{0xF924, 0xe0},
+	{0xF925, 0x70},
+	{0xF926, 0x02},
+	{0xF927, 0xa3},
+	{0xF928, 0xe0},
+	{0xF929, 0x70},
+	{0xF92A, 0x0a},
+	{0xF92B, 0x90},
+	{0xF92C, 0xa1},
+	{0xF92D, 0x10},
+	{0xF92E, 0xe0},
+	{0xF92F, 0xfe},
+	{0xF930, 0xa3},
+	{0xF931, 0xe0},
+	{0xF932, 0xff},
+	{0xF933, 0x80},
+	{0xF934, 0x04},
+	{0xF935, 0x7e},
+	{0xF936, 0x00},
+	{0xF937, 0x7f},
+	{0xF938, 0x00},
+	{0xF939, 0x8e},
+	{0xF93A, 0x7e},
+	{0xF93B, 0x8f},
+	{0xF93C, 0x7f},
+	{0xF93D, 0x90},
+	{0xF93E, 0x36},
+	{0xF93F, 0x0d},
+	{0xF940, 0xe0},
+	{0xF941, 0x44},
+	{0xF942, 0x02},
+	{0xF943, 0xf0},
+	{0xF944, 0x90},
+	{0xF945, 0x36},
+	{0xF946, 0x0e},
+	{0xF947, 0xe5},
+	{0xF948, 0x7e},
+	{0xF949, 0xf0},
+	{0xF94A, 0xa3},
+	{0xF94B, 0xe5},
+	{0xF94C, 0x7f},
+	{0xF94D, 0xf0},
+	{0xF94E, 0xe5},
+	{0xF94F, 0x3a},
+	{0xF950, 0x60},
+	{0xF951, 0x0c},
+	{0xF952, 0x90},
+	{0xF953, 0x36},
+	{0xF954, 0x09},
+	{0xF955, 0xe0},
+	{0xF956, 0x70},
+	{0xF957, 0x06},
+	{0xF958, 0x90},
+	{0xF959, 0x36},
+	{0xF95A, 0x08},
+	{0xF95B, 0xf0},
+	{0xF95C, 0xf5},
+	{0xF95D, 0x3a},
+	{0xF95E, 0x02},
+	{0xF95F, 0x03},
+	{0xF960, 0x94},
+	{0xF961, 0x22},
+	{0xF962, 0x78},
+	{0xF963, 0x07},
+	{0xF964, 0xe6},
+	{0xF965, 0xd3},
+	{0xF966, 0x94},
+	{0xF967, 0x00},
+	{0xF968, 0x40},
+	{0xF969, 0x16},
+	{0xF96A, 0x16},
+	{0xF96B, 0xe6},
+	{0xF96C, 0x90},
+	{0xF96D, 0x30},
+	{0xF96E, 0xa1},
+	{0xF96F, 0xf0},
+	{0xF970, 0x90},
+	{0xF971, 0x43},
+	{0xF972, 0x83},
+	{0xF973, 0xe0},
+	{0xF974, 0xb4},
+	{0xF975, 0x01},
+	{0xF976, 0x0f},
+	{0xF977, 0x90},
+	{0xF978, 0x43},
+	{0xF979, 0x87},
+	{0xF97A, 0xe0},
+	{0xF97B, 0xb4},
+	{0xF97C, 0x01},
+	{0xF97D, 0x08},
+	{0xF97E, 0x80},
+	{0xF97F, 0x00},
+	{0xF980, 0x90},
+	{0xF981, 0x30},
+	{0xF982, 0xa0},
+	{0xF983, 0x74},
+	{0xF984, 0x01},
+	{0xF985, 0xf0},
+	{0xF986, 0x22},
+	{0xF987, 0xf0},
+	{0xF988, 0x90},
+	{0xF989, 0x35},
+	{0xF98A, 0xba},
+	{0xF98B, 0xe0},
+	{0xF98C, 0xb4},
+	{0xF98D, 0x0a},
+	{0xF98E, 0x0d},
+	{0xF98F, 0xa3},
+	{0xF990, 0xe0},
+	{0xF991, 0xb4},
+	{0xF992, 0x01},
+	{0xF993, 0x08},
+	{0xF994, 0x90},
+	{0xF995, 0xfb},
+	{0xF996, 0x94},
+	{0xF997, 0xe0},
+	{0xF998, 0x90},
+	{0xF999, 0x35},
+	{0xF99A, 0xb8},
+	{0xF99B, 0xf0},
+	{0xF99C, 0xd0},
+	{0xF99D, 0xd0},
+	{0xF99E, 0xd0},
+	{0xF99F, 0x82},
+	{0xF9A0, 0xd0},
+	{0xF9A1, 0x83},
+	{0xF9A2, 0xd0},
+	{0xF9A3, 0xe0},
+	{0xF9A4, 0x32},
+	{0xF9A5, 0x22},
+	{0xF9A6, 0xe5},
+	{0xF9A7, 0x7f},
+	{0xF9A8, 0x45},
+	{0xF9A9, 0x7e},
+	{0xF9AA, 0x60},
+	{0xF9AB, 0x15},
+	{0xF9AC, 0x90},
+	{0xF9AD, 0x01},
+	{0xF9AE, 0x00},
+	{0xF9AF, 0xe0},
+	{0xF9B0, 0x70},
+	{0xF9B1, 0x0f},
+	{0xF9B2, 0x90},
+	{0xF9B3, 0xa0},
+	{0xF9B4, 0xf8},
+	{0xF9B5, 0xe5},
+	{0xF9B6, 0x7e},
+	{0xF9B7, 0xf0},
+	{0xF9B8, 0xa3},
+	{0xF9B9, 0xe5},
+	{0xF9BA, 0x7f},
+	{0xF9BB, 0xf0},
+	{0xF9BC, 0xe4},
+	{0xF9BD, 0xf5},
+	{0xF9BE, 0x7e},
+	{0xF9BF, 0xf5},
+	{0xF9C0, 0x7f},
+	{0xF9C1, 0x22},
+	{0xF9C2, 0x02},
+	{0xF9C3, 0x0e},
+	{0xF9C4, 0x79},
+	{0xF9C5, 0x22},
+	/* Offsets:*/
+	{0x35C6, 0x00},/* FIDDLEDARKCAL*/
+	{0x35C7, 0x00},
+	{0x35C8, 0x01},/*STOREDISTANCEATSTOPSTREAMING*/
+	{0x35C9, 0x20},
+	{0x35CA, 0x01},/*BRUCEFIX*/
+	{0x35CB, 0x62},
+	{0x35CC, 0x01},/*FIXDATAXFERSTATUSREG*/
+	{0x35CD, 0x87},
+	{0x35CE, 0x01},/*FOCUSDISTANCEUPDATE*/
+	{0x35CF, 0xA6},
+	{0x35D0, 0x01},/*SKIPEDOFRESET*/
+	{0x35D1, 0xC2},
+	{0x35D2, 0x00},
+	{0x35D3, 0xFB},
+	{0x35D4, 0x00},
+	{0x35D5, 0x94},
+	{0x35D6, 0x00},
+	{0x35D7, 0xFB},
+	{0x35D8, 0x00},
+	{0x35D9, 0x94},
+	{0x35DA, 0x00},
+	{0x35DB, 0xFB},
+	{0x35DC, 0x00},
+	{0x35DD, 0x94},
+	{0x35DE, 0x00},
+	{0x35DF, 0xFB},
+	{0x35E0, 0x00},
+	{0x35E1, 0x94},
+	{0x35E6, 0x18},/* FIDDLEDARKCAL*/
+	{0x35E7, 0x2F},
+	{0x35E8, 0x03},/* STOREDISTANCEATSTOPSTREAMING*/
+	{0x35E9, 0x93},
+	{0x35EA, 0x18},/* BRUCEFIX*/
+	{0x35EB, 0x99},
+	{0x35EC, 0x00},/* FIXDATAXFERSTATUSREG*/
+	{0x35ED, 0xA3},
+	{0x35EE, 0x21},/* FOCUSDISTANCEUPDATE*/
+	{0x35EF, 0x5B},
+	{0x35F0, 0x0E},/* SKIPEDOFRESET*/
+	{0x35F1, 0x74},
+	{0x35F2, 0x04},
+	{0x35F3, 0x64},
+	{0x35F4, 0x04},
+	{0x35F5, 0x65},
+	{0x35F6, 0x04},
+	{0x35F7, 0x7B},
+	{0x35F8, 0x04},
+	{0x35F9, 0x7C},
+	{0x35FA, 0x04},
+	{0x35FB, 0xDD},
+	{0x35FC, 0x04},
+	{0x35FD, 0xDE},
+	{0x35FE, 0x04},
+	{0x35FF, 0xEF},
+	{0x3600, 0x04},
+	{0x3601, 0xF0},
+	/*Jump/Data:*/
+	{0x35C2, 0x3F},/* Jump Reg*/
+	{0x35C3, 0xFF},/* Jump Reg*/
+	{0x35C4, 0x3F},/* Data Reg*/
+	{0x35C5, 0xC0},/* Data Reg*/
+	{0x35C0, 0x01},/* Enable*/
+
+};
+
+static struct vx6953_i2c_reg_conf cut3_cali_data[] = {
+		{0x360A, 0x07 },
+		{0x3530, 0x07 },
+		{0x35B5, 0x00 },
+		{0x35BC, 0x00 },
+		{0xAFF8, 0x00 },
+		{0xAFF9, 0x01 },
+		{0xF800, 0x90 },
+		{0xF801, 0x30 },
+		{0xF802, 0x31 },
+		{0xF803, 0xe0 },
+		{0xF804, 0xf5 },
+		{0xF805, 0x7d },
+		{0xF806, 0xb4 },
+		{0xF807, 0x01 },
+		{0xF808, 0x06 },
+		{0xF809, 0x75 },
+		{0xF80A, 0x7d },
+		{0xF80B, 0x03 },
+		{0xF80C, 0x74 },
+		{0xF80D, 0x03 },
+		{0xF80E, 0xf0 },
+		{0xF80F, 0x90 },
+		{0xF810, 0x30 },
+		{0xF811, 0x04 },
+		{0xF812, 0x74 },
+		{0xF813, 0x33 },
+		{0xF814, 0xf0 },
+		{0xF815, 0x90 },
+		{0xF816, 0x30 },
+		{0xF817, 0x06 },
+		{0xF818, 0xe4 },
+		{0xF819, 0xf0 },
+		{0xF81A, 0xa3 },
+		{0xF81B, 0x74 },
+		{0xF81C, 0x08 },
+		{0xF81D, 0xf0 },
+		{0xF81E, 0x90 },
+		{0xF81F, 0x30 },
+		{0xF820, 0x10 },
+		{0xF821, 0xe4 },
+		{0xF822, 0xf0 },
+		{0xF823, 0xa3 },
+		{0xF824, 0xf0 },
+		{0xF825, 0x90 },
+		{0xF826, 0x30 },
+		{0xF827, 0x16 },
+		{0xF828, 0x74 },
+		{0xF829, 0x1e },
+		{0xF82A, 0xf0 },
+		{0xF82B, 0x90 },
+		{0xF82C, 0x30 },
+		{0xF82D, 0x1a },
+		{0xF82E, 0x74 },
+		{0xF82F, 0x6a },
+		{0xF830, 0xf0 },
+		{0xF831, 0x90 },
+		{0xF832, 0x30 },
+		{0xF833, 0x30 },
+		{0xF834, 0x74 },
+		{0xF835, 0x08 },
+		{0xF836, 0xf0 },
+		{0xF837, 0x90 },
+		{0xF838, 0x30 },
+		{0xF839, 0x36 },
+		{0xF83A, 0x74 },
+		{0xF83B, 0x2c },
+		{0xF83C, 0xf0 },
+		{0xF83D, 0x90 },
+		{0xF83E, 0x30 },
+		{0xF83F, 0x41 },
+		{0xF840, 0xe4 },
+		{0xF841, 0xf0 },
+		{0xF842, 0xa3 },
+		{0xF843, 0x74 },
+		{0xF844, 0x24 },
+		{0xF845, 0xf0 },
+		{0xF846, 0x90 },
+		{0xF847, 0x30 },
+		{0xF848, 0x45 },
+		{0xF849, 0x74 },
+		{0xF84A, 0x81 },
+		{0xF84B, 0xf0 },
+		{0xF84C, 0x90 },
+		{0xF84D, 0x30 },
+		{0xF84E, 0x98 },
+		{0xF84F, 0x74 },
+		{0xF850, 0x01 },
+		{0xF851, 0xf0 },
+		{0xF852, 0x90 },
+		{0xF853, 0x30 },
+		{0xF854, 0x9d },
+		{0xF855, 0x74 },
+		{0xF856, 0x05 },
+		{0xF857, 0xf0 },
+		{0xF858, 0xe5 },
+		{0xF859, 0x7d },
+		{0xF85A, 0x70 },
+		{0xF85B, 0x22 },
+		{0xF85C, 0x90 },
+		{0xF85D, 0x02 },
+		{0xF85E, 0x00 },
+		{0xF85F, 0x74 },
+		{0xF860, 0x02 },
+		{0xF861, 0xf0 },
+		{0xF862, 0xa3 },
+		{0xF863, 0x74 },
+		{0xF864, 0x54 },
+		{0xF865, 0xf0 },
+		{0xF866, 0x90 },
+		{0xF867, 0x30 },
+		{0xF868, 0x05 },
+		{0xF869, 0x74 },
+		{0xF86A, 0x01 },
+		{0xF86B, 0xf0 },
+		{0xF86C, 0x90 },
+		{0xF86D, 0x30 },
+		{0xF86E, 0x1b },
+		{0xF86F, 0x74 },
+		{0xF870, 0x29 },
+		{0xF871, 0xf0 },
+		{0xF872, 0x90 },
+		{0xF873, 0x30 },
+		{0xF874, 0x30 },
+		{0xF875, 0xe4 },
+		{0xF876, 0xf0 },
+		{0xF877, 0x90 },
+		{0xF878, 0x30 },
+		{0xF879, 0x35 },
+		{0xF87A, 0x04 },
+		{0xF87B, 0xf0 },
+		{0xF87C, 0x80 },
+		{0xF87D, 0x69 },
+		{0xF87E, 0xe5 },
+		{0xF87F, 0x7d },
+		{0xF880, 0x64 },
+		{0xF881, 0x02 },
+		{0xF882, 0x70 },
+		{0xF883, 0x3c },
+		{0xF884, 0x90 },
+		{0xF885, 0x02 },
+		{0xF886, 0x00 },
+		{0xF887, 0x74 },
+		{0xF888, 0x04 },
+		{0xF889, 0xf0 },
+		{0xF88A, 0xa3 },
+		{0xF88B, 0x74 },
+		{0xF88C, 0x10 },
+		{0xF88D, 0xf0 },
+		{0xF88E, 0x90 },
+		{0xF88F, 0x30 },
+		{0xF890, 0x04 },
+		{0xF891, 0x74 },
+		{0xF892, 0x34 },
+		{0xF893, 0xf0 },
+		{0xF894, 0xa3 },
+		{0xF895, 0x74 },
+		{0xF896, 0x07 },
+		{0xF897, 0xf0 },
+		{0xF898, 0x90 },
+		{0xF899, 0x30 },
+		{0xF89A, 0x10 },
+		{0xF89B, 0x74 },
+		{0xF89C, 0x10 },
+		{0xF89D, 0xf0 },
+		{0xF89E, 0x90 },
+		{0xF89F, 0x30 },
+		{0xF8A0, 0x16 },
+		{0xF8A1, 0x74 },
+		{0xF8A2, 0x1f },
+		{0xF8A3, 0xf0 },
+		{0xF8A4, 0x90 },
+		{0xF8A5, 0x30 },
+		{0xF8A6, 0x1a },
+		{0xF8A7, 0x74 },
+		{0xF8A8, 0x62 },
+		{0xF8A9, 0xf0 },
+		{0xF8AA, 0xa3 },
+		{0xF8AB, 0x74 },
+		{0xF8AC, 0x2a },
+		{0xF8AD, 0xf0 },
+		{0xF8AE, 0x90 },
+		{0xF8AF, 0x30 },
+		{0xF8B0, 0x35 },
+		{0xF8B1, 0x74 },
+		{0xF8B2, 0x04 },
+		{0xF8B3, 0xf0 },
+		{0xF8B4, 0x90 },
+		{0xF8B5, 0x30 },
+		{0xF8B6, 0x41 },
+		{0xF8B7, 0x74 },
+		{0xF8B8, 0x60 },
+		{0xF8B9, 0xf0 },
+		{0xF8BA, 0xa3 },
+		{0xF8BB, 0x74 },
+		{0xF8BC, 0x64 },
+		{0xF8BD, 0xf0 },
+		{0xF8BE, 0x80 },
+		{0xF8BF, 0x27 },
+		{0xF8C0, 0xe5 },
+		{0xF8C1, 0x7d },
+		{0xF8C2, 0xb4 },
+		{0xF8C3, 0x03 },
+		{0xF8C4, 0x22 },
+		{0xF8C5, 0x90 },
+		{0xF8C6, 0x02 },
+		{0xF8C7, 0x00 },
+		{0xF8C8, 0x74 },
+		{0xF8C9, 0x02 },
+		{0xF8CA, 0xf0 },
+		{0xF8CB, 0xa3 },
+		{0xF8CC, 0x74 },
+		{0xF8CD, 0x26 },
+		{0xF8CE, 0xf0 },
+		{0xF8CF, 0x90 },
+		{0xF8D0, 0x30 },
+		{0xF8D1, 0x05 },
+		{0xF8D2, 0x74 },
+		{0xF8D3, 0x03 },
+		{0xF8D4, 0xf0 },
+		{0xF8D5, 0x90 },
+		{0xF8D6, 0x30 },
+		{0xF8D7, 0x11 },
+		{0xF8D8, 0x74 },
+		{0xF8D9, 0x01 },
+		{0xF8DA, 0xf0 },
+		{0xF8DB, 0x90 },
+		{0xF8DC, 0x30 },
+		{0xF8DD, 0x1b },
+		{0xF8DE, 0x74 },
+		{0xF8DF, 0x2a },
+		{0xF8E0, 0xf0 },
+		{0xF8E1, 0x90 },
+		{0xF8E2, 0x30 },
+		{0xF8E3, 0x35 },
+		{0xF8E4, 0x74 },
+		{0xF8E5, 0x03 },
+		{0xF8E6, 0xf0 },
+		{0xF8E7, 0x90 },
+		{0xF8E8, 0x41 },
+		{0xF8E9, 0x01 },
+		{0xF8EA, 0xe0 },
+		{0xF8EB, 0xf5 },
+		{0xF8EC, 0x79 },
+		{0xF8ED, 0x90 },
+		{0xF8EE, 0x43 },
+		{0xF8EF, 0x87 },
+		{0xF8F0, 0xe0 },
+		{0xF8F1, 0xf5 },
+		{0xF8F2, 0x7a },
+		{0xF8F3, 0x90 },
+		{0xF8F4, 0x42 },
+		{0xF8F5, 0x05 },
+		{0xF8F6, 0xe0 },
+		{0xF8F7, 0xf5 },
+		{0xF8F8, 0x7b },
+		{0xF8F9, 0x22 },
+		{0xF8FA, 0x78 },
+		{0xF8FB, 0x07 },
+		{0xF8FC, 0xe6 },
+		{0xF8FD, 0xf5 },
+		{0xF8FE, 0x7c },
+		{0xF8FF, 0xe5 },
+		{0xF900, 0x7c },
+		{0xF901, 0x60 },
+		{0xF902, 0x1e },
+		{0xF903, 0x90 },
+		{0xF904, 0x43 },
+		{0xF905, 0x83 },
+		{0xF906, 0xe0 },
+		{0xF907, 0xb4 },
+		{0xF908, 0x01 },
+		{0xF909, 0x17 },
+		{0xF90A, 0x90 },
+		{0xF90B, 0x43 },
+		{0xF90C, 0x87 },
+		{0xF90D, 0xe0 },
+		{0xF90E, 0xb4 },
+		{0xF90F, 0x01 },
+		{0xF910, 0x10 },
+		{0xF911, 0x15 },
+		{0xF912, 0x7c },
+		{0xF913, 0x90 },
+		{0xF914, 0x30 },
+		{0xF915, 0xa1 },
+		{0xF916, 0xe5 },
+		{0xF917, 0x7c },
+		{0xF918, 0xf0 },
+		{0xF919, 0x90 },
+		{0xF91A, 0x30 },
+		{0xF91B, 0xa0 },
+		{0xF91C, 0x74 },
+		{0xF91D, 0x01 },
+		{0xF91E, 0xf0 },
+		{0xF91F, 0x80 },
+		{0xF920, 0x05 },
+		{0xF921, 0xe4 },
+		{0xF922, 0x90 },
+		{0xF923, 0x30 },
+		{0xF924, 0xa0 },
+		{0xF925, 0xf0 },
+		{0xF926, 0x90 },
+		{0xF927, 0x41 },
+		{0xF928, 0x01 },
+		{0xF929, 0xe0 },
+		{0xF92A, 0xfc },
+		{0xF92B, 0x54 },
+		{0xF92C, 0x02 },
+		{0xF92D, 0xfe },
+		{0xF92E, 0xe5 },
+		{0xF92F, 0x79 },
+		{0xF930, 0x54 },
+		{0xF931, 0x02 },
+		{0xF932, 0xb5 },
+		{0xF933, 0x06 },
+		{0xF934, 0x0f },
+		{0xF935, 0x90 },
+		{0xF936, 0x43 },
+		{0xF937, 0x87 },
+		{0xF938, 0xe0 },
+		{0xF939, 0xb5 },
+		{0xF93A, 0x7a },
+		{0xF93B, 0x08 },
+		{0xF93C, 0x90 },
+		{0xF93D, 0x42 },
+		{0xF93E, 0x05 },
+		{0xF93F, 0xe0 },
+		{0xF940, 0x65 },
+		{0xF941, 0x7b },
+		{0xF942, 0x60 },
+		{0xF943, 0x0b },
+		{0xF944, 0x90 },
+		{0xF945, 0x30 },
+		{0xF946, 0x50 },
+		{0xF947, 0xe0 },
+		{0xF948, 0x54 },
+		{0xF949, 0xf9 },
+		{0xF94A, 0x44 },
+		{0xF94B, 0x02 },
+		{0xF94C, 0xf0 },
+		{0xF94D, 0x80 },
+		{0xF94E, 0x09 },
+		{0xF94F, 0x90 },
+		{0xF950, 0x30 },
+		{0xF951, 0x50 },
+		{0xF952, 0xe0 },
+		{0xF953, 0x54 },
+		{0xF954, 0xf9 },
+		{0xF955, 0x44 },
+		{0xF956, 0x04 },
+		{0xF957, 0xf0 },
+		{0xF958, 0x8c },
+		{0xF959, 0x79 },
+		{0xF95A, 0x90 },
+		{0xF95B, 0x43 },
+		{0xF95C, 0x87 },
+		{0xF95D, 0xe0 },
+		{0xF95E, 0xf5 },
+		{0xF95F, 0x7a },
+		{0xF960, 0x90 },
+		{0xF961, 0x42 },
+		{0xF962, 0x05 },
+		{0xF963, 0xe0 },
+		{0xF964, 0xf5 },
+		{0xF965, 0x7b },
+		{0xF966, 0x22 },
+		{0xF967, 0xc3 },
+		{0xF968, 0x90 },
+		{0xF969, 0x0b },
+		{0xF96A, 0x89 },
+		{0xF96B, 0xe0 },
+		{0xF96C, 0x94 },
+		{0xF96D, 0x1e },
+		{0xF96E, 0x90 },
+		{0xF96F, 0x0b },
+		{0xF970, 0x88 },
+		{0xF971, 0xe0 },
+		{0xF972, 0x94 },
+		{0xF973, 0x00 },
+		{0xF974, 0x50 },
+		{0xF975, 0x06 },
+		{0xF976, 0x7e },
+		{0xF977, 0x00 },
+		{0xF978, 0x7f },
+		{0xF979, 0x01 },
+		{0xF97A, 0x80 },
+		{0xF97B, 0x3d },
+		{0xF97C, 0xc3 },
+		{0xF97D, 0x90 },
+		{0xF97E, 0x0b },
+		{0xF97F, 0x89 },
+		{0xF980, 0xe0 },
+		{0xF981, 0x94 },
+		{0xF982, 0x3c },
+		{0xF983, 0x90 },
+		{0xF984, 0x0b },
+		{0xF985, 0x88 },
+		{0xF986, 0xe0 },
+		{0xF987, 0x94 },
+		{0xF988, 0x00 },
+		{0xF989, 0x50 },
+		{0xF98A, 0x06 },
+		{0xF98B, 0x7e },
+		{0xF98C, 0x00 },
+		{0xF98D, 0x7f },
+		{0xF98E, 0x02 },
+		{0xF98F, 0x80 },
+		{0xF990, 0x28 },
+		{0xF991, 0xc3 },
+		{0xF992, 0x90 },
+		{0xF993, 0x0b },
+		{0xF994, 0x89 },
+		{0xF995, 0xe0 },
+		{0xF996, 0x94 },
+		{0xF997, 0xfa },
+		{0xF998, 0x90 },
+		{0xF999, 0x0b },
+		{0xF99A, 0x88 },
+		{0xF99B, 0xe0 },
+		{0xF99C, 0x94 },
+		{0xF99D, 0x00 },
+		{0xF99E, 0x50 },
+		{0xF99F, 0x06 },
+		{0xF9A0, 0x7e },
+		{0xF9A1, 0x00 },
+		{0xF9A2, 0x7f },
+		{0xF9A3, 0x03 },
+		{0xF9A4, 0x80 },
+		{0xF9A5, 0x13 },
+		{0xF9A6, 0xc3 },
+		{0xF9A7, 0x90 },
+		{0xF9A8, 0x0b },
+		{0xF9A9, 0x88 },
+		{0xF9AA, 0xe0 },
+		{0xF9AB, 0x94 },
+		{0xF9AC, 0x80 },
+		{0xF9AD, 0x50 },
+		{0xF9AE, 0x06 },
+		{0xF9AF, 0x7e },
+		{0xF9B0, 0x00 },
+		{0xF9B1, 0x7f },
+		{0xF9B2, 0x04 },
+		{0xF9B3, 0x80 },
+		{0xF9B4, 0x04 },
+		{0xF9B5, 0xae },
+		{0xF9B6, 0x7e },
+		{0xF9B7, 0xaf },
+		{0xF9B8, 0x7f },
+		{0xF9B9, 0x90 },
+		{0xF9BA, 0xa0 },
+		{0xF9BB, 0xf8 },
+		{0xF9BC, 0xee },
+		{0xF9BD, 0xf0 },
+		{0xF9BE, 0xa3 },
+		{0xF9BF, 0xef },
+		{0xF9C0, 0xf0 },
+		{0xF9C1, 0x22 },
+		{0xF9C2, 0x90 },
+		{0xF9C3, 0x33 },
+		{0xF9C4, 0x82 },
+		{0xF9C5, 0xe0 },
+		{0xF9C6, 0xff },
+		{0xF9C7, 0x64 },
+		{0xF9C8, 0x01 },
+		{0xF9C9, 0x70 },
+		{0xF9CA, 0x30 },
+		{0xF9CB, 0xe5 },
+		{0xF9CC, 0x7f },
+		{0xF9CD, 0x64 },
+		{0xF9CE, 0x02 },
+		{0xF9CF, 0x45 },
+		{0xF9D0, 0x7e },
+		{0xF9D1, 0x70 },
+		{0xF9D2, 0x04 },
+		{0xF9D3, 0x7d },
+		{0xF9D4, 0x1e },
+		{0xF9D5, 0x80 },
+		{0xF9D6, 0x1d },
+		{0xF9D7, 0xe5 },
+		{0xF9D8, 0x7f },
+		{0xF9D9, 0x64 },
+		{0xF9DA, 0x03 },
+		{0xF9DB, 0x45 },
+		{0xF9DC, 0x7e },
+		{0xF9DD, 0x70 },
+		{0xF9DE, 0x04 },
+		{0xF9DF, 0x7d },
+		{0xF9E0, 0x3c },
+		{0xF9E1, 0x80 },
+		{0xF9E2, 0x11 },
+		{0xF9E3, 0xe5 },
+		{0xF9E4, 0x7f },
+		{0xF9E5, 0x64 },
+		{0xF9E6, 0x04 },
+		{0xF9E7, 0x45 },
+		{0xF9E8, 0x7e },
+		{0xF9E9, 0x70 },
+		{0xF9EA, 0x04 },
+		{0xF9EB, 0x7d },
+		{0xF9EC, 0xfa },
+		{0xF9ED, 0x80 },
+		{0xF9EE, 0x05 },
+		{0xF9EF, 0x90 },
+		{0xF9F0, 0x33 },
+		{0xF9F1, 0x81 },
+		{0xF9F2, 0xe0 },
+		{0xF9F3, 0xfd },
+		{0xF9F4, 0xae },
+		{0xF9F5, 0x05 },
+		{0xF9F6, 0x90 },
+		{0xF9F7, 0x33 },
+		{0xF9F8, 0x81 },
+		{0xF9F9, 0xed },
+		{0xF9FA, 0xf0 },
+		{0xF9FB, 0xef },
+		{0xF9FC, 0xb4 },
+		{0xF9FD, 0x01 },
+		{0xF9FE, 0x10 },
+		{0xF9FF, 0x90 },
+		{0xFA00, 0x01 },
+		{0xFA01, 0x00 },
+		{0xFA02, 0xe0 },
+		{0xFA03, 0x60 },
+		{0xFA04, 0x0a },
+		{0xFA05, 0x90 },
+		{0xFA06, 0xa1 },
+		{0xFA07, 0x10 },
+		{0xFA08, 0xe0 },
+		{0xFA09, 0xf5 },
+		{0xFA0A, 0x7e },
+		{0xFA0B, 0xa3 },
+		{0xFA0C, 0xe0 },
+		{0xFA0D, 0xf5 },
+		{0xFA0E, 0x7f },
+		{0xFA0F, 0x22 },
+		{0xFA10, 0x12 },
+		{0xFA11, 0x2f },
+		{0xFA12, 0x4d },
+		{0xFA13, 0x90 },
+		{0xFA14, 0x35 },
+		{0xFA15, 0x38 },
+		{0xFA16, 0xe0 },
+		{0xFA17, 0x70 },
+		{0xFA18, 0x05 },
+		{0xFA19, 0x12 },
+		{0xFA1A, 0x00 },
+		{0xFA1B, 0x0e },
+		{0xFA1C, 0x80 },
+		{0xFA1D, 0x03 },
+		{0xFA1E, 0x12 },
+		{0xFA1F, 0x07 },
+		{0xFA20, 0xc9 },
+		{0xFA21, 0x90 },
+		{0xFA22, 0x40 },
+		{0xFA23, 0x06 },
+		{0xFA24, 0xe0 },
+		{0xFA25, 0xf4 },
+		{0xFA26, 0x54 },
+		{0xFA27, 0x02 },
+		{0xFA28, 0xff },
+		{0xFA29, 0xe0 },
+		{0xFA2A, 0x54 },
+		{0xFA2B, 0x01 },
+		{0xFA2C, 0x4f },
+		{0xFA2D, 0x90 },
+		{0xFA2E, 0x31 },
+		{0xFA2F, 0x32 },
+		{0xFA30, 0xf0 },
+		{0xFA31, 0x90 },
+		{0xFA32, 0xfa },
+		{0xFA33, 0x9d },
+		{0xFA34, 0xe0 },
+		{0xFA35, 0x70 },
+		{0xFA36, 0x03 },
+		{0xFA37, 0x12 },
+		{0xFA38, 0x27 },
+		{0xFA39, 0x27 },
+		{0xFA3A, 0x02 },
+		{0xFA3B, 0x05 },
+		{0xFA3C, 0xac },
+		{0xFA3D, 0x22 },
+		{0xFA3E, 0xf0 },
+		{0xFA3F, 0xe5 },
+		{0xFA40, 0x3a },
+		{0xFA41, 0xb4 },
+		{0xFA42, 0x06 },
+		{0xFA43, 0x06 },
+		{0xFA44, 0x63 },
+		{0xFA45, 0x3e },
+		{0xFA46, 0x02 },
+		{0xFA47, 0x12 },
+		{0xFA48, 0x03 },
+		{0xFA49, 0xea },
+		{0xFA4A, 0x02 },
+		{0xFA4B, 0x17 },
+		{0xFA4C, 0x4a },
+		{0xFA4D, 0x22 },
+		{0x35C9, 0xFA },
+		{0x35CA, 0x01 },
+		{0x35CB, 0x67 },
+		{0x35CC, 0x01 },
+		{0x35CD, 0xC2 },
+		{0x35CE, 0x02 },
+		{0x35CF, 0x10 },
+		{0x35D0, 0x02 },
+		{0x35D1, 0x3E },
+		{0x35D3, 0xF6 },
+		{0x35D5, 0x07 },
+		{0x35D7, 0xA3 },
+		{0x35DB, 0x02 },
+		{0x35DD, 0x06 },
+		{0x35DF, 0x27 },
+		{0x35E6, 0x28 },
+		{0x35E7, 0x76 },
+		{0x35E8, 0x2A },
+		{0x35E9, 0x15 },
+		{0x35EA, 0x2D },
+		{0x35EB, 0x07 },
+		{0x35EC, 0x04 },
+		{0x35ED, 0x43 },
+		{0x35EE, 0x05 },
+		{0x35EF, 0xA9 },
+		{0x35F0, 0x17 },
+		{0x35F1, 0x41 },
+		{0x35F2, 0x24 },
+		{0x35F3, 0x88 },
+		{0x35F4, 0x01 },
+		{0x35F5, 0x54 },
+		{0x35F6, 0x01 },
+		{0x35F7, 0x55 },
+		{0x35F8, 0x2E },
+		{0x35F9, 0xF2 },
+		{0x35FA, 0x06 },
+		{0x35FB, 0x02 },
+		{0x35FC, 0x06 },
+		{0x35FD, 0x03 },
+		{0x35FE, 0x06 },
+		{0x35FF, 0x04 },
+		{0x3600, 0x0F },
+		{0x3601, 0x48 },
+		{0x3602, 0x0F },
+		{0x3603, 0x49 },
+		{0x3604, 0x0F },
+		{0x3605, 0x4A },
+		{0x35C2, 0xFF },
+		{0x35C3, 0xFF },
+		{0x35C4, 0xFF },
+		{0x35C5, 0xC0 },
+		{0x35C0, 0x01 },
+
+
+		{0xa098, 0x02 },
+		{0xa099, 0x87 },
+		{0xa09c, 0x00 },
+		{0xa09d, 0xc5 },
+		{0xa4ec, 0x05 },
+		{0xa4ed, 0x05 },
+		{0xa4f0, 0x04 },
+		{0xa4f1, 0x04 },
+		{0xa4f4, 0x04 },
+		{0xa4f5, 0x05 },
+		{0xa4f8, 0x05 },
+		{0xa4f9, 0x07 },
+		{0xa4fc, 0x07 },
+		{0xa4fd, 0x07 },
+		{0xa500, 0x07 },
+		{0xa501, 0x07 },
+		{0xa504, 0x08 },
+		{0xa505, 0x08 },
+		{0xa518, 0x01 },
+		{0xa519, 0x02 },
+		{0xa51c, 0x01 },
+		{0xa51d, 0x00 },
+		{0xa534, 0x00 },
+		{0xa535, 0x04 },
+		{0xa538, 0x04 },
+		{0xa539, 0x03 },
+		{0xa53c, 0x05 },
+		{0xa53d, 0x07 },
+		{0xa540, 0x07 },
+		{0xa541, 0x06 },
+		{0xa544, 0x07 },
+		{0xa545, 0x06 },
+		{0xa548, 0x05 },
+		{0xa549, 0x06 },
+		{0xa54c, 0x06 },
+		{0xa54d, 0x07 },
+		{0xa550, 0x07 },
+		{0xa551, 0x04 },
+		{0xa554, 0x04 },
+		{0xa555, 0x04 },
+		{0xa558, 0x05 },
+		{0xa559, 0x06 },
+		{0xa55c, 0x07 },
+		{0xa55d, 0x07 },
+		{0xa56c, 0x00 },
+		{0xa56d, 0x0a },
+		{0xa570, 0x08 },
+		{0xa571, 0x05 },
+		{0xa574, 0x04 },
+		{0xa575, 0x03 },
+		{0xa578, 0x04 },
+		{0xa579, 0x04 },
+		{0xa58c, 0x1f },
+		{0xa58d, 0x1b },
+		{0xa590, 0x17 },
+		{0xa591, 0x13 },
+		{0xa594, 0x10 },
+		{0xa595, 0x0d },
+		{0xa598, 0x0f },
+		{0xa599, 0x11 },
+		{0xa59c, 0x03 },
+		{0xa59d, 0x03 },
+		{0xa5a0, 0x03 },
+		{0xa5a1, 0x03 },
+		{0xa5a4, 0x03 },
+		{0xa5a5, 0x04 },
+		{0xa5a8, 0x05 },
+		{0xa5a9, 0x00 },
+		{0xa5ac, 0x00 },
+		{0xa5ad, 0x00 },
+		{0xa5b0, 0x00 },
+		{0xa5b1, 0x00 },
+		{0xa5b4, 0x00 },
+		{0xa5b5, 0x00 },
+		{0xa5c4, 0x1f },
+		{0xa5c5, 0x13 },
+		{0xa5c8, 0x14 },
+		{0xa5c9, 0x14 },
+		{0xa5cc, 0x14 },
+		{0xa5cd, 0x13 },
+		{0xa5d0, 0x17 },
+		{0xa5d1, 0x1a },
+		{0xa5f4, 0x05 },
+		{0xa5f5, 0x05 },
+		{0xa5f8, 0x05 },
+		{0xa5f9, 0x06 },
+		{0xa5fc, 0x06 },
+		{0xa5fd, 0x06 },
+		{0xa600, 0x06 },
+		{0xa601, 0x06 },
+		{0xa608, 0x07 },
+		{0xa609, 0x08 },
+		{0xa60c, 0x08 },
+		{0xa60d, 0x07 },
+		{0xa63c, 0x00 },
+		{0xa63d, 0x02 },
+		{0xa640, 0x02 },
+		{0xa641, 0x02 },
+		{0xa644, 0x02 },
+		{0xa645, 0x02 },
+		{0xa648, 0x03 },
+		{0xa649, 0x04 },
+		{0xa64c, 0x0a },
+		{0xa64d, 0x09 },
+		{0xa650, 0x08 },
+		{0xa651, 0x09 },
+		{0xa654, 0x09 },
+		{0xa655, 0x0a },
+		{0xa658, 0x0a },
+		{0xa659, 0x0a },
+		{0xa65c, 0x0a },
+		{0xa65d, 0x09 },
+		{0xa660, 0x09 },
+		{0xa661, 0x09 },
+		{0xa664, 0x09 },
+		{0xa665, 0x08 },
+		{0xa680, 0x01 },
+		{0xa681, 0x02 },
+		{0xa694, 0x1f },
+		{0xa695, 0x10 },
+		{0xa698, 0x0e },
+		{0xa699, 0x0c },
+		{0xa69c, 0x0d },
+		{0xa69d, 0x0d },
+		{0xa6a0, 0x0f },
+		{0xa6a1, 0x11 },
+		{0xa6a4, 0x00 },
+		{0xa6a5, 0x00 },
+		{0xa6a8, 0x00 },
+		{0xa6a9, 0x00 },
+		{0xa6ac, 0x00 },
+		{0xa6ad, 0x00 },
+		{0xa6b0, 0x00 },
+		{0xa6b1, 0x04 },
+		{0xa6b4, 0x04 },
+		{0xa6b5, 0x04 },
+		{0xa6b8, 0x04 },
+		{0xa6b9, 0x04 },
+		{0xa6bc, 0x05 },
+		{0xa6bd, 0x05 },
+		{0xa6c0, 0x1f },
+		{0xa6c1, 0x1f },
+		{0xa6c4, 0x1f },
+		{0xa6c5, 0x1f },
+		{0xa6c8, 0x1f },
+		{0xa6c9, 0x1f },
+		{0xa6cc, 0x1f },
+		{0xa6cd, 0x0b },
+		{0xa6d0, 0x0c },
+		{0xa6d1, 0x0d },
+		{0xa6d4, 0x0d },
+		{0xa6d5, 0x0d },
+		{0xa6d8, 0x11 },
+		{0xa6d9, 0x14 },
+		{0xa6fc, 0x02 },
+		{0xa6fd, 0x03 },
+		{0xa700, 0x03 },
+		{0xa701, 0x03 },
+		{0xa704, 0x03 },
+		{0xa705, 0x04 },
+		{0xa708, 0x05 },
+		{0xa709, 0x02 },
+		{0xa70c, 0x02 },
+		{0xa70d, 0x02 },
+		{0xa710, 0x03 },
+		{0xa711, 0x04 },
+		{0xa714, 0x04 },
+		{0xa715, 0x04 },
+		{0xa744, 0x00 },
+		{0xa745, 0x03 },
+		{0xa748, 0x04 },
+		{0xa749, 0x04 },
+		{0xa74c, 0x05 },
+		{0xa74d, 0x06 },
+		{0xa750, 0x07 },
+		{0xa751, 0x07 },
+		{0xa754, 0x05 },
+		{0xa755, 0x05 },
+		{0xa758, 0x05 },
+		{0xa759, 0x05 },
+		{0xa75c, 0x05 },
+		{0xa75d, 0x06 },
+		{0xa760, 0x07 },
+		{0xa761, 0x07 },
+		{0xa764, 0x06 },
+		{0xa765, 0x05 },
+		{0xa768, 0x05 },
+		{0xa769, 0x05 },
+		{0xa76c, 0x06 },
+		{0xa76d, 0x07 },
+		{0xa77c, 0x00 },
+		{0xa77d, 0x05 },
+		{0xa780, 0x05 },
+		{0xa781, 0x05 },
+		{0xa784, 0x05 },
+		{0xa785, 0x04 },
+		{0xa788, 0x05 },
+		{0xa789, 0x06 },
+		{0xa79c, 0x1f },
+		{0xa79d, 0x15 },
+		{0xa7a0, 0x13 },
+		{0xa7a1, 0x10 },
+		{0xa7a4, 0x0f },
+		{0xa7a5, 0x0d },
+		{0xa7a8, 0x11 },
+		{0xa7a9, 0x14 },
+		{0xa7ac, 0x02 },
+		{0xa7ad, 0x02 },
+		{0xa7b0, 0x02 },
+		{0xa7b1, 0x02 },
+		{0xa7b4, 0x02 },
+		{0xa7b5, 0x03 },
+		{0xa7b8, 0x03 },
+		{0xa7b9, 0x00 },
+		{0xa7bc, 0x00 },
+		{0xa7bd, 0x00 },
+		{0xa7c0, 0x00 },
+		{0xa7c1, 0x00 },
+		{0xa7c4, 0x00 },
+		{0xa7c5, 0x00 },
+		{0xa7d4, 0x1f },
+		{0xa7d5, 0x0d },
+		{0xa7d8, 0x0f },
+		{0xa7d9, 0x10 },
+		{0xa7dc, 0x10 },
+		{0xa7dd, 0x10 },
+		{0xa7e0, 0x13 },
+		{0xa7e1, 0x16 },
+		{0xa7f4, 0x00 },
+		{0xa7f5, 0x03 },
+		{0xa7f8, 0x04 },
+		{0xa7f9, 0x04 },
+		{0xa7fc, 0x04 },
+		{0xa7fd, 0x03 },
+		{0xa800, 0x03 },
+		{0xa801, 0x03 },
+		{0xa804, 0x03 },
+		{0xa805, 0x03 },
+		{0xa808, 0x03 },
+		{0xa809, 0x03 },
+		{0xa80c, 0x03 },
+		{0xa80d, 0x04 },
+		{0xa810, 0x04 },
+		{0xa811, 0x0a },
+		{0xa814, 0x0a },
+		{0xa815, 0x0a },
+		{0xa818, 0x0f },
+		{0xa819, 0x14 },
+		{0xa81c, 0x14 },
+		{0xa81d, 0x14 },
+		{0xa82c, 0x00 },
+		{0xa82d, 0x04 },
+		{0xa830, 0x02 },
+		{0xa831, 0x00 },
+		{0xa834, 0x00 },
+		{0xa835, 0x00 },
+		{0xa838, 0x00 },
+		{0xa839, 0x00 },
+		{0xa840, 0x1f },
+		{0xa841, 0x1f },
+		{0xa848, 0x1f },
+		{0xa849, 0x1f },
+		{0xa84c, 0x1f },
+		{0xa84d, 0x0c },
+		{0xa850, 0x0c },
+		{0xa851, 0x0c },
+		{0xa854, 0x0c },
+		{0xa855, 0x0c },
+		{0xa858, 0x0c },
+		{0xa859, 0x0c },
+		{0xa85c, 0x0c },
+		{0xa85d, 0x0c },
+		{0xa860, 0x0c },
+		{0xa861, 0x0c },
+		{0xa864, 0x0c },
+		{0xa865, 0x0c },
+		{0xa868, 0x0c },
+		{0xa869, 0x0c },
+		{0xa86c, 0x0c },
+		{0xa86d, 0x0c },
+		{0xa870, 0x0c },
+		{0xa871, 0x0c },
+		{0xa874, 0x0c },
+		{0xa875, 0x0c },
+		{0xa878, 0x1f },
+		{0xa879, 0x1f },
+		{0xa87c, 0x1f },
+		{0xa87d, 0x1f },
+		{0xa880, 0x1f },
+		{0xa881, 0x1f },
+		{0xa884, 0x1f },
+		{0xa885, 0x0c },
+		{0xa888, 0x0c },
+		{0xa889, 0x0c },
+		{0xa88c, 0x0c },
+		{0xa88d, 0x0c },
+		{0xa890, 0x0c },
+		{0xa891, 0x0c },
+		{0xa898, 0x1f },
+		{0xa899, 0x1f },
+		{0xa8a0, 0x1f },
+		{0xa8a1, 0x1f },
+		{0xa8a4, 0x1f },
+		{0xa8a5, 0x0c },
+		{0xa8a8, 0x0c },
+		{0xa8a9, 0x0c },
+		{0xa8ac, 0x0c },
+		{0xa8ad, 0x0c },
+		{0xa8b0, 0x0c },
+		{0xa8b1, 0x0c },
+		{0xa8b4, 0x0c },
+		{0xa8b5, 0x0c },
+		{0xa8b8, 0x0c },
+		{0xa8b9, 0x0c },
+		{0xa8bc, 0x0c },
+		{0xa8bd, 0x0c },
+		{0xa8c0, 0x0c },
+		{0xa8c1, 0x0c },
+		{0xa8c4, 0x0c },
+		{0xa8c5, 0x0c },
+		{0xa8c8, 0x0c },
+		{0xa8c9, 0x0c },
+		{0xa8cc, 0x0c },
+		{0xa8cd, 0x0c },
+		{0xa8d0, 0x1f },
+		{0xa8d1, 0x1f },
+		{0xa8d4, 0x1f },
+		{0xa8d5, 0x1f },
+		{0xa8d8, 0x1f },
+		{0xa8d9, 0x1f },
+		{0xa8dc, 0x1f },
+		{0xa8dd, 0x0c },
+		{0xa8e0, 0x0c },
+		{0xa8e1, 0x0c },
+		{0xa8e4, 0x0c },
+		{0xa8e5, 0x0c },
+		{0xa8e8, 0x0c },
+		{0xa8e9, 0x0c },
+		{0xa8f0, 0x1f },
+		{0xa8f1, 0x1f },
+		{0xa8f8, 0x1f },
+		{0xa8f9, 0x1f },
+		{0xa8fc, 0x1f },
+		{0xa8fd, 0x0c },
+		{0xa900, 0x0c },
+		{0xa901, 0x0c },
+		{0xa904, 0x0c },
+		{0xa905, 0x0c },
+		{0xa908, 0x0c },
+		{0xa909, 0x0c },
+		{0xa90c, 0x0c },
+		{0xa90d, 0x0c },
+		{0xa910, 0x0c },
+		{0xa911, 0x0c },
+		{0xa914, 0x0c },
+		{0xa915, 0x0c },
+		{0xa918, 0x0c },
+		{0xa919, 0x0c },
+		{0xa91c, 0x0c },
+		{0xa91d, 0x0c },
+		{0xa920, 0x0c },
+		{0xa921, 0x0c },
+		{0xa924, 0x0c },
+		{0xa925, 0x0c },
+		{0xa928, 0x1f },
+		{0xa929, 0x1f },
+		{0xa92c, 0x1f },
+		{0xa92d, 0x1f },
+		{0xa930, 0x1f },
+		{0xa931, 0x1f },
+		{0xa934, 0x1f },
+		{0xa935, 0x0c },
+		{0xa938, 0x0c },
+		{0xa939, 0x0c },
+		{0xa93c, 0x0c },
+		{0xa93d, 0x0c },
+		{0xa940, 0x0c },
+		{0xa941, 0x0c },
+		{0xa96c, 0x0d },
+		{0xa96d, 0x16 },
+		{0xa970, 0x19 },
+		{0xa971, 0x0e },
+		{0xa974, 0x16 },
+		{0xa975, 0x1a },
+		{0xa978, 0x0d },
+		{0xa979, 0x15 },
+		{0xa97c, 0x19 },
+		{0xa97d, 0x0d },
+		{0xa980, 0x15 },
+		{0xa981, 0x1a },
+		{0xa984, 0x0d },
+		{0xa985, 0x15 },
+		{0xa988, 0x1a },
+		{0xa989, 0x0d },
+		{0xa98c, 0x15 },
+		{0xa98d, 0x1a },
+		{0xa990, 0x0b },
+		{0xa991, 0x11 },
+		{0xa994, 0x02 },
+		{0xa995, 0x0e },
+		{0xa998, 0x16 },
+		{0xa999, 0x02 },
+		{0xa99c, 0x0c },
+		{0xa99d, 0x13 },
+		{0xa9a0, 0x02 },
+		{0xa9a1, 0x0c },
+		{0xa9a4, 0x12 },
+		{0xa9a5, 0x02 },
+		{0xa9a8, 0x0c },
+		{0xa9a9, 0x12 },
+		{0xa9ac, 0x02 },
+		{0xa9ad, 0x0c },
+		{0xa9b0, 0x12 },
+		{0xa9b1, 0x02 },
+		{0xa9b4, 0x10 },
+		{0xa9b5, 0x1e },
+		{0xa9b8, 0x0f },
+		{0xa9b9, 0x13 },
+		{0xa9bc, 0x20 },
+		{0xa9bd, 0x10 },
+		{0xa9c0, 0x11 },
+		{0xa9c1, 0x1e },
+		{0xa9c4, 0x10 },
+		{0xa9c5, 0x11 },
+		{0xa9c8, 0x1e },
+		{0xa9c9, 0x10 },
+		{0xa9cc, 0x11 },
+		{0xa9cd, 0x20 },
+		{0xa9d0, 0x10 },
+		{0xa9d1, 0x13 },
+		{0xa9d4, 0x24 },
+		{0xa9d5, 0x10 },
+		{0xa9f0, 0x02 },
+		{0xa9f1, 0x01 },
+		{0xa9f8, 0x19 },
+		{0xa9f9, 0x0b },
+		{0xa9fc, 0x0a },
+		{0xa9fd, 0x07 },
+		{0xaa00, 0x0c },
+		{0xaa01, 0x0e },
+		{0xaa08, 0x0c },
+		{0xaa09, 0x06 },
+		{0xaa0c, 0x0c },
+		{0xaa0d, 0x0a },
+		{0xaa24, 0x10 },
+		{0xaa25, 0x12 },
+		{0xaa28, 0x0b },
+		{0xaa29, 0x07 },
+		{0xaa2c, 0x10 },
+		{0xaa2d, 0x14 },
+		{0xaa34, 0x0e },
+		{0xaa35, 0x0e },
+		{0xaa38, 0x07 },
+		{0xaa39, 0x07 },
+		{0xaa3c, 0x0e },
+		{0xaa3d, 0x0c },
+		{0xaa48, 0x09 },
+		{0xaa49, 0x0c },
+		{0xaa4c, 0x0c },
+		{0xaa4d, 0x07 },
+		{0xaa54, 0x08 },
+		{0xaa55, 0x06 },
+		{0xaa58, 0x04 },
+		{0xaa59, 0x05 },
+		{0xaa5c, 0x06 },
+		{0xaa5d, 0x06 },
+		{0xaa68, 0x05 },
+		{0xaa69, 0x05 },
+		{0xaa6c, 0x04 },
+		{0xaa6d, 0x05 },
+		{0xaa74, 0x06 },
+		{0xaa75, 0x04 },
+		{0xaa78, 0x05 },
+		{0xaa79, 0x05 },
+		{0xaa7c, 0x04 },
+		{0xaa7d, 0x06 },
+		{0xac18, 0x14 },
+		{0xac19, 0x00 },
+		{0xac1c, 0x14 },
+		{0xac1d, 0x00 },
+		{0xac20, 0x14 },
+		{0xac21, 0x00 },
+		{0xac24, 0x14 },
+		{0xac25, 0x00 },
+		{0xac28, 0x14 },
+		{0xac29, 0x00 },
+		{0xac2c, 0x14 },
+		{0xac2d, 0x00 },
+		{0xac34, 0x16 },
+		{0xac35, 0x00 },
+		{0xac38, 0x16 },
+		{0xac39, 0x00 },
+		{0xac3c, 0x16 },
+		{0xac3d, 0x00 },
+		{0xac40, 0x16 },
+		{0xac41, 0x00 },
+		{0xac44, 0x16 },
+		{0xac45, 0x00 },
+		{0xac48, 0x16 },
+		{0xac49, 0x00 },
+		{0xac50, 0x1b },
+		{0xac51, 0x00 },
+		{0xac54, 0x1b },
+		{0xac55, 0x00 },
+		{0xac58, 0x1b },
+		{0xac59, 0x00 },
+		{0xac5c, 0x1b },
+		{0xac5d, 0x00 },
+		{0xac60, 0x1b },
+		{0xac61, 0x00 },
+		{0xac64, 0x1b },
+		{0xac65, 0x00 },
+		{0xac74, 0x09 },
+		{0xac75, 0x0c },
+		{0xac78, 0x0f },
+		{0xac79, 0x11 },
+		{0xac7c, 0x12 },
+		{0xac7d, 0x14 },
+		{0xac80, 0x09 },
+		{0xac81, 0x0c },
+		{0xac84, 0x0f },
+		{0xac85, 0x11 },
+		{0xac88, 0x12 },
+		{0xac89, 0x14 },
+		{0xac8c, 0x09 },
+		{0xac8d, 0x0c },
+		{0xac90, 0x0f },
+		{0xac91, 0x11 },
+		{0xac94, 0x12 },
+		{0xac95, 0x14 },
+		{0xac98, 0x09 },
+		{0xac99, 0x0c },
+		{0xac9c, 0x0f },
+		{0xac9d, 0x11 },
+		{0xaca0, 0x12 },
+		{0xaca1, 0x14 },
+		{0xaca4, 0x09 },
+		{0xaca5, 0x0c },
+		{0xaca8, 0x0f },
+		{0xaca9, 0x11 },
+		{0xacac, 0x12 },
+		{0xacad, 0x14 },
+		{0xacb0, 0x07 },
+		{0xacb1, 0x09 },
+		{0xacb4, 0x0c },
+		{0xacb5, 0x0d },
+		{0xacb8, 0x0d },
+		{0xacb9, 0x0e },
+		{0xacbc, 0x05 },
+		{0xacbd, 0x07 },
+		{0xacc0, 0x0a },
+		{0xacc1, 0x0b },
+		{0xacc4, 0x0b },
+		{0xacc5, 0x0c },
+		{0xacc8, 0x03 },
+		{0xacc9, 0x04 },
+		{0xaccc, 0x07 },
+		{0xaccd, 0x08 },
+		{0xacd0, 0x09 },
+		{0xacd1, 0x09 },
+		{0x35B5, 0x01 },
+		{0x35BC, 0x01 },
+		{0x360A, 0x02 },
+		{0xFA9B, 0x01 },
+};
+
+#define NUM_LSC_CAST_REGS      33
+
+enum LSC_Cast_t{
+	cast_H = 0,
+	cast_U30,
+	cast_CW,
+	cast_D,
+	cast_MAX
+};
+
+static short int LSC_CorrectionForCast[cast_MAX][NUM_LSC_CAST_REGS] = {
+	{-30, -20,  8, 11, -16, -26, -35, -53, -9, -10, 44, 57, -39,
+		-14, 50, -173, -38, -32, -1, 9, 39, 51, -33, -49, -28,
+		-22, 7, 11, -21, 17, -62, -56, 0},
+	{-29, -18,  6,  1,  17, -35, -77, 0, 5, -17, -6, -22, -41, -1,
+		-37, 83, -38, -32, 1, -2, 15, 25, -67, 19, -28, -22, 5,
+		2, -18, 21, -86, 0, 0},
+	{-10, -15, -4, -6,  -8,  -3, -63, 8, 25, -9, -39, -51, -9,
+		0, -21, 112, -10, -23, -7, -9, 10, 18, -11, 23, -10,
+		-15, -4, -6, -10, -3, -52, 7, 0},
+	{  5,   3, -4, -5,  -1,   3,   4, 8, 12, 3, -22, -21, 7, 17,
+		2, 35, 8, 2, -3, -2, -9, -5, 10, 4, 9, 2, -4, -5,
+		-2, 0, -6, 9, 0}
+};
+
+static unsigned short LSC_CastRegs[] = {
+	0xFB7E,			/* H   */
+	0xFB3C,			/* U30 */
+	0xFAFA,			/* CW  */
+	0xFAB8			/* D65 */
+};
+
+/*=============================================================*/
+
+static int vx6953_i2c_rxdata(unsigned short saddr,
+	unsigned char *rxdata, int length)
+{
+	struct i2c_msg msgs[] = {
+		{
+			.addr  = saddr,
+			.flags = 0,
+			.len   = 2,
+			.buf   = rxdata,
+		},
+		{
+			.addr  = saddr,
+			.flags = I2C_M_RD,
+			.len   = 2,
+			.buf   = rxdata,
+		},
+	};
+	if (i2c_transfer(vx6953_client->adapter, msgs, 2) < 0) {
+		CDBG("vx6953_i2c_rxdata failed!\n");
+		return -EIO;
+	}
+	return 0;
+}
+static int32_t vx6953_i2c_txdata(unsigned short saddr,
+				unsigned char *txdata, int length)
+{
+	struct i2c_msg msg[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = length,
+			.buf = txdata,
+		 },
+	};
+	if (i2c_transfer(vx6953_client->adapter, msg, 1) < 0) {
+		CDBG("vx6953_i2c_txdata faild 0x%x\n", vx6953_client->addr);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+
+static int32_t vx6953_i2c_read(unsigned short raddr,
+	unsigned short *rdata, int rlen)
+{
+	int32_t rc = 0;
+	unsigned char buf[2];
+	if (!rdata)
+		return -EIO;
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (raddr & 0xFF00) >> 8;
+	buf[1] = (raddr & 0x00FF);
+	rc = vx6953_i2c_rxdata(vx6953_client->addr>>1, buf, rlen);
+	if (rc < 0) {
+		CDBG("vx6953_i2c_read 0x%x failed!\n", raddr);
+		return rc;
+	}
+	*rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]);
+	return rc;
+}
+static int32_t vx6953_i2c_write_b_sensor(unsigned short waddr, uint8_t bdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[3];
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = bdata;
+	CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata);
+	rc = vx6953_i2c_txdata(vx6953_client->addr>>1, buf, 3);
+	if (rc < 0) {
+		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+			waddr, bdata);
+	}
+	return rc;
+}
+static int32_t vx6953_i2c_write_w_sensor(unsigned short waddr, uint16_t wdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[4];
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = (wdata & 0xFF00) >> 8;
+	buf[3] = (wdata & 0x00FF);
+	CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, wdata);
+	rc = vx6953_i2c_txdata(vx6953_client->addr>>1, buf, 4);
+	if (rc < 0) {
+		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+			waddr, wdata);
+	}
+	return rc;
+}
+static int32_t vx6953_i2c_write_seq_sensor(unsigned short waddr,
+	uint8_t *bdata, uint16_t len)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[len+2];
+	int i;
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	for (i = 2; i < len+2; i++)
+		buf[i] = *bdata++;
+	rc = vx6953_i2c_txdata(vx6953_client->addr>>1, buf, len+2);
+	if (rc < 0) {
+		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+			 waddr, bdata[0]);
+	}
+	return rc;
+}
+
+static int32_t vx6953_i2c_write_w_table(struct vx6953_i2c_reg_conf const
+					 *reg_conf_tbl, int num)
+{
+	int i;
+	int32_t rc = -EIO;
+	for (i = 0; i < num; i++) {
+		rc = vx6953_i2c_write_b_sensor(reg_conf_tbl->waddr,
+			reg_conf_tbl->wdata);
+		if (rc < 0)
+			break;
+		reg_conf_tbl++;
+	}
+	return rc;
+}
+
+static void vx6953_get_pict_fps(uint16_t fps, uint16_t *pfps)
+{
+	/* input fps is preview fps in Q8 format */
+	uint16_t preview_frame_length_lines, snapshot_frame_length_lines;
+	uint16_t preview_line_length_pck, snapshot_line_length_pck;
+	uint32_t divider, d1, d2;
+	/* Total frame_length_lines and line_length_pck for preview */
+	preview_frame_length_lines = VX6953_QTR_SIZE_HEIGHT +
+		VX6953_VER_QTR_BLK_LINES;
+	preview_line_length_pck = VX6953_QTR_SIZE_WIDTH +
+		VX6953_HRZ_QTR_BLK_PIXELS;
+	/* Total frame_length_lines and line_length_pck for snapshot */
+	snapshot_frame_length_lines = VX6953_FULL_SIZE_HEIGHT +
+		VX6953_VER_FULL_BLK_LINES;
+	snapshot_line_length_pck = VX6953_FULL_SIZE_WIDTH +
+		VX6953_HRZ_FULL_BLK_PIXELS;
+	d1 = preview_frame_length_lines * 0x00000400/
+		snapshot_frame_length_lines;
+	d2 = preview_line_length_pck * 0x00000400/
+		snapshot_line_length_pck;
+	divider = d1 * d2 / 0x400;
+	/*Verify PCLK settings and frame sizes.*/
+	*pfps = (uint16_t) (fps * divider / 0x400);
+	/* 2 is the ratio of no.of snapshot channels
+	to number of preview channels */
+
+}
+
+static uint16_t vx6953_get_prev_lines_pf(void)
+{
+	if (vx6953_ctrl->prev_res == QTR_SIZE)
+		return VX6953_QTR_SIZE_HEIGHT + VX6953_VER_QTR_BLK_LINES;
+	else
+		return VX6953_FULL_SIZE_HEIGHT + VX6953_VER_FULL_BLK_LINES;
+
+}
+
+static uint16_t vx6953_get_prev_pixels_pl(void)
+{
+	if (vx6953_ctrl->prev_res == QTR_SIZE)
+		return VX6953_QTR_SIZE_WIDTH + VX6953_HRZ_QTR_BLK_PIXELS;
+	else
+		return VX6953_FULL_SIZE_WIDTH + VX6953_HRZ_FULL_BLK_PIXELS;
+}
+
+static uint16_t vx6953_get_pict_lines_pf(void)
+{
+		if (vx6953_ctrl->pict_res == QTR_SIZE)
+			return VX6953_QTR_SIZE_HEIGHT +
+				VX6953_VER_QTR_BLK_LINES;
+		else
+			return VX6953_FULL_SIZE_HEIGHT +
+				VX6953_VER_FULL_BLK_LINES;
+}
+
+static uint16_t vx6953_get_pict_pixels_pl(void)
+{
+	if (vx6953_ctrl->pict_res == QTR_SIZE)
+		return VX6953_QTR_SIZE_WIDTH +
+			VX6953_HRZ_QTR_BLK_PIXELS;
+	else
+		return VX6953_FULL_SIZE_WIDTH +
+			VX6953_HRZ_FULL_BLK_PIXELS;
+}
+
+static uint32_t vx6953_get_pict_max_exp_lc(void)
+{
+	if (vx6953_ctrl->pict_res == QTR_SIZE)
+		return (VX6953_QTR_SIZE_HEIGHT +
+			VX6953_VER_QTR_BLK_LINES)*24;
+	else
+		return (VX6953_FULL_SIZE_HEIGHT +
+			VX6953_VER_FULL_BLK_LINES)*24;
+}
+
+static int32_t vx6953_set_fps(struct fps_cfg	*fps)
+{
+	uint16_t total_lines_per_frame;
+	int32_t rc = 0;
+	total_lines_per_frame = (uint16_t)((VX6953_QTR_SIZE_HEIGHT +
+		VX6953_VER_QTR_BLK_LINES) * vx6953_ctrl->fps_divider/0x400);
+
+	vx6953_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
+		GROUPED_PARAMETER_HOLD);
+	if (vx6953_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_HI,
+		((total_lines_per_frame & 0xFF00) >> 8)) < 0)
+		return rc;
+	if (vx6953_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_LO,
+		(total_lines_per_frame & 0x00FF)) < 0)
+		return rc;
+	vx6953_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
+		GROUPED_PARAMETER_HOLD_OFF);
+	return rc;
+}
+
+static int32_t vx6953_write_exp_gain(uint16_t gain, uint32_t line)
+{
+	uint16_t line_length_pck, frame_length_lines;
+	uint8_t gain_hi, gain_lo;
+	uint8_t intg_time_hi, intg_time_lo;
+	uint8_t frame_length_lines_hi = 0, frame_length_lines_lo = 0;
+	int32_t rc = 0;
+	if (vx6953_ctrl->sensormode != SENSOR_SNAPSHOT_MODE) {
+		frame_length_lines = VX6953_QTR_SIZE_HEIGHT +
+		VX6953_VER_QTR_BLK_LINES;
+		line_length_pck = VX6953_QTR_SIZE_WIDTH +
+			VX6953_HRZ_QTR_BLK_PIXELS;
+		if (line > (frame_length_lines -
+			VX6953_STM5M0EDOF_OFFSET)) {
+			vx6953_ctrl->fps = (uint16_t) (30 * Q8 *
+			(frame_length_lines - VX6953_STM5M0EDOF_OFFSET)/
+			line);
+		} else {
+			vx6953_ctrl->fps = (uint16_t) (30 * Q8);
+		}
+	} else {
+		frame_length_lines = VX6953_FULL_SIZE_HEIGHT +
+				VX6953_VER_FULL_BLK_LINES;
+		line_length_pck = VX6953_FULL_SIZE_WIDTH +
+				VX6953_HRZ_FULL_BLK_PIXELS;
+	}
+
+	vx6953_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
+		GROUPED_PARAMETER_HOLD);
+	if ((line + VX6953_STM5M0EDOF_OFFSET) > MAX_FRAME_LENGTH_LINES) {
+		frame_length_lines = MAX_FRAME_LENGTH_LINES;
+		line = MAX_FRAME_LENGTH_LINES - VX6953_STM5M0EDOF_OFFSET;
+	} else if ((line + VX6953_STM5M0EDOF_OFFSET) > frame_length_lines) {
+		frame_length_lines = line + VX6953_STM5M0EDOF_OFFSET;
+		line = frame_length_lines;
+	}
+
+	frame_length_lines_hi = (uint8_t) ((frame_length_lines &
+		0xFF00) >> 8);
+	frame_length_lines_lo = (uint8_t) (frame_length_lines &
+		0x00FF);
+	vx6953_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_HI,
+		frame_length_lines_hi);
+	vx6953_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_LO,
+		frame_length_lines_lo);
+
+	/* update analogue gain registers */
+	gain_hi = (uint8_t) ((gain & 0xFF00) >> 8);
+	gain_lo = (uint8_t) (gain & 0x00FF);
+	vx6953_i2c_write_b_sensor(REG_ANALOGUE_GAIN_CODE_GLOBAL_LO,
+		gain_lo);
+	vx6953_i2c_write_b_sensor(REG_DIGITAL_GAIN_GREEN_R_LO, gain_hi);
+	vx6953_i2c_write_b_sensor(REG_DIGITAL_GAIN_RED_LO, gain_hi);
+	vx6953_i2c_write_b_sensor(REG_DIGITAL_GAIN_BLUE_LO, gain_hi);
+	vx6953_i2c_write_b_sensor(REG_DIGITAL_GAIN_GREEN_B_LO, gain_hi);
+	CDBG("%s, gain_hi 0x%x, gain_lo 0x%x\n", __func__,
+		gain_hi, gain_lo);
+	/* update line count registers */
+	intg_time_hi = (uint8_t) (((uint16_t)line & 0xFF00) >> 8);
+	intg_time_lo = (uint8_t) ((uint16_t)line & 0x00FF);
+	vx6953_i2c_write_b_sensor(REG_COARSE_INTEGRATION_TIME_HI,
+		intg_time_hi);
+	vx6953_i2c_write_b_sensor(REG_COARSE_INTEGRATION_TIME_LO,
+		intg_time_lo);
+	vx6953_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
+		GROUPED_PARAMETER_HOLD_OFF);
+
+	return rc;
+}
+
+static int32_t vx6953_set_pict_exp_gain(uint16_t gain, uint32_t line)
+{
+	int32_t rc = 0;
+	rc = vx6953_write_exp_gain(gain, line);
+	return rc;
+} /* endof vx6953_set_pict_exp_gain*/
+
+static int32_t vx6953_move_focus(int direction,
+	int32_t num_steps)
+{
+	return 0;
+}
+
+
+static int32_t vx6953_set_default_focus(uint8_t af_step)
+{
+	return 0;
+}
+
+static int32_t vx6953_test(enum vx6953_test_mode_t mo)
+{
+	int32_t rc = 0;
+	if (mo == TEST_OFF)
+		return rc;
+	else {
+		/* REG_0x30D8[4] is TESBYPEN: 0: Normal Operation,
+		1: Bypass Signal Processing
+		REG_0x30D8[5] is EBDMASK: 0:
+		Output Embedded data, 1: No output embedded data */
+		if (vx6953_i2c_write_b_sensor(REG_TEST_PATTERN_MODE,
+			(uint8_t) mo) < 0) {
+			return rc;
+		}
+	}
+	return rc;
+}
+
+static int vx6953_enable_edof(enum edof_mode_t edof_mode)
+{
+	int rc = 0;
+	if (edof_mode == VX6953_EDOF_ESTIMATION) {
+		/* EDof Estimation mode for preview */
+		if (vx6953_i2c_write_b_sensor(REG_0x0b80, 0x02) < 0)
+			return rc;
+		CDBG("VX6953_EDOF_ESTIMATION");
+	} else if (edof_mode == VX6953_EDOF_APPLICATION) {
+		/* EDof Application mode for Capture */
+		if (vx6953_i2c_write_b_sensor(REG_0x0b80, 0x01) < 0)
+			return rc;
+		CDBG("VX6953_EDOF_APPLICATION");
+	} else {
+		/* EDOF disabled */
+		if (vx6953_i2c_write_b_sensor(REG_0x0b80, 0x00) < 0)
+			return rc;
+		CDBG("VX6953_EDOF_DISABLE");
+	}
+	return rc;
+}
+
+static int32_t vx6953_patch_for_cut2(void)
+{
+	int32_t rc = 0;
+	rc = vx6953_i2c_write_w_table(patch_tbl_cut2,
+		ARRAY_SIZE(patch_tbl_cut2));
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+
+static int32_t vx6953_lsc_patch(void)
+{
+	int32_t rc = 0;
+	int i, j;
+	short int  v;
+	unsigned short version = 0;
+	unsigned short LSC_Raw[NUM_LSC_CAST_REGS];
+	unsigned short LSC_Fixed[NUM_LSC_CAST_REGS];
+
+	vx6953_i2c_read(0x10, &version, 1);
+	CDBG("Cut 3 Version %d\n", version);
+	if (version != 1)
+		return 0;
+
+	vx6953_i2c_write_b_sensor(0x3640, 0x00);
+	for (j = cast_H; j < cast_MAX; j++) {
+		for (i = 0; i < NUM_LSC_CAST_REGS; i++) {
+			rc = vx6953_i2c_read(LSC_CastRegs[cast_D]+(2*i),
+								&LSC_Raw[i], 2);
+			if (rc < 0)
+				return rc;
+			v = LSC_Raw[i];
+			v +=  LSC_CorrectionForCast[j][i];
+			LSC_Fixed[i] = (unsigned short) v;
+		}
+		for (i = 0; i < NUM_LSC_CAST_REGS; i++) {
+			rc = vx6953_i2c_write_w_sensor(LSC_CastRegs[j]+(2*i),
+								LSC_Fixed[i]);
+			if (rc < 0)
+				return rc;
+		}
+	}
+	CDBG("vx6953_lsc_patch done\n");
+	return rc;
+}
+
+static int32_t vx6953_sensor_setting(int update_type, int rt)
+{
+
+	int32_t rc = 0;
+	unsigned short frame_cnt;
+	struct msm_camera_csi_params vx6953_csi_params;
+	if (vx6953_ctrl->sensor_type != VX6953_STM5M0EDOF_CUT_2) {
+		switch (update_type) {
+		case REG_INIT:
+		if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+			struct vx6953_i2c_reg_conf init_tbl[] = {
+				{REG_0x0112,
+					vx6953_regs.reg_pat_init[0].
+					reg_0x0112},
+				{REG_0x0113,
+					vx6953_regs.reg_pat_init[0].
+					reg_0x0113},
+				{REG_VT_PIX_CLK_DIV,
+					vx6953_regs.reg_pat_init[0].
+					vt_pix_clk_div},
+				{0x303, 0x01},
+				{0x30b, 0x01},
+				{REG_PRE_PLL_CLK_DIV,
+					vx6953_regs.reg_pat_init[0].
+					pre_pll_clk_div},
+				{REG_PLL_MULTIPLIER,
+					vx6953_regs.reg_pat_init[0].
+					pll_multiplier},
+				{REG_OP_PIX_CLK_DIV,
+					vx6953_regs.reg_pat_init[0].
+					op_pix_clk_div},
+				{REG_0x3210, 0x01},
+				{REG_0x0111,
+					vx6953_regs.reg_pat_init[0].
+					reg_0x0111},
+				{REG_0x0b00,
+					vx6953_regs.reg_pat_init[0].
+					reg_0x0b00},
+				{REG_0x0136,
+					vx6953_regs.reg_pat_init[0].
+					reg_0x0136},
+				{REG_0x0137,
+					vx6953_regs.reg_pat_init[0].
+					reg_0x0137},
+				{REG_0x0b06,
+					vx6953_regs.reg_pat_init[0].
+					reg_0x0b06},
+				{REG_0x0b07,
+					vx6953_regs.reg_pat_init[0].
+					reg_0x0b07},
+				{REG_0x0b08,
+					vx6953_regs.reg_pat_init[0].
+					reg_0x0b08},
+				{REG_0x0b09,
+					vx6953_regs.reg_pat_init[0].
+					reg_0x0b09},
+				{REG_0x0b83,
+					vx6953_regs.reg_pat_init[0].
+					reg_0x0b83},
+				{REG_0x0b84,
+					vx6953_regs.reg_pat_init[0].
+					reg_0x0b84},
+				{REG_0x0b85,
+					vx6953_regs.reg_pat_init[0].
+					reg_0x0b85},
+				{REG_0x0b88,
+					vx6953_regs.reg_pat_init[0].
+					reg_0x0b88},
+				{REG_0x0b89,
+					vx6953_regs.reg_pat_init[0].
+					reg_0x0b89},
+				{REG_0x0b8a,
+					vx6953_regs.reg_pat_init[0].
+					reg_0x0b8a},
+				{0x3393, 0x06},
+				{0x3394, 0x07},
+				{0x338d, 0x08},
+				{0x338e, 0x08},
+				{0x338f, 0x00},
+			};
+			/* reset fps_divider */
+			vx6953_ctrl->fps = 30 * Q8;
+			/* stop streaming */
+
+			count = 0;
+			CDBG("Init vx6953_sensor_setting standby\n");
+			if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT,
+				MODE_SELECT_STANDBY_MODE) < 0)
+				return rc;
+			msleep(vx6953_stm5m0edof_delay_msecs_stdby);
+			vx6953_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
+			GROUPED_PARAMETER_HOLD);
+
+			rc = vx6953_i2c_write_w_table(cut3_cali_data,
+				ARRAY_SIZE(cut3_cali_data));
+
+			vx6953_lsc_patch();
+
+			vx6953_i2c_write_w_sensor(0x100A, 0x07A3);
+			vx6953_i2c_write_w_sensor(0x114A, 0x002A);
+			vx6953_i2c_write_w_sensor(0x1716, 0x0204);
+			vx6953_i2c_write_w_sensor(0x1718, 0x0880);
+
+			rc = vx6953_i2c_write_w_table(&init_tbl[0],
+				ARRAY_SIZE(init_tbl));
+			if (rc < 0)
+				return rc;
+
+			msleep(10);
+
+		}
+		return rc;
+		case UPDATE_PERIODIC:
+		if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+			struct vx6953_i2c_reg_conf preview_mode_tbl[] = {
+				{0x200, 0x02},
+				{0x201, 0x26},
+				{REG_COARSE_INTEGRATION_TIME_HI,
+					vx6953_regs.reg_pat[rt].
+					coarse_integration_time_hi},
+				{REG_COARSE_INTEGRATION_TIME_LO,
+					vx6953_regs.reg_pat[rt].
+					coarse_integration_time_lo},
+				{REG_ANALOGUE_GAIN_CODE_GLOBAL_LO,
+					vx6953_regs.reg_pat[rt].
+					analogue_gain_code_global},
+				{REG_FRAME_LENGTH_LINES_HI,
+					vx6953_regs.reg_pat[rt].
+					frame_length_lines_hi},
+				{REG_FRAME_LENGTH_LINES_LO,
+					vx6953_regs.reg_pat[rt].
+					frame_length_lines_lo},
+				{REG_LINE_LENGTH_PCK_HI,
+					vx6953_regs.reg_pat[rt].
+					line_length_pck_hi},
+				{REG_LINE_LENGTH_PCK_LO,
+					vx6953_regs.reg_pat[rt].
+					line_length_pck_lo},
+				{REG_0x0b80,
+					vx6953_regs.reg_pat[rt].
+					reg_0x0b80},
+				{REG_0x0900,
+					vx6953_regs.reg_pat[rt].
+					reg_0x0900},
+				{REG_0x0901,
+					vx6953_regs.reg_pat[rt].
+					reg_0x0901},
+				{REG_0x0902,
+					vx6953_regs.reg_pat[rt].
+					reg_0x0902},
+				{REG_0x0383,
+					vx6953_regs.reg_pat[rt].
+					reg_0x0383},
+				{REG_0x0387,
+					vx6953_regs.reg_pat[rt].
+					reg_0x0387},
+				{REG_0x034c,
+					vx6953_regs.reg_pat[rt].
+					reg_0x034c},
+				{REG_0x034d,
+					vx6953_regs.reg_pat[rt].
+					reg_0x034d},
+				{REG_0x034e,
+					vx6953_regs.reg_pat[rt].
+					reg_0x034e},
+				{REG_0x034f,
+					vx6953_regs.reg_pat[rt].
+					reg_0x034f},
+				{REG_0x3640, 0x00},
+			};
+
+			struct vx6953_i2c_reg_conf snapshot_mode_tbl[] = {
+				{0x0200, 0x02},
+				{0x0201, 0x54},
+				{REG_COARSE_INTEGRATION_TIME_HI,
+					vx6953_regs.reg_pat[rt].
+					coarse_integration_time_hi},
+				{REG_COARSE_INTEGRATION_TIME_LO,
+					vx6953_regs.reg_pat[rt].
+					coarse_integration_time_lo},
+				{REG_ANALOGUE_GAIN_CODE_GLOBAL_LO,
+					vx6953_regs.reg_pat[rt].
+					analogue_gain_code_global},
+				{REG_FRAME_LENGTH_LINES_HI,
+					vx6953_regs.reg_pat[rt].
+					frame_length_lines_hi},
+				{REG_FRAME_LENGTH_LINES_LO,
+					vx6953_regs.reg_pat[rt].
+					frame_length_lines_lo},
+				{REG_LINE_LENGTH_PCK_HI,
+					vx6953_regs.reg_pat[rt].
+					line_length_pck_hi},
+				{REG_LINE_LENGTH_PCK_LO,
+					vx6953_regs.reg_pat[rt].
+					line_length_pck_lo},
+				{REG_0x0b80,
+					vx6953_regs.reg_pat[rt].
+					reg_0x0b80},
+				{REG_0x0900,
+					vx6953_regs.reg_pat[rt].
+					reg_0x0900},
+				{REG_0x0901,
+					vx6953_regs.reg_pat[rt].
+					reg_0x0901},
+				{REG_0x0902,
+					vx6953_regs.reg_pat[rt].
+					reg_0x0902},
+				{REG_0x0383,
+					vx6953_regs.reg_pat[rt].
+					reg_0x0383},
+				{REG_0x0387,
+					vx6953_regs.reg_pat[rt].
+					reg_0x0387},
+				{REG_0x034c,
+					vx6953_regs.reg_pat[rt].
+					reg_0x034c},
+				{REG_0x034d,
+					vx6953_regs.reg_pat[rt].
+					reg_0x034d},
+				{REG_0x034e,
+					vx6953_regs.reg_pat[rt].
+					reg_0x034e},
+				{REG_0x034f,
+					vx6953_regs.reg_pat[rt].
+					reg_0x034f},
+				{0x3140, 0x01},
+				{REG_0x3640, 0x00},
+			};
+			/* stop streaming */
+
+			if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT,
+				MODE_SELECT_STANDBY_MODE) < 0)
+				return rc;
+			msleep(vx6953_stm5m0edof_delay_msecs_stdby);
+
+			if (count == 0) {
+				vx6953_csi_params.data_format = CSI_8BIT;
+				vx6953_csi_params.lane_cnt = 1;
+				vx6953_csi_params.lane_assign = 0xe4;
+				vx6953_csi_params.dpcm_scheme = 0;
+				vx6953_csi_params.settle_cnt = 7;
+				rc = msm_camio_csi_config(&vx6953_csi_params);
+				if (rc < 0)
+					CDBG("config csi controller failed\n");
+
+				msleep(20);
+				count = 1;
+			}
+
+			vx6953_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
+			GROUPED_PARAMETER_HOLD);
+
+			if (rt == RES_PREVIEW) {
+				rc = vx6953_i2c_write_w_table(
+					&preview_mode_tbl[0],
+					ARRAY_SIZE(preview_mode_tbl));
+				if (rc < 0)
+					return rc;
+			}
+			if (rt == RES_CAPTURE) {
+				rc = vx6953_i2c_write_w_table(
+					&snapshot_mode_tbl[0],
+					ARRAY_SIZE(snapshot_mode_tbl));
+				if (rc < 0)
+					return rc;
+			}
+
+			vx6953_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
+			GROUPED_PARAMETER_HOLD_OFF);
+
+			/* Start sensor streaming */
+			if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT,
+				MODE_SELECT_STREAM) < 0)
+				return rc;
+			msleep(10);
+
+			if (vx6953_i2c_read(0x0005, &frame_cnt, 1) < 0)
+				return rc;
+
+			while (frame_cnt == 0xFF) {
+				if (vx6953_i2c_read(0x0005, &frame_cnt, 1) < 0)
+					return rc;
+				CDBG("frame_cnt=%d\n", frame_cnt);
+				msleep(2);
+			}
+		}
+		return rc;
+		default:
+			return rc;
+		}
+	} else {
+		switch (update_type) {
+		case REG_INIT:
+		if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+			struct vx6953_i2c_reg_conf init_tbl[] = {
+			{REG_0x0112,
+				vx6953_regs.reg_pat_init[0].reg_0x0112},
+			{REG_0x0113,
+				vx6953_regs.reg_pat_init[0].reg_0x0113},
+			{REG_VT_PIX_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				vt_pix_clk_div},
+			{REG_PRE_PLL_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				pre_pll_clk_div},
+			{REG_PLL_MULTIPLIER,
+				vx6953_regs.reg_pat_init[0].
+				pll_multiplier},
+			{REG_OP_PIX_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				op_pix_clk_div},
+			{REG_COARSE_INTEGRATION_TIME_HI,
+				vx6953_regs.reg_pat[rt].
+				coarse_integration_time_hi},
+			{REG_COARSE_INTEGRATION_TIME_LO,
+				vx6953_regs.reg_pat[rt].
+				coarse_integration_time_lo},
+			{REG_ANALOGUE_GAIN_CODE_GLOBAL_LO,
+				vx6953_regs.reg_pat[rt].
+				analogue_gain_code_global},
+			{REG_0x3030,
+				vx6953_regs.reg_pat_init[0].reg_0x3030},
+			/* 953 specific registers */
+			{REG_0x0111,
+				vx6953_regs.reg_pat_init[0].reg_0x0111},
+			{REG_0x0b00,
+				vx6953_regs.reg_pat_init[0].reg_0x0b00},
+			{REG_0x3001,
+				vx6953_regs.reg_pat_init[0].reg_0x3001},
+			{REG_0x3004,
+				vx6953_regs.reg_pat_init[0].reg_0x3004},
+			{REG_0x3007,
+				vx6953_regs.reg_pat_init[0].reg_0x3007},
+			{REG_0x3016,
+				vx6953_regs.reg_pat_init[0].reg_0x3016},
+			{REG_0x301d,
+				vx6953_regs.reg_pat_init[0].reg_0x301d},
+			{REG_0x317e,
+				vx6953_regs.reg_pat_init[0].reg_0x317e},
+			{REG_0x317f,
+				vx6953_regs.reg_pat_init[0].reg_0x317f},
+			{REG_0x3400,
+				vx6953_regs.reg_pat_init[0].reg_0x3400},
+			/* DEFCOR settings */
+			/*Single Defect Correction Weight DISABLE*/
+			{0x0b06,
+				vx6953_regs.reg_pat_init[0].reg_0x0b06},
+			/*Single_defect_correct_weight = auto*/
+			{0x0b07,
+				vx6953_regs.reg_pat_init[0].reg_0x0b07},
+			/*Dynamic couplet correction ENABLED*/
+			{0x0b08,
+				vx6953_regs.reg_pat_init[0].reg_0x0b08},
+			/*Dynamic couplet correction weight*/
+			{0x0b09,
+				vx6953_regs.reg_pat_init[0].reg_0x0b09},
+			/* Clock Setup */
+			/* Tell sensor ext clk is 24MHz*/
+			{0x0136,
+				vx6953_regs.reg_pat_init[0].reg_0x0136},
+			{0x0137,
+				vx6953_regs.reg_pat_init[0].reg_0x0137},
+			/* The white balance gains must be written
+			to the sensor every frame. */
+			/* Edof */
+			{REG_0x0b83,
+				vx6953_regs.reg_pat_init[0].reg_0x0b83},
+			{REG_0x0b84,
+				vx6953_regs.reg_pat_init[0].reg_0x0b84},
+			{0x0b85,
+				vx6953_regs.reg_pat_init[0].reg_0x0b85},
+			{0x0b88,
+				vx6953_regs.reg_pat_init[0].reg_0x0b88},
+			{0x0b89,
+				vx6953_regs.reg_pat_init[0].reg_0x0b89},
+			{REG_0x0b8a,
+				vx6953_regs.reg_pat_init[0].reg_0x0b8a},
+			/* Mode specific regieters */
+			{REG_FRAME_LENGTH_LINES_HI,
+				vx6953_regs.reg_pat[rt].
+				frame_length_lines_hi},
+			{REG_FRAME_LENGTH_LINES_LO,
+				vx6953_regs.reg_pat[rt].
+				frame_length_lines_lo},
+			{REG_LINE_LENGTH_PCK_HI,
+				vx6953_regs.reg_pat[rt].
+				line_length_pck_hi},
+			{REG_LINE_LENGTH_PCK_LO,
+				vx6953_regs.reg_pat[rt].
+				line_length_pck_lo},
+			{REG_0x3005,
+				vx6953_regs.reg_pat[rt].reg_0x3005},
+			{0x3010,
+				vx6953_regs.reg_pat[rt].reg_0x3010},
+			{REG_0x3011,
+				vx6953_regs.reg_pat[rt].reg_0x3011},
+			{REG_0x301a,
+				vx6953_regs.reg_pat[rt].reg_0x301a},
+			{REG_0x3035,
+				vx6953_regs.reg_pat[rt].reg_0x3035},
+			{REG_0x3036,
+				vx6953_regs.reg_pat[rt].reg_0x3036},
+			{REG_0x3041,
+				vx6953_regs.reg_pat[rt].reg_0x3041},
+			{0x3042,
+				vx6953_regs.reg_pat[rt].reg_0x3042},
+			{REG_0x3045,
+				vx6953_regs.reg_pat[rt].reg_0x3045},
+			/*EDOF: Estimation settings for Preview mode
+			Application settings for capture mode
+			(standard settings - Not tuned) */
+			{REG_0x0b80,
+				vx6953_regs.reg_pat[rt].reg_0x0b80},
+			{REG_0x0900,
+				vx6953_regs.reg_pat[rt].reg_0x0900},
+			{REG_0x0901,
+				vx6953_regs.reg_pat[rt].reg_0x0901},
+			{REG_0x0902,
+				vx6953_regs.reg_pat[rt].reg_0x0902},
+			{REG_0x0383,
+				vx6953_regs.reg_pat[rt].reg_0x0383},
+			{REG_0x0387,
+				vx6953_regs.reg_pat[rt].reg_0x0387},
+			/* Change output size / frame rate */
+			{REG_0x034c,
+				vx6953_regs.reg_pat[rt].reg_0x034c},
+			{REG_0x034d,
+				vx6953_regs.reg_pat[rt].reg_0x034d},
+			{REG_0x034e,
+				vx6953_regs.reg_pat[rt].reg_0x034e},
+			{REG_0x034f,
+				vx6953_regs.reg_pat[rt].reg_0x034f},
+			{REG_0x1716,
+				vx6953_regs.reg_pat[rt].reg_0x1716},
+			{REG_0x1717,
+				vx6953_regs.reg_pat[rt].reg_0x1717},
+			{REG_0x1718,
+				vx6953_regs.reg_pat[rt].reg_0x1718},
+			{REG_0x1719,
+				vx6953_regs.reg_pat[rt].reg_0x1719},
+			};
+						/* reset fps_divider */
+			vx6953_ctrl->fps = 30 * Q8;
+			/* stop streaming */
+
+			/* Reset everything first */
+			if (vx6953_i2c_write_b_sensor(0x103, 0x01) < 0) {
+				CDBG("S/W reset failed\n");
+				return rc;
+			} else
+				CDBG("S/W reset successful\n");
+
+			msleep(10);
+
+			CDBG("Init vx6953_sensor_setting standby\n");
+			if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT,
+				MODE_SELECT_STANDBY_MODE) < 0)
+				return rc;
+				/*vx6953_stm5m0edof_delay_msecs_stdby*/
+			msleep(vx6953_stm5m0edof_delay_msecs_stdby);
+			vx6953_patch_for_cut2();
+			rc = vx6953_i2c_write_w_table(&init_tbl[0],
+				ARRAY_SIZE(init_tbl));
+			if (rc < 0)
+				return rc;
+				msleep(vx6953_stm5m0edof_delay_msecs_stdby);
+		}
+	return rc;
+	case UPDATE_PERIODIC:
+		if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+			struct vx6953_i2c_reg_conf init_mode_tbl[] =  {
+			{REG_0x0112,
+				vx6953_regs.reg_pat_init[0].reg_0x0112},
+			{REG_0x0113,
+				vx6953_regs.reg_pat_init[0].reg_0x0113},
+			{REG_VT_PIX_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				vt_pix_clk_div},
+			{REG_PRE_PLL_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				pre_pll_clk_div},
+			{REG_PLL_MULTIPLIER,
+				vx6953_regs.reg_pat_init[0].
+				pll_multiplier},
+			{REG_OP_PIX_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				op_pix_clk_div},
+			{REG_COARSE_INTEGRATION_TIME_HI,
+				vx6953_regs.reg_pat[rt].
+				coarse_integration_time_hi},
+			{REG_COARSE_INTEGRATION_TIME_LO,
+				vx6953_regs.reg_pat[rt].
+				coarse_integration_time_lo},
+			{REG_ANALOGUE_GAIN_CODE_GLOBAL_LO,
+				vx6953_regs.reg_pat[rt].
+				analogue_gain_code_global},
+			{REG_0x3030,
+				vx6953_regs.reg_pat_init[0].reg_0x3030},
+			/* 953 specific registers */
+			{REG_0x0111,
+				vx6953_regs.reg_pat_init[0].reg_0x0111},
+			{REG_0x0b00,
+				vx6953_regs.reg_pat_init[0].reg_0x0b00},
+			{REG_0x3001,
+				vx6953_regs.reg_pat_init[0].reg_0x3001},
+			{REG_0x3004,
+				vx6953_regs.reg_pat_init[0].reg_0x3004},
+			{REG_0x3007,
+				vx6953_regs.reg_pat_init[0].reg_0x3007},
+			{REG_0x3016,
+				vx6953_regs.reg_pat_init[0].reg_0x3016},
+			{REG_0x301d,
+				vx6953_regs.reg_pat_init[0].reg_0x301d},
+			{REG_0x317e,
+				vx6953_regs.reg_pat_init[0].reg_0x317e},
+			{REG_0x317f,
+				vx6953_regs.reg_pat_init[0].reg_0x317f},
+			{REG_0x3400,
+				vx6953_regs.reg_pat_init[0].reg_0x3400},
+			{0x0b06,
+				vx6953_regs.reg_pat_init[0].reg_0x0b06},
+			/*Single_defect_correct_weight = auto*/
+			{0x0b07,
+				vx6953_regs.reg_pat_init[0].reg_0x0b07},
+			/*Dynamic couplet correction ENABLED*/
+			{0x0b08,
+				vx6953_regs.reg_pat_init[0].reg_0x0b08},
+			/*Dynamic couplet correction weight*/
+			{0x0b09,
+				vx6953_regs.reg_pat_init[0].reg_0x0b09},
+			/* Clock Setup */
+			/* Tell sensor ext clk is 24MHz*/
+			{0x0136,
+				vx6953_regs.reg_pat_init[0].reg_0x0136},
+			{0x0137,
+				vx6953_regs.reg_pat_init[0].reg_0x0137},
+			/* The white balance gains must be written
+			to the sensor every frame. */
+			/* Edof */
+			{REG_0x0b83,
+				vx6953_regs.reg_pat_init[0].reg_0x0b83},
+			{REG_0x0b84,
+				vx6953_regs.reg_pat_init[0].reg_0x0b84},
+			{0x0b85,
+				vx6953_regs.reg_pat_init[0].reg_0x0b85},
+			{0x0b88,
+				vx6953_regs.reg_pat_init[0].reg_0x0b88},
+			{0x0b89,
+				vx6953_regs.reg_pat_init[0].reg_0x0b89},
+			{REG_0x0b8a,
+				vx6953_regs.reg_pat_init[0].reg_0x0b8a},
+			/* Mode specific regieters */
+			{REG_FRAME_LENGTH_LINES_HI,
+				vx6953_regs.reg_pat[rt].
+				frame_length_lines_hi},
+			{REG_FRAME_LENGTH_LINES_LO,
+				vx6953_regs.reg_pat[rt].
+				frame_length_lines_lo},
+			{REG_LINE_LENGTH_PCK_HI,
+				vx6953_regs.reg_pat[rt].
+				line_length_pck_hi},
+			{REG_LINE_LENGTH_PCK_LO,
+				vx6953_regs.reg_pat[rt].
+				line_length_pck_lo},
+			{REG_0x3005,
+				vx6953_regs.reg_pat[rt].reg_0x3005},
+			{0x3010,
+				vx6953_regs.reg_pat[rt].reg_0x3010},
+			{REG_0x3011,
+				vx6953_regs.reg_pat[rt].reg_0x3011},
+			{REG_0x301a,
+				vx6953_regs.reg_pat[rt].reg_0x301a},
+			{REG_0x3035,
+				vx6953_regs.reg_pat[rt].reg_0x3035},
+			{REG_0x3036,
+				vx6953_regs.reg_pat[rt].reg_0x3036},
+			{REG_0x3041,
+				vx6953_regs.reg_pat[rt].reg_0x3041},
+			{0x3042,
+				vx6953_regs.reg_pat[rt].reg_0x3042},
+			{REG_0x3045,
+				vx6953_regs.reg_pat[rt].reg_0x3045},
+			/*EDOF: Estimation settings for Preview mode
+			Application settings for capture mode
+			(standard settings - Not tuned) */
+			{REG_0x0b80,
+				vx6953_regs.reg_pat[rt].reg_0x0b80},
+			{REG_0x0900,
+				vx6953_regs.reg_pat[rt].reg_0x0900},
+			{REG_0x0901,
+				vx6953_regs.reg_pat[rt].reg_0x0901},
+			{REG_0x0902,
+				vx6953_regs.reg_pat[rt].reg_0x0902},
+			{REG_0x0383,
+				vx6953_regs.reg_pat[rt].reg_0x0383},
+			{REG_0x0387,
+				vx6953_regs.reg_pat[rt].reg_0x0387},
+			/* Change output size / frame rate */
+			{REG_0x034c,
+				vx6953_regs.reg_pat[rt].reg_0x034c},
+			{REG_0x034d,
+				vx6953_regs.reg_pat[rt].reg_0x034d},
+			{REG_0x034e,
+				vx6953_regs.reg_pat[rt].reg_0x034e},
+			{REG_0x034f,
+				vx6953_regs.reg_pat[rt].reg_0x034f},
+			{REG_0x1716,
+				vx6953_regs.reg_pat[rt].reg_0x1716},
+			{REG_0x1717,
+				vx6953_regs.reg_pat[rt].reg_0x1717},
+			{REG_0x1718,
+				vx6953_regs.reg_pat[rt].reg_0x1718},
+			{REG_0x1719,
+				vx6953_regs.reg_pat[rt].reg_0x1719},
+			};
+			struct vx6953_i2c_reg_conf mode_tbl[] = {
+			{REG_0x0112,
+				vx6953_regs.reg_pat_init[0].reg_0x0112},
+			{REG_0x0113,
+				vx6953_regs.reg_pat_init[0].reg_0x0113},
+			{REG_VT_PIX_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				vt_pix_clk_div},
+			{REG_PRE_PLL_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				pre_pll_clk_div},
+			{REG_PLL_MULTIPLIER,
+				vx6953_regs.reg_pat_init[0].
+				pll_multiplier},
+			{REG_OP_PIX_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				op_pix_clk_div},
+		/* Mode specific regieters */
+			{REG_FRAME_LENGTH_LINES_HI,
+				vx6953_regs.reg_pat[rt].frame_length_lines_hi},
+			{REG_FRAME_LENGTH_LINES_LO,
+				vx6953_regs.reg_pat[rt].frame_length_lines_lo},
+			{REG_LINE_LENGTH_PCK_HI,
+				vx6953_regs.reg_pat[rt].line_length_pck_hi},
+			{REG_LINE_LENGTH_PCK_LO,
+				vx6953_regs.reg_pat[rt].line_length_pck_lo},
+			{REG_0x3005, vx6953_regs.reg_pat[rt].reg_0x3005},
+			{0x3010, vx6953_regs.reg_pat[rt].reg_0x3010},
+			{REG_0x3011, vx6953_regs.reg_pat[rt].reg_0x3011},
+			{REG_0x301a, vx6953_regs.reg_pat[rt].reg_0x301a},
+			{REG_0x3035, vx6953_regs.reg_pat[rt].reg_0x3035},
+			{REG_0x3036, vx6953_regs.reg_pat[rt].reg_0x3036},
+			{REG_0x3041, vx6953_regs.reg_pat[rt].reg_0x3041},
+			{0x3042, vx6953_regs.reg_pat[rt].reg_0x3042},
+			{REG_0x3045, vx6953_regs.reg_pat[rt].reg_0x3045},
+			/*EDOF: Estimation settings for Preview mode
+			Application settings for capture
+			mode(standard settings - Not tuned) */
+			{REG_0x0b80, vx6953_regs.reg_pat[rt].reg_0x0b80},
+			{REG_0x0900, vx6953_regs.reg_pat[rt].reg_0x0900},
+			{REG_0x0901, vx6953_regs.reg_pat[rt].reg_0x0901},
+			{REG_0x0902, vx6953_regs.reg_pat[rt].reg_0x0902},
+			{REG_0x0383, vx6953_regs.reg_pat[rt].reg_0x0383},
+			{REG_0x0387, vx6953_regs.reg_pat[rt].reg_0x0387},
+			/* Change output size / frame rate */
+			{REG_0x034c, vx6953_regs.reg_pat[rt].reg_0x034c},
+			{REG_0x034d, vx6953_regs.reg_pat[rt].reg_0x034d},
+			{REG_0x034e, vx6953_regs.reg_pat[rt].reg_0x034e},
+			{REG_0x034f, vx6953_regs.reg_pat[rt].reg_0x034f},
+			/*{0x200, vx6953_regs.reg_pat[rt].reg_0x0200},
+			{0x201, vx6953_regs.reg_pat[rt].reg_0x0201},*/
+			{REG_0x1716, vx6953_regs.reg_pat[rt].reg_0x1716},
+			{REG_0x1717, vx6953_regs.reg_pat[rt].reg_0x1717},
+			{REG_0x1718, vx6953_regs.reg_pat[rt].reg_0x1718},
+			{REG_0x1719, vx6953_regs.reg_pat[rt].reg_0x1719},
+			};
+			/* stop streaming */
+			msleep(5);
+
+			/* Reset everything first */
+			if (vx6953_i2c_write_b_sensor(0x103, 0x01) < 0) {
+				CDBG("S/W reset failed\n");
+				return rc;
+			} else
+				CDBG("S/W reset successful\n");
+
+			msleep(10);
+
+			if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT,
+				MODE_SELECT_STANDBY_MODE) < 0)
+				return rc;
+			/*vx6953_stm5m0edof_delay_msecs_stdby*/
+			msleep(vx6953_stm5m0edof_delay_msecs_stdby);
+
+
+			vx6953_csi_params.data_format = CSI_8BIT;
+			vx6953_csi_params.lane_cnt = 1;
+			vx6953_csi_params.lane_assign = 0xe4;
+			vx6953_csi_params.dpcm_scheme = 0;
+			vx6953_csi_params.settle_cnt = 7;
+			rc = msm_camio_csi_config(&vx6953_csi_params);
+			if (rc < 0)
+				CDBG(" config csi controller failed \n");
+
+			msleep(vx6953_stm5m0edof_delay_msecs_stdby);
+
+			vx6953_patch_for_cut2();
+			rc = vx6953_i2c_write_w_table(&init_mode_tbl[0],
+				ARRAY_SIZE(init_mode_tbl));
+			if (rc < 0)
+				return rc;
+
+			msleep(vx6953_stm5m0edof_delay_msecs_stdby);
+
+			rc = vx6953_i2c_write_w_table(&mode_tbl[0],
+				ARRAY_SIZE(mode_tbl));
+			if (rc < 0)
+				return rc;
+
+			msleep(vx6953_stm5m0edof_delay_msecs_stdby);
+
+			/* Start sensor streaming */
+			if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT,
+				MODE_SELECT_STREAM) < 0)
+				return rc;
+			msleep(vx6953_stm5m0edof_delay_msecs_stream);
+
+			if (vx6953_i2c_read(0x0005, &frame_cnt, 1) < 0)
+				return rc;
+
+			while (frame_cnt == 0xFF) {
+				if (vx6953_i2c_read(0x0005, &frame_cnt, 1) < 0)
+					return rc;
+				CDBG("frame_cnt=%d", frame_cnt);
+				msleep(10);
+			}
+		}
+		return rc;
+	default:
+		return rc;
+	}
+	}
+	return rc;
+}
+
+
+static int32_t vx6953_video_config(int mode)
+{
+
+	int32_t	rc = 0;
+	int	rt;
+	/* change sensor resolution	if needed */
+	if (vx6953_ctrl->curr_res != vx6953_ctrl->prev_res) {
+		if (vx6953_ctrl->prev_res == QTR_SIZE) {
+			rt = RES_PREVIEW;
+			vx6953_stm5m0edof_delay_msecs_stdby	=
+				((((2 * 1000 * vx6953_ctrl->fps_divider) /
+				   vx6953_ctrl->fps) * Q8) / Q10) + 1;
+		} else {
+			rt = RES_CAPTURE;
+			vx6953_stm5m0edof_delay_msecs_stdby	=
+				((((1000 * vx6953_ctrl->fps_divider) /
+				   vx6953_ctrl->fps) * Q8) / Q10) + 1;
+		}
+		if (vx6953_sensor_setting(UPDATE_PERIODIC, rt) < 0)
+			return rc;
+	}
+	if (vx6953_ctrl->set_test) {
+		if (vx6953_test(vx6953_ctrl->set_test) < 0)
+			return	rc;
+	}
+	vx6953_ctrl->edof_mode = VX6953_EDOF_ESTIMATION;
+	rc = vx6953_enable_edof(vx6953_ctrl->edof_mode);
+	if (rc < 0)
+		return rc;
+	vx6953_ctrl->curr_res = vx6953_ctrl->prev_res;
+	vx6953_ctrl->sensormode = mode;
+	return rc;
+}
+
+static int32_t vx6953_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+	int rt;
+	/*change sensor resolution if needed */
+	if (vx6953_ctrl->curr_res != vx6953_ctrl->pict_res) {
+		if (vx6953_ctrl->pict_res == QTR_SIZE) {
+			rt = RES_PREVIEW;
+			vx6953_stm5m0edof_delay_msecs_stdby =
+				((((2 * 1000 * vx6953_ctrl->fps_divider) /
+				vx6953_ctrl->fps) * Q8) / Q10) + 1;
+		} else {
+			rt = RES_CAPTURE;
+			vx6953_stm5m0edof_delay_msecs_stdby =
+				((((1000 * vx6953_ctrl->fps_divider) /
+				vx6953_ctrl->fps) * Q8) / Q10) + 1;
+		}
+	if (vx6953_sensor_setting(UPDATE_PERIODIC, rt) < 0)
+		return rc;
+	}
+
+	vx6953_ctrl->edof_mode = VX6953_EDOF_APPLICATION;
+	if (vx6953_enable_edof(vx6953_ctrl->edof_mode) < 0)
+		return rc;
+	vx6953_ctrl->curr_res = vx6953_ctrl->pict_res;
+	vx6953_ctrl->sensormode = mode;
+	return rc;
+} /*end of vx6953_snapshot_config*/
+
+static int32_t vx6953_raw_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+	int rt;
+	/* change sensor resolution if needed */
+	if (vx6953_ctrl->curr_res != vx6953_ctrl->pict_res) {
+		if (vx6953_ctrl->pict_res == QTR_SIZE) {
+			rt = RES_PREVIEW;
+			vx6953_stm5m0edof_delay_msecs_stdby =
+				((((2 * 1000 * vx6953_ctrl->fps_divider)/
+				vx6953_ctrl->fps) * Q8) / Q10) + 1;
+		} else {
+			rt = RES_CAPTURE;
+			vx6953_stm5m0edof_delay_msecs_stdby =
+				((((1000 * vx6953_ctrl->fps_divider)/
+				vx6953_ctrl->fps) * Q8) / Q10) + 1;
+		}
+		if (vx6953_sensor_setting(UPDATE_PERIODIC, rt) < 0)
+			return rc;
+	}
+	vx6953_ctrl->edof_mode = VX6953_EDOF_APPLICATION;
+	if (vx6953_enable_edof(vx6953_ctrl->edof_mode) < 0)
+		return rc;
+	vx6953_ctrl->curr_res = vx6953_ctrl->pict_res;
+	vx6953_ctrl->sensormode = mode;
+	return rc;
+} /*end of vx6953_raw_snapshot_config*/
+static int32_t vx6953_set_sensor_mode(int mode,
+	int res)
+{
+	int32_t rc = 0;
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		rc = vx6953_video_config(mode);
+		break;
+	case SENSOR_SNAPSHOT_MODE:
+		rc = vx6953_snapshot_config(mode);
+		break;
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		rc = vx6953_raw_snapshot_config(mode);
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+static int32_t vx6953_power_down(void)
+{
+	return 0;
+}
+
+
+static int vx6953_probe_init_done(const struct msm_camera_sensor_info *data)
+{
+	gpio_set_value_cansleep(data->sensor_reset, 0);
+	gpio_free(data->sensor_reset);
+	return 0;
+}
+static int vx6953_probe_init_sensor(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc = 0;
+	unsigned short chipidl, chipidh;
+	CDBG("%s: %d\n", __func__, __LINE__);
+	rc = gpio_request(data->sensor_reset, "vx6953");
+	CDBG(" vx6953_probe_init_sensor \n");
+	if (!rc) {
+		CDBG("sensor_reset = %d\n", rc);
+		CDBG(" vx6953_probe_init_sensor 1\n");
+		gpio_direction_output(data->sensor_reset, 0);
+		msleep(10);
+		CDBG(" vx6953_probe_init_sensor 1\n");
+		gpio_set_value_cansleep(data->sensor_reset, 1);
+	} else {
+		CDBG(" vx6953_probe_init_sensor 2\n");
+		goto init_probe_done;
+	}
+	msleep(20);
+	CDBG(" vx6953_probe_init_sensor is called\n");
+	/* 3. Read sensor Model ID: */
+	rc = vx6953_i2c_read(0x0000, &chipidh, 1);
+	if (rc < 0) {
+		CDBG(" vx6953_probe_init_sensor 3\n");
+		goto init_probe_fail;
+	}
+	rc = vx6953_i2c_read(0x0001, &chipidl, 1);
+	if (rc < 0) {
+		CDBG(" vx6953_probe_init_sensor4\n");
+		goto init_probe_fail;
+	}
+	CDBG("vx6953 model_id = 0x%x  0x%x\n", chipidh, chipidl);
+	/* 4. Compare sensor ID to VX6953 ID: */
+	if (chipidh != 0x03 || chipidl != 0xB9) {
+		rc = -ENODEV;
+		CDBG("vx6953_probe_init_sensor fail chip id doesnot match\n");
+		goto init_probe_fail;
+	}
+	goto init_probe_done;
+init_probe_fail:
+	CDBG(" vx6953_probe_init_sensor fails\n");
+	vx6953_probe_init_done(data);
+init_probe_done:
+	CDBG(" vx6953_probe_init_sensor finishes\n");
+	return rc;
+	}
+/* camsensor_iu060f_vx6953_reset */
+int vx6953_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+	unsigned short revision_number;
+	int32_t rc = 0;
+
+	CDBG("%s: %d\n", __func__, __LINE__);
+	CDBG("Calling vx6953_sensor_open_init\n");
+	vx6953_ctrl = kzalloc(sizeof(struct vx6953_ctrl_t), GFP_KERNEL);
+	if (!vx6953_ctrl) {
+		CDBG("vx6953_init failed!\n");
+		rc = -ENOMEM;
+		goto init_done;
+	}
+	vx6953_ctrl->fps_divider = 1 * 0x00000400;
+	vx6953_ctrl->pict_fps_divider = 1 * 0x00000400;
+	vx6953_ctrl->set_test = TEST_OFF;
+	vx6953_ctrl->prev_res = QTR_SIZE;
+	vx6953_ctrl->pict_res = FULL_SIZE;
+	vx6953_ctrl->curr_res = INVALID_SIZE;
+	vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_2;
+	vx6953_ctrl->edof_mode = VX6953_EDOF_ESTIMATION;
+	if (data)
+		vx6953_ctrl->sensordata = data;
+	if (rc < 0) {
+		CDBG("Calling vx6953_sensor_open_init fail1\n");
+		return rc;
+	}
+	CDBG("%s: %d\n", __func__, __LINE__);
+	/* enable mclk first */
+	msm_camio_clk_rate_set(VX6953_STM5M0EDOF_DEFAULT_MASTER_CLK_RATE);
+	CDBG("%s: %d\n", __func__, __LINE__);
+	rc = vx6953_probe_init_sensor(data);
+	if (rc < 0) {
+		CDBG("Calling vx6953_sensor_open_init fail3\n");
+		goto init_fail;
+	}
+	if (vx6953_i2c_read(0x0002, &revision_number, 1) < 0)
+		return rc;
+		CDBG("sensor revision number major = 0x%x\n", revision_number);
+	if (vx6953_i2c_read(0x0018, &revision_number, 1) < 0)
+		return rc;
+		CDBG("sensor revision number = 0x%x\n", revision_number);
+	if (revision_number == VX6953_REVISION_NUMBER_CUT3) {
+		vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_3;
+		CDBG("VX6953 EDof Cut 3.0 sensor\n ");
+	} else if (revision_number == VX6953_REVISION_NUMBER_CUT2) {
+		vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_2;
+		CDBG("VX6953 EDof Cut 2.0 sensor\n ");
+	} else {/* Cut1.0 reads 0x00 for register 0x0018*/
+		vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_1;
+		CDBG("VX6953 EDof Cut 1.0 sensor\n ");
+	}
+	if (vx6953_ctrl->prev_res == QTR_SIZE) {
+		if (vx6953_sensor_setting(REG_INIT, RES_PREVIEW) < 0)
+			return rc;
+	} else {
+		if (vx6953_sensor_setting(REG_INIT, RES_CAPTURE) < 0)
+			return rc;
+	}
+	vx6953_ctrl->fps = 30*Q8;
+	if (rc < 0)
+		goto init_fail;
+	else
+		goto init_done;
+init_fail:
+	CDBG("init_fail\n");
+	vx6953_probe_init_done(data);
+	kfree(vx6953_ctrl);
+init_done:
+	CDBG("init_done\n");
+	return rc;
+} /*endof vx6953_sensor_open_init*/
+
+static int vx6953_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&vx6953_wait_queue);
+	return 0;
+}
+
+static const struct i2c_device_id vx6953_i2c_id[] = {
+	{"vx6953", 0},
+	{ }
+};
+
+static int vx6953_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int rc = 0;
+	CDBG("vx6953_probe called!\n");
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		CDBG("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	vx6953_sensorw = kzalloc(sizeof(struct vx6953_work_t), GFP_KERNEL);
+	if (!vx6953_sensorw) {
+		CDBG("kzalloc failed.\n");
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, vx6953_sensorw);
+	vx6953_init_client(client);
+	vx6953_client = client;
+
+	msleep(50);
+
+	CDBG("vx6953_probe successed! rc = %d\n", rc);
+	return 0;
+
+probe_failure:
+	CDBG("vx6953_probe failed! rc = %d\n", rc);
+	return rc;
+}
+
+static int vx6953_send_wb_info(struct wb_info_cfg *wb)
+{
+	unsigned short read_data;
+	uint8_t temp[8];
+	int rc = 0;
+	int i = 0;
+
+	/* red_gain */
+	temp[2] = wb->red_gain >> 8;
+	temp[3] = wb->red_gain & 0xFF;
+
+	/* green_gain */
+	temp[0] = wb->green_gain >> 8;
+	temp[1] = wb->green_gain & 0xFF;
+	temp[6] = temp[0];
+	temp[7] = temp[1];
+
+	/* blue_gain */
+	temp[4] = wb->blue_gain >> 8;
+	temp[5] = wb->blue_gain & 0xFF;
+	rc = vx6953_i2c_write_seq_sensor(0x0B8E, &temp[0], 8);
+
+	for (i = 0; i < 6; i++) {
+		rc = vx6953_i2c_read(0x0B8E + i, &read_data, 1);
+		CDBG("%s addr 0x%x val %d \n", __func__, 0x0B8E + i, read_data);
+	}
+	rc = vx6953_i2c_read(0x0B82, &read_data, 1);
+	CDBG("%s addr 0x%x val %d \n", __func__, 0x0B82, read_data);
+	if (rc < 0)
+		return rc;
+	return rc;
+} /*end of vx6953_snapshot_config*/
+
+static int __exit vx6953_remove(struct i2c_client *client)
+{
+	struct vx6953_work_t_t *sensorw = i2c_get_clientdata(client);
+	free_irq(client->irq, sensorw);
+	vx6953_client = NULL;
+	kfree(sensorw);
+	return 0;
+}
+
+static struct i2c_driver vx6953_i2c_driver = {
+	.id_table = vx6953_i2c_id,
+	.probe  = vx6953_i2c_probe,
+	.remove = __exit_p(vx6953_i2c_remove),
+	.driver = {
+		.name = "vx6953",
+	},
+};
+
+int vx6953_sensor_config(void __user *argp)
+{
+	struct sensor_cfg_data cdata;
+	long   rc = 0;
+	if (copy_from_user(&cdata,
+		(void *)argp,
+		sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+	mutex_lock(&vx6953_mut);
+	CDBG("vx6953_sensor_config: cfgtype = %d\n",
+	cdata.cfgtype);
+		switch (cdata.cfgtype) {
+		case CFG_GET_PICT_FPS:
+			vx6953_get_pict_fps(
+				cdata.cfg.gfps.prevfps,
+				&(cdata.cfg.gfps.pictfps));
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PREV_L_PF:
+			cdata.cfg.prevl_pf =
+			vx6953_get_prev_lines_pf();
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PREV_P_PL:
+			cdata.cfg.prevp_pl =
+				vx6953_get_prev_pixels_pl();
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PICT_L_PF:
+			cdata.cfg.pictl_pf =
+				vx6953_get_pict_lines_pf();
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PICT_P_PL:
+			cdata.cfg.pictp_pl =
+				vx6953_get_pict_pixels_pl();
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PICT_MAX_EXP_LC:
+			cdata.cfg.pict_max_exp_lc =
+				vx6953_get_pict_max_exp_lc();
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_SET_FPS:
+		case CFG_SET_PICT_FPS:
+			rc = vx6953_set_fps(&(cdata.cfg.fps));
+			break;
+
+		case CFG_SET_EXP_GAIN:
+			rc =
+				vx6953_write_exp_gain(
+					cdata.cfg.exp_gain.gain,
+					cdata.cfg.exp_gain.line);
+			break;
+
+		case CFG_SET_PICT_EXP_GAIN:
+			rc =
+				vx6953_set_pict_exp_gain(
+				cdata.cfg.exp_gain.gain,
+				cdata.cfg.exp_gain.line);
+			break;
+
+		case CFG_SET_MODE:
+			rc = vx6953_set_sensor_mode(cdata.mode,
+					cdata.rs);
+			break;
+
+		case CFG_PWR_DOWN:
+			rc = vx6953_power_down();
+			break;
+
+		case CFG_MOVE_FOCUS:
+			rc =
+				vx6953_move_focus(
+				cdata.cfg.focus.dir,
+				cdata.cfg.focus.steps);
+			break;
+
+		case CFG_SET_DEFAULT_FOCUS:
+			rc =
+				vx6953_set_default_focus(
+				cdata.cfg.focus.steps);
+			break;
+
+		case CFG_SET_EFFECT:
+			rc = vx6953_set_default_focus(
+				cdata.cfg.effect);
+			break;
+
+
+		case CFG_SEND_WB_INFO:
+			rc = vx6953_send_wb_info(
+				&(cdata.cfg.wb_info));
+			break;
+
+		default:
+			rc = -EFAULT;
+			break;
+		}
+
+	mutex_unlock(&vx6953_mut);
+
+	return rc;
+}
+
+
+
+
+static int vx6953_sensor_release(void)
+{
+	int rc = -EBADF;
+	mutex_lock(&vx6953_mut);
+	vx6953_power_down();
+	gpio_direction_output(vx6953_ctrl->sensordata->sensor_reset, 0);
+	gpio_free(vx6953_ctrl->sensordata->sensor_reset);
+	kfree(vx6953_ctrl);
+	vx6953_ctrl = NULL;
+	CDBG("vx6953_release completed\n");
+	mutex_unlock(&vx6953_mut);
+
+	return rc;
+}
+
+static int vx6953_sensor_probe(const struct msm_camera_sensor_info *info,
+		struct msm_sensor_ctrl *s)
+{
+	int rc = 0;
+	rc = i2c_add_driver(&vx6953_i2c_driver);
+	if (rc < 0 || vx6953_client == NULL) {
+		rc = -ENOTSUPP;
+		goto probe_fail;
+	}
+	msm_camio_clk_rate_set(24000000);
+	rc = vx6953_probe_init_sensor(info);
+	if (rc < 0)
+		goto probe_fail;
+	s->s_init = vx6953_sensor_open_init;
+	s->s_release = vx6953_sensor_release;
+	s->s_config  = vx6953_sensor_config;
+	s->s_mount_angle  = 0;
+	vx6953_probe_init_done(info);
+	return rc;
+
+probe_fail:
+	CDBG("vx6953_sensor_probe: SENSOR PROBE FAILS!\n");
+	return rc;
+}
+
+static int __vx6953_probe(struct platform_device *pdev)
+{
+	return msm_camera_drv_start(pdev, vx6953_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = __vx6953_probe,
+	.driver = {
+		.name = "msm_camera_vx6953",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init vx6953_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(vx6953_init);
+void vx6953_exit(void)
+{
+	i2c_del_driver(&vx6953_i2c_driver);
+}
+
+
diff --git a/drivers/media/video/msm/vx6953.h b/drivers/media/video/msm/vx6953.h
new file mode 100644
index 0000000..0e12063
--- /dev/null
+++ b/drivers/media/video/msm/vx6953.h
@@ -0,0 +1,136 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#ifndef VX6953_H
+#define VX6953_H
+#include <linux/types.h>
+#include <mach/board.h>
+extern struct vx6953_reg vx6953_regs;
+struct reg_struct_init {
+	uint8_t reg_0x0112;      /* 0x0112*/
+	uint8_t reg_0x0113;      /* 0x0113*/
+	uint8_t vt_pix_clk_div;  /* 0x0301*/
+	uint8_t pre_pll_clk_div; /* 0x0305*/
+	uint8_t pll_multiplier;  /* 0x0307*/
+	uint8_t op_pix_clk_div;  /* 0x0309*/
+	uint8_t reg_0x3030;      /*0x3030*/
+	uint8_t reg_0x0111;      /*0x0111*/
+	uint8_t reg_0x0b00;      /*0x0b00*/
+	uint8_t reg_0x3001;      /*0x3001*/
+	uint8_t reg_0x3004;      /*0x3004*/
+	uint8_t reg_0x3007;      /*0x3007*/
+	uint8_t reg_0x3016;      /*0x3016*/
+	uint8_t reg_0x301d;      /*0x301d*/
+	uint8_t reg_0x317e;      /*0x317E*/
+	uint8_t reg_0x317f;      /*0x317F*/
+	uint8_t reg_0x3400;      /*0x3400*/
+	uint8_t reg_0x0b06;      /*0x0b06*/
+	uint8_t reg_0x0b07;      /*0x0b07*/
+	uint8_t reg_0x0b08;      /*0x0b08*/
+	uint8_t reg_0x0b09;      /*0x0b09*/
+	uint8_t reg_0x0136;
+	uint8_t reg_0x0137;
+	/* Edof */
+	uint8_t reg_0x0b83;      /*0x0b83*/
+	uint8_t reg_0x0b84;      /*0x0b84*/
+	uint8_t reg_0x0b85;      /*0x0b85*/
+	uint8_t reg_0x0b88;      /*0x0b88*/
+	uint8_t reg_0x0b89;      /*0x0b89*/
+	uint8_t reg_0x0b8a;      /*0x0b8a*/
+	};
+struct reg_struct {
+	uint8_t coarse_integration_time_hi; /*REG_COARSE_INTEGRATION_TIME_HI*/
+	uint8_t coarse_integration_time_lo; /*REG_COARSE_INTEGRATION_TIME_LO*/
+	uint8_t analogue_gain_code_global;
+	uint8_t frame_length_lines_hi; /* 0x0340*/
+	uint8_t frame_length_lines_lo; /* 0x0341*/
+	uint8_t line_length_pck_hi;    /* 0x0342*/
+	uint8_t line_length_pck_lo;    /* 0x0343*/
+	uint8_t reg_0x3005;   /* 0x3005*/
+	uint8_t reg_0x3010;  /* 0x3010*/
+	uint8_t reg_0x3011;  /* 0x3011*/
+	uint8_t reg_0x301a;  /* 0x301a*/
+	uint8_t reg_0x3035;  /* 0x3035*/
+	uint8_t reg_0x3036;   /* 0x3036*/
+	uint8_t reg_0x3041;  /*0x3041*/
+	uint8_t reg_0x3042;  /*0x3042*/
+	uint8_t reg_0x3045;  /*0x3045*/
+	uint8_t reg_0x0b80;   /* 0x0b80*/
+	uint8_t reg_0x0900;   /*0x0900*/
+	uint8_t reg_0x0901;   /* 0x0901*/
+	uint8_t reg_0x0902;   /*0x0902*/
+	uint8_t reg_0x0383;   /*0x0383*/
+	uint8_t reg_0x0387;   /* 0x0387*/
+	uint8_t reg_0x034c;   /* 0x034c*/
+	uint8_t reg_0x034d;   /*0x034d*/
+	uint8_t reg_0x034e;   /* 0x034e*/
+	uint8_t reg_0x034f;   /* 0x034f*/
+	uint8_t reg_0x1716; /*0x1716*/
+	uint8_t reg_0x1717; /*0x1717*/
+	uint8_t reg_0x1718; /*0x1718*/
+	uint8_t reg_0x1719; /*0x1719*/
+	uint8_t reg_0x3210;/*0x3210*/
+	uint8_t reg_0x111; /*0x111*/
+	uint8_t reg_0x3410;  /*0x3410*/
+	uint8_t reg_0x3098;
+	uint8_t reg_0x309D;
+	uint8_t reg_0x0200;
+	uint8_t reg_0x0201;
+	};
+struct vx6953_i2c_reg_conf {
+	unsigned short waddr;
+	unsigned short wdata;
+};
+
+enum vx6953_test_mode_t {
+	TEST_OFF,
+	TEST_1,
+	TEST_2,
+	TEST_3
+};
+
+enum vx6953_resolution_t {
+	QTR_SIZE,
+	FULL_SIZE,
+	INVALID_SIZE
+};
+enum vx6953_setting {
+	RES_PREVIEW,
+	RES_CAPTURE
+};
+enum mt9p012_reg_update {
+	/* Sensor egisters that need to be updated during initialization */
+	REG_INIT,
+	/* Sensor egisters that needs periodic I2C writes */
+	UPDATE_PERIODIC,
+	/* All the sensor Registers will be updated */
+	UPDATE_ALL,
+	/* Not valid update */
+	UPDATE_INVALID
+};
+
+enum sensor_revision_t {
+	VX6953_STM5M0EDOF_CUT_1,
+	VX6953_STM5M0EDOF_CUT_2,
+	VX6953_STM5M0EDOF_CUT_3
+};
+enum edof_mode_t {
+	VX6953_EDOF_DISABLE,       /* 0x00 */
+	VX6953_EDOF_APPLICATION,   /* 0x01 */
+	VX6953_EDOF_ESTIMATION     /* 0x02 */
+};
+struct vx6953_reg {
+	const struct reg_struct_init  *reg_pat_init;
+	const struct reg_struct  *reg_pat;
+};
+#endif /* VX6953_H */
diff --git a/drivers/media/video/msm/vx6953_reg.c b/drivers/media/video/msm/vx6953_reg.c
new file mode 100644
index 0000000..48fc71f
--- /dev/null
+++ b/drivers/media/video/msm/vx6953_reg.c
@@ -0,0 +1,135 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+
+#include "vx6953.h"
+const struct reg_struct_init vx6953_reg_init[1] = {
+	{
+		10,			/*REG = 0x0112 , 10 bit */
+		10,			/*REG = 0x0113*/
+		9,			/*REG = 0x0301 vt_pix_clk_div*/
+		4,		/*REG = 0x0305 pre_pll_clk_div*/
+		133,		/*REG = 0x0307 pll_multiplier*/
+		10,		/*REG = 0x0309 op_pix_clk_div*/
+		0x08,		/*REG = 0x3030*/
+		0x02,		/*REG = 0x0111*/
+		0x01,		/*REG = 0x0b00 ,lens shading off */
+		0x30,		/*REG = 0x3001*/
+		0x33,		/*REG = 0x3004*/
+		0x09,		/*REG = 0x3007*/
+		0x1F,		/*REG = 0x3016*/
+		0x03,		/*REG = 0x301d*/
+		0x11,		/*REG = 0x317E*/
+		0x09,		/*REG = 0x317F*/
+		0x38,		/*REG = 0x3400*/
+		0x00,		/*REG_0x0b06*/
+		0x80,		/*REG_0x0b07*/
+		0x01,		/*REG_0x0b08*/
+		0x4F,		/*REG_0x0b09*/
+		0x18,		/*REG_0x0136*/
+		0x00,		/*/REG_0x0137*/
+		0x20,		/*REG = 0x0b83*/
+		0x90,		/*REG = 0x0b84*/
+		0x20,		/*REG = 0x0b85*/
+		0x80,		/*REG = 0x0b88*/
+		0x00,		/*REG = 0x0b89*/
+		0x00,		/*REG = 0x0b8a*/
+	}
+};
+const struct reg_struct vx6953_reg_pat[2] = {
+	{/* Preview */
+		0x03,	/*REG = 0x0202 coarse integration_time_hi*/
+		0xd0,	/*REG = 0x0203 coarse_integration_time_lo*/
+		0xc0,	/*REG = 0x0205 analogue_gain_code_global*/
+		0x03,	/*REG = 0x0340 frame_length_lines_hi*/
+		0xf0,	/*REG = 0x0341 frame_length_lines_lo*/
+		0x0b,	/*REG = 0x0342  line_length_pck_hi*/
+		0x74,	/*REG = 0x0343  line_length_pck_lo*/
+		0x03,	/*REG = 0x3005*/
+		0x00,	/*REG = 0x3010*/
+		0x01,	/*REG = 0x3011*/
+		0x6a,	/*REG = 0x301a*/
+		0x03,	/*REG = 0x3035*/
+		0x2c,	/*REG = 0x3036*/
+		0x00,	/*REG = 0x3041*/
+		0x24,	/*REG = 0x3042*/
+		0x81,	/*REG = 0x3045*/
+		0x02,	/*REG = 0x0b80 edof estimate*/
+		0x01,	/*REG = 0x0900*/
+		0x22,	/*REG = 0x0901*/
+		0x04,	/*REG = 0x0902*/
+		0x03,	/*REG = 0x0383*/
+		0x03,	/*REG = 0x0387*/
+		0x05,	/*REG = 0x034c*/
+		0x18,	/*REG = 0x034d*/
+		0x03,	/*REG = 0x034e*/
+		0xd4,	/*REG = 0x034f*/
+		0x02,	/*0x1716*/
+		0x04,	/*0x1717*/
+		0x08,	/*0x1718*/
+		0x2c,	/*0x1719*/
+		0x01,   /*0x3210*/
+		0x02,   /*0x111*/
+		0x01,   /*0x3410*/
+		0x01,   /*0x3098*/
+		0x05,   /*0x309D*/
+		0x02,
+		0x04,
+	},
+	{ /* Snapshot */
+		0x07,/*REG = 0x0202 coarse_integration_time_hi*/
+		0x00,/*REG = 0x0203 coarse_integration_time_lo*/
+		0xc0,/*REG = 0x0205 analogue_gain_code_global*/
+		0x07,/*REG = 0x0340 frame_length_lines_hi*/
+		0xd0,/*REG = 0x0341 frame_length_lines_lo*/
+		0x0b,/*REG = 0x0342 line_length_pck_hi*/
+		0x8c,/*REG = 0x0343 line_length_pck_lo*/
+		0x01,/*REG = 0x3005*/
+		0x00,/*REG = 0x3010*/
+		0x00,/*REG = 0x3011*/
+		0x55,/*REG = 0x301a*/
+		0x01,/*REG = 0x3035*/
+		0x23,/*REG = 0x3036*/
+		0x00,/*REG = 0x3041*/
+		0x24,/*REG = 0x3042*/
+		0xb7,/*REG = 0x3045*/
+		0x01,/*REG = 0x0b80 edof application*/
+		0x00,/*REG = 0x0900*/
+		0x00,/*REG = 0x0901*/
+		0x00,/*REG = 0x0902*/
+		0x01,/*REG = 0x0383*/
+		0x01,/*REG = 0x0387*/
+		0x0A,/*REG = 0x034c*/
+		0x30,/*REG = 0x034d*/
+		0x07,/*REG = 0x034e*/
+		0xA8,/*REG = 0x034f*/
+		0x02,/*0x1716*/
+		0x0d,/*0x1717*/
+		0x07,/*0x1718*/
+		0x7d,/*0x1719*/
+		0x01,/*0x3210*/
+		0x02,/*0x111*/
+		0x01,/*0x3410*/
+		0x01,/*0x3098*/
+		0x05, /*0x309D*/
+		0x02,
+		0x00,
+	}
+};
+
+
+
+struct vx6953_reg vx6953_regs = {
+	.reg_pat_init = &vx6953_reg_init[0],
+	.reg_pat = &vx6953_reg_pat[0],
+};
diff --git a/drivers/media/video/msm/vx6953_reg_v4l2.c b/drivers/media/video/msm/vx6953_reg_v4l2.c
new file mode 100644
index 0000000..f16054b
--- /dev/null
+++ b/drivers/media/video/msm/vx6953_reg_v4l2.c
@@ -0,0 +1,135 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+
+#include "vx6953_v4l2.h"
+const struct reg_struct_init vx6953_reg_init[1] = {
+	{
+		10,			/*REG = 0x0112 , 10 bit */
+		10,			/*REG = 0x0113*/
+		9,			/*REG = 0x0301 vt_pix_clk_div*/
+		4,		/*REG = 0x0305 pre_pll_clk_div*/
+		133,		/*REG = 0x0307 pll_multiplier*/
+		10,		/*REG = 0x0309 op_pix_clk_div*/
+		0x08,		/*REG = 0x3030*/
+		0x02,		/*REG = 0x0111*/
+		0x01,		/*REG = 0x0b00 ,lens shading off */
+		0x30,		/*REG = 0x3001*/
+		0x33,		/*REG = 0x3004*/
+		0x09,		/*REG = 0x3007*/
+		0x1F,		/*REG = 0x3016*/
+		0x03,		/*REG = 0x301d*/
+		0x11,		/*REG = 0x317E*/
+		0x09,		/*REG = 0x317F*/
+		0x38,		/*REG = 0x3400*/
+		0x00,		/*REG_0x0b06*/
+		0x80,		/*REG_0x0b07*/
+		0x01,		/*REG_0x0b08*/
+		0x4F,		/*REG_0x0b09*/
+		0x18,		/*REG_0x0136*/
+		0x00,		/*/REG_0x0137*/
+		0x20,		/*REG = 0x0b83*/
+		0x90,		/*REG = 0x0b84*/
+		0x20,		/*REG = 0x0b85*/
+		0x80,		/*REG = 0x0b88*/
+		0x00,		/*REG = 0x0b89*/
+		0x00,		/*REG = 0x0b8a*/
+	}
+};
+const struct reg_struct vx6953_reg_pat[2] = {
+	{/* Preview */
+		0x03,	/*REG = 0x0202 coarse integration_time_hi*/
+		0xd0,	/*REG = 0x0203 coarse_integration_time_lo*/
+		0xc0,	/*REG = 0x0205 analogue_gain_code_global*/
+		0x03,	/*REG = 0x0340 frame_length_lines_hi*/
+		0xf0,	/*REG = 0x0341 frame_length_lines_lo*/
+		0x0b,	/*REG = 0x0342  line_length_pck_hi*/
+		0xa5,	/*REG = 0x0343  line_length_pck_lo*/
+		0x03,	/*REG = 0x3005*/
+		0x00,	/*REG = 0x3010*/
+		0x01,	/*REG = 0x3011*/
+		0x6a,	/*REG = 0x301a*/
+		0x03,	/*REG = 0x3035*/
+		0x2c,	/*REG = 0x3036*/
+		0x00,	/*REG = 0x3041*/
+		0x24,	/*REG = 0x3042*/
+		0x81,	/*REG = 0x3045*/
+		0x02,	/*REG = 0x0b80 edof estimate*/
+		0x01,	/*REG = 0x0900*/
+		0x22,	/*REG = 0x0901*/
+		0x04,	/*REG = 0x0902*/
+		0x03,	/*REG = 0x0383*/
+		0x03,	/*REG = 0x0387*/
+		0x05,	/*REG = 0x034c*/
+		0x18,	/*REG = 0x034d*/
+		0x03,	/*REG = 0x034e*/
+		0xd4,	/*REG = 0x034f*/
+		0x02,	/*0x1716*/
+		0x04,	/*0x1717*/
+		0x08,	/*0x1718*/
+		0x80,	/*0x1719*/
+		0x01,   /*0x3210*/
+		0x02,   /*0x111*/
+		0x01,   /*0x3410*/
+		0x01,   /*0x3098*/
+		0x05,   /*0x309D*/
+		0x02,
+		0x04,
+	},
+	{ /* Snapshot */
+		0x07,/*REG = 0x0202 coarse_integration_time_hi*/
+		0x00,/*REG = 0x0203 coarse_integration_time_lo*/
+		0xc0,/*REG = 0x0205 analogue_gain_code_global*/
+		0x07,/*REG = 0x0340 frame_length_lines_hi*/
+		0xd0,/*REG = 0x0341 frame_length_lines_lo*/
+		0x0b,/*REG = 0x0342 line_length_pck_hi*/
+		0x8c,/*REG = 0x0343 line_length_pck_lo*/
+		0x01,/*REG = 0x3005*/
+		0x00,/*REG = 0x3010*/
+		0x00,/*REG = 0x3011*/
+		0x55,/*REG = 0x301a*/
+		0x01,/*REG = 0x3035*/
+		0x23,/*REG = 0x3036*/
+		0x00,/*REG = 0x3041*/
+		0x24,/*REG = 0x3042*/
+		0xb7,/*REG = 0x3045*/
+		0x01,/*REG = 0x0b80 edof application*/
+		0x00,/*REG = 0x0900*/
+		0x00,/*REG = 0x0901*/
+		0x00,/*REG = 0x0902*/
+		0x01,/*REG = 0x0383*/
+		0x01,/*REG = 0x0387*/
+		0x0A,/*REG = 0x034c*/
+		0x30,/*REG = 0x034d*/
+		0x07,/*REG = 0x034e*/
+		0xA8,/*REG = 0x034f*/
+		0x02,/*0x1716*/
+		0x0d,/*0x1717*/
+		0x07,/*0x1718*/
+		0x7d,/*0x1719*/
+		0x01,/*0x3210*/
+		0x02,/*0x111*/
+		0x01,/*0x3410*/
+		0x01,/*0x3098*/
+		0x05, /*0x309D*/
+		0x02,
+		0x00,
+	}
+};
+
+
+
+struct vx6953_reg vx6953_regs = {
+	.reg_pat_init = &vx6953_reg_init[0],
+	.reg_pat = &vx6953_reg_pat[0],
+};
diff --git a/drivers/media/video/msm/vx6953_v4l2.c b/drivers/media/video/msm/vx6953_v4l2.c
new file mode 100644
index 0000000..2e5e39b
--- /dev/null
+++ b/drivers/media/video/msm/vx6953_v4l2.c
@@ -0,0 +1,4149 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <media/v4l2-subdev.h>
+#include <media/msm_camera.h>
+#include <mach/gpio.h>
+#include <mach/camera.h>
+#include <linux/slab.h>
+#include "vx6953_v4l2.h"
+#include "msm.h"
+
+#define V4L2_IDENT_VX6953  50000
+
+/*=============================================================
+	SENSOR REGISTER DEFINES
+==============================================================*/
+
+#define REG_GROUPED_PARAMETER_HOLD			0x0104
+#define GROUPED_PARAMETER_HOLD_OFF			0x00
+#define GROUPED_PARAMETER_HOLD				0x01
+#define REG_MODE_SELECT					0x0100
+#define MODE_SELECT_STANDBY_MODE			0x00
+#define MODE_SELECT_STREAM				0x01
+/* Integration Time */
+#define REG_COARSE_INTEGRATION_TIME_HI			0x0202
+#define REG_COARSE_INTEGRATION_TIME_LO			0x0203
+/* Gain */
+#define REG_ANALOGUE_GAIN_CODE_GLOBAL_HI		0x0204
+#define REG_ANALOGUE_GAIN_CODE_GLOBAL_LO		0x0205
+/* Digital Gain */
+#define REG_DIGITAL_GAIN_GREEN_R_HI			0x020E
+#define REG_DIGITAL_GAIN_GREEN_R_LO			0x020F
+#define REG_DIGITAL_GAIN_RED_HI				0x0210
+#define REG_DIGITAL_GAIN_RED_LO				0x0211
+#define REG_DIGITAL_GAIN_BLUE_HI			0x0212
+#define REG_DIGITAL_GAIN_BLUE_LO			0x0213
+#define REG_DIGITAL_GAIN_GREEN_B_HI			0x0214
+#define REG_DIGITAL_GAIN_GREEN_B_LO			0x0215
+/* output bits setting */
+#define REG_0x0112					0x0112
+#define REG_0x0113					0x0113
+/* PLL registers */
+#define REG_VT_PIX_CLK_DIV				0x0301
+#define REG_PRE_PLL_CLK_DIV				0x0305
+#define REG_PLL_MULTIPLIER				0x0307
+#define REG_OP_PIX_CLK_DIV				0x0309
+#define REG_0x034c					0x034c
+#define REG_0x034d					0x034d
+#define REG_0x034e					0x034e
+#define REG_0x034f					0x034f
+#define REG_0x0387					0x0387
+#define REG_0x0383					0x0383
+#define REG_FRAME_LENGTH_LINES_HI			0x0340
+#define REG_FRAME_LENGTH_LINES_LO			0x0341
+#define REG_LINE_LENGTH_PCK_HI				0x0342
+#define REG_LINE_LENGTH_PCK_LO				0x0343
+#define REG_0x3030					0x3030
+#define REG_0x0111					0x0111
+#define REG_0x0136					0x0136
+#define REG_0x0137					0x0137
+#define REG_0x0b00					0x0b00
+#define REG_0x3001					0x3001
+#define REG_0x3004					0x3004
+#define REG_0x3007					0x3007
+#define REG_0x301a					0x301a
+#define REG_0x3101					0x3101
+#define REG_0x3364					0x3364
+#define REG_0x3365					0x3365
+#define REG_0x0b83					0x0b83
+#define REG_0x0b84					0x0b84
+#define REG_0x0b85					0x0b85
+#define REG_0x0b88					0x0b88
+#define REG_0x0b89					0x0b89
+#define REG_0x0b8a					0x0b8a
+#define REG_0x3005					0x3005
+#define REG_0x3010					0x3010
+#define REG_0x3036					0x3036
+#define REG_0x3041					0x3041
+#define REG_0x0b80					0x0b80
+#define REG_0x0900					0x0900
+#define REG_0x0901					0x0901
+#define REG_0x0902					0x0902
+#define REG_0x3016					0x3016
+#define REG_0x301d					0x301d
+#define REG_0x317e					0x317e
+#define REG_0x317f					0x317f
+#define REG_0x3400					0x3400
+#define REG_0x303a					0x303a
+#define REG_0x1716					0x1716
+#define REG_0x1717					0x1717
+#define REG_0x1718					0x1718
+#define REG_0x1719					0x1719
+#define REG_0x3006					0x3006
+#define REG_0x301b					0x301b
+#define REG_0x3098					0x3098
+#define REG_0x309d					0x309d
+#define REG_0x3011					0x3011
+#define REG_0x3035					0x3035
+#define REG_0x3045					0x3045
+#define REG_0x3210					0x3210
+#define	REG_0x0111					0x0111
+#define REG_0x3410					0x3410
+/* Test Pattern */
+#define REG_TEST_PATTERN_MODE				0x0601
+
+/*============================================================================
+							 TYPE DECLARATIONS
+============================================================================*/
+
+/* 16bit address - 8 bit context register structure */
+#define	VX6953_STM5M0EDOF_OFFSET	9
+#define	Q8		0x00000100
+#define	Q10		0x00000400
+#define	VX6953_STM5M0EDOF_MAX_SNAPSHOT_EXPOSURE_LINE_COUNT	2922
+#define	VX6953_STM5M0EDOF_DEFAULT_MASTER_CLK_RATE	24000000
+#define	VX6953_STM5M0EDOF_OP_PIXEL_CLOCK_RATE	79800000
+#define	VX6953_STM5M0EDOF_VT_PIXEL_CLOCK_RATE	88670000
+/* Full	Size */
+#define	VX6953_FULL_SIZE_WIDTH	2608
+#define	VX6953_FULL_SIZE_HEIGHT		1960
+#define	VX6953_FULL_SIZE_DUMMY_PIXELS	1
+#define	VX6953_FULL_SIZE_DUMMY_LINES	0
+/* Quarter Size	*/
+#define	VX6953_QTR_SIZE_WIDTH	1304
+#define	VX6953_QTR_SIZE_HEIGHT		980
+#define	VX6953_QTR_SIZE_DUMMY_PIXELS	1
+#define	VX6953_QTR_SIZE_DUMMY_LINES		0
+/* Blanking	as measured	on the scope */
+/* Full	Size */
+#define	VX6953_HRZ_FULL_BLK_PIXELS	348
+#define	VX6953_VER_FULL_BLK_LINES	40
+/* Quarter Size	*/
+#define	VX6953_HRZ_QTR_BLK_PIXELS	1628
+#define	VX6953_VER_QTR_BLK_LINES	28
+#define	MAX_LINE_LENGTH_PCK		8190
+#define	VX6953_REVISION_NUMBER_CUT2	0x10/*revision number	for	Cut2.0*/
+#define	VX6953_REVISION_NUMBER_CUT3	0x20/*revision number	for	Cut3.0*/
+/* FIXME: Changes from here */
+struct vx6953_work_t {
+	struct work_struct work;
+};
+
+static struct vx6953_work_t *vx6953_sensorw;
+static struct i2c_client *vx6953_client;
+
+struct vx6953_ctrl_t {
+	const struct  msm_camera_sensor_info *sensordata;
+
+	uint32_t sensormode;
+	uint32_t fps_divider;  /* init to 1 * 0x00000400 */
+	uint32_t pict_fps_divider;  /* init to 1 * 0x00000400 */
+	uint16_t fps;
+
+	int16_t curr_lens_pos;
+	uint16_t curr_step_pos;
+	uint16_t my_reg_gain;
+	uint32_t my_reg_line_count;
+	uint16_t total_lines_per_frame;
+
+	enum vx6953_resolution_t prev_res;
+	enum vx6953_resolution_t pict_res;
+	enum vx6953_resolution_t curr_res;
+	enum vx6953_test_mode_t  set_test;
+	enum sensor_revision_t sensor_type;
+
+	enum edof_mode_t edof_mode;
+
+	unsigned short imgaddr;
+
+	struct v4l2_subdev *sensor_dev;
+	struct vx6953_format *fmt;
+};
+
+
+static uint8_t vx6953_stm5m0edof_delay_msecs_stdby;
+static uint16_t vx6953_stm5m0edof_delay_msecs_stream = 20;
+
+static struct vx6953_ctrl_t *vx6953_ctrl;
+static DECLARE_WAIT_QUEUE_HEAD(vx6953_wait_queue);
+DEFINE_MUTEX(vx6953_mut);
+static struct vx6953_i2c_reg_conf patch_tbl_cut2[] = {
+	{0xFB94, 0},	/*intialise Data Xfer Status reg*/
+	{0xFB95, 0},	/*gain 1	  (0x00)*/
+	{0xFB96, 0},	/*gain 1.07   (0x10)*/
+	{0xFB97, 0},	/*gain 1.14   (0x20)*/
+	{0xFB98, 0},	/*gain 1.23   (0x30)*/
+	{0xFB99, 0},	/*gain 1.33   (0x40)*/
+	{0xFB9A, 0},	/*gain 1.45   (0x50)*/
+	{0xFB9B, 0},	/*gain 1.6    (0x60)*/
+	{0xFB9C, 0},	/*gain 1.78   (0x70)*/
+	{0xFB9D, 2},	/*gain 2	  (0x80)*/
+	{0xFB9E, 2},	/*gain 2.29   (0x90)*/
+	{0xFB9F, 3},	/*gain 2.67   (0xA0)*/
+	{0xFBA0, 3},	/*gain 3.2    (0xB0)*/
+	{0xFBA1, 4},	/*gain 4	  (0xC0)*/
+	{0xFBA2, 7},	/*gain 5.33   (0xD0)*/
+	{0xFBA3, 10},	/*gain 8	  (0xE0)*/
+	{0xFBA4, 11},	/*gain 9.14   (0xE4)*/
+	{0xFBA5, 13},	/*gain 10.67  (0xE8)*/
+	{0xFBA6, 15},	/*gain 12.8   (0xEC)*/
+	{0xFBA7, 19},	/*gain 16     (0xF0)*/
+	{0xF800, 0x12},
+	{0xF801, 0x06},
+	{0xF802, 0xf7},
+	{0xF803, 0x90},
+	{0xF804, 0x02},
+	{0xF805, 0x05},
+	{0xF806, 0xe0},
+	{0xF807, 0xff},
+	{0xF808, 0x65},
+	{0xF809, 0x7d},
+	{0xF80A, 0x70},
+	{0xF80B, 0x03},
+	{0xF80C, 0x02},
+	{0xF80D, 0xf9},
+	{0xF80E, 0x1c},
+	{0xF80F, 0x8f},
+	{0xF810, 0x7d},
+	{0xF811, 0xe4},
+	{0xF812, 0xf5},
+	{0xF813, 0x7a},
+	{0xF814, 0x75},
+	{0xF815, 0x78},
+	{0xF816, 0x30},
+	{0xF817, 0x75},
+	{0xF818, 0x79},
+	{0xF819, 0x53},
+	{0xF81A, 0x85},
+	{0xF81B, 0x79},
+	{0xF81C, 0x82},
+	{0xF81D, 0x85},
+	{0xF81E, 0x78},
+	{0xF81F, 0x83},
+	{0xF820, 0xe0},
+	{0xF821, 0xc3},
+	{0xF822, 0x95},
+	{0xF823, 0x7b},
+	{0xF824, 0xf0},
+	{0xF825, 0x74},
+	{0xF826, 0x02},
+	{0xF827, 0x25},
+	{0xF828, 0x79},
+	{0xF829, 0xf5},
+	{0xF82A, 0x79},
+	{0xF82B, 0xe4},
+	{0xF82C, 0x35},
+	{0xF82D, 0x78},
+	{0xF82E, 0xf5},
+	{0xF82F, 0x78},
+	{0xF830, 0x05},
+	{0xF831, 0x7a},
+	{0xF832, 0xe5},
+	{0xF833, 0x7a},
+	{0xF834, 0xb4},
+	{0xF835, 0x08},
+	{0xF836, 0xe3},
+	{0xF837, 0xe5},
+	{0xF838, 0x7d},
+	{0xF839, 0x70},
+	{0xF83A, 0x04},
+	{0xF83B, 0xff},
+	{0xF83C, 0x02},
+	{0xF83D, 0xf8},
+	{0xF83E, 0xe4},
+	{0xF83F, 0xe5},
+	{0xF840, 0x7d},
+	{0xF841, 0xb4},
+	{0xF842, 0x10},
+	{0xF843, 0x05},
+	{0xF844, 0x7f},
+	{0xF845, 0x01},
+	{0xF846, 0x02},
+	{0xF847, 0xf8},
+	{0xF848, 0xe4},
+	{0xF849, 0xe5},
+	{0xF84A, 0x7d},
+	{0xF84B, 0xb4},
+	{0xF84C, 0x20},
+	{0xF84D, 0x05},
+	{0xF84E, 0x7f},
+	{0xF84F, 0x02},
+	{0xF850, 0x02},
+	{0xF851, 0xf8},
+	{0xF852, 0xe4},
+	{0xF853, 0xe5},
+	{0xF854, 0x7d},
+	{0xF855, 0xb4},
+	{0xF856, 0x30},
+	{0xF857, 0x05},
+	{0xF858, 0x7f},
+	{0xF859, 0x03},
+	{0xF85A, 0x02},
+	{0xF85B, 0xf8},
+	{0xF85C, 0xe4},
+	{0xF85D, 0xe5},
+	{0xF85E, 0x7d},
+	{0xF85F, 0xb4},
+	{0xF860, 0x40},
+	{0xF861, 0x04},
+	{0xF862, 0x7f},
+	{0xF863, 0x04},
+	{0xF864, 0x80},
+	{0xF865, 0x7e},
+	{0xF866, 0xe5},
+	{0xF867, 0x7d},
+	{0xF868, 0xb4},
+	{0xF869, 0x50},
+	{0xF86A, 0x04},
+	{0xF86B, 0x7f},
+	{0xF86C, 0x05},
+	{0xF86D, 0x80},
+	{0xF86E, 0x75},
+	{0xF86F, 0xe5},
+	{0xF870, 0x7d},
+	{0xF871, 0xb4},
+	{0xF872, 0x60},
+	{0xF873, 0x04},
+	{0xF874, 0x7f},
+	{0xF875, 0x06},
+	{0xF876, 0x80},
+	{0xF877, 0x6c},
+	{0xF878, 0xe5},
+	{0xF879, 0x7d},
+	{0xF87A, 0xb4},
+	{0xF87B, 0x70},
+	{0xF87C, 0x04},
+	{0xF87D, 0x7f},
+	{0xF87E, 0x07},
+	{0xF87F, 0x80},
+	{0xF880, 0x63},
+	{0xF881, 0xe5},
+	{0xF882, 0x7d},
+	{0xF883, 0xb4},
+	{0xF884, 0x80},
+	{0xF885, 0x04},
+	{0xF886, 0x7f},
+	{0xF887, 0x08},
+	{0xF888, 0x80},
+	{0xF889, 0x5a},
+	{0xF88A, 0xe5},
+	{0xF88B, 0x7d},
+	{0xF88C, 0xb4},
+	{0xF88D, 0x90},
+	{0xF88E, 0x04},
+	{0xF88F, 0x7f},
+	{0xF890, 0x09},
+	{0xF891, 0x80},
+	{0xF892, 0x51},
+	{0xF893, 0xe5},
+	{0xF894, 0x7d},
+	{0xF895, 0xb4},
+	{0xF896, 0xa0},
+	{0xF897, 0x04},
+	{0xF898, 0x7f},
+	{0xF899, 0x0a},
+	{0xF89A, 0x80},
+	{0xF89B, 0x48},
+	{0xF89C, 0xe5},
+	{0xF89D, 0x7d},
+	{0xF89E, 0xb4},
+	{0xF89F, 0xb0},
+	{0xF8A0, 0x04},
+	{0xF8A1, 0x7f},
+	{0xF8A2, 0x0b},
+	{0xF8A3, 0x80},
+	{0xF8A4, 0x3f},
+	{0xF8A5, 0xe5},
+	{0xF8A6, 0x7d},
+	{0xF8A7, 0xb4},
+	{0xF8A8, 0xc0},
+	{0xF8A9, 0x04},
+	{0xF8AA, 0x7f},
+	{0xF8AB, 0x0c},
+	{0xF8AC, 0x80},
+	{0xF8AD, 0x36},
+	{0xF8AE, 0xe5},
+	{0xF8AF, 0x7d},
+	{0xF8B0, 0xb4},
+	{0xF8B1, 0xd0},
+	{0xF8B2, 0x04},
+	{0xF8B3, 0x7f},
+	{0xF8B4, 0x0d},
+	{0xF8B5, 0x80},
+	{0xF8B6, 0x2d},
+	{0xF8B7, 0xe5},
+	{0xF8B8, 0x7d},
+	{0xF8B9, 0xb4},
+	{0xF8BA, 0xe0},
+	{0xF8BB, 0x04},
+	{0xF8BC, 0x7f},
+	{0xF8BD, 0x0e},
+	{0xF8BE, 0x80},
+	{0xF8BF, 0x24},
+	{0xF8C0, 0xe5},
+	{0xF8C1, 0x7d},
+	{0xF8C2, 0xb4},
+	{0xF8C3, 0xe4},
+	{0xF8C4, 0x04},
+	{0xF8C5, 0x7f},
+	{0xF8C6, 0x0f},
+	{0xF8C7, 0x80},
+	{0xF8C8, 0x1b},
+	{0xF8C9, 0xe5},
+	{0xF8CA, 0x7d},
+	{0xF8CB, 0xb4},
+	{0xF8CC, 0xe8},
+	{0xF8CD, 0x04},
+	{0xF8CE, 0x7f},
+	{0xF8CF, 0x10},
+	{0xF8D0, 0x80},
+	{0xF8D1, 0x12},
+	{0xF8D2, 0xe5},
+	{0xF8D3, 0x7d},
+	{0xF8D4, 0xb4},
+	{0xF8D5, 0xec},
+	{0xF8D6, 0x04},
+	{0xF8D7, 0x7f},
+	{0xF8D8, 0x11},
+	{0xF8D9, 0x80},
+	{0xF8DA, 0x09},
+	{0xF8DB, 0xe5},
+	{0xF8DC, 0x7d},
+	{0xF8DD, 0x7f},
+	{0xF8DE, 0x00},
+	{0xF8DF, 0xb4},
+	{0xF8E0, 0xf0},
+	{0xF8E1, 0x02},
+	{0xF8E2, 0x7f},
+	{0xF8E3, 0x12},
+	{0xF8E4, 0x8f},
+	{0xF8E5, 0x7c},
+	{0xF8E6, 0xef},
+	{0xF8E7, 0x24},
+	{0xF8E8, 0x95},
+	{0xF8E9, 0xff},
+	{0xF8EA, 0xe4},
+	{0xF8EB, 0x34},
+	{0xF8EC, 0xfb},
+	{0xF8ED, 0x8f},
+	{0xF8EE, 0x82},
+	{0xF8EF, 0xf5},
+	{0xF8F0, 0x83},
+	{0xF8F1, 0xe4},
+	{0xF8F2, 0x93},
+	{0xF8F3, 0xf5},
+	{0xF8F4, 0x7c},
+	{0xF8F5, 0xf5},
+	{0xF8F6, 0x7b},
+	{0xF8F7, 0xe4},
+	{0xF8F8, 0xf5},
+	{0xF8F9, 0x7a},
+	{0xF8FA, 0x75},
+	{0xF8FB, 0x78},
+	{0xF8FC, 0x30},
+	{0xF8FD, 0x75},
+	{0xF8FE, 0x79},
+	{0xF8FF, 0x53},
+	{0xF900, 0x85},
+	{0xF901, 0x79},
+	{0xF902, 0x82},
+	{0xF903, 0x85},
+	{0xF904, 0x78},
+	{0xF905, 0x83},
+	{0xF906, 0xe0},
+	{0xF907, 0x25},
+	{0xF908, 0x7c},
+	{0xF909, 0xf0},
+	{0xF90A, 0x74},
+	{0xF90B, 0x02},
+	{0xF90C, 0x25},
+	{0xF90D, 0x79},
+	{0xF90E, 0xf5},
+	{0xF90F, 0x79},
+	{0xF910, 0xe4},
+	{0xF911, 0x35},
+	{0xF912, 0x78},
+	{0xF913, 0xf5},
+	{0xF914, 0x78},
+	{0xF915, 0x05},
+	{0xF916, 0x7a},
+	{0xF917, 0xe5},
+	{0xF918, 0x7a},
+	{0xF919, 0xb4},
+	{0xF91A, 0x08},
+	{0xF91B, 0xe4},
+	{0xF91C, 0x02},
+	{0xF91D, 0x18},
+	{0xF91E, 0x32},
+	{0xF91F, 0x22},
+	{0xF920, 0xf0},
+	{0xF921, 0x90},
+	{0xF922, 0xa0},
+	{0xF923, 0xf8},
+	{0xF924, 0xe0},
+	{0xF925, 0x70},
+	{0xF926, 0x02},
+	{0xF927, 0xa3},
+	{0xF928, 0xe0},
+	{0xF929, 0x70},
+	{0xF92A, 0x0a},
+	{0xF92B, 0x90},
+	{0xF92C, 0xa1},
+	{0xF92D, 0x10},
+	{0xF92E, 0xe0},
+	{0xF92F, 0xfe},
+	{0xF930, 0xa3},
+	{0xF931, 0xe0},
+	{0xF932, 0xff},
+	{0xF933, 0x80},
+	{0xF934, 0x04},
+	{0xF935, 0x7e},
+	{0xF936, 0x00},
+	{0xF937, 0x7f},
+	{0xF938, 0x00},
+	{0xF939, 0x8e},
+	{0xF93A, 0x7e},
+	{0xF93B, 0x8f},
+	{0xF93C, 0x7f},
+	{0xF93D, 0x90},
+	{0xF93E, 0x36},
+	{0xF93F, 0x0d},
+	{0xF940, 0xe0},
+	{0xF941, 0x44},
+	{0xF942, 0x02},
+	{0xF943, 0xf0},
+	{0xF944, 0x90},
+	{0xF945, 0x36},
+	{0xF946, 0x0e},
+	{0xF947, 0xe5},
+	{0xF948, 0x7e},
+	{0xF949, 0xf0},
+	{0xF94A, 0xa3},
+	{0xF94B, 0xe5},
+	{0xF94C, 0x7f},
+	{0xF94D, 0xf0},
+	{0xF94E, 0xe5},
+	{0xF94F, 0x3a},
+	{0xF950, 0x60},
+	{0xF951, 0x0c},
+	{0xF952, 0x90},
+	{0xF953, 0x36},
+	{0xF954, 0x09},
+	{0xF955, 0xe0},
+	{0xF956, 0x70},
+	{0xF957, 0x06},
+	{0xF958, 0x90},
+	{0xF959, 0x36},
+	{0xF95A, 0x08},
+	{0xF95B, 0xf0},
+	{0xF95C, 0xf5},
+	{0xF95D, 0x3a},
+	{0xF95E, 0x02},
+	{0xF95F, 0x03},
+	{0xF960, 0x94},
+	{0xF961, 0x22},
+	{0xF962, 0x78},
+	{0xF963, 0x07},
+	{0xF964, 0xe6},
+	{0xF965, 0xd3},
+	{0xF966, 0x94},
+	{0xF967, 0x00},
+	{0xF968, 0x40},
+	{0xF969, 0x16},
+	{0xF96A, 0x16},
+	{0xF96B, 0xe6},
+	{0xF96C, 0x90},
+	{0xF96D, 0x30},
+	{0xF96E, 0xa1},
+	{0xF96F, 0xf0},
+	{0xF970, 0x90},
+	{0xF971, 0x43},
+	{0xF972, 0x83},
+	{0xF973, 0xe0},
+	{0xF974, 0xb4},
+	{0xF975, 0x01},
+	{0xF976, 0x0f},
+	{0xF977, 0x90},
+	{0xF978, 0x43},
+	{0xF979, 0x87},
+	{0xF97A, 0xe0},
+	{0xF97B, 0xb4},
+	{0xF97C, 0x01},
+	{0xF97D, 0x08},
+	{0xF97E, 0x80},
+	{0xF97F, 0x00},
+	{0xF980, 0x90},
+	{0xF981, 0x30},
+	{0xF982, 0xa0},
+	{0xF983, 0x74},
+	{0xF984, 0x01},
+	{0xF985, 0xf0},
+	{0xF986, 0x22},
+	{0xF987, 0xf0},
+	{0xF988, 0x90},
+	{0xF989, 0x35},
+	{0xF98A, 0xba},
+	{0xF98B, 0xe0},
+	{0xF98C, 0xb4},
+	{0xF98D, 0x0a},
+	{0xF98E, 0x0d},
+	{0xF98F, 0xa3},
+	{0xF990, 0xe0},
+	{0xF991, 0xb4},
+	{0xF992, 0x01},
+	{0xF993, 0x08},
+	{0xF994, 0x90},
+	{0xF995, 0xfb},
+	{0xF996, 0x94},
+	{0xF997, 0xe0},
+	{0xF998, 0x90},
+	{0xF999, 0x35},
+	{0xF99A, 0xb8},
+	{0xF99B, 0xf0},
+	{0xF99C, 0xd0},
+	{0xF99D, 0xd0},
+	{0xF99E, 0xd0},
+	{0xF99F, 0x82},
+	{0xF9A0, 0xd0},
+	{0xF9A1, 0x83},
+	{0xF9A2, 0xd0},
+	{0xF9A3, 0xe0},
+	{0xF9A4, 0x32},
+	{0xF9A5, 0x22},
+	{0xF9A6, 0xe5},
+	{0xF9A7, 0x7f},
+	{0xF9A8, 0x45},
+	{0xF9A9, 0x7e},
+	{0xF9AA, 0x60},
+	{0xF9AB, 0x15},
+	{0xF9AC, 0x90},
+	{0xF9AD, 0x01},
+	{0xF9AE, 0x00},
+	{0xF9AF, 0xe0},
+	{0xF9B0, 0x70},
+	{0xF9B1, 0x0f},
+	{0xF9B2, 0x90},
+	{0xF9B3, 0xa0},
+	{0xF9B4, 0xf8},
+	{0xF9B5, 0xe5},
+	{0xF9B6, 0x7e},
+	{0xF9B7, 0xf0},
+	{0xF9B8, 0xa3},
+	{0xF9B9, 0xe5},
+	{0xF9BA, 0x7f},
+	{0xF9BB, 0xf0},
+	{0xF9BC, 0xe4},
+	{0xF9BD, 0xf5},
+	{0xF9BE, 0x7e},
+	{0xF9BF, 0xf5},
+	{0xF9C0, 0x7f},
+	{0xF9C1, 0x22},
+	{0xF9C2, 0x02},
+	{0xF9C3, 0x0e},
+	{0xF9C4, 0x79},
+	{0xF9C5, 0x22},
+	/* Offsets:*/
+	{0x35C6, 0x00},/* FIDDLEDARKCAL*/
+	{0x35C7, 0x00},
+	{0x35C8, 0x01},/*STOREDISTANCEATSTOPSTREAMING*/
+	{0x35C9, 0x20},
+	{0x35CA, 0x01},/*BRUCEFIX*/
+	{0x35CB, 0x62},
+	{0x35CC, 0x01},/*FIXDATAXFERSTATUSREG*/
+	{0x35CD, 0x87},
+	{0x35CE, 0x01},/*FOCUSDISTANCEUPDATE*/
+	{0x35CF, 0xA6},
+	{0x35D0, 0x01},/*SKIPEDOFRESET*/
+	{0x35D1, 0xC2},
+	{0x35D2, 0x00},
+	{0x35D3, 0xFB},
+	{0x35D4, 0x00},
+	{0x35D5, 0x94},
+	{0x35D6, 0x00},
+	{0x35D7, 0xFB},
+	{0x35D8, 0x00},
+	{0x35D9, 0x94},
+	{0x35DA, 0x00},
+	{0x35DB, 0xFB},
+	{0x35DC, 0x00},
+	{0x35DD, 0x94},
+	{0x35DE, 0x00},
+	{0x35DF, 0xFB},
+	{0x35E0, 0x00},
+	{0x35E1, 0x94},
+	{0x35E6, 0x18},/* FIDDLEDARKCAL*/
+	{0x35E7, 0x2F},
+	{0x35E8, 0x03},/* STOREDISTANCEATSTOPSTREAMING*/
+	{0x35E9, 0x93},
+	{0x35EA, 0x18},/* BRUCEFIX*/
+	{0x35EB, 0x99},
+	{0x35EC, 0x00},/* FIXDATAXFERSTATUSREG*/
+	{0x35ED, 0xA3},
+	{0x35EE, 0x21},/* FOCUSDISTANCEUPDATE*/
+	{0x35EF, 0x5B},
+	{0x35F0, 0x0E},/* SKIPEDOFRESET*/
+	{0x35F1, 0x74},
+	{0x35F2, 0x04},
+	{0x35F3, 0x64},
+	{0x35F4, 0x04},
+	{0x35F5, 0x65},
+	{0x35F6, 0x04},
+	{0x35F7, 0x7B},
+	{0x35F8, 0x04},
+	{0x35F9, 0x7C},
+	{0x35FA, 0x04},
+	{0x35FB, 0xDD},
+	{0x35FC, 0x04},
+	{0x35FD, 0xDE},
+	{0x35FE, 0x04},
+	{0x35FF, 0xEF},
+	{0x3600, 0x04},
+	{0x3601, 0xF0},
+	/*Jump/Data:*/
+	{0x35C2, 0x3F},/* Jump Reg*/
+	{0x35C3, 0xFF},/* Jump Reg*/
+	{0x35C4, 0x3F},/* Data Reg*/
+	{0x35C5, 0xC0},/* Data Reg*/
+	{0x35C0, 0x01},/* Enable*/
+
+};
+
+static struct vx6953_i2c_reg_conf edof_tbl[] = {
+	{0xa098, 0x02},
+	{0xa099, 0x87},
+	{0xa09c, 0x00},
+	{0xa09d, 0xc5},
+	{0xa4ec, 0x05},
+	{0xa4ed, 0x05},
+	{0xa4f0, 0x04},
+	{0xa4f1, 0x04},
+	{0xa4f4, 0x04},
+	{0xa4f5, 0x05},
+	{0xa4f8, 0x05},
+	{0xa4f9, 0x07},
+	{0xa4fc, 0x07},
+	{0xa4fd, 0x07},
+	{0xa500, 0x07},
+	{0xa501, 0x07},
+	{0xa504, 0x08},
+	{0xa505, 0x08},
+	{0xa518, 0x01},
+	{0xa519, 0x02},
+	{0xa51c, 0x01},
+	{0xa51d, 0x00},
+	{0xa534, 0x00},
+	{0xa535, 0x04},
+	{0xa538, 0x04},
+	{0xa539, 0x03},
+	{0xa53c, 0x05},
+	{0xa53d, 0x07},
+	{0xa540, 0x07},
+	{0xa541, 0x06},
+	{0xa544, 0x07},
+	{0xa545, 0x06},
+	{0xa548, 0x05},
+	{0xa549, 0x06},
+	{0xa54c, 0x06},
+	{0xa54d, 0x07},
+	{0xa550, 0x07},
+	{0xa551, 0x04},
+	{0xa554, 0x04},
+	{0xa555, 0x04},
+	{0xa558, 0x05},
+	{0xa559, 0x06},
+	{0xa55c, 0x07},
+	{0xa55d, 0x07},
+	{0xa56c, 0x00},
+	{0xa56d, 0x0a},
+	{0xa570, 0x08},
+	{0xa571, 0x05},
+	{0xa574, 0x04},
+	{0xa575, 0x03},
+	{0xa578, 0x04},
+	{0xa579, 0x04},
+	{0xa58c, 0x1f},
+	{0xa58d, 0x1b},
+	{0xa590, 0x17},
+	{0xa591, 0x13},
+	{0xa594, 0x10},
+	{0xa595, 0x0d},
+	{0xa598, 0x0f},
+	{0xa599, 0x11},
+	{0xa59c, 0x03},
+	{0xa59d, 0x03},
+	{0xa5a0, 0x03},
+	{0xa5a1, 0x03},
+	{0xa5a4, 0x03},
+	{0xa5a5, 0x04},
+	{0xa5a8, 0x05},
+	{0xa5a9, 0x00},
+	{0xa5ac, 0x00},
+	{0xa5ad, 0x00},
+	{0xa5b0, 0x00},
+	{0xa5b1, 0x00},
+	{0xa5b4, 0x00},
+	{0xa5b5, 0x00},
+	{0xa5c4, 0x1f},
+	{0xa5c5, 0x13},
+	{0xa5c8, 0x14},
+	{0xa5c9, 0x14},
+	{0xa5cc, 0x14},
+	{0xa5cd, 0x13},
+	{0xa5d0, 0x17},
+	{0xa5d1, 0x1a},
+	{0xa5f4, 0x05},
+	{0xa5f5, 0x05},
+	{0xa5f8, 0x05},
+	{0xa5f9, 0x06},
+	{0xa5fc, 0x06},
+	{0xa5fd, 0x06},
+	{0xa600, 0x06},
+	{0xa601, 0x06},
+	{0xa608, 0x07},
+	{0xa609, 0x08},
+	{0xa60c, 0x08},
+	{0xa60d, 0x07},
+	{0xa63c, 0x00},
+	{0xa63d, 0x02},
+	{0xa640, 0x02},
+	{0xa641, 0x02},
+	{0xa644, 0x02},
+	{0xa645, 0x02},
+	{0xa648, 0x03},
+	{0xa649, 0x04},
+	{0xa64c, 0x0a},
+	{0xa64d, 0x09},
+	{0xa650, 0x08},
+	{0xa651, 0x09},
+	{0xa654, 0x09},
+	{0xa655, 0x0a},
+	{0xa658, 0x0a},
+	{0xa659, 0x0a},
+	{0xa65c, 0x0a},
+	{0xa65d, 0x09},
+	{0xa660, 0x09},
+	{0xa661, 0x09},
+	{0xa664, 0x09},
+	{0xa665, 0x08},
+	{0xa680, 0x01},
+	{0xa681, 0x02},
+	{0xa694, 0x1f},
+	{0xa695, 0x10},
+	{0xa698, 0x0e},
+	{0xa699, 0x0c},
+	{0xa69c, 0x0d},
+	{0xa69d, 0x0d},
+	{0xa6a0, 0x0f},
+	{0xa6a1, 0x11},
+	{0xa6a4, 0x00},
+	{0xa6a5, 0x00},
+	{0xa6a8, 0x00},
+	{0xa6a9, 0x00},
+	{0xa6ac, 0x00},
+	{0xa6ad, 0x00},
+	{0xa6b0, 0x00},
+	{0xa6b1, 0x04},
+	{0xa6b4, 0x04},
+	{0xa6b5, 0x04},
+	{0xa6b8, 0x04},
+	{0xa6b9, 0x04},
+	{0xa6bc, 0x05},
+	{0xa6bd, 0x05},
+	{0xa6c0, 0x1f},
+	{0xa6c1, 0x1f},
+	{0xa6c4, 0x1f},
+	{0xa6c5, 0x1f},
+	{0xa6c8, 0x1f},
+	{0xa6c9, 0x1f},
+	{0xa6cc, 0x1f},
+	{0xa6cd, 0x0b},
+	{0xa6d0, 0x0c},
+	{0xa6d1, 0x0d},
+	{0xa6d4, 0x0d},
+	{0xa6d5, 0x0d},
+	{0xa6d8, 0x11},
+	{0xa6d9, 0x14},
+	{0xa6fc, 0x02},
+	{0xa6fd, 0x03},
+	{0xa700, 0x03},
+	{0xa701, 0x03},
+	{0xa704, 0x03},
+	{0xa705, 0x04},
+	{0xa708, 0x05},
+	{0xa709, 0x02},
+	{0xa70c, 0x02},
+	{0xa70d, 0x02},
+	{0xa710, 0x03},
+	{0xa711, 0x04},
+	{0xa714, 0x04},
+	{0xa715, 0x04},
+	{0xa744, 0x00},
+	{0xa745, 0x03},
+	{0xa748, 0x04},
+	{0xa749, 0x04},
+	{0xa74c, 0x05},
+	{0xa74d, 0x06},
+	{0xa750, 0x07},
+	{0xa751, 0x07},
+	{0xa754, 0x05},
+	{0xa755, 0x05},
+	{0xa758, 0x05},
+	{0xa759, 0x05},
+	{0xa75c, 0x05},
+	{0xa75d, 0x06},
+	{0xa760, 0x07},
+	{0xa761, 0x07},
+	{0xa764, 0x06},
+	{0xa765, 0x05},
+	{0xa768, 0x05},
+	{0xa769, 0x05},
+	{0xa76c, 0x06},
+	{0xa76d, 0x07},
+	{0xa77c, 0x00},
+	{0xa77d, 0x05},
+	{0xa780, 0x05},
+	{0xa781, 0x05},
+	{0xa784, 0x05},
+	{0xa785, 0x04},
+	{0xa788, 0x05},
+	{0xa789, 0x06},
+	{0xa79c, 0x1f},
+	{0xa79d, 0x15},
+	{0xa7a0, 0x13},
+	{0xa7a1, 0x10},
+	{0xa7a4, 0x0f},
+	{0xa7a5, 0x0d},
+	{0xa7a8, 0x11},
+	{0xa7a9, 0x14},
+	{0xa7ac, 0x02},
+	{0xa7ad, 0x02},
+	{0xa7b0, 0x02},
+	{0xa7b1, 0x02},
+	{0xa7b4, 0x02},
+	{0xa7b5, 0x03},
+	{0xa7b8, 0x03},
+	{0xa7b9, 0x00},
+	{0xa7bc, 0x00},
+	{0xa7bd, 0x00},
+	{0xa7c0, 0x00},
+	{0xa7c1, 0x00},
+	{0xa7c4, 0x00},
+	{0xa7c5, 0x00},
+	{0xa7d4, 0x1f},
+	{0xa7d5, 0x0d},
+	{0xa7d8, 0x0f},
+	{0xa7d9, 0x10},
+	{0xa7dc, 0x10},
+	{0xa7dd, 0x10},
+	{0xa7e0, 0x13},
+	{0xa7e1, 0x16},
+	{0xa7f4, 0x00},
+	{0xa7f5, 0x03},
+	{0xa7f8, 0x04},
+	{0xa7f9, 0x04},
+	{0xa7fc, 0x04},
+	{0xa7fd, 0x03},
+	{0xa800, 0x03},
+	{0xa801, 0x03},
+	{0xa804, 0x03},
+	{0xa805, 0x03},
+	{0xa808, 0x03},
+	{0xa809, 0x03},
+	{0xa80c, 0x03},
+	{0xa80d, 0x04},
+	{0xa810, 0x04},
+	{0xa811, 0x0a},
+	{0xa814, 0x0a},
+	{0xa815, 0x0a},
+	{0xa818, 0x0f},
+	{0xa819, 0x14},
+	{0xa81c, 0x14},
+	{0xa81d, 0x14},
+	{0xa82c, 0x00},
+	{0xa82d, 0x04},
+	{0xa830, 0x02},
+	{0xa831, 0x00},
+	{0xa834, 0x00},
+	{0xa835, 0x00},
+	{0xa838, 0x00},
+	{0xa839, 0x00},
+	{0xa840, 0x1f},
+	{0xa841, 0x1f},
+	{0xa848, 0x1f},
+	{0xa849, 0x1f},
+	{0xa84c, 0x1f},
+	{0xa84d, 0x0c},
+	{0xa850, 0x0c},
+	{0xa851, 0x0c},
+	{0xa854, 0x0c},
+	{0xa855, 0x0c},
+	{0xa858, 0x0c},
+	{0xa859, 0x0c},
+	{0xa85c, 0x0c},
+	{0xa85d, 0x0c},
+	{0xa860, 0x0c},
+	{0xa861, 0x0c},
+	{0xa864, 0x0c},
+	{0xa865, 0x0c},
+	{0xa868, 0x0c},
+	{0xa869, 0x0c},
+	{0xa86c, 0x0c},
+	{0xa86d, 0x0c},
+	{0xa870, 0x0c},
+	{0xa871, 0x0c},
+	{0xa874, 0x0c},
+	{0xa875, 0x0c},
+	{0xa878, 0x1f},
+	{0xa879, 0x1f},
+	{0xa87c, 0x1f},
+	{0xa87d, 0x1f},
+	{0xa880, 0x1f},
+	{0xa881, 0x1f},
+	{0xa884, 0x1f},
+	{0xa885, 0x0c},
+	{0xa888, 0x0c},
+	{0xa889, 0x0c},
+	{0xa88c, 0x0c},
+	{0xa88d, 0x0c},
+	{0xa890, 0x0c},
+	{0xa891, 0x0c},
+	{0xa898, 0x1f},
+	{0xa899, 0x1f},
+	{0xa8a0, 0x1f},
+	{0xa8a1, 0x1f},
+	{0xa8a4, 0x1f},
+	{0xa8a5, 0x0c},
+	{0xa8a8, 0x0c},
+	{0xa8a9, 0x0c},
+	{0xa8ac, 0x0c},
+	{0xa8ad, 0x0c},
+	{0xa8b0, 0x0c},
+	{0xa8b1, 0x0c},
+	{0xa8b4, 0x0c},
+	{0xa8b5, 0x0c},
+	{0xa8b8, 0x0c},
+	{0xa8b9, 0x0c},
+	{0xa8bc, 0x0c},
+	{0xa8bd, 0x0c},
+	{0xa8c0, 0x0c},
+	{0xa8c1, 0x0c},
+	{0xa8c4, 0x0c},
+	{0xa8c5, 0x0c},
+	{0xa8c8, 0x0c},
+	{0xa8c9, 0x0c},
+	{0xa8cc, 0x0c},
+	{0xa8cd, 0x0c},
+	{0xa8d0, 0x1f},
+	{0xa8d1, 0x1f},
+	{0xa8d4, 0x1f},
+	{0xa8d5, 0x1f},
+	{0xa8d8, 0x1f},
+	{0xa8d9, 0x1f},
+	{0xa8dc, 0x1f},
+	{0xa8dd, 0x0c},
+	{0xa8e0, 0x0c},
+	{0xa8e1, 0x0c},
+	{0xa8e4, 0x0c},
+	{0xa8e5, 0x0c},
+	{0xa8e8, 0x0c},
+	{0xa8e9, 0x0c},
+	{0xa8f0, 0x1f},
+	{0xa8f1, 0x1f},
+	{0xa8f8, 0x1f},
+	{0xa8f9, 0x1f},
+	{0xa8fc, 0x1f},
+	{0xa8fd, 0x0c},
+	{0xa900, 0x0c},
+	{0xa901, 0x0c},
+	{0xa904, 0x0c},
+	{0xa905, 0x0c},
+	{0xa908, 0x0c},
+	{0xa909, 0x0c},
+	{0xa90c, 0x0c},
+	{0xa90d, 0x0c},
+	{0xa910, 0x0c},
+	{0xa911, 0x0c},
+	{0xa914, 0x0c},
+	{0xa915, 0x0c},
+	{0xa918, 0x0c},
+	{0xa919, 0x0c},
+	{0xa91c, 0x0c},
+	{0xa91d, 0x0c},
+	{0xa920, 0x0c},
+	{0xa921, 0x0c},
+	{0xa924, 0x0c},
+	{0xa925, 0x0c},
+	{0xa928, 0x1f},
+	{0xa929, 0x1f},
+	{0xa92c, 0x1f},
+	{0xa92d, 0x1f},
+	{0xa930, 0x1f},
+	{0xa931, 0x1f},
+	{0xa934, 0x1f},
+	{0xa935, 0x0c},
+	{0xa938, 0x0c},
+	{0xa939, 0x0c},
+	{0xa93c, 0x0c},
+	{0xa93d, 0x0c},
+	{0xa940, 0x0c},
+	{0xa941, 0x0c},
+	{0xa96c, 0x0d},
+	{0xa96d, 0x16},
+	{0xa970, 0x19},
+	{0xa971, 0x0e},
+	{0xa974, 0x16},
+	{0xa975, 0x1a},
+	{0xa978, 0x0d},
+	{0xa979, 0x15},
+	{0xa97c, 0x19},
+	{0xa97d, 0x0d},
+	{0xa980, 0x15},
+	{0xa981, 0x1a},
+	{0xa984, 0x0d},
+	{0xa985, 0x15},
+	{0xa988, 0x1a},
+	{0xa989, 0x0d},
+	{0xa98c, 0x15},
+	{0xa98d, 0x1a},
+	{0xa990, 0x0b},
+	{0xa991, 0x11},
+	{0xa994, 0x02},
+	{0xa995, 0x0e},
+	{0xa998, 0x16},
+	{0xa999, 0x02},
+	{0xa99c, 0x0c},
+	{0xa99d, 0x13},
+	{0xa9a0, 0x02},
+	{0xa9a1, 0x0c},
+	{0xa9a4, 0x12},
+	{0xa9a5, 0x02},
+	{0xa9a8, 0x0c},
+	{0xa9a9, 0x12},
+	{0xa9ac, 0x02},
+	{0xa9ad, 0x0c},
+	{0xa9b0, 0x12},
+	{0xa9b1, 0x02},
+	{0xa9b4, 0x10},
+	{0xa9b5, 0x1e},
+	{0xa9b8, 0x0f},
+	{0xa9b9, 0x13},
+	{0xa9bc, 0x20},
+	{0xa9bd, 0x10},
+	{0xa9c0, 0x11},
+	{0xa9c1, 0x1e},
+	{0xa9c4, 0x10},
+	{0xa9c5, 0x11},
+	{0xa9c8, 0x1e},
+	{0xa9c9, 0x10},
+	{0xa9cc, 0x11},
+	{0xa9cd, 0x20},
+	{0xa9d0, 0x10},
+	{0xa9d1, 0x13},
+	{0xa9d4, 0x24},
+	{0xa9d5, 0x10},
+	{0xa9f0, 0x02},
+	{0xa9f1, 0x01},
+	{0xa9f8, 0x19},
+	{0xa9f9, 0x0b},
+	{0xa9fc, 0x0a},
+	{0xa9fd, 0x07},
+	{0xaa00, 0x0c},
+	{0xaa01, 0x0e},
+	{0xaa08, 0x0c},
+	{0xaa09, 0x06},
+	{0xaa0c, 0x0c},
+	{0xaa0d, 0x0a},
+	{0xaa24, 0x10},
+	{0xaa25, 0x12},
+	{0xaa28, 0x0b},
+	{0xaa29, 0x07},
+	{0xaa2c, 0x10},
+	{0xaa2d, 0x14},
+	{0xaa34, 0x0e},
+	{0xaa35, 0x0e},
+	{0xaa38, 0x07},
+	{0xaa39, 0x07},
+	{0xaa3c, 0x0e},
+	{0xaa3d, 0x0c},
+	{0xaa48, 0x09},
+	{0xaa49, 0x0c},
+	{0xaa4c, 0x0c},
+	{0xaa4d, 0x07},
+	{0xaa54, 0x08},
+	{0xaa55, 0x06},
+	{0xaa58, 0x04},
+	{0xaa59, 0x05},
+	{0xaa5c, 0x06},
+	{0xaa5d, 0x06},
+	{0xaa68, 0x05},
+	{0xaa69, 0x05},
+	{0xaa6c, 0x04},
+	{0xaa6d, 0x05},
+	{0xaa74, 0x06},
+	{0xaa75, 0x04},
+	{0xaa78, 0x05},
+	{0xaa79, 0x05},
+	{0xaa7c, 0x04},
+	{0xaa7d, 0x06},
+	{0xac18, 0x14},
+	{0xac19, 0x00},
+	{0xac1c, 0x14},
+	{0xac1d, 0x00},
+	{0xac20, 0x14},
+	{0xac21, 0x00},
+	{0xac24, 0x14},
+	{0xac25, 0x00},
+	{0xac28, 0x14},
+	{0xac29, 0x00},
+	{0xac2c, 0x14},
+	{0xac2d, 0x00},
+	{0xac34, 0x16},
+	{0xac35, 0x00},
+	{0xac38, 0x16},
+	{0xac39, 0x00},
+	{0xac3c, 0x16},
+	{0xac3d, 0x00},
+	{0xac40, 0x16},
+	{0xac41, 0x00},
+	{0xac44, 0x16},
+	{0xac45, 0x00},
+	{0xac48, 0x16},
+	{0xac49, 0x00},
+	{0xac50, 0x1b},
+	{0xac51, 0x00},
+	{0xac54, 0x1b},
+	{0xac55, 0x00},
+	{0xac58, 0x1b},
+	{0xac59, 0x00},
+	{0xac5c, 0x1b},
+	{0xac5d, 0x00},
+	{0xac60, 0x1b},
+	{0xac61, 0x00},
+	{0xac64, 0x1b},
+	{0xac65, 0x00},
+	{0xac74, 0x09},
+	{0xac75, 0x0c},
+	{0xac78, 0x0f},
+	{0xac79, 0x11},
+	{0xac7c, 0x12},
+	{0xac7d, 0x14},
+	{0xac80, 0x09},
+	{0xac81, 0x0c},
+	{0xac84, 0x0f},
+	{0xac85, 0x11},
+	{0xac88, 0x12},
+	{0xac89, 0x14},
+	{0xac8c, 0x09},
+	{0xac8d, 0x0c},
+	{0xac90, 0x0f},
+	{0xac91, 0x11},
+	{0xac94, 0x12},
+	{0xac95, 0x14},
+	{0xac98, 0x09},
+	{0xac99, 0x0c},
+	{0xac9c, 0x0f},
+	{0xac9d, 0x11},
+	{0xaca0, 0x12},
+	{0xaca1, 0x14},
+	{0xaca4, 0x09},
+	{0xaca5, 0x0c},
+	{0xaca8, 0x0f},
+	{0xaca9, 0x11},
+	{0xacac, 0x12},
+	{0xacad, 0x14},
+	{0xacb0, 0x07},
+	{0xacb1, 0x09},
+	{0xacb4, 0x0c},
+	{0xacb5, 0x0d},
+	{0xacb8, 0x0d},
+	{0xacb9, 0x0e},
+	{0xacbc, 0x05},
+	{0xacbd, 0x07},
+	{0xacc0, 0x0a},
+	{0xacc1, 0x0b},
+	{0xacc4, 0x0b},
+	{0xacc5, 0x0c},
+	{0xacc8, 0x03},
+	{0xacc9, 0x04},
+	{0xaccc, 0x07},
+	{0xaccd, 0x08},
+	{0xacd0, 0x09},
+	{0xacd1, 0x09}
+};
+
+static struct vx6953_i2c_reg_conf patch_tbl_cut3[] = {
+	{0xF800, 0x90},
+	{0xF801, 0x30},
+	{0xF802, 0x31},
+	{0xF803, 0xe0},
+	{0xF804, 0xf5},
+	{0xF805, 0x7d},
+	{0xF806, 0xb4},
+	{0xF807, 0x01},
+	{0xF808, 0x06},
+	{0xF809, 0x75},
+	{0xF80A, 0x7d},
+	{0xF80B, 0x03},
+	{0xF80C, 0x74},
+	{0xF80D, 0x03},
+	{0xF80E, 0xf0},
+	{0xF80F, 0x90},
+	{0xF810, 0x30},
+	{0xF811, 0x04},
+	{0xF812, 0x74},
+	{0xF813, 0x33},
+	{0xF814, 0xf0},
+	{0xF815, 0x90},
+	{0xF816, 0x30},
+	{0xF817, 0x06},
+	{0xF818, 0xe4},
+	{0xF819, 0xf0},
+	{0xF81A, 0xa3},
+	{0xF81B, 0x74},
+	{0xF81C, 0x09},
+	{0xF81D, 0xf0},
+	{0xF81E, 0x90},
+	{0xF81F, 0x30},
+	{0xF820, 0x10},
+	{0xF821, 0xe4},
+	{0xF822, 0xf0},
+	{0xF823, 0xa3},
+	{0xF824, 0xf0},
+	{0xF825, 0x90},
+	{0xF826, 0x30},
+	{0xF827, 0x16},
+	{0xF828, 0x74},
+	{0xF829, 0x1e},
+	{0xF82A, 0xf0},
+	{0xF82B, 0x90},
+	{0xF82C, 0x30},
+	{0xF82D, 0x1a},
+	{0xF82E, 0x74},
+	{0xF82F, 0x6a},
+	{0xF830, 0xf0},
+	{0xF831, 0xa3},
+	{0xF832, 0x74},
+	{0xF833, 0x29},
+	{0xF834, 0xf0},
+	{0xF835, 0x90},
+	{0xF836, 0x30},
+	{0xF837, 0x30},
+	{0xF838, 0x74},
+	{0xF839, 0x08},
+	{0xF83A, 0xf0},
+	{0xF83B, 0x90},
+	{0xF83C, 0x30},
+	{0xF83D, 0x36},
+	{0xF83E, 0x74},
+	{0xF83F, 0x2c},
+	{0xF840, 0xf0},
+	{0xF841, 0x90},
+	{0xF842, 0x30},
+	{0xF843, 0x41},
+	{0xF844, 0xe4},
+	{0xF845, 0xf0},
+	{0xF846, 0xa3},
+	{0xF847, 0x74},
+	{0xF848, 0x24},
+	{0xF849, 0xf0},
+	{0xF84A, 0x90},
+	{0xF84B, 0x30},
+	{0xF84C, 0x45},
+	{0xF84D, 0x74},
+	{0xF84E, 0x81},
+	{0xF84F, 0xf0},
+	{0xF850, 0x90},
+	{0xF851, 0x30},
+	{0xF852, 0x98},
+	{0xF853, 0x74},
+	{0xF854, 0x01},
+	{0xF855, 0xf0},
+	{0xF856, 0x90},
+	{0xF857, 0x30},
+	{0xF858, 0x9d},
+	{0xF859, 0x74},
+	{0xF85A, 0x05},
+	{0xF85B, 0xf0},
+	{0xF85C, 0xe5},
+	{0xF85D, 0x7d},
+	{0xF85E, 0x70},
+	{0xF85F, 0x10},
+	{0xF860, 0x90},
+	{0xF861, 0x30},
+	{0xF862, 0x05},
+	{0xF863, 0x04},
+	{0xF864, 0xf0},
+	{0xF865, 0x90},
+	{0xF866, 0x30},
+	{0xF867, 0x30},
+	{0xF868, 0xe4},
+	{0xF869, 0xf0},
+	{0xF86A, 0x90},
+	{0xF86B, 0x30},
+	{0xF86C, 0x35},
+	{0xF86D, 0x04},
+	{0xF86E, 0xf0},
+	{0xF86F, 0x22},
+	{0xF870, 0xe5},
+	{0xF871, 0x7d},
+	{0xF872, 0x64},
+	{0xF873, 0x02},
+	{0xF874, 0x70},
+	{0xF875, 0x2d},
+	{0xF876, 0x90},
+	{0xF877, 0x30},
+	{0xF878, 0x04},
+	{0xF879, 0x74},
+	{0xF87A, 0x34},
+	{0xF87B, 0xf0},
+	{0xF87C, 0xa3},
+	{0xF87D, 0x74},
+	{0xF87E, 0x07},
+	{0xF87F, 0xf0},
+	{0xF880, 0x90},
+	{0xF881, 0x30},
+	{0xF882, 0x10},
+	{0xF883, 0x74},
+	{0xF884, 0x10},
+	{0xF885, 0xf0},
+	{0xF886, 0x90},
+	{0xF887, 0x30},
+	{0xF888, 0x16},
+	{0xF889, 0x74},
+	{0xF88A, 0x1f},
+	{0xF88B, 0xf0},
+	{0xF88C, 0x90},
+	{0xF88D, 0x30},
+	{0xF88E, 0x1a},
+	{0xF88F, 0x74},
+	{0xF890, 0x62},
+	{0xF891, 0xf0},
+	{0xF892, 0x90},
+	{0xF893, 0x30},
+	{0xF894, 0x35},
+	{0xF895, 0x74},
+	{0xF896, 0x04},
+	{0xF897, 0xf0},
+	{0xF898, 0x90},
+	{0xF899, 0x30},
+	{0xF89A, 0x41},
+	{0xF89B, 0x74},
+	{0xF89C, 0x60},
+	{0xF89D, 0xf0},
+	{0xF89E, 0xa3},
+	{0xF89F, 0x74},
+	{0xF8A0, 0x64},
+	{0xF8A1, 0xf0},
+	{0xF8A2, 0x22},
+	{0xF8A3, 0xe5},
+	{0xF8A4, 0x7d},
+	{0xF8A5, 0xb4},
+	{0xF8A6, 0x03},
+	{0xF8A7, 0x12},
+	{0xF8A8, 0x90},
+	{0xF8A9, 0x30},
+	{0xF8AA, 0x05},
+	{0xF8AB, 0x74},
+	{0xF8AC, 0x03},
+	{0xF8AD, 0xf0},
+	{0xF8AE, 0x90},
+	{0xF8AF, 0x30},
+	{0xF8B0, 0x11},
+	{0xF8B1, 0x74},
+	{0xF8B2, 0x01},
+	{0xF8B3, 0xf0},
+	{0xF8B4, 0x90},
+	{0xF8B5, 0x30},
+	{0xF8B6, 0x35},
+	{0xF8B7, 0x74},
+	{0xF8B8, 0x03},
+	{0xF8B9, 0xf0},
+	{0xF8BA, 0x22},
+	{0xF8BB, 0xc3},
+	{0xF8BC, 0x90},
+	{0xF8BD, 0x0b},
+	{0xF8BE, 0x89},
+	{0xF8BF, 0xe0},
+	{0xF8C0, 0x94},
+	{0xF8C1, 0x1e},
+	{0xF8C2, 0x90},
+	{0xF8C3, 0x0b},
+	{0xF8C4, 0x88},
+	{0xF8C5, 0xe0},
+	{0xF8C6, 0x94},
+	{0xF8C7, 0x00},
+	{0xF8C8, 0x50},
+	{0xF8C9, 0x06},
+	{0xF8CA, 0x7e},
+	{0xF8CB, 0x00},
+	{0xF8CC, 0x7f},
+	{0xF8CD, 0x01},
+	{0xF8CE, 0x80},
+	{0xF8CF, 0x3d},
+	{0xF8D0, 0xc3},
+	{0xF8D1, 0x90},
+	{0xF8D2, 0x0b},
+	{0xF8D3, 0x89},
+	{0xF8D4, 0xe0},
+	{0xF8D5, 0x94},
+	{0xF8D6, 0x3c},
+	{0xF8D7, 0x90},
+	{0xF8D8, 0x0b},
+	{0xF8D9, 0x88},
+	{0xF8DA, 0xe0},
+	{0xF8DB, 0x94},
+	{0xF8DC, 0x00},
+	{0xF8DD, 0x50},
+	{0xF8DE, 0x06},
+	{0xF8DF, 0x7e},
+	{0xF8E0, 0x00},
+	{0xF8E1, 0x7f},
+	{0xF8E2, 0x02},
+	{0xF8E3, 0x80},
+	{0xF8E4, 0x28},
+	{0xF8E5, 0xc3},
+	{0xF8E6, 0x90},
+	{0xF8E7, 0x0b},
+	{0xF8E8, 0x89},
+	{0xF8E9, 0xe0},
+	{0xF8EA, 0x94},
+	{0xF8EB, 0xfa},
+	{0xF8EC, 0x90},
+	{0xF8ED, 0x0b},
+	{0xF8EE, 0x88},
+	{0xF8EF, 0xe0},
+	{0xF8F0, 0x94},
+	{0xF8F1, 0x00},
+	{0xF8F2, 0x50},
+	{0xF8F3, 0x06},
+	{0xF8F4, 0x7e},
+	{0xF8F5, 0x00},
+	{0xF8F6, 0x7f},
+	{0xF8F7, 0x03},
+	{0xF8F8, 0x80},
+	{0xF8F9, 0x13},
+	{0xF8FA, 0xc3},
+	{0xF8FB, 0x90},
+	{0xF8FC, 0x0b},
+	{0xF8FD, 0x88},
+	{0xF8FE, 0xe0},
+	{0xF8FF, 0x94},
+	{0xF900, 0x80},
+	{0xF901, 0x50},
+	{0xF902, 0x06},
+	{0xF903, 0x7e},
+	{0xF904, 0x00},
+	{0xF905, 0x7f},
+	{0xF906, 0x04},
+	{0xF907, 0x80},
+	{0xF908, 0x04},
+	{0xF909, 0xae},
+	{0xF90A, 0x7e},
+	{0xF90B, 0xaf},
+	{0xF90C, 0x7f},
+	{0xF90D, 0x90},
+	{0xF90E, 0xa0},
+	{0xF90F, 0xf8},
+	{0xF910, 0xee},
+	{0xF911, 0xf0},
+	{0xF912, 0xa3},
+	{0xF913, 0xef},
+	{0xF914, 0xf0},
+	{0xF915, 0x22},
+	{0xF916, 0x90},
+	{0xF917, 0x33},
+	{0xF918, 0x82},
+	{0xF919, 0xe0},
+	{0xF91A, 0xff},
+	{0xF91B, 0x64},
+	{0xF91C, 0x01},
+	{0xF91D, 0x70},
+	{0xF91E, 0x30},
+	{0xF91F, 0xe5},
+	{0xF920, 0x7f},
+	{0xF921, 0x64},
+	{0xF922, 0x02},
+	{0xF923, 0x45},
+	{0xF924, 0x7e},
+	{0xF925, 0x70},
+	{0xF926, 0x04},
+	{0xF927, 0x7d},
+	{0xF928, 0x1e},
+	{0xF929, 0x80},
+	{0xF92A, 0x1d},
+	{0xF92B, 0xe5},
+	{0xF92C, 0x7f},
+	{0xF92D, 0x64},
+	{0xF92E, 0x03},
+	{0xF92F, 0x45},
+	{0xF930, 0x7e},
+	{0xF931, 0x70},
+	{0xF932, 0x04},
+	{0xF933, 0x7d},
+	{0xF934, 0x3c},
+	{0xF935, 0x80},
+	{0xF936, 0x11},
+	{0xF937, 0xe5},
+	{0xF938, 0x7f},
+	{0xF939, 0x64},
+	{0xF93A, 0x04},
+	{0xF93B, 0x45},
+	{0xF93C, 0x7e},
+	{0xF93D, 0x70},
+	{0xF93E, 0x04},
+	{0xF93F, 0x7d},
+	{0xF940, 0xfa},
+	{0xF941, 0x80},
+	{0xF942, 0x05},
+	{0xF943, 0x90},
+	{0xF944, 0x33},
+	{0xF945, 0x81},
+	{0xF946, 0xe0},
+	{0xF947, 0xfd},
+	{0xF948, 0xae},
+	{0xF949, 0x05},
+	{0xF94A, 0x90},
+	{0xF94B, 0x33},
+	{0xF94C, 0x81},
+	{0xF94D, 0xed},
+	{0xF94E, 0xf0},
+	{0xF94F, 0xef},
+	{0xF950, 0xb4},
+	{0xF951, 0x01},
+	{0xF952, 0x10},
+	{0xF953, 0x90},
+	{0xF954, 0x01},
+	{0xF955, 0x00},
+	{0xF956, 0xe0},
+	{0xF957, 0x60},
+	{0xF958, 0x0a},
+	{0xF959, 0x90},
+	{0xF95A, 0xa1},
+	{0xF95B, 0x10},
+	{0xF95C, 0xe0},
+	{0xF95D, 0xf5},
+	{0xF95E, 0x7e},
+	{0xF95F, 0xa3},
+	{0xF960, 0xe0},
+	{0xF961, 0xf5},
+	{0xF962, 0x7f},
+	{0xF963, 0x22},
+	{0xF964, 0x12},
+	{0xF965, 0x2f},
+	{0xF966, 0x4d},
+	{0xF967, 0x90},
+	{0xF968, 0x35},
+	{0xF969, 0x38},
+	{0xF96A, 0xe0},
+	{0xF96B, 0x70},
+	{0xF96C, 0x05},
+	{0xF96D, 0x12},
+	{0xF96E, 0x00},
+	{0xF96F, 0x0e},
+	{0xF970, 0x80},
+	{0xF971, 0x03},
+	{0xF972, 0x12},
+	{0xF973, 0x07},
+	{0xF974, 0xc9},
+	{0xF975, 0x90},
+	{0xF976, 0x40},
+	{0xF977, 0x06},
+	{0xF978, 0xe0},
+	{0xF979, 0xf4},
+	{0xF97A, 0x54},
+	{0xF97B, 0x02},
+	{0xF97C, 0xff},
+	{0xF97D, 0xe0},
+	{0xF97E, 0x54},
+	{0xF97F, 0x01},
+	{0xF980, 0x4f},
+	{0xF981, 0x90},
+	{0xF982, 0x31},
+	{0xF983, 0x32},
+	{0xF984, 0xf0},
+	{0xF985, 0x90},
+	{0xF986, 0xfa},
+	{0xF987, 0x9d},
+	{0xF988, 0xe0},
+	{0xF989, 0x70},
+	{0xF98A, 0x03},
+	{0xF98B, 0x12},
+	{0xF98C, 0x27},
+	{0xF98D, 0x27},
+	{0xF98E, 0x02},
+	{0xF98F, 0x05},
+	{0xF990, 0xac},
+	{0xF991, 0x22},
+	{0xF992, 0x78},
+	{0xF993, 0x07},
+	{0xF994, 0xe6},
+	{0xF995, 0xf5},
+	{0xF996, 0x7c},
+	{0xF997, 0xe5},
+	{0xF998, 0x7c},
+	{0xF999, 0x60},
+	{0xF99A, 0x1d},
+	{0xF99B, 0x90},
+	{0xF99C, 0x43},
+	{0xF99D, 0x83},
+	{0xF99E, 0xe0},
+	{0xF99F, 0xb4},
+	{0xF9A0, 0x01},
+	{0xF9A1, 0x16},
+	{0xF9A2, 0x90},
+	{0xF9A3, 0x43},
+	{0xF9A4, 0x87},
+	{0xF9A5, 0xe0},
+	{0xF9A6, 0xb4},
+	{0xF9A7, 0x01},
+	{0xF9A8, 0x0f},
+	{0xF9A9, 0x15},
+	{0xF9AA, 0x7c},
+	{0xF9AB, 0x90},
+	{0xF9AC, 0x30},
+	{0xF9AD, 0xa1},
+	{0xF9AE, 0xe5},
+	{0xF9AF, 0x7c},
+	{0xF9B0, 0xf0},
+	{0xF9B1, 0x90},
+	{0xF9B2, 0x30},
+	{0xF9B3, 0xa0},
+	{0xF9B4, 0x74},
+	{0xF9B5, 0x01},
+	{0xF9B6, 0xf0},
+	{0xF9B7, 0x22},
+	{0xF9B8, 0xe4},
+	{0xF9B9, 0x90},
+	{0xF9BA, 0x30},
+	{0xF9BB, 0xa0},
+	{0xF9BC, 0xf0},
+	{0xF9BD, 0x22},
+	{0xF9BE, 0xf0},
+	{0xF9BF, 0xe5},
+	{0xF9C0, 0x3a},
+	{0xF9C1, 0xb4},
+	{0xF9C2, 0x06},
+	{0xF9C3, 0x06},
+	{0xF9C4, 0x63},
+	{0xF9C5, 0x3e},
+	{0xF9C6, 0x02},
+	{0xF9C7, 0x12},
+	{0xF9C8, 0x03},
+	{0xF9C9, 0xea},
+	{0xF9CA, 0x02},
+	{0xF9CB, 0x17},
+	{0xF9CC, 0x4a},
+	{0xF9CD, 0x22},
+	{0x35C9, 0xBB},
+	{0x35CA, 0x01},
+	{0x35CB, 0x16},
+	{0x35CC, 0x01},
+	{0x35CD, 0x64},
+	{0x35CE, 0x01},
+	{0x35CF, 0x92},
+	{0x35D0, 0x01},
+	{0x35D1, 0xBE},
+	{0x35D3, 0xF6},
+	{0x35D5, 0x07},
+	{0x35D7, 0xA3},
+	{0x35DB, 0x02},
+	{0x35DD, 0x06},
+	{0x35DF, 0x1B},
+	{0x35E6, 0x28},
+	{0x35E7, 0x76},
+	{0x35E8, 0x2D},
+	{0x35E9, 0x07},
+	{0x35EA, 0x04},
+	{0x35EB, 0x43},
+	{0x35EC, 0x05},
+	{0x35ED, 0xA9},
+	{0x35EE, 0x2A},
+	{0x35EF, 0x15},
+	{0x35F0, 0x17},
+	{0x35F1, 0x41},
+	{0x35F2, 0x24},
+	{0x35F3, 0x88},
+	{0x35F4, 0x01},
+	{0x35F5, 0x54},
+	{0x35F6, 0x01},
+	{0x35F7, 0x55},
+	{0x35F8, 0x2E},
+	{0x35F9, 0xF2},
+	{0x35FA, 0x06},
+	{0x35FB, 0x02},
+	{0x35FC, 0x06},
+	{0x35FD, 0x03},
+	{0x35FE, 0x06},
+	{0x35FF, 0x04},
+	{0x35C2, 0x1F},
+	{0x35C3, 0xFF},
+	{0x35C4, 0x1F},
+	{0x35C5, 0xC0},
+	{0x35C0, 0x01},
+};
+
+struct vx6953_format {
+	enum v4l2_mbus_pixelcode code;
+	enum v4l2_colorspace colorspace;
+	u16 fmt;
+	u16 order;
+};
+
+static const struct vx6953_format vx6953_cfmts[] = {
+	{
+	.code   = V4L2_MBUS_FMT_YUYV8_2X8,
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	.fmt    = 1,
+	.order    = 0,
+	}
+	/* more can be supported, to be added later */
+};
+
+
+/*=============================================================*/
+
+static int vx6953_i2c_rxdata(unsigned short saddr,
+	unsigned char *rxdata, int length)
+{
+	struct i2c_msg msgs[] = {
+		{
+			.addr  = saddr,
+			.flags = 0,
+			.len   = 2,
+			.buf   = rxdata,
+		},
+		{
+			.addr  = saddr,
+			.flags = I2C_M_RD,
+			.len   = 2,
+			.buf   = rxdata,
+		},
+	};
+	if (i2c_transfer(vx6953_client->adapter, msgs, 2) < 0) {
+		CDBG("vx6953_i2c_rxdata failed!\n");
+		return -EIO;
+	}
+	return 0;
+}
+static int32_t vx6953_i2c_txdata(unsigned short saddr,
+				unsigned char *txdata, int length)
+{
+	struct i2c_msg msg[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = length,
+			.buf = txdata,
+		 },
+	};
+	if (i2c_transfer(vx6953_client->adapter, msg, 1) < 0) {
+		CDBG("vx6953_i2c_txdata faild 0x%x\n", vx6953_client->addr);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+
+static int32_t vx6953_i2c_read(unsigned short raddr,
+	unsigned short *rdata, int rlen)
+{
+	int32_t rc = 0;
+	unsigned char buf[2];
+	if (!rdata)
+		return -EIO;
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (raddr & 0xFF00) >> 8;
+	buf[1] = (raddr & 0x00FF);
+	rc = vx6953_i2c_rxdata(vx6953_client->addr>>1, buf, rlen);
+	if (rc < 0) {
+		CDBG("vx6953_i2c_read 0x%x failed!\n", raddr);
+		return rc;
+	}
+	*rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]);
+	return rc;
+}
+static int32_t vx6953_i2c_write_b_sensor(unsigned short waddr, uint8_t bdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[3];
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	buf[2] = bdata;
+	CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata);
+	rc = vx6953_i2c_txdata(vx6953_client->addr>>1, buf, 3);
+	if (rc < 0) {
+		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+			waddr, bdata);
+	}
+	return rc;
+}
+static int32_t vx6953_i2c_write_seq_sensor(unsigned short waddr,
+	uint8_t *bdata, uint16_t len)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[len+2];
+	int i;
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (waddr & 0xFF00) >> 8;
+	buf[1] = (waddr & 0x00FF);
+	for (i = 2; i < len+2; i++)
+		buf[i] = *bdata++;
+	rc = vx6953_i2c_txdata(vx6953_client->addr>>1, buf, len+2);
+	if (rc < 0) {
+		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+			 waddr, bdata[0]);
+	}
+	return rc;
+}
+
+static int32_t vx6953_i2c_write_w_table(struct vx6953_i2c_reg_conf const
+					 *reg_conf_tbl, int num)
+{
+	int i;
+	int32_t rc = -EIO;
+	for (i = 0; i < num; i++) {
+		rc = vx6953_i2c_write_b_sensor(reg_conf_tbl->waddr,
+			reg_conf_tbl->wdata);
+		if (rc < 0)
+			break;
+		reg_conf_tbl++;
+	}
+	return rc;
+}
+
+static void vx6953_get_pict_fps(uint16_t fps, uint16_t *pfps)
+{
+	/* input fps is preview fps in Q8 format */
+	uint16_t preview_frame_length_lines, snapshot_frame_length_lines;
+	uint16_t preview_line_length_pck, snapshot_line_length_pck;
+	uint32_t divider, d1, d2;
+	/* Total frame_length_lines and line_length_pck for preview */
+	preview_frame_length_lines = VX6953_QTR_SIZE_HEIGHT +
+		VX6953_VER_QTR_BLK_LINES;
+	preview_line_length_pck = VX6953_QTR_SIZE_WIDTH +
+		VX6953_HRZ_QTR_BLK_PIXELS;
+	/* Total frame_length_lines and line_length_pck for snapshot */
+	snapshot_frame_length_lines = VX6953_FULL_SIZE_HEIGHT +
+		VX6953_VER_FULL_BLK_LINES;
+	snapshot_line_length_pck = VX6953_FULL_SIZE_WIDTH +
+		VX6953_HRZ_FULL_BLK_PIXELS;
+	d1 = preview_frame_length_lines * 0x00000400/
+		snapshot_frame_length_lines;
+	d2 = preview_line_length_pck * 0x00000400/
+		snapshot_line_length_pck;
+	divider = d1 * d2 / 0x400;
+	/*Verify PCLK settings and frame sizes.*/
+	*pfps = (uint16_t) (fps * divider / 0x400);
+	/* 2 is the ratio of no.of snapshot channels
+	to number of preview channels */
+
+}
+
+static uint16_t vx6953_get_prev_lines_pf(void)
+{
+	if (vx6953_ctrl->prev_res == QTR_SIZE)
+		return VX6953_QTR_SIZE_HEIGHT + VX6953_VER_QTR_BLK_LINES;
+	else
+		return VX6953_FULL_SIZE_HEIGHT + VX6953_VER_FULL_BLK_LINES;
+
+}
+
+static uint16_t vx6953_get_prev_pixels_pl(void)
+{
+	if (vx6953_ctrl->prev_res == QTR_SIZE)
+		return VX6953_QTR_SIZE_WIDTH + VX6953_HRZ_QTR_BLK_PIXELS;
+	else
+		return VX6953_FULL_SIZE_WIDTH + VX6953_HRZ_FULL_BLK_PIXELS;
+}
+
+static uint16_t vx6953_get_pict_lines_pf(void)
+{
+		if (vx6953_ctrl->pict_res == QTR_SIZE)
+			return VX6953_QTR_SIZE_HEIGHT +
+				VX6953_VER_QTR_BLK_LINES;
+		else
+			return VX6953_FULL_SIZE_HEIGHT +
+				VX6953_VER_FULL_BLK_LINES;
+}
+
+static uint16_t vx6953_get_pict_pixels_pl(void)
+{
+	if (vx6953_ctrl->pict_res == QTR_SIZE)
+		return VX6953_QTR_SIZE_WIDTH +
+			VX6953_HRZ_QTR_BLK_PIXELS;
+	else
+		return VX6953_FULL_SIZE_WIDTH +
+			VX6953_HRZ_FULL_BLK_PIXELS;
+}
+
+static uint32_t vx6953_get_pict_max_exp_lc(void)
+{
+	if (vx6953_ctrl->pict_res == QTR_SIZE)
+		return (VX6953_QTR_SIZE_HEIGHT +
+			VX6953_VER_QTR_BLK_LINES)*24;
+	else
+		return (VX6953_FULL_SIZE_HEIGHT +
+			VX6953_VER_FULL_BLK_LINES)*24;
+}
+
+static int32_t vx6953_set_fps(struct fps_cfg	*fps)
+{
+	uint16_t total_lines_per_frame;
+	int32_t rc = 0;
+	total_lines_per_frame = (uint16_t)((VX6953_QTR_SIZE_HEIGHT +
+		VX6953_VER_QTR_BLK_LINES) * vx6953_ctrl->fps_divider/0x400);
+	if (vx6953_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_HI,
+		((total_lines_per_frame & 0xFF00) >> 8)) < 0)
+		return rc;
+	if (vx6953_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_LO,
+		(total_lines_per_frame & 0x00FF)) < 0)
+		return rc;
+	return rc;
+}
+
+static int32_t vx6953_write_exp_gain(uint16_t gain, uint32_t line)
+{
+	uint16_t line_length_pck, frame_length_lines;
+	uint8_t gain_hi, gain_lo;
+	uint8_t intg_time_hi, intg_time_lo;
+	uint8_t line_length_pck_hi = 0, line_length_pck_lo = 0;
+	uint16_t line_length_ratio = 1 * Q8;
+	int32_t rc = 0;
+	if (vx6953_ctrl->sensormode != SENSOR_SNAPSHOT_MODE) {
+		frame_length_lines = VX6953_QTR_SIZE_HEIGHT +
+		VX6953_VER_QTR_BLK_LINES;
+		line_length_pck = VX6953_QTR_SIZE_WIDTH +
+			VX6953_HRZ_QTR_BLK_PIXELS;
+		if (line > (frame_length_lines -
+			VX6953_STM5M0EDOF_OFFSET)) {
+			vx6953_ctrl->fps = (uint16_t) (30 * Q8 *
+			(frame_length_lines - VX6953_STM5M0EDOF_OFFSET)/
+			line);
+		} else {
+			vx6953_ctrl->fps = (uint16_t) (30 * Q8);
+		}
+	} else {
+		frame_length_lines = VX6953_FULL_SIZE_HEIGHT +
+				VX6953_VER_FULL_BLK_LINES;
+		line_length_pck = VX6953_FULL_SIZE_WIDTH +
+				VX6953_HRZ_FULL_BLK_PIXELS;
+	}
+	/* calculate line_length_ratio */
+	if ((frame_length_lines - VX6953_STM5M0EDOF_OFFSET) < line) {
+		line_length_ratio = (line*Q8) /
+			(frame_length_lines - VX6953_STM5M0EDOF_OFFSET);
+		line = frame_length_lines - VX6953_STM5M0EDOF_OFFSET;
+	} else {
+		line_length_ratio = 1*Q8;
+	}
+	vx6953_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
+		GROUPED_PARAMETER_HOLD);
+	line_length_pck = (line_length_pck >
+		MAX_LINE_LENGTH_PCK) ?
+		MAX_LINE_LENGTH_PCK : line_length_pck;
+	line_length_pck = (uint16_t) (line_length_pck *
+		line_length_ratio/Q8);
+	line_length_pck_hi = (uint8_t) ((line_length_pck &
+		0xFF00) >> 8);
+	line_length_pck_lo = (uint8_t) (line_length_pck &
+		0x00FF);
+	vx6953_i2c_write_b_sensor(REG_LINE_LENGTH_PCK_HI,
+		line_length_pck_hi);
+	vx6953_i2c_write_b_sensor(REG_LINE_LENGTH_PCK_LO,
+		line_length_pck_lo);
+	/* update analogue gain registers */
+	gain_hi = (uint8_t) ((gain & 0xFF00) >> 8);
+	gain_lo = (uint8_t) (gain & 0x00FF);
+	vx6953_i2c_write_b_sensor(REG_ANALOGUE_GAIN_CODE_GLOBAL_LO,
+		gain_lo);
+	vx6953_i2c_write_b_sensor(REG_DIGITAL_GAIN_GREEN_R_LO, gain_hi);
+	vx6953_i2c_write_b_sensor(REG_DIGITAL_GAIN_RED_LO, gain_hi);
+	vx6953_i2c_write_b_sensor(REG_DIGITAL_GAIN_BLUE_LO, gain_hi);
+	vx6953_i2c_write_b_sensor(REG_DIGITAL_GAIN_GREEN_B_LO, gain_hi);
+	CDBG("%s, gain_hi 0x%x, gain_lo 0x%x\n", __func__,
+		gain_hi, gain_lo);
+	/* update line count registers */
+	intg_time_hi = (uint8_t) (((uint16_t)line & 0xFF00) >> 8);
+	intg_time_lo = (uint8_t) ((uint16_t)line & 0x00FF);
+	vx6953_i2c_write_b_sensor(REG_COARSE_INTEGRATION_TIME_HI,
+		intg_time_hi);
+	vx6953_i2c_write_b_sensor(REG_COARSE_INTEGRATION_TIME_LO,
+		intg_time_lo);
+	vx6953_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
+		GROUPED_PARAMETER_HOLD_OFF);
+
+	return rc;
+}
+
+static int32_t vx6953_set_pict_exp_gain(uint16_t gain, uint32_t line)
+{
+	int32_t rc = 0;
+	rc = vx6953_write_exp_gain(gain, line);
+	return rc;
+} /* endof vx6953_set_pict_exp_gain*/
+
+static int32_t vx6953_move_focus(int direction,
+	int32_t num_steps)
+{
+	return 0;
+}
+
+
+static int32_t vx6953_set_default_focus(uint8_t af_step)
+{
+	return 0;
+}
+
+static int32_t vx6953_test(enum vx6953_test_mode_t mo)
+{
+	int32_t rc = 0;
+	if (mo == TEST_OFF)
+		return rc;
+	else {
+		/* REG_0x30D8[4] is TESBYPEN: 0: Normal Operation,
+		1: Bypass Signal Processing
+		REG_0x30D8[5] is EBDMASK: 0:
+		Output Embedded data, 1: No output embedded data */
+		if (vx6953_i2c_write_b_sensor(REG_TEST_PATTERN_MODE,
+			(uint8_t) mo) < 0) {
+			return rc;
+		}
+	}
+	return rc;
+}
+
+static int vx6953_enable_edof(enum edof_mode_t edof_mode)
+{
+	int rc = 0;
+	if (edof_mode == VX6953_EDOF_ESTIMATION) {
+		/* EDof Estimation mode for preview */
+		if (vx6953_i2c_write_b_sensor(REG_0x0b80, 0x02) < 0)
+			return rc;
+		CDBG("VX6953_EDOF_ESTIMATION");
+	} else if (edof_mode == VX6953_EDOF_APPLICATION) {
+		/* EDof Application mode for Capture */
+		if (vx6953_i2c_write_b_sensor(REG_0x0b80, 0x01) < 0)
+			return rc;
+		CDBG("VX6953_EDOF_APPLICATION");
+	} else {
+		/* EDOF disabled */
+		if (vx6953_i2c_write_b_sensor(REG_0x0b80, 0x00) < 0)
+			return rc;
+		CDBG("VX6953_EDOF_DISABLE");
+	}
+	return rc;
+}
+
+static int32_t vx6953_patch_for_cut2(void)
+{
+	int32_t rc = 0;
+	rc = vx6953_i2c_write_w_table(patch_tbl_cut2,
+		ARRAY_SIZE(patch_tbl_cut2));
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+static int32_t vx6953_patch_for_cut3(void)
+{
+	int32_t rc = 0;
+	rc = vx6953_i2c_write_w_table(patch_tbl_cut3,
+		ARRAY_SIZE(patch_tbl_cut3));
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+static int32_t vx6953_sensor_setting(int update_type, int rt)
+{
+
+	int32_t rc = 0;
+	unsigned short frame_cnt;
+	struct msm_camera_csi_params vx6953_csi_params;
+	if (vx6953_ctrl->sensor_type != VX6953_STM5M0EDOF_CUT_2) {
+		switch (update_type) {
+		case REG_INIT:
+		if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+			struct vx6953_i2c_reg_conf init_tbl[] = {
+			{REG_0x0112,
+				vx6953_regs.reg_pat_init[0].reg_0x0112},
+			{0x6003, 0x01},
+			{REG_0x0113,
+				vx6953_regs.reg_pat_init[0].reg_0x0113},
+			{REG_VT_PIX_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				vt_pix_clk_div},
+			{REG_PRE_PLL_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				pre_pll_clk_div},
+			{REG_PLL_MULTIPLIER,
+				vx6953_regs.reg_pat_init[0].
+				pll_multiplier},
+			{REG_OP_PIX_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				op_pix_clk_div},
+			{REG_COARSE_INTEGRATION_TIME_HI,
+				vx6953_regs.reg_pat[rt].
+				coarse_integration_time_hi},
+			{REG_COARSE_INTEGRATION_TIME_LO,
+				vx6953_regs.reg_pat[rt].
+				coarse_integration_time_lo},
+			{REG_ANALOGUE_GAIN_CODE_GLOBAL_LO,
+				vx6953_regs.reg_pat[rt].
+				analogue_gain_code_global},
+			{REG_0x3030,
+				vx6953_regs.reg_pat_init[0].reg_0x3030},
+			/* 953 specific registers */
+			{REG_0x0111,
+				vx6953_regs.reg_pat_init[0].reg_0x0111},
+			{REG_0x0b00,
+				vx6953_regs.reg_pat_init[0].reg_0x0b00},
+			{REG_0x3001,
+				vx6953_regs.reg_pat_init[0].reg_0x3001},
+			{REG_0x3004,
+				vx6953_regs.reg_pat_init[0].reg_0x3004},
+			{0x3006, 0x00},
+			{REG_0x3007,
+				vx6953_regs.reg_pat_init[0].reg_0x3007},
+			{0x301b, 0x29},
+			/* DEFCOR settings */
+			/*Single Defect Correction Weight DISABLE*/
+			{0x0b06,
+				vx6953_regs.reg_pat_init[0].reg_0x0b06},
+			/*Single_defect_correct_weight = auto*/
+			{0x0b07,
+				vx6953_regs.reg_pat_init[0].reg_0x0b07},
+			/*Dynamic couplet correction ENABLED*/
+			{0x0b08,
+				vx6953_regs.reg_pat_init[0].reg_0x0b08},
+			/*Dynamic couplet correction weight*/
+			{0x0b09,
+				vx6953_regs.reg_pat_init[0].reg_0x0b09},
+			/* Clock Setup */
+			/* Tell sensor ext clk is 24MHz*/
+			{REG_0x0136,
+				vx6953_regs.reg_pat_init[0].reg_0x0136},
+			{REG_0x0137,
+				vx6953_regs.reg_pat_init[0].reg_0x0137},
+			/* The white balance gains must be written
+			to the sensor every frame. */
+			/* Edof */
+			{REG_0x0b83,
+				vx6953_regs.reg_pat_init[0].reg_0x0b83},
+			{REG_0x0b84,
+				vx6953_regs.reg_pat_init[0].reg_0x0b84},
+			{REG_0x0b85,
+				vx6953_regs.reg_pat_init[0].reg_0x0b85},
+			{REG_0x0b88,
+				vx6953_regs.reg_pat_init[0].reg_0x0b88},
+			{REG_0x0b89,
+				vx6953_regs.reg_pat_init[0].reg_0x0b89},
+			{REG_0x0b8a,
+				vx6953_regs.reg_pat_init[0].reg_0x0b8a},
+			/* Mode specific regieters */
+			{REG_FRAME_LENGTH_LINES_HI,
+				vx6953_regs.reg_pat[rt].
+				frame_length_lines_hi},
+			{REG_FRAME_LENGTH_LINES_LO,
+				vx6953_regs.reg_pat[rt].
+				frame_length_lines_lo},
+			{REG_LINE_LENGTH_PCK_HI,
+				vx6953_regs.reg_pat[rt].
+				line_length_pck_hi},
+			{REG_LINE_LENGTH_PCK_LO,
+				vx6953_regs.reg_pat[rt].
+				line_length_pck_lo},
+			{REG_0x3005,
+				vx6953_regs.reg_pat[rt].reg_0x3005},
+			{0x3010,
+				vx6953_regs.reg_pat[rt].reg_0x3010},
+			{REG_0x3011,
+				vx6953_regs.reg_pat[rt].reg_0x3011},
+			{REG_0x301a,
+				vx6953_regs.reg_pat[rt].reg_0x301a},
+			{REG_0x3035,
+				vx6953_regs.reg_pat[rt].reg_0x3035},
+			{REG_0x3036,
+				vx6953_regs.reg_pat[rt].reg_0x3036},
+			{REG_0x3041,
+				vx6953_regs.reg_pat[rt].reg_0x3041},
+			{0x3042,
+				vx6953_regs.reg_pat[rt].reg_0x3042},
+			{REG_0x3045,
+				vx6953_regs.reg_pat[rt].reg_0x3045},
+			/*EDOF: Estimation settings for Preview mode
+			Application settings for capture mode
+			(standard settings - Not tuned) */
+			{REG_0x0b80,
+				vx6953_regs.reg_pat[rt].reg_0x0b80},
+			{REG_0x0900,
+				vx6953_regs.reg_pat[rt].reg_0x0900},
+			{REG_0x0901,
+				vx6953_regs.reg_pat[rt].reg_0x0901},
+			{REG_0x0902,
+				vx6953_regs.reg_pat[rt].reg_0x0902},
+			{REG_0x0383,
+				vx6953_regs.reg_pat[rt].reg_0x0383},
+			{REG_0x0387,
+				vx6953_regs.reg_pat[rt].reg_0x0387},
+			/* Change output size / frame rate */
+			{REG_0x034c,
+				vx6953_regs.reg_pat[rt].reg_0x034c},
+			{REG_0x034d,
+				vx6953_regs.reg_pat[rt].reg_0x034d},
+			{REG_0x034e,
+				vx6953_regs.reg_pat[rt].reg_0x034e},
+			{REG_0x034f,
+				vx6953_regs.reg_pat[rt].reg_0x034f},
+			};
+			/* reset fps_divider */
+			vx6953_ctrl->fps = 30 * Q8;
+			/* stop streaming */
+
+			/* Reset everything first */
+			if (vx6953_i2c_write_b_sensor(0x103, 0x01) < 0) {
+				CDBG("S/W reset failed\n");
+				return rc;
+			} else
+				CDBG("S/W reset successful\n");
+
+			msleep(10);
+
+			CDBG("Init vx6953_sensor_setting standby\n");
+			if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT,
+				MODE_SELECT_STANDBY_MODE) < 0)
+				return rc;
+			/*vx6953_stm5m0edof_delay_msecs_stdby*/
+			msleep(vx6953_stm5m0edof_delay_msecs_stdby);
+
+
+
+			vx6953_patch_for_cut3();
+			rc = vx6953_i2c_write_w_table(&init_tbl[0],
+				ARRAY_SIZE(init_tbl));
+			if (rc < 0)
+				return rc;
+
+			msleep(vx6953_stm5m0edof_delay_msecs_stdby);
+
+			vx6953_i2c_write_b_sensor(0x0b80, 0x00);
+			vx6953_i2c_write_b_sensor(0x3388, 0x03);
+			vx6953_i2c_write_b_sensor(0x3640, 0x00);
+
+			rc = vx6953_i2c_write_w_table(&edof_tbl[0],
+				ARRAY_SIZE(edof_tbl));
+			vx6953_i2c_write_b_sensor(0x3388, 0x00);
+
+		}
+		return rc;
+		case UPDATE_PERIODIC:
+		if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+			struct vx6953_i2c_reg_conf preview_mode_tbl[] = {
+			{REG_0x0112,
+				vx6953_regs.reg_pat_init[0].reg_0x0112},
+			{0x6003, 0x01},
+			{REG_0x0113,
+				vx6953_regs.reg_pat_init[0].reg_0x0113},
+			{REG_VT_PIX_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				vt_pix_clk_div},
+			{REG_PRE_PLL_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				pre_pll_clk_div},
+			{REG_PLL_MULTIPLIER,
+				vx6953_regs.reg_pat_init[0].
+				pll_multiplier},
+			{REG_OP_PIX_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				op_pix_clk_div},
+
+			{REG_COARSE_INTEGRATION_TIME_HI,
+				vx6953_regs.reg_pat[rt].
+				coarse_integration_time_hi},
+			{REG_COARSE_INTEGRATION_TIME_LO,
+				vx6953_regs.reg_pat[rt].
+				coarse_integration_time_lo},
+			{REG_ANALOGUE_GAIN_CODE_GLOBAL_LO,
+				vx6953_regs.reg_pat[rt].
+				analogue_gain_code_global},
+
+			{REG_0x3210, vx6953_regs.reg_pat[rt].reg_0x3210},
+			{REG_0x0111, vx6953_regs.reg_pat[rt].reg_0x111},
+			{REG_0x3410, vx6953_regs.reg_pat[rt].reg_0x3410},
+
+			{REG_0x3004,
+				vx6953_regs.reg_pat_init[0].reg_0x3004},
+			{REG_0x3006, 0x00},
+			{REG_0x3007,
+				vx6953_regs.reg_pat_init[0].reg_0x3007},
+			{REG_0x301b, 0x29},
+			{REG_0x3036,
+				vx6953_regs.reg_pat[rt].reg_0x3036},
+			{REG_0x3045, vx6953_regs.reg_pat[rt].reg_0x3045},
+			{REG_0x3098, vx6953_regs.reg_pat[rt].reg_0x3098},
+			{REG_0x309d, vx6953_regs.reg_pat[rt].reg_0x309D},
+
+			{REG_0x0900, vx6953_regs.reg_pat[rt].reg_0x0900},
+			{REG_0x0901, vx6953_regs.reg_pat[rt].reg_0x0901},
+			{REG_0x0902, vx6953_regs.reg_pat[rt].reg_0x0902},
+			{REG_0x0383, vx6953_regs.reg_pat[rt].reg_0x0383},
+			{REG_0x0387, vx6953_regs.reg_pat[rt].reg_0x0387},
+
+			{REG_FRAME_LENGTH_LINES_HI,
+				vx6953_regs.reg_pat[rt].
+				frame_length_lines_hi},
+			{REG_FRAME_LENGTH_LINES_LO,
+				vx6953_regs.reg_pat[rt].
+				frame_length_lines_lo},
+			{REG_LINE_LENGTH_PCK_HI,
+				vx6953_regs.reg_pat[rt].
+				line_length_pck_hi},
+			{REG_LINE_LENGTH_PCK_LO,
+				vx6953_regs.reg_pat[rt].
+				line_length_pck_lo},
+			{REG_0x034c,
+				vx6953_regs.reg_pat[rt].reg_0x034c},
+			{REG_0x034d,
+				vx6953_regs.reg_pat[rt].reg_0x034d},
+			{REG_0x034e,
+				vx6953_regs.reg_pat[rt].reg_0x034e},
+			{REG_0x034f,
+				vx6953_regs.reg_pat[rt].reg_0x034f},
+
+			{REG_0x3005, vx6953_regs.reg_pat[rt].reg_0x3005},
+			{REG_0x3010, vx6953_regs.reg_pat[rt].reg_0x3010},
+			{REG_0x3011, vx6953_regs.reg_pat[rt].reg_0x3011},
+			{REG_0x301a, vx6953_regs.reg_pat[rt].reg_0x301a},
+			{REG_0x3030, 0x08},
+			{REG_0x3035, vx6953_regs.reg_pat[rt].reg_0x3035},
+			{REG_0x3041, vx6953_regs.reg_pat[rt].reg_0x3041},
+			{0x3042, vx6953_regs.reg_pat[rt].reg_0x3042},
+
+			{0x200, vx6953_regs.reg_pat[rt].reg_0x0200},
+			{0x201, vx6953_regs.reg_pat[rt].reg_0x0201},
+
+			{0x0b06,
+				vx6953_regs.reg_pat_init[0].reg_0x0b06},
+			/*Single_defect_correct_weight = auto*/
+			{0x0b07,
+				vx6953_regs.reg_pat_init[0].reg_0x0b07},
+			/*Dynamic couplet correction ENABLED*/
+			{0x0b08,
+				vx6953_regs.reg_pat_init[0].reg_0x0b08},
+			/*Dynamic couplet correction weight*/
+			{0x0b09,
+				vx6953_regs.reg_pat_init[0].reg_0x0b09},
+
+			{REG_0x0136,
+				vx6953_regs.reg_pat_init[0].reg_0x0136},
+			{REG_0x0137,
+				vx6953_regs.reg_pat_init[0].reg_0x0137},
+
+			/*EDOF: Estimation settings for Preview mode
+			Application settings for capture
+			mode(standard settings - Not tuned) */
+			{REG_0x0b80, vx6953_regs.reg_pat[rt].reg_0x0b80},
+			{REG_0x0b83,
+				vx6953_regs.reg_pat_init[0].reg_0x0b83},
+			{REG_0x0b84,
+				vx6953_regs.reg_pat_init[0].reg_0x0b84},
+			{REG_0x0b85,
+				vx6953_regs.reg_pat_init[0].reg_0x0b85},
+			{REG_0x0b88,
+				vx6953_regs.reg_pat_init[0].reg_0x0b88},
+			{REG_0x0b89,
+				vx6953_regs.reg_pat_init[0].reg_0x0b89},
+			{REG_0x0b8a,
+				vx6953_regs.reg_pat_init[0].reg_0x0b8a},
+			{0x3393, 0x06}, /* man_spec_edof_ctrl_edof*/
+			{0x3394, 0x07}, /* man_spec_edof_ctrl_edof*/
+			};
+
+			struct vx6953_i2c_reg_conf snapshot_mode_tbl[] = {
+			{REG_MODE_SELECT,	MODE_SELECT_STANDBY_MODE},
+			{REG_0x0112,
+				vx6953_regs.reg_pat_init[0].reg_0x0112},
+			{0x6003, 0x01},
+			{REG_0x0113,
+				vx6953_regs.reg_pat_init[0].reg_0x0113},
+			{REG_VT_PIX_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				vt_pix_clk_div},
+			{0x303,	1}, /* VT_SYS_CLK_DIV */
+			{REG_PRE_PLL_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				pre_pll_clk_div},
+			{REG_PLL_MULTIPLIER,
+				vx6953_regs.reg_pat_init[0].
+				pll_multiplier},
+			{REG_OP_PIX_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				op_pix_clk_div},
+			{0x30b,	1},
+			{REG_COARSE_INTEGRATION_TIME_HI,
+				vx6953_regs.reg_pat[rt].
+				coarse_integration_time_hi},
+			{REG_COARSE_INTEGRATION_TIME_LO,
+				vx6953_regs.reg_pat[rt].
+				coarse_integration_time_lo},
+			{REG_ANALOGUE_GAIN_CODE_GLOBAL_LO,
+				vx6953_regs.reg_pat[rt].
+				analogue_gain_code_global},
+			{REG_LINE_LENGTH_PCK_HI,
+				vx6953_regs.reg_pat[rt].
+				line_length_pck_hi},
+			{REG_LINE_LENGTH_PCK_LO,
+				vx6953_regs.reg_pat[rt].
+				line_length_pck_lo},
+			{REG_FRAME_LENGTH_LINES_HI,
+				vx6953_regs.reg_pat[rt].
+				frame_length_lines_hi},
+			{REG_FRAME_LENGTH_LINES_LO,
+				vx6953_regs.reg_pat[rt].
+				frame_length_lines_lo},
+			{REG_0x3210, vx6953_regs.reg_pat[rt].reg_0x3210},
+			{REG_0x0111, vx6953_regs.reg_pat[rt].reg_0x111},
+
+			{REG_0x0b00,
+				vx6953_regs.reg_pat_init[0].reg_0x0b00},
+			{0x3140, 0x01},  /* AV2X2 block enabled */
+			{REG_0x3410, vx6953_regs.reg_pat[rt].reg_0x3410},
+			{0x0b06,
+				vx6953_regs.reg_pat_init[0].reg_0x0b06},
+			/*Single_defect_correct_weight = auto*/
+			{0x0b07,
+				vx6953_regs.reg_pat_init[0].reg_0x0b07},
+			/*Dynamic couplet correction ENABLED*/
+			{0x0b08,
+				vx6953_regs.reg_pat_init[0].reg_0x0b08},
+			/*Dynamic couplet correction weight*/
+			{0x0b09,
+				vx6953_regs.reg_pat_init[0].reg_0x0b09},
+
+
+			{REG_0x3004,
+				vx6953_regs.reg_pat_init[0].reg_0x3004},
+			{REG_0x3006, 0x00},
+			{REG_0x3007,
+				vx6953_regs.reg_pat_init[0].reg_0x3007},
+			{0x301A, 0x6A},
+			{REG_0x301b, 0x29},
+			{REG_0x3036,
+				vx6953_regs.reg_pat[rt].reg_0x3036},
+			{REG_0x3045, vx6953_regs.reg_pat[rt].reg_0x3045},
+			{REG_0x3098, vx6953_regs.reg_pat[rt].reg_0x3098},
+			{REG_0x309d, vx6953_regs.reg_pat[rt].reg_0x309D},
+
+			{REG_0x0136,
+				vx6953_regs.reg_pat_init[0].reg_0x0136},
+			{REG_0x0137,
+				vx6953_regs.reg_pat_init[0].reg_0x0137},
+
+			{REG_0x0b80, vx6953_regs.reg_pat[rt].reg_0x0b80},
+			{REG_0x0b83,
+				vx6953_regs.reg_pat_init[0].reg_0x0b83},
+			{REG_0x0b84,
+				vx6953_regs.reg_pat_init[0].reg_0x0b84},
+			{REG_0x0b85,
+				vx6953_regs.reg_pat_init[0].reg_0x0b85},
+			{REG_0x0b88,
+				vx6953_regs.reg_pat_init[0].reg_0x0b88},
+			{REG_0x0b89,
+				vx6953_regs.reg_pat_init[0].reg_0x0b89},
+			{REG_0x0b8a,
+				vx6953_regs.reg_pat_init[0].reg_0x0b8a},
+			{0x3393, 0x06}, /* man_spec_edof_ctrl*/
+			{0x3394, 0x07}, /* man_spec_edof_ctrl*/
+			};
+			/* stop streaming */
+			msleep(5);
+
+			/* Reset everything first */
+
+			if (vx6953_i2c_write_b_sensor(0x103, 0x01) < 0) {
+				CDBG("S/W reset failed\n");
+				return rc;
+			} else
+				CDBG("S/W reset successful\n");
+
+			msleep(10);
+
+			if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT,
+				MODE_SELECT_STANDBY_MODE) < 0)
+				return rc;
+			/*vx6953_stm5m0edof_delay_msecs_stdby*/
+			msleep(vx6953_stm5m0edof_delay_msecs_stdby);
+
+			vx6953_csi_params.data_format = CSI_8BIT;
+			vx6953_csi_params.lane_cnt = 1;
+			vx6953_csi_params.lane_assign = 0xe4;
+			vx6953_csi_params.dpcm_scheme = 0;
+			vx6953_csi_params.settle_cnt = 7;
+			rc = msm_camio_csi_config(&vx6953_csi_params);
+			if (rc < 0)
+				CDBG(" config csi controller failed\n");
+
+			msleep(vx6953_stm5m0edof_delay_msecs_stdby);
+
+			vx6953_patch_for_cut3();
+
+			msleep(vx6953_stm5m0edof_delay_msecs_stdby);
+
+			if (rt == RES_PREVIEW) {
+				rc = vx6953_i2c_write_w_table(
+					&preview_mode_tbl[0],
+					ARRAY_SIZE(preview_mode_tbl));
+				if (rc < 0)
+					return rc;
+			}
+			if (rt == RES_CAPTURE) {
+				rc = vx6953_i2c_write_w_table(
+					&snapshot_mode_tbl[0],
+					ARRAY_SIZE(snapshot_mode_tbl));
+				if (rc < 0)
+					return rc;
+			}
+			msleep(vx6953_stm5m0edof_delay_msecs_stdby);
+
+			/* Start sensor streaming */
+			if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT,
+				MODE_SELECT_STREAM) < 0)
+				return rc;
+			msleep(vx6953_stm5m0edof_delay_msecs_stream);
+			/* man_spec_edof_ctrl_tune_smooth_lowlight*/
+			vx6953_i2c_write_b_sensor(0x338d, 0x08);
+			/* man_spec_edof_ctrl_tune_smooth_indoor*/
+			vx6953_i2c_write_b_sensor(0x338e, 0x08);
+			/* man_spec_edof_ctrl_tune_smooth_outdoor*/
+			vx6953_i2c_write_b_sensor(0x338f, 0x00);
+			/*Apply Capture FPGA state machine reset*/
+			vx6953_i2c_write_b_sensor(0x16, 0x00);
+			msleep(100);
+			vx6953_i2c_write_b_sensor(0x16, 0x01);
+
+			if (vx6953_i2c_read(0x0005, &frame_cnt, 1) < 0)
+				return rc;
+
+			while (frame_cnt == 0xFF) {
+				if (vx6953_i2c_read(0x0005, &frame_cnt, 1) < 0)
+					return rc;
+				CDBG("frame_cnt=%d", frame_cnt);
+				msleep(10);
+			}
+		}
+		return rc;
+		default:
+			return rc;
+		}
+	} else {
+		switch (update_type) {
+		case REG_INIT:
+		if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+			struct vx6953_i2c_reg_conf init_tbl[] = {
+			{REG_0x0112,
+				vx6953_regs.reg_pat_init[0].reg_0x0112},
+			{REG_0x0113,
+				vx6953_regs.reg_pat_init[0].reg_0x0113},
+			{REG_VT_PIX_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				vt_pix_clk_div},
+			{REG_PRE_PLL_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				pre_pll_clk_div},
+			{REG_PLL_MULTIPLIER,
+				vx6953_regs.reg_pat_init[0].
+				pll_multiplier},
+			{REG_OP_PIX_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				op_pix_clk_div},
+			{REG_COARSE_INTEGRATION_TIME_HI,
+				vx6953_regs.reg_pat[rt].
+				coarse_integration_time_hi},
+			{REG_COARSE_INTEGRATION_TIME_LO,
+				vx6953_regs.reg_pat[rt].
+				coarse_integration_time_lo},
+			{REG_ANALOGUE_GAIN_CODE_GLOBAL_LO,
+				vx6953_regs.reg_pat[rt].
+				analogue_gain_code_global},
+			{REG_0x3030,
+				vx6953_regs.reg_pat_init[0].reg_0x3030},
+			/* 953 specific registers */
+			{REG_0x0111,
+				vx6953_regs.reg_pat_init[0].reg_0x0111},
+			{REG_0x0b00,
+				vx6953_regs.reg_pat_init[0].reg_0x0b00},
+			{REG_0x3001,
+				vx6953_regs.reg_pat_init[0].reg_0x3001},
+			{REG_0x3004,
+				vx6953_regs.reg_pat_init[0].reg_0x3004},
+			{REG_0x3007,
+				vx6953_regs.reg_pat_init[0].reg_0x3007},
+			{REG_0x3016,
+				vx6953_regs.reg_pat_init[0].reg_0x3016},
+			{REG_0x301d,
+				vx6953_regs.reg_pat_init[0].reg_0x301d},
+			{REG_0x317e,
+				vx6953_regs.reg_pat_init[0].reg_0x317e},
+			{REG_0x317f,
+				vx6953_regs.reg_pat_init[0].reg_0x317f},
+			{REG_0x3400,
+				vx6953_regs.reg_pat_init[0].reg_0x3400},
+			/* DEFCOR settings */
+			/*Single Defect Correction Weight DISABLE*/
+			{0x0b06,
+				vx6953_regs.reg_pat_init[0].reg_0x0b06},
+			/*Single_defect_correct_weight = auto*/
+			{0x0b07,
+				vx6953_regs.reg_pat_init[0].reg_0x0b07},
+			/*Dynamic couplet correction ENABLED*/
+			{0x0b08,
+				vx6953_regs.reg_pat_init[0].reg_0x0b08},
+			/*Dynamic couplet correction weight*/
+			{0x0b09,
+				vx6953_regs.reg_pat_init[0].reg_0x0b09},
+			/* Clock Setup */
+			/* Tell sensor ext clk is 24MHz*/
+			{0x0136,
+				vx6953_regs.reg_pat_init[0].reg_0x0136},
+			{0x0137,
+				vx6953_regs.reg_pat_init[0].reg_0x0137},
+			/* The white balance gains must be written
+			to the sensor every frame. */
+			/* Edof */
+			{REG_0x0b83,
+				vx6953_regs.reg_pat_init[0].reg_0x0b83},
+			{REG_0x0b84,
+				vx6953_regs.reg_pat_init[0].reg_0x0b84},
+			{0x0b85,
+				vx6953_regs.reg_pat_init[0].reg_0x0b85},
+			{0x0b88,
+				vx6953_regs.reg_pat_init[0].reg_0x0b88},
+			{0x0b89,
+				vx6953_regs.reg_pat_init[0].reg_0x0b89},
+			{REG_0x0b8a,
+				vx6953_regs.reg_pat_init[0].reg_0x0b8a},
+			/* Mode specific regieters */
+			{REG_FRAME_LENGTH_LINES_HI,
+				vx6953_regs.reg_pat[rt].
+				frame_length_lines_hi},
+			{REG_FRAME_LENGTH_LINES_LO,
+				vx6953_regs.reg_pat[rt].
+				frame_length_lines_lo},
+			{REG_LINE_LENGTH_PCK_HI,
+				vx6953_regs.reg_pat[rt].
+				line_length_pck_hi},
+			{REG_LINE_LENGTH_PCK_LO,
+				vx6953_regs.reg_pat[rt].
+				line_length_pck_lo},
+			{REG_0x3005,
+				vx6953_regs.reg_pat[rt].reg_0x3005},
+			{0x3010,
+				vx6953_regs.reg_pat[rt].reg_0x3010},
+			{REG_0x3011,
+				vx6953_regs.reg_pat[rt].reg_0x3011},
+			{REG_0x301a,
+				vx6953_regs.reg_pat[rt].reg_0x301a},
+			{REG_0x3035,
+				vx6953_regs.reg_pat[rt].reg_0x3035},
+			{REG_0x3036,
+				vx6953_regs.reg_pat[rt].reg_0x3036},
+			{REG_0x3041,
+				vx6953_regs.reg_pat[rt].reg_0x3041},
+			{0x3042,
+				vx6953_regs.reg_pat[rt].reg_0x3042},
+			{REG_0x3045,
+				vx6953_regs.reg_pat[rt].reg_0x3045},
+			/*EDOF: Estimation settings for Preview mode
+			Application settings for capture mode
+			(standard settings - Not tuned) */
+			{REG_0x0b80,
+				vx6953_regs.reg_pat[rt].reg_0x0b80},
+			{REG_0x0900,
+				vx6953_regs.reg_pat[rt].reg_0x0900},
+			{REG_0x0901,
+				vx6953_regs.reg_pat[rt].reg_0x0901},
+			{REG_0x0902,
+				vx6953_regs.reg_pat[rt].reg_0x0902},
+			{REG_0x0383,
+				vx6953_regs.reg_pat[rt].reg_0x0383},
+			{REG_0x0387,
+				vx6953_regs.reg_pat[rt].reg_0x0387},
+			/* Change output size / frame rate */
+			{REG_0x034c,
+				vx6953_regs.reg_pat[rt].reg_0x034c},
+			{REG_0x034d,
+				vx6953_regs.reg_pat[rt].reg_0x034d},
+			{REG_0x034e,
+				vx6953_regs.reg_pat[rt].reg_0x034e},
+			{REG_0x034f,
+				vx6953_regs.reg_pat[rt].reg_0x034f},
+			{REG_0x1716,
+				vx6953_regs.reg_pat[rt].reg_0x1716},
+			{REG_0x1717,
+				vx6953_regs.reg_pat[rt].reg_0x1717},
+			{REG_0x1718,
+				vx6953_regs.reg_pat[rt].reg_0x1718},
+			{REG_0x1719,
+				vx6953_regs.reg_pat[rt].reg_0x1719},
+			};
+			/* reset fps_divider */
+			vx6953_ctrl->fps = 30 * Q8;
+			/* stop streaming */
+
+			/* Reset everything first */
+			if (vx6953_i2c_write_b_sensor(0x103, 0x01) < 0) {
+				CDBG("S/W reset failed\n");
+				return rc;
+			} else
+				CDBG("S/W reset successful\n");
+
+			msleep(10);
+
+			CDBG("Init vx6953_sensor_setting standby\n");
+			if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT,
+				MODE_SELECT_STANDBY_MODE) < 0)
+				return rc;
+				/*vx6953_stm5m0edof_delay_msecs_stdby*/
+			msleep(vx6953_stm5m0edof_delay_msecs_stdby);
+			vx6953_patch_for_cut2();
+			rc = vx6953_i2c_write_w_table(&init_tbl[0],
+				ARRAY_SIZE(init_tbl));
+			if (rc < 0)
+				return rc;
+				msleep(vx6953_stm5m0edof_delay_msecs_stdby);
+		}
+		return rc;
+		case UPDATE_PERIODIC:
+		if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+			struct vx6953_i2c_reg_conf init_mode_tbl[] =  {
+			{REG_0x0112,
+				vx6953_regs.reg_pat_init[0].reg_0x0112},
+			{REG_0x0113,
+				vx6953_regs.reg_pat_init[0].reg_0x0113},
+			{REG_VT_PIX_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				vt_pix_clk_div},
+			{REG_PRE_PLL_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				pre_pll_clk_div},
+			{REG_PLL_MULTIPLIER,
+				vx6953_regs.reg_pat_init[0].
+				pll_multiplier},
+			{REG_OP_PIX_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				op_pix_clk_div},
+			{REG_COARSE_INTEGRATION_TIME_HI,
+				vx6953_regs.reg_pat[rt].
+				coarse_integration_time_hi},
+			{REG_COARSE_INTEGRATION_TIME_LO,
+				vx6953_regs.reg_pat[rt].
+				coarse_integration_time_lo},
+			{REG_ANALOGUE_GAIN_CODE_GLOBAL_LO,
+				vx6953_regs.reg_pat[rt].
+				analogue_gain_code_global},
+			{REG_0x3030,
+				vx6953_regs.reg_pat_init[0].reg_0x3030},
+			/* 953 specific registers */
+			{REG_0x0111,
+				vx6953_regs.reg_pat_init[0].reg_0x0111},
+			{REG_0x0b00,
+				vx6953_regs.reg_pat_init[0].reg_0x0b00},
+			{REG_0x3001,
+				vx6953_regs.reg_pat_init[0].reg_0x3001},
+			{REG_0x3004,
+				vx6953_regs.reg_pat_init[0].reg_0x3004},
+			{REG_0x3007,
+				vx6953_regs.reg_pat_init[0].reg_0x3007},
+			{REG_0x3016,
+				vx6953_regs.reg_pat_init[0].reg_0x3016},
+			{REG_0x301d,
+				vx6953_regs.reg_pat_init[0].reg_0x301d},
+			{REG_0x317e,
+				vx6953_regs.reg_pat_init[0].reg_0x317e},
+			{REG_0x317f,
+				vx6953_regs.reg_pat_init[0].reg_0x317f},
+			{REG_0x3400,
+				vx6953_regs.reg_pat_init[0].reg_0x3400},
+			{0x0b06,
+				vx6953_regs.reg_pat_init[0].reg_0x0b06},
+			/*Single_defect_correct_weight = auto*/
+			{0x0b07,
+				vx6953_regs.reg_pat_init[0].reg_0x0b07},
+			/*Dynamic couplet correction ENABLED*/
+			{0x0b08,
+				vx6953_regs.reg_pat_init[0].reg_0x0b08},
+			/*Dynamic couplet correction weight*/
+			{0x0b09,
+				vx6953_regs.reg_pat_init[0].reg_0x0b09},
+			/* Clock Setup */
+			/* Tell sensor ext clk is 24MHz*/
+			{0x0136,
+				vx6953_regs.reg_pat_init[0].reg_0x0136},
+			{0x0137,
+				vx6953_regs.reg_pat_init[0].reg_0x0137},
+			/* The white balance gains must be written
+			to the sensor every frame. */
+			/* Edof */
+			{REG_0x0b83,
+				vx6953_regs.reg_pat_init[0].reg_0x0b83},
+			{REG_0x0b84,
+				vx6953_regs.reg_pat_init[0].reg_0x0b84},
+			{0x0b85,
+				vx6953_regs.reg_pat_init[0].reg_0x0b85},
+			{0x0b88,
+				vx6953_regs.reg_pat_init[0].reg_0x0b88},
+			{0x0b89,
+				vx6953_regs.reg_pat_init[0].reg_0x0b89},
+			{REG_0x0b8a,
+				vx6953_regs.reg_pat_init[0].reg_0x0b8a},
+			/* Mode specific regieters */
+			{REG_FRAME_LENGTH_LINES_HI,
+				vx6953_regs.reg_pat[rt].
+				frame_length_lines_hi},
+			{REG_FRAME_LENGTH_LINES_LO,
+				vx6953_regs.reg_pat[rt].
+				frame_length_lines_lo},
+			{REG_LINE_LENGTH_PCK_HI,
+				vx6953_regs.reg_pat[rt].
+				line_length_pck_hi},
+			{REG_LINE_LENGTH_PCK_LO,
+				vx6953_regs.reg_pat[rt].
+				line_length_pck_lo},
+			{REG_0x3005,
+				vx6953_regs.reg_pat[rt].reg_0x3005},
+			{0x3010,
+				vx6953_regs.reg_pat[rt].reg_0x3010},
+			{REG_0x3011,
+				vx6953_regs.reg_pat[rt].reg_0x3011},
+			{REG_0x301a,
+				vx6953_regs.reg_pat[rt].reg_0x301a},
+			{REG_0x3035,
+				vx6953_regs.reg_pat[rt].reg_0x3035},
+			{REG_0x3036,
+				vx6953_regs.reg_pat[rt].reg_0x3036},
+			{REG_0x3041,
+				vx6953_regs.reg_pat[rt].reg_0x3041},
+			{0x3042,
+				vx6953_regs.reg_pat[rt].reg_0x3042},
+			{REG_0x3045,
+				vx6953_regs.reg_pat[rt].reg_0x3045},
+			/*EDOF: Estimation settings for Preview mode
+			Application settings for capture mode
+			(standard settings - Not tuned) */
+			{REG_0x0b80,
+				vx6953_regs.reg_pat[rt].reg_0x0b80},
+			{REG_0x0900,
+				vx6953_regs.reg_pat[rt].reg_0x0900},
+			{REG_0x0901,
+				vx6953_regs.reg_pat[rt].reg_0x0901},
+			{REG_0x0902,
+				vx6953_regs.reg_pat[rt].reg_0x0902},
+			{REG_0x0383,
+				vx6953_regs.reg_pat[rt].reg_0x0383},
+			{REG_0x0387,
+				vx6953_regs.reg_pat[rt].reg_0x0387},
+			/* Change output size / frame rate */
+			{REG_0x034c,
+				vx6953_regs.reg_pat[rt].reg_0x034c},
+			{REG_0x034d,
+				vx6953_regs.reg_pat[rt].reg_0x034d},
+			{REG_0x034e,
+				vx6953_regs.reg_pat[rt].reg_0x034e},
+			{REG_0x034f,
+				vx6953_regs.reg_pat[rt].reg_0x034f},
+			{REG_0x1716,
+				vx6953_regs.reg_pat[rt].reg_0x1716},
+			{REG_0x1717,
+				vx6953_regs.reg_pat[rt].reg_0x1717},
+			{REG_0x1718,
+				vx6953_regs.reg_pat[rt].reg_0x1718},
+			{REG_0x1719,
+				vx6953_regs.reg_pat[rt].reg_0x1719},
+			};
+			struct vx6953_i2c_reg_conf mode_tbl[] = {
+			{REG_0x0112,
+				vx6953_regs.reg_pat_init[0].reg_0x0112},
+			{REG_0x0113,
+				vx6953_regs.reg_pat_init[0].reg_0x0113},
+			{REG_VT_PIX_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				vt_pix_clk_div},
+			{REG_PRE_PLL_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				pre_pll_clk_div},
+			{REG_PLL_MULTIPLIER,
+				vx6953_regs.reg_pat_init[0].
+				pll_multiplier},
+			{REG_OP_PIX_CLK_DIV,
+				vx6953_regs.reg_pat_init[0].
+				op_pix_clk_div},
+		/* Mode specific regieters */
+			{REG_FRAME_LENGTH_LINES_HI,
+				vx6953_regs.reg_pat[rt].frame_length_lines_hi},
+			{REG_FRAME_LENGTH_LINES_LO,
+				vx6953_regs.reg_pat[rt].frame_length_lines_lo},
+			{REG_LINE_LENGTH_PCK_HI,
+				vx6953_regs.reg_pat[rt].line_length_pck_hi},
+			{REG_LINE_LENGTH_PCK_LO,
+				vx6953_regs.reg_pat[rt].line_length_pck_lo},
+			{REG_0x3005, vx6953_regs.reg_pat[rt].reg_0x3005},
+			{0x3010, vx6953_regs.reg_pat[rt].reg_0x3010},
+			{REG_0x3011, vx6953_regs.reg_pat[rt].reg_0x3011},
+			{REG_0x301a, vx6953_regs.reg_pat[rt].reg_0x301a},
+			{REG_0x3035, vx6953_regs.reg_pat[rt].reg_0x3035},
+			{REG_0x3036, vx6953_regs.reg_pat[rt].reg_0x3036},
+			{REG_0x3041, vx6953_regs.reg_pat[rt].reg_0x3041},
+			{0x3042, vx6953_regs.reg_pat[rt].reg_0x3042},
+			{REG_0x3045, vx6953_regs.reg_pat[rt].reg_0x3045},
+			/*EDOF: Estimation settings for Preview mode
+			Application settings for capture
+			mode(standard settings - Not tuned) */
+			{REG_0x0b80, vx6953_regs.reg_pat[rt].reg_0x0b80},
+			{REG_0x0900, vx6953_regs.reg_pat[rt].reg_0x0900},
+			{REG_0x0901, vx6953_regs.reg_pat[rt].reg_0x0901},
+			{REG_0x0902, vx6953_regs.reg_pat[rt].reg_0x0902},
+			{REG_0x0383, vx6953_regs.reg_pat[rt].reg_0x0383},
+			{REG_0x0387, vx6953_regs.reg_pat[rt].reg_0x0387},
+			/* Change output size / frame rate */
+			{REG_0x034c, vx6953_regs.reg_pat[rt].reg_0x034c},
+			{REG_0x034d, vx6953_regs.reg_pat[rt].reg_0x034d},
+			{REG_0x034e, vx6953_regs.reg_pat[rt].reg_0x034e},
+			{REG_0x034f, vx6953_regs.reg_pat[rt].reg_0x034f},
+			/*{0x200, vx6953_regs.reg_pat[rt].reg_0x0200},
+			{0x201, vx6953_regs.reg_pat[rt].reg_0x0201},*/
+			{REG_0x1716, vx6953_regs.reg_pat[rt].reg_0x1716},
+			{REG_0x1717, vx6953_regs.reg_pat[rt].reg_0x1717},
+			{REG_0x1718, vx6953_regs.reg_pat[rt].reg_0x1718},
+			{REG_0x1719, vx6953_regs.reg_pat[rt].reg_0x1719},
+			};
+			/* stop streaming */
+			msleep(5);
+
+			/* Reset everything first */
+			if (vx6953_i2c_write_b_sensor(0x103, 0x01) < 0) {
+				CDBG("S/W reset failed\n");
+				return rc;
+			} else
+				CDBG("S/W reset successful\n");
+
+			msleep(10);
+
+			if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT,
+				MODE_SELECT_STANDBY_MODE) < 0)
+				return rc;
+			/*vx6953_stm5m0edof_delay_msecs_stdby*/
+			msleep(vx6953_stm5m0edof_delay_msecs_stdby);
+
+			vx6953_csi_params.data_format = CSI_8BIT;
+			vx6953_csi_params.lane_cnt = 1;
+			vx6953_csi_params.lane_assign = 0xe4;
+			vx6953_csi_params.dpcm_scheme = 0;
+			vx6953_csi_params.settle_cnt = 7;
+			rc = msm_camio_csi_config(&vx6953_csi_params);
+			if (rc < 0)
+				CDBG(" config csi controller failed\n");
+
+			msleep(vx6953_stm5m0edof_delay_msecs_stdby);
+
+			vx6953_patch_for_cut2();
+			rc = vx6953_i2c_write_w_table(&init_mode_tbl[0],
+				ARRAY_SIZE(init_mode_tbl));
+			if (rc < 0)
+				return rc;
+
+			msleep(vx6953_stm5m0edof_delay_msecs_stdby);
+
+			rc = vx6953_i2c_write_w_table(&mode_tbl[0],
+				ARRAY_SIZE(mode_tbl));
+			if (rc < 0)
+				return rc;
+
+			msleep(vx6953_stm5m0edof_delay_msecs_stdby);
+
+			/* Start sensor streaming */
+			if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT,
+				MODE_SELECT_STREAM) < 0)
+				return rc;
+			msleep(vx6953_stm5m0edof_delay_msecs_stream);
+
+			if (vx6953_i2c_read(0x0005, &frame_cnt, 1) < 0)
+				return rc;
+
+			while (frame_cnt == 0xFF) {
+				if (vx6953_i2c_read(0x0005, &frame_cnt, 1) < 0)
+					return rc;
+				CDBG("frame_cnt=%d", frame_cnt);
+				msleep(10);
+			}
+		}
+		return rc;
+		default:
+		return rc;
+	}
+	}
+	return rc;
+}
+
+
+static int32_t vx6953_video_config(int mode)
+{
+
+	int32_t	rc = 0;
+	int	rt;
+	/* change sensor resolution	if needed */
+	if (vx6953_ctrl->prev_res == QTR_SIZE) {
+		rt = RES_PREVIEW;
+		vx6953_stm5m0edof_delay_msecs_stdby	=
+			((((2 * 1000 * vx6953_ctrl->fps_divider) /
+			vx6953_ctrl->fps) * Q8) / Q10) + 1;
+	} else {
+		rt = RES_CAPTURE;
+		vx6953_stm5m0edof_delay_msecs_stdby	=
+			((((1000 * vx6953_ctrl->fps_divider) /
+			vx6953_ctrl->fps) * Q8) / Q10) + 1;
+	}
+	if (vx6953_sensor_setting(UPDATE_PERIODIC, rt) < 0)
+		return rc;
+	if (vx6953_ctrl->set_test) {
+		if (vx6953_test(vx6953_ctrl->set_test) < 0)
+			return	rc;
+	}
+	vx6953_ctrl->edof_mode = VX6953_EDOF_ESTIMATION;
+	rc = vx6953_enable_edof(vx6953_ctrl->edof_mode);
+	if (rc < 0)
+		return rc;
+	vx6953_ctrl->curr_res = vx6953_ctrl->prev_res;
+	vx6953_ctrl->sensormode = mode;
+	return rc;
+}
+
+static int32_t vx6953_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+	int rt;
+	/*change sensor resolution if needed */
+	if (vx6953_ctrl->curr_res != vx6953_ctrl->pict_res) {
+		if (vx6953_ctrl->pict_res == QTR_SIZE) {
+			rt = RES_PREVIEW;
+			vx6953_stm5m0edof_delay_msecs_stdby =
+				((((2 * 1000 * vx6953_ctrl->fps_divider) /
+				vx6953_ctrl->fps) * Q8) / Q10) + 1;
+		} else {
+			rt = RES_CAPTURE;
+			vx6953_stm5m0edof_delay_msecs_stdby =
+				((((1000 * vx6953_ctrl->fps_divider) /
+				vx6953_ctrl->fps) * Q8) / Q10) + 1;
+		}
+	if (vx6953_sensor_setting(UPDATE_PERIODIC, rt) < 0)
+		return rc;
+	}
+
+	vx6953_ctrl->edof_mode = VX6953_EDOF_APPLICATION;
+	if (vx6953_enable_edof(vx6953_ctrl->edof_mode) < 0)
+		return rc;
+	vx6953_ctrl->curr_res = vx6953_ctrl->pict_res;
+	vx6953_ctrl->sensormode = mode;
+	return rc;
+} /*end of vx6953_snapshot_config*/
+
+static int32_t vx6953_raw_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+	int rt;
+	/* change sensor resolution if needed */
+	if (vx6953_ctrl->curr_res != vx6953_ctrl->pict_res) {
+		if (vx6953_ctrl->pict_res == QTR_SIZE) {
+			rt = RES_PREVIEW;
+			vx6953_stm5m0edof_delay_msecs_stdby =
+				((((2 * 1000 * vx6953_ctrl->fps_divider)/
+				vx6953_ctrl->fps) * Q8) / Q10) + 1;
+		} else {
+			rt = RES_CAPTURE;
+			vx6953_stm5m0edof_delay_msecs_stdby =
+				((((1000 * vx6953_ctrl->fps_divider)/
+				vx6953_ctrl->fps) * Q8) / Q10) + 1;
+		}
+		if (vx6953_sensor_setting(UPDATE_PERIODIC, rt) < 0)
+			return rc;
+	}
+	vx6953_ctrl->edof_mode = VX6953_EDOF_APPLICATION;
+	if (vx6953_enable_edof(vx6953_ctrl->edof_mode) < 0)
+		return rc;
+	vx6953_ctrl->curr_res = vx6953_ctrl->pict_res;
+	vx6953_ctrl->sensormode = mode;
+	return rc;
+} /*end of vx6953_raw_snapshot_config*/
+static int32_t vx6953_set_sensor_mode(int mode,
+	int res)
+{
+	int32_t rc = 0;
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		rc = vx6953_video_config(mode);
+		break;
+	case SENSOR_SNAPSHOT_MODE:
+		rc = vx6953_snapshot_config(mode);
+		break;
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		rc = vx6953_raw_snapshot_config(mode);
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+static int32_t vx6953_power_down(void)
+{
+	vx6953_i2c_write_b_sensor(REG_MODE_SELECT,
+	MODE_SELECT_STANDBY_MODE);
+	return 0;
+}
+
+
+static int vx6953_probe_init_done(const struct msm_camera_sensor_info *data)
+{
+	gpio_free(data->sensor_reset);
+	kfree(vx6953_ctrl);
+	vx6953_ctrl = NULL;
+	return 0;
+}
+static int vx6953_probe_init_sensor(const struct msm_camera_sensor_info *data)
+{
+	unsigned short revision_number;
+	int32_t rc = 0;
+	unsigned short chipidl, chipidh;
+	CDBG("%s: %d\n", __func__, __LINE__);
+	rc = gpio_request(data->sensor_reset, "vx6953");
+	CDBG(" vx6953_probe_init_sensor\n");
+	if (!rc) {
+		CDBG("sensor_reset = %d\n", rc);
+		CDBG(" vx6953_probe_init_sensor 1\n");
+		gpio_direction_output(data->sensor_reset, 0);
+		msleep(50);
+		CDBG(" vx6953_probe_init_sensor 1\n");
+		gpio_direction_output(data->sensor_reset, 1);
+		msleep(13);
+	} else {
+		CDBG(" vx6953_probe_init_sensor 2\n");
+		goto init_probe_done;
+	}
+	msleep(20);
+	CDBG(" vx6953_probe_init_sensor is called\n");
+	/* 3. Read sensor Model ID: */
+	rc = vx6953_i2c_read(0x0000, &chipidh, 1);
+	if (rc < 0) {
+		CDBG(" vx6953_probe_init_sensor 3\n");
+		goto init_probe_fail;
+	}
+	rc = vx6953_i2c_read(0x0001, &chipidl, 1);
+	if (rc < 0) {
+		CDBG(" vx6953_probe_init_sensor4\n");
+		goto init_probe_fail;
+	}
+	CDBG("vx6953 model_id = 0x%x  0x%x\n", chipidh, chipidl);
+	/* 4. Compare sensor ID to VX6953 ID: */
+	if (chipidh != 0x03 || chipidl != 0xB9) {
+		rc = -ENODEV;
+		CDBG("vx6953_probe_init_sensor fail chip id doesnot match\n");
+		goto init_probe_fail;
+	}
+
+	vx6953_ctrl = kzalloc(sizeof(struct vx6953_ctrl_t), GFP_KERNEL);
+	if (!vx6953_ctrl) {
+		CDBG("vx6953_init failed!\n");
+		rc = -ENOMEM;
+	}
+	vx6953_ctrl->fps_divider = 1 * 0x00000400;
+	vx6953_ctrl->pict_fps_divider = 1 * 0x00000400;
+	vx6953_ctrl->set_test = TEST_OFF;
+	vx6953_ctrl->prev_res = QTR_SIZE;
+	vx6953_ctrl->pict_res = FULL_SIZE;
+	vx6953_ctrl->curr_res = INVALID_SIZE;
+	vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_2;
+	vx6953_ctrl->edof_mode = VX6953_EDOF_ESTIMATION;
+
+	if (data)
+		vx6953_ctrl->sensordata = data;
+
+	if (vx6953_i2c_read(0x0002, &revision_number, 1) < 0)
+		return rc;
+		CDBG("sensor revision number major = 0x%x\n", revision_number);
+	if (vx6953_i2c_read(0x0018, &revision_number, 1) < 0)
+		return rc;
+		CDBG("sensor revision number = 0x%x\n", revision_number);
+	if (revision_number == VX6953_REVISION_NUMBER_CUT3) {
+		vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_3;
+		CDBG("VX6953 EDof Cut 3.0 sensor\n ");
+	} else if (revision_number == VX6953_REVISION_NUMBER_CUT2) {
+		vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_2;
+		CDBG("VX6953 EDof Cut 2.0 sensor\n ");
+	} else {/* Cut1.0 reads 0x00 for register 0x0018*/
+		vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_1;
+		CDBG("VX6953 EDof Cut 1.0 sensor\n ");
+	}
+
+	if (vx6953_ctrl->prev_res == QTR_SIZE) {
+		if (vx6953_sensor_setting(REG_INIT, RES_PREVIEW) < 0)
+			goto init_probe_fail;
+	} else {
+		if (vx6953_sensor_setting(REG_INIT, RES_CAPTURE) < 0)
+			goto init_probe_fail;
+	}
+
+	goto init_probe_done;
+init_probe_fail:
+	CDBG(" vx6953_probe_init_sensor fails\n");
+	gpio_direction_output(data->sensor_reset, 0);
+	vx6953_probe_init_done(data);
+init_probe_done:
+	CDBG(" vx6953_probe_init_sensor finishes\n");
+	return rc;
+	}
+/* camsensor_iu060f_vx6953_reset */
+int vx6953_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+	unsigned short revision_number;
+	int32_t rc = 0;
+
+	CDBG("%s: %d\n", __func__, __LINE__);
+	CDBG("Calling vx6953_sensor_open_init\n");
+	rc = gpio_request(data->sensor_reset, "vx6953");
+	if (!rc)
+		CDBG("vx6953 gpio_request fail\n");
+
+	vx6953_ctrl = kzalloc(sizeof(struct vx6953_ctrl_t), GFP_KERNEL);
+	if (!vx6953_ctrl) {
+		CDBG("vx6953_init failed!\n");
+		rc = -ENOMEM;
+		goto init_done;
+	}
+	vx6953_ctrl->fps_divider = 1 * 0x00000400;
+	vx6953_ctrl->pict_fps_divider = 1 * 0x00000400;
+	vx6953_ctrl->set_test = TEST_OFF;
+	vx6953_ctrl->prev_res = QTR_SIZE;
+	vx6953_ctrl->pict_res = FULL_SIZE;
+	vx6953_ctrl->curr_res = INVALID_SIZE;
+	vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_2;
+	vx6953_ctrl->edof_mode = VX6953_EDOF_ESTIMATION;
+	if (data)
+		vx6953_ctrl->sensordata = data;
+	if (rc < 0) {
+		CDBG("Calling vx6953_sensor_open_init fail1\n");
+		return rc;
+	}
+	CDBG("%s: %d\n", __func__, __LINE__);
+	/* enable mclk first */
+	msm_camio_clk_rate_set(VX6953_STM5M0EDOF_DEFAULT_MASTER_CLK_RATE);
+	CDBG("%s: %d\n", __func__, __LINE__);
+	if (vx6953_i2c_read(0x0002, &revision_number, 1) < 0)
+		return rc;
+		CDBG("sensor revision number major = 0x%x\n", revision_number);
+	if (vx6953_i2c_read(0x0018, &revision_number, 1) < 0)
+		return rc;
+		CDBG("sensor revision number = 0x%x\n", revision_number);
+	if (revision_number == VX6953_REVISION_NUMBER_CUT3) {
+		vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_3;
+		CDBG("VX6953 EDof Cut 3.0 sensor\n ");
+	} else if (revision_number == VX6953_REVISION_NUMBER_CUT2) {
+		vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_2;
+		CDBG("VX6953 EDof Cut 2.0 sensor\n ");
+	} else {/* Cut1.0 reads 0x00 for register 0x0018*/
+		vx6953_ctrl->sensor_type = VX6953_STM5M0EDOF_CUT_1;
+		CDBG("VX6953 EDof Cut 1.0 sensor\n ");
+	}
+
+	vx6953_ctrl->fps = 30*Q8;
+	if (rc < 0)
+		goto init_fail;
+	else
+		goto init_done;
+init_fail:
+	CDBG("init_fail\n");
+	gpio_direction_output(data->sensor_reset, 0);
+	vx6953_probe_init_done(data);
+init_done:
+	CDBG("init_done\n");
+	return rc;
+} /*endof vx6953_sensor_open_init*/
+
+static int vx6953_init_client(struct i2c_client *client)
+{
+	/* Initialize the MSM_CAMI2C Chip */
+	init_waitqueue_head(&vx6953_wait_queue);
+	return 0;
+}
+
+static const struct i2c_device_id vx6953_i2c_id[] = {
+	{"vx6953", 0},
+	{ }
+};
+
+static int vx6953_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int rc = 0;
+	CDBG("vx6953_probe called!\n");
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		CDBG("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	vx6953_sensorw = kzalloc(sizeof(struct vx6953_work_t), GFP_KERNEL);
+	if (!vx6953_sensorw) {
+		CDBG("kzalloc failed.\n");
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, vx6953_sensorw);
+	vx6953_init_client(client);
+	vx6953_client = client;
+
+	msleep(50);
+
+	CDBG("vx6953_probe successed! rc = %d\n", rc);
+	return 0;
+
+probe_failure:
+	CDBG("vx6953_probe failed! rc = %d\n", rc);
+	return rc;
+}
+
+static int vx6953_send_wb_info(struct wb_info_cfg *wb)
+{
+	unsigned short read_data;
+	uint8_t temp[8];
+	int rc = 0;
+	int i = 0;
+
+	/* red_gain */
+	temp[2] = wb->red_gain >> 8;
+	temp[3] = wb->red_gain & 0xFF;
+
+	/* green_gain */
+	temp[0] = wb->green_gain >> 8;
+	temp[1] = wb->green_gain & 0xFF;
+	temp[6] = temp[0];
+	temp[7] = temp[1];
+
+	/* blue_gain */
+	temp[4] = wb->blue_gain >> 8;
+	temp[5] = wb->blue_gain & 0xFF;
+	rc = vx6953_i2c_write_seq_sensor(0x0B8E, &temp[0], 8);
+
+	for (i = 0; i < 6; i++) {
+		rc = vx6953_i2c_read(0x0B8E + i, &read_data, 1);
+		CDBG("%s addr 0x%x val %d\n", __func__, 0x0B8E + i, read_data);
+	}
+	rc = vx6953_i2c_read(0x0B82, &read_data, 1);
+	CDBG("%s addr 0x%x val %d\n", __func__, 0x0B82, read_data);
+	if (rc < 0)
+		return rc;
+	return rc;
+} /*end of vx6953_snapshot_config*/
+
+static int __exit vx6953_remove(struct i2c_client *client)
+{
+	struct vx6953_work_t_t *sensorw = i2c_get_clientdata(client);
+	free_irq(client->irq, sensorw);
+	vx6953_client = NULL;
+	kfree(sensorw);
+	return 0;
+}
+
+static struct i2c_driver vx6953_i2c_driver = {
+	.id_table = vx6953_i2c_id,
+	.probe  = vx6953_i2c_probe,
+	.remove = __exit_p(vx6953_i2c_remove),
+	.driver = {
+		.name = "vx6953",
+	},
+};
+
+static int vx6953_sensor_config(void __user *argp)
+{
+	struct sensor_cfg_data cdata;
+	long   rc = 0;
+	if (copy_from_user(&cdata,
+		(void *)argp,
+		sizeof(struct sensor_cfg_data)))
+		return -EFAULT;
+	mutex_lock(&vx6953_mut);
+	CDBG("vx6953_sensor_config: cfgtype = %d\n",
+	cdata.cfgtype);
+		switch (cdata.cfgtype) {
+		case CFG_GET_PICT_FPS:
+			vx6953_get_pict_fps(
+				cdata.cfg.gfps.prevfps,
+				&(cdata.cfg.gfps.pictfps));
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PREV_L_PF:
+			cdata.cfg.prevl_pf =
+			vx6953_get_prev_lines_pf();
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PREV_P_PL:
+			cdata.cfg.prevp_pl =
+				vx6953_get_prev_pixels_pl();
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PICT_L_PF:
+			cdata.cfg.pictl_pf =
+				vx6953_get_pict_lines_pf();
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PICT_P_PL:
+			cdata.cfg.pictp_pl =
+				vx6953_get_pict_pixels_pl();
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_GET_PICT_MAX_EXP_LC:
+			cdata.cfg.pict_max_exp_lc =
+				vx6953_get_pict_max_exp_lc();
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
+		case CFG_SET_FPS:
+		case CFG_SET_PICT_FPS:
+			rc = vx6953_set_fps(&(cdata.cfg.fps));
+			break;
+
+		case CFG_SET_EXP_GAIN:
+			rc =
+				vx6953_write_exp_gain(
+					cdata.cfg.exp_gain.gain,
+					cdata.cfg.exp_gain.line);
+			break;
+
+		case CFG_SET_PICT_EXP_GAIN:
+			rc =
+				vx6953_set_pict_exp_gain(
+				cdata.cfg.exp_gain.gain,
+				cdata.cfg.exp_gain.line);
+			break;
+
+		case CFG_SET_MODE:
+			rc = vx6953_set_sensor_mode(cdata.mode,
+					cdata.rs);
+			break;
+
+		case CFG_PWR_DOWN:
+			rc = vx6953_power_down();
+			break;
+
+		case CFG_MOVE_FOCUS:
+			rc =
+				vx6953_move_focus(
+				cdata.cfg.focus.dir,
+				cdata.cfg.focus.steps);
+			break;
+
+		case CFG_SET_DEFAULT_FOCUS:
+			rc =
+				vx6953_set_default_focus(
+				cdata.cfg.focus.steps);
+			break;
+
+		case CFG_SET_EFFECT:
+			rc = vx6953_set_default_focus(
+				cdata.cfg.effect);
+			break;
+
+
+		case CFG_SEND_WB_INFO:
+			rc = vx6953_send_wb_info(
+				&(cdata.cfg.wb_info));
+			break;
+
+		default:
+			rc = -EFAULT;
+			break;
+		}
+
+	mutex_unlock(&vx6953_mut);
+
+	return rc;
+}
+
+
+
+
+static int vx6953_sensor_release(void)
+{
+	int rc = -EBADF;
+	mutex_lock(&vx6953_mut);
+	vx6953_power_down();
+	gpio_free(vx6953_ctrl->sensordata->sensor_reset);
+	kfree(vx6953_ctrl);
+	vx6953_ctrl = NULL;
+	CDBG("vx6953_release completed\n");
+	mutex_unlock(&vx6953_mut);
+
+	return rc;
+}
+
+static int vx6953_g_chip_ident(struct v4l2_subdev *sd,
+			struct v4l2_dbg_chip_ident *id)
+{
+	/* TODO: Need to add this ID in v4l2-chip-ident.h */
+	id->ident    = V4L2_IDENT_VX6953;
+	id->revision = 0;
+
+	return 0;
+}
+
+static int vx6953_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *param)
+{
+	int ret = 0;
+	/* return current mode value */
+	param->parm.capture.capturemode = vx6953_ctrl->sensormode;
+	return ret;
+}
+
+static int vx6953_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *param)
+{
+	/* set the desired mode */
+	/* right now, the only purpose is to set the desired mode -
+	 preview or snapshot */
+	vx6953_ctrl->sensormode = param->parm.capture.capturemode;
+	return 0;
+}
+
+static int vx6953_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	long rc = 0;
+	int mode = vx6953_ctrl->sensormode;
+	int rt = RES_PREVIEW;
+	unsigned short frame_cnt;
+	struct msm_camera_csi_params vx6953_csi_params;
+
+	CDBG("mode = %d, enable = %d\n", mode, enable);
+
+	if (!enable) {
+		/* turn off streaming */
+		/* TODO: Make call to I2C write to turn streaming off */
+		/* rc = vx6953_i2c_write_b_sensor(); */
+
+		struct vx6953_i2c_reg_conf init_tbl[] = {
+			{REG_0x0112,
+			vx6953_regs.reg_pat_init[0].reg_0x0112},
+			{0x6003, 0x01},
+			{REG_0x0113,
+			vx6953_regs.reg_pat_init[0].reg_0x0113},
+			{REG_VT_PIX_CLK_DIV,
+			vx6953_regs.reg_pat_init[0].
+			vt_pix_clk_div},
+			{REG_PRE_PLL_CLK_DIV,
+			vx6953_regs.reg_pat_init[0].
+			pre_pll_clk_div},
+			{REG_PLL_MULTIPLIER,
+			vx6953_regs.reg_pat_init[0].
+			pll_multiplier},
+			{REG_OP_PIX_CLK_DIV,
+			vx6953_regs.reg_pat_init[0].
+			op_pix_clk_div},
+			{REG_COARSE_INTEGRATION_TIME_HI,
+			vx6953_regs.reg_pat[rt].
+			coarse_integration_time_hi},
+			{REG_COARSE_INTEGRATION_TIME_LO,
+			vx6953_regs.reg_pat[rt].
+			coarse_integration_time_lo},
+			{REG_ANALOGUE_GAIN_CODE_GLOBAL_LO,
+			vx6953_regs.reg_pat[rt].
+			analogue_gain_code_global},
+			{REG_0x3030,
+			vx6953_regs.reg_pat_init[0].reg_0x3030},
+			/* 953 specific registers */
+			{REG_0x0111,
+			vx6953_regs.reg_pat_init[0].reg_0x0111},
+			{REG_0x0b00,
+			vx6953_regs.reg_pat_init[0].reg_0x0b00},
+			{REG_0x3001,
+			vx6953_regs.reg_pat_init[0].reg_0x3001},
+			{REG_0x3004,
+			vx6953_regs.reg_pat_init[0].reg_0x3004},
+			{0x3006, 0x00},
+			{REG_0x3007,
+			vx6953_regs.reg_pat_init[0].reg_0x3007},
+			{0x301b, 0x29},
+			/* DEFCOR settings */
+			/*Single Defect Correction Weight DISABLE*/
+			{0x0b06,
+			vx6953_regs.reg_pat_init[0].reg_0x0b06},
+			/*Single_defect_correct_weight = auto*/
+			{0x0b07,
+			vx6953_regs.reg_pat_init[0].reg_0x0b07},
+			/*Dynamic couplet correction ENABLED*/
+			{0x0b08,
+			vx6953_regs.reg_pat_init[0].reg_0x0b08},
+			/*Dynamic couplet correction weight*/
+			{0x0b09,
+			vx6953_regs.reg_pat_init[0].reg_0x0b09},
+			/* Clock Setup */
+			/* Tell sensor ext clk is 24MHz*/
+			{REG_0x0136,
+			vx6953_regs.reg_pat_init[0].reg_0x0136},
+			{REG_0x0137,
+			vx6953_regs.reg_pat_init[0].reg_0x0137},
+			/* The white balance gains must be written
+			 to the sensor every frame. */
+			/* Edof */
+			{REG_0x0b83,
+			vx6953_regs.reg_pat_init[0].reg_0x0b83},
+			{REG_0x0b84,
+			vx6953_regs.reg_pat_init[0].reg_0x0b84},
+			{REG_0x0b85,
+			vx6953_regs.reg_pat_init[0].reg_0x0b85},
+			{REG_0x0b88,
+			vx6953_regs.reg_pat_init[0].reg_0x0b88},
+			{REG_0x0b89,
+			vx6953_regs.reg_pat_init[0].reg_0x0b89},
+			{REG_0x0b8a,
+			vx6953_regs.reg_pat_init[0].reg_0x0b8a},
+			/* Mode specific regieters */
+			{REG_FRAME_LENGTH_LINES_HI,
+			vx6953_regs.reg_pat[rt].
+			frame_length_lines_hi},
+			{REG_FRAME_LENGTH_LINES_LO,
+			vx6953_regs.reg_pat[rt].
+			frame_length_lines_lo},
+			{REG_LINE_LENGTH_PCK_HI,
+			vx6953_regs.reg_pat[rt].
+			line_length_pck_hi},
+			{REG_LINE_LENGTH_PCK_LO,
+			vx6953_regs.reg_pat[rt].
+			line_length_pck_lo},
+			{REG_0x3005,
+			vx6953_regs.reg_pat[rt].reg_0x3005},
+			{0x3010,
+			vx6953_regs.reg_pat[rt].reg_0x3010},
+			{REG_0x3011,
+			vx6953_regs.reg_pat[rt].reg_0x3011},
+			{REG_0x301a,
+			vx6953_regs.reg_pat[rt].reg_0x301a},
+			{REG_0x3035,
+			vx6953_regs.reg_pat[rt].reg_0x3035},
+			{REG_0x3036,
+			vx6953_regs.reg_pat[rt].reg_0x3036},
+			{REG_0x3041,
+			vx6953_regs.reg_pat[rt].reg_0x3041},
+			{0x3042,
+			vx6953_regs.reg_pat[rt].reg_0x3042},
+			{REG_0x3045,
+			vx6953_regs.reg_pat[rt].reg_0x3045},
+			/*EDOF: Estimation settings for Preview mode
+			  Application settings for capture mode
+			  (standard settings - Not tuned) */
+			{REG_0x0b80,
+			vx6953_regs.reg_pat[rt].reg_0x0b80},
+			{REG_0x0900,
+			vx6953_regs.reg_pat[rt].reg_0x0900},
+			{REG_0x0901,
+			vx6953_regs.reg_pat[rt].reg_0x0901},
+			{REG_0x0902,
+			vx6953_regs.reg_pat[rt].reg_0x0902},
+			{REG_0x0383,
+			vx6953_regs.reg_pat[rt].reg_0x0383},
+			{REG_0x0387,
+			vx6953_regs.reg_pat[rt].reg_0x0387},
+			/* Change output size / frame rate */
+			{REG_0x034c,
+			vx6953_regs.reg_pat[rt].reg_0x034c},
+			{REG_0x034d,
+			vx6953_regs.reg_pat[rt].reg_0x034d},
+			{REG_0x034e,
+			vx6953_regs.reg_pat[rt].reg_0x034e},
+			{REG_0x034f,
+			vx6953_regs.reg_pat[rt].reg_0x034f},
+		};
+		/* reset fps_divider */
+		vx6953_ctrl->fps = 30 * Q8;
+		/* stop streaming */
+
+		/* Reset everything first */
+		if (vx6953_i2c_write_b_sensor(0x103, 0x01) < 0) {
+			CDBG("S/W reset failed\n");
+			return rc;
+		} else
+			CDBG("S/W reset successful\n");
+
+		msleep(10);
+
+		CDBG("Init vx6953_sensor_setting standby\n");
+		if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT,
+				    MODE_SELECT_STANDBY_MODE) < 0)
+			return rc;
+
+		/*vx6953_stm5m0edof_delay_msecs_stdby*/
+		msleep(vx6953_stm5m0edof_delay_msecs_stdby);
+
+		vx6953_csi_params.data_format = CSI_8BIT;
+		vx6953_csi_params.lane_cnt = 1;
+		vx6953_csi_params.lane_assign = 0xe4;
+		vx6953_csi_params.dpcm_scheme = 0;
+		vx6953_csi_params.settle_cnt = 7;
+		rc = msm_camio_csi_config(&vx6953_csi_params);
+		if (rc < 0)
+			CDBG(" config csi controller failed\n");
+		msleep(vx6953_stm5m0edof_delay_msecs_stdby);
+
+		vx6953_patch_for_cut3();
+		rc = vx6953_i2c_write_w_table(&init_tbl[0],
+					    ARRAY_SIZE(init_tbl));
+		if (rc < 0)
+			return rc;
+
+		msleep(vx6953_stm5m0edof_delay_msecs_stdby);
+
+		vx6953_i2c_write_b_sensor(0x0b80, 0x00);
+		vx6953_i2c_write_b_sensor(0x3388, 0x03);
+		vx6953_i2c_write_b_sensor(0x3640, 0x00);
+		return rc;
+	} else {
+		/* Start sensor streaming */
+		if (vx6953_i2c_write_b_sensor(REG_MODE_SELECT,
+					    MODE_SELECT_STREAM) < 0)
+			return rc;
+		CDBG("Init vx6953_sensor_setting stream\n");
+		msleep(vx6953_stm5m0edof_delay_msecs_stream);
+		if (vx6953_i2c_read(0x0005, &frame_cnt, 1) < 0)
+			return rc;
+
+		rc = vx6953_i2c_write_w_table(&edof_tbl[0],
+					    ARRAY_SIZE(edof_tbl));
+		vx6953_i2c_write_b_sensor(0x3388, 0x00);
+
+		while (frame_cnt == 0xFF) {
+			if (vx6953_i2c_read(0x0005, &frame_cnt, 1) < 0)
+				return rc;
+			CDBG("frame_cnt=%d", frame_cnt);
+			msleep(10);
+		}
+
+		/* set desired mode */
+		switch (mode) {
+		case SENSOR_PREVIEW_MODE:
+			CDBG("SENSOR_PREVIEW_MODE\n");
+			rc = vx6953_video_config(mode);
+			break;
+		case SENSOR_SNAPSHOT_MODE:
+			CDBG("SENSOR_SNAPSHOT_MODE\n");
+			rc = vx6953_snapshot_config(mode);
+			break;
+		case SENSOR_RAW_SNAPSHOT_MODE:
+			CDBG("SENSOR_RAW_SNAPSHOT_MODE\n");
+			rc = vx6953_raw_snapshot_config(mode);
+			break;
+		default:
+			CDBG("default\n");
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static void vx6953_frame_check(u32 *width, u32 *height)
+{
+	/* get mode first */
+	int mode = vx6953_ctrl->sensormode;
+
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		if (*width > VX6953_QTR_SIZE_WIDTH)
+			*width = VX6953_QTR_SIZE_WIDTH;
+
+		if (*height > VX6953_QTR_SIZE_HEIGHT)
+			*height = VX6953_QTR_SIZE_HEIGHT;
+		break;
+	case SENSOR_SNAPSHOT_MODE:
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		if (*width > VX6953_HRZ_FULL_BLK_PIXELS)
+			*width = VX6953_HRZ_FULL_BLK_PIXELS;
+
+		if (*height > VX6953_VER_FULL_BLK_LINES)
+			*height = VX6953_VER_FULL_BLK_LINES;
+		break;
+	default:
+		break;
+	}
+}
+
+
+static int vx6953_set_params(struct i2c_client *client, u32 width, u32 height,
+			     enum v4l2_mbus_pixelcode code)
+{
+	int i;
+	vx6953_ctrl->fmt = NULL;
+
+	/*
+	 * frame size check
+	 */
+	vx6953_frame_check(&width, &height);
+
+	/*
+	 * get color format
+	 */
+	for (i = 0; i < ARRAY_SIZE(vx6953_cfmts); i++)
+		if (vx6953_cfmts[i].code == code)
+			break;
+	if (i == ARRAY_SIZE(vx6953_cfmts))
+		return -EINVAL;
+
+	/* sensor supports one fixed size depending upon the mode */
+	switch (vx6953_ctrl->sensormode) {
+	case SENSOR_PREVIEW_MODE:
+		vx6953_video_config(vx6953_ctrl->sensormode);
+		break;
+	case SENSOR_SNAPSHOT_MODE:
+		vx6953_snapshot_config(vx6953_ctrl->sensormode);
+		break;
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		vx6953_raw_snapshot_config(vx6953_ctrl->sensormode);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* why need this ? vx6953_ctrl->fmt = &(vx6953_cfmts[i]); */
+
+	return 0;
+}
+
+static int vx6953_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+	/* right now we are not supporting, probably vfe can take care */
+	return -EINVAL;
+}
+
+static int vx6953_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	return -EINVAL;
+}
+
+static int vx6953_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	return -EINVAL;
+}
+
+static int vx6953_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
+{
+	/* by this time vx6953_client should already be set */
+	struct i2c_client *client = vx6953_client;
+
+	/* currently sensor supports fixed dimensions only
+	 * depending upon the mode*/
+	if (!vx6953_ctrl->fmt) {
+		int ret = vx6953_set_params(client, VX6953_QTR_SIZE_WIDTH,
+						VX6953_QTR_SIZE_HEIGHT,
+						V4L2_MBUS_FMT_YUYV8_2X8);
+		if (ret < 0)
+			return ret;
+	}
+
+	mf->width = vx6953_get_pict_pixels_pl();
+	mf->height  = vx6953_get_pict_lines_pf();
+	/* TODO: set colorspace */
+	mf->code  = vx6953_ctrl->fmt->code;
+	mf->field = V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+static int vx6953_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
+{
+	/* by this time vx6953_client should already be set */
+	struct i2c_client *client = vx6953_client;
+
+	/* TODO: We need to define this function */
+	/* TODO: set colorspace */
+	return vx6953_set_params(client, mf->width, mf->height, mf->code);
+}
+
+static int vx6953_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(vx6953_cfmts); i++)
+		if (mf->code == vx6953_cfmts[i].code)
+			break;
+
+	if (i == ARRAY_SIZE(vx6953_cfmts))
+		return -EINVAL;
+
+	/* check that frame is within max sensor supported frame size */
+	vx6953_frame_check(&mf->width, &mf->height);
+
+	/* TODO: set colorspace */
+	mf->field = V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+static int vx6953_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+			   enum v4l2_mbus_pixelcode *code)
+{
+	printk(KERN_DEBUG "Index is %d\n", index);
+	if ((unsigned int)index >= ARRAY_SIZE(vx6953_cfmts))
+		return -EINVAL;
+
+	*code = vx6953_cfmts[index].code;
+	return 0;
+}
+
+static struct v4l2_subdev_core_ops vx6953_subdev_core_ops = {
+	.g_chip_ident = vx6953_g_chip_ident,
+};
+
+static struct v4l2_subdev_video_ops vx6953_subdev_video_ops = {
+	.g_parm			   = vx6953_g_parm,
+	.s_parm			   = vx6953_s_parm,
+	.s_stream = vx6953_s_stream,
+	.g_mbus_fmt = vx6953_g_fmt,
+	.s_mbus_fmt = vx6953_s_fmt,
+	.try_mbus_fmt = vx6953_try_fmt,
+	.cropcap  = vx6953_cropcap,
+	.g_crop   = vx6953_g_crop,
+	.s_crop   = vx6953_s_crop,
+	.enum_mbus_fmt  = vx6953_enum_fmt,
+};
+
+static struct v4l2_subdev_ops vx6953_subdev_ops = {
+	.core = &vx6953_subdev_core_ops,
+	.video  = &vx6953_subdev_video_ops,
+};
+
+static int vx6953_sensor_probe(const struct msm_camera_sensor_info *info,
+		struct msm_sensor_ctrl *s)
+{
+	int rc = 0;
+	rc = i2c_add_driver(&vx6953_i2c_driver);
+	if (rc < 0 || vx6953_client == NULL) {
+		rc = -ENOTSUPP;
+		goto probe_fail;
+	}
+	msm_camio_clk_rate_set(24000000);
+	rc = vx6953_probe_init_sensor(info);
+	if (rc < 0)
+		goto probe_fail;
+	s->s_init = vx6953_sensor_open_init;
+	s->s_release = vx6953_sensor_release;
+	s->s_config  = vx6953_sensor_config;
+	vx6953_probe_init_done(info);
+	return rc;
+
+probe_fail:
+	CDBG("vx6953_sensor_probe: SENSOR PROBE FAILS!\n");
+	return rc;
+}
+
+
+static int vx6953_sensor_probe_cb(const struct msm_camera_sensor_info *info,
+	struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s)
+{
+	int rc = 0;
+	rc = vx6953_sensor_probe(info, s);
+	if (rc < 0)
+		return rc;
+
+	vx6953_ctrl = kzalloc(sizeof(struct vx6953_ctrl_t), GFP_KERNEL);
+	if (!vx6953_ctrl) {
+		CDBG("vx6953_sensor_probe failed!\n");
+		return -ENOMEM;
+	}
+
+	/* probe is successful, init a v4l2 subdevice */
+	printk(KERN_DEBUG "going into v4l2_i2c_subdev_init\n");
+	if (sdev) {
+		v4l2_i2c_subdev_init(sdev, vx6953_client,
+						&vx6953_subdev_ops);
+		vx6953_ctrl->sensor_dev = sdev;
+	}
+	return rc;
+}
+
+static int __vx6953_probe(struct platform_device *pdev)
+{
+	return msm_sensor_register(pdev, vx6953_sensor_probe_cb);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = __vx6953_probe,
+	.driver = {
+		.name = "msm_camera_vx6953",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init vx6953_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(vx6953_init);
+void vx6953_exit(void)
+{
+	i2c_del_driver(&vx6953_i2c_driver);
+}
+
+
diff --git a/drivers/media/video/msm/vx6953_v4l2.h b/drivers/media/video/msm/vx6953_v4l2.h
new file mode 100644
index 0000000..e5428e9
--- /dev/null
+++ b/drivers/media/video/msm/vx6953_v4l2.h
@@ -0,0 +1,136 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#ifndef VX6953_V4L2_H
+#define VX6953_V4L2_H
+#include <linux/types.h>
+#include <mach/board.h>
+extern struct vx6953_reg vx6953_regs;
+struct reg_struct_init {
+	uint8_t reg_0x0112;      /* 0x0112*/
+	uint8_t reg_0x0113;      /* 0x0113*/
+	uint8_t vt_pix_clk_div;  /* 0x0301*/
+	uint8_t pre_pll_clk_div; /* 0x0305*/
+	uint8_t pll_multiplier;  /* 0x0307*/
+	uint8_t op_pix_clk_div;  /* 0x0309*/
+	uint8_t reg_0x3030;      /*0x3030*/
+	uint8_t reg_0x0111;      /*0x0111*/
+	uint8_t reg_0x0b00;      /*0x0b00*/
+	uint8_t reg_0x3001;      /*0x3001*/
+	uint8_t reg_0x3004;      /*0x3004*/
+	uint8_t reg_0x3007;      /*0x3007*/
+	uint8_t reg_0x3016;      /*0x3016*/
+	uint8_t reg_0x301d;      /*0x301d*/
+	uint8_t reg_0x317e;      /*0x317E*/
+	uint8_t reg_0x317f;      /*0x317F*/
+	uint8_t reg_0x3400;      /*0x3400*/
+	uint8_t reg_0x0b06;      /*0x0b06*/
+	uint8_t reg_0x0b07;      /*0x0b07*/
+	uint8_t reg_0x0b08;      /*0x0b08*/
+	uint8_t reg_0x0b09;      /*0x0b09*/
+	uint8_t reg_0x0136;
+	uint8_t reg_0x0137;
+	/* Edof */
+	uint8_t reg_0x0b83;      /*0x0b83*/
+	uint8_t reg_0x0b84;      /*0x0b84*/
+	uint8_t reg_0x0b85;      /*0x0b85*/
+	uint8_t reg_0x0b88;      /*0x0b88*/
+	uint8_t reg_0x0b89;      /*0x0b89*/
+	uint8_t reg_0x0b8a;      /*0x0b8a*/
+	};
+struct reg_struct {
+	uint8_t coarse_integration_time_hi; /*REG_COARSE_INTEGRATION_TIME_HI*/
+	uint8_t coarse_integration_time_lo; /*REG_COARSE_INTEGRATION_TIME_LO*/
+	uint8_t analogue_gain_code_global;
+	uint8_t frame_length_lines_hi; /* 0x0340*/
+	uint8_t frame_length_lines_lo; /* 0x0341*/
+	uint8_t line_length_pck_hi;    /* 0x0342*/
+	uint8_t line_length_pck_lo;    /* 0x0343*/
+	uint8_t reg_0x3005;   /* 0x3005*/
+	uint8_t reg_0x3010;  /* 0x3010*/
+	uint8_t reg_0x3011;  /* 0x3011*/
+	uint8_t reg_0x301a;  /* 0x301a*/
+	uint8_t reg_0x3035;  /* 0x3035*/
+	uint8_t reg_0x3036;   /* 0x3036*/
+	uint8_t reg_0x3041;  /*0x3041*/
+	uint8_t reg_0x3042;  /*0x3042*/
+	uint8_t reg_0x3045;  /*0x3045*/
+	uint8_t reg_0x0b80;   /* 0x0b80*/
+	uint8_t reg_0x0900;   /*0x0900*/
+	uint8_t reg_0x0901;   /* 0x0901*/
+	uint8_t reg_0x0902;   /*0x0902*/
+	uint8_t reg_0x0383;   /*0x0383*/
+	uint8_t reg_0x0387;   /* 0x0387*/
+	uint8_t reg_0x034c;   /* 0x034c*/
+	uint8_t reg_0x034d;   /*0x034d*/
+	uint8_t reg_0x034e;   /* 0x034e*/
+	uint8_t reg_0x034f;   /* 0x034f*/
+	uint8_t reg_0x1716; /*0x1716*/
+	uint8_t reg_0x1717; /*0x1717*/
+	uint8_t reg_0x1718; /*0x1718*/
+	uint8_t reg_0x1719; /*0x1719*/
+	uint8_t reg_0x3210;/*0x3210*/
+	uint8_t reg_0x111; /*0x111*/
+	uint8_t reg_0x3410;  /*0x3410*/
+	uint8_t reg_0x3098;
+	uint8_t reg_0x309D;
+	uint8_t reg_0x0200;
+	uint8_t reg_0x0201;
+	};
+struct vx6953_i2c_reg_conf {
+	unsigned short waddr;
+	unsigned short wdata;
+};
+
+enum vx6953_test_mode_t {
+	TEST_OFF,
+	TEST_1,
+	TEST_2,
+	TEST_3
+};
+
+enum vx6953_resolution_t {
+	QTR_SIZE,
+	FULL_SIZE,
+	INVALID_SIZE
+};
+enum vx6953_setting {
+	RES_PREVIEW,
+	RES_CAPTURE
+};
+enum mt9p012_reg_update {
+	/* Sensor egisters that need to be updated during initialization */
+	REG_INIT,
+	/* Sensor egisters that needs periodic I2C writes */
+	UPDATE_PERIODIC,
+	/* All the sensor Registers will be updated */
+	UPDATE_ALL,
+	/* Not valid update */
+	UPDATE_INVALID
+};
+
+enum sensor_revision_t {
+	VX6953_STM5M0EDOF_CUT_1,
+	VX6953_STM5M0EDOF_CUT_2,
+	VX6953_STM5M0EDOF_CUT_3
+};
+enum edof_mode_t {
+	VX6953_EDOF_DISABLE,       /* 0x00 */
+	VX6953_EDOF_APPLICATION,   /* 0x01 */
+	VX6953_EDOF_ESTIMATION     /* 0x02 */
+};
+struct vx6953_reg {
+	const struct reg_struct_init  *reg_pat_init;
+	const struct reg_struct  *reg_pat;
+};
+#endif /* VX6953_H */
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
index de4fa4e..ac48afd 100644
--- a/drivers/media/video/videobuf-core.c
+++ b/drivers/media/video/videobuf-core.c
@@ -330,6 +330,7 @@
 		break;
 	case V4L2_MEMORY_USERPTR:
 		b->m.userptr = vb->baddr;
+		b->reserved = vb->boff;
 		b->length    = vb->bsize;
 		break;
 	case V4L2_MEMORY_OVERLAY:
@@ -600,6 +601,7 @@
 		    buf->baddr != b->m.userptr)
 			q->ops->buf_release(q, buf);
 		buf->baddr = b->m.userptr;
+		buf->boff = b->reserved;
 		break;
 	case V4L2_MEMORY_OVERLAY:
 		buf->boff = b->m.offset;
@@ -1138,8 +1140,6 @@
 			buf = list_entry(q->stream.next,
 					 struct videobuf_buffer, stream);
 	} else {
-		if (!q->reading)
-			__videobuf_read_start(q);
 		if (!q->reading) {
 			rc = POLLERR;
 		} else if (NULL == q->read_buf) {
diff --git a/drivers/media/video/videobuf-msm-mem.c b/drivers/media/video/videobuf-msm-mem.c
new file mode 100644
index 0000000..6f2cf9f
--- /dev/null
+++ b/drivers/media/video/videobuf-msm-mem.c
@@ -0,0 +1,394 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * Based on videobuf-dma-contig.c,
+ * (c) 2008 Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * helper functions for physically contiguous pmem capture buffers
+ * The functions support contiguous memory allocations using pmem
+ * kernel API.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/sched.h>
+#include <linux/io.h>
+#include <linux/android_pmem.h>
+#include <linux/memory_alloc.h>
+#include <media/videobuf-msm-mem.h>
+#include <media/msm_camera.h>
+#include <mach/memory.h>
+
+#define MAGIC_PMEM 0x0733ac64
+#define MAGIC_CHECK(is, should)               \
+	if (unlikely((is) != (should))) {           \
+		pr_err("magic mismatch: %x expected %x\n", (is), (should)); \
+		BUG();                  \
+	}
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+#define D(fmt, args...) printk(KERN_DEBUG "videobuf-msm-mem: " fmt, ##args)
+#else
+#define D(fmt, args...) do {} while (0)
+#endif
+
+static int32_t msm_mem_allocate(const size_t size)
+{
+	int32_t phyaddr;
+	phyaddr = allocate_contiguous_ebi_nomap(size, SZ_4K);
+	return phyaddr;
+}
+
+static int32_t msm_mem_free(const int32_t phyaddr)
+{
+	int32_t rc = 0;
+	free_contiguous_memory_by_paddr(phyaddr);
+	return rc;
+}
+
+static void
+videobuf_vm_open(struct vm_area_struct *vma)
+{
+	struct videobuf_mapping *map = vma->vm_private_data;
+
+	D("vm_open %p [count=%u,vma=%08lx-%08lx]\n",
+		map, map->count, vma->vm_start, vma->vm_end);
+
+	map->count++;
+}
+
+static void videobuf_vm_close(struct vm_area_struct *vma)
+{
+	struct videobuf_mapping *map = vma->vm_private_data;
+	struct videobuf_queue *q = map->q;
+	int i, rc;
+
+	D("vm_close %p [count=%u,vma=%08lx-%08lx]\n",
+		map, map->count, vma->vm_start, vma->vm_end);
+
+	map->count--;
+	if (0 == map->count) {
+		struct videobuf_contig_pmem *mem;
+
+		D("munmap %p q=%p\n", map, q);
+		mutex_lock(&q->vb_lock);
+
+		/* We need first to cancel streams, before unmapping */
+		if (q->streaming)
+			videobuf_queue_cancel(q);
+
+		for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+			if (NULL == q->bufs[i])
+				continue;
+
+			if (q->bufs[i]->map != map)
+				continue;
+
+			mem = q->bufs[i]->priv;
+			if (mem) {
+				/* This callback is called only if kernel has
+				 * allocated memory and this memory is mmapped.
+				 * In this case, memory should be freed,
+				 * in order to do memory unmap.
+				 */
+
+				MAGIC_CHECK(mem->magic, MAGIC_PMEM);
+
+				/* vfree is not atomic - can't be
+				 called with IRQ's disabled
+				 */
+				D("buf[%d] freeing physical %d\n",
+					i, mem->phyaddr);
+
+				rc = msm_mem_free(mem->phyaddr);
+				if (rc < 0)
+					D("%s: Invalid memory location\n",
+								__func__);
+				else {
+					mem->phyaddr = 0;
+				}
+			}
+
+			q->bufs[i]->map   = NULL;
+			q->bufs[i]->baddr = 0;
+		}
+
+		kfree(map);
+
+		mutex_unlock(&q->vb_lock);
+
+		/* deallocate the q->bufs[i] structure not a good solution
+		 as it will result in unnecessary iterations but right now
+		 this looks like the only cleaner way  */
+		videobuf_mmap_free(q);
+	}
+}
+
+static const struct vm_operations_struct videobuf_vm_ops = {
+	.open     = videobuf_vm_open,
+	.close    = videobuf_vm_close,
+};
+
+/**
+ * videobuf_pmem_contig_user_put() - reset pointer to user space buffer
+ * @mem: per-buffer private videobuf-contig-pmem data
+ *
+ * This function resets the user space pointer
+ */
+static void videobuf_pmem_contig_user_put(struct videobuf_contig_pmem *mem)
+{
+	put_pmem_file(mem->file);
+	mem->is_userptr = 0;
+	mem->phyaddr = 0;
+	mem->size = 0;
+}
+
+/**
+ * videobuf_pmem_contig_user_get() - setup user space memory pointer
+ * @mem: per-buffer private videobuf-contig-pmem data
+ * @vb: video buffer to map
+ *
+ * This function validates and sets up a pointer to user space memory.
+ * Only physically contiguous pfn-mapped memory is accepted.
+ *
+ * Returns 0 if successful.
+ */
+static int videobuf_pmem_contig_user_get(struct videobuf_contig_pmem *mem,
+					struct videobuf_buffer *vb)
+{
+	unsigned long kvstart;
+	unsigned long len;
+	int rc;
+
+	mem->size = PAGE_ALIGN(vb->size);
+	rc = get_pmem_file(vb->baddr, (unsigned long *)&mem->phyaddr,
+					&kvstart, &len, &mem->file);
+	if (rc < 0) {
+		pr_err("%s: get_pmem_file fd %lu error %d\n",
+					__func__, vb->baddr,
+							rc);
+		return rc;
+	}
+	mem->phyaddr += vb->boff;
+	mem->y_off = 0;
+	mem->cbcr_off = (vb->size)*2/3;
+	mem->is_userptr = 1;
+	return rc;
+}
+
+static struct videobuf_buffer *__videobuf_alloc(size_t size)
+{
+	struct videobuf_contig_pmem *mem;
+	struct videobuf_buffer *vb;
+
+	vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
+	if (vb) {
+		mem = vb->priv = ((char *)vb) + size;
+		mem->magic = MAGIC_PMEM;
+	}
+
+	return vb;
+}
+
+static void *__videobuf_to_vaddr(struct videobuf_buffer *buf)
+{
+	struct videobuf_contig_pmem *mem = buf->priv;
+
+	BUG_ON(!mem);
+	MAGIC_CHECK(mem->magic, MAGIC_PMEM);
+
+	return mem->vaddr;
+}
+
+static int __videobuf_iolock(struct videobuf_queue *q,
+				struct videobuf_buffer *vb,
+				struct v4l2_framebuffer *fbuf)
+{
+	int rc = 0;
+	struct videobuf_contig_pmem *mem = vb->priv;
+
+	BUG_ON(!mem);
+	MAGIC_CHECK(mem->magic, MAGIC_PMEM);
+
+	switch (vb->memory) {
+	case V4L2_MEMORY_MMAP:
+		D("%s memory method MMAP\n", __func__);
+
+		/* All handling should be done by __videobuf_mmap_mapper() */
+		break;
+	case V4L2_MEMORY_USERPTR:
+		D("%s memory method USERPTR\n", __func__);
+
+		/* handle pointer from user space */
+		rc = videobuf_pmem_contig_user_get(mem, vb);
+		break;
+	case V4L2_MEMORY_OVERLAY:
+	default:
+		pr_err("%s memory method OVERLAY/unknown\n", __func__);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static int __videobuf_mmap_mapper(struct videobuf_queue *q,
+		struct videobuf_buffer *buf,
+		struct vm_area_struct *vma)
+{
+	struct videobuf_contig_pmem *mem;
+	struct videobuf_mapping *map;
+	int retval;
+	unsigned long size;
+
+	D("%s\n", __func__);
+
+	/* create mapping + update buffer list */
+	map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
+	if (!map) {
+		pr_err("%s: kzalloc failed.\n", __func__);
+		return -ENOMEM;
+	}
+
+	buf->map = map;
+	map->q = q;
+
+	buf->baddr = vma->vm_start;
+
+	mem = buf->priv;
+	D("mem = 0x%x\n", (u32)mem);
+	D("buf = 0x%x\n", (u32)buf);
+	BUG_ON(!mem);
+	MAGIC_CHECK(mem->magic, MAGIC_PMEM);
+
+	mem->size = PAGE_ALIGN(buf->bsize);
+	mem->y_off = 0;
+	mem->cbcr_off = (buf->bsize)*2/3;
+	if (buf->i >= 0 && buf->i <= 3)
+		mem->buffer_type = OUTPUT_TYPE_P;
+	else
+		mem->buffer_type = OUTPUT_TYPE_V;
+
+	buf->bsize = mem->size;
+	mem->phyaddr = msm_mem_allocate(mem->size);
+
+	if (IS_ERR((void *)mem->phyaddr)) {
+		pr_err("%s : pmem memory allocation failed\n", __func__);
+		goto error;
+	}
+
+	/* Try to remap memory */
+	size = vma->vm_end - vma->vm_start;
+	size = (size < mem->size) ? size : mem->size;
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	retval = remap_pfn_range(vma, vma->vm_start,
+		mem->phyaddr >> PAGE_SHIFT,
+		size, vma->vm_page_prot);
+	if (retval) {
+		pr_err("mmap: remap failed with error %d. ", retval);
+		retval = msm_mem_free(mem->phyaddr);
+		if (retval < 0)
+			printk(KERN_ERR "%s: Invalid memory location\n",
+								__func__);
+		else {
+			mem->phyaddr = 0;
+		}
+		goto error;
+	}
+
+	vma->vm_ops          = &videobuf_vm_ops;
+	vma->vm_flags       |= VM_DONTEXPAND;
+	vma->vm_private_data = map;
+
+	D("mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
+		map, q, vma->vm_start, vma->vm_end,
+		(long int)buf->bsize,
+		vma->vm_pgoff, buf->i);
+
+	videobuf_vm_open(vma);
+
+	return 0;
+
+error:
+	kfree(map);
+	return -ENOMEM;
+}
+
+static struct videobuf_qtype_ops qops = {
+	.magic        = MAGIC_QTYPE_OPS,
+
+	.alloc_vb     = __videobuf_alloc,
+	.iolock       = __videobuf_iolock,
+	.mmap_mapper  = __videobuf_mmap_mapper,
+	.vaddr        = __videobuf_to_vaddr,
+};
+
+void videobuf_queue_pmem_contig_init(struct videobuf_queue *q,
+	const struct videobuf_queue_ops *ops,
+	struct device *dev,
+	spinlock_t *irqlock,
+	enum v4l2_buf_type type,
+	enum v4l2_field field,
+	unsigned int msize,
+	void *priv,
+	struct mutex *ext_lock)
+{
+	videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
+							priv, &qops, ext_lock);
+}
+EXPORT_SYMBOL_GPL(videobuf_queue_pmem_contig_init);
+
+int videobuf_to_pmem_contig(struct videobuf_buffer *buf)
+{
+	struct videobuf_contig_pmem *mem = buf->priv;
+
+	BUG_ON(!mem);
+	MAGIC_CHECK(mem->magic, MAGIC_PMEM);
+
+	return mem->phyaddr;
+}
+EXPORT_SYMBOL_GPL(videobuf_to_pmem_contig);
+
+int videobuf_pmem_contig_free(struct videobuf_queue *q,
+				struct videobuf_buffer *buf)
+{
+	struct videobuf_contig_pmem *mem = buf->priv;
+
+	/* mmapped memory can't be freed here, otherwise mmapped region
+	 would be released, while still needed. In this case, the memory
+	 release should happen inside videobuf_vm_close().
+	 So, it should free memory only if the memory were allocated for
+	 read() operation.
+	*/
+	if (buf->memory != V4L2_MEMORY_USERPTR)
+		return -EINVAL;
+
+	if (!mem)
+		return -ENOMEM;
+
+	MAGIC_CHECK(mem->magic, MAGIC_PMEM);
+
+	/* handle user space pointer case */
+	if (buf->baddr) {
+		videobuf_pmem_contig_user_put(mem);
+		return 0;
+	} else {
+		/* don't support read() method */
+		return -EINVAL;
+	}
+}
+EXPORT_SYMBOL_GPL(videobuf_pmem_contig_free);
+
+MODULE_DESCRIPTION("helper module to manage video4linux PMEM contig buffers");
+MODULE_LICENSE("GPL v2");