Răsfoiți Sursa

msm: camera: sensor: Add CCI BURST WRITE Support

Introduce Threshold IRQ and compose dynamically
allocated buffer with CCI BURST WRITE Commands
and finally write to the CCI HW register and
manage Threshold Interrupts in optimized way. So,
that SW Driver latencies will not affect the I2C
BURST WRITE functionality.

CRs-Fixed: 3562709
Change-Id: I5749ba3b61e28d8f2c1075f46f470f5a9c5bd6b5
Signed-off-by: Lokesh Kumar Aakulu <[email protected]>
(cherry picked from commit 1e4f481db9076c766b7300bb65364a13a61247c1)
Lokesh Kumar Aakulu 2 ani în urmă
părinte
comite
3efecb742f

+ 434 - 12
drivers/cam_sensor_module/cam_cci/cam_cci_core.c

@@ -218,8 +218,13 @@ static void cam_cci_lock_queue(struct cci_device *cci_dev,
 	cam_io_w_mb(val, base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
 		reg_offset);
 
-	read_val = cam_io_r_mb(base +
-		CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset);
+	if (cci_dev->cci_master_info[master].is_burst_enable[queue] == true) {
+		cci_dev->cci_master_info[master].num_words_exec[queue]++;
+		read_val = cci_dev->cci_master_info[master].num_words_exec[queue];
+	} else {
+		read_val = cam_io_r_mb(base +
+			CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset);
+	}
 
 	CAM_DBG(CAM_CCI, "CCI%d_I2C_M%d_Q%d_EXEC_WORD_CNT_ADDR %d",
 		cci_dev->soc_info.index, master, queue, read_val);
@@ -353,14 +358,19 @@ static void cam_cci_load_report_cmd(struct cci_device *cci_dev,
 	cam_io_w_mb(report_val,
 		base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
 		reg_offset);
-	read_val++;
-
+	if (cci_dev->cci_master_info[master].is_burst_enable[queue] == true) {
+		cci_dev->cci_master_info[master].num_words_exec[queue]++;
+		read_val = cci_dev->cci_master_info[master].num_words_exec[queue];
+	} else {
+		read_val++;
+	}
 	cci_dev->cci_i2c_queue_info[master][queue].report_id++;
 	if (cci_dev->cci_i2c_queue_info[master][queue].report_id == REPORT_IDSIZE)
 		cci_dev->cci_i2c_queue_info[master][queue].report_id = 0;
 
-	CAM_DBG(CAM_CCI, "CCI%d_I2C_M%d_Q%d_EXEC_WORD_CNT_ADDR %d",
-		cci_dev->soc_info.index, master, queue, read_val);
+	CAM_DBG(CAM_CCI, "CCI%d_I2C_M%d_Q%d_EXEC_WORD_CNT_ADDR %d (ReadValue: %u)",
+		cci_dev->soc_info.index, master, queue, read_val,
+		cam_io_r_mb(base + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset));
 	cam_io_w_mb(read_val, base +
 		CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset);
 }
@@ -730,6 +740,403 @@ static int32_t cam_cci_set_clk_param(struct cci_device *cci_dev,
 	return 0;
 }
 
+static int32_t cam_cci_data_queue_burst(struct cci_device *cci_dev,
+	struct cam_cci_ctrl *c_ctrl, enum cci_i2c_queue_t queue,
+	enum cci_i2c_sync sync_en)
+{
+	uint16_t i = 0, j = 0, len = 0;
+	int32_t rc = 0, en_seq_write = 0;
+	struct cam_sensor_i2c_reg_setting *i2c_msg =
+		&c_ctrl->cfg.cci_i2c_write_cfg;
+	struct cam_sensor_i2c_reg_array *i2c_cmd = i2c_msg->reg_setting;
+	enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master;
+	uint16_t reg_addr = 0, cmd_size = i2c_msg->size;
+	uint32_t reg_offset, val, delay = 0;
+	uint32_t max_queue_size, queue_size = 0;
+	struct cam_hw_soc_info *soc_info =
+		&cci_dev->soc_info;
+	void __iomem *base = soc_info->reg_map[0].mem_base;
+	uint32_t reg_val = 1 << ((master * 2) + queue);
+	unsigned long flags;
+	uint8_t next_position = i2c_msg->data_type;
+	uint32_t half_queue_mark = 0, full_queue_mark = 0, num_payload = 0;
+	uint32_t num_word_written_to_queue = 0;
+	uint32_t *data_queue = NULL;
+	uint8_t data_len = 0, addr_len = 0;
+	uint32_t index = 0;
+	uint8_t *buf = NULL;
+	uint32_t iterate = 0;
+	uint32_t num_bytes = 0;
+	uint32_t last_i2c_full_payload = 0;
+	uint32_t num_words_in_queue = 0;
+	uint32_t trigger_half_queue = 0, queue_start_threshold = 0;
+	bool condition = false;
+
+	if (i2c_cmd == NULL) {
+		CAM_ERR(CAM_CCI, "CCI%d_I2C_M%d_Q%d Failed: i2c cmd is NULL",
+			cci_dev->soc_info.index, master, queue);
+		return -EINVAL;
+	}
+
+	if ((!cmd_size) || (cmd_size > CCI_I2C_MAX_WRITE)) {
+		CAM_ERR(CAM_CCI, "CCI%d_I2C_M%d_Q%d failed: invalid cmd_size %d",
+			cci_dev->soc_info.index, master, queue, cmd_size);
+		return -EINVAL;
+	}
+
+	CAM_DBG(CAM_CCI, "CCI%d_I2C_M%d_Q%d addr type %d data type %d cmd_size %d",
+		cci_dev->soc_info.index, master, queue, i2c_msg->addr_type, i2c_msg->data_type, cmd_size);
+
+	if (i2c_msg->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) {
+		CAM_ERR(CAM_CCI, "CCI%d_I2C_M%d_Q%d failed: invalid addr_type 0x%X",
+			cci_dev->soc_info.index, master, queue, i2c_msg->addr_type);
+		return -EINVAL;
+	}
+	if (i2c_msg->data_type >= CAMERA_SENSOR_I2C_TYPE_MAX) {
+		CAM_ERR(CAM_CCI, "CCI%d_I2C_M%d_Q%d failed: invalid data_type 0x%X",
+			cci_dev->soc_info.index, master, queue, i2c_msg->data_type);
+		return -EINVAL;
+	}
+
+	addr_len = cam_cci_convert_type_to_num_bytes(i2c_msg->addr_type);
+	data_len = cam_cci_convert_type_to_num_bytes(i2c_msg->data_type);
+	len = (cmd_size * data_len + addr_len);
+	last_i2c_full_payload = len/MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11;
+	/*
+	 * For every 11 Bytes of Data 1 Byte of data is Control cmd: 0xF9 or 0xE9 or {0x19 to 0xB9}
+	 * Hence compute will account for "len/PAYLOAD_SIZE_11"
+	 */
+	len = len + len/MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11 +
+		(((len % MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11) == 0) ? 0 : 1);
+	if (len % 4) {
+		len = len/4 + 1;
+	} else {
+		len = len/4;
+	}
+	/* Its possible that 8 number of CCI cmds, each 32-bit
+	 * can co-exisist in QUEUE along with I2C Data
+	 */
+	len = len + 8;
+
+	data_queue = kzalloc((len * sizeof(uint32_t)),
+			GFP_KERNEL);
+	if (!data_queue) {
+		CAM_ERR(CAM_CCI, "Unable to allocate memory, BUF is NULL");
+		return -ENOMEM;
+	}
+
+	reg_offset = master * 0x200 + queue * 0x100;
+
+	cam_io_w_mb(cci_dev->cci_wait_sync_cfg.cid,
+		base + CCI_SET_CID_SYNC_TIMER_ADDR +
+		cci_dev->cci_wait_sync_cfg.csid *
+		CCI_SET_CID_SYNC_TIMER_OFFSET);
+
+	/* Retry count is not supported in BURST MODE */
+	c_ctrl->cci_info->retries = 0;
+
+	/* 
+	 * 1. Configure Slave ID through SET_PARAM_CMD
+	 *    For Burst Mode retries are not supported.
+	 *    Record the number of words written to QUEUE
+	*/
+	val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 |
+		c_ctrl->cci_info->retries << 16 |
+		c_ctrl->cci_info->id_map << 18;
+
+	CAM_DBG(CAM_CCI, "CCI%d_I2C_M%d_Q%d_LOAD_DATA_ADDR:val 0x%x:0x%x",
+		cci_dev->soc_info.index, master, queue, CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+		reg_offset, val);
+	cam_io_w_mb(val, base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+		reg_offset);
+	index++;
+
+	/* 
+	 * 2. Initialize the variables used for synchronizing between
+	 *    process context and CCI IRQ Context
+	 */
+	spin_lock_irqsave(&cci_dev->cci_master_info[master].lock_q[queue],
+		flags);
+	atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 0);
+	// atomic_set(&cci_dev->cci_master_info[master].th_irq_ref_cnt[queue], 0);
+	reinit_completion(&cci_dev->cci_master_info[master].th_burst_complete[queue]);
+	spin_unlock_irqrestore(&cci_dev->cci_master_info[master].lock_q[queue],
+		flags);
+	cci_dev->cci_master_info[master].th_irq_ref_cnt[queue] = 0;
+
+	max_queue_size =
+		cci_dev->cci_i2c_queue_info[master][queue].max_queue_size;
+
+	if ((c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ) ||
+		(c_ctrl->cmd == MSM_CCI_I2C_WRITE_BURST))
+		queue_size = max_queue_size;
+	else
+		queue_size = max_queue_size / 2;
+	reg_addr = i2c_cmd->reg_addr;
+
+	if (sync_en == MSM_SYNC_ENABLE && cci_dev->valid_sync &&
+		cmd_size < max_queue_size) {
+		val = CCI_I2C_WAIT_SYNC_CMD |
+			((cci_dev->cci_wait_sync_cfg.line) << 4);
+		cam_io_w_mb(val,
+			base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+			reg_offset);
+		index++;
+	}
+
+	/* 3. LOCK the QUEUE So that we can start BURST WRITE*/
+	cam_cci_lock_queue(cci_dev, master, queue, 1);
+	index++;
+
+	/*
+	 * 4. Need to place 0xE0 marker in middle and end of the QUEUE to trigger
+	 *    Thresold Interrupt
+	 */
+	full_queue_mark = (queue_size - index - 1) / MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_WORDS;
+	half_queue_mark = full_queue_mark / 2;
+	CAM_DBG(CAM_CCI, "CCI%d_I2C_M%d_Q%d queue_size: %d full_queue_mark: %d half_queue_mark: %d",
+		cci_dev->soc_info.index, master, queue, queue_size, full_queue_mark, half_queue_mark);
+
+	/*
+	 * 5. Iterate through entire size of settings ==> {reg_addr, reg_data}
+	 *    and formulate in QUEUE0 like below
+	 *            D2 A1 A2 F9  ==> 0xF9: Hold the BUS for I2C WRITE; {0xA2A1, 0xD2D1,
+	 *            D6 D3 D4 D1  ==> 0xD4D3, 0xD6D5, 0xD8D7, 0xD10D9.......}
+	 *           D10 D7 D8 D5
+	 */
+
+	index = 0;
+	buf = (uint8_t *) &data_queue[index];
+	while (cmd_size) {
+		delay = i2c_cmd->delay;
+		i = 0;
+		buf[i++] = CCI_I2C_WRITE_CMD;
+
+		if (en_seq_write == 0) {
+			for (j = 0; j < i2c_msg->addr_type; j++) {
+				buf[i2c_msg->addr_type - j] = (reg_addr >> (j * 8)) & 0xFF;
+				i++;
+			}
+		}
+		do {
+			if (i2c_msg->data_type == CAMERA_SENSOR_I2C_TYPE_BYTE) {
+				buf[i++] = i2c_cmd->reg_data;
+				if (c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ ||
+					c_ctrl->cmd == MSM_CCI_I2C_WRITE_BURST)
+					reg_addr++;
+			} else {
+				if (i <= cci_dev->payload_size) {
+					/*
+					 * this logic fill reg data to buf[] array
+					 * which has a max index value 11,
+					 * and the sensor reg data type can be DWORD/3B/WORD,
+					 * next_position records the split position or the
+					 * position in the reg data where will be filled into
+					 * next buf[] array slot.
+					 */
+					if (next_position >= CAMERA_SENSOR_I2C_TYPE_DWORD) {
+						buf[i++] = (i2c_cmd->reg_data &
+							0xFF000000) >> 24;
+						if ((i-1) == MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11) {
+							next_position = CAMERA_SENSOR_I2C_TYPE_3B;
+							break;
+						}
+					}
+					/* fill highest byte of 3B type sensor reg data */
+					if (next_position >= CAMERA_SENSOR_I2C_TYPE_3B) {
+						buf[i++] = (i2c_cmd->reg_data &
+							0x00FF0000) >> 16;
+						if ((i-1) == MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11) {
+							next_position = CAMERA_SENSOR_I2C_TYPE_WORD;
+							break;
+						}
+					}
+					/* fill high byte of WORD type sensor reg data */
+					if (next_position >= CAMERA_SENSOR_I2C_TYPE_WORD) {
+						buf[i++] = (i2c_cmd->reg_data &
+							0x0000FF00) >> 8;
+						if ((i-1) == MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11) {
+							next_position = CAMERA_SENSOR_I2C_TYPE_BYTE;
+							break;
+						}
+					}
+					/* fill lowest byte of sensor reg data */
+					buf[i++] = i2c_cmd->reg_data & 0x000000FF;
+					next_position = i2c_msg->data_type;
+
+					if (c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ ||
+						c_ctrl->cmd == MSM_CCI_I2C_WRITE_BURST)
+						reg_addr += i2c_msg->data_type;
+				}
+			}
+			/* move to next cmd while all reg data bytes are filled */
+			if (next_position == i2c_msg->data_type) {
+				i2c_cmd++;
+				--cmd_size;
+			}
+		} while ((cmd_size > 0) && (i <= cci_dev->payload_size));
+
+		num_payload++;
+		if (cmd_size > 0) {
+			if (((num_payload % half_queue_mark) == 0) ||
+				(num_payload == last_i2c_full_payload)) {
+				buf[0] |= 0xE0;
+				cci_dev->cci_master_info[master].th_irq_ref_cnt[queue]++;
+				CAM_DBG(CAM_CCI,
+					"CCI%d_I2C_M%d_Q%d Th IRQ enabled for index: %d "
+					"num_payld: %d th_irq_ref_cnt: %d",
+					cci_dev->soc_info.index, master, queue, num_word_written_to_queue,
+					num_payload, cci_dev->cci_master_info[master].th_irq_ref_cnt[queue]);
+			} else {
+				buf[0] |= 0xF0;
+			}
+		} else {
+			buf[0] |= ((i-1) << 4);
+			CAM_DBG(CAM_CCI, "End of register Write............ ");
+		}
+		en_seq_write = 1;
+		len = ((i-1)/4) + 1;
+		/* increment pointer to next multiple of 4; which is a word in CCI QUEUE */
+		buf = buf + ((i+3) & ~0x03);
+		num_word_written_to_queue += len;
+	}
+
+	CAM_DBG(CAM_CCI, "CCI%d_I2C_M%d_Q%d num words to Queue: %d th_irq_ref_cnt: %d",
+		cci_dev->soc_info.index, master, queue, num_word_written_to_queue,
+		cci_dev->cci_master_info[master].th_irq_ref_cnt[queue]);
+
+	index = 0;
+	queue_start_threshold = half_queue_mark * MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_WORDS;
+	num_words_in_queue = cam_io_r_mb(base +
+		CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset);
+
+	while (index < num_word_written_to_queue) {
+		num_bytes = (data_queue[index] & 0xF0) >> 4;
+		if ((num_bytes == 0xF) || (num_bytes == 0xE)) {
+			iterate = 3;
+		} else {
+			num_bytes = (num_bytes + 4) & ~0x03;
+			iterate = num_bytes / 4;
+		}
+		if (num_bytes == 0xE) {
+			CAM_DBG(CAM_CCI, "CCI%d_I2C_M%d_Q%d THRESHOLD IRQ Enabled; data_queue[%d]: 0x%x refcnt: %d",
+				cci_dev->soc_info.index, master, queue, index, data_queue[index],
+				cci_dev->cci_master_info[master].th_irq_ref_cnt[queue]);
+		}
+		if (trigger_half_queue == 0) {
+			condition = ((num_words_in_queue + iterate + 1) > queue_size);
+		} else {
+			condition = (num_words_in_queue >= queue_start_threshold);
+		}
+
+		if (condition == true) {
+			CAM_DBG(CAM_CCI, "CCI%d_I2C_M%d_Q%d CUR_WORD_CNT_ADDR %d len %d max %d",
+				cci_dev->soc_info.index, master, queue, num_words_in_queue, iterate, max_queue_size);
+			if ((cci_dev->cci_master_info[master].th_irq_ref_cnt[queue]) > 0) {
+				cam_io_w_mb(num_words_in_queue, base +
+					CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset);
+				cam_io_w_mb(reg_val, base + CCI_QUEUE_START_ADDR);
+				trigger_half_queue = 1;
+				num_words_in_queue = 0;
+				CAM_DBG(CAM_CCI,
+					"CCI%d_I2C_M%d_Q%d Issued QUEUE_START, "
+					"wait for Threshold_IRQ, th_irq_ref_cnt[%d]:%d",
+					cci_dev->soc_info.index, master, queue, queue,
+					cci_dev->cci_master_info[master].th_irq_ref_cnt[queue]);
+
+				if (!cam_common_wait_for_completion_timeout(
+					&cci_dev->cci_master_info[master].th_burst_complete[queue],
+					CCI_TIMEOUT)) {
+					CAM_ERR(CAM_CCI, "CCI%d_I2C_M%d_Q%d : M0_STATUS: 0x%x",
+						cci_dev->soc_info.index, master, queue,
+						cam_io_r_mb(base + CCI_I2C_M0_STATUS_ADDR + reg_offset));
+					cam_cci_dump_registers(cci_dev, master, queue);
+
+					CAM_ERR(CAM_CCI,
+						"CCI%d_I2C_M%d_Q%d wait timeout, rc: %d",
+						cci_dev->soc_info.index, master, queue, rc);
+					rc = -ETIMEDOUT;
+					cam_cci_flush_queue(cci_dev, master);
+					CAM_INFO(CAM_CCI,
+						"CCI%d_I2C_M%d_Q%d dump register after reset",
+						cci_dev->soc_info.index, master, queue);
+					cam_cci_dump_registers(cci_dev, master, queue);
+					goto ERROR;
+				}
+				cci_dev->cci_master_info[master].th_irq_ref_cnt[queue]--;
+				CAM_DBG(CAM_CCI,
+					"CCI%d_I2C_M%d_Q%d Threshold IRQ Raised, BufferLevel: %d",
+					cci_dev->soc_info.index, master, queue,
+					cam_io_r_mb(base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset));
+			}
+		} else {
+			while (iterate > 0) {
+				cam_io_w_mb(data_queue[index], base +
+					CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+					master * 0x200 + queue * 0x100);
+				CAM_DBG(CAM_CCI,
+					"CCI%d_I2C_M%d_Q%d LOAD_DATA_ADDR 0x%x, "
+					"index: %d trig: %d numWordsInQueue: %d",
+					cci_dev->soc_info.index, master, queue,
+					data_queue[index], (index + 1),
+					trigger_half_queue, (num_words_in_queue + 1));
+				num_words_in_queue++;
+				index++;
+				iterate--;
+			}
+		}
+	}
+
+	if (num_words_in_queue > 0) {
+		cam_io_w_mb(num_words_in_queue, base +
+			CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset);
+		cam_io_w_mb(reg_val, base + CCI_QUEUE_START_ADDR);
+		CAM_DBG(CAM_CCI,
+			"CCI%d_I2C_M%d_Q%d Issued ****** FINAL QUEUE_START********, "
+			"numWordsInQueue: %d, th_irq_ref_cnt[%d]:%d",
+			cci_dev->soc_info.index, master, queue, queue, num_words_in_queue,
+			cci_dev->cci_master_info[master].th_irq_ref_cnt[queue]);
+		num_words_in_queue = 0;
+	}
+
+	while ((cci_dev->cci_master_info[master].th_irq_ref_cnt[queue]) > 0) {
+		if (!cam_common_wait_for_completion_timeout(
+			&cci_dev->cci_master_info[master].th_burst_complete[queue],
+			CCI_TIMEOUT)) {
+			cam_cci_dump_registers(cci_dev, master, queue);
+
+			CAM_ERR(CAM_CCI,
+				"CCI%d_I2C_M%d_Q%d wait timeout, rc: %d",
+				cci_dev->soc_info.index, master, queue, rc);
+			rc = -ETIMEDOUT;
+			cam_cci_flush_queue(cci_dev, master);
+			CAM_INFO(CAM_CCI,
+				"CCI%d_I2C_M%d_Q%d dump register after reset",
+				cci_dev->soc_info.index, master, queue);
+			cam_cci_dump_registers(cci_dev, master, queue);
+			goto ERROR;
+		}
+		cci_dev->cci_master_info[master].th_irq_ref_cnt[queue]--;
+		CAM_DBG(CAM_CCI,
+			"CCI%d_I2C_M%d_Q%d Threshold IRQ Raised, BufferLevel: %d",
+			cci_dev->soc_info.index, master, queue,
+			cam_io_r_mb(base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset));
+	}
+
+	cci_dev->cci_master_info[master].is_burst_enable[queue] = true;
+	cci_dev->cci_master_info[master].num_words_exec[queue] = 0;
+
+	rc = cam_cci_transfer_end(cci_dev, master, queue);
+	if (rc < 0) {
+		CAM_ERR(CAM_CCI, "CCI%d_I2C_M%d_Q%d Slave: 0x%x failed rc %d",
+			cci_dev->soc_info.index, master, queue, (c_ctrl->cci_info->sid << 1), rc);
+		goto ERROR;
+	}
+ERROR:
+	kfree(data_queue);
+	return rc;
+}
+
 static int32_t cam_cci_data_queue(struct cci_device *cci_dev,
 	struct cam_cci_ctrl *c_ctrl, enum cci_i2c_queue_t queue,
 	enum cci_i2c_sync sync_en)
