Merge "msm: camera: Add QUP i2c burst and sequential write support" into dev/msm-4.9-camx
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h
index 10b07ec..7cddcf9 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h
@@ -163,4 +163,18 @@
 int32_t cam_qup_i2c_write_table(
 	struct camera_io_master *client,
 	struct cam_sensor_i2c_reg_setting *write_setting);
+
+/**
+ * cam_qup_i2c_write_continuous_write: QUP based I2C write continuous(Burst/Seq)
+ * @client: QUP I2C client structure
+ * @write_setting: I2C register setting
+ * @cam_sensor_i2c_write_flag: burst or seq write
+ *
+ * This API handles QUP continuous write
+ */
+int32_t cam_qup_i2c_write_continuous_table(
+	struct camera_io_master *client,
+	struct cam_sensor_i2c_reg_setting *write_setting,
+	uint8_t cam_sensor_i2c_write_flag);
+
 #endif /*_CAM_SENSOR_I2C_H*/
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
index 8eb04ec..d69ff47 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
@@ -129,8 +129,8 @@
 		return cam_cci_i2c_write_continuous_table(io_master_info,
 			write_setting, cam_sensor_i2c_write_flag);
 	} else if (io_master_info->master_type == I2C_MASTER) {
-		return cam_qup_i2c_write_table(io_master_info,
-			write_setting);
+		return cam_qup_i2c_write_continuous_table(io_master_info,
+			write_setting, cam_sensor_i2c_write_flag);
 	} else if (io_master_info->master_type == SPI_MASTER) {
 		return cam_spi_write_table(io_master_info,
 			write_setting);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c
index 72e51ee..1c6ab0b 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c
@@ -353,3 +353,174 @@
 
 	return rc;
 }
