msm: camera: Initial commit for qs_mt9p017

Initial support for qs_mt9p017 on 8960

Signed-off-by: Kevin Chan <ktchan@codeaurora.org>
diff --git a/arch/arm/mach-msm/board-msm8960-regulator.c b/arch/arm/mach-msm/board-msm8960-regulator.c
index 7e33c28..6ba6474 100644
--- a/arch/arm/mach-msm/board-msm8960-regulator.c
+++ b/arch/arm/mach-msm/board-msm8960-regulator.c
@@ -31,6 +31,7 @@
 	REGULATOR_SUPPLY("dsi_vdda",		"mipi_dsi.1"),
 	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_camera_imx074.0"),
 	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_camera_ov2720.0"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_camera_qs_mt9p017.0"),
 };
 VREG_CONSUMERS(L3) = {
 	REGULATOR_SUPPLY("8921_l3",		NULL),
@@ -70,11 +71,13 @@
 	REGULATOR_SUPPLY("8921_l11",		NULL),
 	REGULATOR_SUPPLY("cam_vana",		"msm_camera_imx074.0"),
 	REGULATOR_SUPPLY("cam_vana",		"msm_camera_ov2720.0"),
+	REGULATOR_SUPPLY("cam_vana",		"msm_camera_qs_mt9p017.0"),
 };
 VREG_CONSUMERS(L12) = {
 	REGULATOR_SUPPLY("8921_l12",		NULL),
 	REGULATOR_SUPPLY("cam_vdig",		"msm_camera_imx074.0"),
 	REGULATOR_SUPPLY("cam_vdig",		"msm_camera_ov2720.0"),
+	REGULATOR_SUPPLY("cam_vdig",		"msm_camera_qs_mt9p017.0"),
 };
 VREG_CONSUMERS(L14) = {
 	REGULATOR_SUPPLY("8921_l14",		NULL),
@@ -86,6 +89,7 @@
 	REGULATOR_SUPPLY("8921_l16",		NULL),
 	REGULATOR_SUPPLY("cam_vaf",		"msm_camera_imx074.0"),
 	REGULATOR_SUPPLY("cam_vaf",		"msm_camera_ov2720.0"),
+	REGULATOR_SUPPLY("cam_vaf",		"msm_camera_qs_mt9p017.0"),
 };
 VREG_CONSUMERS(L17) = {
 	REGULATOR_SUPPLY("8921_l17",		NULL),
@@ -185,6 +189,7 @@
 	REGULATOR_SUPPLY("8921_lvs5",		NULL),
 	REGULATOR_SUPPLY("cam_vio",		"msm_camera_imx074.0"),
 	REGULATOR_SUPPLY("cam_vio",		"msm_camera_ov2720.0"),
+	REGULATOR_SUPPLY("cam_vio",		"msm_camera_qs_mt9p017.0"),
 };
 VREG_CONSUMERS(LVS6) = {
 	REGULATOR_SUPPLY("8921_lvs6",		NULL),
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
index 608a93d..4a1a45f 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -867,12 +867,37 @@
 	},
 };
 #endif
+
+static struct msm_camera_sensor_flash_data flash_qs_mt9p017 = {
+	.flash_type	= MSM_CAMERA_FLASH_LED,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_qs_mt9p017_data = {
+	.sensor_name	= "qs_mt9p017",
+	.sensor_reset	= 107,
+	.sensor_pwd	= 85,
+	.vcm_pwd	= 0,
+	.vcm_enable	= 1,
+	.pdata	= &msm_camera_csi0_device_data,
+	.flash_data	= &flash_qs_mt9p017,
+	.sensor_platform_info = &sensor_board_info,
+	.csi_if	= 1
+};
+
+struct platform_device msm8960_camera_sensor_qs_mt9p017 = {
+	.name	= "msm_camera_qs_mt9p017",
+	.dev	= {
+		.platform_data = &msm_camera_sensor_qs_mt9p017_data,
+	},
+};
+
 static void __init msm8960_init_cam(void)
 {
 	int i;
 	struct platform_device *cam_dev[] = {
 		&msm8960_camera_sensor_imx074,
 		&msm8960_camera_sensor_ov2720,
+		&msm8960_camera_sensor_qs_mt9p017,
 	};
 
 	for (i = 0; i < ARRAY_SIZE(cam_dev); i++) {
@@ -3118,6 +3143,9 @@
 	I2C_BOARD_INFO("ov2720", 0x6C),
 	},
 #endif
+	{
+	I2C_BOARD_INFO("qs_mt9p017", 0x6C >> 1),
+	},
 };
 #endif
 
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index b792702..9b5ba9a 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -3821,17 +3821,21 @@
 	CLK_LOOKUP("cam_clk",		cam1_clk.c,		NULL),
 	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"msm_camera_imx074.0"),
 	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"msm_camera_ov2720.0"),
+	CLK_LOOKUP("cam_clk",	cam0_clk.c,	"msm_camera_qs_mt9p017.0"),
 	CLK_LOOKUP("csi_src_clk",	csi0_src_clk.c,		NULL),
 	CLK_LOOKUP("csi_src_clk",	csi1_src_clk.c,		NULL),
 	CLK_LOOKUP("csi_src_clk",	csi0_src_clk.c,	"msm_camera_imx074.0"),
+	CLK_LOOKUP("csi_src_clk", csi0_src_clk.c, "msm_camera_qs_mt9p017.0"),
 	CLK_LOOKUP("csi_src_clk",	csi1_src_clk.c,	"msm_camera_ov2720.0"),
 	CLK_LOOKUP("csi_clk",		csi0_clk.c,		NULL),
 	CLK_LOOKUP("csi_clk",		csi1_clk.c,		NULL),
 	CLK_LOOKUP("csi_clk",		csi0_clk.c,	"msm_camera_imx074.0"),
+	CLK_LOOKUP("csi_clk",	csi0_clk.c,	"msm_camera_qs_mt9p017.0"),
 	CLK_LOOKUP("csi_clk",		csi1_clk.c,	"msm_camera_ov2720.0"),
 	CLK_LOOKUP("csi_phy_clk",	csi0_phy_clk.c,		NULL),
 	CLK_LOOKUP("csi_phy_clk",	csi1_phy_clk.c,		NULL),
 	CLK_LOOKUP("csi_phy_clk",	csi0_phy_clk.c,	"msm_camera_imx074.0"),
+	CLK_LOOKUP("csi_phy_clk", csi0_phy_clk.c, "msm_camera_qs_mt9p017.0"),
 	CLK_LOOKUP("csi_phy_clk",	csi1_phy_clk.c,	"msm_camera_ov2720.0"),
 	CLK_LOOKUP("csi_pix_clk",	csi_pix_clk.c,		NULL),
 	CLK_LOOKUP("csi_rdi_clk",	csi_rdi_clk.c,		NULL),
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index 6ba1abd..71ac0e2 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -149,6 +149,12 @@
 	depends on MSM_CAMERA && ARCH_MSM8960
 	default y
 
+config QS_MT9P017
+	bool "Sensor qs_mt9p017 (Aptina 3D 5M)"
+	depends on MSM_CAMERA
+	---help---
+	  Aptina 3D 5M with Autofocus
+
 config VB6801
 	bool "Sensor vb6801"
 	depends on MSM_CAMERA && !ARCH_MSM8X60 && !MSM_CAMERA_V4L2
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index c366834..0e8054f 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -35,6 +35,7 @@
   obj-$(CONFIG_IMX074) += imx074.o imx074_reg.o
 endif
 obj-$(CONFIG_QS_S5K4E1) += qs_s5k4e1.o qs_s5k4e1_reg.o
+obj-$(CONFIG_QS_MT9P017) += qs_mt9p017.o qs_mt9p017_reg.o
 obj-$(CONFIG_VB6801) += vb6801.o
 obj-$(CONFIG_IMX072) += imx072.o imx072_reg.o
 obj-$(CONFIG_OV2720) += ov2720.o
diff --git a/drivers/media/video/msm/qs_mt9p017.c b/drivers/media/video/msm/qs_mt9p017.c
new file mode 100644
index 0000000..f5bc070
--- /dev/null
+++ b/drivers/media/video/msm/qs_mt9p017.c
@@ -0,0 +1,1252 @@
+/* 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 <media/v4l2-subdev.h>
+#include <mach/gpio.h>
+#include <mach/camera.h>
+#include "qs_mt9p017.h"
+#include "msm.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
+#define REG_GR_GAIN						0x3056
+#define REG_R_GAIN						0x3058
+#define REG_B_GAIN						0x305A
+#define REG_GB_GAIN						0x305C
+
+/* PLL registers */
+#define REG_FRAME_LENGTH_LINES			0x300A
+#define REG_LINE_LENGTH_PCK				0x300C
+/* 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_MT9P017_MASTER_CLK_RATE 24000000
+#define QS_MT9P017_OFFSET			8
+
+/* AF Total steps parameters */
+#define QS_MT9P017_TOTAL_STEPS_NEAR_TO_FAR    32
+#define QS_MT9P017_NL_REGION_BOUNDARY 3
+#define QS_MT9P017_NL_REGION_CODE_PER_STEP 30
+#define QS_MT9P017_L_REGION_CODE_PER_STEP 4
+
+#define QS_MT9P017_BRIDGE_DBG 0
+
+static struct i2c_client *qs_mt9p017_client;
+
+struct qs_mt9p017_format {
+	enum v4l2_mbus_pixelcode code;
+	enum v4l2_colorspace colorspace;
+	u16 fmt;
+	u16 order;
+};
+
+struct qs_mt9p017_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_mt9p017_resolution_t prev_res;
+	enum qs_mt9p017_resolution_t pict_res;
+	enum qs_mt9p017_resolution_t curr_res;
+	enum qs_mt9p017_cam_mode_t cam_mode;
+	struct v4l2_subdev *sensor_dev;
+	struct qs_mt9p017_format *fmt;
+	uint16_t qs_mt9p017_step_position_table
+		[QS_MT9P017_TOTAL_STEPS_NEAR_TO_FAR+1];
+	uint16_t prev_line_length_pck;
+	uint16_t prev_frame_length_lines;
+	uint16_t snap_line_length_pck;
+	uint16_t snap_frame_length_lines;
+};
+
+static bool CSI_CONFIG;
+static struct qs_mt9p017_ctrl_t *qs_mt9p017_ctrl;
+DEFINE_MUTEX(qs_mt9p017_mut);
+/*=============================================================*/
+
+static int qs_mt9p017_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(qs_mt9p017_client->adapter, msgs, 2) < 0) {
+		CDBG("qs_mt9p017_i2c_rxdata faild 0x%x\n", saddr);
+		return -EIO;
+	}
+	return 0;
+}
+
+static int32_t qs_mt9p017_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_mt9p017_client->adapter, msg, 1) < 0) {
+		CDBG("qs_mt9p017_i2c_txdata faild 0x%x\n", saddr);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t qs_mt9p017_i2c_read(unsigned short raddr,
+	unsigned short *rdata, int rlen)
+{
+	int32_t rc = 0;
+	unsigned char buf[] = {
+		raddr >> BITS_PER_BYTE,
+		raddr,
+	};
+	if (!rdata)
+		return -EIO;
+	rc = qs_mt9p017_i2c_rxdata(qs_mt9p017_client->addr, buf, rlen);
+	if (rc < 0) {
+		CDBG("qs_mt9p017_i2c_read 0x%x failed!\n", raddr);
+		return rc;
+	}
+	*rdata = (rlen == 2 ? buf[0] << BITS_PER_BYTE | buf[1] : buf[0]);
+	CDBG("qs_mt9p017_i2c_read 0x%x val = 0x%x!\n", raddr, *rdata);
+	return rc;
+}
+
+static int32_t qs_mt9p017_i2c_write_w_sensor(unsigned short waddr,
+	uint16_t wdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[] = {
+		waddr >> BITS_PER_BYTE,
+		waddr,
+		wdata >> BITS_PER_BYTE,
+		wdata,
+	};
+	CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, wdata);
+	rc = qs_mt9p017_i2c_txdata(qs_mt9p017_client->addr, 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_mt9p017_i2c_write_b_sensor(unsigned short waddr,
+	uint8_t bdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[] = {
+		waddr >> BITS_PER_BYTE,
+		waddr,
+		bdata,
+	};
+	CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata);
+	rc = qs_mt9p017_i2c_txdata(qs_mt9p017_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 qs_mt9p017_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;
+	buf[0] = waddr >> BITS_PER_BYTE;
+	buf[1] = waddr;
+	for (i = 0; i < len; i++)
+		buf[i+2] = seq_data[i];
+	rc = qs_mt9p017_i2c_txdata(qs_mt9p017_client->addr, buf, len+2);
+	return rc;
+}
+
+static int32_t qs_mt9p017_i2c_write_w_table(struct qs_mt9p017_i2c_reg_conf const
+					 *reg_conf_tbl, int num)
+{
+	int i;
+	int32_t rc = -EIO;
+	for (i = 0; i < num; i++) {
+		rc = qs_mt9p017_i2c_write_w_sensor(reg_conf_tbl->waddr,
+			reg_conf_tbl->wdata);
+		if (rc < 0)
+			break;
+		reg_conf_tbl++;
+	}
+	return rc;
+}
+
+static int32_t bridge_i2c_write_w(unsigned short waddr, uint16_t wdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[] = {
+		waddr >> BITS_PER_BYTE,
+		waddr,
+		wdata >> BITS_PER_BYTE,
+		wdata,
+	};
+	CDBG("bridge_i2c_write_w addr = 0x%x, val = 0x%x\n", waddr, wdata);
+	rc = qs_mt9p017_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[] = {
+		raddr >> BITS_PER_BYTE,
+		raddr,
+	};
+	if (!rdata)
+		return -EIO;
+	rc = qs_mt9p017_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] << BITS_PER_BYTE | buf[1] : buf[0]);
+	CDBG("bridge_i2c_read 0x%x val = 0x%x!\n", raddr, *rdata);
+	return rc;
+}
+
+static int32_t qs_mt9p017_eeprom_i2c_read(unsigned short raddr,
+	unsigned char *rdata, int rlen)
+{
+	int32_t rc = 0;
+	unsigned short i2caddr = 0xA0 >> 1;
+	uint8_t block_num = 0;
+	unsigned char buf[rlen+2];
+	int i = 0;
+	if (!rdata)
+		return -EIO;
+
+	block_num = raddr >> BITS_PER_BYTE;
+	i2caddr |= block_num;
+
+	buf[0] = raddr >> BITS_PER_BYTE;
+	buf[1] = raddr;
+	rc = qs_mt9p017_i2c_rxdata(i2caddr, buf, rlen);
+	if (rc < 0) {
+		CDBG("qs_mt9p017_eeprom_i2c_read 0x%x failed!\n", raddr);
+		return rc;
+	}
+	for (i = 0; i < rlen; i++) {
+		rdata[i] = buf[i];
+		CDBG("qs_mt9p017_eeprom_i2c_read 0x%x index: %d val = 0x%x!\n",
+			raddr, i, buf[i]);
+	}
+	return rc;
+}
+
+static int32_t qs_mt9p017_eeprom_i2c_read_b(unsigned short raddr,
+	unsigned short *rdata, int rlen)
+{
+	int32_t rc = 0;
+	unsigned char buf[2];
+	rc = qs_mt9p017_eeprom_i2c_read(raddr, &buf[0], rlen);
+	*rdata = (rlen == 2 ? buf[0] << BITS_PER_BYTE | buf[1] : buf[0]);
+	CDBG("qs_mt9p017_eeprom_i2c_read 0x%x val = 0x%x!\n", raddr, *rdata);
+	return rc;
+}
+
+static int32_t qs_mt9p017_get_calibration_data(
+	struct sensor_3d_cali_data_t *cdata)
+{
+	struct qs_mt9p017_i2c_read_seq_t eeprom_read_seq_tbl[] = {
+		{0x0, &(cdata->left_p_matrix[0][0][0]), 96},
+		{0x60, &(cdata->right_p_matrix[0][0][0]), 96},
+		{0xC0, &(cdata->square_len[0]), 8},
+		{0xC8, &(cdata->focal_len[0]), 8},
+		{0xD0, &(cdata->pixel_pitch[0]), 8},
+	};
+
+	struct qs_mt9p017_i2c_read_t eeprom_read_tbl[] = {
+		{0x100, &(cdata->left_r), 1},
+		{0x101, &(cdata->right_r), 1},
+		{0x102, &(cdata->left_b), 1},
+		{0x103, &(cdata->right_b), 1},
+		{0x104, &(cdata->left_gb), 1},
+		{0x105, &(cdata->right_gb), 1},
+		{0x110, &(cdata->left_af_far), 2},
+		{0x112, &(cdata->right_af_far), 2},
+		{0x114, &(cdata->left_af_mid), 2},
+		{0x116, &(cdata->right_af_mid), 2},
+		{0x118, &(cdata->left_af_short), 2},
+		{0x11A, &(cdata->right_af_short), 2},
+		{0x11C, &(cdata->left_af_5um), 2},
+		{0x11E, &(cdata->right_af_5um), 2},
+		{0x120, &(cdata->left_af_50up), 2},
+		{0x122, &(cdata->right_af_50up), 2},
+		{0x124, &(cdata->left_af_50down), 2},
+		{0x126, &(cdata->right_af_50down), 2},
+	};
+
+	int i;
+	for (i = 0; i < ARRAY_SIZE(eeprom_read_seq_tbl); i++) {
+		qs_mt9p017_eeprom_i2c_read(
+			eeprom_read_seq_tbl[i].raddr,
+			eeprom_read_seq_tbl[i].rdata,
+			eeprom_read_seq_tbl[i].rlen);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(eeprom_read_tbl); i++) {
+		qs_mt9p017_eeprom_i2c_read_b(
+			eeprom_read_tbl[i].raddr,
+			eeprom_read_tbl[i].rdata,
+			eeprom_read_tbl[i].rlen);
+	}
+	return 0;
+}
+
+static int32_t qs_mt9p017_load_left_lsc(void)
+{
+	int i;
+	unsigned char left_lsc1[210];
+	unsigned short left_origin_c, left_origin_r;
+	struct qs_mt9p017_i2c_reg_conf lsc_conf[] = {
+		{0x37C0, 0x0000},
+		{0x37C2, 0x0000},
+		{0x37C4, 0x0000},
+		{0x37C6, 0x0000},
+		{0x3780, 0x8000},
+	};
+	qs_mt9p017_eeprom_i2c_read(0x200, &left_lsc1[0], 126);
+	qs_mt9p017_eeprom_i2c_read_b(0x27E, &left_origin_c, 2);
+	qs_mt9p017_eeprom_i2c_read_b(0x280, &left_origin_r, 2);
+	bridge_i2c_write_w(0x06, 0x01);
+	qs_mt9p017_i2c_write_seq_sensor(0x3600, left_lsc1, 126);
+	qs_mt9p017_i2c_write_w_sensor(0x3782, left_origin_c);
+	qs_mt9p017_i2c_write_w_sensor(0x3784, left_origin_r);
+	for (i = 0; i < ARRAY_SIZE(lsc_conf); i++) {
+		qs_mt9p017_i2c_write_w_sensor(
+			lsc_conf[i].waddr, lsc_conf[i].wdata);
+	}
+	return 0;
+}
+
+static int32_t qs_mt9p017_load_right_lsc(void)
+{
+	int i;
+	unsigned char right_lsc1[210];
+	unsigned short right_origin_c, right_origin_r;
+	struct qs_mt9p017_i2c_reg_conf lsc_conf[] = {
+		{0x37C0, 0x0000},
+		{0x37C2, 0x0000},
+		{0x37C4, 0x0000},
+		{0x37C6, 0x0000},
+		{0x3780, 0x8000},
+	};
+	qs_mt9p017_eeprom_i2c_read(0x2D2, &right_lsc1[0], 126);
+	qs_mt9p017_eeprom_i2c_read_b(0x350, &right_origin_c, 2);
+	qs_mt9p017_eeprom_i2c_read_b(0x352, &right_origin_r, 2);
+	bridge_i2c_write_w(0x06, 0x02);
+	qs_mt9p017_i2c_write_seq_sensor(0x3600, right_lsc1, 126);
+	qs_mt9p017_i2c_write_w_sensor(0x3782, right_origin_c);
+	qs_mt9p017_i2c_write_w_sensor(0x3784, right_origin_r);
+
+	for (i = 0; i < ARRAY_SIZE(lsc_conf); i++) {
+		qs_mt9p017_i2c_write_w_sensor(
+			lsc_conf[i].waddr, lsc_conf[i].wdata);
+	}
+	return 0;
+}
+
+static int32_t qs_mt9p017_load_lsc(void)
+{
+	qs_mt9p017_load_left_lsc();
+	qs_mt9p017_load_right_lsc();
+	return 0;
+}
+
+static int32_t af_i2c_write_b_sensor(unsigned short baddr, uint8_t bdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[2];
+	buf[0] = baddr;
+	buf[1] = bdata;
+	CDBG("af i2c_write_b addr = 0x%x, val = 0x%x\n", baddr, bdata);
+	rc = qs_mt9p017_i2c_txdata(AF_ADDR>>1, buf, 2);
+	if (rc < 0) {
+		CDBG("af i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+			baddr, bdata);
+	}
+	return rc;
+}
+
+static void qs_mt9p017_bridge_reset(void){
+	unsigned short rstl_state = 0, gpio_state = 0;
+	bridge_i2c_write_w(0x50, 0x00);
+	bridge_i2c_write_w(0x53, 0x00);
+	msleep(30);
+	bridge_i2c_write_w(0x53, 0x01);
+	msleep(30);
+	bridge_i2c_write_w(0x14, 0x0C);
+	bridge_i2c_write_w(0x0E, 0xFFFF);
+
+	bridge_i2c_read(0x54, &rstl_state, 2);
+	bridge_i2c_write_w(0x54, (rstl_state | 0x1));
+	msleep(30);
+	bridge_i2c_write_w(0x54, (rstl_state | 0x3));
+	bridge_i2c_read(0x54, &rstl_state, 2);
+	bridge_i2c_write_w(0x54, (rstl_state | 0x4));
+	bridge_i2c_write_w(0x54, (rstl_state | 0xC));
+
+	bridge_i2c_read(0x55, &gpio_state, 2);
+	bridge_i2c_write_w(0x55, (gpio_state | 0x1));
+	msleep(30);
+	bridge_i2c_write_w(0x55, (gpio_state | 0x3));
+
+	bridge_i2c_read(0x55, &gpio_state, 2);
+	bridge_i2c_write_w(0x55, (gpio_state | 0x4));
+	msleep(30);
+	bridge_i2c_write_w(0x55, (gpio_state | 0xC));
+	bridge_i2c_read(0x55, &gpio_state, 2);
+}
+
+static void qs_mt9p017_bridge_config(int mode, int rt)
+{
+	if (mode == MODE_3D) {
+		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, 0x6C18);
+		bridge_i2c_write_w(0x50, 0x00);
+	} else if (mode == MODE_2D_LEFT) {
+		bridge_i2c_write_w(0x06, 0x01);
+		bridge_i2c_write_w(0x04, 0x6C18);
+		bridge_i2c_write_w(0x50, 0x01);
+	} else if (mode == MODE_2D_RIGHT) {
+		bridge_i2c_write_w(0x06, 0x02);
+		bridge_i2c_write_w(0x04, 0x6C18);
+		bridge_i2c_write_w(0x50, 0x02);
+	}
+}
+
+static void qs_mt9p017_group_hold_on(void)
+{
+	qs_mt9p017_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
+						GROUPED_PARAMETER_HOLD);
+}
+
+static void qs_mt9p017_group_hold_off(void)
+{
+	qs_mt9p017_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
+						GROUPED_PARAMETER_HOLD_OFF);
+}
+
+static void qs_mt9p017_start_stream(void)
+{
+	qs_mt9p017_i2c_write_w_sensor(0x301A, 0x065C|0x2);
+}
+
+static void qs_mt9p017_stop_stream(void)
+{
+	qs_mt9p017_i2c_write_b_sensor(0x0100, 0x00);
+}
+
+static void qs_mt9p017_get_pict_fps(uint16_t fps, uint16_t *pfps)
+{
+	/* input fps is preview fps in Q8 format */
+	uint32_t divider, d1, d2;
+
+	d1 = qs_mt9p017_ctrl->prev_frame_length_lines * 0x400
+		/ qs_mt9p017_ctrl->snap_frame_length_lines;
+	d2 = qs_mt9p017_ctrl->prev_line_length_pck * 0x400
+		/ qs_mt9p017_ctrl->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 int32_t qs_mt9p017_set_fps(struct fps_cfg   *fps)
+{
+	uint16_t total_lines_per_frame;
+	int32_t rc = 0;
+	total_lines_per_frame = (uint16_t)
+		((qs_mt9p017_ctrl->prev_frame_length_lines) *
+		qs_mt9p017_ctrl->fps_divider/0x400);
+	qs_mt9p017_ctrl->fps_divider = fps->fps_div;
+	qs_mt9p017_ctrl->pict_fps_divider = fps->pict_fps_div;
+
+	qs_mt9p017_group_hold_on();
+	rc = qs_mt9p017_i2c_write_w_sensor(REG_FRAME_LENGTH_LINES,
+							total_lines_per_frame);
+	qs_mt9p017_group_hold_off();
+	return rc;
+}
+
+static int32_t qs_mt9p017_write_exp_gain(struct sensor_3d_exp_cfg exp_cfg)
+{
+	uint16_t max_legal_gain = 0xE7F;
+	uint16_t gain = exp_cfg.gain;
+	uint32_t line = exp_cfg.line;
+	int32_t rc = 0;
+	if (gain > max_legal_gain) {
+		CDBG("Max legal gain Line:%d\n", __LINE__);
+		gain = max_legal_gain;
+	}
+	qs_mt9p017_group_hold_on();
+	rc = qs_mt9p017_i2c_write_w_sensor(REG_GLOBAL_GAIN, gain|0x1000);
+	rc = qs_mt9p017_i2c_write_w_sensor(REG_COARSE_INTEGRATION_TIME, line);
+	if (qs_mt9p017_ctrl->cam_mode == MODE_3D) {
+		bridge_i2c_write_w(0x06, 0x02);
+		rc = qs_mt9p017_i2c_write_w_sensor(REG_GR_GAIN, gain|0x1000);
+		rc = qs_mt9p017_i2c_write_w_sensor(REG_R_GAIN,
+				exp_cfg.r_gain|0x1000);
+		rc = qs_mt9p017_i2c_write_w_sensor(REG_B_GAIN,
+				exp_cfg.b_gain|0x1000);
+		rc = qs_mt9p017_i2c_write_w_sensor(REG_GB_GAIN,
+				exp_cfg.gb_gain|0x1000);
+		bridge_i2c_write_w(0x06, 0x03);
+	}
+	qs_mt9p017_group_hold_off();
+	return rc;
+}
+
+static int32_t qs_mt9p017_set_pict_exp_gain(struct sensor_3d_exp_cfg exp_cfg)
+{
+	int32_t rc = 0;
+	rc = qs_mt9p017_write_exp_gain(exp_cfg);
+	qs_mt9p017_i2c_write_w_sensor(0x301A, 0x065C|0x2);
+	return rc;
+}
+
+static int32_t qs_mt9p017_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 * (int16_t) num_steps);
+	next_position = (int16_t) (qs_mt9p017_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 >> 8;
+	code_val_lsb = (next_position & 0x00FF);
+	af_i2c_write_b_sensor(0x4, code_val_msb);
+	af_i2c_write_b_sensor(0x5, code_val_lsb);
+
+	qs_mt9p017_ctrl->curr_lens_pos = next_position;
+	return 0;
+}
+
+static int32_t qs_mt9p017_set_default_focus(uint8_t af_step)
+{
+	int32_t rc = 0;
+	if (qs_mt9p017_ctrl->curr_step_pos != 0) {
+		rc = qs_mt9p017_move_focus(MOVE_FAR,
+		qs_mt9p017_ctrl->curr_step_pos);
+	} else {
+		af_i2c_write_b_sensor(0x4, 0);
+		af_i2c_write_b_sensor(0x5, 0);
+	}
+
+	qs_mt9p017_ctrl->curr_lens_pos = 0;
+	qs_mt9p017_ctrl->curr_step_pos = 0;
+
+	return rc;
+}
+
+static void qs_mt9p017_init_focus(void)
+{
+	uint8_t i;
+	qs_mt9p017_ctrl->qs_mt9p017_step_position_table[0] = 0;
+	for (i = 1; i <= QS_MT9P017_TOTAL_STEPS_NEAR_TO_FAR; i++) {
+		if (i <= QS_MT9P017_NL_REGION_BOUNDARY) {
+			qs_mt9p017_ctrl->qs_mt9p017_step_position_table[i] =
+			qs_mt9p017_ctrl->qs_mt9p017_step_position_table[i-1]
+				+ QS_MT9P017_NL_REGION_CODE_PER_STEP;
+		} else {
+			qs_mt9p017_ctrl->qs_mt9p017_step_position_table[i] =
+			qs_mt9p017_ctrl->qs_mt9p017_step_position_table[i-1]
+				+ QS_MT9P017_L_REGION_CODE_PER_STEP;
+		}
+
+		if (qs_mt9p017_ctrl->qs_mt9p017_step_position_table[i] > 255)
+			qs_mt9p017_ctrl->
+			qs_mt9p017_step_position_table[i] = 255;
+	}
+}
+
+static int32_t qs_mt9p017_sensor_setting(int update_type, int rt)
+{
+
+	int32_t rc = 0, i;
+	uint16_t read_data;
+	struct msm_camera_csid_params qs_mt9p017_csid_params;
+	struct msm_camera_csiphy_params qs_mt9p017_csiphy_params;
+	qs_mt9p017_stop_stream();
+	msleep(30);
+	bridge_i2c_write_w(0x53, 0x00);
+	msleep(30);
+	if (update_type == REG_INIT) {
+		CSI_CONFIG = 0;
+		qs_mt9p017_bridge_config(qs_mt9p017_ctrl->cam_mode, rt);
+		qs_mt9p017_i2c_write_w_table(qs_mt9p017_regs.rec_settings,
+			qs_mt9p017_regs.rec_size);
+		if (qs_mt9p017_ctrl->cam_mode == MODE_3D)
+			qs_mt9p017_i2c_write_w_table(qs_mt9p017_regs.reg_3d_pll,
+			qs_mt9p017_regs.reg_3d_pll_size);
+		else
+			qs_mt9p017_i2c_write_w_table(qs_mt9p017_regs.reg_pll,
+			qs_mt9p017_regs.reg_pll_size);
+		qs_mt9p017_i2c_write_w_table(qs_mt9p017_regs.reg_lens,
+			qs_mt9p017_regs.reg_lens_size);
+		qs_mt9p017_i2c_read(0x31BE, &read_data, 2);
+		qs_mt9p017_i2c_write_w_sensor(0x31BE, read_data | 0x4);
+	} else if (update_type == UPDATE_PERIODIC) {
+		qs_mt9p017_i2c_write_w_table(
+			qs_mt9p017_regs.conf_array[rt].conf,
+			qs_mt9p017_regs.conf_array[rt].size);
+
+		msleep(20);
+		bridge_i2c_write_w(0x53, 0x01);
+		msleep(30);
+		if (!CSI_CONFIG) {
+			if (qs_mt9p017_ctrl->cam_mode == MODE_3D) {
+				struct msm_camera_csid_vc_cfg
+					qs_mt9p017_vccfg[] = {
+					{0, CSI_RAW10, CSI_DECODE_10BIT},
+					{1, CSI_EMBED_DATA, CSI_DECODE_8BIT},
+				};
+				qs_mt9p017_csid_params.lane_cnt = 4;
+				qs_mt9p017_csiphy_params.lane_cnt = 4;
+				qs_mt9p017_csid_params.lut_params.num_cid =
+					ARRAY_SIZE(qs_mt9p017_vccfg);
+				qs_mt9p017_csid_params.lut_params.vc_cfg =
+					&qs_mt9p017_vccfg[0];
+			} else {
+				struct msm_camera_csid_vc_cfg
+					qs_mt9p017_vccfg[] = {
+					{0, CSI_RAW10, CSI_DECODE_10BIT},
+					{1, CSI_EMBED_DATA, CSI_DECODE_8BIT},
+				};
+				qs_mt9p017_csid_params.lane_cnt = 2;
+				qs_mt9p017_csiphy_params.lane_cnt = 2;
+				qs_mt9p017_csid_params.lut_params.num_cid =
+					ARRAY_SIZE(qs_mt9p017_vccfg);
+				qs_mt9p017_csid_params.lut_params.vc_cfg =
+					&qs_mt9p017_vccfg[0];
+			}
+			qs_mt9p017_csid_params.lane_assign = 0xe4;
+			qs_mt9p017_csiphy_params.settle_cnt = 0x18;
+			rc = msm_camio_csid_config(&qs_mt9p017_csid_params);
+			rc = msm_camio_csiphy_config
+				(&qs_mt9p017_csiphy_params);
+			v4l2_subdev_notify(qs_mt9p017_ctrl->sensor_dev,
+					NOTIFY_CID_CHANGE, NULL);
+			msleep(100);
+			CSI_CONFIG = 1;
+		}
+		qs_mt9p017_start_stream();
+		msleep(30);
+
+		for (i = 0; i < QS_MT9P017_BRIDGE_DBG; i++) {
+			bridge_i2c_read(0x10, &read_data, 2);
+			CDBG("IRQ Status: 0x%x\n", read_data);
+			bridge_i2c_read(0x0A, &read_data, 2);
+			CDBG("Skew Value: 0x%x\n", read_data);
+		}
+	}
+	return rc;
+}
+
+static int32_t qs_mt9p017_video_config(int mode)
+{
+
+	int32_t rc = 0;
+	/* change sensor resolution if needed */
+	rc = qs_mt9p017_sensor_setting(UPDATE_PERIODIC,
+		qs_mt9p017_ctrl->prev_res);
+	if (rc < 0)
+		return rc;
+
+	qs_mt9p017_ctrl->curr_res = qs_mt9p017_ctrl->prev_res;
+	qs_mt9p017_ctrl->sensormode = mode;
+	return rc;
+}
+
+static int32_t qs_mt9p017_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+	/*change sensor resolution if needed */
+	if (qs_mt9p017_ctrl->curr_res != qs_mt9p017_ctrl->pict_res) {
+		rc = qs_mt9p017_sensor_setting(UPDATE_PERIODIC,
+					qs_mt9p017_ctrl->pict_res);
+		if (rc < 0)
+			return rc;
+	}
+
+	qs_mt9p017_ctrl->curr_res = qs_mt9p017_ctrl->pict_res;
+	qs_mt9p017_ctrl->sensormode = mode;
+	return rc;
+} /*end of qs_mt9p017_snapshot_config*/
+
+static int32_t qs_mt9p017_raw_snapshot_config(int mode)
+{
+	int32_t rc = 0;
+	/* change sensor resolution if needed */
+	if (qs_mt9p017_ctrl->curr_res != qs_mt9p017_ctrl->pict_res) {
+		rc = qs_mt9p017_sensor_setting(UPDATE_PERIODIC,
+					qs_mt9p017_ctrl->pict_res);
+		if (rc < 0)
+			return rc;
+	}
+
+	qs_mt9p017_ctrl->curr_res = qs_mt9p017_ctrl->pict_res;
+	qs_mt9p017_ctrl->sensormode = mode;
+	return rc;
+} /*end of qs_mt9p017_raw_snapshot_config*/
+
+static int32_t qs_mt9p017_mode_init(int mode, struct sensor_init_cfg init_info)
+{
+	int32_t rc = 0;
+	if (mode == qs_mt9p017_ctrl->cam_mode)
+		return rc;
+
+	qs_mt9p017_ctrl->prev_res = init_info.prev_res;
+	qs_mt9p017_ctrl->pict_res = init_info.pict_res;
+	qs_mt9p017_ctrl->cam_mode = mode;
+
+	qs_mt9p017_ctrl->prev_frame_length_lines =
+		qs_mt9p017_regs.conf_array[qs_mt9p017_ctrl->prev_res].
+		conf[QS_MT9P017_FRAME_LENGTH_LINES].wdata;
+	qs_mt9p017_ctrl->prev_line_length_pck =
+		qs_mt9p017_regs.conf_array[qs_mt9p017_ctrl->prev_res].
+		conf[QS_MT9P017_LINE_LENGTH_PCK].wdata;
+	qs_mt9p017_ctrl->snap_frame_length_lines =
+		qs_mt9p017_regs.conf_array[qs_mt9p017_ctrl->pict_res].
+		conf[QS_MT9P017_FRAME_LENGTH_LINES].wdata;
+	qs_mt9p017_ctrl->snap_line_length_pck =
+		qs_mt9p017_regs.conf_array[qs_mt9p017_ctrl->pict_res].
+		conf[QS_MT9P017_LINE_LENGTH_PCK].wdata;
+
+	if (mode == MODE_2D_LEFT)
+		qs_mt9p017_load_left_lsc();
+	else if (mode == MODE_2D_RIGHT)
+		qs_mt9p017_load_right_lsc();
+	else
+		qs_mt9p017_load_lsc();
+
+	rc = qs_mt9p017_sensor_setting(REG_INIT,
+		qs_mt9p017_ctrl->prev_res);
+	return rc;
+}
+
+static int32_t qs_mt9p017_set_sensor_mode(int mode, int res)
+{
+	int32_t rc = 0;
+
+	switch (mode) {
+	case SENSOR_PREVIEW_MODE:
+		qs_mt9p017_ctrl->prev_res = res;
+		rc = qs_mt9p017_video_config(mode);
+		break;
+	case SENSOR_SNAPSHOT_MODE:
+		qs_mt9p017_ctrl->pict_res = res;
+		rc = qs_mt9p017_snapshot_config(mode);
+		break;
+	case SENSOR_RAW_SNAPSHOT_MODE:
+		qs_mt9p017_ctrl->pict_res = res;
+		rc = qs_mt9p017_raw_snapshot_config(mode);
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+static int32_t qs_mt9p017_check_id(void){
+	int rc;
+	uint16_t chipid = 0x0;
+
+	rc = qs_mt9p017_i2c_read(0x0000, &chipid, 2);
+	if (rc < 0)
+		return rc;
+
+	CDBG(KERN_ERR "qs_mt9p017 model_id = 0x%x\n", chipid);
+	if (chipid != 0x4800) {
+		rc = -ENODEV;
+		CDBG("qs_mt9p017 fail chip id doesnot match\n");
+	}
+	return rc;
+}
+
+static int32_t qs_mt9p017_power_up(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc = 0;
+	rc = gpio_request(data->sensor_reset, "qs_mt9p017");
+	CDBG("%s\n", __func__);
+	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 {
+		CDBG("sensor reset fail");
+	}
+	qs_mt9p017_bridge_reset();
+	qs_mt9p017_bridge_config(MODE_3D, RES_PREVIEW);
+	msleep(30);
+	return rc;
+}
+
+static int32_t qs_mt9p017_power_down(const struct msm_camera_sensor_info *data)
+{
+	gpio_set_value_cansleep(data->sensor_reset, 0);
+	gpio_free(data->sensor_reset);
+	return 0;
+}
+
+static int qs_mt9p017_sensor_open_init
+	(const struct msm_camera_sensor_info *data)
+{
+	int32_t rc = 0;
+	CDBG("%s: %d\n", __func__, __LINE__);
+	qs_mt9p017_ctrl->fps_divider = 1 * 0x00000400;
+	qs_mt9p017_ctrl->pict_fps_divider = 1 * 0x00000400;
+	qs_mt9p017_ctrl->cam_mode = MODE_INVALID;
+	qs_mt9p017_ctrl->fps = 30*Q8;
+
+	if (data)
+		qs_mt9p017_ctrl->sensordata = data;
+
+	msm_camio_clk_rate_set(QS_MT9P017_MASTER_CLK_RATE);
+	msleep(20);
+
+	rc = qs_mt9p017_power_up(data);
+	if (rc < 0) {
+		CDBG("Calling qs_mt9p017_sensor_open_init fail\n");
+		return rc;
+	}
+
+	qs_mt9p017_init_focus();
+	return rc;
+}
+
+static const struct i2c_device_id qs_mt9p017_i2c_id[] = {
+	{"qs_mt9p017", 0},
+	{ }
+};
+
+static int qs_mt9p017_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int rc = 0;
+	CDBG("qs_mt9p017_probe called!\n");
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		CDBG("i2c_check_functionality failed\n");
+		rc = -1;
+		goto probe_failure;
+	}
+
+	qs_mt9p017_client = client;
+	CDBG("qs_mt9p017_probe successed! rc = %d\n", rc);
+	return rc;
+
+probe_failure:
+	CDBG("qs_mt9p017_probe failed! rc = %d\n", rc);
+	return rc;
+}
+
+static int __exit qs_mt9p017_i2c_remove(struct i2c_client *client)
+{
+	qs_mt9p017_client = NULL;
+	return 0;
+}
+
+static struct i2c_driver qs_mt9p017_i2c_driver = {
+	.id_table = qs_mt9p017_i2c_id,
+	.probe  = qs_mt9p017_i2c_probe,
+	.remove = __exit_p(qs_mt9p017_i2c_remove),
+	.driver = {
+		.name = "qs_mt9p017",
+	},
+};
+
+static int qs_mt9p017_3D_sensor_config(void __user *argp)
+{
+	struct sensor_large_data cdata;
+	int rc;
+	if (copy_from_user(&cdata,
+		(void *)argp,
+		sizeof(struct sensor_large_data)))
+		return -EFAULT;
+	mutex_lock(&qs_mt9p017_mut);
+	rc = qs_mt9p017_get_calibration_data
+		(&cdata.data.sensor_3d_cali_data);
+	if (copy_to_user((void *)argp,
+		&cdata,
+		sizeof(struct sensor_large_data)))
+		rc = -EFAULT;
+	mutex_unlock(&qs_mt9p017_mut);
+	return rc;
+}
+
+static int qs_mt9p017_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_mt9p017_mut);
+	CDBG("qs_mt9p017_sensor_config: cfgtype = %d\n",
+	cdata.cfgtype);
+	switch (cdata.cfgtype) {
+	case CFG_GET_PICT_FPS:
+		qs_mt9p017_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_mt9p017_ctrl->prev_frame_length_lines;
+
+		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_mt9p017_ctrl->prev_line_length_pck;
+
+		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_mt9p017_ctrl->snap_frame_length_lines;
+
+		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_mt9p017_ctrl->snap_line_length_pck;
+
+		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_mt9p017_ctrl->snap_frame_length_lines * 24;
+
+		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_mt9p017_set_fps(&(cdata.cfg.fps));
+		break;
+
+	case CFG_SET_EXP_GAIN:
+		rc =
+			qs_mt9p017_write_exp_gain(
+				cdata.cfg.sensor_3d_exp);
+		break;
+
+	case CFG_SET_PICT_EXP_GAIN:
+		rc =
+			qs_mt9p017_set_pict_exp_gain(
+			cdata.cfg.sensor_3d_exp);
+		break;
+
+	case CFG_SET_MODE:
+		rc = qs_mt9p017_set_sensor_mode(cdata.mode,
+				cdata.rs);
+		break;
+
+	case CFG_PWR_DOWN:
+		rc = qs_mt9p017_power_down(qs_mt9p017_ctrl->sensordata);
+		break;
+
+	case CFG_MOVE_FOCUS:
+		rc =
+			qs_mt9p017_move_focus(
+			cdata.cfg.focus.dir,
+			cdata.cfg.focus.steps);
+		break;
+
+	case CFG_SET_DEFAULT_FOCUS:
+		rc =
+			qs_mt9p017_set_default_focus(
+			cdata.cfg.focus.steps);
+		break;
+
+	case CFG_GET_AF_MAX_STEPS:
+		cdata.max_steps = QS_MT9P017_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_mt9p017_set_default_focus(
+			cdata.cfg.effect);
+		break;
+
+	case CFG_SENSOR_INIT:
+		rc = qs_mt9p017_mode_init(cdata.mode,
+				cdata.cfg.init_info);
+		break;
+
+	default:
+		rc = -EFAULT;
+		break;
+	}
+
+	mutex_unlock(&qs_mt9p017_mut);
+
+	return rc;
+}
+
+static int qs_mt9p017_sensor_config(void __user *argp)
+{
+	int cfgtype;
+	if (copy_from_user(&cfgtype,
+		(void *)argp,
+		sizeof(int)))
+		return -EFAULT;
+	if (cfgtype != CFG_GET_3D_CALI_DATA)
+		qs_mt9p017_2D_sensor_config(argp);
+	else
+		qs_mt9p017_3D_sensor_config(argp);
+	return 0;
+}
+
+static int qs_mt9p017_sensor_release(void)
+{
+	int rc = -EBADF;
+	mutex_lock(&qs_mt9p017_mut);
+	qs_mt9p017_power_down(qs_mt9p017_ctrl->sensordata);
+	mutex_unlock(&qs_mt9p017_mut);
+	return rc;
+}
+
+static int qs_mt9p017_sensor_probe(const struct msm_camera_sensor_info *info,
+		struct msm_sensor_ctrl *s)
+{
+	int rc = 0;
+	rc = i2c_add_driver(&qs_mt9p017_i2c_driver);
+	if (rc < 0 || qs_mt9p017_client == NULL) {
+		rc = -ENOTSUPP;
+		CDBG("I2C add driver failed");
+		goto i2c_probe_fail;
+	}
+	msm_camio_clk_rate_set(QS_MT9P017_MASTER_CLK_RATE);
+	rc = qs_mt9p017_power_up(info);
+	if (rc < 0)
+		goto gpio_request_fail;
+
+	rc = qs_mt9p017_check_id();
+	if (rc < 0) {
+		qs_mt9p017_power_down(info);
+		goto i2c_probe_fail;
+	}
+	s->s_init = qs_mt9p017_sensor_open_init;
+	s->s_release = qs_mt9p017_sensor_release;
+	s->s_config  = qs_mt9p017_sensor_config;
+	s->s_mount_angle = 270;
+
+	qs_mt9p017_power_down(info);
+	return rc;
+
+gpio_request_fail:
+	pr_err("%s: gpio request fail\n", __func__);
+i2c_probe_fail:
+	CDBG("qs_mt9p017_sensor_probe: probe failed!\n");
+	i2c_del_driver(&qs_mt9p017_i2c_driver);
+	return rc;
+}
+
+static struct qs_mt9p017_format qs_mt9p017_subdev_info[] = {
+	{
+		.code   = V4L2_MBUS_FMT_YUYV8_2X8,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.fmt    = 1,
+		.order    = 0,
+	},
+};
+
+static int qs_mt9p017_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+			   enum v4l2_mbus_pixelcode *code)
+{
+	CDBG(KERN_DEBUG "Index is %d\n", index);
+	if (index >= ARRAY_SIZE(qs_mt9p017_subdev_info))
+		return -EINVAL;
+
+	*code = qs_mt9p017_subdev_info[index].code;
+	return 0;
+}
+
+static struct v4l2_subdev_core_ops qs_mt9p017_subdev_core_ops;
+static struct v4l2_subdev_video_ops qs_mt9p017_subdev_video_ops = {
+	.enum_mbus_fmt = qs_mt9p017_enum_fmt,
+};
+
+static struct v4l2_subdev_ops qs_mt9p017_subdev_ops = {
+	.core = &qs_mt9p017_subdev_core_ops,
+	.video  = &qs_mt9p017_subdev_video_ops,
+};
+
+
+static int qs_mt9p017_sensor_probe_cb(const struct msm_camera_sensor_info *info,
+	struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s)
+{
+	int rc = 0;
+	qs_mt9p017_ctrl = kzalloc(sizeof(struct qs_mt9p017_ctrl_t), GFP_KERNEL);
+	if (!qs_mt9p017_ctrl) {
+		CDBG("qs_mt9p017_sensor_probe failed!\n");
+		return -ENOMEM;
+	}
+
+	rc = qs_mt9p017_sensor_probe(info, s);
+	if (rc < 0) {
+		kfree(qs_mt9p017_ctrl);
+		return rc;
+	}
+
+	/* probe is successful, init a v4l2 subdevice */
+	CDBG(KERN_DEBUG "going into v4l2_i2c_subdev_init\n");
+	if (sdev) {
+		v4l2_i2c_subdev_init(sdev, qs_mt9p017_client,
+						&qs_mt9p017_subdev_ops);
+		qs_mt9p017_ctrl->sensor_dev = sdev;
+	}
+	return rc;
+}
+
+static int __qs_mt9p017_probe(struct platform_device *pdev)
+{
+	return msm_sensor_register(pdev, qs_mt9p017_sensor_probe_cb);
+}
+
+static struct platform_driver msm_camera_driver = {
+	.probe = __qs_mt9p017_probe,
+	.driver = {
+		.name = "msm_camera_qs_mt9p017",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init qs_mt9p017_init(void)
+{
+	return platform_driver_register(&msm_camera_driver);
+}
+
+static void __exit qs_mt9p017_exit(void)
+{
+	platform_driver_unregister(&msm_camera_driver);
+}
+module_init(qs_mt9p017_init);
+module_exit(qs_mt9p017_exit);
+MODULE_DESCRIPTION("Aptina 8 MP Bayer sensor driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/media/video/msm/qs_mt9p017.h b/drivers/media/video/msm/qs_mt9p017.h
new file mode 100644
index 0000000..8ac1cc1
--- /dev/null
+++ b/drivers/media/video/msm/qs_mt9p017.h
@@ -0,0 +1,95 @@
+/* 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_MT9P017_H
+#define QS_MT9P017_H
+#include <linux/types.h>
+#include <linux/kernel.h>
+extern struct qs_mt9p017_reg qs_mt9p017_regs;
+
+struct qs_mt9p017_i2c_reg_conf {
+	unsigned short waddr;
+	unsigned short wdata;
+};
+
+struct qs_mt9p017_i2c_conf_array {
+	struct qs_mt9p017_i2c_reg_conf *conf;
+	unsigned short size;
+};
+
+struct qs_mt9p017_i2c_read_t {
+	unsigned short raddr;
+	unsigned short *rdata;
+	int rlen;
+};
+
+struct qs_mt9p017_i2c_read_seq_t {
+	unsigned short raddr;
+	unsigned char *rdata;
+	int rlen;
+};
+
+enum qs_mt9p017_test_mode_t {
+	TEST_OFF,
+	TEST_1,
+	TEST_2,
+	TEST_3
+};
+
+enum qs_mt9p017_resolution_t {
+	QTR_2D_SIZE,
+	FULL_2D_SIZE,
+	QTR_3D_SIZE,
+	FULL_3D_SIZE,
+	INVALID_SIZE
+};
+enum qs_mt9p017_setting {
+	RES_PREVIEW,
+	RES_CAPTURE,
+	RES_3D_PREVIEW,
+	RES_3D_CAPTURE
+};
+enum qs_mt9p017_cam_mode_t {
+	MODE_2D_RIGHT,
+	MODE_2D_LEFT,
+	MODE_3D,
+	MODE_INVALID
+};
+enum qs_mt9p017_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_mt9p017_reg_mode {
+	QS_MT9P017_LINE_LENGTH_PCK = 7,
+	QS_MT9P017_FRAME_LENGTH_LINES,
+};
+
+struct qs_mt9p017_reg {
+	const struct qs_mt9p017_i2c_reg_conf *rec_settings;
+	const unsigned short rec_size;
+	const struct qs_mt9p017_i2c_reg_conf *reg_pll;
+	const unsigned short reg_pll_size;
+	const struct qs_mt9p017_i2c_reg_conf *reg_3d_pll;
+	const unsigned short reg_3d_pll_size;
+	const struct qs_mt9p017_i2c_reg_conf *reg_lens;
+	const unsigned short reg_lens_size;
+	const struct qs_mt9p017_i2c_conf_array *conf_array;
+};
+#endif /* QS_MT9P017_H */
diff --git a/drivers/media/video/msm/qs_mt9p017_reg.c b/drivers/media/video/msm/qs_mt9p017_reg.c
new file mode 100644
index 0000000..04715a2
--- /dev/null
+++ b/drivers/media/video/msm/qs_mt9p017_reg.c
@@ -0,0 +1,352 @@
+/* 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_mt9p017.h"
+
+struct qs_mt9p017_i2c_reg_conf qs_mt9p017_pll_settings[] = {
+	{0x301A, 0x0018},/*reset_register*/
+	{0x3064, 0x7800},/*smia_test_2lane_mipi*/
+	{0x31AE, 0x0202},/*dual_lane_MIPI_interface*/
+	{0x0300, 0x0005},/*vt_pix_clk_div*/
+	{0x0302, 0x0001},/*vt_sys_clk_div*/
+	{0x0304, 0x0002},/*pre_pll_clk_div*/
+	{0x0306, 0x002C},/*pll_multipler*/
+	{0x0308, 0x000A},/*op_pix_clk_div*/
+	{0x030A, 0x0001} /*op_sys_clk_div*/
+};
+
+struct qs_mt9p017_i2c_reg_conf qs_mt9p017_3d_pll_settings[] = {
+	{0x301A, 0x0018},/*reset_register*/
+	{0x3064, 0x7800},/*smia_test_2lane_mipi*/
+	{0x31AE, 0x0202},/*dual_lane_MIPI_interface*/
+	{0x0300, 0x0005},/*vt_pix_clk_div*/
+	{0x0302, 0x0001},/*vt_sys_clk_div*/
+	{0x0304, 0x0002},/*pre_pll_clk_div*/
+	{0x0306, 0x0018},/*pll_multipler*/
+	{0x0308, 0x000A},/*op_pix_clk_div*/
+	{0x030A, 0x0001},/*op_sys_clk_div*/
+};
+
+struct qs_mt9p017_i2c_reg_conf qs_mt9p017_recommend_settings[] = {
+	{0x316A, 0x8200},
+	{0x3ED2, 0xD965},
+	{0x3ED8, 0x7F1B},
+	{0x3EDA, 0xAF11},
+	{0x3EDE, 0xCA00},
+	{0x3EE2, 0x0068},
+	{0x3EF2, 0xD965},
+	{0x3EF8, 0x797F},
+	{0x3EFC, 0xAFEF},
+	{0x3EFE, 0x1308},
+	{0x31E0, 0x1F01},
+	{0x3e00, 0x0429},/*[REV3_pixel_timing]*/
+	{0x3e02, 0xFFFF},
+	{0x3e04, 0xFFFF},
+	{0x3e06, 0xFFFF},
+	{0x3e08, 0x8080},
+	{0x3e0a, 0x7180},
+	{0x3e0c, 0x7200},
+	{0x3e0e, 0x4353},
+	{0x3e10, 0x1300},
+	{0x3e12, 0x8710},
+	{0x3e14, 0x6085},
+	{0x3e16, 0x40A2},
+	{0x3e18, 0x0018},
+	{0x3e1a, 0x9057},
+	{0x3e1c, 0xA049},
+	{0x3e1e, 0xA649},
+	{0x3e20, 0x8846},
+	{0x3e22, 0x8142},
+	{0x3e24, 0x0082},
+	{0x3e26, 0x8B49},
+	{0x3e28, 0x9C49},
+	{0x3e2a, 0x8E47},
+	{0x3e2c, 0x884D},
+	{0x3e2e, 0x8010},
+	{0x3e30, 0x0C04},
+	{0x3e32, 0x0691},
+	{0x3e34, 0x100C},
+	{0x3e36, 0x8C4D},
+	{0x3e38, 0xB94A},
+	{0x3e3a, 0x4283},
+	{0x3e3c, 0x4181},
+	{0x3e3e, 0x4BB2},
+	{0x3e40, 0x4B80},
+	{0x3e42, 0x5680},
+	{0x3e44, 0x001C},
+	{0x3e46, 0x8110},
+	{0x3e48, 0xE080},
+	{0x3e4a, 0x1300},
+	{0x3e4c, 0x1C00},
+	{0x3e4e, 0x827C},
+	{0x3e50, 0x0970},
+	{0x3e52, 0x8082},
+	{0x3e54, 0x7281},
+	{0x3e56, 0x4C40},
+	{0x3e58, 0x8E4D},
+	{0x3e5a, 0x8110},
+	{0x3e5c, 0x0CAF},
+	{0x3e5e, 0x4D80},
+	{0x3e60, 0x100C},
+	{0x3e62, 0x8440},
+	{0x3e64, 0x4C81},
+	{0x3e66, 0x7C53},
+	{0x3e68, 0x7000},
+	{0x3e6a, 0x0000},
+	{0x3e6c, 0x0000},
+	{0x3e6e, 0x0000},
+	{0x3e70, 0x0000},
+	{0x3e72, 0x0000},
+	{0x3e74, 0x0000},
+	{0x3e76, 0x0000},
+	{0x3e78, 0x7000},
+	{0x3e7a, 0x0000},
+	{0x3e7c, 0x0000},
+	{0x3e7e, 0x0000},
+	{0x3e80, 0x0000},
+	{0x3e82, 0x0000},
+	{0x3e84, 0x0000},
+	{0x3e86, 0x0000},
+	{0x3e88, 0x0000},
+	{0x3e8a, 0x0000},
+	{0x3e8c, 0x0000},
+	{0x3e8e, 0x0000},
+	{0x3e90, 0x0000},
+	{0x3e92, 0x0000},
+	{0x3e94, 0x0000},
+	{0x3e96, 0x0000},
+	{0x3e98, 0x0000},
+	{0x3e9a, 0x0000},
+	{0x3e9c, 0x0000},
+	{0x3e9e, 0x0000},
+	{0x3ea0, 0x0000},
+	{0x3ea2, 0x0000},
+	{0x3ea4, 0x0000},
+	{0x3ea6, 0x0000},
+	{0x3ea8, 0x0000},
+	{0x3eaa, 0x0000},
+	{0x3eac, 0x0000},
+	{0x3eae, 0x0000},
+	{0x3eb0, 0x0000},
+	{0x3eb2, 0x0000},
+	{0x3eb4, 0x0000},
+	{0x3eb6, 0x0000},
+	{0x3eb8, 0x0000},
+	{0x3eba, 0x0000},
+	{0x3ebc, 0x0000},
+	{0x3ebe, 0x0000},
+	{0x3ec0, 0x0000},
+	{0x3ec2, 0x0000},
+	{0x3ec4, 0x0000},
+	{0x3ec6, 0x0000},
+	{0x3ec8, 0x0000},
+	{0x3eca, 0x0000},
+	{0x3ec0, 0x0000},
+	{0x3ec2, 0x0000},
+	{0x3ec4, 0x0000},
+	{0x3ec6, 0x0000},
+	{0x3ec8, 0x0000},
+	{0x3eca, 0x0000}
+
+};
+
+struct qs_mt9p017_i2c_reg_conf qs_mt9p017_prev_settings[] = {
+	{0x3004, 0x0008},/*x_addr_start*/
+	{0x3008, 0x0A25},/*x_addr_end*/
+	{0x3002, 0x0008},/*y_start_addr*/
+	{0x3006, 0x079D},/*y_addr_end*/
+	{0x3040, 0x04C3},/*read_mode*/
+	{0x034C, 0x0510},/*x_output_size*/
+	{0x034E, 0x03CC},/*y_output_size*/
+	{0x300C, 0x0D66},/*line_length_pck*/
+	{0x300A, 0x0415},/*frame_length_lines*/
+	{0x3012, 0x0414},/*coarse_integration_time*/
+	{0x3014, 0x0A22},/*fine_integration_time*/
+	{0x3010, 0x0184} /*fine_correction*/
+};
+
+struct qs_mt9p017_i2c_reg_conf qs_mt9p017_snap_settings[] = {
+	{0x3004, 0x0000},/*x_addr_start*/
+	{0x3008, 0x0A2F},/*x_addr_end*/
+	{0x3002, 0x0000},/*y_start_addr*/
+	{0x3006, 0x07A7},/*y_addr_end*/
+	{0x3040, 0x0041},/*read_mode*/
+	{0x034C, 0x0A30},/*x_output_size*/
+	{0x034E, 0x07A8},/*y_output_size*/
+	{0x300C, 0x0E7E},/*line_length_pck*/
+	{0x300A, 0x07F5},/*frame_length_lines*/
+	{0x3012, 0x07F4},/*coarse_integration_time*/
+	{0x3014, 0x0C9C},/*fine_integration_time*/
+	{0x3010, 0x00A0},/*fine_correction*/
+};
+
+struct qs_mt9p017_i2c_reg_conf qs_mt9p017_3d_prev_settings[] = {
+	{0x3004, 0x0008},/*x_addr_start*/
+	{0x3008, 0x0785},/*x_addr_end*/
+	{0x3002, 0x0008},/*y_start_addr*/
+	{0x3006, 0x043F},/*y_addr_end*/
+	{0x3040, 0x00C1},/*read_mode*/
+	{0x034C, 0x03C0},/*x_output_size*/
+	{0x034E, 0x0438},/*y_output_size*/
+	{0x300C, 0x0BCE},/*line_length_pck*/
+	{0x300A, 0x04A6},/*frame_length_lines*/
+	{0x3012, 0x04A5},/*coarse_integration_time*/
+	{0x3014, 0x062C},/*fine_integration_time*/
+	{0x3010, 0x00A0} /*fine_correction*/
+};
+
+struct qs_mt9p017_i2c_reg_conf qs_mt9p017_3d_snap_settings[] = {
+	{0x3004, 0x0008},/*x_addr_start*/
+	{0x3008, 0x0787},/*x_addr_end*/
+	{0x3002, 0x0008},/*y_start_addr*/
+	{0x3006, 0x043F},/*y_addr_end*/
+	{0x3040, 0x0041},/*read_mode*/
+	{0x034C, 0x0780},/*x_output_size*/
+	{0x034E, 0x0438},/*y_output_size*/
+	{0x300C, 0x0BCE},/*line_length_pck*/
+	{0x300A, 0x04A6},/*frame_length_lines*/
+	{0x3012, 0x04A5},/*coarse_integration_time*/
+	{0x3014, 0x09EC},/*fine_integration_time*/
+	{0x3010, 0x00A0} /*fine_correction*/
+};
+
+struct qs_mt9p017_i2c_reg_conf qs_mt9p017_lens_settings[] = {
+	{0x3600, 0x0650},
+	{0x3602, 0x564D},
+	{0x3604, 0x6730},
+	{0x3606, 0x49CC},
+	{0x3608, 0xC790},
+	{0x360A, 0x0350},
+	{0x360C, 0xF7ED},
+	{0x360E, 0x5970},
+	{0x3610, 0x378F},
+	{0x3612, 0xDCD0},
+	{0x3614, 0x0290},
+	{0x3616, 0x4C2D},
+	{0x3618, 0x35AF},
+	{0x361A, 0xA5ED},
+	{0x361C, 0xC1CE},
+	{0x361E, 0x0310},
+	{0x3620, 0x83EE},
+	{0x3622, 0x79B0},
+	{0x3624, 0x0F2F},
+	{0x3626, 0xEEF0},
+	{0x3640, 0x86AD},
+	{0x3642, 0xAE8D},
+	{0x3644, 0x9D4E},
+	{0x3646, 0x782B},
+	{0x3648, 0x216F},
+	{0x364A, 0xAC6C},
+	{0x364C, 0x33CD},
+	{0x364E, 0x922C},
+	{0x3650, 0xA12D},
+	{0x3652, 0x3DCB},
+	{0x3654, 0x506C},
+	{0x3656, 0x306D},
+	{0x3658, 0x934B},
+	{0x365A, 0xC5CD},
+	{0x365C, 0x6568},
+	{0x365E, 0x0CEC},
+	{0x3660, 0xEE8D},
+	{0x3662, 0x0A8E},
+	{0x3664, 0x104E},
+	{0x3666, 0xECCE},
+	{0x3680, 0x0FF1},
+	{0x3682, 0x1B8F},
+	{0x3684, 0x92D3},
+	{0x3686, 0x8910},
+	{0x3688, 0x1FF4},
+	{0x368A, 0x1BD1},
+	{0x368C, 0x5A0D},
+	{0x368E, 0x89B3},
+	{0x3690, 0xFF10},
+	{0x3692, 0x1994},
+	{0x3694, 0x2DD0},
+	{0x3696, 0x796C},
+	{0x3698, 0xC912},
+	{0x369A, 0x194F},
+	{0x369C, 0x7633},
+	{0x369E, 0x06B1},
+	{0x36A0, 0x018E},
+	{0x36A2, 0x8F13},
+	{0x36A4, 0xF110},
+	{0x36A6, 0x2014},
+	{0x36C0, 0xA089},
+	{0x36C2, 0x44AD},
+	{0x36C4, 0x3C4B},
+	{0x36C6, 0x658C},
+	{0x36C8, 0xDF10},
+	{0x36CA, 0x2D2E},
+	{0x36CC, 0xAC8A},
+	{0x36CE, 0xD450},
+	{0x36D0, 0x742E},
+	{0x36D2, 0x4E4F},
+	{0x36D4, 0xE86D},
+	{0x36D6, 0xE1AD},
+	{0x36D8, 0x6CAF},
+	{0x36DA, 0x2D8F},
+	{0x36DC, 0x9B71},
+	{0x36DE, 0x9C8D},
+	{0x36E0, 0x55CE},
+	{0x36E2, 0xC28F},
+	{0x36E4, 0xED4F},
+	{0x36E6, 0x23F0},
+	{0x3700, 0xECF1},
+	{0x3702, 0x9130},
+	{0x3704, 0x31F4},
+	{0x3706, 0xED2F},
+	{0x3708, 0xB8B4},
+	{0x370A, 0xE4D1},
+	{0x370C, 0x220B},
+	{0x370E, 0x2394},
+	{0x3710, 0xEED1},
+	{0x3712, 0xD4B3},
+	{0x3714, 0x9431},
+	{0x3716, 0x428E},
+	{0x3718, 0x1894},
+	{0x371A, 0xBCF2},
+	{0x371C, 0x9C94},
+	{0x371E, 0xD271},
+	{0x3720, 0xE56B},
+	{0x3722, 0x1E54},
+	{0x3724, 0xEA10},
+	{0x3726, 0x8EF4},
+	{0x3782, 0x04A4},
+	{0x3784, 0x03B4},
+	{0x37C0, 0x0000},
+	{0x37C2, 0x0000},
+	{0x37C4, 0x0000},
+	{0x37C6, 0x0000},
+	{0x3780, 0x8000}
+};
+
+struct qs_mt9p017_i2c_conf_array qs_mt9p017_confs[] = {
+	{&qs_mt9p017_prev_settings[0], ARRAY_SIZE(qs_mt9p017_prev_settings)},
+	{&qs_mt9p017_snap_settings[0], ARRAY_SIZE(qs_mt9p017_snap_settings)},
+	{&qs_mt9p017_3d_prev_settings[0],
+		ARRAY_SIZE(qs_mt9p017_3d_prev_settings)},
+	{&qs_mt9p017_3d_snap_settings[0],
+		ARRAY_SIZE(qs_mt9p017_3d_snap_settings)},
+};
+
+struct qs_mt9p017_reg qs_mt9p017_regs = {
+	.rec_settings = &qs_mt9p017_recommend_settings[0],
+	.rec_size = ARRAY_SIZE(qs_mt9p017_recommend_settings),
+	.reg_pll = &qs_mt9p017_pll_settings[0],
+	.reg_pll_size = ARRAY_SIZE(qs_mt9p017_pll_settings),
+	.reg_3d_pll = &qs_mt9p017_3d_pll_settings[0],
+	.reg_3d_pll_size = ARRAY_SIZE(qs_mt9p017_3d_pll_settings),
+	.reg_lens = &qs_mt9p017_lens_settings[0],
+	.reg_lens_size = ARRAY_SIZE(qs_mt9p017_lens_settings),
+	.conf_array = &qs_mt9p017_confs[0],
+};