mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-09 21:59:12 -04:00
Merge "i2c: i2c-msm-geni: WAR to halt cancel if IOS not in good state"
This commit is contained in:
commit
938b49e74b
1 changed files with 69 additions and 15 deletions
|
|
@ -134,6 +134,7 @@ struct geni_i2c_dev {
|
|||
bool first_resume;
|
||||
bool gpi_reset;
|
||||
bool disable_dma_mode;
|
||||
bool prev_cancel_pending; //Halt cancel till IOS in good state
|
||||
};
|
||||
|
||||
static struct geni_i2c_dev *gi2c_dev_dbg[MAX_SE];
|
||||
|
|
@ -241,10 +242,45 @@ err_ret:
|
|||
gi2c->err = gi2c_log[err].err;
|
||||
}
|
||||
|
||||
static int geni_i2c_prepare(struct geni_i2c_dev *gi2c)
|
||||
static int do_pending_cancel(struct geni_i2c_dev *gi2c)
|
||||
{
|
||||
int timeout = 0;
|
||||
u32 geni_ios = 0;
|
||||
|
||||
geni_ios = geni_read_reg_nolog(gi2c->base, SE_GENI_IOS);
|
||||
if ((geni_ios & 0x3) != 0x3) {
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"%s: Can't do pending cancel, IOS bad state: 0x%x\n",
|
||||
__func__, geni_ios);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (gi2c->se_mode == GSI_ONLY) {
|
||||
dmaengine_terminate_all(gi2c->tx_c);
|
||||
gi2c->cfg_sent = 0;
|
||||
} else {
|
||||
reinit_completion(&gi2c->xfer);
|
||||
geni_cancel_m_cmd(gi2c->base);
|
||||
timeout = wait_for_completion_timeout(&gi2c->xfer, HZ);
|
||||
if (!timeout) {
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"%s:Pending Cancel failed\n", __func__);
|
||||
reinit_completion(&gi2c->xfer);
|
||||
geni_abort_m_cmd(gi2c->base);
|
||||
timeout = wait_for_completion_timeout(&gi2c->xfer, HZ);
|
||||
if (!timeout)
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"%s:Abort failed\n", __func__);
|
||||
}
|
||||
}
|
||||
gi2c->prev_cancel_pending = false;
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"%s: Pending Cancel done\n", __func__);
|
||||
return timeout;
|
||||
}
|
||||
|
||||
static int geni_i2c_prepare(struct geni_i2c_dev *gi2c)
|
||||
{
|
||||
if (gi2c->se_mode == UNINITIALIZED) {
|
||||
int proto = get_se_proto(gi2c->base);
|
||||
u32 se_mode;
|
||||
|
|
@ -256,16 +292,6 @@ static int geni_i2c_prepare(struct geni_i2c_dev *gi2c)
|
|||
return -ENXIO;
|
||||
}
|
||||
|
||||
geni_ios = geni_read_reg_nolog(gi2c->base, SE_GENI_IOS);
|
||||
if ((geni_ios & 0x3) != 0x3) { //SCL:b'1, SDA:b'0
|
||||
GENI_SE_DBG(gi2c->ipcl, true, gi2c->dev,
|
||||
"IO lines not in good state, Check power to slave\n");
|
||||
|
||||
if (!gi2c->is_le_vm)
|
||||
se_geni_resources_off(&gi2c->i2c_rsc);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
se_mode = readl_relaxed(gi2c->base +
|
||||
GENI_IF_FIFO_DISABLE_RO);
|
||||
if (se_mode) {
|
||||
|
|
@ -933,6 +959,8 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
|||
timeout = wait_for_completion_timeout(&gi2c->xfer,
|
||||
gi2c->xfer_timeout);
|
||||
if (!timeout) {
|
||||
u32 geni_ios = 0;
|
||||
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"I2C gsi xfer timeout:%u flags:%d addr:0x%x\n",
|
||||
gi2c->xfer_timeout, gi2c->cur->flags,
|
||||
|
|
@ -940,6 +968,15 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
|||
geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base,
|
||||
gi2c->ipcl);
|
||||
gi2c->err = -ETIMEDOUT;
|
||||
|
||||
/* WAR: Set flag to mark cancel pending if IOS stuck */
|
||||
geni_ios = geni_read_reg_nolog(gi2c->base, SE_GENI_IOS);
|
||||
if ((geni_ios & 0x3) != 0x3) { //SCL:b'1, SDA:b'0
|
||||
GENI_SE_DBG(gi2c->ipcl, true, gi2c->dev,
|
||||
"%s: IO lines not in good state\n", __func__);
|
||||
gi2c->prev_cancel_pending = true;
|
||||
goto geni_i2c_gsi_cancel_pending;
|
||||
}
|
||||
}
|
||||
geni_i2c_err_prep_sg:
|
||||
if (gi2c->err) {
|
||||
|
|
@ -962,6 +999,7 @@ geni_i2c_err_prep_sg:
|
|||
/* Resend cfg tre for every new message on shared se */
|
||||
gi2c->cfg_sent = 0;
|
||||
|
||||
geni_i2c_gsi_cancel_pending:
|
||||
if (msgs[i].flags & I2C_M_RD)
|
||||
geni_se_iommu_unmap_buf(rx_dev, &gi2c->rx_ph,
|
||||
msgs[i].len, DMA_FROM_DEVICE);
|
||||
|
|
@ -1007,6 +1045,13 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
|
|||
}
|
||||
}
|
||||
|
||||
// WAR : Complete previous pending cancel cmd
|
||||
if (gi2c->prev_cancel_pending) {
|
||||
ret = do_pending_cancel(gi2c);
|
||||
if (ret)
|
||||
return ret; //Don't perform xfer is cancel failed
|
||||
}
|
||||
|
||||
GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
|
||||
"n:%d addr:0x%x\n", num, msgs[0].addr);
|
||||
|
||||
|
|
@ -1124,9 +1169,20 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
|
|||
timeout = wait_for_completion_timeout(&gi2c->xfer,
|
||||
gi2c->xfer_timeout);
|
||||
if (!timeout) {
|
||||
u32 geni_ios = 0;
|
||||
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"I2C xfer timeout: %d\n", gi2c->xfer_timeout);
|
||||
geni_i2c_err(gi2c, GENI_TIMEOUT);
|
||||
|
||||
/* WAR: Set flag to mark cancel pending if IOS bad */
|
||||
geni_ios = geni_read_reg_nolog(gi2c->base, SE_GENI_IOS);
|
||||
if ((geni_ios & 0x3) != 0x3) { //SCL:b'1, SDA:b'0
|
||||
GENI_SE_DBG(gi2c->ipcl, true, gi2c->dev,
|
||||
"%s: IO lines not in good state\n", __func__);
|
||||
gi2c->prev_cancel_pending = true;
|
||||
goto geni_i2c_txn_ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (gi2c->err) {
|
||||
|
|
@ -1453,19 +1509,17 @@ static int geni_i2c_runtime_resume(struct device *dev)
|
|||
if (!gi2c->is_le_vm) {
|
||||
/* Do not control clk/gpio/icb for LE-VM */
|
||||
ret = se_geni_resources_on(&gi2c->i2c_rsc);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = geni_i2c_prepare(gi2c);
|
||||
if (ret) {
|
||||
dev_err(gi2c->dev, "I2C prepare failed\n");
|
||||
dev_err(gi2c->dev, "I2C prepare failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (gi2c->se_mode == FIFO_SE_DMA)
|
||||
enable_irq(gi2c->irq);
|
||||
|
||||
} else if (!gi2c->first_resume) {
|
||||
/*
|
||||
* For first resume call in le, do nothing, and in
|
||||
|
|
@ -1475,7 +1529,7 @@ static int geni_i2c_runtime_resume(struct device *dev)
|
|||
*/
|
||||
ret = geni_i2c_prepare(gi2c);
|
||||
if (ret) {
|
||||
dev_err(gi2c->dev, "I2C prepare failed\n");
|
||||
dev_err(gi2c->dev, "I2C prepare failed:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue