Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 831e8c19 authored by Viswanadha Raju Thotakura's avatar Viswanadha Raju Thotakura
Browse files

msm: camera: Modify interrupt handler for CCI



In the case of read burst, sometimes hardware randomly
raises interrupts for each cycle. To overcome it, once
threhold is hit, disable threshold IRQ till complete data
is read from client.

Change-Id: If0fe8c3723cee8003e0dddd12bf1af74c11c8e95
Signed-off-by: default avatarViswanadha Raju Thotakura <viswanad@codeaurora.org>
parent 863447f6
Loading
Loading
Loading
Loading
+15 −8
Original line number Diff line number Diff line
@@ -869,7 +869,7 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd,
	struct cam_cci_ctrl *c_ctrl)
{
	int32_t rc = 0;
	uint32_t val = 0, i = 0, j = 0;
	uint32_t val = 0, i = 0, j = 0, irq_mask_update = 0;
	unsigned long rem_jiffies, flags;
	int32_t read_words = 0, exp_words = 0;
	int32_t index = 0, first_byte = 0, total_read_words = 0;
@@ -1048,13 +1048,20 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd,
			j, total_read_words);

		spin_lock_irqsave(&cci_dev->lock_status, flags);
		if (cci_dev->irq_status1) {
			CAM_DBG(CAM_CCI, "clear irq_status1:%x",
				cci_dev->irq_status1);
			cam_io_w_mb(cci_dev->irq_status1,
				base + CCI_IRQ_CLEAR_1_ADDR);
			cam_io_w_mb(0x1, base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR);
			cci_dev->irq_status1 = 0;
		if (cci_dev->irqs_disabled) {
			irq_mask_update =
				cam_io_r_mb(base + CCI_IRQ_MASK_1_ADDR) |
				CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD;
			if (master == MASTER_0 && cci_dev->irqs_disabled &
				CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD)
				irq_mask_update |=
					CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD;
			else if (master == MASTER_1 && cci_dev->irqs_disabled &
				CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD)
				irq_mask_update |=
					CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD;
			cam_io_w_mb(irq_mask_update,
				base + CCI_IRQ_MASK_1_ADDR);
		}
		spin_unlock_irqrestore(&cci_dev->lock_status, flags);

+58 −9
Original line number Diff line number Diff line
@@ -60,8 +60,8 @@ static long cam_cci_subdev_compat_ioctl(struct v4l2_subdev *sd,

irqreturn_t cam_cci_irq(int irq_num, void *data)
{
	uint32_t irq_status0 = 0;
	uint32_t irq_status1 = 0;
	uint32_t irq_status0, irq_status1, reg_bmsk;
	uint32_t irq_update_rd_done = 0;
	struct cci_device *cci_dev = data;
	struct cam_hw_soc_info *soc_info =
		&cci_dev->soc_info;
@@ -143,6 +143,7 @@ irqreturn_t cam_cci_irq(int irq_num, void *data)
			&cci_dev->cci_master_info[MASTER_0].lock_q[QUEUE_1],
			flags);
	}
	rd_done_th_assert = false;
	if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) &&
		(irq_status1 & CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD)) {
		cci_dev->cci_master_info[MASTER_1].status = 0;
@@ -225,19 +226,67 @@ irqreturn_t cam_cci_irq(int irq_num, void *data)
		cam_io_w_mb(CCI_M1_HALT_REQ_RMSK,
			base + CCI_HALT_REQ_ADDR);
		CAM_DBG(CAM_CCI, "MASTER_1 error 0x%x", irq_status0);

	}

	if ((rd_done_th_assert) || (!cci_dev->is_burst_read)) {
		cam_io_w_mb(irq_status1, base + CCI_IRQ_CLEAR_1_ADDR);
		CAM_DBG(CAM_CCI, "clear irq_status0:%x irq_status1:%x",
			irq_status0, irq_status1);
	} else {
	cam_io_w_mb(irq_status0, base + CCI_IRQ_CLEAR_0_ADDR);

	reg_bmsk = CCI_IRQ_MASK_1_RMSK;
	if ((irq_status1 & CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD) &&
	!(irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK)) {
		reg_bmsk &= ~CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD;
		spin_lock_irqsave(&cci_dev->lock_status, flags);
		cci_dev->irq_status1 |= irq_status1;
		cci_dev->irqs_disabled |=
			CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD;
		spin_unlock_irqrestore(&cci_dev->lock_status, flags);
	}

	cam_io_w_mb(irq_status0, base + CCI_IRQ_CLEAR_0_ADDR);
	if ((irq_status1 & CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD) &&
	!(irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK)) {
		reg_bmsk &= ~CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD;
		spin_lock_irqsave(&cci_dev->lock_status, flags);
		cci_dev->irqs_disabled |=
			CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD;
		spin_unlock_irqrestore(&cci_dev->lock_status, flags);
	}

	if (reg_bmsk != CCI_IRQ_MASK_1_RMSK) {
		cam_io_w_mb(reg_bmsk, base + CCI_IRQ_MASK_1_ADDR);
		CAM_DBG(CAM_CCI, "Updating the reg mask for irq1: 0x%x",
			reg_bmsk);
	} else if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK ||
		irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) {
		if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) {
			spin_lock_irqsave(&cci_dev->lock_status, flags);
			if (cci_dev->irqs_disabled &
				CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD) {
				irq_update_rd_done |=
					CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD;
				cci_dev->irqs_disabled &=
					~CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD;
			}
			spin_unlock_irqrestore(&cci_dev->lock_status, flags);
		}
		if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) {
			spin_lock_irqsave(&cci_dev->lock_status, flags);
			if (cci_dev->irqs_disabled &
				CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD) {
				irq_update_rd_done |=
					CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD;
				cci_dev->irqs_disabled &=
					~CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD;
			}
			spin_unlock_irqrestore(&cci_dev->lock_status, flags);
		}
	}

	if (irq_update_rd_done != 0) {
		irq_update_rd_done |= cam_io_r_mb(base + CCI_IRQ_MASK_1_ADDR);
		cam_io_w_mb(irq_update_rd_done, base + CCI_IRQ_MASK_1_ADDR);
	}


	cam_io_w_mb(irq_status1, base + CCI_IRQ_CLEAR_1_ADDR);
	cam_io_w_mb(0x1, base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR);
	return IRQ_HANDLED;
}
+2 −0
Original line number Diff line number Diff line
@@ -200,6 +200,7 @@ enum cam_cci_state_t {
 * @lock_status: to protect changes to irq_status1
 * @is_burst_read: Flag to determine if we are performing
 *                 a burst read operation or not
 * @irqs_disabled: Mask for IRQs that are disabled
 */
struct cci_device {
	struct v4l2_subdev subdev;
@@ -227,6 +228,7 @@ struct cci_device {
	uint32_t irq_status1;
	spinlock_t lock_status;
	bool is_burst_read;
	uint32_t irqs_disabled;
};

enum cam_cci_i2c_cmd_type {