Skip to content

Commit

Permalink
i2c: mxs: only flag completion when queue is completely done
Browse files Browse the repository at this point in the history
The hardware generates an interrupt for every completed command in the
queue while the code assumed that it will only generate one interrupt
when the queue is empty. So, explicitly check if the queue is really
empty. This patch fixed problems which occurred due to high traffic on
the bus. While we are here, move the completion-initialization after the
parameter error checking.

Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Cc: Shawn Guo <shawn.guo@linaro.org>
Cc: Marek Vasut <marek.vasut@gmail.com>
Cc: Lothar Waßmann <LW@KARO-electronics.de>
Cc: stable@kernel.org
  • Loading branch information
Wolfram Sang committed Feb 24, 2012
1 parent b01543d commit 844990d
Showing 1 changed file with 10 additions and 3 deletions.
13 changes: 10 additions & 3 deletions drivers/i2c/busses/i2c-mxs.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@

#define MXS_I2C_QUEUESTAT (0x70)
#define MXS_I2C_QUEUESTAT_RD_QUEUE_EMPTY 0x00002000
#define MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK 0x0000001F

#define MXS_I2C_QUEUECMD (0x80)

Expand Down Expand Up @@ -219,14 +220,14 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
int ret;
int flags;

init_completion(&i2c->cmd_complete);

dev_dbg(i2c->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
msg->addr, msg->len, msg->flags, stop);

if (msg->len == 0)
return -EINVAL;

init_completion(&i2c->cmd_complete);

flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0;

if (msg->flags & I2C_M_RD)
Expand Down Expand Up @@ -286,6 +287,7 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id)
{
struct mxs_i2c_dev *i2c = dev_id;
u32 stat = readl(i2c->regs + MXS_I2C_CTRL1) & MXS_I2C_IRQ_MASK;
bool is_last_cmd;

if (!stat)
return IRQ_NONE;
Expand All @@ -300,9 +302,14 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id)
else
i2c->cmd_err = 0;

complete(&i2c->cmd_complete);
is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) &
MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0;

if (is_last_cmd || i2c->cmd_err)
complete(&i2c->cmd_complete);

writel(stat, i2c->regs + MXS_I2C_CTRL1_CLR);

return IRQ_HANDLED;
}

Expand Down

0 comments on commit 844990d

Please sign in to comment.