include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / drivers / i2c / busses / i2c-designware.c
index 940bbf3..b664ed8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Synopsys Designware I2C adapter driver (master only).
+ * Synopsys DesignWare I2C adapter driver (master only).
  *
  * Based on the TI DAVINCI I2C adapter driver.
  *
@@ -36,6 +36,7 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/slab.h>
 
 /*
  * Registers offset
 #define DW_IC_INTR_START_DET   0x400
 #define DW_IC_INTR_GEN_CALL    0x800
 
+#define DW_IC_INTR_DEFAULT_MASK                (DW_IC_INTR_RX_FULL | \
+                                        DW_IC_INTR_TX_EMPTY | \
+                                        DW_IC_INTR_TX_ABRT | \
+                                        DW_IC_INTR_STOP_DET)
+
 #define DW_IC_STATUS_ACTIVITY  0x1
 
 #define DW_IC_ERR_TX_ABRT      0x1
 #define ABRT_SBYTE_ACKDET      7
 #define ABRT_SBYTE_NORSTRT     9
 #define ABRT_10B_RD_NORSTRT    10
-#define ARB_MASTER_DIS         11
+#define ABRT_MASTER_DIS                11
 #define ARB_LOST               12
 
+#define DW_IC_TX_ABRT_7B_ADDR_NOACK    (1UL << ABRT_7B_ADDR_NOACK)
+#define DW_IC_TX_ABRT_10ADDR1_NOACK    (1UL << ABRT_10ADDR1_NOACK)
+#define DW_IC_TX_ABRT_10ADDR2_NOACK    (1UL << ABRT_10ADDR2_NOACK)
+#define DW_IC_TX_ABRT_TXDATA_NOACK     (1UL << ABRT_TXDATA_NOACK)
+#define DW_IC_TX_ABRT_GCALL_NOACK      (1UL << ABRT_GCALL_NOACK)
+#define DW_IC_TX_ABRT_GCALL_READ       (1UL << ABRT_GCALL_READ)
+#define DW_IC_TX_ABRT_SBYTE_ACKDET     (1UL << ABRT_SBYTE_ACKDET)
+#define DW_IC_TX_ABRT_SBYTE_NORSTRT    (1UL << ABRT_SBYTE_NORSTRT)
+#define DW_IC_TX_ABRT_10B_RD_NORSTRT   (1UL << ABRT_10B_RD_NORSTRT)
+#define DW_IC_TX_ABRT_MASTER_DIS       (1UL << ABRT_MASTER_DIS)
+#define DW_IC_TX_ARB_LOST              (1UL << ARB_LOST)
+
+#define DW_IC_TX_ABRT_NOACK            (DW_IC_TX_ABRT_7B_ADDR_NOACK | \
+                                        DW_IC_TX_ABRT_10ADDR1_NOACK | \
+                                        DW_IC_TX_ABRT_10ADDR2_NOACK | \
+                                        DW_IC_TX_ABRT_TXDATA_NOACK | \
+                                        DW_IC_TX_ABRT_GCALL_NOACK)
+
 static char *abort_sources[] = {
-       [ABRT_7B_ADDR_NOACK]    =
+       [ABRT_7B_ADDR_NOACK] =
                "slave address not acknowledged (7bit mode)",
-       [ABRT_10ADDR1_NOACK]    =
+       [ABRT_10ADDR1_NOACK] =
                "first address byte not acknowledged (10bit mode)",
-       [ABRT_10ADDR2_NOACK]    =
+       [ABRT_10ADDR2_NOACK] =
                "second address byte not acknowledged (10bit mode)",
-       [ABRT_TXDATA_NOACK]             =
+       [ABRT_TXDATA_NOACK] =
                "data not acknowledged",
-       [ABRT_GCALL_NOACK]              =
+       [ABRT_GCALL_NOACK] =
                "no acknowledgement for a general call",
-       [ABRT_GCALL_READ]               =
+       [ABRT_GCALL_READ] =
                "read after general call",
-       [ABRT_SBYTE_ACKDET]             =
+       [ABRT_SBYTE_ACKDET] =
                "start byte acknowledged",
-       [ABRT_SBYTE_NORSTRT]    =
+       [ABRT_SBYTE_NORSTRT] =
                "trying to send start byte when restart is disabled",
-       [ABRT_10B_RD_NORSTRT]   =
+       [ABRT_10B_RD_NORSTRT] =
                "trying to read when restart is disabled (10bit mode)",
-       [ARB_MASTER_DIS]                =
+       [ABRT_MASTER_DIS] =
                "trying to use disabled adapter",
-       [ARB_LOST]                      =
+       [ARB_LOST] =
                "lost arbitration",
 };
 
@@ -326,85 +350,109 @@ static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
        return 0;
 }
 
+static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
+{
+       struct i2c_msg *msgs = dev->msgs;
+       u32 ic_con;
+
+       /* Disable the adapter */
+       writel(0, dev->base + DW_IC_ENABLE);
+
+       /* set the slave (target) address */
+       writel(msgs[dev->msg_write_idx].addr, dev->base + DW_IC_TAR);
+
+       /* if the slave address is ten bit address, enable 10BITADDR */
+       ic_con = readl(dev->base + DW_IC_CON);
+       if (msgs[dev->msg_write_idx].flags & I2C_M_TEN)
+               ic_con |= DW_IC_CON_10BITADDR_MASTER;
+       else
+               ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
+       writel(ic_con, dev->base + DW_IC_CON);
+
+       /* Enable the adapter */
+       writel(1, dev->base + DW_IC_ENABLE);
+
+       /* Enable interrupts */
+       writel(DW_IC_INTR_DEFAULT_MASK, dev->base + DW_IC_INTR_MASK);
+}
+
 /*
- * Initiate low level master read/write transaction.
- * This function is called from i2c_dw_xfer when starting a transfer.
- * This function is also called from i2c_dw_isr to continue a transfer
- * that is longer than the size of the TX FIFO.
+ * Initiate (and continue) low level master read/write transaction.
+ * This function is only called from i2c_dw_isr, and pumping i2c_msg
+ * messages into the tx buffer.  Even if the size of i2c_msg data is
+ * longer than the size of the tx buffer, it handles everything.
  */
 static void
 i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
 {
        struct i2c_msg *msgs = dev->msgs;
-       u32 ic_con, intr_mask;
-       int tx_limit = dev->tx_fifo_depth - readl(dev->base + DW_IC_TXFLR);
-       int rx_limit = dev->rx_fifo_depth - readl(dev->base + DW_IC_RXFLR);
+       u32 intr_mask;
+       int tx_limit, rx_limit;
        u32 addr = msgs[dev->msg_write_idx].addr;
        u32 buf_len = dev->tx_buf_len;
+       u8 *buf = dev->tx_buf;;
 
-       intr_mask = DW_IC_INTR_STOP_DET | DW_IC_INTR_TX_ABRT | DW_IC_INTR_RX_FULL;
-
-       if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) {
-               /* Disable the adapter */
-               writel(0, dev->base + DW_IC_ENABLE);
-
-               /* set the slave (target) address */
-               writel(msgs[dev->msg_write_idx].addr, dev->base + DW_IC_TAR);
-
-               /* if the slave address is ten bit address, enable 10BITADDR */
-               ic_con = readl(dev->base + DW_IC_CON);
-               if (msgs[dev->msg_write_idx].flags & I2C_M_TEN)
-                       ic_con |= DW_IC_CON_10BITADDR_MASTER;
-               else
-                       ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
-               writel(ic_con, dev->base + DW_IC_CON);
-
-               /* Enable the adapter */
-               writel(1, dev->base + DW_IC_ENABLE);
-       }
+       intr_mask = DW_IC_INTR_DEFAULT_MASK;
 
        for (; dev->msg_write_idx < dev->msgs_num; dev->msg_write_idx++) {
-               /* if target address has changed, we need to
+               /*
+                * if target address has changed, we need to
                 * reprogram the target address in the i2c
                 * adapter when we are done with this transfer
                 */
-               if (msgs[dev->msg_write_idx].addr != addr)
-                       return;
+               if (msgs[dev->msg_write_idx].addr != addr) {
+                       dev_err(dev->dev,
+                               "%s: invalid target address\n", __func__);
+                       dev->msg_err = -EINVAL;
+                       break;
+               }
 
                if (msgs[dev->msg_write_idx].len == 0) {
                        dev_err(dev->dev,
                                "%s: invalid message length\n", __func__);
                        dev->msg_err = -EINVAL;
-                       return;
+                       break;
                }
 
                if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) {
                        /* new i2c_msg */
-                       dev->tx_buf = msgs[dev->msg_write_idx].buf;
+                       buf = msgs[dev->msg_write_idx].buf;
                        buf_len = msgs[dev->msg_write_idx].len;
                }
 
