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

Commit 2dad6bd0 authored by Jigarkumar Zala's avatar Jigarkumar Zala Committed by Gerrit - the friendly Code Review server
Browse files

msm: camera: sensor: Notify completion in error case



There is no need to wait till timeout in case of NACK or
underflow error irq is raised, so notify thread for rd_done
completion. Also, correct the error mask to catch the NACK
error for Master 1.

CRs-Fixed: 2598605
Change-Id: Ib8a16ee119dd81f1384283ac7e9f82d3ac2588bb
Signed-off-by: default avatarJigarkumar Zala <jzala@codeaurora.org>
Signed-off-by: default avatarDepeng Shao <depengs@codeaurora.org>
Signed-off-by: default avatarKarthik Jayakumar <kjayakum@codeaurora.org>
parent 64c6e1ec
Loading
Loading
Loading
Loading
+68 −7
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 */

#include <linux/module.h>
@@ -42,6 +42,9 @@ static void cam_cci_flush_queue(struct cci_device *cci_dev,
	void __iomem *base = soc_info->reg_map[0].mem_base;

	cam_io_w_mb(1 << master, base + CCI_HALT_REQ_ADDR);
	if (!cci_dev->cci_master_info[master].status)
		reinit_completion(&cci_dev->cci_master_info[master]
			.reset_complete);
	rc = wait_for_completion_timeout(
		&cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT);
	if (rc < 0) {
@@ -51,6 +54,7 @@ static void cam_cci_flush_queue(struct cci_device *cci_dev,

		/* Set reset pending flag to true */
		cci_dev->cci_master_info[master].reset_pending = true;
		cci_dev->cci_master_info[master].status = 0;

		/* Set proper mask to RESET CMD address based on MASTER */
		if (master == MASTER_0)
@@ -66,6 +70,7 @@ static void cam_cci_flush_queue(struct cci_device *cci_dev,
			CCI_TIMEOUT);
		if (rc <= 0)
			CAM_ERR(CAM_CCI, "wait failed %d", rc);
		cci_dev->cci_master_info[master].status = 0;
	}
}

@@ -127,8 +132,10 @@ static int32_t cam_cci_validate_queue(struct cci_device *cci_dev,
			return rc;
		}
		rc = cci_dev->cci_master_info[master].status;
		if (rc < 0)
		if (rc < 0) {
			CAM_ERR(CAM_CCI, "Failed rc %d", rc);
			cci_dev->cci_master_info[master].status = 0;
		}
	}

	return rc;
@@ -246,14 +253,16 @@ static uint32_t cam_cci_wait(struct cci_device *cci_dev,
		cam_cci_dump_registers(cci_dev, master, queue);
#endif
		CAM_ERR(CAM_CCI, "wait for queue: %d", queue);
		if (rc == 0)
		if (rc == 0) {
			rc = -ETIMEDOUT;
			cam_cci_flush_queue(cci_dev, master);
			return rc;
		}
	}
	rc = cci_dev->cci_master_info[master].status;
	if (rc < 0) {
		CAM_ERR(CAM_CCI, "failed rc %d", rc);
		cci_dev->cci_master_info[master].status = 0;
		return rc;
	}

@@ -851,7 +860,8 @@ static int32_t cam_cci_data_queue(struct cci_device *cci_dev,

	rc = cam_cci_transfer_end(cci_dev, master, queue);
	if (rc < 0) {
		CAM_ERR(CAM_CCI, "failed rc %d", rc);
		CAM_ERR(CAM_CCI, "Slave: 0x%x failed rc %d",
			(c_ctrl->cci_info->sid << 1), rc);
		return rc;
	}

@@ -918,6 +928,7 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd,
	mutex_unlock(&cci_dev->cci_master_info[master].mutex);

	mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]);
	reinit_completion(&cci_dev->cci_master_info[master].report_q[queue]);
	/*
	 * Call validate queue to make sure queue is empty before starting.
	 * If this call fails, don't proceed with i2c_read call. This is to
@@ -1024,6 +1035,14 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd,
			goto rel_mutex_q;
		}

		if (cci_dev->cci_master_info[master].status) {
			CAM_ERR(CAM_CCI, "Error with Salve: 0x%x",
				(c_ctrl->cci_info->sid << 1));
			rc = -EINVAL;
			cci_dev->cci_master_info[master].status = 0;
			goto rel_mutex_q;
		}

		read_words = cam_io_r_mb(base +
			CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100);
		if (read_words <= 0) {
@@ -1104,6 +1123,14 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd,
					cam_cci_flush_queue(cci_dev, master);
				goto rel_mutex_q;
			}

			if (cci_dev->cci_master_info[master].status) {
				CAM_ERR(CAM_CCI, "Error with Slave 0x%x",
					(c_ctrl->cci_info->sid << 1));
				rc = -EINVAL;
				cci_dev->cci_master_info[master].status = 0;
				goto rel_mutex_q;
			}
			break;
		}
	}
@@ -1183,6 +1210,7 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd,
	mutex_unlock(&cci_dev->cci_master_info[master].mutex);

	mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]);
	reinit_completion(&cci_dev->cci_master_info[master].report_q[queue]);
	/*
	 * Call validate queue to make sure queue is empty before starting.
	 * If this call fails, don't proceed with i2c_read call. This is to
@@ -1290,6 +1318,14 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd,
		rc = 0;
	}

	if (cci_dev->cci_master_info[master].status) {
		CAM_ERR(CAM_CCI, "ERROR with Slave 0x%x:",
			(c_ctrl->cci_info->sid << 1));
		rc = -EINVAL;
		cci_dev->cci_master_info[master].status = 0;
		goto rel_mutex_q;
	}

	read_words = cam_io_r_mb(base +
		CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100);
	exp_words = ((read_cfg->num_byte / 4) + 1);
@@ -1384,6 +1420,8 @@ static int32_t cam_cci_i2c_write(struct v4l2_subdev *sd,
		goto ERROR;
	}
	mutex_unlock(&cci_dev->cci_master_info[master].mutex);

	reinit_completion(&cci_dev->cci_master_info[master].report_q[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
@@ -1546,6 +1584,7 @@ static int32_t cam_cci_read_bytes(struct v4l2_subdev *sd,
	 * THRESHOLD irq's, we reinit the threshold wait before
	 * we load the burst read cmd.
	 */
	reinit_completion(&cci_dev->cci_master_info[master].rd_done);
	reinit_completion(&cci_dev->cci_master_info[master].th_complete);

	CAM_DBG(CAM_CCI, "Bytes to read %u", read_bytes);
@@ -1687,7 +1726,29 @@ int32_t cam_cci_core_cfg(struct v4l2_subdev *sd,
{
	int32_t rc = 0;
	struct cci_device *cci_dev = v4l2_get_subdevdata(sd);
	CAM_DBG(CAM_CCI, "cmd %d", cci_ctrl->cmd);
	enum cci_i2c_master_t master = MASTER_MAX;

	if (!cci_dev) {
		CAM_ERR(CAM_CCI, "CCI_DEV IS NULL");
		return -EINVAL;
	}

	if (!cci_ctrl) {
		CAM_ERR(CAM_CCI, "CCI_CTRL IS NULL");
		return -EINVAL;
	}

	master = cci_ctrl->cci_info->cci_i2c_master;
	if (master >= MASTER_MAX) {
		CAM_ERR(CAM_CCI, "INVALID MASTER: %d", master);
		return -EINVAL;
	}

	if (cci_dev->cci_master_info[master].status < 0) {
		CAM_WARN(CAM_CCI, "CCI hardware is resetting");
		return -EAGAIN;
	}
	CAM_DBG(CAM_CCI, "master = %d, cmd = %d", master, cci_ctrl->cmd);

	switch (cci_ctrl->cmd) {
	case MSM_CCI_INIT:
+37 −11
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 */

#include "cam_cci_dev.h"
@@ -82,7 +82,9 @@ irqreturn_t cam_cci_irq(int irq_num, void *data)
				false;
			if (!cci_master_info->status)
				complete(&cci_master_info->reset_complete);
			cci_master_info->status = 0;

			complete_all(&cci_master_info->rd_done);
			complete_all(&cci_master_info->th_complete);
		}
		if (cci_dev->cci_master_info[MASTER_1].reset_pending == true) {
			cci_master_info = &cci_dev->cci_master_info[MASTER_1];
@@ -90,7 +92,9 @@ irqreturn_t cam_cci_irq(int irq_num, void *data)
				false;
			if (!cci_master_info->status)
				complete(&cci_master_info->reset_complete);
			cci_master_info->status = 0;

			complete_all(&cci_master_info->rd_done);
			complete_all(&cci_master_info->th_complete);
		}
	}

@@ -223,9 +227,18 @@ irqreturn_t cam_cci_irq(int irq_num, void *data)
	}
	if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK) {
		cci_dev->cci_master_info[MASTER_0].status = -EINVAL;
		if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK)
			CAM_ERR(CAM_CCI, "Base:%pK, M0 NACK ERROR: 0x%x",
		if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0_NACK_ERROR_BMSK) {
			CAM_ERR(CAM_CCI, "Base:%pK, M0_Q0 NACK ERROR: 0x%x",
				base, irq_status0);
			complete_all(&cci_dev->cci_master_info[MASTER_0]
				.report_q[QUEUE_0]);
		}
		if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q1_NACK_ERROR_BMSK) {
			CAM_ERR(CAM_CCI, "Base:%pK, M0_Q1 NACK ERROR: 0x%x",
				base, irq_status0);
			complete_all(&cci_dev->cci_master_info[MASTER_0]
			.report_q[QUEUE_1]);
		}
		if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK)
			CAM_ERR(CAM_CCI,
			"Base:%pK, M0 QUEUE_OVER/UNDER_FLOW OR CMD ERR: 0x%x",
@@ -234,22 +247,35 @@ irqreturn_t cam_cci_irq(int irq_num, void *data)
			CAM_ERR(CAM_CCI,
				"Base: %pK, M0 RD_OVER/UNDER_FLOW ERROR: 0x%x",
				base, irq_status0);
		cam_io_w_mb(CCI_M0_HALT_REQ_RMSK, base + CCI_HALT_REQ_ADDR);

		cci_dev->cci_master_info[MASTER_0].reset_pending = true;
		cam_io_w_mb(CCI_M0_RESET_RMSK, base + CCI_RESET_CMD_ADDR);
	}
	if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK) {
		cci_dev->cci_master_info[MASTER_1].status = -EINVAL;
		if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK)
			CAM_ERR(CAM_CCI, "Base:%pK, M1 NACK ERROR: 0x%x",
		if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q0_NACK_ERROR_BMSK) {
			CAM_ERR(CAM_CCI, "Base:%pK, M1_Q0 NACK ERROR: 0x%x",
				base, irq_status0);
		if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK)
			complete_all(&cci_dev->cci_master_info[MASTER_1]
			.report_q[QUEUE_0]);
		}
		if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q1_NACK_ERROR_BMSK) {
			CAM_ERR(CAM_CCI, "Base:%pK, M1_Q1 NACK ERROR: 0x%x",
				base, irq_status0);
			complete_all(&cci_dev->cci_master_info[MASTER_1]
			.report_q[QUEUE_1]);
		}
		if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_ERROR_BMSK)
			CAM_ERR(CAM_CCI,
			"Base:%pK, M1 QUEUE_OVER_UNDER_FLOW OR CMD ERROR:0x%x",
				base, irq_status0);
		if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_ERROR_BMSK)
		if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_ERROR_BMSK)
			CAM_ERR(CAM_CCI,
				"Base:%pK, M1 RD_OVER/UNDER_FLOW ERROR: 0x%x",
				base, irq_status0);
		cam_io_w_mb(CCI_M1_HALT_REQ_RMSK, base + CCI_HALT_REQ_ADDR);

		cci_dev->cci_master_info[MASTER_1].reset_pending = true;
		cam_io_w_mb(CCI_M1_RESET_RMSK, base + CCI_RESET_CMD_ADDR);
	}

	cam_io_w_mb(irq_status0, base + CCI_IRQ_CLEAR_0_ADDR);
