|
@@ -1,6 +1,6 @@
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
|
// 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>
|
|
#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;
|
|
void __iomem *base = soc_info->reg_map[0].mem_base;
|
|
|
|
|
|
cam_io_w_mb(1 << master, base + CCI_HALT_REQ_ADDR);
|
|
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(
|
|
rc = wait_for_completion_timeout(
|
|
&cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT);
|
|
&cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT);
|
|
if (rc < 0) {
|
|
if (rc < 0) {
|
|
@@ -51,6 +54,7 @@ static void cam_cci_flush_queue(struct cci_device *cci_dev,
|
|
|
|
|
|
/* Set reset pending flag to true */
|
|
/* Set reset pending flag to true */
|
|
cci_dev->cci_master_info[master].reset_pending = 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 */
|
|
/* Set proper mask to RESET CMD address based on MASTER */
|
|
if (master == MASTER_0)
|
|
if (master == MASTER_0)
|
|
@@ -66,6 +70,7 @@ static void cam_cci_flush_queue(struct cci_device *cci_dev,
|
|
CCI_TIMEOUT);
|
|
CCI_TIMEOUT);
|
|
if (rc <= 0)
|
|
if (rc <= 0)
|
|
CAM_ERR(CAM_CCI, "wait failed %d", rc);
|
|
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;
|
|
return rc;
|
|
}
|
|
}
|
|
rc = cci_dev->cci_master_info[master].status;
|
|
rc = cci_dev->cci_master_info[master].status;
|
|
- if (rc < 0)
|
|
|
|
|
|
+ if (rc < 0) {
|
|
CAM_ERR(CAM_CCI, "Failed rc %d", rc);
|
|
CAM_ERR(CAM_CCI, "Failed rc %d", rc);
|
|
|
|
+ cci_dev->cci_master_info[master].status = 0;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
return rc;
|
|
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);
|
|
cam_cci_dump_registers(cci_dev, master, queue);
|
|
#endif
|
|
#endif
|
|
CAM_ERR(CAM_CCI, "wait for queue: %d", queue);
|
|
CAM_ERR(CAM_CCI, "wait for queue: %d", queue);
|
|
- if (rc == 0)
|
|
|
|
|
|
+ if (rc == 0) {
|
|
rc = -ETIMEDOUT;
|
|
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;
|
|
rc = cci_dev->cci_master_info[master].status;
|
|
if (rc < 0) {
|
|
if (rc < 0) {
|
|
CAM_ERR(CAM_CCI, "failed rc %d", rc);
|
|
CAM_ERR(CAM_CCI, "failed rc %d", rc);
|
|
|
|
+ cci_dev->cci_master_info[master].status = 0;
|
|
return rc;
|
|
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);
|
|
rc = cam_cci_transfer_end(cci_dev, master, queue);
|
|
if (rc < 0) {
|
|
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;
|
|
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_unlock(&cci_dev->cci_master_info[master].mutex);
|
|
|
|
|
|
mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]);
|
|
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.
|
|
* 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
|
|
* 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;
|
|
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 +
|
|
read_words = cam_io_r_mb(base +
|
|
CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100);
|
|
CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100);
|
|
if (read_words <= 0) {
|
|
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);
|
|
cam_cci_flush_queue(cci_dev, master);
|
|
goto rel_mutex_q;
|
|
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;
|
|
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_unlock(&cci_dev->cci_master_info[master].mutex);
|
|
|
|
|
|
mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]);
|
|
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.
|
|
* 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
|
|
* 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;
|
|
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 +
|
|
read_words = cam_io_r_mb(base +
|
|
CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100);
|
|
CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100);
|
|
exp_words = ((read_cfg->num_byte / 4) + 1);
|
|
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;
|
|
goto ERROR;
|
|
}
|
|
}
|
|
mutex_unlock(&cci_dev->cci_master_info[master].mutex);
|
|
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.
|
|
* 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
|
|
* 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
|
|
* THRESHOLD irq's, we reinit the threshold wait before
|
|
* we load the burst read cmd.
|
|
* 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);
|
|
reinit_completion(&cci_dev->cci_master_info[master].th_complete);
|
|
|
|
|
|
CAM_DBG(CAM_CCI, "Bytes to read %u", read_bytes);
|
|
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;
|
|
int32_t rc = 0;
|
|
struct cci_device *cci_dev = v4l2_get_subdevdata(sd);
|
|
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) {
|
|
switch (cci_ctrl->cmd) {
|
|
case MSM_CCI_INIT:
|
|
case MSM_CCI_INIT:
|