]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/i2c/busses/i2c-omap.c
Merge branch 'drm-fixes-3.7' of git://people.freedesktop.org/~agd5f/linux
[karo-tx-linux.git] / drivers / i2c / busses / i2c-omap.c
index a0e49f6aaf96eaa81ac712a4a279fafbdf13af95..3525c9e62cb0f9bf23f47705fd86d3bba9707b45 100644 (file)
@@ -55,6 +55,9 @@
 /* timeout waiting for the controller to respond */
 #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
 
+/* timeout for pm runtime autosuspend */
+#define OMAP_I2C_PM_TIMEOUT            1000    /* ms */
+
 /* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */
 enum {
        OMAP_I2C_REV_REG = 0,
@@ -176,6 +179,7 @@ enum {
 #define I2C_OMAP_ERRATA_I462           (1 << 1)
 
 struct omap_i2c_dev {
+       spinlock_t              lock;           /* IRQ synchronization */
        struct device           *dev;
        void __iomem            *base;          /* virtual */
        int                     irq;
@@ -193,12 +197,14 @@ struct omap_i2c_dev {
        u8                      *regs;
        size_t                  buf_len;
        struct i2c_adapter      adapter;
+       u8                      threshold;
        u8                      fifo_size;      /* use as flag and value
                                                 * fifo_size==0 implies no fifo
                                                 * if set, should be trsh+1
                                                 */
        u8                      rev;
        unsigned                b_hw:1;         /* bad h/w fixes */
+       unsigned                receiver:1;     /* true when we're in receiver mode */
        u16                     iestate;        /* Saved interrupt register */
        u16                     pscstate;
        u16                     scllstate;
@@ -417,13 +423,6 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
        omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll);
        omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh);
 
-       if (dev->fifo_size) {
-               /* Note: setup required fifo size - 1. RTRSH and XTRSH */
-               buf = (dev->fifo_size - 1) << 8 | OMAP_I2C_BUF_RXFIF_CLR |
-                       (dev->fifo_size - 1) | OMAP_I2C_BUF_TXFIF_CLR;
-               omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf);
-       }
-
        /* Take the I2C module out of reset: */
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
 
@@ -461,6 +460,45 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev)
        return 0;
 }
 
+static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx)
+{
+       u16             buf;
+
+       if (dev->flags & OMAP_I2C_FLAG_NO_FIFO)
+               return;
+
+       /*
+        * Set up notification threshold based on message size. We're doing
+        * this to try and avoid draining feature as much as possible. Whenever
+        * we have big messages to transfer (bigger than our total fifo size)
+        * then we might use draining feature to transfer the remaining bytes.
+        */
+
+       dev->threshold = clamp(size, (u8) 1, dev->fifo_size);
+
+       buf = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG);
+
+       if (is_rx) {
+               /* Clear RX Threshold */
+               buf &= ~(0x3f << 8);
+               buf |= ((dev->threshold - 1) << 8) | OMAP_I2C_BUF_RXFIF_CLR;
+       } else {
+               /* Clear TX Threshold */
+               buf &= ~0x3f;
+               buf |= (dev->threshold - 1) | OMAP_I2C_BUF_TXFIF_CLR;
+       }
+
+       omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf);
+
+       if (dev->rev < OMAP_I2C_REV_ON_3630_4430)
+               dev->b_hw = 1; /* Enable hardware fixes */
+
+       /* calculate wakeup latency constraint for MPU */
+       if (dev->set_mpu_wkup_lat != NULL)
+               dev->latency = (1000000 * dev->threshold) /
+                       (1000 * dev->speed / 8);
+}
+
 /*
  * Low level master read/write transaction.
  */
@@ -477,12 +515,18 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
        if (msg->len == 0)
                return -EINVAL;
 
+       dev->receiver = !!(msg->flags & I2C_M_RD);
+       omap_i2c_resize_fifo(dev, msg->len, dev->receiver);
+
        omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr);
 
        /* REVISIT: Could the STB bit of I2C_CON be used with probing? */
        dev->buf = msg->buf;
        dev->buf_len = msg->len;
 
+       /* make sure writes to dev->buf_len are ordered */
+       barrier();
+
        omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len);
 
        /* Clear the FIFO Buffers */
@@ -540,7 +584,6 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
         */
        timeout = wait_for_completion_timeout(&dev->cmd_complete,
                                                OMAP_I2C_TIMEOUT);
