Port I2C driver from current driver to k30
authorBin Yang <bin.yang@intel.com>
Mon, 21 Nov 2011 16:36:02 +0000 (16:36 +0000)
committerGross, Mark <mark.gross@intel.com>
Thu, 24 Nov 2011 06:24:07 +0000 (22:24 -0800)
BZ: 15206

1. some differences of runtime PM implementation, including
auto runtime suspend.
2. one bug fixing in ISR.
3. add dump function for debugging.
4. correct clock setting.

Change-Id: Ib3d82e91333aa33bd319d5fed88389b15bd698fc
Signed-off-by: Bin Yang <bin.yang@intel.com>
Reviewed-on: http://android.intel.com:8080/25164
Reviewed-by: buildbot <buildbot@intel.com>
Reviewed-by: Gross, Mark <mark.gross@intel.com>
Tested-by: Gross, Mark <mark.gross@intel.com>
drivers/i2c/busses/i2c-designware-core.c
drivers/i2c/busses/i2c-designware-core.h
drivers/i2c/busses/i2c-designware-pcidrv.c

index df87992..0480177 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/io.h>
 #include <linux/pm_runtime.h>
 #include <linux/delay.h>
+#include <linux/semaphore.h>
 #include "i2c-designware-core.h"
 
 /*
 
 #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 */
 
 /*
@@ -180,6 +174,48 @@ void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset)
        writel(b, dev->base + offset);
 }
 
+static void i2c_dw_dump(struct dw_i2c_dev *dev)
+{
+       u32 value;
+
+       dev_err(dev->dev, "===== REGISTER DUMP (i2c) =====\n");
+       value = dw_readl(dev, DW_IC_CON);
+       dev_err(dev->dev, "DW_IC_CON:               0x%x\n", value);
+       value = dw_readl(dev, DW_IC_TAR);
+       dev_err(dev->dev, "DW_IC_TAR:               0x%x\n", value);
+       value = dw_readl(dev, DW_IC_SS_SCL_HCNT);
+       dev_err(dev->dev, "DW_IC_SS_SCL_HCNT:       0x%x\n", value);
+       value = dw_readl(dev, DW_IC_SS_SCL_LCNT);
+       dev_err(dev->dev, "DW_IC_SS_SCL_LCNT:       0x%x\n", value);
+       value = dw_readl(dev, DW_IC_FS_SCL_HCNT);
+       dev_err(dev->dev, "DW_IC_FS_SCL_HCNT:       0x%x\n", value);
+       value = dw_readl(dev, DW_IC_FS_SCL_LCNT);
+       dev_err(dev->dev, "DW_IC_FS_SCL_LCNT:       0x%x\n", value);
+       value = dw_readl(dev, DW_IC_INTR_STAT);
+       dev_err(dev->dev, "DW_IC_INTR_STAT:         0x%x\n", value);
+       value = dw_readl(dev, DW_IC_INTR_MASK);
+       dev_err(dev->dev, "DW_IC_INTR_MASK:         0x%x\n", value);
+       value = dw_readl(dev, DW_IC_RAW_INTR_STAT);
+       dev_err(dev->dev, "DW_IC_RAW_INTR_STAT:     0x%x\n", value);
+       value = dw_readl(dev, DW_IC_RX_TL);
+       dev_err(dev->dev, "DW_IC_RX_TL:             0x%x\n", value);
+       value = dw_readl(dev, DW_IC_TX_TL);
+       dev_err(dev->dev, "DW_IC_TX_TL:             0x%x\n", value);
+       value = dw_readl(dev, DW_IC_ENABLE);
+       dev_err(dev->dev, "DW_IC_ENABLE:            0x%x\n", value);
+       value = dw_readl(dev, DW_IC_STATUS);
+       dev_err(dev->dev, "DW_IC_STATUS:            0x%x\n", value);
+       value = dw_readl(dev, DW_IC_TXFLR);
+       dev_err(dev->dev, "DW_IC_TXFLR:             0x%x\n", value);
+       value = dw_readl(dev, DW_IC_RXFLR);
+       dev_err(dev->dev, "DW_IC_RXFLR:             0x%x\n", value);
+       value = dw_readl(dev, DW_IC_TX_ABRT_SOURCE);
+       dev_err(dev->dev, "DW_IC_TX_ABRT_SOURCE:    0x%x\n", value);
+       value = dw_readl(dev, DW_IC_DATA_CMD);
+       dev_err(dev->dev, "DW_IC_DATA_CMD:          0x%x\n", value);
+       dev_err(dev->dev, "===============================\n");
+}
+
 static u32
 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
 {
@@ -366,9 +402,11 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
        u32 addr = msgs[dev->msg_write_idx].addr;
        u32 buf_len = dev->tx_buf_len;
        u8 *buf = dev->tx_buf;
+       unsigned long flags;
 
        intr_mask = DW_IC_INTR_DEFAULT_MASK;
 
+       raw_local_irq_save(flags);
        for (; dev->msg_write_idx < dev->msgs_num; dev->msg_write_idx++) {
                /*
                 * if target address has changed, we need to
@@ -417,6 +455,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
                } else
                        dev->status &= ~STATUS_WRITE_IN_PROGRESS;
        }
+       raw_local_irq_restore(flags);
 
        /*
         * If i2c_msg index search is completed, we don't need TX_EMPTY
@@ -501,7 +540,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);
+       down(&dev->lock);
        pm_runtime_get_sync(dev->dev);
 
        INIT_COMPLETION(dev->cmd_complete);
@@ -522,9 +561,10 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
        i2c_dw_xfer_init(dev);
 
        /* wait for tx to complete */
