]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/i2c/busses/i2c-omap.c
Merge tag 'v2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / drivers / i2c / busses / i2c-omap.c
index b33c78586bfccf815d9322df1d561b7bec5797b5..58a58c7eaa17d6eb7fac8b2ca6014110e0e3f225 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/i2c-omap.h>
+#include <linux/pm_runtime.h>
 
 /* I2C controller revisions */
 #define OMAP_I2C_REV_2                 0x20
@@ -175,8 +176,6 @@ struct omap_i2c_dev {
        void __iomem            *base;          /* virtual */
        int                     irq;
        int                     reg_shift;      /* bit shift for I2C register addresses */
-       struct clk              *iclk;          /* Interface clock */
-       struct clk              *fclk;          /* Functional clock */
        struct completion       cmd_complete;
        struct resource         *ioarea;
        u32                     latency;        /* maximum mpu wkup latency */
@@ -265,45 +264,18 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
                                (i2c_dev->regs[reg] << i2c_dev->reg_shift));
 }
 
-static int __init omap_i2c_get_clocks(struct omap_i2c_dev *dev)
+static void omap_i2c_unidle(struct omap_i2c_dev *dev)
 {
-       int ret;
-
-       dev->iclk = clk_get(dev->dev, "ick");
-       if (IS_ERR(dev->iclk)) {
-               ret = PTR_ERR(dev->iclk);
-               dev->iclk = NULL;
-               return ret;
-       }
-
-       dev->fclk = clk_get(dev->dev, "fck");
-       if (IS_ERR(dev->fclk)) {
-               ret = PTR_ERR(dev->fclk);
-               if (dev->iclk != NULL) {
-                       clk_put(dev->iclk);
-                       dev->iclk = NULL;
-               }
-               dev->fclk = NULL;
-               return ret;
-       }
+       struct platform_device *pdev;
+       struct omap_i2c_bus_platform_data *pdata;
 
-       return 0;
-}
+       WARN_ON(!dev->idle);
 
-static void omap_i2c_put_clocks(struct omap_i2c_dev *dev)
-{
-       clk_put(dev->fclk);
-       dev->fclk = NULL;
-       clk_put(dev->iclk);
-       dev->iclk = NULL;
-}
+       pdev = to_platform_device(dev->dev);
+       pdata = pdev->dev.platform_data;
 
-static void omap_i2c_unidle(struct omap_i2c_dev *dev)
-{
-       WARN_ON(!dev->idle);
+       pm_runtime_get_sync(&pdev->dev);
 
-       clk_enable(dev->iclk);
-       clk_enable(dev->fclk);
        if (cpu_is_omap34xx()) {
                omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
                omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate);
@@ -326,10 +298,15 @@ static void omap_i2c_unidle(struct omap_i2c_dev *dev)
 
 static void omap_i2c_idle(struct omap_i2c_dev *dev)
 {
+       struct platform_device *pdev;
+       struct omap_i2c_bus_platform_data *pdata;
        u16 iv;
 
        WARN_ON(dev->idle);
 
+       pdev = to_platform_device(dev->dev);
+       pdata = pdev->dev.platform_data;
+
        dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
        if (dev->rev >= OMAP_I2C_REV_ON_4430)
                omap_i2c_write_reg(dev, OMAP_I2C_IRQENABLE_CLR, 1);
@@ -345,8 +322,8 @@ static void omap_i2c_idle(struct omap_i2c_dev *dev)
                omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
        }
        dev->idle = 1;
-       clk_disable(dev->fclk);
-       clk_disable(dev->iclk);
+
+       pm_runtime_put_sync(&pdev->dev);
 }
 
 static int omap_i2c_init(struct omap_i2c_dev *dev)
@@ -356,6 +333,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
        unsigned long fclk_rate = 12000000;
        unsigned long timeout;
        unsigned long internal_clk = 0;
+       struct clk *fclk;
 
        if (dev->rev >= OMAP_I2C_REV_2) {
                /* Disable I2C controller before soft reset */
@@ -400,9 +378,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
                         * REVISIT: Some wkup sources might not be needed.
                         */
                        dev->westate = OMAP_I2C_WE_ALL;
-                       if (dev->rev < OMAP_I2C_REV_ON_4430)
-                               omap_i2c_write_reg(dev, OMAP_I2C_WE_REG,
-                                                               dev->westate);
+                       omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate);
                }
        }
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
@@ -414,7 +390,9 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
                 * always returns 12MHz for the functional clock, we can
                 * do this bit unconditionally.
                 */