+               tx_limit = dev->tx_fifo_depth - readl(dev->base + DW_IC_TXFLR);
+               rx_limit = dev->rx_fifo_depth - readl(dev->base + DW_IC_RXFLR);
+
                while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) {
                        if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {
                                writel(0x100, dev->base + DW_IC_DATA_CMD);
                                rx_limit--;
                        } else
-                               writel(*(dev->tx_buf++),
-                                               dev->base + DW_IC_DATA_CMD);
+                               writel(*buf++, dev->base + DW_IC_DATA_CMD);
                        tx_limit--; buf_len--;
                }
 
+               dev->tx_buf = buf;
                dev->tx_buf_len = buf_len;
 
                if (buf_len > 0) {
                        /* more bytes to be written */
-                       intr_mask |= DW_IC_INTR_TX_EMPTY;
                        dev->status |= STATUS_WRITE_IN_PROGRESS;
                        break;
                } else
                        dev->status &= ~STATUS_WRITE_IN_PROGRESS;
        }
 
+       /*
+        * If i2c_msg index search is completed, we don't need TX_EMPTY
+        * interrupt any more.
+        */
+       if (dev->msg_write_idx == dev->msgs_num)
+               intr_mask &= ~DW_IC_INTR_TX_EMPTY;
+
+       if (dev->msg_err)
+               intr_mask = 0;
+
        writel(intr_mask, dev->base + DW_IC_INTR_MASK);
 }
 
