Skip to content

Commit

Permalink
i2c-omap: fix I2C timeouts due to recursive omap_i2c_{un,}idle()
Browse files Browse the repository at this point in the history
omap_i2c_unidle() and omap_i2c_idle() are called recursively during
omap_i2c_probe().  This is evidently unexpected and will wipe
out the I2C interrupt enable register the second time that
omap_i2c_idle() is called consecutively.  Any I2C transactions
following a probe of a bus with at least one device on it will then
time out.

Fix by moving omap_i2c_idle() further up in omap_i2c_probe().  Ensure
the I2C controller is marked as idle before the probe starts.  Also
attempt to catch future reappearances of this bug early in development
by warning in omap_i2c_{un,}idle() when they are called recursively.

Problem reported by David Brownell <david-b@pacbell.net>.

Tested on 3430SDP and 2430SDP.

Signed-off-by: Paul Walmsley <paul@pwsan.com>
Cc: David Brownell <david-b@pacbell.net>
Cc: Richard Woodruff <r-woodruff2@ti.com>
Acked-by; Steve Sakoman <steve@sakoman.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
  • Loading branch information
Paul Walmsley authored and Tony Lindgren committed Nov 21, 2008
1 parent c1a473b commit 3831f15
Showing 1 changed file with 7 additions and 2 deletions.
9 changes: 7 additions & 2 deletions drivers/i2c/busses/i2c-omap.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ static void omap_i2c_put_clocks(struct omap_i2c_dev *dev)

static void omap_i2c_unidle(struct omap_i2c_dev *dev)
{
WARN_ON(!dev->idle);

if (dev->iclk != NULL)
clk_enable(dev->iclk);
clk_enable(dev->fclk);
Expand All @@ -203,6 +205,8 @@ static void omap_i2c_idle(struct omap_i2c_dev *dev)
{
u16 iv;

WARN_ON(dev->idle);

dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
if (dev->rev1) {
Expand Down Expand Up @@ -740,6 +744,7 @@ omap_i2c_probe(struct platform_device *pdev)
speed = 100; /* Defualt speed */

dev->speed = speed;
dev->idle = 1;
dev->dev = &pdev->dev;
dev->irq = irq->start;
dev->base = ioremap(mem->start, mem->end - mem->start + 1);
Expand Down Expand Up @@ -788,6 +793,8 @@ omap_i2c_probe(struct platform_device *pdev)
dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n",
pdev->id, r >> 4, r & 0xf, dev->speed);

omap_i2c_idle(dev);

adap = &dev->adapter;
i2c_set_adapdata(adap, dev);
adap->owner = THIS_MODULE;
Expand All @@ -804,8 +811,6 @@ omap_i2c_probe(struct platform_device *pdev)
goto err_free_irq;
}

omap_i2c_idle(dev);

return 0;

err_free_irq:
Expand Down

0 comments on commit 3831f15

Please sign in to comment.