msm: camera: eeprom subdevice support for camera sensor

The OTP data for calibration is stored in the eeprom. The eeprom
is registered as a subdevice and necessary functionality is added
for reading and fetching data to user space.

Change-Id: I119a31fa7eccc597c92b7c418c8d04c291e294f5
Signed-off-by: Jeyaprakash Soundrapandian <jsound@codeaurora.org>
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index 24f0f41..36953ef 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -468,6 +468,15 @@
 	.csi_lane_params = &imx074_csi_lane_params,
 };
 
+static struct i2c_board_info imx074_eeprom_i2c_info = {
+	I2C_BOARD_INFO("imx074_eeprom", 0x34 << 1),
+};
+
+static struct msm_eeprom_info imx074_eeprom_info = {
+	.board_info     = &imx074_eeprom_i2c_info,
+	.bus_id         = APQ_8064_GSBI4_QUP_I2C_BUS_ID,
+};
+
 static struct msm_camera_sensor_info msm_camera_sensor_imx074_data = {
 	.sensor_name	= "imx074",
 	.pdata	= &msm_camera_csi_device_data[0],
@@ -477,7 +486,9 @@
 	.camera_type = BACK_CAMERA_2D,
 	.sensor_type = BAYER_SENSOR,
 	.actuator_info = &msm_act_main_cam_0_info,
+	.eeprom_info = &imx074_eeprom_info,
 };
+
 static struct msm_camera_csi_lane_params imx091_csi_lane_params = {
 	.csi_lane_assign = 0xE4,
 	.csi_lane_mask = 0xF,
@@ -503,6 +514,15 @@
 	.csi_lane_params = &imx091_csi_lane_params,
 };
 
+static struct i2c_board_info imx091_eeprom_i2c_info = {
+	I2C_BOARD_INFO("imx091_eeprom", 0x21),
+};
+
+static struct msm_eeprom_info imx091_eeprom_info = {
+	.board_info     = &imx091_eeprom_i2c_info,
+	.bus_id         = APQ_8064_GSBI4_QUP_I2C_BUS_ID,
+};
+
 static struct msm_camera_sensor_info msm_camera_sensor_imx091_data = {
 	.sensor_name	= "imx091",
 	.pdata	= &msm_camera_csi_device_data[0],
@@ -512,6 +532,7 @@
 	.camera_type = BACK_CAMERA_2D,
 	.sensor_type = BAYER_SENSOR,
 	.actuator_info = &msm_act_main_cam_1_info,
+	.eeprom_info = &imx091_eeprom_info,
 };
 
 static struct camera_vreg_t apq_8064_s5k3l1yx_vreg[] = {
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index 3331c91..371bb53 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -524,6 +524,15 @@
 	.csi_lane_params = &imx074_csi_lane_params,
 };
 
+static struct i2c_board_info imx074_eeprom_i2c_info = {
+	I2C_BOARD_INFO("imx074_eeprom", 0x34 << 1),
+};
+
+static struct msm_eeprom_info imx074_eeprom_info = {
+	.board_info     = &imx074_eeprom_i2c_info,
+	.bus_id         = MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+};
+
 static struct msm_camera_sensor_info msm_camera_sensor_imx074_data = {
 	.sensor_name	= "imx074",
 	.pdata	= &msm_camera_csi_device_data[0],
@@ -534,6 +543,7 @@
 	.camera_type = BACK_CAMERA_2D,
 	.sensor_type = BAYER_SENSOR,
 	.actuator_info = &msm_act_main_cam_0_info,
+	.eeprom_info = &imx074_eeprom_info,
 };
 
 static struct camera_vreg_t msm_8960_mt9m114_vreg[] = {
@@ -667,6 +677,15 @@
 	.csi_lane_params = &imx091_csi_lane_params,
 };
 
+static struct i2c_board_info imx091_eeprom_i2c_info = {
+	I2C_BOARD_INFO("imx091_eeprom", 0x21),
+};
+
+static struct msm_eeprom_info imx091_eeprom_info = {
+	.board_info     = &imx091_eeprom_i2c_info,
+	.bus_id         = MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+};
+
 static struct msm_camera_sensor_info msm_camera_sensor_imx091_data = {
 	.sensor_name	= "imx091",
 	.pdata	= &msm_camera_csi_device_data[0],
@@ -676,6 +695,7 @@
 	.camera_type = BACK_CAMERA_2D,
 	.sensor_type = BAYER_SENSOR,
 	.actuator_info = &msm_act_main_cam_1_info,
+	.eeprom_info = &imx091_eeprom_info,
 };
 
 static struct pm8xxx_mpp_config_data privacy_light_on_config = {
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index d6476f7..8a1474a 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -261,6 +261,11 @@
 	int vcm_enable;
 };
 
+struct msm_eeprom_info {
+	struct i2c_board_info const *board_info;
+	int bus_id;
+};
+
 struct msm_camera_sensor_info {
 	const char *sensor_name;
 	int sensor_reset_enable;
@@ -283,6 +288,7 @@
 	enum msm_sensor_type sensor_type;
 	struct msm_actuator_info *actuator_info;
 	int pmic_gpio_enable;
+	struct msm_eeprom_info *eeprom_info;
 };
 
 struct msm_camera_board_info {
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index db10546..fbc3a37 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -211,6 +211,18 @@
 	bool "Qualcomm MSM actuator support"
 	depends on MSM_CAMERA
 
+config MSM_EEPROM
+	bool "Qualcomm MSM EEPROM support"
+	depends on MSM_CAMERA
+
+config IMX074_EEPROM
+	bool "IMX074 EEPROM support"
+	depends on MSM_CAMERA
+
+config IMX091_EEPROM
+	bool "IMX091 EEPROM support"
+	depends on MSM_CAMERA
+
 config MSM_GEMINI
 	tristate "Qualcomm MSM Gemini Jpeg Engine support"
 	depends on MSM_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_MSM8960)
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 85157f7..ebfed6c 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -7,10 +7,12 @@
 obj-$(CONFIG_MSM_CAMERA) += io/
 ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
   EXTRA_CFLAGS += -Idrivers/media/video/msm/csi
+  EXTRA_CFLAGS += -Idrivers/media/video/msm/io
+  EXTRA_CFLAGS += -Idrivers/media/video/msm/eeprom
   EXTRA_CFLAGS += -Idrivers/media/video/msm/sensors
   EXTRA_CFLAGS += -Idrivers/media/video/msm/actuators
   obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o