@@ -412,8 +460,7 @@ static void
 i2c_dw_read(struct dw_i2c_dev *dev)
 {
        struct i2c_msg *msgs = dev->msgs;
-       u32 addr = msgs[dev->msg_read_idx].addr;
-       int rx_valid = readl(dev->base + DW_IC_RXFLR);
+       int rx_valid;
 
        for (; dev->msg_read_idx < dev->msgs_num; dev->msg_read_idx++) {
                u32 len;
@@ -422,10 +469,6 @@ i2c_dw_read(struct dw_i2c_dev *dev)
                if (!(msgs[dev->msg_read_idx].flags & I2C_M_RD))
                        continue;
 
-               /* different i2c client, reprogram the i2c adapter */
-               if (msgs[dev->msg_read_idx].addr != addr)
-                       return;
-
                if (!(dev->status & STATUS_READ_IN_PROGRESS)) {
                        len = msgs[dev->msg_read_idx].len;
                        buf = msgs[dev->msg_read_idx].buf;
@@ -434,6 +477,8 @@ i2c_dw_read(struct dw_i2c_dev *dev)
                        buf = dev->rx_buf;
                }
 
+               rx_valid = readl(dev->base + DW_IC_RXFLR);
+
                for (; len > 0 && rx_valid > 0; len--, rx_valid--)
                        *buf++ = readl(dev->base + DW_IC_DATA_CMD);
 
@@ -447,6 +492,29 @@ i2c_dw_read(struct dw_i2c_dev *dev)
        }
 }
 
+static int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
+{
+       unsigned long abort_source = dev->abort_source;
+       int i;
+
+       if (abort_source & DW_IC_TX_ABRT_NOACK) {
+               for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
+                       dev_dbg(dev->dev,
+                               "%s: %s\n", __func__, abort_sources[i]);
+               return -EREMOTEIO;
+       }
+
+       for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
+               dev_err(dev->dev, "%s: %s\n", __func__, abort_sources[i]);
+
+       if (abort_source & DW_IC_TX_ARB_LOST)
+               return -EAGAIN;
+       else if (abort_source & DW_IC_TX_ABRT_GCALL_READ)
+               return -EINVAL; /* wrong msgs[] data */
+       else
+               return -EIO;
+}
+
 /*
  * Prepare controller for a transaction and call i2c_dw_xfer_msg
  */
@@ -468,13 +536,14 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
        dev->msg_read_idx = 0;
        dev->msg_err = 0;
        dev->status = STATUS_IDLE;
+       dev->abort_source = 0;
 
        ret = i2c_dw_wait_bus_not_busy(dev);
        if (ret < 0)
                goto done;
 
        /* start the transfers */
-       i2c_dw_xfer_msg(dev);
+       i2c_dw_xfer_init(dev);
 
        /* wait for tx to complete */
        ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ);
@@ -501,12 +570,8 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 
        /* We have an error */
        if (dev->cmd_err == DW_IC_ERR_TX_ABRT) {
-               unsigned long abort_source = dev->abort_source;
-               int i;
-
-               for_each_bit(i, &abort_source, ARRAY_SIZE(abort_sources)) {
-                   dev_err(dev->dev, "%s: %s\n", __func__, abort_sources[i]);
-               }
+               ret = i2c_dw_handle_tx_abort(dev);
+               goto done;
        }
        ret = -EIO;
 
@@ -518,7 +583,12 @@ done:
 
 static u32 i2c_dw_func(struct i2c_adapter *adap)
 {
-       return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR;
+       return  I2C_FUNC_I2C |
+               I2C_FUNC_10BIT_ADDR |
+               I2C_FUNC_SMBUS_BYTE |
+               I2C_FUNC_SMBUS_BYTE_DATA |
+               I2C_FUNC_SMBUS_WORD_DATA |
+               I2C_FUNC_SMBUS_I2C_BLOCK;
 }
 
 static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
@@ -591,6 +661,13 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
        if (stat & DW_IC_INTR_TX_ABRT) {
                dev->cmd_err |= DW_IC_ERR_TX_ABRT;
                dev->status = STATUS_IDLE;
+
+               /*
+                * Anytime TX_ABRT is set, the contents of the tx/rx
+                * buffers are flushed.  Make sure to skip them.
+                */
+               writel(0, dev->base + DW_IC_INTR_MASK);
+               goto tx_aborted;
        }
 
        if (stat & DW_IC_INTR_RX_FULL)
@@ -605,7 +682,8 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
         * the current transmit status.
         */
 
-       if (stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET))
+tx_aborted:
+       if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err)
                complete(&dev->cmd_complete);
 
        return IRQ_HANDLED;
@@ -677,7 +755,7 @@ static int __devinit dw_i2c_probe(struct platform_device *pdev)
        i2c_dw_init(dev);
 
        writel(0, dev->base + DW_IC_INTR_MASK); /* disable IRQ */
-       r = request_irq(dev->irq, i2c_dw_isr, 0, pdev->name, dev);
+       r = request_irq(dev->irq, i2c_dw_isr, IRQF_DISABLED, pdev->name, dev);
        if (r) {
                dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
                goto err_iounmap;