-       ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ);
+       ret = wait_for_completion_timeout(&dev->cmd_complete, HZ);
        if (ret == 0) {
-               dev_err(dev->dev, "controller timed out\n");
+               dev_WARN(dev->dev, "controller timed out\n");
+               i2c_dw_dump(dev);
                i2c_dw_init(dev);
                ret = -ETIMEDOUT;
                goto done;
@@ -552,8 +592,9 @@ 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);
+       pm_runtime_mark_last_busy(dev->dev);
+       pm_runtime_put_autosuspend(dev->dev);
+       up(&dev->lock);
 
        return ret;
 }
index 4a75888..119fad6 100644 (file)
 #define DW_IC_CON_RESTART_EN           0x20
 #define DW_IC_CON_SLAVE_DISABLE                0x40
 
+/*
+ * status codes
+ */
+#define STATUS_POWERON                 0x0
+#define STATUS_IDLE                    STATUS_POWERON
+#define STATUS_WRITE_IN_PROGRESS       0x1
+#define STATUS_READ_IN_PROGRESS                0x2
+
 
 /**
  * struct dw_i2c_dev - private i2c-designware data
@@ -65,7 +73,7 @@ struct dw_i2c_dev {
        struct device           *dev;
        void __iomem            *base;
        struct completion       cmd_complete;
-       struct mutex            lock;
+       struct semaphore        lock;
        struct clk              *clk;
        u32                     (*get_clk_rate_khz) (struct dw_i2c_dev *dev);
        struct dw_pci_controller *controller;
index 837dd22..142be53 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/pm_runtime.h>
+#include <linux/semaphore.h>
 #include "i2c-designware-core.h"
 
 #define DRIVER_NAME "i2c-designware-pci"
@@ -95,42 +96,42 @@ static struct  dw_pci_controller  dw_pci_controllers[] = {
                .bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
                .tx_fifo_depth = 32,
                .rx_fifo_depth = 32,
-               .clk_khz      = 25000,
+               .clk_khz      = 17000,
        },
        [medfield_1] = {
                .bus_num     = 1,
-               .bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+               .bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_STD,
                .tx_fifo_depth = 32,
                .rx_fifo_depth = 32,
-               .clk_khz      = 25000,
+               .clk_khz      = 20500,
        },
        [medfield_2] = {
                .bus_num     = 2,
                .bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
                .tx_fifo_depth = 32,
                .rx_fifo_depth = 32,
-               .clk_khz      = 25000,
+               .clk_khz      = 17000,
        },
        [medfield_3] = {
                .bus_num     = 3,
                .bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_STD,
                .tx_fifo_depth = 32,
                .rx_fifo_depth = 32,
-               .clk_khz      = 25000,
+               .clk_khz      = 17000,
        },
        [medfield_4] = {
                .bus_num     = 4,
                .bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
                .tx_fifo_depth = 32,
                .rx_fifo_depth = 32,
-               .clk_khz      = 25000,
+               .clk_khz      = 17000,
        },
        [medfield_5] = {
                .bus_num     = 5,
                .bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
                .tx_fifo_depth = 32,
                .rx_fifo_depth = 32,
-               .clk_khz      = 25000,
+               .clk_khz      = 17000,
        },
 };
 static struct i2c_algorithm i2c_dw_algo = {
@@ -142,9 +143,23 @@ static int i2c_dw_pci_suspend(struct device *dev)
 {
        struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
        struct dw_i2c_dev *i2c = pci_get_drvdata(pdev);
-       int err;
 
+       dev_dbg(dev, "suspend called\n");
+       if (down_trylock(&i2c->lock))
+               return -EBUSY;
+       i2c_dw_disable(i2c);
+       i2c->status &= ~STATUS_POWERON;
+
+       return 0;
+}
+
+static int i2c_dw_pci_runtime_suspend(struct device *dev)
+{
+       struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+       struct dw_i2c_dev *i2c = pci_get_drvdata(pdev);
+       int err;
 
+       dev_dbg(dev, "runtime suspend called\n");
        i2c_dw_disable(i2c);
 
        err = pci_save_state(pdev);
@@ -166,40 +181,39 @@ static int i2c_dw_pci_resume(struct device *dev)
 {
        struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
        struct dw_i2c_dev *i2c = pci_get_drvdata(pdev);
-       int err;
-       u32 enabled;
 
-       enabled = i2c_dw_is_enabled(i2c);
-       if (enabled)
-               return 0;
+       dev_dbg(dev, "resume called\n");
+       i2c_dw_init(i2c);
+       i2c->status |= STATUS_POWERON;
+       up(&i2c->lock);
+
+       return 0;
+}
 
+static int i2c_dw_pci_runtime_resume(struct device *dev)
+{
+       struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+       struct dw_i2c_dev *i2c = pci_get_drvdata(pdev);
+       int err;
+
+       dev_dbg(dev, "runtime resume called\n");
        err = pci_set_power_state(pdev, PCI_D0);
        if (err) {
                dev_err(&pdev->dev, "pci_set_power_state() failed\n");
                return err;
        }
-
        pci_restore_state(pdev);
-
        i2c_dw_init(i2c);
-       return 0;
-}
-
-static int i2c_dw_pci_runtime_idle(struct device *dev)
-{
-       int err = pm_schedule_suspend(dev, 500);
-       dev_dbg(dev, "runtime_idle called\n");
 
-       if (err != 0)
-               return 0;
-       return -EBUSY;
+       return 0;
 }
 
 static const struct dev_pm_ops i2c_dw_pm_ops = {
-       .resume         = i2c_dw_pci_resume,
-       .suspend        = i2c_dw_pci_suspend,
-       SET_RUNTIME_PM_OPS(i2c_dw_pci_suspend, i2c_dw_pci_resume,
-                          i2c_dw_pci_runtime_idle)
+       SET_SYSTEM_SLEEP_PM_OPS(i2c_dw_pci_suspend,
+                               i2c_dw_pci_resume)
+       SET_RUNTIME_PM_OPS(i2c_dw_pci_runtime_suspend,
+                          i2c_dw_pci_runtime_resume,
+                          NULL)
 };
 
 static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
@@ -264,7 +278,8 @@ const struct pci_device_id *id)
        }
 
        init_completion(&dev->cmd_complete);
-       mutex_init(&dev->lock);
+       sema_init(&dev->lock, 1);
+       dev->status = STATUS_IDLE;
        dev->clk = NULL;
        dev->controller = controller;
        dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
@@ -312,6 +327,8 @@ const struct pci_device_id *id)
 
        pm_runtime_put_noidle(&pdev->dev);
        pm_runtime_allow(&pdev->dev);
+       pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_set_autosuspend_delay(&pdev->dev, 5);
 
        return 0;