+
+static int32_t cam_qup_i2c_write_seq(struct camera_io_master *client,
+	struct cam_sensor_i2c_reg_setting *write_setting)
+{
+	int i;
+	int32_t rc = 0;
+	struct cam_sensor_i2c_reg_array *reg_setting;
+
+	reg_setting = write_setting->reg_setting;
+
+	for (i = 0; i < write_setting->size; i++) {
+		reg_setting->reg_addr += i;
+		rc = cam_qup_i2c_write(client, reg_setting,
+			write_setting->addr_type, write_setting->data_type);
+		if (rc < 0) {
+			CAM_ERR(CAM_SENSOR,
+				"Sequential i2c write failed: rc: %d", rc);
+			break;
+		}
+		reg_setting++;
+	}
+
+	if (write_setting->delay > 20)
+		msleep(write_setting->delay);
+	else if (write_setting->delay)
+		usleep_range(write_setting->delay * 1000, (write_setting->delay
+			* 1000) + 1000);
+
+	return rc;
+}
+
+static int32_t cam_qup_i2c_write_burst(struct camera_io_master *client,
+	struct cam_sensor_i2c_reg_setting *write_setting)
+{
+	int i;
+	int32_t rc = 0;
+	uint32_t len = 0;
+	unsigned char *buf = NULL;
+	struct cam_sensor_i2c_reg_array *reg_setting;
+	enum camera_sensor_i2c_type addr_type;
+	enum camera_sensor_i2c_type data_type;
+
+	buf = kzalloc((write_setting->addr_type +
+			(write_setting->size * write_setting->data_type)),
+			GFP_KERNEL);
+
+	if (!buf) {
+		CAM_ERR(CAM_SENSOR, "BUF is NULL");
+		return -ENOMEM;
+	}
+
+	reg_setting = write_setting->reg_setting;
+	addr_type = write_setting->addr_type;
+	data_type = write_setting->data_type;
+
+	CAM_DBG(CAM_SENSOR, "reg addr = 0x%x data type: %d",
+			reg_setting->reg_addr, data_type);
+	if (addr_type == CAMERA_SENSOR_I2C_TYPE_BYTE) {
+		buf[0] = reg_setting->reg_addr;
+		CAM_DBG(CAM_SENSOR, "byte %d: 0x%x", len, buf[len]);
+		len = 1;
+	} else if (addr_type == CAMERA_SENSOR_I2C_TYPE_WORD) {
+		buf[0] = reg_setting->reg_addr >> 8;
+		buf[1] = reg_setting->reg_addr;
+		CAM_DBG(CAM_SENSOR, "byte %d: 0x%x", len, buf[len]);
+		CAM_DBG(CAM_SENSOR, "byte %d: 0x%x", len+1, buf[len+1]);
+		len = 2;
+	} else if (addr_type == CAMERA_SENSOR_I2C_TYPE_3B) {
+		buf[0] = reg_setting->reg_addr >> 16;
+		buf[1] = reg_setting->reg_addr >> 8;
+		buf[2] = reg_setting->reg_addr;
+		len = 3;
+	} else if (addr_type == CAMERA_SENSOR_I2C_TYPE_DWORD) {
+		buf[0] = reg_setting->reg_addr >> 24;
+		buf[1] = reg_setting->reg_addr >> 16;
+		buf[2] = reg_setting->reg_addr >> 8;
+		buf[3] = reg_setting->reg_addr;
+		len = 4;
+	} else {
+		CAM_ERR(CAM_SENSOR, "Invalid I2C addr type");
+		rc = -EINVAL;
+		goto free_res;
+	}
+
+	for (i = 0; i < write_setting->size; i++) {
+		if (data_type == CAMERA_SENSOR_I2C_TYPE_BYTE) {
+			buf[len] = reg_setting->reg_data;
+			CAM_DBG(CAM_SENSOR,
+				"Byte %d: 0x%x", len, buf[len]);
+			len += 1;
+		} else if (data_type == CAMERA_SENSOR_I2C_TYPE_WORD) {
+			buf[len] = reg_setting->reg_data >> 8;
+			buf[len+1] = reg_setting->reg_data;
+			CAM_DBG(CAM_SENSOR,
+				"Byte %d: 0x%x", len, buf[len]);
+			CAM_DBG(CAM_SENSOR,
+				"Byte %d: 0x%x", len+1, buf[len+1]);
+			len += 2;
+		} else if (data_type == CAMERA_SENSOR_I2C_TYPE_3B) {
+			buf[len] = reg_setting->reg_data >> 16;
+			buf[len + 1] = reg_setting->reg_data >> 8;
+			buf[len + 2] = reg_setting->reg_data;
+			CAM_DBG(CAM_SENSOR,
+				"Byte %d: 0x%x", len, buf[len]);
+			CAM_DBG(CAM_SENSOR,
+				"Byte %d: 0x%x", len+1, buf[len+1]);
+			CAM_DBG(CAM_SENSOR,
+				"Byte %d: 0x%x", len+2, buf[len+2]);
+			len += 3;
+		} else if (data_type == CAMERA_SENSOR_I2C_TYPE_DWORD) {
+			buf[len] = reg_setting->reg_data >> 24;
+			buf[len + 1] = reg_setting->reg_data >> 16;
+			buf[len + 2] = reg_setting->reg_data >> 8;
+			buf[len + 3] = reg_setting->reg_data;
+			CAM_DBG(CAM_SENSOR,
+				"Byte %d: 0x%x", len, buf[len]);
+			CAM_DBG(CAM_SENSOR,
+				"Byte %d: 0x%x", len+1, buf[len+1]);
+			CAM_DBG(CAM_SENSOR,
+				"Byte %d: 0x%x", len+2, buf[len+2]);
+			CAM_DBG(CAM_SENSOR,
+				"Byte %d: 0x%x", len+3, buf[len+3]);
+			len += 4;
+		} else {
+			CAM_ERR(CAM_SENSOR, "Invalid Data Type");
+			rc = -EINVAL;
+			goto free_res;
+		}
+		reg_setting++;
+	}
+
+	if (len > (write_setting->addr_type +
+		(write_setting->size * write_setting->data_type))) {
+		CAM_ERR(CAM_SENSOR, "Invalid Length: %u | Expected length: %u",
+			len, (write_setting->addr_type +
+			(write_setting->size * write_setting->data_type)));
+		rc = -EINVAL;
+		goto free_res;
+	}
+
+	rc = cam_qup_i2c_txdata(client, buf, len);
+	if (rc < 0)
+		CAM_ERR(CAM_SENSOR, "failed rc: %d", rc);
+
+free_res:
+	kfree(buf);
+	return rc;
+}
+
+int32_t cam_qup_i2c_write_continuous_table(struct camera_io_master *client,
+	struct cam_sensor_i2c_reg_setting *write_settings,
+	uint8_t cam_sensor_i2c_write_flag)
+{
+	int32_t rc = 0;
+
+	if (!client || !write_settings)
+		return -EINVAL;
+
+	if ((write_settings->addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
+		|| write_settings->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX
+		|| (write_settings->data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
+		|| write_settings->data_type >= CAMERA_SENSOR_I2C_TYPE_MAX)))
+		return -EINVAL;
+
+	if (cam_sensor_i2c_write_flag == CAM_SENSOR_I2C_WRITE_BURST)
+		rc = cam_qup_i2c_write_burst(client, write_settings);
+	else if (cam_sensor_i2c_write_flag == CAM_SENSOR_I2C_WRITE_SEQ)
+		rc = cam_qup_i2c_write_seq(client, write_settings);
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
index 0a3878e..da4ed90 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
@@ -231,6 +231,8 @@
 		cam_cmd_i2c_continuous_wr->header.addr_type;
 	i2c_list->i2c_settings.data_type =
 		cam_cmd_i2c_continuous_wr->header.data_type;
+	i2c_list->i2c_settings.size =
+		cam_cmd_i2c_continuous_wr->header.count;
 
 	for (cnt = 0; cnt < (cam_cmd_i2c_continuous_wr->header.count);
 		cnt++) {