Merge branch 'i2c-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6
[pandora-kernel.git] / drivers / i2c / busses / i2c-omap.c
index cb55cf2..e7eb7bf 100644 (file)
@@ -128,6 +128,8 @@ struct omap_i2c_dev {
        size_t                  buf_len;
        struct i2c_adapter      adapter;
        unsigned                rev1:1;
+       unsigned                idle:1;
+       u16                     iestate;        /* Saved interrupt register */
 };
 
 static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
@@ -174,18 +176,30 @@ static void omap_i2c_put_clocks(struct omap_i2c_dev *dev)
        }
 }
 
-static void omap_i2c_enable_clocks(struct omap_i2c_dev *dev)
+static void omap_i2c_unidle(struct omap_i2c_dev *dev)
 {
        if (dev->iclk != NULL)
                clk_enable(dev->iclk);
        clk_enable(dev->fclk);
+       if (dev->iestate)
+               omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
+       dev->idle = 0;
 }
 
-static void omap_i2c_disable_clocks(struct omap_i2c_dev *dev)
+static void omap_i2c_idle(struct omap_i2c_dev *dev)
 {
+       u16 iv;
+
+       dev->idle = 1;
+       dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
+       omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
+       if (dev->rev1)
+               iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);   /* Read clears */
+       else
+               omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, dev->iestate);
+       clk_disable(dev->fclk);
        if (dev->iclk != NULL)
                clk_disable(dev->iclk);
-       clk_disable(dev->fclk);
 }
 
 static int omap_i2c_init(struct omap_i2c_dev *dev)
@@ -360,10 +374,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
        int i;
        int r;
 
-       omap_i2c_enable_clocks(dev);
+       omap_i2c_unidle(dev);
 
-       /* REVISIT: initialize and use adap->retries. This is an optional
-        * feature */
        if ((r = omap_i2c_wait_for_bb(dev)) < 0)
                goto out;
 
@@ -376,7 +388,7 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
        if (r == 0)
                r = num;
 out:
-       omap_i2c_disable_clocks(dev);
+       omap_i2c_idle(dev);
        return r;
 }
 
@@ -405,6 +417,9 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id)
        struct omap_i2c_dev *dev = dev_id;
        u16 iv, w;
 
+       if (dev->idle)
+               return IRQ_NONE;
+
        iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);
        switch (iv) {
        case 0x00:      /* None */
@@ -459,6 +474,9 @@ omap_i2c_isr(int this_irq, void *dev_id)
        u16 stat, w;
        int count = 0;
 
+       if (dev->idle)
+               return IRQ_NONE;
+
        bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
        while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) {
                dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat);
@@ -577,7 +595,7 @@ omap_i2c_probe(struct platform_device *pdev)
        if ((r = omap_i2c_get_clocks(dev)) != 0)
                goto err_free_mem;
 
-       omap_i2c_enable_clocks(dev);
+       omap_i2c_unidle(dev);
 
        if (cpu_is_omap15xx())
                dev->rev1 = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) < 0x20;
@@ -612,20 +630,20 @@ omap_i2c_probe(struct platform_device *pdev)
                goto err_free_irq;
        }
 
-       omap_i2c_disable_clocks(dev);
+       omap_i2c_idle(dev);
 
        return 0;
 
 err_free_irq:
        free_irq(dev->irq, dev);
 err_unuse_clocks:
-       omap_i2c_disable_clocks(dev);
+       omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+       omap_i2c_idle(dev);
        omap_i2c_put_clocks(dev);
 err_free_mem:
        platform_set_drvdata(pdev, NULL);
        kfree(dev);
 err_release_region:
-       omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
        release_mem_region(mem->start, (mem->end - mem->start) + 1);
 
        return r;
@@ -675,3 +693,4 @@ module_exit(omap_i2c_exit_driver);
 MODULE_AUTHOR("MontaVista Software, Inc. (and others)");
 MODULE_DESCRIPTION("TI OMAP I2C bus adapter");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:i2c_omap");