Merge "msm: camera: sensor: Notify completion in error case" into camera-kernel.lnx.4.0

This commit is contained in:
Camera Software Integration 2020-02-07 15:13:06 -08:00 • committed by Gerrit - the friendly Code Review server
commit 5a3fb45a2a
4 changed files with 113 additions and 21 deletions

View file

@ -1,6 +1,6 @@
// 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;
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:

View file

@ -1,6 +1,6 @@
// 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);

View file

@ -1,6 +1,6 @@
/* 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

View file

@ -55,6 +55,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,
@ -68,6 +69,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;
@ -142,6 +144,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);