@@ -777,6 +1184,8 @@ static int32_t cam_cci_data_queue(struct cci_device *cci_dev,
 	}
 	reg_offset = master * 0x200 + queue * 0x100;
 
+	cci_dev->cci_master_info[master].is_burst_enable[queue] = false;
+	cci_dev->cci_master_info[master].num_words_exec[queue] = 0;
 	cam_io_w_mb(cci_dev->cci_wait_sync_cfg.cid,
 		base + CCI_SET_CID_SYNC_TIMER_ADDR +
 		cci_dev->cci_wait_sync_cfg.csid *
@@ -950,6 +1359,8 @@ static int32_t cam_cci_data_queue(struct cci_device *cci_dev,
 		}
 		len = ((i-1)/4) + 1;
 
+		CAM_DBG(CAM_CCI, "free_size %d, en_seq_write %d i: %d len: %d ",
+			free_size, en_seq_write, i, len);
 		read_val = cam_io_r_mb(base +
 			CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset);
 		for (h = 0, k = 0; h < len; h++) {
@@ -1561,6 +1972,7 @@ static int32_t cam_cci_i2c_write(struct v4l2_subdev *sd,
 		return rc;
 	}
 	reinit_completion(&cci_dev->cci_master_info[master].report_q[queue]);
+	reinit_completion(&cci_dev->cci_master_info[master].th_burst_complete[queue]);
 	/*
 	 * Call validate queue to make sure queue is empty before starting.
 	 * If this call fails, don't proceed with i2c_write call. This is to
@@ -1580,12 +1992,22 @@ static int32_t cam_cci_i2c_write(struct v4l2_subdev *sd,
 			cci_dev->soc_info.index, master, queue, c_ctrl->cci_info->retries, CCI_I2C_READ_MAX_RETRIES);
 		goto ERROR;
 	}
-	rc = cam_cci_data_queue(cci_dev, c_ctrl, queue, sync_en);
-	if (rc < 0) {
-		CAM_ERR(CAM_CCI,
-			"CCI%d_I2C_M%d_Q%d Failed in queueing the data for rc: %d",
-			cci_dev->soc_info.index, master, queue, rc);
-		goto ERROR;
+	if (c_ctrl->cmd == MSM_CCI_I2C_WRITE_BURST) {
+		rc = cam_cci_data_queue_burst(cci_dev, c_ctrl, queue, sync_en);
+		if (rc < 0) {
+			CAM_ERR(CAM_CCI,
+				"CCI%d_I2C_M%d_Q%d Failed in queueing i2c Burst write data for rc: %d",
+				cci_dev->soc_info.index, master, queue, rc);
+			goto ERROR;
+		}
+	} else {
+		rc = cam_cci_data_queue(cci_dev, c_ctrl, queue, sync_en);
+		if (rc < 0) {
+			CAM_ERR(CAM_CCI,
+				"CCI%d_I2C_M%d_Q%d Failed in queueing the data for rc: %d",
+				cci_dev->soc_info.index, master, queue, rc);
+			goto ERROR;
+		}
 	}
 
 ERROR:

+ 54 - 2
drivers/cam_sensor_module/cam_cci/cam_cci_dev.c

@@ -70,6 +70,7 @@ irqreturn_t cam_cci_irq(int irq_num, void *data)
 	void __iomem *base = soc_info->reg_map[0].mem_base;
 	unsigned long flags;
 	bool rd_done_th_assert = false;
+	struct cam_cci_master_info *cci_master_info;
 
 	irq_status0 = cam_io_r_mb(base + CCI_IRQ_STATUS_0_ADDR);
 	irq_status1 = cam_io_r_mb(base + CCI_IRQ_STATUS_1_ADDR);
@@ -181,6 +182,50 @@ irqreturn_t cam_cci_irq(int irq_num, void *data)
 		cci_dev->cci_master_info[MASTER_0].status = 0;
 		complete(&cci_dev->cci_master_info[MASTER_0].th_complete);
 	}
+	if (irq_status1 & CCI_IRQ_STATUS_1_I2C_M1_Q0_THRESHOLD)
+	{
+		cci_master_info = &cci_dev->cci_master_info[MASTER_1];
+		spin_lock_irqsave(
+			&cci_master_info->lock_q[QUEUE_0],
+			flags);
+		complete(&cci_master_info->th_burst_complete[QUEUE_0]);
+		spin_unlock_irqrestore(
+			&cci_master_info->lock_q[QUEUE_0],
+			flags);
+	}
+	if (irq_status1 & CCI_IRQ_STATUS_1_I2C_M1_Q1_THRESHOLD)
+	{
+		cci_master_info = &cci_dev->cci_master_info[MASTER_1];
+		spin_lock_irqsave(
+			&cci_master_info->lock_q[QUEUE_1],
+			flags);
+		complete(&cci_master_info->th_burst_complete[QUEUE_1]);
+		spin_unlock_irqrestore(
+			&cci_master_info->lock_q[QUEUE_1],
+			flags);
+	}
+	if (irq_status1 & CCI_IRQ_STATUS_1_I2C_M0_Q0_THRESHOLD)
+	{
+		cci_master_info = &cci_dev->cci_master_info[MASTER_0];
+		spin_lock_irqsave(
+			&cci_master_info->lock_q[QUEUE_0],
+			flags);
+		complete(&cci_master_info->th_burst_complete[QUEUE_0]);
+		spin_unlock_irqrestore(
+			&cci_master_info->lock_q[QUEUE_0],
+			flags);
+	}
+	if (irq_status1 & CCI_IRQ_STATUS_1_I2C_M0_Q1_THRESHOLD)
+	{
+		cci_master_info = &cci_dev->cci_master_info[MASTER_0];
+		spin_lock_irqsave(
+			&cci_master_info->lock_q[QUEUE_1],
+			flags);
+		complete(&cci_master_info->th_burst_complete[QUEUE_1]);
+		spin_unlock_irqrestore(
+			&cci_master_info->lock_q[QUEUE_1],
+			flags);
+	}
 	if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK) {
 		struct cam_cci_master_info *cci_master_info;
 
@@ -378,10 +423,16 @@ irqreturn_t cam_cci_irq(int irq_num, void *data)
 static int cam_cci_irq_routine(struct v4l2_subdev *sd, u32 status,
 	bool *handled)
 {
-	struct cci_device *cci_dev = v4l2_get_subdevdata(sd);
+	struct cci_device *cci_dev = NULL;
 	irqreturn_t ret;
 	struct cam_hw_soc_info *soc_info = NULL;
 
+	if (!sd) {
+		CAM_ERR(CAM_CCI, "Error No data in subdev");
+		return -EINVAL;
+	}
+
+	cci_dev = v4l2_get_subdevdata(sd);
 	if (!cci_dev) {
 		CAM_ERR(CAM_CCI, "cci_dev NULL");
 		return -EINVAL;
@@ -560,13 +611,14 @@ static void cam_cci_component_unbind(struct device *dev,
 	struct platform_device *pdev = to_platform_device(dev);
 
 	struct v4l2_subdev *subdev = platform_get_drvdata(pdev);
-	struct cci_device *cci_dev = cci_dev = v4l2_get_subdevdata(subdev);
+	struct cci_device *cci_dev = NULL;
 
 	if (!subdev) {
 		CAM_ERR(CAM_CCI, "Error No data in subdev");
 		return;
 	}
 
+	cci_dev = v4l2_get_subdevdata(subdev);
 	if (!cci_dev) {
 		CAM_ERR(CAM_CCI, "Error No data in cci_dev");
 		return;

+ 6 - 1
drivers/cam_sensor_module/cam_cci/cam_cci_dev.h

@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CAM_CCI_DEV_H_
@@ -46,6 +46,7 @@
 #define NUM_QUEUES 2
 
 #define MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11 11
+#define MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_WORDS ((MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11 + 1) / 4)
 #define BURST_MIN_FREE_SIZE 8
 
 /* Max bytes that can be read per CCI read transaction */
@@ -141,6 +142,10 @@ struct cam_cci_master_info {
 	struct mutex freq_cnt_lock;
 	uint16_t freq_ref_cnt;
 	bool is_initilized;
+	struct completion th_burst_complete[NUM_QUEUES];
+	uint32_t th_irq_ref_cnt[NUM_QUEUES];
+	bool is_burst_enable[NUM_QUEUES];
+	uint32_t num_words_exec[NUM_QUEUES];
 };
 
 struct cam_cci_clk_params_t {

+ 8 - 1
drivers/cam_sensor_module/cam_cci/cam_cci_hwreg.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2012-2015, 2017-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CAM_CCI_HWREG_
@@ -20,6 +21,7 @@
 #define CCI_I2C_M0_SDA_CTL_2_ADDR                                   0x0000010c
 #define CCI_I2C_M0_READ_DATA_ADDR                                   0x00000118
 #define CCI_I2C_M0_MISC_CTL_ADDR                                    0x00000110
+#define CCI_I2C_M0_STATUS_ADDR                                      0x00000114
 #define CCI_I2C_M0_READ_BUF_LEVEL_ADDR                              0x0000011C
 #define CCI_HALT_REQ_ADDR                                           0x00000034
 #define CCI_M0_HALT_REQ_RMSK                                               0x1
@@ -29,6 +31,7 @@
 #define CCI_I2C_M1_SDA_CTL_1_ADDR                                   0x00000208
 #define CCI_I2C_M1_SDA_CTL_2_ADDR                                   0x0000020c
 #define CCI_I2C_M1_MISC_CTL_ADDR                                    0x00000210
+#define CCI_I2C_M1_STATUS_ADDR                                      0x00000214
 #define CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR                             0x00000304
 #define CCI_I2C_M0_Q0_CUR_CMD_ADDR                                  0x00000308
 #define CCI_I2C_M0_Q0_REPORT_STATUS_ADDR                            0x0000030c
@@ -37,7 +40,7 @@
 #define CCI_IRQ_MASK_0_ADDR                                         0x00000c04
 #define CCI_IRQ_MASK_0_RMSK                                         0x7fff7ff7
 #define CCI_IRQ_MASK_1_ADDR                                         0x00000c10
-#define CCI_IRQ_MASK_1_RMSK                                         0x00110000
+#define CCI_IRQ_MASK_1_RMSK                                         0x00DD0000
 #define CCI_IRQ_CLEAR_0_ADDR                                        0x00000c08
 #define CCI_IRQ_CLEAR_1_ADDR                                        0x00000c14
 #define CCI_IRQ_STATUS_0_ADDR                                       0x00000c0c
@@ -65,6 +68,10 @@
 #define CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK                               0x1
 #define CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD                           0x10000
 #define CCI_IRQ_STATUS_1_I2C_M0_RD_PAUSE                               0x20000
+#define CCI_IRQ_STATUS_1_I2C_M1_Q0_THRESHOLD                          0x400000
+#define CCI_IRQ_STATUS_1_I2C_M1_Q1_THRESHOLD                          0x800000
+#define CCI_IRQ_STATUS_1_I2C_M0_Q0_THRESHOLD                           0x40000
+#define CCI_IRQ_STATUS_1_I2C_M0_Q1_THRESHOLD                           0x80000
 #define CCI_I2C_M0_RD_THRESHOLD_ADDR                                0x00000120
 #define CCI_I2C_M1_RD_THRESHOLD_ADDR                                0x00000220
 #define CCI_I2C_RD_THRESHOLD_VALUE                                        0x30

+ 2 - 0
drivers/cam_sensor_module/cam_cci/cam_cci_soc.c

@@ -258,6 +258,8 @@ static void cam_cci_init_cci_params(struct cci_device *new_cci_dev)
 			mutex_init(&new_cci_dev->cci_master_info[i].mutex_q[j]);
 			init_completion(
 				&new_cci_dev->cci_master_info[i].report_q[j]);
+			init_completion(
+				&new_cci_dev->cci_master_info[i].th_burst_complete[j]);
 			spin_lock_init(
 				&new_cci_dev->cci_master_info[i].lock_q[j]);
 		}