Merge "msm: camera: Write a few registers before camera probe"
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
index c0c83e5..6f39956 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -82,9 +82,13 @@
 
 int32_t msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl)
 {
+	struct msm_camera_sensor_slave_info *slave_info = NULL;
+
 	if (!s_ctrl->pdev && !s_ctrl->sensor_i2c_client->client)
 		return 0;
 	kfree(s_ctrl->sensordata->slave_info);
+	slave_info = s_ctrl->sensordata->cam_slave_info;
+	kfree(slave_info->sensor_id_info.setting.reg_setting);
 	kfree(s_ctrl->sensordata->cam_slave_info);
 	kfree(s_ctrl->sensordata->actuator_info);
 	kfree(s_ctrl->sensordata->power_info.gpio_conf->gpio_num_info);
@@ -261,6 +265,17 @@
 		return -EINVAL;
 	}
 
+	if (slave_info->setting && slave_info->setting->size > 0) {
+		rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
+			i2c_write_table(s_ctrl->sensor_i2c_client,
+			slave_info->setting);
+		if (rc < 0)
+			pr_err("Write array failed prior to probe\n");
+
+	} else {
+		CDBG("No writes needed for this sensor before probe\n");
+	}
+
 	rc = sensor_i2c_client->i2c_func_tbl->i2c_read(
 		sensor_i2c_client, slave_info->sensor_id_reg_addr,
 		&chipid, MSM_CAMERA_I2C_WORD_DATA);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
index f80de3a..7832181 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
@@ -757,6 +757,8 @@
 
 	unsigned long                        mount_pos = 0;
 	uint32_t                             is_yuv;
+	struct msm_camera_i2c_reg_array     *reg_setting = NULL;
+	struct msm_sensor_id_info_t         *id_info = NULL;
 
 	/* Validate input parameters */
 	if (!setting) {
@@ -805,7 +807,54 @@
 		slave_info->camera_id = slave_info32->camera_id;
 
 		slave_info->i2c_freq_mode = slave_info32->i2c_freq_mode;
-		slave_info->sensor_id_info = slave_info32->sensor_id_info;
+		slave_info->sensor_id_info.sensor_id_reg_addr =
+			slave_info32->sensor_id_info.sensor_id_reg_addr;
+		slave_info->sensor_id_info.sensor_id_mask =
+			slave_info32->sensor_id_info.sensor_id_mask;
+		slave_info->sensor_id_info.sensor_id =
+			slave_info32->sensor_id_info.sensor_id;
+
+		slave_info->sensor_id_info.setting.addr_type =
+			slave_info32->sensor_id_info.setting.addr_type;
+		slave_info->sensor_id_info.setting.data_type =
+			slave_info32->sensor_id_info.setting.data_type;
+		slave_info->sensor_id_info.setting.delay =
+			slave_info32->sensor_id_info.setting.delay;
+		slave_info->sensor_id_info.setting.size =
+			slave_info32->sensor_id_info.setting.size;
+
+		if (!slave_info->sensor_id_info.setting.size ||
+			(slave_info->sensor_id_info.setting.size >
+				I2C_REG_DATA_MAX)) {
+			CDBG("%s:No writes needed to probe\n", __func__);
+			slave_info->sensor_id_info.setting.reg_setting = NULL;
+		} else {
+			id_info = &(slave_info->sensor_id_info);
+			reg_setting =
+				kzalloc(id_info->setting.size *
+					(sizeof
+					(struct msm_camera_i2c_reg_array)),
+					GFP_KERNEL);
+			if (!reg_setting) {
+				rc = -ENOMEM;
+				goto free_slave_info;
+			}
+			if (copy_from_user(reg_setting,
+				(void __user *)
+				compat_ptr(slave_info32->sensor_id_info.
+				setting.reg_setting),
+				slave_info->sensor_id_info.setting.size *
+				sizeof(struct msm_camera_i2c_reg_array))) {
+				pr_err("%s:%d: sensor id info copy failed\n",
+					__func__, __LINE__);
+				kfree(reg_setting);
+				rc = -EFAULT;
+				goto free_slave_info;
+			}
+
+			slave_info->sensor_id_info.setting.reg_setting =
+				reg_setting;
+		}
 
 		slave_info->slave_addr = slave_info32->slave_addr;
 		slave_info->power_setting_array.size =
@@ -841,6 +890,37 @@
 			rc = -EFAULT;
 			goto free_slave_info;
 		}
