From: "Chang, Rebecca Swee Fun" <rebecca.swee.fun.ch...@intel.com>

i2c-designware: Baytrail has 7 I2C controllers which can be PCI
and ACPI enumerated.

Signed-off-by: Chang, Rebecca Swee Fun <rebecca.swee.fun.ch...@intel.com>
---
 ...gnware-Add-support-for-Intel-Baytrail-I2C.patch |  961 ++++++++++++++++++++
 1 file changed, 961 insertions(+)
 create mode 100644 
meta/cfg/kernel-cache/features/valleyisland-io/0006-i2c-designware-Add-support-for-Intel-Baytrail-I2C.patch

diff --git 
a/meta/cfg/kernel-cache/features/valleyisland-io/0006-i2c-designware-Add-support-for-Intel-Baytrail-I2C.patch
 
b/meta/cfg/kernel-cache/features/valleyisland-io/0006-i2c-designware-Add-support-for-Intel-Baytrail-I2C.patch
new file mode 100644
index 0000000..668c049
--- /dev/null
+++ 
b/meta/cfg/kernel-cache/features/valleyisland-io/0006-i2c-designware-Add-support-for-Intel-Baytrail-I2C.patch
@@ -0,0 +1,961 @@
+i2c-designware: Add support for Intel Valley Island I2C
+
+Valley Island has 7 I2C controllers which can be PCI or ACPI enumerated.
+
+Signed-off-by: Chang, Rebecca Swee Fun <rebecca.swee.fun.ch...@intel.com>
+---
+ .../devicetree/bindings/i2c/i2c-designware.txt     |   15 ++
+ drivers/i2c/busses/i2c-designware-core.c           |  136 ++++++++----
+ drivers/i2c/busses/i2c-designware-core.h           |   15 +-
+ drivers/i2c/busses/i2c-designware-pcidrv.c         |  227 +++++++++++++++-----
+ drivers/i2c/busses/i2c-designware-platdrv.c        |  165 +++++++++-----
+ 5 files changed, 408 insertions(+), 150 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/i2c/i2c-designware.txt 
b/Documentation/devicetree/bindings/i2c/i2c-designware.txt
+index e42a2ee..fb2eac8 100644
+--- a/Documentation/devicetree/bindings/i2c/i2c-designware.txt
++++ b/Documentation/devicetree/bindings/i2c/i2c-designware.txt
+@@ -10,6 +10,10 @@ Recommended properties :
+
+  - clock-frequency : desired I2C bus clock frequency in Hz.
+
++Optional properties :
++ - sda-hold-time : If this property is present, the register SDA_HOLD will
++   be initialised with its value.
++
+ Example :
+
+       i2c@f0000 {
+@@ -20,3 +24,14 @@ Example :
+               interrupts = <11>;
+               clock-frequency = <400000>;
+       };
++
++      i2c@1120000 {
++              #address-cells = <1>;
++              #size-cells = <0>;
++              compatible = "snps,designware-i2c";
++              reg = <0x1120000 0x1000>;
++              interrupt-parent = <&ictl>;
++              interrupts = <12 1>;
++              clock-frequency = <400000>;
++              sda-hold-time = <0x64>;
++      };
+diff --git a/drivers/i2c/busses/i2c-designware-core.c 
b/drivers/i2c/busses/i2c-designware-core.c
+index f5258c2..e730640 100644
+--- a/drivers/i2c/busses/i2c-designware-core.c
++++ b/drivers/i2c/busses/i2c-designware-core.c
+@@ -67,7 +67,9 @@
+ #define DW_IC_STATUS          0x70
+ #define DW_IC_TXFLR           0x74
+ #define DW_IC_RXFLR           0x78
++#define DW_IC_SDA_HOLD                0x7c
+ #define DW_IC_TX_ABRT_SOURCE  0x80
++#define DW_IC_ENABLE_STATUS   0x9c
+ #define DW_IC_COMP_PARAM_1    0xf4
+ #define DW_IC_COMP_TYPE               0xfc
+ #define DW_IC_COMP_TYPE_VALUE 0x44570140
+@@ -248,6 +250,22 @@ static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, 
int offset)
+       return ((ic_clk * (tLOW + tf) + 5000) / 10000) - 1 + offset;
+ }
+
++static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable)
++{
++      int timeout = 100;
++
++      do {
++              dw_writel(dev, enable, DW_IC_ENABLE);
++              if ((dw_readl(dev, DW_IC_ENABLE_STATUS) & 1) == enable)
++                      return;
++
++              usleep_range(25, 250);
++      } while (timeout-- > 0);
++
++      dev_warn(dev->dev, "timeout in %sabling adapter\n",
++               enable ? "en" : "dis");
++}
++
+ /**
+  * i2c_dw_init() - initialize the designware i2c master hardware
+  * @dev: device private data
+@@ -278,38 +296,52 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
+       }
+
+       /* Disable the adapter */
+-      dw_writel(dev, 0, DW_IC_ENABLE);
++      __i2c_dw_enable(dev, false);
+
+       /* set standard and fast speed deviders for high/low periods */
+
+       /* Standard-mode */
+-      hcnt = i2c_dw_scl_hcnt(input_clock_khz,
+-                              40,     /* tHD;STA = tHIGH = 4.0 us */
+-                              3,      /* tf = 0.3 us */
+-                              0,      /* 0: DW default, 1: Ideal */
+-                              0);     /* No offset */
+-      lcnt = i2c_dw_scl_lcnt(input_clock_khz,
+-                              47,     /* tLOW = 4.7 us */
+-                              3,      /* tf = 0.3 us */
+-                              0);     /* No offset */
++      if (dev->ss_hcnt && dev->ss_lcnt) {
++              hcnt = dev->ss_hcnt;
++              lcnt = dev->ss_lcnt;
++      } else {
++              hcnt = i2c_dw_scl_hcnt(input_clock_khz,
++                                      40,     /* tHD;STA = tHIGH = 4.0 us */
++                                      3,      /* tf = 0.3 us */
++                                      0,      /* 0: DW default, 1: Ideal */
++                                      0);     /* No offset */
++              lcnt = i2c_dw_scl_lcnt(input_clock_khz,
++                                      47,     /* tLOW = 4.7 us */
++                                      3,      /* tf = 0.3 us */
++                                      0);     /* No offset */
++      }
+       dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT);
+       dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT);
+       dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
+
+       /* Fast-mode */
+-      hcnt = i2c_dw_scl_hcnt(input_clock_khz,
+-                              6,      /* tHD;STA = tHIGH = 0.6 us */
+-                              3,      /* tf = 0.3 us */
+-                              0,      /* 0: DW default, 1: Ideal */
+-                              0);     /* No offset */
+-      lcnt = i2c_dw_scl_lcnt(input_clock_khz,
+-                              13,     /* tLOW = 1.3 us */
+-                              3,      /* tf = 0.3 us */
+-                              0);     /* No offset */
++      if (dev->fs_hcnt && dev->fs_lcnt) {
++              hcnt = dev->fs_hcnt;
++              lcnt = dev->fs_lcnt;
++      } else {
++              hcnt = i2c_dw_scl_hcnt(input_clock_khz,
++                                      6,      /* tHD;STA = tHIGH = 0.6 us */
++                                      3,      /* tf = 0.3 us */
++                                      0,      /* 0: DW default, 1: Ideal */
++                                      0);     /* No offset */
++              lcnt = i2c_dw_scl_lcnt(input_clock_khz,
++                                      13,     /* tLOW = 1.3 us */
++                                      3,      /* tf = 0.3 us */
++                                      0);     /* No offset */
++      }
+       dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT);
+       dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT);
+       dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
+
++      /* Configure SDA Hold Time if required */
++      if (dev->sda_hold_time)
++              dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
++
+       /* Configure Tx/Rx FIFO threshold levels */
+       dw_writel(dev, dev->tx_fifo_depth - 1, DW_IC_TX_TL);
+       dw_writel(dev, 0, DW_IC_RX_TL);
+@@ -333,7 +365,7 @@ static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
+                       return -ETIMEDOUT;
+               }
+               timeout--;
+-              mdelay(1);
++              usleep_range(1000, 1000);
+       }
+
+       return 0;
+@@ -342,24 +374,31 @@ static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev 
*dev)
+ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
+ {
+       struct i2c_msg *msgs = dev->msgs;
+-      u32 ic_con;
++      u32 ic_con, ic_tar = 0;
+
+       /* Disable the adapter */
+-      dw_writel(dev, 0, DW_IC_ENABLE);
++      __i2c_dw_enable(dev, false);
+
+-      /* set the slave (target) address */
+-      dw_writel(dev, msgs[dev->msg_write_idx].addr, DW_IC_TAR);
+-
+-      /* if the slave address is ten bit address, enable 10BITADDR */
++      /* If the slave address is ten bit address, enable 10BITADDR.
++       * However, if I2C_DYNAMIC_TAR_UPDATE is set to 1,the 10 bit
++       * addressing mode control is resided in bit 12 of IC_TAR
++       * register instead of IC_CON register.
++       */
+       ic_con = dw_readl(dev, DW_IC_CON);
+-      if (msgs[dev->msg_write_idx].flags & I2C_M_TEN)
++
++      if (msgs[dev->msg_write_idx].flags & I2C_M_TEN){
+               ic_con |= DW_IC_CON_10BITADDR_MASTER;
+-      else
++              ic_tar = DW_IC_TAR_10BITADDR_MASTER;
++      } else
+               ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
++
+       dw_writel(dev, ic_con, DW_IC_CON);
+
++      /* set the slave (target) address */
++      dw_writel(dev, msgs[dev->msg_write_idx].addr | ic_tar, DW_IC_TAR);
++
+       /* Enable the adapter */
+-      dw_writel(dev, 1, DW_IC_ENABLE);
++      __i2c_dw_enable(dev, true);
+
+       /* Enable interrupts */
+       dw_writel(dev, DW_IC_INTR_DEFAULT_MASK, DW_IC_INTR_MASK);
+@@ -380,6 +419,7 @@ 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;
++      bool need_restart = false;
+
+       intr_mask = DW_IC_INTR_DEFAULT_MASK;
+
+@@ -407,17 +447,39 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
+                       /* new i2c_msg */
+                       buf = msgs[dev->msg_write_idx].buf;
+                       buf_len = msgs[dev->msg_write_idx].len;
++
++                      /* insert restart bit between msgs */
++                      if ((dev->master_cfg & DW_IC_CON_RESTART_EN) &&
++                                      (dev->msg_write_idx > 0))
++                              need_restart = true;
+               }
+
+               tx_limit = dev->tx_fifo_depth - dw_readl(dev, DW_IC_TXFLR);
+               rx_limit = dev->rx_fifo_depth - dw_readl(dev, DW_IC_RXFLR);
+
+               while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) {
++                      u32 cmd = 0;
++
++                      /*
++                       * If IC_EMPTYFIFO_HOLD_MASTER_EN is set we must
++                       * manually set the stop bit. However, it cannot be
++                       * detected from the registers so we set it always
++                       * when writing/reading the last byte.
++                       */
++                      if (dev->msg_write_idx == dev->msgs_num - 1 &&
++                                      buf_len == 1)
++                              cmd |= BIT(9);
++
++                      if (need_restart) {
++                              cmd |= BIT(10);
++                              need_restart = false;
++                      }
++
+                       if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {
+-                              dw_writel(dev, 0x100, DW_IC_DATA_CMD);
++                              dw_writel(dev, cmd | 0x100, DW_IC_DATA_CMD);
+                               rx_limit--;
+                       } else
+-                              dw_writel(dev, *buf++, DW_IC_DATA_CMD);
++                              dw_writel(dev, cmd | *buf++, DW_IC_DATA_CMD);
+                       tx_limit--; buf_len--;
+               }
+
+@@ -428,8 +490,9 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
+                       /* more bytes to be written */
+                       dev->status |= STATUS_WRITE_IN_PROGRESS;
+                       break;
+-              } else
++              } else {
+                       dev->status &= ~STATUS_WRITE_IN_PROGRESS;
++              }
+       }
+
+       /*
+@@ -553,7 +616,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg 
msgs[], int num)
+       /* no error */
+       if (likely(!dev->cmd_err)) {
+               /* Disable the adapter */
+-              dw_writel(dev, 0, DW_IC_ENABLE);
++              __i2c_dw_enable(dev, false);
+               ret = num;
+               goto done;
+       }
+@@ -566,7 +629,8 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg 
msgs[], int num)
+       ret = -EIO;
+
+ done:
+-      pm_runtime_put(dev->dev);
++      pm_runtime_mark_last_busy(dev->dev);
++      pm_runtime_put_autosuspend(dev->dev);
+       mutex_unlock(&dev->lock);
+
+       return ret;
+@@ -688,7 +752,7 @@ EXPORT_SYMBOL_GPL(i2c_dw_isr);
+ void i2c_dw_enable(struct dw_i2c_dev *dev)
+ {
+        /* Enable the adapter */
+-      dw_writel(dev, 1, DW_IC_ENABLE);
++      __i2c_dw_enable(dev, true);
+ }
+ EXPORT_SYMBOL_GPL(i2c_dw_enable);
+
+@@ -701,7 +765,7 @@ EXPORT_SYMBOL_GPL(i2c_dw_is_enabled);
+ void i2c_dw_disable(struct dw_i2c_dev *dev)
+ {
+       /* Disable controller */
+-      dw_writel(dev, 0, DW_IC_ENABLE);
++      __i2c_dw_enable(dev, false);
+
+       /* Disable all interupts */
+       dw_writel(dev, 0, DW_IC_INTR_MASK);
+diff --git a/drivers/i2c/busses/i2c-designware-core.h 
b/drivers/i2c/busses/i2c-designware-core.h
+index 9c1840e..ac21421 100644
+--- a/drivers/i2c/busses/i2c-designware-core.h
++++ b/drivers/i2c/busses/i2c-designware-core.h
+@@ -33,7 +33,7 @@
+ #define DW_IC_CON_10BITADDR_MASTER    0x10
+ #define DW_IC_CON_RESTART_EN          0x20
+ #define DW_IC_CON_SLAVE_DISABLE               0x40
+-
++#define DW_IC_TAR_10BITADDR_MASTER    0x1000
+
+ /**
+  * struct dw_i2c_dev - private i2c-designware data
+@@ -60,6 +60,14 @@
+  * @adapter: i2c subsystem adapter node
+  * @tx_fifo_depth: depth of the hardware tx fifo
+  * @rx_fifo_depth: depth of the hardware rx fifo
++ * @ss_hcnt: standard speed HCNT value
++ * @ss_lcnt: standard speed LCNT value
++ * @fs_hcnt: fast speed HCNT value
++ * @fs_lcnt: fast speed LCNT value
++ *
++ * HCNT and LCNT parameters can be used if the platform knows more accurate
++ * values than the one computed based only on the input clock frequency.
++ * Leave them to be %0 if not used.
+  */
+ struct dw_i2c_dev {
+       struct device           *dev;
+@@ -88,6 +96,11 @@ struct dw_i2c_dev {
+       u32                     master_cfg;
+       unsigned int            tx_fifo_depth;
+       unsigned int            rx_fifo_depth;
++      u32                     sda_hold_time;
++      u16                     ss_hcnt;
++      u16                     ss_lcnt;
++      u16                     fs_hcnt;
++      u16                     fs_lcnt;
+ };
+
+ #define ACCESS_SWAP           0x00000001
+diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c 
b/drivers/i2c/busses/i2c-designware-pcidrv.c
+index 6add851..a181e56 100644
+--- a/drivers/i2c/busses/i2c-designware-pcidrv.c
++++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
+@@ -41,8 +41,14 @@
+ #include <linux/pm_runtime.h>
+ #include "i2c-designware-core.h"
+
++#include <asm/processor.h>
++
+ #define DRIVER_NAME "i2c-designware-pci"
+
++static bool force_std_mode;
++module_param(force_std_mode, bool, 0);
++MODULE_PARM_DESC(force_std_mode, "Force standard mode (100 kHz)");
++
+ enum dw_pci_ctl_id_t {
+       moorestown_0,
+       moorestown_1,
+@@ -54,6 +60,14 @@ enum dw_pci_ctl_id_t {
+       medfield_3,
+       medfield_4,
+       medfield_5,
++
++      byt_0,
++      byt_1,
++      byt_2,
++      byt_3,
++      byt_4,
++      byt_5,
++      byt_6,
+ };
+
+ struct dw_pci_controller {
+@@ -62,12 +76,22 @@ struct dw_pci_controller {
+       u32 tx_fifo_depth;
+       u32 rx_fifo_depth;
+       u32 clk_khz;
++      u32 ss_hcnt;
++      u32 ss_lcnt;
++      u32 fs_hcnt;
++      u32 fs_lcnt;
++      u32 ss_sda;
++      u32 fs_sda;
+ };
+
+ #define INTEL_MID_STD_CFG  (DW_IC_CON_MASTER |                        \
+                               DW_IC_CON_SLAVE_DISABLE |       \
+                               DW_IC_CON_RESTART_EN)
+
++#define INTEL_BYT_STD_CFG  (DW_IC_CON_MASTER |                \
++                              DW_IC_CON_SLAVE_DISABLE |       \
++                              DW_IC_CON_RESTART_EN)
++
+ static struct  dw_pci_controller  dw_pci_controllers[] = {
+       [moorestown_0] = {
+               .bus_num     = 0,
+@@ -132,6 +156,97 @@ static struct  dw_pci_controller  dw_pci_controllers[] = {
+               .rx_fifo_depth = 32,
+               .clk_khz      = 25000,
+       },
++      [byt_0] = {
++              .bus_num     = 0,
++              .bus_cfg   = INTEL_BYT_STD_CFG | DW_IC_CON_SPEED_FAST,
++              .tx_fifo_depth = 32,
++              .rx_fifo_depth = 32,
++              .clk_khz      = 100000,
++              .ss_hcnt        = 0x200,
++              .ss_lcnt        = 0x200,
++              .fs_hcnt        = 0x55,
++              .fs_lcnt        = 0x99,
++              .ss_sda         = 0x6,
++              .fs_sda         = 0x6,
++      },
++      [byt_1] = {
++              .bus_num     = 1,
++              .bus_cfg   = INTEL_BYT_STD_CFG | DW_IC_CON_SPEED_FAST,
++              .tx_fifo_depth = 32,
++              .rx_fifo_depth = 32,
++              .clk_khz      = 100000,
++              .ss_hcnt        = 0x200,
++              .ss_lcnt        = 0x200,
++              .fs_hcnt        = 0x55,
++              .fs_lcnt        = 0x99,
++              .ss_sda         = 0x6,
++              .fs_sda         = 0x6,
++      },
++      [byt_2] = {
++              .bus_num     = 2,
++              .bus_cfg   = INTEL_BYT_STD_CFG | DW_IC_CON_SPEED_FAST,
++              .tx_fifo_depth = 32,
++              .rx_fifo_depth = 32,
++              .clk_khz      = 100000,
++              .ss_hcnt        = 0x200,
++              .ss_lcnt        = 0x200,
++              .fs_hcnt        = 0x55,
++              .fs_lcnt        = 0x99,
++              .ss_sda         = 0x6,
++              .fs_sda         = 0x6,
++      },
++      [byt_3] = {
++              .bus_num     = 3,
++              .bus_cfg   = INTEL_BYT_STD_CFG | DW_IC_CON_SPEED_FAST,
++              .tx_fifo_depth = 32,
++              .rx_fifo_depth = 32,
++              .clk_khz      = 100000,
++              .ss_hcnt        = 0x200,
++              .ss_lcnt        = 0x200,
++              .fs_hcnt        = 0x55,
++              .fs_lcnt        = 0x99,
++              .ss_sda         = 0x6,
++              .fs_sda         = 0x6,
++      },
++      [byt_4] = {
++              .bus_num     = 4,
++              .bus_cfg   = INTEL_BYT_STD_CFG | DW_IC_CON_SPEED_FAST,
++              .tx_fifo_depth = 32,
++              .rx_fifo_depth = 32,
++              .clk_khz      = 100000,
++              .ss_hcnt        = 0x200,
++              .ss_lcnt        = 0x200,
++              .fs_hcnt        = 0x55,
++              .fs_lcnt        = 0x99,
++              .ss_sda         = 0x6,
++              .fs_sda         = 0x6,
++      },
++      [byt_5] = {
++              .bus_num     = 5,
++              .bus_cfg   = INTEL_BYT_STD_CFG | DW_IC_CON_SPEED_FAST,
++              .tx_fifo_depth = 32,
++              .rx_fifo_depth = 32,
++              .clk_khz      = 100000,
++              .ss_hcnt        = 0x200,
++              .ss_lcnt        = 0x200,
++              .fs_hcnt        = 0x55,
++              .fs_lcnt        = 0x99,
++              .ss_sda         = 0x6,
++              .fs_sda         = 0x6,
++      },
++      [byt_6] = {
++              .bus_num     = 6,
++              .bus_cfg   = INTEL_BYT_STD_CFG | DW_IC_CON_SPEED_FAST,
++              .tx_fifo_depth = 32,
++              .rx_fifo_depth = 32,
++              .clk_khz      = 100000,
++              .ss_hcnt        = 0x200,
++              .ss_lcnt        = 0x200,
++              .fs_hcnt        = 0x55,
++              .fs_lcnt        = 0x99,
++              .ss_sda         = 0x6,
++              .fs_sda         = 0x6,
++      },
+ };
+ static struct i2c_algorithm i2c_dw_algo = {
+       .master_xfer    = i2c_dw_xfer,
+@@ -208,83 +323,85 @@ static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev 
*dev)
+ }
+
+ static int i2c_dw_pci_probe(struct pci_dev *pdev,
+-const struct pci_device_id *id)
++                          const struct pci_device_id *id)
+ {
+       struct dw_i2c_dev *dev;
+       struct i2c_adapter *adap;
+-      unsigned long start, len;
+-      void __iomem *base;
+       int r;
++      u32 mode;
+       struct  dw_pci_controller *controller;
+
+       if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) {
+-              printk(KERN_ERR "dw_i2c_pci_probe: invalid driver data %ld\n",
++              dev_err(&pdev->dev, "%s: invalid driver data %ld\n", __func__,
+                       id->driver_data);
+               return -EINVAL;
+       }
+
+       controller = &dw_pci_controllers[id->driver_data];
+
+-      r = pci_enable_device(pdev);
++      r = pcim_enable_device(pdev);
+       if (r) {
+               dev_err(&pdev->dev, "Failed to enable I2C PCI device (%d)\n",
+                       r);
+-              goto exit;
+-      }
+-
+-      /* Determine the address of the I2C area */
+-      start = pci_resource_start(pdev, 0);
+-      len = pci_resource_len(pdev, 0);
+-      if (!start || len == 0) {
+-              dev_err(&pdev->dev, "base address not set\n");
+-              r = -ENODEV;
+-              goto exit;
++              return r;
+       }
+
+-      r = pci_request_region(pdev, 0, DRIVER_NAME);
++      r = pcim_iomap_regions(pdev, 1 << 0, pci_name(pdev));
+       if (r) {
+-              dev_err(&pdev->dev, "failed to request I2C region "
+-                      "0x%lx-0x%lx\n", start,
+-                      (unsigned long)pci_resource_end(pdev, 0));
+-              goto exit;
+-      }
+-
+-      base = ioremap_nocache(start, len);
+-      if (!base) {
+               dev_err(&pdev->dev, "I/O memory remapping failed\n");
+-              r = -ENOMEM;
+-              goto err_release_region;
++              return r;
+       }
+
+-
+-      dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL);
+-      if (!dev) {
+-              r = -ENOMEM;
+-              goto err_release_region;
+-      }
++      dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL);
++      if (!dev)
++              return -ENOMEM;
+
+       init_completion(&dev->cmd_complete);
+       mutex_init(&dev->lock);
+       dev->clk = NULL;
+       dev->controller = controller;
+       dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
+-      dev->base = base;
+-      dev->dev = get_device(&pdev->dev);
++      dev->base = pcim_iomap_table(pdev)[0];
++      dev->dev = &pdev->dev;
+       dev->functionality =
+               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;
+-      dev->master_cfg =  controller->bus_cfg;
+
++      /*
++       * BYT A0: Override base clock, hcnt and lcnt default settings
++       */
++      if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && boot_cpu_data.x86 
== 0x6 &&
++              boot_cpu_data.x86_model == 0x37 && boot_cpu_data.x86_mask < 2) {
++              controller->clk_khz = 133000;
++              controller->ss_hcnt = 0x28f;
++              controller->ss_lcnt = 0x2ba;
++              controller->fs_hcnt = 0x71;
++              controller->fs_lcnt = 0xce;
++      }
++
++      dev->ss_hcnt = controller->ss_hcnt;
++      dev->ss_lcnt = controller->ss_lcnt;
++      dev->fs_hcnt = controller->fs_hcnt;
++      dev->fs_lcnt = controller->fs_lcnt;
++      mode = controller->bus_cfg & (DW_IC_CON_SPEED_STD | 
DW_IC_CON_SPEED_FAST);
++      if (force_std_mode && !(mode & DW_IC_CON_SPEED_STD)){
++              controller->bus_cfg &= ~mode;
++              controller->bus_cfg |= DW_IC_CON_SPEED_STD;
++      }
++
++      dev->master_cfg =  controller->bus_cfg;
++      dev->sda_hold_time = (dev->master_cfg & DW_IC_CON_SPEED_FAST) ? 
controller->fs_sda : controller->ss_sda;
+       pci_set_drvdata(pdev, dev);
+
+       dev->tx_fifo_depth = controller->tx_fifo_depth;
+       dev->rx_fifo_depth = controller->rx_fifo_depth;
+       r = i2c_dw_init(dev);
+       if (r)
+-              goto err_iounmap;
++              return r;
+
+       adap = &dev->adapter;
+       i2c_set_adapdata(adap, dev);
+@@ -296,10 +413,11 @@ const struct pci_device_id *id)
+       snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci-%d",
+               adap->nr);
+
+-      r = request_irq(pdev->irq, i2c_dw_isr, IRQF_SHARED, adap->name, dev);
++      r = devm_request_irq(&pdev->dev, pdev->irq, i2c_dw_isr, IRQF_SHARED,
++                      adap->name, dev);
+       if (r) {
+               dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
+-              goto err_iounmap;
++              return r;
+       }
+
+       i2c_dw_disable_int(dev);
+@@ -307,25 +425,15 @@ const struct pci_device_id *id)
+       r = i2c_add_numbered_adapter(adap);
+       if (r) {
+               dev_err(&pdev->dev, "failure adding adapter\n");
+-              goto err_free_irq;
++              return r;
+       }
+
+-      pm_runtime_put_noidle(&pdev->dev);
+-      pm_runtime_allow(&pdev->dev);
++      /* Increase reference counter */
++      get_device(&pdev->dev);
+
+-      return 0;
++      pm_runtime_forbid(&pdev->dev);
+
+-err_free_irq:
+-      free_irq(pdev->irq, dev);
+-err_iounmap:
+-      iounmap(dev->base);
+-      pci_set_drvdata(pdev, NULL);
+-      put_device(&pdev->dev);
+-      kfree(dev);
+-err_release_region:
+-      pci_release_region(pdev, 0);
+-exit:
+-      return r;
++      return 0;
+ }
+
+ static void i2c_dw_pci_remove(struct pci_dev *pdev)
+@@ -336,13 +444,8 @@ static void i2c_dw_pci_remove(struct pci_dev *pdev)
+       pm_runtime_forbid(&pdev->dev);
+       pm_runtime_get_noresume(&pdev->dev);
+
+-      pci_set_drvdata(pdev, NULL);
+       i2c_del_adapter(&dev->adapter);
+       put_device(&pdev->dev);
+-
+-      free_irq(dev->irq, dev);
+-      kfree(dev);
+-      pci_release_region(pdev, 0);
+ }
+
+ /* work with hotplug and coldplug */
+@@ -360,6 +463,14 @@ static DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = {
+       { PCI_VDEVICE(INTEL, 0x082C), medfield_0 },
+       { PCI_VDEVICE(INTEL, 0x082D), medfield_1 },
+       { PCI_VDEVICE(INTEL, 0x082E), medfield_2 },
++      /* BYT */
++      { PCI_VDEVICE(INTEL, 0x0F41), byt_0 },
++      { PCI_VDEVICE(INTEL, 0x0F42), byt_1 },
++      { PCI_VDEVICE(INTEL, 0x0F43), byt_2 },
++      { PCI_VDEVICE(INTEL, 0x0F44), byt_3 },
++      { PCI_VDEVICE(INTEL, 0x0F45), byt_4 },
++      { PCI_VDEVICE(INTEL, 0x0F46), byt_5 },
++      { PCI_VDEVICE(INTEL, 0x0F47), byt_6 },
+       { 0,}
+ };
+ MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids);
+diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c 
b/drivers/i2c/busses/i2c-designware-platdrv.c
+index 343357a..888e107 100644
+--- a/drivers/i2c/busses/i2c-designware-platdrv.c
++++ b/drivers/i2c/busses/i2c-designware-platdrv.c
+@@ -34,13 +34,20 @@
+ #include <linux/sched.h>
+ #include <linux/err.h>
+ #include <linux/interrupt.h>
++#include <linux/of.h>
+ #include <linux/of_i2c.h>
+ #include <linux/platform_device.h>
+ #include <linux/pm.h>
++#include <linux/pm_runtime.h>
+ #include <linux/io.h>
+ #include <linux/slab.h>
++#include <linux/acpi.h>
+ #include "i2c-designware-core.h"
+
++static bool force_std_mode;
++module_param(force_std_mode, bool, 0);
++MODULE_PARM_DESC(force_std_mode, "Force standard mode (100 kHz)");
++
+ static struct i2c_algorithm i2c_dw_algo = {
+       .master_xfer    = i2c_dw_xfer,
+       .functionality  = i2c_dw_func,
+@@ -50,11 +57,75 @@ static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
+       return clk_get_rate(dev->clk)/1000;
+ }
+
++#ifdef CONFIG_ACPI
++static void dw_i2c_acpi_get_cnt(struct dw_i2c_dev *dev, acpi_string name,
++                              u16 *hcnt, u16 *lcnt, u32 *sda)
++{
++      struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
++      acpi_handle handle = ACPI_HANDLE(dev->dev);
++      union acpi_object *obj;
++
++      if (ACPI_FAILURE(acpi_evaluate_object(handle, name, NULL, &buf)))
++              return;
++
++      obj = (union acpi_object *)buf.pointer;
++      if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 3) {
++              const union acpi_object *objs = obj->package.elements;
++
++              *hcnt = (u16)objs[0].integer.value;
++              *lcnt = (u16)objs[1].integer.value;
++              *sda = (u32)objs[2].integer.value;
++      }
++
++      kfree(buf.pointer);
++}
++
++static int dw_i2c_acpi_configure(struct platform_device *pdev)
++{
++      struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
++      u32 ss_sda, fs_sda;
++
++      if (!ACPI_HANDLE(&pdev->dev))
++              return -ENODEV;
++
++      dev->adapter.nr = -1;
++      dev->tx_fifo_depth = 32;
++      dev->rx_fifo_depth = 32;
++
++      /*
++       * Try to get platform specific *CNT and SDA hold values from BIOS
++       * if provided. Otherwise use the defaults.
++       */
++      ss_sda = fs_sda = 9;
++      dw_i2c_acpi_get_cnt(dev, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt, &ss_sda);
++      dw_i2c_acpi_get_cnt(dev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt, &fs_sda);
++
++      if (dev->master_cfg & DW_IC_CON_SPEED_FAST)
++              dev->sda_hold_time = fs_sda;
++      else
++              dev->sda_hold_time = ss_sda;
++      return 0;
++}
++
++static const struct acpi_device_id dw_i2c_acpi_match[] = {
++      { "80860F41", 0 },
++      { "INT33C2", 0 },
++      { "INT33C3", 0 },
++      { }
++};
++MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
++#else
++static inline int dw_i2c_acpi_configure(struct platform_device *pdev)
++{
++      return -ENODEV;
++}
++#endif
++
+ static int dw_i2c_probe(struct platform_device *pdev)
+ {
+       struct dw_i2c_dev *dev;
+       struct i2c_adapter *adap;
+-      struct resource *mem, *ioarea;
++      struct resource *mem;
+       int irq, r;
+
+       /* NOTE: driver uses the static register mapping */
+@@ -70,34 +141,33 @@ static int dw_i2c_probe(struct platform_device *pdev)
+               return irq; /* -ENXIO */
+       }
+
+-      ioarea = request_mem_region(mem->start, resource_size(mem),
+-                      pdev->name);
+-      if (!ioarea) {
++      dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL);
++      if (!dev)
++              return -ENOMEM;
++
++      dev->base = devm_request_and_ioremap(&pdev->dev, mem);
++      if (!dev->base) {
+               dev_err(&pdev->dev, "I2C region already claimed\n");
+               return -EBUSY;
+       }
+
+-      dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL);
+-      if (!dev) {
+-              r = -ENOMEM;
+-              goto err_release_region;
+-      }
+-
+       init_completion(&dev->cmd_complete);
+       mutex_init(&dev->lock);
+-      dev->dev = get_device(&pdev->dev);
++      dev->dev = &pdev->dev;
+       dev->irq = irq;
+       platform_set_drvdata(pdev, dev);
+
+-      dev->clk = clk_get(&pdev->dev, NULL);
++      dev->clk = devm_clk_get(&pdev->dev, NULL);
+       dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
+
+-      if (IS_ERR(dev->clk)) {
+-              r = -ENODEV;
+-              goto err_free_mem;
+-      }
++      if (IS_ERR(dev->clk))
++              return PTR_ERR(dev->clk);
+       clk_prepare_enable(dev->clk);
+
++      if (pdev->dev.of_node)
++              of_property_read_u32(pdev->dev.of_node, "sda-hold-time",
++                                              &dev->sda_hold_time);
++
+       dev->functionality =
+               I2C_FUNC_I2C |
+               I2C_FUNC_10BIT_ADDR |
+@@ -106,29 +176,29 @@ static int dw_i2c_probe(struct platform_device *pdev)
+               I2C_FUNC_SMBUS_WORD_DATA |
+               I2C_FUNC_SMBUS_I2C_BLOCK;
+       dev->master_cfg =  DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
+-              DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
++              DW_IC_CON_RESTART_EN;
+
+-      dev->base = ioremap(mem->start, resource_size(mem));
+-      if (dev->base == NULL) {
+-              dev_err(&pdev->dev, "failure mapping io resources\n");
+-              r = -EBUSY;
+-              goto err_unuse_clocks;
+-      }
+-      {
++      dev->master_cfg |= (force_std_mode ? DW_IC_CON_SPEED_STD : 
DW_IC_CON_SPEED_FAST);
++
++      /* Try first if we can configure the device from ACPI */
++      r = dw_i2c_acpi_configure(pdev);
++      if (r) {
+               u32 param1 = i2c_dw_read_comp_param(dev);
+
+               dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1;
+               dev->rx_fifo_depth = ((param1 >> 8)  & 0xff) + 1;
++              dev->adapter.nr = pdev->id;
+       }
+       r = i2c_dw_init(dev);
+       if (r)
+-              goto err_iounmap;
++              return r;
+
+       i2c_dw_disable_int(dev);
+-      r = request_irq(dev->irq, i2c_dw_isr, IRQF_DISABLED, pdev->name, dev);
++      r = devm_request_irq(&pdev->dev, dev->irq, i2c_dw_isr, IRQF_SHARED,
++                      pdev->name, dev);
+       if (r) {
+               dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
+-              goto err_iounmap;
++              return r;
+       }
+
+       adap = &dev->adapter;
+@@ -140,54 +210,38 @@ static int dw_i2c_probe(struct platform_device *pdev)
+       adap->algo = &i2c_dw_algo;
+       adap->dev.parent = &pdev->dev;
+       adap->dev.of_node = pdev->dev.of_node;
++      ACPI_HANDLE_SET(&adap->dev, ACPI_HANDLE(&pdev->dev));
+
+-      adap->nr = pdev->id;
+       r = i2c_add_numbered_adapter(adap);
+       if (r) {
+               dev_err(&pdev->dev, "failure adding adapter\n");
+-              goto err_free_irq;
++              return r;
+       }
+       of_i2c_register_devices(adap);
++      acpi_i2c_register_devices(adap);
+
+-      return 0;
++      /* Increase reference counter */
++      get_device(&pdev->dev);
+
+-err_free_irq:
+-      free_irq(dev->irq, dev);
+-err_iounmap:
+-      iounmap(dev->base);
+-err_unuse_clocks:
+-      clk_disable_unprepare(dev->clk);
+-      clk_put(dev->clk);
+-      dev->clk = NULL;
+-err_free_mem:
+-      platform_set_drvdata(pdev, NULL);
+-      put_device(&pdev->dev);
+-      kfree(dev);
+-err_release_region:
+-      release_mem_region(mem->start, resource_size(mem));
++      pm_runtime_forbid(&pdev->dev);
+
+-      return r;
++      return 0;
+ }
+
+ static int dw_i2c_remove(struct platform_device *pdev)
+ {
+       struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
+-      struct resource *mem;
+
+-      platform_set_drvdata(pdev, NULL);
++      pm_runtime_get_sync(&pdev->dev);
++
+       i2c_del_adapter(&dev->adapter);
+       put_device(&pdev->dev);
+
+-      clk_disable_unprepare(dev->clk);
+-      clk_put(dev->clk);
+-      dev->clk = NULL;
+-
+       i2c_dw_disable(dev);
+-      free_irq(dev->irq, dev);
+-      kfree(dev);
+
+-      mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-      release_mem_region(mem->start, resource_size(mem));
++      pm_runtime_put(&pdev->dev);
++      pm_runtime_disable(&pdev->dev);
++
+       return 0;
+ }
+
+@@ -233,6 +287,7 @@ static struct platform_driver dw_i2c_driver = {
+               .name   = "i2c_designware",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(dw_i2c_of_match),
++              .acpi_match_table = ACPI_PTR(dw_i2c_acpi_match),
+               .pm     = &dw_i2c_dev_pm_ops,
+       },
+ };
+--
+1.7.10.4
+
-- 
1.7.10.4

_______________________________________________
linux-yocto mailing list
linux-yocto@yoctoproject.org
https://lists.yoctoproject.org/listinfo/linux-yocto

Reply via email to