-       dev->buf_len = 0;
        if (timeout == 0) {
                dev_err(dev->dev, "controller timed out\n");
                omap_i2c_init(dev);
@@ -607,7 +650,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 
        omap_i2c_wait_for_bb(dev);
 out:
-       pm_runtime_put(dev->dev);
+       pm_runtime_mark_last_busy(dev->dev);
+       pm_runtime_put_autosuspend(dev->dev);
        return r;
 }
 
@@ -725,186 +769,252 @@ omap_i2c_omap1_isr(int this_irq, void *dev_id)
  * 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_i462(struct omap_i2c_dev *dev, u16 *stat, int *err)
+static int errata_omap3_i462(struct omap_i2c_dev *dev)
 {
        unsigned long timeout = 10000;
+       u16 stat;
 
-       while (--timeout && !(*stat & OMAP_I2C_STAT_XUDF)) {
-               if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
-                       omap_i2c_ack_stat(dev, *stat & (OMAP_I2C_STAT_XRDY |
+       do {
+               stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
+               if (stat & OMAP_I2C_STAT_XUDF)
+                       break;
+
+               if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
+                       omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY |
                                                        OMAP_I2C_STAT_XDR));
-                       return -ETIMEDOUT;
+                       if (stat & OMAP_I2C_STAT_NACK) {
+                               dev->cmd_err |= OMAP_I2C_STAT_NACK;
+                               omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK);
+                       }
+
+                       if (stat & OMAP_I2C_STAT_AL) {
+                               dev_err(dev->dev, "Arbitration lost\n");
+                               dev->cmd_err |= OMAP_I2C_STAT_AL;
+                               omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK);
+                       }
+
+                       return -EIO;
                }
 
                cpu_relax();
-               *stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
-       }
+       } while (--timeout);
 
        if (!timeout) {
                dev_err(dev->dev, "timeout waiting on XUDF bit\n");
                return 0;
        }
 
-       *err |= OMAP_I2C_STAT_XUDF;
        return 0;
 }
 
+static void omap_i2c_receive_data(struct omap_i2c_dev *dev, u8 num_bytes,
+               bool is_rdr)
+{
+       u16             w;
+
+       while (num_bytes--) {
+               w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
+               *dev->buf++ = w;
+               dev->buf_len--;
+
+               /*
+                * Data reg in 2430, omap3 and
+                * omap4 is 8 bit wide
+                */
+               if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) {
+                       *dev->buf++ = w >> 8;
+                       dev->buf_len--;
+               }
+       }
+}
+
+static int omap_i2c_transmit_data(struct omap_i2c_dev *dev, u8 num_bytes,
+               bool is_xdr)
+{
+       u16             w;
+
+       while (num_bytes--) {
+               w = *dev->buf++;
+               dev->buf_len--;
+
+               /*
+                * Data reg in 2430, omap3 and
+                * omap4 is 8 bit wide
+                */
+               if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) {
+                       w |= *dev->buf++ << 8;
+                       dev->buf_len--;
+               }
+
+               if (dev->errata & I2C_OMAP_ERRATA_I462) {
+                       int ret;
+
+                       ret = errata_omap3_i462(dev);
+                       if (ret < 0)
+                               return ret;
+               }
+
+               omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+       }
+
+       return 0;
+}
+
+static irqreturn_t
+omap_i2c_isr(int irq, void *dev_id)
+{
+       struct omap_i2c_dev *dev = dev_id;
+       irqreturn_t ret = IRQ_HANDLED;
+       u16 mask;
+       u16 stat;
+
+       spin_lock(&dev->lock);
+       mask = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
+       stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
+
+       if (stat & mask)
+               ret = IRQ_WAKE_THREAD;
+
+       spin_unlock(&dev->lock);
+
+       return ret;
+}
+
 static irqreturn_t
