aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorPaul Walmsley <paul@pwsan.com>2008-11-21 16:39:47 -0500
committerTony Lindgren <tony@atomide.com>2008-11-21 16:39:47 -0500
commit3831f154418e058616129942e8175dc4c7e4a1d8 (patch)
tree39373d541573f986cce29acd8b54f7e4584e11af /drivers
parentc1a473bde4c06e8e6996ce3a33121b7a9a86b4b9 (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.c9
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
192static void omap_i2c_unidle(struct omap_i2c_dev *dev) 192static 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
811err_free_irq: 816err_free_irq: