Merge "Merge commit 'f0ce15af0bab0fcf877b74d18fc1edb3ef2402de' into msm-4.9-PC112"
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
index 8c04f12..8523ce7 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
@@ -2834,8 +2834,23 @@
 			packet->header.op_code & 0xff);
 		return -EINVAL;
 	}
-	CAM_DBG(CAM_ICP, "number of cmd/patch info: %u %u",
-			packet->num_cmd_buf, packet->num_patches);
+
+	if (packet->num_io_configs > IPE_IO_IMAGES_MAX) {
+		CAM_ERR(CAM_ICP, "Invalid number of io configs: %d %d",
+			IPE_IO_IMAGES_MAX, packet->num_io_configs);
+		return -EINVAL;
+	}
+
+	if (packet->num_cmd_buf > CAM_ICP_CTX_MAX_CMD_BUFFERS) {
+		CAM_ERR(CAM_ICP, "Invalid number of cmd buffers: %d %d",
+			CAM_ICP_CTX_MAX_CMD_BUFFERS, packet->num_cmd_buf);
+		return -EINVAL;
+	}
+
+	CAM_DBG(CAM_ICP, "number of cmd/patch info: %u %u %u %u",
+			packet->num_cmd_buf,
+			packet->num_io_configs, IPE_IO_IMAGES_MAX,
+			packet->num_patches);
 	return 0;
 }
 
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
index aac4a5e..1bca3da 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
@@ -68,6 +68,8 @@
 #define CAM_ICP_CTX_STATE_ACQUIRED  0x2
 #define CAM_ICP_CTX_STATE_RELEASE   0x3
 
+#define CAM_ICP_CTX_MAX_CMD_BUFFERS 0x2
+
 /**
  * struct icp_hfi_mem_info
  * @qtbl: Memory info of queue table
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
index ff0c91f..2931fda 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
@@ -1037,16 +1037,23 @@
 
 static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw)
 {
-	int rc = 0;
+	int rc = -EINVAL;
 	struct cam_hw_soc_info             *soc_info;
 	struct cam_ife_csid_reg_offset     *csid_reg;
 
+	/* Check for refcount */
+	if (!csid_hw->hw_info->open_count) {
+		CAM_WARN(CAM_ISP, "Unbalanced disable_hw");
+		return rc;
+	}
 
 	/*  Decrement ref Count */
-	if (csid_hw->hw_info->open_count)
-		csid_hw->hw_info->open_count--;
-	if (csid_hw->hw_info->open_count)
+	csid_hw->hw_info->open_count--;
+
+	if (csid_hw->hw_info->open_count) {
+		rc = 0;
 		return rc;
+	}
 
 	soc_info = &csid_hw->hw_info->soc_info;
 	csid_reg = csid_hw->csid_info->csid_reg;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
index f4aa5c3..3f843c3 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
@@ -273,7 +273,8 @@
 	}
 
 	if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) {
-		CAM_DBG(CAM_ISP, "VFE:%d Not ready to set clocks yet :%d",
+		CAM_ERR_RATE_LIMIT(CAM_ISP,
+			"VFE:%d Not ready to set clocks yet :%d",
 			res->hw_intf->hw_idx,
 			hw_info->hw_state);
 	} else
@@ -321,7 +322,8 @@
 	}
 
 	if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) {
-		CAM_DBG(CAM_ISP, "VFE:%d Not ready to set BW yet :%d",
+		CAM_ERR_RATE_LIMIT(CAM_ISP,
+			"VFE:%d Not ready to set BW yet :%d",
 			res->hw_intf->hw_idx,
 			hw_info->hw_state);
 	} else
@@ -364,7 +366,8 @@
 	}
 
 	if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) {
-		CAM_DBG(CAM_ISP, "VFE:%d Not ready to set BW yet :%d",
+		CAM_ERR_RATE_LIMIT(CAM_ISP,
+			"VFE:%d Not ready to set BW yet :%d",
 			res->hw_intf->hw_idx,
 			hw_info->hw_state);
 	} else {
@@ -517,6 +520,7 @@
 {
 	struct cam_vfe_top_ver2_priv            *top_priv;
 	struct cam_isp_resource_node            *mux_res;
+	struct cam_hw_info                      *hw_info = NULL;
 	int rc = 0;
 
 	if (!device_priv || !start_args) {
@@ -526,24 +530,33 @@
 
 	top_priv = (struct cam_vfe_top_ver2_priv *)device_priv;
 	mux_res = (struct cam_isp_resource_node *)start_args;
+	hw_info = (struct cam_hw_info  *)mux_res->hw_intf->hw_priv;
 
-	rc = cam_vfe_top_set_hw_clk_rate(top_priv);
-	if (rc) {
-		CAM_ERR(CAM_ISP, "set_hw_clk_rate failed, rc=%d", rc);
-		return rc;
-	}
+	if (hw_info->hw_state == CAM_HW_STATE_POWER_UP) {
+		rc = cam_vfe_top_set_hw_clk_rate(top_priv);
+		if (rc) {
+			CAM_ERR(CAM_ISP,
+				"set_hw_clk_rate failed, rc=%d", rc);
+			return rc;
+		}
 
-	rc = cam_vfe_top_set_axi_bw_vote(top_priv, true);
-	if (rc) {
-		CAM_ERR(CAM_ISP, "set_axi_bw_vote failed, rc=%d", rc);
-		return rc;
-	}
+		rc = cam_vfe_top_set_axi_bw_vote(top_priv, true);
+		if (rc) {
+			CAM_ERR(CAM_ISP,
+				"set_axi_bw_vote failed, rc=%d", rc);
+			return rc;
+		}
 
-	if (mux_res->start) {
-		rc = mux_res->start(mux_res);
+		if (mux_res->start) {
+			rc = mux_res->start(mux_res);
+		} else {
+			CAM_ERR(CAM_ISP,
+				"Invalid res id:%d", mux_res->res_id);
+			rc = -EINVAL;
+		}
 	} else {
-		CAM_ERR(CAM_ISP, "Invalid res id:%d", mux_res->res_id);
-		rc = -EINVAL;
+		CAM_ERR(CAM_ISP, "VFE HW not powered up");
+		rc = -EPERM;
 	}
 
 	return rc;
@@ -554,6 +567,7 @@
 {
 	struct cam_vfe_top_ver2_priv            *top_priv;
 	struct cam_isp_resource_node            *mux_res;
+	struct cam_hw_info                      *hw_info = NULL;
 	int i, rc = 0;
 
 	if (!device_priv || !stop_args) {
@@ -563,6 +577,7 @@
 
 	top_priv = (struct cam_vfe_top_ver2_priv   *)device_priv;
 	mux_res = (struct cam_isp_resource_node *)stop_args;
+	hw_info = (struct cam_hw_info  *)mux_res->hw_intf->hw_priv;
 
 	if (mux_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF ||
 		(mux_res->res_id >= CAM_ISP_HW_VFE_IN_RDI0 &&
@@ -585,16 +600,23 @@
 			}
 		}
 
-		rc = cam_vfe_top_set_hw_clk_rate(top_priv);
-		if (rc) {
-			CAM_ERR(CAM_ISP, "set_hw_clk_rate failed, rc=%d", rc);
-			return rc;
-		}
+		if (hw_info->hw_state == CAM_HW_STATE_POWER_UP) {
+			rc = cam_vfe_top_set_hw_clk_rate(top_priv);
+			if (rc) {
+				CAM_ERR(CAM_ISP,
+					"set_hw_clk_rate failed, rc=%d", rc);
+				return rc;
+			}
 
-		rc = cam_vfe_top_set_axi_bw_vote(top_priv, true);
-		if (rc) {
-			CAM_ERR(CAM_ISP, "set_axi_bw_vote failed, rc=%d", rc);
-			return rc;
+			rc = cam_vfe_top_set_axi_bw_vote(top_priv, true);
+			if (rc) {
+				CAM_ERR(CAM_ISP,
+					"set_axi_bw_vote failed, rc=%d", rc);
+				return rc;
+			}
+		} else {
+			CAM_ERR(CAM_ISP, "VFE HW not powered up");
+			rc = -EPERM;
 		}
 	}
 
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
index 262e49c..4f30f56 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. 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
@@ -71,9 +71,9 @@
 			csiphy_reset_reg[i].reg_addr);
 
 		usleep_range(csiphy_dev->ctrl_reg->
-			csiphy_reset_reg[i].delay * 100,
+			csiphy_reset_reg[i].delay * 1000,
 			csiphy_dev->ctrl_reg->
-			csiphy_reset_reg[i].delay * 100 + 1000);
+			csiphy_reset_reg[i].delay * 1000 + 10);
 	}
 }
 
@@ -285,6 +285,10 @@
 					csiphybase +
 					csiphy_dev->ctrl_reg->
 					csiphy_common_reg[i].reg_addr);
+				usleep_range(csiphy_dev->ctrl_reg->
+					csiphy_common_reg[i].delay*1000,
+					csiphy_dev->ctrl_reg->
+					csiphy_common_reg[i].delay*1000 + 10);
 			break;
 			case CSIPHY_DEFAULT_PARAMS:
 				cam_io_w_mb(csiphy_dev->ctrl_reg->
@@ -292,6 +296,10 @@
 					csiphybase +
 					csiphy_dev->ctrl_reg->
 					csiphy_common_reg[i].reg_addr);
+				usleep_range(csiphy_dev->ctrl_reg->
+					csiphy_common_reg[i].delay*1000,
+					csiphy_dev->ctrl_reg->
+					csiphy_common_reg[i].delay*1000 + 10);
 			break;
 			default:
 			break;
@@ -506,6 +514,13 @@
 		bridge_params.media_entity_flag = 0;
 		bridge_params.priv = csiphy_dev;
 
+		if (csiphy_acq_params.combo_mode >= 2) {
+			CAM_ERR(CAM_CSIPHY, "Invalid combo_mode %d",
+				csiphy_acq_params.combo_mode);
+			rc = -EINVAL;
+			goto release_mutex;
+		}
+
 		csiphy_acq_dev.device_handle =
 			cam_create_device_hdl(&bridge_params);
 		csiphy_dev->bridge_intf.
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c
index 131b0ae..07b390b 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. 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
@@ -468,6 +468,63 @@
 	return rc;
 }
 
+int32_t cam_spi_write_seq(struct camera_io_master *client,
+	uint32_t addr, uint8_t *data,
+	enum camera_sensor_i2c_type addr_type, uint32_t num_byte)
+{
+	struct cam_camera_spi_inst *pg =
+		&client->spi_client->cmd_tbl.page_program;
+	const uint32_t page_size = client->spi_client->page_size;
+	uint8_t header_len = sizeof(pg->opcode) + pg->addr_len + pg->dummy_len;
+	uint16_t len;
+	uint32_t cur_len, end;
+	char *tx, *pdata = data;
+	int rc = -EINVAL;
+
+	if ((addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) ||
+		(addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID))
+		return rc;
+    /* single page write */
+	if ((addr % page_size) + num_byte <= page_size) {
+		len = header_len + num_byte;
+		tx = kmalloc(len, GFP_KERNEL | GFP_DMA);
+		if (!tx)
+			goto NOMEM;
+		rc = cam_spi_page_program(client, addr, data, addr_type,
+			num_byte, tx);
+		if (rc < 0)
+			goto ERROR;
+		goto OUT;
+	}
+	/* multi page write */
+	len = header_len + page_size;
+	tx = kmalloc(len, GFP_KERNEL | GFP_DMA);
+	if (!tx)
+		goto NOMEM;
+	while (num_byte) {
+		end = min(page_size, (addr % page_size) + num_byte);
+		cur_len = end - (addr % page_size);
+		CAM_ERR(CAM_SENSOR, "Addr: 0x%x curr_len: 0x%x pgSize: %d",
+			addr, cur_len, page_size);
+		rc = cam_spi_page_program(client, addr, pdata, addr_type,
+			cur_len, tx);
+		if (rc < 0)
+			goto ERROR;
+		addr += cur_len;
+		pdata += cur_len;
+		num_byte -= cur_len;
+	}
+	goto OUT;
+NOMEM:
+	pr_err("%s: memory allocation failed\n", __func__);
+	return -ENOMEM;
+ERROR:
+	pr_err("%s: error write\n", __func__);
+OUT:
+	kfree(tx);
+	return rc;
+}
+
 int cam_spi_write_table(struct camera_io_master *client,
 	struct cam_sensor_i2c_reg_setting *write_setting)
 {
@@ -508,3 +565,35 @@
 	addr_type = client_addr_type;
 	return rc;
 }
+
+int cam_spi_erase(struct camera_io_master *client,
+	uint32_t addr, enum camera_sensor_i2c_type addr_type,
+	uint32_t size) {
+	struct cam_camera_spi_inst *se = &client->spi_client->cmd_tbl.erase;
+	int rc = 0;
+	uint32_t cur;
+	uint32_t end = addr + size;
+	uint32_t erase_size = client->spi_client->erase_size;
+
+	end = addr + size;
+	for (cur = rounddown(addr, erase_size); cur < end; cur += erase_size) {
+		CAM_ERR(CAM_SENSOR, "%s: erasing 0x%x size: %d\n",
+			__func__, cur, erase_size);
+		rc = cam_spi_write_enable(client, addr_type);
+		if (rc < 0)
+			return rc;
+		rc = cam_spi_tx_helper(client, se, cur, NULL, addr_type, 0,
+			NULL, NULL);
+		if (rc < 0) {
+			CAM_ERR(CAM_SENSOR, "%s: erase failed\n", __func__);
+			return rc;
+		}
+		rc = cam_spi_wait(client, se, addr_type);
+		if (rc < 0) {
+			CAM_ERR(CAM_SENSOR, "%s: erase timedout\n", __func__);
+			return rc;
+		}
+	}
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h
index ec1bede..a63bff2 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. 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
@@ -99,4 +99,12 @@
 int cam_spi_write_table(struct camera_io_master *client,
 	struct cam_sensor_i2c_reg_setting *write_setting);
 
+int cam_spi_erase(struct camera_io_master *client,
+	uint32_t addr, enum camera_sensor_i2c_type addr_type,
+	uint32_t size);
+
+int32_t cam_spi_write_seq(struct camera_io_master *client,
+	uint32_t addr, uint8_t *data,
+	enum camera_sensor_i2c_type addr_type, uint32_t num_byte);
+
 #endif