+5 −3
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2012-2015, 2017-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2012-2015, 2017-2020, The Linux Foundation. All rights reserved.
 */

#ifndef _CAM_CCI_HWREG_
@@ -54,8 +54,10 @@
#define CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK                            0x10
#define CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK                          0x18000EE6
#define CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK                          0x60EE6000
#define CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK                     0x18000000
#define CCI_IRQ_STATUS_0_I2C_M1_NACK_ERROR_BMSK                     0x60000000
#define CCI_IRQ_STATUS_0_I2C_M0_Q0_NACK_ERROR_BMSK                   0x8000000
#define CCI_IRQ_STATUS_0_I2C_M0_Q1_NACK_ERROR_BMSK                  0x10000000
#define CCI_IRQ_STATUS_0_I2C_M1_Q0_NACK_ERROR_BMSK                  0x20000000
#define CCI_IRQ_STATUS_0_I2C_M1_Q1_NACK_ERROR_BMSK                  0x40000000
#define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK                          0xEE0
#define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_ERROR_BMSK                       0xEE0000
#define CCI_IRQ_STATUS_0_I2C_M0_RD_ERROR_BMSK                              0x6
+3 −0
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ int cam_cci_init(struct v4l2_subdev *sd,
				&cci_dev->cci_master_info[master].report_q[i]);
			/* Set reset pending flag to true */
			cci_dev->cci_master_info[master].reset_pending = true;
			cci_dev->cci_master_info[master].status = 0;
			/* Set proper mask to RESET CMD address */
			if (master == MASTER_0)
				cam_io_w_mb(CCI_M0_RESET_RMSK,
@@ -67,6 +68,7 @@ int cam_cci_init(struct v4l2_subdev *sd,
				CCI_TIMEOUT);
			if (rc <= 0)
				CAM_ERR(CAM_CCI, "wait failed %d", rc);
			cci_dev->cci_master_info[master].status = 0;
			mutex_unlock(&cci_dev->cci_master_info[master].mutex);
		}
		return 0;
@@ -132,6 +134,7 @@ int cam_cci_init(struct v4l2_subdev *sd,
	}

	cci_dev->cci_master_info[master].reset_pending = true;
	cci_dev->cci_master_info[master].status = 0;
	cam_io_w_mb(CCI_RESET_CMD_RMSK, base +
			CCI_RESET_CMD_ADDR);
	cam_io_w_mb(0x1, base + CCI_RESET_CMD_ADDR);