-omap_i2c_isr(int this_irq, void *dev_id)
+omap_i2c_isr_thread(int this_irq, void *dev_id)
 {
        struct omap_i2c_dev *dev = dev_id;
+       unsigned long flags;
        u16 bits;
-       u16 stat, w;
-       int err, count = 0;
+       u16 stat;
+       int err = 0, count = 0;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       do {
+               bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
+               stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
+               stat &= bits;
+
+               /* If we're in receiver mode, ignore XDR/XRDY */
+               if (dev->receiver)
+                       stat &= ~(OMAP_I2C_STAT_XDR | OMAP_I2C_STAT_XRDY);
+               else
+                       stat &= ~(OMAP_I2C_STAT_RDR | OMAP_I2C_STAT_RRDY);
 
-       if (pm_runtime_suspended(dev->dev))
-               return IRQ_NONE;
+               if (!stat) {
+                       /* my work here is done */
+                       goto out;
+               }
 
-       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);
                if (count++ == 100) {
                        dev_warn(dev->dev, "Too much work in one IRQ\n");
                        break;
                }
 
-               err = 0;
-complete:
-               /*
-                * Ack the stat in one go, but [R/X]DR and [R/X]RDY should be
-                * acked after the data operation is complete.
-                * Ref: TRM SWPU114Q Figure 18-31
-                */
-               omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat &
-                               ~(OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR |
-                               OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
-
-               if (stat & OMAP_I2C_STAT_NACK)
+               if (stat & OMAP_I2C_STAT_NACK) {
                        err |= OMAP_I2C_STAT_NACK;
+                       omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK);
+                       break;
+               }
 
                if (stat & OMAP_I2C_STAT_AL) {
                        dev_err(dev->dev, "Arbitration lost\n");
                        err |= OMAP_I2C_STAT_AL;
+                       omap_i2c_ack_stat(dev, OMAP_I2C_STAT_AL);
+                       break;
                }
+
                /*
                 * 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_ARDY));
-                       omap_i2c_complete_cmd(dev, err);
-                       return IRQ_HANDLED;
+                       omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY |
+                                               OMAP_I2C_STAT_RDR |
+                                               OMAP_I2C_STAT_XRDY |
+                                               OMAP_I2C_STAT_XDR |
+                                               OMAP_I2C_STAT_ARDY));
+                       break;
                }
-               if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) {
+
+               if (stat & OMAP_I2C_STAT_RDR) {
                        u8 num_bytes = 1;
 
+                       if (dev->fifo_size)
+                               num_bytes = dev->buf_len;
+
+                       omap_i2c_receive_data(dev, num_bytes, true);
+
                        if (dev->errata & I2C_OMAP_ERRATA_I207)
                                i2c_omap_errata_i207(dev, stat);
 
-                       if (dev->fifo_size) {
-                               if (stat & OMAP_I2C_STAT_RRDY)
-                                       num_bytes = dev->fifo_size;
-                               else    /* read RXSTAT on RDR interrupt */
-                                       num_bytes = (omap_i2c_read_reg(dev,
-                                                       OMAP_I2C_BUFSTAT_REG)
-                                                       >> 8) & 0x3F;
-                       }
-                       while (num_bytes) {
-                               num_bytes--;
-                               w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
-                               if (dev->buf_len) {
-                                       *dev->buf++ = w;
-                                       dev->buf_len--;
-                                       /*
-                                        * Data reg in 2430, omap3 and
-                                        * omap4 is 8 bit wide
-                                        */
-                                       if (dev->flags &
-                                                OMAP_I2C_FLAG_16BIT_DATA_REG) {
-                                               if (dev->buf_len) {
-                                                       *dev->buf++ = w >> 8;
-                                                       dev->buf_len--;
-                                               }
-                                       }
-                               } else {
-                                       if (stat & OMAP_I2C_STAT_RRDY)
-                                               dev_err(dev->dev,
-                                                       "RRDY IRQ while no data"
-                                                               " requested\n");
-                                       if (stat & OMAP_I2C_STAT_RDR)
-                                               dev_err(dev->dev,
-                                                       "RDR IRQ while no data"
-                                                               " requested\n");
-                                       break;
-                               }
-                       }
-                       omap_i2c_ack_stat(dev,
-                               stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR));
+                       omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR);
+                       break;
+               }
+
+               if (stat & OMAP_I2C_STAT_RRDY) {
+                       u8 num_bytes = 1;
+
+                       if (dev->threshold)
+                               num_bytes = dev->threshold;
+
+                       omap_i2c_receive_data(dev, num_bytes, false);
+                       omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY);
                        continue;
                }
