diff --git a/drivers/i2c/busses/i2c-msm-geni.c b/drivers/i2c/busses/i2c-msm-geni.c index d1c7af60c50f..21b2dcfd8a6d 100644 --- a/drivers/i2c/busses/i2c-msm-geni.c +++ b/drivers/i2c/busses/i2c-msm-geni.c @@ -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; }