-               fclk_rate = clk_get_rate(dev->fclk);
+               fclk = clk_get(dev->dev, "fck");
+               fclk_rate = clk_get_rate(fclk);
+               clk_put(fclk);
 
                /* TRM for 5912 says the I2C clock must be prescaled to be
                 * between 7 - 12 MHz. The XOR input clock is typically
@@ -443,7 +421,9 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
                        internal_clk = 9600;
                else
                        internal_clk = 4000;
-               fclk_rate = clk_get_rate(dev->fclk) / 1000;
+               fclk = clk_get(dev->dev, "fck");
+               fclk_rate = clk_get_rate(fclk) / 1000;
+               clk_put(fclk);
 
                /* Compute prescaler divisor */
                psc = fclk_rate / internal_clk;
@@ -616,12 +596,8 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
         * REVISIT: We should abort the transfer on signals, but the bus goes
         * into arbitration and we're currently unable to recover from it.
         */
-       if (dev->set_mpu_wkup_lat != NULL)
-               dev->set_mpu_wkup_lat(dev->dev, dev->latency);
        r = wait_for_completion_timeout(&dev->cmd_complete,
                                        OMAP_I2C_TIMEOUT);
-       if (dev->set_mpu_wkup_lat != NULL)
-               dev->set_mpu_wkup_lat(dev->dev, -1);
        dev->buf_len = 0;
        if (r < 0)
                return r;
@@ -672,12 +648,18 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
        if (r < 0)
                goto out;
 
+       if (dev->set_mpu_wkup_lat != NULL)
+               dev->set_mpu_wkup_lat(dev->dev, dev->latency);
+
        for (i = 0; i < num; i++) {
                r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)));
                if (r != 0)
                        break;
        }
 
+       if (dev->set_mpu_wkup_lat != NULL)
+               dev->set_mpu_wkup_lat(dev->dev, -1);
+
        if (r == 0)
                r = num;
 
@@ -863,11 +845,15 @@ complete:
                        dev_err(dev->dev, "Arbitration lost\n");
                        err |= OMAP_I2C_STAT_AL;
                }
+               /*
+                * ProDB0017052: Clear ARDY bit twice
+                */
                if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
                                        OMAP_I2C_STAT_AL)) {
                        omap_i2c_ack_stat(dev, stat &
                                (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR |
-                               OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
+                               OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR |
+                               OMAP_I2C_STAT_ARDY));
                        omap_i2c_complete_cmd(dev, err);
                        return IRQ_HANDLED;
                }
@@ -1048,14 +1034,12 @@ omap_i2c_probe(struct platform_device *pdev)
        else
                dev->reg_shift = 2;
 
-       if ((r = omap_i2c_get_clocks(dev)) != 0)
-               goto err_iounmap;
-
        if (cpu_is_omap44xx())
                dev->regs = (u8 *) omap4_reg_map;
        else
                dev->regs = (u8 *) reg_map;
 
+       pm_runtime_enable(&pdev->dev);
        omap_i2c_unidle(dev);
 
        dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
@@ -1127,8 +1111,6 @@ err_free_irq:
 err_unuse_clocks:
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
        omap_i2c_idle(dev);
-       omap_i2c_put_clocks(dev);
-err_iounmap:
        iounmap(dev->base);
 err_free_mem:
        platform_set_drvdata(pdev, NULL);
@@ -1150,7 +1132,6 @@ omap_i2c_remove(struct platform_device *pdev)
        free_irq(dev->irq, dev);
        i2c_del_adapter(&dev->adapter);
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
-       omap_i2c_put_clocks(dev);
        iounmap(dev->base);
        kfree(dev);
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1158,12 +1139,41 @@ omap_i2c_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_SUSPEND
+static int omap_i2c_suspend(struct device *dev)
+{
+       if (!pm_runtime_suspended(dev))
+               if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend)
+                       dev->bus->pm->runtime_suspend(dev);
+
+       return 0;
+}
+
+static int omap_i2c_resume(struct device *dev)
+{
+       if (!pm_runtime_suspended(dev))
+               if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume)
+                       dev->bus->pm->runtime_resume(dev);
+
+       return 0;
+}
+
+static struct dev_pm_ops omap_i2c_pm_ops = {
+       .suspend = omap_i2c_suspend,
+       .resume = omap_i2c_resume,
+};
+#define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops)
+#else
+#define OMAP_I2C_PM_OPS NULL
+#endif
+
 static struct platform_driver omap_i2c_driver = {
        .probe          = omap_i2c_probe,
        .remove         = omap_i2c_remove,
        .driver         = {
-               .name   = "i2c_omap",
+               .name   = "omap_i2c",
                .owner  = THIS_MODULE,
+               .pm     = OMAP_I2C_PM_OPS,
        },
 };
 
@@ -1184,4 +1194,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");
+MODULE_ALIAS("platform:omap_i2c");