+		if (!slave_info->sensor_id_info.setting.size ||
+			slave_info->sensor_id_info.setting.size >
+			I2C_REG_DATA_MAX) {
+			CDBG("%s:No writes needed to probe\n", __func__);
+			slave_info->sensor_id_info.setting.reg_setting = NULL;
+		} else {
+			id_info = &(slave_info->sensor_id_info);
+			reg_setting =
+				kzalloc(id_info->setting.size *
+					(sizeof
+					(struct msm_camera_i2c_reg_array)),
+					GFP_KERNEL);
+			if (!reg_setting) {
+				rc = -ENOMEM;
+				goto free_slave_info;
+			}
+			if (copy_from_user(reg_setting,
+				(void __user *)
+				slave_info->sensor_id_info.setting.reg_setting,
+				slave_info->sensor_id_info.setting.size *
+				sizeof(struct msm_camera_i2c_reg_array))) {
+				pr_err("%s:%d: sensor id info copy failed\n",
+					__func__, __LINE__);
+				kfree(reg_setting);
+				rc = -EFAULT;
+				goto free_slave_info;
+			}
+
+			slave_info->sensor_id_info.setting.reg_setting =
+				reg_setting;
+		}
 	}
 
 	if (strlen(slave_info->sensor_name) >= MAX_SENSOR_NAME ||
@@ -956,6 +1036,7 @@
 		slave_info->sensor_id_info.sensor_id_reg_addr;
 	camera_info->sensor_id = slave_info->sensor_id_info.sensor_id;
 	camera_info->sensor_id_mask = slave_info->sensor_id_info.sensor_id_mask;
+	camera_info->setting = &(slave_info->sensor_id_info.setting);
 
 	/* Fill CCI master, slave address and CCI default params */
 	if (!s_ctrl->sensor_i2c_client) {
@@ -1116,6 +1197,7 @@
 free_camera_info:
 	kfree(camera_info);
 free_slave_info:
+	kfree(slave_info->sensor_id_info.setting.reg_setting);
 	kfree(slave_info);
 	return rc;
 }
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index 2c8b651..54cd27b 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -26,6 +26,21 @@
 	uint16_t size_down;
 };
 
+struct msm_camera_i2c_reg_setting32 {
+	compat_uptr_t reg_setting;
+	uint16_t size;
+	enum msm_camera_i2c_reg_addr_type addr_type;
+	enum msm_camera_i2c_data_type data_type;
+	uint16_t delay;
+};
+
+struct msm_sensor_id_info_t32 {
+	unsigned short sensor_id_reg_addr;
+	unsigned short sensor_id;
+	unsigned short sensor_id_mask;
+	struct msm_camera_i2c_reg_setting32 setting;
+};
+
 struct msm_camera_sensor_slave_info32 {
 	char sensor_name[32];
 	char eeprom_name[32];
@@ -36,7 +51,7 @@
 	uint16_t slave_addr;
 	enum i2c_freq_mode_t i2c_freq_mode;
 	enum msm_camera_i2c_reg_addr_type addr_type;
-	struct msm_sensor_id_info_t sensor_id_info;
+	struct msm_sensor_id_info_t32 sensor_id_info;
 	struct msm_sensor_power_setting_array32 power_setting_array;
 	uint8_t  is_init_params_valid;
 	struct msm_sensor_init_params sensor_init_params;
@@ -128,14 +143,6 @@
 	uint16_t delay;
 };
 
-struct msm_camera_i2c_reg_setting32 {
-	compat_uptr_t reg_setting;
-	uint16_t size;
-	enum msm_camera_i2c_reg_addr_type addr_type;
-	enum msm_camera_i2c_data_type data_type;
-	uint16_t delay;
-};
-
 struct msm_camera_i2c_array_write_config32 {
 	struct msm_camera_i2c_reg_setting32 conf_array;
 	uint16_t slave_addr;
diff --git a/include/soc/qcom/camera2.h b/include/soc/qcom/camera2.h
index c529aff..5139d22 100644
--- a/include/soc/qcom/camera2.h
+++ b/include/soc/qcom/camera2.h
@@ -47,6 +47,7 @@
 	uint16_t sensor_id_reg_addr;
 	uint16_t sensor_id;
 	uint16_t sensor_id_mask;
+	struct msm_camera_i2c_reg_setting *setting;
 };
 
 struct msm_cam_clk_info {
diff --git a/include/uapi/media/msm_camsensor_sdk.h b/include/uapi/media/msm_camsensor_sdk.h
index 6d25967..63abd156 100644
--- a/include/uapi/media/msm_camsensor_sdk.h
+++ b/include/uapi/media/msm_camsensor_sdk.h
@@ -50,6 +50,8 @@
 
 #define MSM_SENSOR_BYPASS_VIDEO_NODE    1
 
+#define SENSOR_PROBE_WRITE
+
 enum msm_sensor_camera_id_t {
 	CAMERA_0,
 	CAMERA_1,
@@ -292,10 +294,19 @@
 	unsigned int            sensor_mount_angle;
 };
 
+struct msm_camera_i2c_reg_setting {
+	struct msm_camera_i2c_reg_array *reg_setting;
+	unsigned short size;
+	enum msm_camera_i2c_reg_addr_type addr_type;
+	enum msm_camera_i2c_data_type data_type;
+	unsigned short delay;
+};
+
 struct msm_sensor_id_info_t {
 	unsigned short sensor_id_reg_addr;
 	unsigned short sensor_id;
 	unsigned short sensor_id_mask;
+	struct msm_camera_i2c_reg_setting setting;
 };
 
 struct msm_camera_sensor_slave_info {
@@ -322,14 +333,6 @@
 	unsigned int delay;
 };
 
-struct msm_camera_i2c_reg_setting {
-	struct msm_camera_i2c_reg_array *reg_setting;
-	unsigned short size;
-	enum msm_camera_i2c_reg_addr_type addr_type;
-	enum msm_camera_i2c_data_type data_type;
-	unsigned short delay;
-};
-
 struct msm_camera_csid_vc_cfg {
 	unsigned char cid;
 	unsigned char dt;