-  obj-$(CONFIG_MSM_CAMERA) += sensors/ actuators/ csi/
+  obj-$(CONFIG_MSM_CAMERA) += io/ eeprom/ sensors/ actuators/ csi/
 else
   obj-$(CONFIG_MSM_CAMERA) += msm_camera.o
 endif
diff --git a/drivers/media/video/msm/eeprom/Makefile b/drivers/media/video/msm/eeprom/Makefile
new file mode 100644
index 0000000..f7b7f5d
--- /dev/null
+++ b/drivers/media/video/msm/eeprom/Makefile
@@ -0,0 +1,5 @@
+GCC_VERSION      := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
+EXTRA_CFLAGS += -Idrivers/media/video/msm/io
+obj-$(CONFIG_MSM_EEPROM) += msm_camera_eeprom.o
+obj-$(CONFIG_IMX074_EEPROM) += imx074_eeprom.o
+obj-$(CONFIG_IMX091_EEPROM) += imx091_eeprom.o
\ No newline at end of file
diff --git a/drivers/media/video/msm/eeprom/imx074_eeprom.c b/drivers/media/video/msm/eeprom/imx074_eeprom.c
new file mode 100644
index 0000000..f46bc94
--- /dev/null
+++ b/drivers/media/video/msm/eeprom/imx074_eeprom.c
@@ -0,0 +1,111 @@
+/* Copyright (c) 2011-2012, 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 "msm_camera_eeprom.h"
+#include "msm_camera_i2c.h"
+
+DEFINE_MUTEX(imx074_eeprom_mutex);
+static struct msm_eeprom_ctrl_t imx074_eeprom_t;
+
+static const struct i2c_device_id imx074_eeprom_i2c_id[] = {
+	{"imx074_eeprom", (kernel_ulong_t)&imx074_eeprom_t},
+	{ }
+};
+
+static struct i2c_driver imx074_eeprom_i2c_driver = {
+	.id_table = imx074_eeprom_i2c_id,
+	.probe  = msm_eeprom_i2c_probe,
+	.remove = __exit_p(imx074_eeprom_i2c_remove),
+	.driver = {
+		.name = "imx074_eeprom",
+	},
+};
+
+static int __init imx074_eeprom_i2c_add_driver(void)
+{
+	int rc = 0;
+	rc = i2c_add_driver(imx074_eeprom_t.i2c_driver);
+	return rc;
+}
+
+static struct v4l2_subdev_core_ops imx074_eeprom_subdev_core_ops = {
+	.ioctl = msm_eeprom_subdev_ioctl,
+};
+
+static struct v4l2_subdev_ops imx074_eeprom_subdev_ops = {
+	.core = &imx074_eeprom_subdev_core_ops,
+};
+
+uint8_t imx074_wbcalib_data[6];
+struct msm_calib_wb imx074_wb_data;
+
+static struct msm_camera_eeprom_info_t imx074_calib_supp_info = {
+	{FALSE, 0, 0, 1},
+	{TRUE, 6, 0, 1024},
+	{FALSE, 0, 0, 1},
+	{FALSE, 0, 0, 1},
+};
+
+static struct msm_camera_eeprom_read_t imx074_eeprom_read_tbl[] = {
+	{0x10, &imx074_wbcalib_data[0], 6, 0},
+};
+
+
+static struct msm_camera_eeprom_data_t imx074_eeprom_data_tbl[] = {
+	{&imx074_wb_data, sizeof(struct msm_calib_wb)},
+};
+
+static void imx074_format_wbdata(void)
+{
+	imx074_wb_data.r_over_g = (uint16_t)(imx074_wbcalib_data[0] << 8) |
+		imx074_wbcalib_data[1];
+	imx074_wb_data.b_over_g = (uint16_t)(imx074_wbcalib_data[2] << 8) |
+		imx074_wbcalib_data[3];
+	imx074_wb_data.gr_over_gb = (uint16_t)(imx074_wbcalib_data[4] << 8) |
+		imx074_wbcalib_data[5];
+}
+
+void imx074_format_calibrationdata(void)
+{
+	imx074_format_wbdata();
+}
+static struct msm_eeprom_ctrl_t imx074_eeprom_t = {
+	.i2c_driver = &imx074_eeprom_i2c_driver,
+	.i2c_addr = 0xA4,
+	.eeprom_v4l2_subdev_ops = &imx074_eeprom_subdev_ops,
+
+	.i2c_client = {
+		.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+	},
+
+	.eeprom_mutex = &imx074_eeprom_mutex,
+
+	.func_tbl = {
+		.eeprom_init = NULL,
+		.eeprom_release = NULL,
+		.eeprom_get_info = msm_camera_eeprom_get_info,
+		.eeprom_get_data = msm_camera_eeprom_get_data,
+		.eeprom_set_dev_addr = NULL,
+		.eeprom_format_data = imx074_format_calibrationdata,
+	},
+	.info = &imx074_calib_supp_info,
+	.info_size = sizeof(struct msm_camera_eeprom_info_t),
+	.read_tbl = imx074_eeprom_read_tbl,
+	.read_tbl_size = ARRAY_SIZE(imx074_eeprom_read_tbl),
+	.data_tbl = imx074_eeprom_data_tbl,
+	.data_tbl_size = ARRAY_SIZE(imx074_eeprom_data_tbl),
+};
+
+subsys_initcall(imx074_eeprom_i2c_add_driver);
+MODULE_DESCRIPTION("IMX074 EEPROM");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/eeprom/imx091_eeprom.c b/drivers/media/video/msm/eeprom/imx091_eeprom.c
new file mode 100644
index 0000000..8b34513
--- /dev/null
+++ b/drivers/media/video/msm/eeprom/imx091_eeprom.c
@@ -0,0 +1,126 @@
+/* Copyright (c) 2012, 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 "msm_camera_eeprom.h"
+#include "msm_camera_i2c.h"
+
+DEFINE_MUTEX(imx091_eeprom_mutex);
+static struct msm_eeprom_ctrl_t imx091_eeprom_t;
+
+static const struct i2c_device_id imx091_eeprom_i2c_id[] = {
+	{"imx091_eeprom", (kernel_ulong_t)&imx091_eeprom_t},
+	{ }
+};
+
+static struct i2c_driver imx091_eeprom_i2c_driver = {
+	.id_table = imx091_eeprom_i2c_id,
+	.probe  = msm_eeprom_i2c_probe,
+	.remove = __exit_p(imx091_eeprom_i2c_remove),
+	.driver = {
+		.name = "imx091_eeprom",
+	},
+};
+
+static int __init imx091_eeprom_i2c_add_driver(void)
+{
+	int rc = 0;
+	rc = i2c_add_driver(imx091_eeprom_t.i2c_driver);
+	return rc;
+}
+
+static struct v4l2_subdev_core_ops imx091_eeprom_subdev_core_ops = {
+	.ioctl = msm_eeprom_subdev_ioctl,
+};
+
+static struct v4l2_subdev_ops imx091_eeprom_subdev_ops = {
+	.core = &imx091_eeprom_subdev_core_ops,
+};
+
+uint8_t imx091_wbcalib_data[6];
+uint8_t imx091_afcalib_data[6];
+struct msm_calib_wb imx091_wb_data;
+struct msm_calib_af imx091_af_data;
+
+static struct msm_camera_eeprom_info_t imx091_calib_supp_info = {
+	{TRUE, 6, 1, 1},
+	{TRUE, 6, 0, 32768},
+	{FALSE, 0, 0, 1},
+	{FALSE, 0, 0, 1},
+};
+
+static struct msm_camera_eeprom_read_t imx091_eeprom_read_tbl[] = {
+	{0x05, &imx091_wbcalib_data[0], 6, 0},
+	{0x0B, &imx091_afcalib_data[0], 6, 0},
+};
+
+
+static struct msm_camera_eeprom_data_t imx091_eeprom_data_tbl[] = {
+	{&imx091_wb_data, sizeof(struct msm_calib_wb)},
+	{&imx091_af_data, sizeof(struct msm_calib_af)},
+};
+
+static void imx091_format_wbdata(void)
+{
+	imx091_wb_data.r_over_g = (uint16_t)(imx091_wbcalib_data[1] << 8) |
+		(imx091_wbcalib_data[0] - 0x32);
+	imx091_wb_data.b_over_g = (uint16_t)(imx091_wbcalib_data[3] << 8) |
+		(imx091_wbcalib_data[2] - 0x32);
+	imx091_wb_data.gr_over_gb = (uint16_t)(imx091_wbcalib_data[5] << 8) |
+		(imx091_wbcalib_data[4] - 0x32);
+}
+
+static void imx091_format_afdata(void)
+{
+	imx091_af_data.inf_dac = (uint16_t)(imx091_afcalib_data[1] << 8) |
+		imx091_afcalib_data[0];
+	imx091_af_data.macro_dac = (uint16_t)(imx091_afcalib_data[3] << 8) |
+		imx091_afcalib_data[2];
+	imx091_af_data.start_dac = (uint16_t)(imx091_afcalib_data[5] << 8) |
+		imx091_afcalib_data[4];
+}
+
+void imx091_format_calibrationdata(void)
+{
+	imx091_format_wbdata();
+	imx091_format_afdata();
+}
+static struct msm_eeprom_ctrl_t imx091_eeprom_t = {
+	.i2c_driver = &imx091_eeprom_i2c_driver,
+	.i2c_addr = 0xA1,
+	.eeprom_v4l2_subdev_ops = &imx091_eeprom_subdev_ops,
+
+	.i2c_client = {
+		.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+	},
+
+	.eeprom_mutex = &imx091_eeprom_mutex,
+
+	.func_tbl = {
+		.eeprom_init = NULL,
+		.eeprom_release = NULL,
+		.eeprom_get_info = msm_camera_eeprom_get_info,
+		.eeprom_get_data = msm_camera_eeprom_get_data,
+		.eeprom_set_dev_addr = NULL,
+		.eeprom_format_data = imx091_format_calibrationdata,
+	},
+	.info = &imx091_calib_supp_info,
+	.info_size = sizeof(struct msm_camera_eeprom_info_t),
+	.read_tbl = imx091_eeprom_read_tbl,
+	.read_tbl_size = ARRAY_SIZE(imx091_eeprom_read_tbl),
+	.data_tbl = imx091_eeprom_data_tbl,
+	.data_tbl_size = ARRAY_SIZE(imx091_eeprom_data_tbl),
+};
+
+subsys_initcall(imx091_eeprom_i2c_add_driver);
+MODULE_DESCRIPTION("imx091 EEPROM");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/eeprom/msm_camera_eeprom.c b/drivers/media/video/msm/eeprom/msm_camera_eeprom.c
new file mode 100644
index 0000000..96a6e04
--- /dev/null
+++ b/drivers/media/video/msm/eeprom/msm_camera_eeprom.c
@@ -0,0 +1,196 @@
+/* Copyright (c) 2011-2012, 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 "msm_camera_eeprom.h"
+
+int32_t msm_camera_eeprom_read(struct msm_eeprom_ctrl_t *ectrl,
+	uint32_t reg_addr, void *data, uint32_t num_byte,
+	uint16_t convert_endian)
+{
+	int rc = 0;
+	if (ectrl->func_tbl.eeprom_set_dev_addr != NULL)
+		ectrl->func_tbl.eeprom_set_dev_addr(ectrl, &reg_addr);
+
+	if (!convert_endian) {
+		rc = msm_camera_i2c_read_seq(
+			&ectrl->i2c_client, reg_addr, data, num_byte);
+	} else {
+		unsigned char buf[num_byte];
+		uint8_t *data_ptr = (uint8_t *) data;
+		int i;
+		rc = msm_camera_i2c_read_seq(
+			&ectrl->i2c_client, reg_addr, buf, num_byte);
+		for (i = 0; i < num_byte; i += 2) {
+			data_ptr[i] = buf[i+1];
+			data_ptr[i+1] = buf[i];
+		}
+	}
+	return rc;
+}
+
+int32_t msm_camera_eeprom_read_tbl(struct msm_eeprom_ctrl_t *ectrl,
+	struct msm_camera_eeprom_read_t *read_tbl, uint16_t tbl_size)
+{
+	int i, rc = 0;
+	CDBG("%s: open\n", __func__);
+	if (read_tbl == NULL)
+		return rc;
+
+	for (i = 0; i < tbl_size; i++) {
+		rc = msm_camera_eeprom_read
+			(ectrl, read_tbl[i].reg_addr,
+			read_tbl[i].dest_ptr, read_tbl[i].num_byte,
+			read_tbl[i].convert_endian);
+		if (rc < 0) {
+			pr_err("%s: read failed\n", __func__);
+			return rc;
+		}
+	}
+	CDBG("%s: done\n", __func__);
+	return rc;
+}
+
+int32_t msm_camera_eeprom_get_info(struct msm_eeprom_ctrl_t *ectrl,
+	struct msm_camera_eeprom_info_t *einfo)
+{
+	int rc = 0;
+	CDBG("%s: open\n", __func__);
+	memcpy(einfo, ectrl->info, ectrl->info_size);
+	CDBG("%s: done =%d\n", __func__, rc);
+	return rc;
+}
+
+int32_t msm_camera_eeprom_get_data(struct msm_eeprom_ctrl_t *ectrl,
+	struct msm_eeprom_data_t *edata)
+{
+	int rc = 0;
+	if (edata->index >= ectrl->data_tbl_size)
+		return -EFAULT;
+	if (copy_to_user(edata->eeprom_data,
+		ectrl->data_tbl[edata->index].data,
+		ectrl->data_tbl[edata->index].size))
+		rc = -EFAULT;
+	return rc;
+}
+
+int32_t msm_eeprom_config(struct msm_eeprom_ctrl_t *e_ctrl,
+	void __user *argp)
+{
+	struct msm_eeprom_cfg_data cdata;
+	int32_t rc = 0;
+	if (copy_from_user(&cdata,
+		(void *)argp,
+		sizeof(struct msm_eeprom_cfg_data)))
+		return -EFAULT;
+	mutex_lock(e_ctrl->eeprom_mutex);
+
+	switch (cdata.cfgtype) {
+	case CFG_GET_EEPROM_INFO:
+		if (e_ctrl->func_tbl.eeprom_get_info == NULL) {
+			rc = -EFAULT;
+			break;
+		}
+		rc = e_ctrl->func_tbl.eeprom_get_info(e_ctrl,
+			&cdata.cfg.get_info);
+
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct msm_eeprom_cfg_data)))
+			rc = -EFAULT;
+		break;
+	case CFG_GET_EEPROM_DATA:
+		if (e_ctrl->func_tbl.eeprom_get_data == NULL) {
+			rc = -EFAULT;
+			break;
+		}
+		rc = e_ctrl->func_tbl.eeprom_get_data(e_ctrl,
+			&cdata.cfg.get_data);
+
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct msm_eeprom_cfg_data)))
+			rc = -EFAULT;
+		break;
+	default:
+		break;
+	}
+	mutex_unlock(e_ctrl->eeprom_mutex);
+	return rc;
+}
+
+struct msm_eeprom_ctrl_t *get_ectrl(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct msm_eeprom_ctrl_t, sdev);
+}
+
+long msm_eeprom_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	struct msm_eeprom_ctrl_t *e_ctrl = get_ectrl(sd);
+	void __user *argp = (void __user *)arg;
+	switch (cmd) {
+	case VIDIOC_MSM_EEPROM_CFG:
+		return msm_eeprom_config(e_ctrl, argp);
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+int32_t msm_eeprom_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int rc = 0;
+	struct msm_eeprom_ctrl_t *e_ctrl_t = NULL;
+	CDBG("%s called\n", __func__);
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	e_ctrl_t = (struct msm_eeprom_ctrl_t *)(id->driver_data);
+	e_ctrl_t->i2c_client.client = client;
+
+	if (e_ctrl_t->i2c_addr != 0)
+		e_ctrl_t->i2c_client.client->addr = e_ctrl_t->i2c_addr;
+
+	CDBG("%s client = %x\n", __func__, (unsigned int) client);
+
+	/* Assign name for sub device */
+	snprintf(e_ctrl_t->sdev.name, sizeof(e_ctrl_t->sdev.name),
+		"%s", e_ctrl_t->i2c_driver->driver.name);
+
+	if (e_ctrl_t->func_tbl.eeprom_init != NULL) {
+		rc = e_ctrl_t->func_tbl.eeprom_init(e_ctrl_t,
+			e_ctrl_t->i2c_client.client->adapter);
+	}
+	msm_camera_eeprom_read_tbl(e_ctrl_t,
+		e_ctrl_t->read_tbl,
+		e_ctrl_t->read_tbl_size);
+
+	if (e_ctrl_t->func_tbl.eeprom_format_data != NULL)
+		e_ctrl_t->func_tbl.eeprom_format_data();
+
+	if (e_ctrl_t->func_tbl.eeprom_release != NULL)
+		rc = e_ctrl_t->func_tbl.eeprom_release(e_ctrl_t);
+
+
+	/* Initialize sub device */
+	v4l2_i2c_subdev_init(&e_ctrl_t->sdev,
+		e_ctrl_t->i2c_client.client,
+		e_ctrl_t->eeprom_v4l2_subdev_ops);
+	CDBG("%s success resut=%d\n", __func__, rc);
+	return rc;
+
+probe_failure:
+	pr_err("%s failed! rc = %d\n", __func__, rc);
+	return rc;
+}
diff --git a/drivers/media/video/msm/eeprom/msm_camera_eeprom.h b/drivers/media/video/msm/eeprom/msm_camera_eeprom.h
new file mode 100644
index 0000000..830e5d8
--- /dev/null
+++ b/drivers/media/video/msm/eeprom/msm_camera_eeprom.h
@@ -0,0 +1,82 @@
+/* Copyright (c) 2011-2012, 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_CAMERA_EEPROM_H
+#define MSM_CAMERA_EEPROM_H
+
+#include <linux/delay.h>
+#include <mach/camera.h>
+#include <media/v4l2-subdev.h>
+#include "msm_camera_i2c.h"
+
+#define TRUE  1
+#define FALSE 0
+
+struct msm_eeprom_ctrl_t;
+
+struct msm_camera_eeprom_fn_t {
+	int32_t (*eeprom_init)
+		(struct msm_eeprom_ctrl_t *ectrl,
+		struct i2c_adapter *adapter);
+	int32_t (*eeprom_release)
+		(struct msm_eeprom_ctrl_t *ectrl);
+	int32_t (*eeprom_get_info)
+		(struct msm_eeprom_ctrl_t *ectrl,
+		 struct msm_camera_eeprom_info_t *einfo);
+	int32_t (*eeprom_get_data)
+		(struct msm_eeprom_ctrl_t *ectrl,
+		 struct msm_eeprom_data_t *edata);
+	void (*eeprom_set_dev_addr)
+		(struct msm_eeprom_ctrl_t*, uint32_t*);
+	void (*eeprom_format_data)
+		(void);
+};
+
+struct msm_camera_eeprom_read_t {
+	uint32_t reg_addr;
+	void *dest_ptr;
+	uint32_t num_byte;
+	uint16_t convert_endian;
+};
+
+struct msm_camera_eeprom_data_t {
+	void *data;
+	uint16_t size;
+};
+
+struct msm_eeprom_ctrl_t {
+	struct msm_camera_i2c_client i2c_client;
+	uint16_t i2c_addr;
+	struct i2c_driver *i2c_driver;
+	struct mutex *eeprom_mutex;
+	struct v4l2_subdev sdev;
+	struct v4l2_subdev_ops *eeprom_v4l2_subdev_ops;
+	struct msm_camera_eeprom_fn_t func_tbl;
+	struct msm_camera_eeprom_info_t *info;
+	uint16_t info_size;
+	struct msm_camera_eeprom_read_t *read_tbl;
+	uint16_t read_tbl_size;
+	struct msm_camera_eeprom_data_t *data_tbl;
+	uint16_t data_tbl_size;
+};
+
+int32_t msm_camera_eeprom_get_data(struct msm_eeprom_ctrl_t *ectrl,
+	struct msm_eeprom_data_t *edata);
+int32_t msm_camera_eeprom_get_info(struct msm_eeprom_ctrl_t *ectrl,
+	struct msm_camera_eeprom_info_t *einfo);
+int32_t msm_eeprom_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id);
+long msm_eeprom_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg);
+
+#define VIDIOC_MSM_EEPROM_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 12, void __user *)
+#endif
diff --git a/drivers/media/video/msm/io/Makefile b/drivers/media/video/msm/io/Makefile
index dddcbf6..64df7fb 100644
--- a/drivers/media/video/msm/io/Makefile
+++ b/drivers/media/video/msm/io/Makefile
@@ -3,7 +3,7 @@
 obj-$(CONFIG_MSM_CAMERA)   += msm_camera_io_util.o
 EXTRA_CFLAGS += -Idrivers/media/video/msm
 ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
-  obj-$(CONFIG_MSM_CAMERA) += msm_camera_i2c.o msm_camera_eeprom.o msm_camera_i2c_mux.o
+  obj-$(CONFIG_MSM_CAMERA) += msm_camera_i2c.o msm_camera_i2c_mux.o
   obj-$(CONFIG_ARCH_MSM7X27A) += msm_io_7x27a_v4l2.o
   obj-$(CONFIG_ARCH_MSM8X60) += msm_io_vfe31_v4l2.o
   obj-$(CONFIG_ARCH_MSM7X30) += msm_io_vfe31_v4l2.o
diff --git a/drivers/media/video/msm/io/msm_camera_eeprom.c b/drivers/media/video/msm/io/msm_camera_eeprom.c
deleted file mode 100644
index 34dba26..0000000
--- a/drivers/media/video/msm/io/msm_camera_eeprom.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/* 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 "msm_camera_eeprom.h"
-
-int32_t msm_camera_eeprom_init(struct msm_camera_eeprom_client *ectrl,
-	struct i2c_adapter *adapter)
-{
-	CDBG("%s: open", __func__);
-	ectrl->i2c_client->client =
-		i2c_new_dummy(adapter, ectrl->i2c_addr >> 1);
-	if (ectrl->i2c_client->client == NULL) {
-		CDBG("%s: eeprom i2c get client failed\n", __func__);
-		return -EFAULT;
-	}
-	ectrl->i2c_client->client->addr = ectrl->i2c_addr;
-	CDBG("%s: done", __func__);
-	return 0;
-}
-
-int32_t msm_camera_eeprom_release(struct msm_camera_eeprom_client *ectrl)
-{
-	if (ectrl->i2c_client->client != NULL) {
-		i2c_unregister_device(ectrl->i2c_client->client);
-		ectrl->i2c_client->client = NULL;
-	}
-	return 0;
-}
-
-int32_t msm_camera_eeprom_read(struct msm_camera_eeprom_client *ectrl,
-	uint16_t reg_addr, void *data, uint32_t num_byte,
-	uint16_t convert_endian)
-{
-	int rc = 0;
-	if (ectrl->func_tbl.eeprom_set_dev_addr != NULL)
-		ectrl->func_tbl.eeprom_set_dev_addr(ectrl, &reg_addr);
-
-	if (!convert_endian) {
-		rc = msm_camera_i2c_read_seq(
-			ectrl->i2c_client, reg_addr, data, num_byte);
-	} else {
-		unsigned char buf[num_byte];
-		uint8_t *data_ptr = (uint8_t *) data;
-		int i;
-		rc = msm_camera_i2c_read_seq(
-			ectrl->i2c_client, reg_addr, buf, num_byte);
-		for (i = 0; i < num_byte; i++)
-			data_ptr[i] = buf[num_byte-i-1];
-	}
-	return rc;
-}
-
-int32_t msm_camera_eeprom_read_tbl(struct msm_camera_eeprom_client *ectrl,
-	struct msm_camera_eeprom_read_t *read_tbl, uint16_t tbl_size)
-{
-	int i, rc = 0;
-	CDBG("%s: open", __func__);
-	if (read_tbl == NULL)
-		return rc;
-
-	for (i = 0; i < tbl_size; i++) {
-		rc = msm_camera_eeprom_read
-			(ectrl, read_tbl[i].reg_addr,
-			read_tbl[i].dest_ptr, read_tbl[i].num_byte,
-			read_tbl[i].convert_endian);
-		if (rc < 0)	{
-			CDBG("%s: read failed\n", __func__);
-			return rc;
-		}
-	}
-	CDBG("%s: done", __func__);
-	return rc;
-}
-
-int32_t msm_camera_eeprom_get_data(struct msm_camera_eeprom_client *ectrl,
-	struct sensor_eeprom_data_t *edata)
-{
-	int rc = 0;
-	if (edata->index >= ectrl->data_tbl_size)
-		return -EFAULT;
-	if (copy_to_user(edata->eeprom_data,
-		ectrl->data_tbl[edata->index].data,
-		ectrl->data_tbl[edata->index].size))
-		rc = -EFAULT;
-	return rc;
-}
-
diff --git a/drivers/media/video/msm/io/msm_camera_eeprom.h b/drivers/media/video/msm/io/msm_camera_eeprom.h
deleted file mode 100644
index 9dd7b54..0000000
--- a/drivers/media/video/msm/io/msm_camera_eeprom.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* 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 <mach/camera.h>
-#include "msm_camera_i2c.h"
-
-struct msm_camera_eeprom_client;
-
-struct msm_camera_eeprom_fn_t {
-	int32_t (*eeprom_init)
-		(struct msm_camera_eeprom_client *ectrl,
-		struct i2c_adapter *adapter);
-	int32_t (*eeprom_release)
-		(struct msm_camera_eeprom_client *ectrl);
-	int32_t (*eeprom_get_data)
-		(struct msm_camera_eeprom_client *ectrl,
-		 struct sensor_eeprom_data_t *edata);
-	void (*eeprom_set_dev_addr)
-		(struct msm_camera_eeprom_client*, uint16_t*);
-};
-
-struct msm_camera_eeprom_read_t {
-	uint16_t reg_addr;
-	void *dest_ptr;
-	uint32_t num_byte;
-	uint16_t convert_endian;
-};
-
-struct msm_camera_eeprom_data_t {
-	void *data;
-	uint16_t size;
-};
-
-struct msm_camera_eeprom_client {
-	struct msm_camera_i2c_client *i2c_client;
-	uint16_t i2c_addr;
-	struct msm_camera_eeprom_fn_t func_tbl;
-	struct msm_camera_eeprom_read_t *read_tbl;
-	uint16_t read_tbl_size;
-	struct msm_camera_eeprom_data_t *data_tbl;
-	uint16_t data_tbl_size;
-};
-
-int32_t msm_camera_eeprom_init(struct msm_camera_eeprom_client *ectrl,
-	struct i2c_adapter *adapter);
-int32_t msm_camera_eeprom_release(struct msm_camera_eeprom_client *ectrl);
-int32_t msm_camera_eeprom_read(struct msm_camera_eeprom_client *ectrl,
-	uint16_t reg_addr, void *data, uint32_t num_byte,
-	uint16_t convert_endian);
-int32_t msm_camera_eeprom_read_tbl(struct msm_camera_eeprom_client *ectrl,
-	struct msm_camera_eeprom_read_t *read_tbl, uint16_t tbl_size);
-int32_t msm_camera_eeprom_get_data(struct msm_camera_eeprom_client *ectrl,
-	struct sensor_eeprom_data_t *edata);
-
-
-
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 12a0f37..254cf3a 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -26,6 +26,7 @@
 #include "msm_sensor.h"
 #include "msm_actuator.h"
 #include "msm_vfe32.h"
+#include "msm_camera_eeprom.h"
 
 #define MSM_MAX_CAMERA_SENSORS 5
 
@@ -2858,6 +2859,43 @@
 	return NULL;
 }
 
+static struct v4l2_subdev *msm_eeprom_probe(
+	struct msm_eeprom_info *eeprom_info)
+{
+	struct v4l2_subdev *eeprom_sdev;
+	struct i2c_adapter *adapter = NULL;
+	void *eeprom_client = NULL;
+
+	D("%s called\n", __func__);
+
+	if (!eeprom_info)
+		goto probe_fail;
+
+	adapter = i2c_get_adapter(eeprom_info->bus_id);
+	if (!adapter)
+		goto probe_fail;
+
+	eeprom_client = i2c_new_device(adapter, eeprom_info->board_info);
+	if (!eeprom_client)
+		goto device_fail;
+
+	eeprom_sdev = (struct v4l2_subdev *)i2c_get_clientdata(eeprom_client);
+	if (eeprom_sdev == NULL)
+		goto client_fail;
+
+	return eeprom_sdev;
+client_fail:
+	pr_err("%s client_fail\n", __func__);
+	i2c_unregister_device(eeprom_client);
+device_fail:
+	pr_err("%s device_fail\n", __func__);
+	i2c_put_adapter(adapter);
+	adapter = NULL;
+probe_fail:
+	pr_err("%s probe_fail\n", __func__);
+	return NULL;
+}
+
 /* 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 */
