]> Pileus Git - ~andy/linux/blobdiff - drivers/i2c/busses/i2c-omap.c
Merge tag 'rpmsg-3.6-fix' of git://git.kernel.org/pub/scm/linux/kernel/git/ohad/rpmsg
[~andy/linux] / drivers / i2c / busses / i2c-omap.c
index c2148332de0f641fdffcdd395741785cee93af77..5d19a49803c152089c85b5b51c4d83cbb7a91cda 100644 (file)
@@ -49,8 +49,8 @@
 
 /* I2C controller revisions present on specific hardware */
 #define OMAP_I2C_REV_ON_2430           0x36
-#define OMAP_I2C_REV_ON_3430           0x3C
-#define OMAP_I2C_REV_ON_3530_4430      0x40
+#define OMAP_I2C_REV_ON_3430_3530      0x3C
+#define OMAP_I2C_REV_ON_3630_4430      0x40
 
 /* timeout waiting for the controller to respond */
 #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
@@ -173,7 +173,7 @@ enum {
 
 /* Errata definitions */
 #define I2C_OMAP_ERRATA_I207           (1 << 0)
-#define I2C_OMAP3_1P153                        (1 << 1)
+#define I2C_OMAP_ERRATA_I462           (1 << 1)
 
 struct omap_i2c_dev {
        struct device           *dev;
@@ -269,47 +269,6 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
                                (i2c_dev->regs[reg] << i2c_dev->reg_shift));
 }
 
-static void omap_i2c_unidle(struct omap_i2c_dev *dev)
-{
-       if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
-               omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
-               omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate);
-               omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate);
-               omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, dev->sclhstate);
-               omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, dev->bufstate);
-               omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, dev->syscstate);
-               omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate);
-               omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
-       }
-
-       /*
-        * Don't write to this register if the IE state is 0 as it can
-        * cause deadlock.
-        */
-       if (dev->iestate)
-               omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
-}
-
-static void omap_i2c_idle(struct omap_i2c_dev *dev)
-{
-       u16 iv;
-
-       dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
-       if (dev->dtrev == OMAP_I2C_IP_VERSION_2)
-               omap_i2c_write_reg(dev, OMAP_I2C_IP_V2_IRQENABLE_CLR, 1);
-       else
-               omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
-
-       if (dev->rev < OMAP_I2C_OMAP1_REV_2) {
-               iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */
-       } else {
-               omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, dev->iestate);
-
-               /* Flush posted write */
-               omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
-       }
-}
-
 static int omap_i2c_init(struct omap_i2c_dev *dev)
 {
        u16 psc = 0, scll = 0, sclh = 0, buf = 0;
@@ -346,7 +305,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
                        omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG,
                                           SYSC_AUTOIDLE_MASK);
 
-               } else if (dev->rev >= OMAP_I2C_REV_ON_3430) {
+               } else if (dev->rev >= OMAP_I2C_REV_ON_3430_3530) {
                        dev->syscstate = SYSC_AUTOIDLE_MASK;
                        dev->syscstate |= SYSC_ENAWAKEUP_MASK;
                        dev->syscstate |= (SYSC_IDLEMODE_SMART <<
@@ -468,11 +427,6 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
        /* Take the I2C module out of reset: */
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
 
-       dev->errata = 0;
-
-       if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207)
-               dev->errata |= I2C_OMAP_ERRATA_I207;
-
        /* Enable interrupts */
        dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
                        OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
@@ -514,7 +468,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
                             struct i2c_msg *msg, int stop)
 {
        struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
-       int r;
+       unsigned long timeout;
        u16 w;
 
        dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
@@ -536,7 +490,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
        w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR;
        omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w);
 
-       init_completion(&dev->cmd_complete);
+       INIT_COMPLETION(dev->cmd_complete);
        dev->cmd_err = 0;
 
        w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT;
@@ -584,12 +538,10 @@ 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.
         */
-       r = wait_for_completion_timeout(&dev->cmd_complete,
-                                       OMAP_I2C_TIMEOUT);
+       timeout = wait_for_completion_timeout(&dev->cmd_complete,
+                                               OMAP_I2C_TIMEOUT);
        dev->buf_len = 0;
-       if (r < 0)
-               return r;
-       if (r == 0) {
+       if (timeout == 0) {
                dev_err(dev->dev, "controller timed out\n");
                omap_i2c_init(dev);
                return -ETIMEDOUT;
@@ -630,7 +582,9 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
        int i;
        int r;
 
-       pm_runtime_get_sync(dev->dev);
+       r = pm_runtime_get_sync(dev->dev);
+       if (IS_ERR_VALUE(r))
+               goto out;
 
        r = omap_i2c_wait_for_bb(dev);
        if (r < 0)
@@ -767,11 +721,11 @@ omap_i2c_omap1_isr(int this_irq, void *dev_id)
 #endif
 
 /*
- * OMAP3430 Errata 1.153: When an XRDY/XDR is hit, wait for XUDF before writing
+ * OMAP3430 Errata i462: When an XRDY/XDR is hit, wait for XUDF before writing
  * data to DATA_REG. Otherwise some data bytes can be lost while transferring
  * them from the memory to the I2C interface.
  */
-static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err)
+static int errata_omap3_i462(struct omap_i2c_dev *dev, u16 *stat, int *err)
 {
        unsigned long timeout = 10000;
 
@@ -779,7 +733,6 @@ static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err)
                if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
                        omap_i2c_ack_stat(dev, *stat & (OMAP_I2C_STAT_XRDY |
                                                        OMAP_I2C_STAT_XDR));
-                       *err |= OMAP_I2C_STAT_XUDF;
                        return -ETIMEDOUT;
                }
 
@@ -792,6 +745,7 @@ static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err)
                return 0;
        }
 
+       *err |= OMAP_I2C_STAT_XUDF;
        return 0;
 }
 
@@ -930,8 +884,8 @@ complete:
                                        break;
                                }
 
-                               if ((dev->errata & I2C_OMAP3_1P153) &&
-                                   errata_omap3_1p153(dev, &stat, &err))
+                               if ((dev->errata & I2C_OMAP_ERRATA_I462) &&
+                                   errata_omap3_i462(dev, &stat, &err))
                                        goto complete;
 
                                omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
@@ -1048,6 +1002,7 @@ omap_i2c_probe(struct platform_device *pdev)
        }
 
        platform_set_drvdata(pdev, dev);
+       init_completion(&dev->cmd_complete);
 
        dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3;
 
@@ -1057,12 +1012,19 @@ omap_i2c_probe(struct platform_device *pdev)
                dev->regs = (u8 *)reg_map_ip_v1;
 
        pm_runtime_enable(dev->dev);
-       pm_runtime_get_sync(dev->dev);
+       r = pm_runtime_get_sync(dev->dev);
+       if (IS_ERR_VALUE(r))
+               goto err_free_mem;
 
        dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
 
-       if (dev->rev <= OMAP_I2C_REV_ON_3430)
-               dev->errata |= I2C_OMAP3_1P153;
+       dev->errata = 0;
+
+       if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207)
+               dev->errata |= I2C_OMAP_ERRATA_I207;
+
+       if (dev->rev <= OMAP_I2C_REV_ON_3430_3530)
+               dev->errata |= I2C_OMAP_ERRATA_I462;
 
        if (!(dev->flags & OMAP_I2C_FLAG_NO_FIFO)) {
                u16 s;
@@ -1079,7 +1041,7 @@ omap_i2c_probe(struct platform_device *pdev)
 
                dev->fifo_size = (dev->fifo_size / 2);
 
-               if (dev->rev >= OMAP_I2C_REV_ON_3530_4430)
+               if (dev->rev >= OMAP_I2C_REV_ON_3630_4430)
                        dev->b_hw = 0; /* Disable hardware fixes */
                else
                        dev->b_hw = 1; /* Enable hardware fixes */
@@ -1095,7 +1057,7 @@ omap_i2c_probe(struct platform_device *pdev)
 
        isr = (dev->rev < OMAP_I2C_OMAP1_REV_2) ? omap_i2c_omap1_isr :
                                                                   omap_i2c_isr;
-       r = request_irq(dev->irq, isr, 0, pdev->name, dev);
+       r = request_irq(dev->irq, isr, IRQF_NO_SUSPEND, pdev->name, dev);
 
        if (r) {
                dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);
@@ -1105,8 +1067,6 @@ omap_i2c_probe(struct platform_device *pdev)
        dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", pdev->id,
                 dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed);
 
-       pm_runtime_put(dev->dev);
-
        adap = &dev->adapter;
        i2c_set_adapdata(adap, dev);
        adap->owner = THIS_MODULE;
@@ -1126,6 +1086,8 @@ omap_i2c_probe(struct platform_device *pdev)
 
        of_i2c_register_devices(adap);
 
+       pm_runtime_put(dev->dev);
+
        return 0;
 
 err_free_irq:
@@ -1134,6 +1096,7 @@ err_unuse_clocks:
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
        pm_runtime_put(dev->dev);
        iounmap(dev->base);
+       pm_runtime_disable(&pdev->dev);
 err_free_mem:
        platform_set_drvdata(pdev, NULL);
        kfree(dev);
@@ -1143,17 +1106,23 @@ err_release_region:
        return r;
 }
 
-static int
-omap_i2c_remove(struct platform_device *pdev)
+static int __devexit omap_i2c_remove(struct platform_device *pdev)
 {
        struct omap_i2c_dev     *dev = platform_get_drvdata(pdev);
        struct resource         *mem;
+       int ret;
 
        platform_set_drvdata(pdev, NULL);
 
        free_irq(dev->irq, dev);
        i2c_del_adapter(&dev->adapter);
+       ret = pm_runtime_get_sync(&pdev->dev);
+       if (IS_ERR_VALUE(ret))
+               return ret;
+
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+       pm_runtime_put(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
        iounmap(dev->base);
        kfree(dev);
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1161,13 +1130,26 @@ omap_i2c_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
 #ifdef CONFIG_PM_RUNTIME
 static int omap_i2c_runtime_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct omap_i2c_dev *_dev = platform_get_drvdata(pdev);
+       u16 iv;
+
+       _dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG);
+
+       omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0);
 
-       omap_i2c_idle(_dev);
+       if (_dev->rev < OMAP_I2C_OMAP1_REV_2) {
+               iv = omap_i2c_read_reg(_dev, OMAP_I2C_IV_REG); /* Read clears */
+       } else {
+               omap_i2c_write_reg(_dev, OMAP_I2C_STAT_REG, _dev->iestate);
+
+               /* Flush posted write */
+               omap_i2c_read_reg(_dev, OMAP_I2C_STAT_REG);
+       }
 
        return 0;
 }
@@ -1177,23 +1159,40 @@ static int omap_i2c_runtime_resume(struct device *dev)
        struct platform_device *pdev = to_platform_device(dev);
        struct omap_i2c_dev *_dev = platform_get_drvdata(pdev);
 
-       omap_i2c_unidle(_dev);
+       if (_dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
+               omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, 0);
+               omap_i2c_write_reg(_dev, OMAP_I2C_PSC_REG, _dev->pscstate);
+               omap_i2c_write_reg(_dev, OMAP_I2C_SCLL_REG, _dev->scllstate);
+               omap_i2c_write_reg(_dev, OMAP_I2C_SCLH_REG, _dev->sclhstate);
+               omap_i2c_write_reg(_dev, OMAP_I2C_BUF_REG, _dev->bufstate);
+               omap_i2c_write_reg(_dev, OMAP_I2C_SYSC_REG, _dev->syscstate);
+               omap_i2c_write_reg(_dev, OMAP_I2C_WE_REG, _dev->westate);
+               omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+       }
+
+       /*
+        * Don't write to this register if the IE state is 0 as it can
+        * cause deadlock.
+        */
+       if (_dev->iestate)
+               omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, _dev->iestate);
 
        return 0;
 }
+#endif /* CONFIG_PM_RUNTIME */
 
 static struct dev_pm_ops omap_i2c_pm_ops = {
-       .runtime_suspend = omap_i2c_runtime_suspend,
-       .runtime_resume = omap_i2c_runtime_resume,
+       SET_RUNTIME_PM_OPS(omap_i2c_runtime_suspend,
+                          omap_i2c_runtime_resume, NULL)
 };
 #define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops)
 #else
 #define OMAP_I2C_PM_OPS NULL
-#endif
+#endif /* CONFIG_PM */
 
 static struct platform_driver omap_i2c_driver = {
        .probe          = omap_i2c_probe,
-       .remove         = omap_i2c_remove,
+       .remove         = __devexit_p(omap_i2c_remove),
        .driver         = {
                .name   = "omap_i2c",
                .owner  = THIS_MODULE,