Commit 92b775c2 authored by Lucas Stach's avatar Lucas Stach Committed by Wolfram Sang

i2c: mxs: do error checking and handling in PIO mode

In PIO mode we can end up with the same errors as in DMA mode, but as IRQs
are disabled there we have to check for them manually after each command.

Also don't use the big controller reset hammer when receiving a NAK from a
slave. It's sufficient to tell the controller to continue at a clean state.
Signed-off-by: default avatarLucas Stach <l.stach@pengutronix.de>
Tested-by: default avatarMarek Vasut <marex@denx.de>
Signed-off-by: default avatarWolfram Sang <wsa@the-dreams.de>
parent 535ebd21
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
#define MXS_I2C_CTRL1_SET (0x44) #define MXS_I2C_CTRL1_SET (0x44)
#define MXS_I2C_CTRL1_CLR (0x48) #define MXS_I2C_CTRL1_CLR (0x48)
#define MXS_I2C_CTRL1_CLR_GOT_A_NAK 0x10000000
#define MXS_I2C_CTRL1_BUS_FREE_IRQ 0x80 #define MXS_I2C_CTRL1_BUS_FREE_IRQ 0x80
#define MXS_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ 0x40 #define MXS_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ 0x40
#define MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ 0x20 #define MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ 0x20
...@@ -340,6 +341,23 @@ static int mxs_i2c_pio_wait_cplt(struct mxs_i2c_dev *i2c, int last) ...@@ -340,6 +341,23 @@ static int mxs_i2c_pio_wait_cplt(struct mxs_i2c_dev *i2c, int last)
return 0; return 0;
} }
static int mxs_i2c_pio_check_error_state(struct mxs_i2c_dev *i2c)
{
u32 state;
state = readl(i2c->regs + MXS_I2C_CTRL1_CLR) & MXS_I2C_IRQ_MASK;
if (state & MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ)
i2c->cmd_err = -ENXIO;
else if (state & (MXS_I2C_CTRL1_EARLY_TERM_IRQ |
MXS_I2C_CTRL1_MASTER_LOSS_IRQ |
MXS_I2C_CTRL1_SLAVE_STOP_IRQ |
MXS_I2C_CTRL1_SLAVE_IRQ))
i2c->cmd_err = -EIO;
return i2c->cmd_err;
}
static void mxs_i2c_pio_trigger_cmd(struct mxs_i2c_dev *i2c, u32 cmd) static void mxs_i2c_pio_trigger_cmd(struct mxs_i2c_dev *i2c, u32 cmd)
{ {
u32 reg; u32 reg;
...@@ -380,6 +398,9 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, ...@@ -380,6 +398,9 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap,
if (ret) if (ret)
return ret; return ret;
if (mxs_i2c_pio_check_error_state(i2c))
goto cleanup;
/* READ command. */ /* READ command. */
mxs_i2c_pio_trigger_cmd(i2c, mxs_i2c_pio_trigger_cmd(i2c,
MXS_CMD_I2C_READ | flags | MXS_CMD_I2C_READ | flags |
...@@ -440,6 +461,10 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, ...@@ -440,6 +461,10 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap,
if (ret) if (ret)
return ret; return ret;
/* make sure we capture any occurred error into cmd_err */
mxs_i2c_pio_check_error_state(i2c);
cleanup:
/* Clear any dangling IRQs and re-enable interrupts. */ /* Clear any dangling IRQs and re-enable interrupts. */
writel(MXS_I2C_IRQ_MASK, i2c->regs + MXS_I2C_CTRL1_CLR); writel(MXS_I2C_IRQ_MASK, i2c->regs + MXS_I2C_CTRL1_CLR);
writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET); writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET);
...@@ -471,12 +496,12 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, ...@@ -471,12 +496,12 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
* using PIO mode while longer transfers use DMA. The 8 byte border is * using PIO mode while longer transfers use DMA. The 8 byte border is
* based on this empirical measurement and a lot of previous frobbing. * based on this empirical measurement and a lot of previous frobbing.
*/ */
i2c->cmd_err = 0;
if (msg->len < 8) { if (msg->len < 8) {
ret = mxs_i2c_pio_setup_xfer(adap, msg, flags); ret = mxs_i2c_pio_setup_xfer(adap, msg, flags);
if (ret) if (ret)
mxs_i2c_reset(i2c); mxs_i2c_reset(i2c);
} else { } else {
i2c->cmd_err = 0;
INIT_COMPLETION(i2c->cmd_complete); INIT_COMPLETION(i2c->cmd_complete);
ret = mxs_i2c_dma_setup_xfer(adap, msg, flags); ret = mxs_i2c_dma_setup_xfer(adap, msg, flags);
if (ret) if (ret)
...@@ -486,12 +511,18 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, ...@@ -486,12 +511,18 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
msecs_to_jiffies(1000)); msecs_to_jiffies(1000));
if (ret == 0) if (ret == 0)
goto timeout; goto timeout;
}
if (i2c->cmd_err == -ENXIO) if (i2c->cmd_err == -ENXIO) {
mxs_i2c_reset(i2c); /*
* If the transfer fails with a NAK from the slave the
* controller halts until it gets told to return to idle state.
*/
writel(MXS_I2C_CTRL1_CLR_GOT_A_NAK,
i2c->regs + MXS_I2C_CTRL1_SET);
}
ret = i2c->cmd_err; ret = i2c->cmd_err;
}
dev_dbg(i2c->dev, "Done with err=%d\n", ret); dev_dbg(i2c->dev, "Done with err=%d\n", ret);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment