mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
i2c-mpc: work around missing-9th-clock-pulse bug
Work around a problem reported on: http://ozlabs.org/pipermail/linuxppc-embedded/2005-July/019038.html Without this patch I2C on mpc5200 becomes unusable after a while. Tested on mpc5200 boards by Matthias Fechner and me. Signed-off-by: Domen Puncer <domen.puncer@telargo.com> Signed-off-by: Jean Delvare <khali@linux-fr.org>
This commit is contained in:
parent
1b144df1d7
commit
254db9b5e7
@ -74,6 +74,25 @@ static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* Sometimes 9th clock pulse isn't generated, and slave doesn't release
|
||||
* the bus, because it wants to send ACK.
|
||||
* Following sequence of enabling/disabling and sending start/stop generates
|
||||
* the pulse, so it's all OK.
|
||||
*/
|
||||
static void mpc_i2c_fixup(struct mpc_i2c *i2c)
|
||||
{
|
||||
writeccr(i2c, 0);
|
||||
udelay(30);
|
||||
writeccr(i2c, CCR_MEN);
|
||||
udelay(30);
|
||||
writeccr(i2c, CCR_MSTA | CCR_MTX);
|
||||
udelay(30);
|
||||
writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
|
||||
udelay(30);
|
||||
writeccr(i2c, CCR_MEN);
|
||||
udelay(30);
|
||||
}
|
||||
|
||||
static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
|
||||
{
|
||||
unsigned long orig_jiffies = jiffies;
|
||||
@ -153,6 +172,7 @@ static void mpc_i2c_start(struct mpc_i2c *i2c)
|
||||
static void mpc_i2c_stop(struct mpc_i2c *i2c)
|
||||
{
|
||||
writeccr(i2c, CCR_MEN);
|
||||
writeccr(i2c, 0);
|
||||
}
|
||||
|
||||
static int mpc_write(struct mpc_i2c *i2c, int target,
|
||||
@ -245,6 +265,9 @@ static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||
}
|
||||
if (time_after(jiffies, orig_jiffies + HZ)) {
|
||||
pr_debug("I2C: timeout\n");
|
||||
if (readb(i2c->base + MPC_I2C_SR) ==
|
||||
(CSR_MCF | CSR_MBB | CSR_RXAK))
|
||||
mpc_i2c_fixup(i2c);
|
||||
return -EIO;
|
||||
}
|
||||
schedule();
|
||||
|
Loading…
Reference in New Issue
Block a user