@@ -2883,6 +2921,7 @@
 	sdata = (struct msm_camera_sensor_info *) s_ctrl->sensordata;
 
 	pcam->act_sdev = msm_actuator_probe(sdata->actuator_info);
+	pcam->eeprom_sdev = msm_eeprom_probe(sdata->eeprom_info);
 
 	D("%s: pcam =0x%p\n", __func__, pcam);
 
@@ -2967,6 +3006,15 @@
 		}
 	}
 
+	if (pcam->eeprom_sdev) {
+		rc = v4l2_device_register_subdev(&pcam->v4l2_dev,
+			pcam->eeprom_sdev);
+		if (rc < 0) {
+			D("%s eeprom sub device register failed\n", __func__);
+			goto failure;
+		}
+	}
+
 	pcam->vnode_id = vnode_count++;
 	return rc;
 
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index fa97e22..671dfd7 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -68,6 +68,7 @@
 	VPE_DEV,
 	SENSOR_DEV,
 	ACTUATOR_DEV,
+	EEPROM_DEV,
 };
 
 /* msm queue management APIs*/
@@ -244,6 +245,7 @@
 	struct v4l2_subdev *gemini_sdev; /* gemini sub device */
 	struct v4l2_subdev *vpe_sdev; /* vpe sub device */
 	struct v4l2_subdev *axi_sdev; /* vpe sub device */
+	struct v4l2_subdev *eeprom_sdev; /* eeprom sub device */
 
 	struct msm_isp_ops *isp_sdev;    /* isp sub device : camif/VFE */
 	struct msm_cam_config_dev *config_device;
@@ -355,6 +357,7 @@
 
 	struct v4l2_subdev *sensor_sdev; /* sensor sub device */
 	struct v4l2_subdev *act_sdev; /* actuator sub device */
+	struct v4l2_subdev *eeprom_sdev; /* actuator sub device */
 	struct msm_camera_sensor_info *sdata;
 };
 
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 4a15b7a..d791771 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -36,6 +36,7 @@
 #include "msm_actuator.h"
 #include "msm_vpe.h"
 #include "msm_vfe32.h"
+#include "msm_camera_eeprom.h"
 
 #ifdef CONFIG_MSM_CAMERA_DEBUG
 #define D(fmt, args...) pr_debug("msm_mctl: " fmt, ##args)
@@ -311,6 +312,33 @@
 		break;
 	}
 
+	case MSM_CAM_IOCTL_EEPROM_IO_CFG: {
+		struct msm_eeprom_cfg_data eeprom_data;
+		if (p_mctl->eeprom_sdev) {
+			eeprom_data.is_eeprom_supported = 1;
+			rc = v4l2_subdev_call(p_mctl->eeprom_sdev,
+				core, ioctl, VIDIOC_MSM_EEPROM_CFG, argp);
+		} else {
+			rc = copy_from_user(
+				&eeprom_data,
+				(void *)argp,
+				sizeof(struct msm_eeprom_cfg_data));
+			if (rc != 0) {
+				rc = -EFAULT;
+				break;
+			}
+			eeprom_data.is_eeprom_supported = 0;
+			rc = copy_to_user((void *)argp,
+					 &eeprom_data,
+					 sizeof(struct msm_eeprom_cfg_data));
+			if (rc != 0) {
+				rc = -EFAULT;
+				break;
+			}
+		}
+		break;
+	}
+
 	case MSM_CAM_IOCTL_GET_KERNEL_SYSTEM_TIME: {
 		struct timeval timestamp;
 		if (copy_from_user(&timestamp, argp, sizeof(timestamp))) {
@@ -815,6 +843,7 @@
 	spin_lock_init(&pmctl->pp_info.lock);
 
 	pmctl->act_sdev = pcam->act_sdev;
+	pmctl->eeprom_sdev = pcam->eeprom_sdev;
 	pmctl->sensor_sdev = pcam->sensor_sdev;
 	pmctl->sdata = pcam->sdata;
 
diff --git a/drivers/media/video/msm/sensors/Makefile b/drivers/media/video/msm/sensors/Makefile
index 07cea70..13dc446 100644
--- a/drivers/media/video/msm/sensors/Makefile
+++ b/drivers/media/video/msm/sensors/Makefile
@@ -1,6 +1,7 @@
 GCC_VERSION      := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
 EXTRA_CFLAGS += -Idrivers/media/video/msm
 EXTRA_CFLAGS += -Idrivers/media/video/msm/io
+EXTRA_CFLAGS += -Idrivers/media/video/msm/eeprom
 EXTRA_CFLAGS += -Idrivers/media/video/msm/csi
 obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor.o
 obj-$(CONFIG_OV5647) += ov5647_v4l2.o
diff --git a/drivers/media/video/msm/sensors/imx074_v4l2.c b/drivers/media/video/msm/sensors/imx074_v4l2.c
index 534b85e..7e41418 100644
--- a/drivers/media/video/msm/sensors/imx074_v4l2.c
+++ b/drivers/media/video/msm/sensors/imx074_v4l2.c
@@ -224,8 +224,6 @@
 	.vert_offset = 3,
 };
 
-static struct sensor_calib_data imx074_calib_data;
-
 static const struct i2c_device_id imx074_i2c_id[] = {
 	{SENSOR_NAME, (kernel_ulong_t)&imx074_s_ctrl},
 	{ }
@@ -243,37 +241,6 @@
 	.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
 };
 
-static struct msm_camera_i2c_client imx074_eeprom_i2c_client = {
-	.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
-};
-
-static struct msm_camera_eeprom_read_t imx074_eeprom_read_tbl[] = {
-	{0x10, &imx074_calib_data.r_over_g, 2, 1},
-	{0x12, &imx074_calib_data.b_over_g, 2, 1},
-	{0x14, &imx074_calib_data.gr_over_gb, 2, 1},
-};
-
-static struct msm_camera_eeprom_data_t imx074_eeprom_data_tbl[] = {
-	{&imx074_calib_data, sizeof(struct sensor_calib_data)},
-};
-
-static struct msm_camera_eeprom_client imx074_eeprom_client = {
-	.i2c_client = &imx074_eeprom_i2c_client,
-	.i2c_addr = 0xA4,
-
-	.func_tbl = {
-		.eeprom_set_dev_addr = NULL,
-		.eeprom_init = msm_camera_eeprom_init,
-		.eeprom_release = msm_camera_eeprom_release,
-		.eeprom_get_data = msm_camera_eeprom_get_data,
-	},
-
-	.read_tbl = imx074_eeprom_read_tbl,
-	.read_tbl_size = ARRAY_SIZE(imx074_eeprom_read_tbl),
-	.data_tbl = imx074_eeprom_data_tbl,
-	.data_tbl_size = ARRAY_SIZE(imx074_eeprom_data_tbl),
-};
-
 static int __init msm_sensor_init_module(void)
 {
 	return i2c_add_driver(&imx074_i2c_driver);
@@ -334,7 +301,6 @@
 	.msm_sensor_reg = &imx074_regs,
 	.sensor_i2c_client = &imx074_sensor_i2c_client,
 	.sensor_i2c_addr = 0x34,
-	.sensor_eeprom_client = &imx074_eeprom_client,
 	.sensor_output_reg_addr = &imx074_reg_addr,
 	.sensor_id_info = &imx074_id_info,
 	.sensor_exp_gain_info = &imx074_exp_gain_info,
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index 4b2ec49..d4d07cd 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -491,24 +491,6 @@
 				rc = -EFAULT;
 			break;
 
-		case CFG_GET_EEPROM_DATA:
-			if (s_ctrl->sensor_eeprom_client == NULL ||
-				s_ctrl->sensor_eeprom_client->
-				func_tbl.eeprom_get_data == NULL) {
-				rc = -EFAULT;
-				break;
-			}
-			rc = s_ctrl->sensor_eeprom_client->
-				func_tbl.eeprom_get_data(
-				s_ctrl->sensor_eeprom_client,
-				&cdata.cfg.eeprom_data);
-
-			if (copy_to_user((void *)argp,
-				&cdata,
-				sizeof(struct sensor_eeprom_data_t)))
-				rc = -EFAULT;
-			break;
-
 		default:
 			rc = -EFAULT;
 			break;
@@ -723,25 +705,6 @@
 	if (rc < 0)
 		goto probe_fail;
 
-	if (s_ctrl->sensor_eeprom_client != NULL) {
-		struct msm_camera_eeprom_client *eeprom_client =
-			s_ctrl->sensor_eeprom_client;
-		if (eeprom_client->func_tbl.eeprom_init != NULL &&
-			eeprom_client->func_tbl.eeprom_release != NULL) {
-			rc = eeprom_client->func_tbl.eeprom_init(
-				eeprom_client,
-				s_ctrl->sensor_i2c_client->client->adapter);
-			if (rc < 0)
-				goto probe_fail;
-
-			rc = msm_camera_eeprom_read_tbl(eeprom_client,
-			eeprom_client->read_tbl, eeprom_client->read_tbl_size);
-			eeprom_client->func_tbl.eeprom_release(eeprom_client);
-			if (rc < 0)
-				goto probe_fail;
-		}
-	}
-
 	snprintf(s_ctrl->sensor_v4l2_subdev.name,
 		sizeof(s_ctrl->sensor_v4l2_subdev.name), "%s", id->name);
 	v4l2_i2c_subdev_init(&s_ctrl->sensor_v4l2_subdev, client,
diff --git a/drivers/media/video/msm/sensors/msm_sensor.h b/drivers/media/video/msm/sensors/msm_sensor.h
index d26a9d3..22cc05b 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.h
+++ b/drivers/media/video/msm/sensors/msm_sensor.h
@@ -144,8 +144,6 @@
 	struct msm_camera_i2c_client *sensor_i2c_client;
 	uint16_t sensor_i2c_addr;
 
-	struct msm_camera_eeprom_client *sensor_eeprom_client;
-
 	struct msm_sensor_output_reg_addr_t *sensor_output_reg_addr;
 	struct msm_sensor_id_info_t *sensor_id_info;
 	struct msm_sensor_exp_gain_info_t *sensor_exp_gain_info;
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index bf02b84..3f647dc 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -187,6 +187,9 @@
 #define MSM_CAM_IOCTL_GET_ACTUATOR_INFO \
 	_IOW(MSM_CAM_IOCTL_MAGIC, 52, struct msm_actuator_cfg_data *)
 
+#define MSM_CAM_IOCTL_EEPROM_IO_CFG \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 53, struct msm_eeprom_cfg_data *)
+
 struct msm_mctl_pp_cmd {
 	int32_t  id;
 	uint16_t length;
@@ -778,18 +781,19 @@
 #define CFG_GET_3D_CALI_DATA 30
 #define CFG_GET_CALIB_DATA		31
 #define CFG_GET_OUTPUT_INFO		32
-#define CFG_GET_EEPROM_DATA		33
-#define CFG_SET_ACTUATOR_INFO		34
-#define CFG_GET_ACTUATOR_INFO           35
+#define CFG_GET_EEPROM_INFO		33
+#define CFG_GET_EEPROM_DATA		34
+#define CFG_SET_ACTUATOR_INFO		35
+#define CFG_GET_ACTUATOR_INFO           36
 /* TBD: QRD */
-#define CFG_SET_SATURATION            36
-#define CFG_SET_SHARPNESS             37
-#define CFG_SET_TOUCHAEC              38
-#define CFG_SET_AUTO_FOCUS            39
-#define CFG_SET_AUTOFLASH             40
-#define CFG_SET_EXPOSURE_COMPENSATION 41
-#define CFG_SET_ISO                   42
-#define CFG_MAX			43
+#define CFG_SET_SATURATION            37
+#define CFG_SET_SHARPNESS             38
+#define CFG_SET_TOUCHAEC              39
+#define CFG_SET_AUTO_FOCUS            40
+#define CFG_SET_AUTOFLASH             41
+#define CFG_SET_EXPOSURE_COMPENSATION 42
+#define CFG_SET_ISO                   43
+#define CFG_MAX			44
 
 
 #define MOVE_NEAR	0
@@ -1076,11 +1080,6 @@
 	uint16_t num_info;
 };
 
-struct sensor_eeprom_data_t {
-	void *eeprom_data;
-	uint16_t index;
-};
-
 struct mirror_flip {
 	int32_t x_mirror;
 	int32_t y_flip;
@@ -1091,6 +1090,11 @@
 	uint32_t y;
 };
 
+struct msm_eeprom_data_t {
+	void *eeprom_data;
+	uint16_t index;
+};
+
 struct sensor_cfg_data {
 	int cfgtype;
 	int mode;
@@ -1116,7 +1120,7 @@
 		struct sensor_3d_exp_cfg sensor_3d_exp;
 		struct sensor_calib_data calib_info;
 		struct sensor_output_info_t output_info;
-		struct sensor_eeprom_data_t eeprom_data;
+		struct msm_eeprom_data_t eeprom_data;
 		/* QRD */
 		uint16_t antibanding;
 		uint8_t contrast;
@@ -1250,6 +1254,60 @@
 	} cfg;
 };
 
+struct msm_eeprom_support {
+	uint16_t is_supported;
+	uint16_t size;
+	uint16_t index;
+	uint16_t qvalue;
+};
+
+struct msm_calib_wb {
+	uint16_t r_over_g;
+	uint16_t b_over_g;
+	uint16_t gr_over_gb;
+};
+
+struct msm_calib_af {
+	uint16_t macro_dac;
+	uint16_t inf_dac;
+	uint16_t start_dac;
+};
+
+struct msm_calib_lsc {
+	uint16_t r_gain[221];
+	uint16_t b_gain[221];
+	uint16_t gr_gain[221];
+	uint16_t gb_gain[221];
+};
+
+struct pixel_t {
+	int x;
+	int y;
+};
+
+struct msm_calib_dpc {
+	uint16_t validcount;
+	struct pixel_t snapshot_coord[128];
+	struct pixel_t preview_coord[128];
+	struct pixel_t video_coord[128];
+};
+
+struct msm_camera_eeprom_info_t {
+	struct msm_eeprom_support af;
+	struct msm_eeprom_support wb;
+	struct msm_eeprom_support lsc;
+	struct msm_eeprom_support dpc;
+};
+
+struct msm_eeprom_cfg_data {
+	int cfgtype;
+	uint8_t is_eeprom_supported;
+	union {
+		struct msm_eeprom_data_t get_data;
+		struct msm_camera_eeprom_info_t get_info;
+	} cfg;
+};
+
 struct sensor_large_data {
 	int cfgtype;
 	union {