Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / drivers / i2c / busses / i2c-designware-core.c
index 7105511..df87992 100644 (file)
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/pm_runtime.h>
 #include <linux/delay.h>
 #include "i2c-designware-core.h"
 
+/*
+ * Registers offset
+ */
+#define DW_IC_CON              0x0
+#define DW_IC_TAR              0x4
+#define DW_IC_DATA_CMD         0x10
+#define DW_IC_SS_SCL_HCNT      0x14
+#define DW_IC_SS_SCL_LCNT      0x18
+#define DW_IC_FS_SCL_HCNT      0x1c
+#define DW_IC_FS_SCL_LCNT      0x20
+#define DW_IC_INTR_STAT                0x2c
+#define DW_IC_INTR_MASK                0x30
+#define DW_IC_RAW_INTR_STAT    0x34
+#define DW_IC_RX_TL            0x38
+#define DW_IC_TX_TL            0x3c
+#define DW_IC_CLR_INTR         0x40
+#define DW_IC_CLR_RX_UNDER     0x44
+#define DW_IC_CLR_RX_OVER      0x48
+#define DW_IC_CLR_TX_OVER      0x4c
+#define DW_IC_CLR_RD_REQ       0x50
+#define DW_IC_CLR_TX_ABRT      0x54
+#define DW_IC_CLR_RX_DONE      0x58
+#define DW_IC_CLR_ACTIVITY     0x5c
+#define DW_IC_CLR_STOP_DET     0x60
+#define DW_IC_CLR_START_DET    0x64
+#define DW_IC_CLR_GEN_CALL     0x68
+#define DW_IC_ENABLE           0x6c
+#define DW_IC_STATUS           0x70
+#define DW_IC_TXFLR            0x74
+#define DW_IC_RXFLR            0x78
+#define DW_IC_TX_ABRT_SOURCE   0x80
+#define DW_IC_COMP_PARAM_1     0xf4
+#define DW_IC_COMP_TYPE                0xfc
+#define DW_IC_COMP_TYPE_VALUE  0x44570140
+
+#define DW_IC_INTR_RX_UNDER    0x001
+#define DW_IC_INTR_RX_OVER     0x002
+#define DW_IC_INTR_RX_FULL     0x004
+#define DW_IC_INTR_TX_OVER     0x008
+#define DW_IC_INTR_TX_EMPTY    0x010
+#define DW_IC_INTR_RD_REQ      0x020
+#define DW_IC_INTR_TX_ABRT     0x040
+#define DW_IC_INTR_RX_DONE     0x080
+#define DW_IC_INTR_ACTIVITY    0x100
+#define DW_IC_INTR_STOP_DET    0x200
+#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
+
+/*
+ * status codes
+ */
+#define STATUS_IDLE                    0x0
+#define STATUS_WRITE_IN_PROGRESS       0x1
+#define STATUS_READ_IN_PROGRESS                0x2
+
+#define TIMEOUT                        20 /* ms */
+
+/*
+ * hardware abort codes from the DW_IC_TX_ABRT_SOURCE register
+ *
+ * only expected abort codes are listed here
+ * refer to the datasheet for the full list
+ */
+#define ABRT_7B_ADDR_NOACK     0
+#define ABRT_10ADDR1_NOACK     1
+#define ABRT_10ADDR2_NOACK     2
+#define ABRT_TXDATA_NOACK      3
+#define ABRT_GCALL_NOACK       4
+#define ABRT_GCALL_READ                5
+#define ABRT_SBYTE_ACKDET      7
+#define ABRT_SBYTE_NORSTRT     9
+#define ABRT_10B_RD_NORSTRT    10
+#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] =
                "slave address not acknowledged (7bit mode)",
@@ -143,7 +246,7 @@ static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
 int i2c_dw_init(struct dw_i2c_dev *dev)
 {
        u32 input_clock_khz;
-       u32 ic_con, hcnt, lcnt;
+       u32 hcnt, lcnt;
        u32 reg;
 
        input_clock_khz = dev->get_clk_rate_khz(dev);
@@ -199,9 +302,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
        dw_writel(dev, 0, DW_IC_RX_TL);
 
        /* configure the i2c master */
-       ic_con = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
-               DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
-       dw_writel(dev, ic_con, DW_IC_CON);
+       dw_writel(dev, dev->master_cfg , DW_IC_CON);
        return 0;
 }
 
@@ -401,6 +502,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
        dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);
 
        mutex_lock(&dev->lock);
+       pm_runtime_get_sync(dev->dev);
 
        INIT_COMPLETION(dev->cmd_complete);
        dev->msgs = msgs;
@@ -450,6 +552,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
        ret = -EIO;
 
 done:
+       pm_runtime_put(dev->dev);
        mutex_unlock(&dev->lock);
 
        return ret;
@@ -523,10 +626,16 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
 irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
 {
        struct dw_i2c_dev *dev = dev_id;
-       u32 stat;
+       u32 stat, enabled;
+
+       enabled = dw_readl(dev, DW_IC_ENABLE);
+       stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
+       dev_dbg(dev->dev, "%s:  %s enabled= 0x%x stat=0x%x\n", __func__,
+               dev->adapter.name, enabled, stat);
+       if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
+               return IRQ_NONE;
 
        stat = i2c_dw_read_clear_intrbits(dev);
-       dev_dbg(dev->dev, "%s: stat=0x%x\n", __func__, stat);
 
        if (stat & DW_IC_INTR_TX_ABRT) {
                dev->cmd_err |= DW_IC_ERR_TX_ABRT;
@@ -558,3 +667,39 @@ tx_aborted:
 
        return IRQ_HANDLED;
 }
+
+void i2c_dw_enable(struct dw_i2c_dev *dev)
+{
+       /* Enable the adapter */
+       dw_writel(dev, 1, DW_IC_ENABLE);
+}
+
+u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev)
+{
+       return dw_readl(dev, DW_IC_ENABLE);
+}
+
+void i2c_dw_disable(struct dw_i2c_dev *dev)
+{
+       /* Disable controller */
+       dw_writel(dev, 0, DW_IC_ENABLE);
+
+       /* Disable all interupts */
+       dw_writel(dev, 0, DW_IC_INTR_MASK);
+       dw_readl(dev, DW_IC_CLR_INTR);
+}
+
+void i2c_dw_clear_int(struct dw_i2c_dev *dev)
+{
+       dw_readl(dev, DW_IC_CLR_INTR);
+}
+
+void i2c_dw_disable_int(struct dw_i2c_dev *dev)
+{
+       dw_writel(dev, 0, DW_IC_INTR_MASK);
+}
+
+u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev)
+{
+       return dw_readl(dev, DW_IC_COMP_PARAM_1);
+}