diff options
author | Paul Walmsley <paul@pwsan.com> | 2008-11-21 16:39:47 -0500 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2008-11-21 16:39:47 -0500 |
commit | 3831f154418e058616129942e8175dc4c7e4a1d8 (patch) | |
tree | 39373d541573f986cce29acd8b54f7e4584e11af /drivers | |
parent | c1a473bde4c06e8e6996ce3a33121b7a9a86b4b9 (diff) |
i2c-omap: fix I2C timeouts due to recursive omap_i2c_{un,}idle()
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/i2c/busses/i2c-omap.c | 9 |
1 files changed, 7 insertions, 2 deletions
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 4aeebad8ec93..40a1e4bc92f1 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c | |||
@@ -191,6 +191,8 @@ static void omap_i2c_put_clocks(struct omap_i2c_dev *dev) | |||
191 | 191 | ||
192 | static void omap_i2c_unidle(struct omap_i2c_dev *dev) | 192 | static void omap_i2c_unidle(struct omap_i2c_dev *dev) |
193 | { | 193 | { |
194 | WARN_ON(!dev->idle); | ||
195 | |||
194 | if (dev->iclk != NULL) | 196 | if (dev->iclk != NULL) |
195 | clk_enable(dev->iclk); | 197 | clk_enable(dev->iclk); |
196 | clk_enable(dev->fclk); | 198 | clk_enable(dev->fclk); |
@@ -203,6 +205,8 @@ static void omap_i2c_idle(struct omap_i2c_dev *dev) | |||
203 | { | 205 | { |
204 | u16 iv; | 206 | u16 iv; |
205 | 207 | ||
208 | WARN_ON(dev->idle); | ||
209 | |||
206 | dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); | 210 | dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); |
207 | omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0); | 211 | omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0); |
208 | if (dev->rev1) { | 212 | if (dev->rev1) { |
@@ -740,6 +744,7 @@ omap_i2c_probe(struct platform_device *pdev) | |||
740 | speed = 100; /* Defualt speed */ | 744 | speed = 100; /* Defualt speed */ |
741 | 745 | ||
742 | dev->speed = speed; | 746 | dev->speed = speed; |
747 | dev->idle = 1; | ||
743 | dev->dev = &pdev->dev; | 748 | dev->dev = &pdev->dev; |
744 | dev->irq = irq->start; | 749 | dev->irq = irq->start; |
745 | dev->base = ioremap(mem->start, mem->end - mem->start + 1); | 750 | dev->base = ioremap(mem->start, mem->end - mem->start + 1); |
@@ -788,6 +793,8 @@ omap_i2c_probe(struct platform_device *pdev) | |||
788 | dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n", | 793 | dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n", |
789 | pdev->id, r >> 4, r & 0xf, dev->speed); | 794 | pdev->id, r >> 4, r & 0xf, dev->speed); |
790 | 795 | ||
796 | omap_i2c_idle(dev); | ||
797 | |||
791 | adap = &dev->adapter; | 798 | adap = &dev->adapter; |
792 | i2c_set_adapdata(adap, dev); | 799 | i2c_set_adapdata(adap, dev); |
793 | adap->owner = THIS_MODULE; | 800 | adap->owner = THIS_MODULE; |
@@ -804,8 +811,6 @@ omap_i2c_probe(struct platform_device *pdev) | |||
804 | goto err_free_irq; | 811 | goto err_free_irq; |
805 | } | 812 | } |
806 | 813 | ||
807 | omap_i2c_idle(dev); | ||
808 | |||
809 | return 0; | 814 | return 0; |
810 | 815 | ||
811 | err_free_irq: | 816 | err_free_irq: |