-               if (stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)) {
+
+               if (stat & OMAP_I2C_STAT_XDR) {
                        u8 num_bytes = 1;
-                       if (dev->fifo_size) {
-                               if (stat & OMAP_I2C_STAT_XRDY)
-                                       num_bytes = dev->fifo_size;
-                               else    /* read TXSTAT on XDR interrupt */
-                                       num_bytes = omap_i2c_read_reg(dev,
-                                                       OMAP_I2C_BUFSTAT_REG)
-                                                       & 0x3F;
-                       }
-                       while (num_bytes) {
-                               num_bytes--;
-                               w = 0;
-                               if (dev->buf_len) {
-                                       w = *dev->buf++;
-                                       dev->buf_len--;
-                                       /*
-                                        * Data reg in 2430, omap3 and
-                                        * omap4 is 8 bit wide
-                                        */
-                                       if (dev->flags &
-                                                OMAP_I2C_FLAG_16BIT_DATA_REG) {
-                                               if (dev->buf_len) {
-                                                       w |= *dev->buf++ << 8;
-                                                       dev->buf_len--;
-                                               }
-                                       }
-                               } else {
-                                       if (stat & OMAP_I2C_STAT_XRDY)
-                                               dev_err(dev->dev,
-                                                       "XRDY IRQ while no "
-                                                       "data to send\n");
-                                       if (stat & OMAP_I2C_STAT_XDR)
-                                               dev_err(dev->dev,
-                                                       "XDR IRQ while no "
-                                                       "data to send\n");
-                                       break;
-                               }
-
-                               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);
-                       }
-                       omap_i2c_ack_stat(dev,
-                               stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
+                       int ret;
+
+                       if (dev->fifo_size)
+                               num_bytes = dev->buf_len;
+
+                       ret = omap_i2c_transmit_data(dev, num_bytes, true);
+                       if (ret < 0)
+                               break;
+
+                       omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XDR);
+                       break;
+               }
+
+               if (stat & OMAP_I2C_STAT_XRDY) {
+                       u8 num_bytes = 1;
+                       int ret;
+
+                       if (dev->threshold)
+                               num_bytes = dev->threshold;
+
+                       ret = omap_i2c_transmit_data(dev, num_bytes, false);
+                       if (ret < 0)
+                               break;
+
+                       omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY);
                        continue;
                }
+
                if (stat & OMAP_I2C_STAT_ROVR) {
                        dev_err(dev->dev, "Receive overrun\n");
-                       dev->cmd_err |= OMAP_I2C_STAT_ROVR;
+                       err |= OMAP_I2C_STAT_ROVR;
+                       omap_i2c_ack_stat(dev, OMAP_I2C_STAT_ROVR);
+                       break;
                }
+
                if (stat & OMAP_I2C_STAT_XUDF) {
                        dev_err(dev->dev, "Transmit underflow\n");
-                       dev->cmd_err |= OMAP_I2C_STAT_XUDF;
+                       err |= OMAP_I2C_STAT_XUDF;
+                       omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XUDF);
+                       break;
                }
-       }
+       } while (stat);
+
+       omap_i2c_complete_cmd(dev, err);
+
+out:
+       spin_unlock_irqrestore(&dev->lock, flags);
 
-       return count ? IRQ_HANDLED : IRQ_NONE;
+       return IRQ_HANDLED;
 }
 
 static const struct i2c_algorithm omap_i2c_algo = {
@@ -943,12 +1053,12 @@ omap_i2c_probe(struct platform_device *pdev)
 {
        struct omap_i2c_dev     *dev;
        struct i2c_adapter      *adap;
-       struct resource         *mem, *irq, *ioarea;
+       struct resource         *mem;
        const struct omap_i2c_bus_platform_data *pdata =
                pdev->dev.platform_data;
        struct device_node      *node = pdev->dev.of_node;
        const struct of_device_id *match;
-       irq_handler_t isr;
+       int irq;
        int r;
 
        /* NOTE: driver uses the static register mapping */
@@ -957,23 +1067,23 @@ omap_i2c_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "no mem resource?\n");
                return -ENODEV;
        }
-       irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!irq) {
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
                dev_err(&pdev->dev, "no irq resource?\n");
-               return -ENODEV;
+               return irq;
        }
 
-       ioarea = request_mem_region(mem->start, resource_size(mem),
-                       pdev->name);
-       if (!ioarea) {
-               dev_err(&pdev->dev, "I2C region already claimed\n");
-               return -EBUSY;
+       dev = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL);
+       if (!dev) {
+               dev_err(&pdev->dev, "Menory allocation failed\n");
+               return -ENOMEM;
        }
 
-       dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL);
-       if (!dev) {
-               r = -ENOMEM;
-               goto err_release_region;
+       dev->base = devm_request_and_ioremap(&pdev->dev, mem);
+       if (!dev->base) {
+               dev_err(&pdev->dev, "I2C region already claimed\n");
+               return -ENOMEM;
        }
 
        match = of_match_device(of_match_ptr(omap_i2c_of_match), &pdev->dev);
@@ -995,12 +1105,9 @@ omap_i2c_probe(struct platform_device *pdev)
        }
 
        dev->dev = &pdev->dev;
-       dev->irq = irq->start;
-       dev->base = ioremap(mem->start, resource_size(mem));
-       if (!dev->base) {
-               r = -ENOMEM;
-               goto err_free_mem;
-       }
+       dev->irq = irq;
+
+       spin_lock_init(&dev->lock);
 
        platform_set_drvdata(pdev, dev);
        init_completion(&dev->cmd_complete);
@@ -1013,6 +1120,9 @@ omap_i2c_probe(struct platform_device *pdev)
                dev->regs = (u8 *)reg_map_ip_v1;
 
        pm_runtime_enable(dev->dev);
+       pm_runtime_set_autosuspend_delay(dev->dev, OMAP_I2C_PM_TIMEOUT);
+       pm_runtime_use_autosuspend(dev->dev);
+
        r = pm_runtime_get_sync(dev->dev);
        if (IS_ERR_VALUE(r))
                goto err_free_mem;
@@ -1042,9 +1152,7 @@ omap_i2c_probe(struct platform_device *pdev)
 
                dev->fifo_size = (dev->fifo_size / 2);
 
-               if (dev->rev >= OMAP_I2C_REV_ON_3630_4430)
-                       dev->b_hw = 0; /* Disable hardware fixes */
-               else
+               if (dev->rev < OMAP_I2C_REV_ON_3630_4430)
                        dev->b_hw = 1; /* Enable hardware fixes */
 
                /* calculate wakeup latency constraint for MPU */
@@ -1056,18 +1164,20 @@ omap_i2c_probe(struct platform_device *pdev)
        /* reset ASAP, clearing any IRQs */
        omap_i2c_init(dev);
 
-       isr = (dev->rev < OMAP_I2C_OMAP1_REV_2) ? omap_i2c_omap1_isr :
-                                                                  omap_i2c_isr;
-       r = request_irq(dev->irq, isr, IRQF_NO_SUSPEND, pdev->name, dev);
+       if (dev->rev < OMAP_I2C_OMAP1_REV_2)
+               r = devm_request_irq(&pdev->dev, dev->irq, omap_i2c_omap1_isr,
+                               IRQF_NO_SUSPEND, pdev->name, dev);
+       else
+               r = devm_request_threaded_irq(&pdev->dev, dev->irq,
+                               omap_i2c_isr, omap_i2c_isr_thread,
+                               IRQF_NO_SUSPEND | IRQF_ONESHOT,
+                               pdev->name, dev);
 
        if (r) {
                dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);
                goto err_unuse_clocks;
        }
 
-       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);
-
        adap = &dev->adapter;
        i2c_set_adapdata(adap, dev);
        adap->owner = THIS_MODULE;
@@ -1082,27 +1192,25 @@ omap_i2c_probe(struct platform_device *pdev)
        r = i2c_add_numbered_adapter(adap);
        if (r) {
                dev_err(dev->dev, "failure adding adapter\n");
-               goto err_free_irq;
+               goto err_unuse_clocks;
        }
 
+       dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", adap->nr,
+                dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed);
+
        of_i2c_register_devices(adap);
 
-       pm_runtime_put(dev->dev);
+       pm_runtime_mark_last_busy(dev->dev);
+       pm_runtime_put_autosuspend(dev->dev);
 
        return 0;
 
-err_free_irq:
-       free_irq(dev->irq, dev);
 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);
-err_release_region:
-       release_mem_region(mem->start, resource_size(mem));
 
        return r;
 }
@@ -1110,12 +1218,10 @@ err_release_region:
 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))
@@ -1124,10 +1230,6 @@ static int __devexit omap_i2c_remove(struct platform_device *pdev)
        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);
-       release_mem_region(mem->start, resource_size(mem));
        return 0;
 }