[linux-yocto] [PATCH 1/1] i2c: allow Designware I2C to be probed before SMBus for Baytrail
chong.yi.chai at intel.com
chong.yi.chai at intel.com
Wed Mar 30 20:12:15 PDT 2016
From: "Chai, Chong Yi" <chong.yi.chai at intel.com>
---
features/soc/baytrail/baytrail.scc | 10 +
...esignware-I2C-to-be-probed-before-SMBus-f.patch | 54 ++++
...i2c-designware-Fix-checkpatch.pl-warnings.patch | 51 ++++
...i2c-designware-add-i2c-high-speed-support.patch | 234 +++++++++++++++
...are-add-per-channel-speed-parameter-and-f.patch | 331 +++++++++++++++++++++
.../i2c-designware-cleanup-__i2c_dw_enable.patch | 54 ++++
...2c-designware-cleanup-irq-handler-setting.patch | 53 ++++
...are-explicitly-abort-running-operation-on.patch | 70 +++++
.../i2c-designware-improve-FIFO-performance.patch | 137 +++++++++
...are-use-hardware-provided-Rx-Tx-FIFO-dept.patch | 220 ++++++++++++++
...nware-use-symbolic-names-for-command-bits.patch | 50 ++++
11 files changed, 1264 insertions(+)
create mode 100644 features/soc/baytrail/i2c-allow-Designware-I2C-to-be-probed-before-SMBus-f.patch
create mode 100644 features/soc/baytrail/i2c-designware-Fix-checkpatch.pl-warnings.patch
create mode 100644 features/soc/baytrail/i2c-designware-add-i2c-high-speed-support.patch
create mode 100644 features/soc/baytrail/i2c-designware-add-per-channel-speed-parameter-and-f.patch
create mode 100644 features/soc/baytrail/i2c-designware-cleanup-__i2c_dw_enable.patch
create mode 100644 features/soc/baytrail/i2c-designware-cleanup-irq-handler-setting.patch
create mode 100644 features/soc/baytrail/i2c-designware-explicitly-abort-running-operation-on.patch
create mode 100644 features/soc/baytrail/i2c-designware-improve-FIFO-performance.patch
create mode 100644 features/soc/baytrail/i2c-designware-use-hardware-provided-Rx-Tx-FIFO-dept.patch
create mode 100644 features/soc/baytrail/i2c-designware-use-symbolic-names-for-command-bits.patch
diff --git a/features/soc/baytrail/baytrail.scc b/features/soc/baytrail/baytrail.scc
index b1638a1..1e7c7f2 100644
--- a/features/soc/baytrail/baytrail.scc
+++ b/features/soc/baytrail/baytrail.scc
@@ -17,3 +17,13 @@ patch usb-dwc3-core-Fix-gadget-for-system-suspend-resume.patch
patch usb-xhci-Change-how-we-indicate-a-host-supports-Link.patch
patch usb-core-hub-Generate-uevent-for-overcurrent-event.patch
patch usb-core-hub-Fix-checkpatch.pl-error.patch
+patch i2c-allow-Designware-I2C-to-be-probed-before-SMBus-f.patch
+patch i2c-designware-cleanup-irq-handler-setting.patch
+patch i2c-designware-use-hardware-provided-Rx-Tx-FIFO-dept.patch
+patch i2c-designware-use-symbolic-names-for-command-bits.patch
+patch i2c-designware-cleanup-__i2c_dw_enable.patch
+patch i2c-designware-explicitly-abort-running-operation-on.patch
+patch i2c-designware-improve-FIFO-performance.patch
+patch i2c-designware-add-per-channel-speed-parameter-and-f.patch
+patch i2c-designware-add-i2c-high-speed-support.patch
+patch i2c-designware-Fix-checkpatch.pl-warnings.patch
diff --git a/features/soc/baytrail/i2c-allow-Designware-I2C-to-be-probed-before-SMBus-f.patch b/features/soc/baytrail/i2c-allow-Designware-I2C-to-be-probed-before-SMBus-f.patch
new file mode 100644
index 0000000..5c26d2d
--- /dev/null
+++ b/features/soc/baytrail/i2c-allow-Designware-I2C-to-be-probed-before-SMBus-f.patch
@@ -0,0 +1,54 @@
+From aca3cf92cab6182363a365ac9d7987398c662d2b Mon Sep 17 00:00:00 2001
+From: Maurice Petallo <mauricex.r.petallo at intel.com>
+Date: Tue, 17 Feb 2015 13:21:01 +0800
+Subject: [PATCH 042/164] i2c: allow Designware I2C to be probed before SMBus
+ for Baytrail
+
+When SMBus is enabled in Baytrail, it is being probed first before
+all the Designware I2C devices. This means SMBus will take the first
+available bus id which is 0 and then the I2C devices will take the
+next succeeding bus ids. This should be fine as long as the I2C
+devices bus ids are assigned dynamically.
+
+The problem arises when the I2C devices' bus ids are assigned
+statically and the SMBus is probed first. The kernel will fail to
+add the i2c adapter because something else, which in that case is
+the SMBus, has taken the bus id that the i2c adapter is trying to
+take.
+
+As mentioned in commit "i2c: designware-pci: use static bus num
+allocation for baytrail", it is required for I2C devices' bus ids
+to be assigned statically for LPE Audio to register the i2c properly.
+
+To resolve this, we either force the SMBus to take the next bus id
+after all the designware I2C devices or we allow all the I2C devices
+to be probed first before the SMBus. This patch implements the 2nd.
+
+Signed-off-by: Maurice Petallo <mauricex.r.petallo at intel.com>
+---
+ drivers/i2c/busses/Makefile | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
+index a08931f..26c50ea 100644
+--- a/drivers/i2c/busses/Makefile
++++ b/drivers/i2c/busses/Makefile
+@@ -12,7 +12,6 @@ obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o
+ obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o
+ obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o
+ obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o
+-obj-$(CONFIG_I2C_I801) += i2c-i801.o
+ obj-$(CONFIG_I2C_ISCH) += i2c-isch.o
+ obj-$(CONFIG_I2C_ISMT) += i2c-ismt.o
+ obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
+@@ -41,6 +40,7 @@ obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o
+ i2c-designware-platform-objs := i2c-designware-platdrv.o
+ obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o
+ i2c-designware-pci-objs := i2c-designware-pcidrv.o
++obj-$(CONFIG_I2C_I801) += i2c-i801.o
+ obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o
+ obj-$(CONFIG_I2C_EXYNOS5) += i2c-exynos5.o
+ obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
+--
+1.7.7.6
+
diff --git a/features/soc/baytrail/i2c-designware-Fix-checkpatch.pl-warnings.patch b/features/soc/baytrail/i2c-designware-Fix-checkpatch.pl-warnings.patch
new file mode 100644
index 0000000..80effb4
--- /dev/null
+++ b/features/soc/baytrail/i2c-designware-Fix-checkpatch.pl-warnings.patch
@@ -0,0 +1,51 @@
+From 9f827d6746c3231a2e6c2a6f2a17fb371443cd2a Mon Sep 17 00:00:00 2001
+From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+Date: Fri, 21 Aug 2015 12:21:20 +0800
+Subject: [PATCH 155/164] i2c: designware: Fix checkpatch.pl warnings
+
+This commit is to fix the result of running scripts/checkpatch.pl against
+0127-i2c-designware-add-per-channel-speed-parameter-and-f.patch
+
+Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+---
+ drivers/i2c/busses/i2c-designware-pcidrv.c | 2 +-
+ drivers/i2c/busses/i2c-designware-platdrv.c | 6 +++---
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c
+index 2c22aef..c52028f 100644
+--- a/drivers/i2c/busses/i2c-designware-pcidrv.c
++++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
+@@ -339,7 +339,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
+ u32 mode;
+ struct dw_pci_controller *controller;
+ struct dw_scl_sda_cfg *cfg;
+- static int channel = 0;
++ static int channel;
+
+ if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) {
+ dev_err(&pdev->dev, "%s: invalid driver data %ld\n", __func__,
+diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
+index 084d6ec..e7a4214 100644
+--- a/drivers/i2c/busses/i2c-designware-platdrv.c
++++ b/drivers/i2c/busses/i2c-designware-platdrv.c
+@@ -95,13 +95,13 @@ static void i2c_dw_parse_flags(char *flags)
+ i++; /* next channel */
+ break;
+ default:
+- pr_err("i2c-designware-platform: invalid "
+- "flag %c for channel %d\n", *p, i);
++ pr_err("i2c-designware-platform: invalid flag %c for channel %d\n",
++ *p, i);
+ }
+ }
+ }
+
+-static int channel = 0;
++static int channel;
+
+ static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
+ {
+--
+1.7.7.6
+
diff --git a/features/soc/baytrail/i2c-designware-add-i2c-high-speed-support.patch b/features/soc/baytrail/i2c-designware-add-i2c-high-speed-support.patch
new file mode 100644
index 0000000..e27076d
--- /dev/null
+++ b/features/soc/baytrail/i2c-designware-add-i2c-high-speed-support.patch
@@ -0,0 +1,234 @@
+From e1cd14a14f6584985c3a27f69f220b4569364380 Mon Sep 17 00:00:00 2001
+From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+Date: Wed, 29 Jul 2015 18:15:01 +0800
+Subject: [PATCH 128/164] i2c: designware: add i2c high-speed support
+
+This patch enable the High-speed mode.
+
+Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+---
+ drivers/i2c/busses/i2c-designware-core.c | 23 +++++++++++++++++++++++
+ drivers/i2c/busses/i2c-designware-core.h | 6 ++++++
+ drivers/i2c/busses/i2c-designware-pcidrv.c | 18 ++++++++++++++++--
+ drivers/i2c/busses/i2c-designware-platdrv.c | 23 +++++++++++++++++++++--
+ 4 files changed, 66 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
+index c359775..2bf62db 100644
+--- a/drivers/i2c/busses/i2c-designware-core.c
++++ b/drivers/i2c/busses/i2c-designware-core.c
+@@ -41,6 +41,7 @@
+ */
+ #define DW_IC_CON 0x0
+ #define DW_IC_TAR 0x4
++# define DW_IC_TAR_HS_MASTER (BIT(10) | BIT(11))
+ #define DW_IC_DATA_CMD 0x10
+ # define DW_IC_CMD_READ BIT(8)
+ # define DW_IC_CMD_STOP BIT(9)
+@@ -49,6 +50,8 @@
+ #define DW_IC_SS_SCL_LCNT 0x18
+ #define DW_IC_FS_SCL_HCNT 0x1c
+ #define DW_IC_FS_SCL_LCNT 0x20
++#define DW_IC_HS_SCL_HCNT 0x24
++#define DW_IC_HS_SCL_LCNT 0x28
+ #define DW_IC_INTR_STAT 0x2c
+ #define DW_IC_INTR_MASK 0x30
+ #define DW_IC_RAW_INTR_STAT 0x34
+@@ -372,6 +375,23 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
+ dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT);
+ dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
+
++ if ((dev->master_cfg & DW_IC_CON_SPEED_MASK) ==
++ DW_IC_CON_SPEED_HIGH) {
++ if (((comp_param1 >> 2) & 3) != 3) {
++ dev_err(dev->dev, "High Speed not supported!\n");
++ dev->master_cfg &= ~DW_IC_CON_SPEED_MASK;
++ dev->master_cfg |= DW_IC_CON_SPEED_FAST;
++ dev->high_speed = false;
++ } else if (dev->hs_hcnt && dev->hs_lcnt) {
++ hcnt = dev->hs_hcnt;
++ lcnt = dev->hs_lcnt;
++ dw_writel(dev, hcnt, DW_IC_HS_SCL_HCNT);
++ dw_writel(dev, lcnt, DW_IC_HS_SCL_LCNT);
++ dev_dbg(dev->dev, "HighSpeed-mode HCNT:LCNT = %d:%d\n",
++ hcnt, lcnt);
++ }
++ }
++
+ /* Configure SDA Hold Time if required */
+ if (dev->sda_hold_time) {
+ reg = dw_readl(dev, DW_IC_COMP_VERSION);
+@@ -438,6 +458,9 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
+ ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
+ }
+
++ if (dev->high_speed) /* High speed */
++ ic_tar |= DW_IC_TAR_HS_MASTER; /* Send master highspeed addr */
++
+ dw_writel(dev, ic_con, DW_IC_CON);
+
+ /*
+diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
+index 956641f..5bbe769 100644
+--- a/drivers/i2c/busses/i2c-designware-core.h
++++ b/drivers/i2c/busses/i2c-designware-core.h
+@@ -31,6 +31,7 @@
+ #define DW_IC_CON_SPEED_MASK 0x6
+ #define DW_IC_CON_SPEED_STD 0x2
+ #define DW_IC_CON_SPEED_FAST 0x4
++#define DW_IC_CON_SPEED_HIGH 0x6
+ #define DW_IC_CON_10BITADDR_MASTER 0x10
+ #define DW_IC_CON_RESTART_EN 0x20
+ #define DW_IC_CON_SLAVE_DISABLE 0x40
+@@ -66,6 +67,8 @@
+ * @ss_lcnt: standard speed LCNT value
+ * @fs_hcnt: fast speed HCNT value
+ * @fs_lcnt: fast speed LCNT value
++ * @hs_hcnt: high speed HCNT value
++ * @hs_lcnt: high 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.
+@@ -104,6 +107,9 @@ struct dw_i2c_dev {
+ u16 ss_lcnt;
+ u16 fs_hcnt;
+ u16 fs_lcnt;
++ u16 hs_hcnt;
++ u16 hs_lcnt;
++ bool high_speed;
+ };
+
+ #define ACCESS_SWAP 0x00000001
+diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c
+index 0332baf..2c22aef 100644
+--- a/drivers/i2c/busses/i2c-designware-pcidrv.c
++++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
+@@ -45,10 +45,11 @@
+
+ static char *flags;
+ module_param(flags, charp, 0444);
+-MODULE_PARM_DESC(flags, "colon-delimited per-channel flags: [sfp]\n"
++MODULE_PARM_DESC(flags, "colon-delimited per-channel flags: [sfph]\n"
+ " s - standard speed (100KHz)\n"
+ " f - fast speed (400KHz)\n"
+-" p - fast-plus speed (1000kHz)\n");
++" p - fast-plus speed (1000kHz)\n"
++" h - high speed (3.4MHz)\n");
+
+ #define MAX_CHANNELS 7
+
+@@ -57,6 +58,7 @@ enum i2c_speeds {
+ i2c_ss,
+ i2c_fs,
+ i2c_fplus,
++ i2c_hs
+ };
+
+ static struct chan_opts {
+@@ -91,6 +93,8 @@ struct dw_scl_sda_cfg {
+ u32 fs_lcnt;
+ u32 fp_hcnt;
+ u32 fp_lcnt;
++ u32 hs_hcnt;
++ u32 hs_lcnt;
+ u32 sda_hold;
+ };
+
+@@ -120,6 +124,8 @@ static struct dw_scl_sda_cfg byt_config = {
+ .fs_lcnt = 0x99,
+ .fp_hcnt = 0x1B,
+ .fp_lcnt = 0x3A,
++ .hs_hcnt = 0x06,
++ .hs_lcnt = 0x0C,
+ .sda_hold = 0x6,
+ };
+
+@@ -242,6 +248,9 @@ static void i2c_dw_parse_flags(char *flags)
+ case 'p':
+ chan_opts[i].speed = i2c_fplus;
+ break;
++ case 'h':
++ chan_opts[i].speed = i2c_hs;
++ break;
+ case ':':
+ i++; /* next channel */
+ break;
+@@ -378,6 +387,9 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
+ } else if (chan_opts[channel].speed == i2c_fs ||
+ chan_opts[channel].speed == i2c_fplus) {
+ mode = DW_IC_CON_SPEED_FAST;
++ } else if (chan_opts[channel].speed == i2c_hs) {
++ dev->high_speed = true;
++ mode = DW_IC_CON_SPEED_HIGH;
+ } else { /* speed not set - using default from dw_pci_controller */
+ mode = controller->bus_cfg & DW_IC_CON_SPEED_MASK;
+ }
+@@ -394,6 +406,8 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
+ dev->fs_hcnt = cfg->fs_hcnt;
+ dev->fs_lcnt = cfg->fs_lcnt;
+ }
++ dev->hs_hcnt = cfg->hs_hcnt;
++ dev->hs_lcnt = cfg->hs_lcnt;
+ dev->sda_hold_time = cfg->sda_hold;
+ }
+
+diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
+index 530b9d1..084d6ec 100644
+--- a/drivers/i2c/busses/i2c-designware-platdrv.c
++++ b/drivers/i2c/busses/i2c-designware-platdrv.c
+@@ -45,10 +45,11 @@
+
+ static char *flags;
+ module_param(flags, charp, 0444);
+-MODULE_PARM_DESC(flags, "colon-delimited per-channel flags: [sfp]\n"
++MODULE_PARM_DESC(flags, "colon-delimited per-channel flags: [sfph]\n"
+ " s - standard speed (100KHz)\n"
+ " f - fast speed (400KHz)\n"
+-" p - fast-plus speed (1000kHz)\n");
++" p - fast-plus speed (1000kHz)\n"
++" h - high speed (3.4MHz)\n");
+
+ #define MAX_CHANNELS 7
+
+@@ -57,6 +58,7 @@ enum i2c_speeds {
+ i2c_ss,
+ i2c_fs,
+ i2c_fplus,
++ i2c_hs
+ };
+
+ static struct chan_opts {
+@@ -86,6 +88,9 @@ static void i2c_dw_parse_flags(char *flags)
+ case 'p':
+ chan_opts[i].speed = i2c_fplus;
+ break;
++ case 'h':
++ chan_opts[i].speed = i2c_hs;
++ break;
+ case ':':
+ i++; /* next channel */
+ break;
+@@ -229,6 +234,20 @@ static int dw_i2c_probe(struct platform_device *pdev)
+ } else if (chan_opts[channel].speed == i2c_fs ||
+ chan_opts[channel].speed == i2c_fplus) {
+ dev->master_cfg |= DW_IC_CON_SPEED_FAST;
++ } else if (chan_opts[channel].speed == i2c_hs) {
++ u32 ic_clk = dev->get_clk_rate_khz(dev);
++ u32 hs_hcnt, hs_lcnt;
++ hs_hcnt = (60 * ic_clk) / 1000000;
++ hs_lcnt = (120 * ic_clk) / 1000000;
++ if (hs_hcnt < 2) {
++ dev_warn(dev->dev, "Clock rate too low for high speed!\n");
++ dev->master_cfg |= DW_IC_CON_SPEED_FAST;
++ } else {
++ dev->hs_hcnt = hs_hcnt;
++ dev->hs_lcnt = hs_lcnt;
++ dev->master_cfg |= DW_IC_CON_SPEED_HIGH;
++ dev->high_speed = true;
++ }
+ } else {
+ dev->master_cfg |= DW_IC_CON_SPEED_FAST;
+ }
+--
+1.7.7.6
+
diff --git a/features/soc/baytrail/i2c-designware-add-per-channel-speed-parameter-and-f.patch b/features/soc/baytrail/i2c-designware-add-per-channel-speed-parameter-and-f.patch
new file mode 100644
index 0000000..410f3f9
--- /dev/null
+++ b/features/soc/baytrail/i2c-designware-add-per-channel-speed-parameter-and-f.patch
@@ -0,0 +1,331 @@
+From a6fae535b3d2d6a1a4997d69f2a7fefe4ed84bcf Mon Sep 17 00:00:00 2001
+From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+Date: Wed, 29 Jul 2015 18:14:53 +0800
+Subject: [PATCH 127/164] i2c: designware: add per-channel speed parameter and
+ fast-plus speed option
+
+This patch allows the I2C transfer speed to be configured via module
+parameter for each channel available.
+
+This patch also enable the Fast-mode Plus.
+
+Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+---
+ drivers/i2c/busses/i2c-designware-core.h | 1 +
+ drivers/i2c/busses/i2c-designware-pcidrv.c | 100 +++++++++++++++++++++++++-
+ drivers/i2c/busses/i2c-designware-platdrv.c | 82 ++++++++++++++++++++--
+ 3 files changed, 174 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
+index e59dc2c..956641f 100644
+--- a/drivers/i2c/busses/i2c-designware-core.h
++++ b/drivers/i2c/busses/i2c-designware-core.h
+@@ -28,6 +28,7 @@
+
+
+ #define DW_IC_CON_MASTER 0x1
++#define DW_IC_CON_SPEED_MASK 0x6
+ #define DW_IC_CON_SPEED_STD 0x2
+ #define DW_IC_CON_SPEED_FAST 0x4
+ #define DW_IC_CON_10BITADDR_MASTER 0x10
+diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c
+index c87f40c..0332baf 100644
+--- a/drivers/i2c/busses/i2c-designware-pcidrv.c
++++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
+@@ -43,6 +43,26 @@
+
+ #define DRIVER_NAME "i2c-designware-pci"
+
++static char *flags;
++module_param(flags, charp, 0444);
++MODULE_PARM_DESC(flags, "colon-delimited per-channel flags: [sfp]\n"
++" s - standard speed (100KHz)\n"
++" f - fast speed (400KHz)\n"
++" p - fast-plus speed (1000kHz)\n");
++
++#define MAX_CHANNELS 7
++
++enum i2c_speeds {
++ i2c_none = 0,
++ i2c_ss,
++ i2c_fs,
++ i2c_fplus,
++};
++
++static struct chan_opts {
++ enum i2c_speeds speed;
++} chan_opts[MAX_CHANNELS];
++
+ enum dw_pci_ctl_id_t {
+ moorestown_0,
+ moorestown_1,
+@@ -69,6 +89,8 @@ struct dw_scl_sda_cfg {
+ u32 fs_hcnt;
+ u32 ss_lcnt;
+ u32 fs_lcnt;
++ u32 fp_hcnt;
++ u32 fp_lcnt;
+ u32 sda_hold;
+ };
+
+@@ -96,6 +118,8 @@ static struct dw_scl_sda_cfg byt_config = {
+ .fs_hcnt = 0x55,
+ .ss_lcnt = 0x200,
+ .fs_lcnt = 0x99,
++ .fp_hcnt = 0x1B,
++ .fp_lcnt = 0x3A,
+ .sda_hold = 0x6,
+ };
+
+@@ -200,6 +224,34 @@ static struct i2c_algorithm i2c_dw_algo = {
+ .functionality = i2c_dw_func,
+ };
+
++static void i2c_dw_parse_flags(char *flags)
++{
++ char *p = flags;
++ int i;
++
++ for (i = 0; i < MAX_CHANNELS; p++) {
++ if (!*p)
++ break;
++ switch (*p) {
++ case 's':
++ chan_opts[i].speed = i2c_ss;
++ break;
++ case 'f':
++ chan_opts[i].speed = i2c_fs;
++ break;
++ case 'p':
++ chan_opts[i].speed = i2c_fplus;
++ break;
++ case ':':
++ i++; /* next channel */
++ break;
++ default:
++ pr_err(DRIVER_NAME ": invalid flag %c for channel %d\n",
++ *p, i);
++ }
++ }
++}
++
+ static int i2c_dw_pci_suspend(struct device *dev)
+ {
+ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+@@ -275,8 +327,10 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
+ struct dw_i2c_dev *dev;
+ struct i2c_adapter *adap;
+ int r;
++ u32 mode;
+ struct dw_pci_controller *controller;
+ struct dw_scl_sda_cfg *cfg;
++ static int channel = 0;
+
+ if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) {
+ dev_err(&pdev->dev, "%s: invalid driver data %ld\n", __func__,
+@@ -313,13 +367,33 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
+ dev->functionality = controller->functionality |
+ DW_DEFAULT_FUNCTIONALITY;
+
+- dev->master_cfg = controller->bus_cfg;
++ if (channel >= MAX_CHANNELS) {
++ dev_warn(&pdev->dev, "Using default params\n");
++ channel = MAX_CHANNELS - 1;
++ memset(&chan_opts[channel], 0, sizeof(struct chan_opts));
++ }
++
++ if (chan_opts[channel].speed == i2c_ss) {
++ mode = DW_IC_CON_SPEED_STD;
++ } else if (chan_opts[channel].speed == i2c_fs ||
++ chan_opts[channel].speed == i2c_fplus) {
++ mode = DW_IC_CON_SPEED_FAST;
++ } else { /* speed not set - using default from dw_pci_controller */
++ mode = controller->bus_cfg & DW_IC_CON_SPEED_MASK;
++ }
++
++ dev->master_cfg = (controller->bus_cfg & ~DW_IC_CON_SPEED_MASK) | mode;
+ if (controller->scl_sda_cfg) {
+ cfg = controller->scl_sda_cfg;
+ dev->ss_hcnt = cfg->ss_hcnt;
+- dev->fs_hcnt = cfg->fs_hcnt;
+ dev->ss_lcnt = cfg->ss_lcnt;
+- dev->fs_lcnt = cfg->fs_lcnt;
++ if (chan_opts[channel].speed == i2c_fplus) {
++ dev->fs_hcnt = cfg->fp_hcnt;
++ dev->fs_lcnt = cfg->fp_lcnt;
++ } else {
++ dev->fs_hcnt = cfg->fs_hcnt;
++ dev->fs_lcnt = cfg->fs_lcnt;
++ }
+ dev->sda_hold_time = cfg->sda_hold;
+ }
+
+@@ -359,6 +433,8 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_allow(&pdev->dev);
+
++ channel++;
++
+ return 0;
+ }
+
+@@ -410,7 +486,23 @@ static struct pci_driver dw_i2c_driver = {
+ },
+ };
+
+-module_pci_driver(dw_i2c_driver);
++static int __init
++i2c_dw_pci_init(void)
++{
++ if (flags)
++ i2c_dw_parse_flags(flags);
++
++ return pci_register_driver(&dw_i2c_driver);
++}
++
++static void __exit
++i2c_dw_pci_exit(void)
++{
++ pci_unregister_driver(&dw_i2c_driver);
++}
++
++module_init(i2c_dw_pci_init);
++module_exit(i2c_dw_pci_exit);
+
+ MODULE_AUTHOR("Baruch Siach <baruch at tkos.co.il>");
+ MODULE_DESCRIPTION("Synopsys DesignWare PCI I2C bus adapter");
+diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
+index e0f0c64..530b9d1 100644
+--- a/drivers/i2c/busses/i2c-designware-platdrv.c
++++ b/drivers/i2c/busses/i2c-designware-platdrv.c
+@@ -43,10 +43,61 @@
+ #include <linux/acpi.h>
+ #include "i2c-designware-core.h"
+
++static char *flags;
++module_param(flags, charp, 0444);
++MODULE_PARM_DESC(flags, "colon-delimited per-channel flags: [sfp]\n"
++" s - standard speed (100KHz)\n"
++" f - fast speed (400KHz)\n"
++" p - fast-plus speed (1000kHz)\n");
++
++#define MAX_CHANNELS 7
++
++enum i2c_speeds {
++ i2c_none = 0,
++ i2c_ss,
++ i2c_fs,
++ i2c_fplus,
++};
++
++static struct chan_opts {
++ enum i2c_speeds speed;
++} chan_opts[MAX_CHANNELS];
++
+ static struct i2c_algorithm i2c_dw_algo = {
+ .master_xfer = i2c_dw_xfer,
+ .functionality = i2c_dw_func,
+ };
++
++static void i2c_dw_parse_flags(char *flags)
++{
++ char *p = flags;
++ int i;
++
++ for (i = 0; i < MAX_CHANNELS; p++) {
++ if (!*p)
++ break;
++ switch (*p) {
++ case 's':
++ chan_opts[i].speed = i2c_ss;
++ break;
++ case 'f':
++ chan_opts[i].speed = i2c_fs;
++ break;
++ case 'p':
++ chan_opts[i].speed = i2c_fplus;
++ break;
++ case ':':
++ i++; /* next channel */
++ break;
++ default:
++ pr_err("i2c-designware-platform: invalid "
++ "flag %c for channel %d\n", *p, i);
++ }
++ }
++}
++
++static int channel = 0;
++
+ static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
+ {
+ return clk_get_rate(dev->clk)/1000;
+@@ -79,7 +130,6 @@ static void dw_i2c_acpi_params(struct platform_device *pdev, char method[],
+ static int dw_i2c_acpi_configure(struct platform_device *pdev)
+ {
+ struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
+- bool fs_mode = dev->master_cfg & DW_IC_CON_SPEED_FAST;
+
+ if (!ACPI_HANDLE(&pdev->dev))
+ return -ENODEV;
+@@ -91,9 +141,13 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev)
+ * it exists for both supported speed modes.
+ */
+ dw_i2c_acpi_params(pdev, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt,
+- fs_mode ? NULL : &dev->sda_hold_time);
+- dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt,
+- fs_mode ? &dev->sda_hold_time : NULL);
++ NULL);
++ if (chan_opts[channel].speed == i2c_fplus)
++ dw_i2c_acpi_params(pdev, "FPCN", &dev->fs_hcnt, &dev->fs_lcnt,
++ &dev->sda_hold_time);
++ else
++ dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt,
++ &dev->sda_hold_time);
+
+ return 0;
+ }
+@@ -162,7 +216,22 @@ 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;
++
++ if (channel >= MAX_CHANNELS) {
++ dev_warn(dev->dev, "Using default params\n");
++ channel = MAX_CHANNELS - 1;
++ memset(&chan_opts[channel], 0, sizeof(struct chan_opts));
++ }
++
++ if (chan_opts[channel].speed == i2c_ss) {
++ dev->master_cfg |= DW_IC_CON_SPEED_STD;
++ } else if (chan_opts[channel].speed == i2c_fs ||
++ chan_opts[channel].speed == i2c_fplus) {
++ dev->master_cfg |= DW_IC_CON_SPEED_FAST;
++ } else {
++ dev->master_cfg |= DW_IC_CON_SPEED_FAST;
++ }
+
+ #ifdef CONFIG_ACPI
+ dw_i2c_acpi_configure(pdev);
+@@ -203,6 +272,7 @@ static int dw_i2c_probe(struct platform_device *pdev)
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
++ channel++;
+ return 0;
+ }
+
+@@ -275,6 +345,8 @@ static struct platform_driver dw_i2c_driver = {
+
+ static int __init dw_i2c_init_driver(void)
+ {
++ if (flags)
++ i2c_dw_parse_flags(flags);
+ return platform_driver_register(&dw_i2c_driver);
+ }
+ subsys_initcall(dw_i2c_init_driver);
+--
+1.7.7.6
+
diff --git a/features/soc/baytrail/i2c-designware-cleanup-__i2c_dw_enable.patch b/features/soc/baytrail/i2c-designware-cleanup-__i2c_dw_enable.patch
new file mode 100644
index 0000000..92b2537
--- /dev/null
+++ b/features/soc/baytrail/i2c-designware-cleanup-__i2c_dw_enable.patch
@@ -0,0 +1,54 @@
+From a12e523011a2e92fe4a6c7e2be2047a1e1c64985 Mon Sep 17 00:00:00 2001
+From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+Date: Wed, 29 Jul 2015 18:14:25 +0800
+Subject: [PATCH 124/164] i2c: designware: cleanup __i2c_dw_enable()
+
+- Do not write boolean value to register (and implicitly depend on match
+ between boolean representation and register bit position).
+
+- Do not implicitly depend on same bit position of enable bit in Enable
+ and Enable Status registers.
+
+Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+---
+ drivers/i2c/busses/i2c-designware-core.c | 9 +++++++--
+ 1 files changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
+index d60d8da..896d711 100644
+--- a/drivers/i2c/busses/i2c-designware-core.c
++++ b/drivers/i2c/busses/i2c-designware-core.c
+@@ -66,12 +66,14 @@
+ #define DW_IC_CLR_START_DET 0x64
+ #define DW_IC_CLR_GEN_CALL 0x68
+ #define DW_IC_ENABLE 0x6c
++# define DW_IC_ENABLE_EN BIT(0)
+ #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_ENABLE_STATUS_EN BIT(0)
+ #define DW_IC_COMP_PARAM_1 0xf4
+ #define DW_IC_COMP_VERSION 0xf8
+ #define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A
+@@ -259,10 +261,13 @@ static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
+ static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable)
+ {
+ int timeout = 100;
++ u32 status;
+
+ do {
+- dw_writel(dev, enable, DW_IC_ENABLE);
+- if ((dw_readl(dev, DW_IC_ENABLE_STATUS) & 1) == enable)
++ dw_writel(dev, enable ? DW_IC_ENABLE_EN : 0, DW_IC_ENABLE);
++ status = dw_readl(dev, DW_IC_ENABLE_STATUS);
++ if ((enable && (status & DW_IC_ENABLE_STATUS_EN)) ||
++ (!enable && !(status & DW_IC_ENABLE_STATUS_EN)))
+ return;
+
+ /*
+--
+1.7.7.6
+
diff --git a/features/soc/baytrail/i2c-designware-cleanup-irq-handler-setting.patch b/features/soc/baytrail/i2c-designware-cleanup-irq-handler-setting.patch
new file mode 100644
index 0000000..da5ee02
--- /dev/null
+++ b/features/soc/baytrail/i2c-designware-cleanup-irq-handler-setting.patch
@@ -0,0 +1,53 @@
+From b4dd652adaf7192c7ef905b9f88692109311fdd0 Mon Sep 17 00:00:00 2001
+From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+Date: Wed, 29 Jul 2015 18:13:56 +0800
+Subject: [PATCH 121/164] i2c: designware: cleanup irq handler setting
+
+Disable irq and clear any pending interrupts both in PCI and platform
+driver, do so before setting interrupt handler.
+
+Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+---
+ drivers/i2c/busses/i2c-designware-pcidrv.c | 5 +++--
+ drivers/i2c/busses/i2c-designware-platdrv.c | 2 ++
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c
+index bd7b6b7..4a2a2a3 100644
+--- a/drivers/i2c/busses/i2c-designware-pcidrv.c
++++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
+@@ -375,6 +375,9 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
+
+ snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci");
+
++ i2c_dw_disable_int(dev);
++ i2c_dw_clear_int(dev);
++
+ r = devm_request_irq(&pdev->dev, pdev->irq, i2c_dw_isr, IRQF_SHARED,
+ adap->name, dev);
+ if (r) {
+@@ -382,8 +385,6 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
+ return r;
+ }
+
+- i2c_dw_disable_int(dev);
+- i2c_dw_clear_int(dev);
+ r = i2c_add_numbered_adapter(adap);
+ if (r) {
+ dev_err(&pdev->dev, "failure adding adapter\n");
+diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
+index d0bdac0..9b9ce46 100644
+--- a/drivers/i2c/busses/i2c-designware-platdrv.c
++++ b/drivers/i2c/busses/i2c-designware-platdrv.c
+@@ -185,6 +185,8 @@ static int dw_i2c_probe(struct platform_device *pdev)
+ return r;
+
+ i2c_dw_disable_int(dev);
++ i2c_dw_clear_int(dev);
++
+ r = devm_request_irq(&pdev->dev, dev->irq, i2c_dw_isr, IRQF_SHARED,
+ pdev->name, dev);
+ if (r) {
+--
+1.7.7.6
+
diff --git a/features/soc/baytrail/i2c-designware-explicitly-abort-running-operation-on.patch b/features/soc/baytrail/i2c-designware-explicitly-abort-running-operation-on.patch
new file mode 100644
index 0000000..52bb9de
--- /dev/null
+++ b/features/soc/baytrail/i2c-designware-explicitly-abort-running-operation-on.patch
@@ -0,0 +1,70 @@
+From 48423cfcaee8dcb7f313ca49bd11f2d7fa145f05 Mon Sep 17 00:00:00 2001
+From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+Date: Wed, 29 Jul 2015 18:14:34 +0800
+Subject: [PATCH 125/164] i2c: designware: explicitly abort running operation
+ on disable
+
+Failure to disable causes hard device hangs in some situations
+involving timeouts.
+
+Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+---
+ drivers/i2c/busses/i2c-designware-core.c | 19 ++++++++++++++++++-
+ 1 files changed, 18 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
+index 896d711..f867c9b 100644
+--- a/drivers/i2c/busses/i2c-designware-core.c
++++ b/drivers/i2c/busses/i2c-designware-core.c
+@@ -67,7 +67,9 @@
+ #define DW_IC_CLR_GEN_CALL 0x68
+ #define DW_IC_ENABLE 0x6c
+ # define DW_IC_ENABLE_EN BIT(0)
++# define DW_IC_ENABLE_ABRT BIT(1)
+ #define DW_IC_STATUS 0x70
++# define DW_IC_STATUS_MST_ACT BIT(5)
+ #define DW_IC_TXFLR 0x74
+ #define DW_IC_RXFLR 0x78
+ #define DW_IC_SDA_HOLD 0x7c
+@@ -174,6 +176,8 @@ static char *abort_sources[] = {
+ "lost arbitration",
+ };
+
++static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev);
++
+ u32 dw_readl(struct dw_i2c_dev *dev, int offset)
+ {
+ u32 value;
+@@ -263,6 +267,17 @@ static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable)
+ int timeout = 100;
+ u32 status;
+
++ if (!enable &&
++ (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_MST_ACT)) {
++ /* Must abort if some activity is pending. */
++ /* Enable first before */
++ dw_writel(dev, DW_IC_ENABLE_EN, DW_IC_ENABLE);
++ /* aborting. */
++ dw_writel(dev, DW_IC_ENABLE_EN | DW_IC_ENABLE_ABRT,
++ DW_IC_ENABLE);
++ i2c_dw_wait_bus_not_busy(dev); /* wait for abort completion */
++ }
++
+ do {
+ dw_writel(dev, enable ? DW_IC_ENABLE_EN : 0, DW_IC_ENABLE);
+ status = dw_readl(dev, DW_IC_ENABLE_STATUS);
+@@ -642,8 +657,10 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+ dev->rx_outstanding = 0;
+
+ ret = i2c_dw_wait_bus_not_busy(dev);
+- if (ret < 0)
++ if (ret < 0) {
++ i2c_dw_disable(dev);
+ goto done;
++ }
+
+ /* start the transfers */
+ i2c_dw_xfer_init(dev);
+--
+1.7.7.6
+
diff --git a/features/soc/baytrail/i2c-designware-improve-FIFO-performance.patch b/features/soc/baytrail/i2c-designware-improve-FIFO-performance.patch
new file mode 100644
index 0000000..5a546b3
--- /dev/null
+++ b/features/soc/baytrail/i2c-designware-improve-FIFO-performance.patch
@@ -0,0 +1,137 @@
+From cf20fd639b092e94c4ee55b8c7f80234df3419bf Mon Sep 17 00:00:00 2001
+From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+Date: Wed, 29 Jul 2015 18:14:43 +0800
+Subject: [PATCH 126/164] i2c: designware: improve FIFO performance
+
+There is no need to catch interrupt after every byte transmitted or
+received, as driver currently does. Hardware has deep FIFOs that allow
+much less software intervention.
+
+This patch reworks FIFO handling such that up to 3/4 of FIFO depth is
+processed per one interrupt. This results into significant decrease of
+number of interrupts and increase of performance.
+
+Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+---
+ drivers/i2c/busses/i2c-designware-core.c | 34 ++++++++++++++++-------------
+ 1 files changed, 19 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
+index f867c9b..c359775 100644
+--- a/drivers/i2c/busses/i2c-designware-core.c
++++ b/drivers/i2c/busses/i2c-designware-core.c
+@@ -387,8 +387,8 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
+ dev->rx_fifo_depth = ((comp_param1 >> 8) & 0xff) + 1;
+ dev_dbg(dev->dev, "Tx/Rx FIFO sizes: %d/%d\n",
+ dev->tx_fifo_depth, dev->rx_fifo_depth);
+- dw_writel(dev, dev->tx_fifo_depth - 1, DW_IC_TX_TL);
+- dw_writel(dev, 0, DW_IC_RX_TL);
++ dw_writel(dev, dev->tx_fifo_depth / 4, DW_IC_TX_TL);
++ dw_writel(dev, dev->rx_fifo_depth * 3 / 4, DW_IC_RX_TL);
+
+ /* configure the i2c master */
+ dw_writel(dev, dev->master_cfg , DW_IC_CON);
+@@ -452,9 +452,8 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
+ /* Enable the adapter */
+ __i2c_dw_enable(dev, true);
+
+- /* Clear and enable interrupts */
++ /* Clear interrupts, they will be enabled in 'xfer' function */
+ i2c_dw_clear_int(dev);
+- dw_writel(dev, DW_IC_INTR_DEFAULT_MASK, DW_IC_INTR_MASK);
+ }
+
+ /*
+@@ -511,7 +510,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
+ }
+
+ tx_limit = dev->tx_fifo_depth - dw_readl(dev, DW_IC_TXFLR);
+- rx_limit = dev->rx_fifo_depth - dw_readl(dev, DW_IC_RXFLR);
++ rx_limit = dev->rx_fifo_depth - dev->rx_outstanding;
+
+ while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) {
+ u32 cmd = 0;
+@@ -532,11 +531,6 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
+ }
+
+ if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {
+-
+- /* avoid rx buffer overrun */
+- if (rx_limit - dev->rx_outstanding <= 0)
+- break;
+-
+ dw_writel(dev, cmd | DW_IC_CMD_READ,
+ DW_IC_DATA_CMD);
+ rx_limit--;
+@@ -570,11 +564,12 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
+ dw_writel(dev, intr_mask, DW_IC_INTR_MASK);
+ }
+
+-static void
++static int
+ i2c_dw_read(struct dw_i2c_dev *dev)
+ {
+ struct i2c_msg *msgs = dev->msgs;
+ int rx_valid;
++ int count = 0;
+
+ for (; dev->msg_read_idx < dev->msgs_num; dev->msg_read_idx++) {
+ u32 len;
+@@ -596,16 +591,19 @@ i2c_dw_read(struct dw_i2c_dev *dev)
+ for (; len > 0 && rx_valid > 0; len--, rx_valid--) {
+ *buf++ = dw_readl(dev, DW_IC_DATA_CMD);
+ dev->rx_outstanding--;
++ count++;
+ }
+
+ if (len > 0) {
+ dev->status |= STATUS_READ_IN_PROGRESS;
+ dev->rx_buf_len = len;
+ dev->rx_buf = buf;
+- return;
++ return count;
+ } else
+ dev->status &= ~STATUS_READ_IN_PROGRESS;
+ }
++
++ return count;
+ }
+
+ static int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
+@@ -665,6 +663,8 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+ /* start the transfers */
+ i2c_dw_xfer_init(dev);
+
++ /* Fill up TX buffer and enable interrupts */
++ i2c_dw_xfer_msg(dev);
+ /* wait for tx to complete */
+ ret = wait_for_completion_timeout(&dev->cmd_complete, HZ);
+ if (ret == 0) {
+@@ -781,6 +781,7 @@ irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
+ {
+ struct dw_i2c_dev *dev = dev_id;
+ u32 stat, enabled;
++ int read_count = 0;
+
+ enabled = dw_readl(dev, DW_IC_ENABLE);
+ stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
+@@ -803,10 +804,13 @@ irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
+ goto tx_aborted;
+ }
+
+- if (stat & DW_IC_INTR_RX_FULL)
+- i2c_dw_read(dev);
++ if ((stat & (DW_IC_INTR_RX_FULL | DW_IC_INTR_STOP_DET)) ||
++ dev->rx_outstanding)
++ read_count = i2c_dw_read(dev);
+
+- if (stat & DW_IC_INTR_TX_EMPTY)
++ /* Allow TX_EMPTY intr if TX queue is not empty */
++ if ((read_count && dev->status & STATUS_WRITE_IN_PROGRESS) ||
++ (stat & DW_IC_INTR_TX_EMPTY))
+ i2c_dw_xfer_msg(dev);
+
+ /*
+--
+1.7.7.6
+
diff --git a/features/soc/baytrail/i2c-designware-use-hardware-provided-Rx-Tx-FIFO-dept.patch b/features/soc/baytrail/i2c-designware-use-hardware-provided-Rx-Tx-FIFO-dept.patch
new file mode 100644
index 0000000..c6b8fcd
--- /dev/null
+++ b/features/soc/baytrail/i2c-designware-use-hardware-provided-Rx-Tx-FIFO-dept.patch
@@ -0,0 +1,220 @@
+From 533841a28abf7d3feca8aee92478047d386755dc Mon Sep 17 00:00:00 2001
+From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+Date: Wed, 29 Jul 2015 18:14:05 +0800
+Subject: [PATCH 122/164] i2c: designware: use hardware-provided Rx/Tx FIFO
+ depths
+
+i2c-designware module provides information about actual Rx/Tx FIFO
+depths in COMP_PARAM1 register.
+
+Current driver uses these hardware-provided values only in case of
+non-ACPI platform device. For all other cases (which includes all
+Bay Trail cases) hardcoded value of 32 is used instead - which leads to
+suboptimal FIFO use.
+
+This patch switches to using hardware-provided values in all cases.
+
+Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+---
+ drivers/i2c/busses/i2c-designware-core.c | 14 +++++++-------
+ drivers/i2c/busses/i2c-designware-core.h | 1 -
+ drivers/i2c/busses/i2c-designware-pcidrv.c | 24 ------------------------
+ drivers/i2c/busses/i2c-designware-platdrv.c | 18 +++---------------
+ 4 files changed, 10 insertions(+), 47 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
+index d95b930..f5d4ce3 100644
+--- a/drivers/i2c/busses/i2c-designware-core.c
++++ b/drivers/i2c/busses/i2c-designware-core.c
+@@ -286,7 +286,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
+ {
+ u32 input_clock_khz;
+ u32 hcnt, lcnt;
+- u32 reg;
++ u32 reg, comp_param1;
+
+ input_clock_khz = dev->get_clk_rate_khz(dev);
+
+@@ -303,6 +303,8 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
+ return -ENODEV;
+ }
+
++ comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1);
++
+ /* Disable the adapter */
+ __i2c_dw_enable(dev, false);
+
+@@ -358,6 +360,10 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
+ }
+
+ /* Configure Tx/Rx FIFO threshold levels */
++ dev->tx_fifo_depth = ((comp_param1 >> 16) & 0xff) + 1;
++ dev->rx_fifo_depth = ((comp_param1 >> 8) & 0xff) + 1;
++ dev_dbg(dev->dev, "Tx/Rx FIFO sizes: %d/%d\n",
++ dev->tx_fifo_depth, dev->rx_fifo_depth);
+ dw_writel(dev, dev->tx_fifo_depth - 1, DW_IC_TX_TL);
+ dw_writel(dev, 0, DW_IC_RX_TL);
+
+@@ -827,11 +833,5 @@ void i2c_dw_disable_int(struct dw_i2c_dev *dev)
+ }
+ EXPORT_SYMBOL_GPL(i2c_dw_disable_int);
+
+-u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev)
+-{
+- return dw_readl(dev, DW_IC_COMP_PARAM_1);
+-}
+-EXPORT_SYMBOL_GPL(i2c_dw_read_comp_param);
+-
+ MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core");
+ MODULE_LICENSE("GPL");
+diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
+index e8a7565..e59dc2c 100644
+--- a/drivers/i2c/busses/i2c-designware-core.h
++++ b/drivers/i2c/busses/i2c-designware-core.h
+@@ -120,4 +120,3 @@ extern u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev);
+ extern void i2c_dw_disable(struct dw_i2c_dev *dev);
+ extern void i2c_dw_clear_int(struct dw_i2c_dev *dev);
+ extern void i2c_dw_disable_int(struct dw_i2c_dev *dev);
+-extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev);
+diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c
+index 385909e..4579a5e 100644
+--- a/drivers/i2c/busses/i2c-designware-pcidrv.c
++++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
+@@ -69,8 +69,6 @@ struct dw_scl_sda_cfg {
+ struct dw_pci_controller {
+ u32 bus_num;
+ u32 bus_cfg;
+- u32 tx_fifo_depth;
+- u32 rx_fifo_depth;
+ u32 clk_khz;
+ u32 functionality;
+ struct dw_scl_sda_cfg *scl_sda_cfg;
+@@ -99,71 +97,51 @@ static struct dw_pci_controller dw_pci_controllers[] = {
+ [moorestown_0] = {
+ .bus_num = 0,
+ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+- .tx_fifo_depth = 32,
+- .rx_fifo_depth = 32,
+ .clk_khz = 25000,
+ },
+ [moorestown_1] = {
+ .bus_num = 1,
+ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+- .tx_fifo_depth = 32,
+- .rx_fifo_depth = 32,
+ .clk_khz = 25000,
+ },
+ [moorestown_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,
+ },
+ [medfield_0] = {
+ .bus_num = 0,
+ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+- .tx_fifo_depth = 32,
+- .rx_fifo_depth = 32,
+ .clk_khz = 25000,
+ },
+ [medfield_1] = {
+ .bus_num = 1,
+ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+- .tx_fifo_depth = 32,
+- .rx_fifo_depth = 32,
+ .clk_khz = 25000,
+ },
+ [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,
+ },
+ [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,
+ },
+ [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,
+ },
+ [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,
+ },
+ [baytrail] = {
+ .bus_num = -1,
+ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+- .tx_fifo_depth = 32,
+- .rx_fifo_depth = 32,
+ .clk_khz = 100000,
+ .functionality = I2C_FUNC_10BIT_ADDR,
+ .scl_sda_cfg = &byt_config,
+@@ -299,8 +277,6 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
+
+ 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)
+ return r;
+diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
+index 8aad948..3834bc2 100644
+--- a/drivers/i2c/busses/i2c-designware-platdrv.c
++++ b/drivers/i2c/busses/i2c-designware-platdrv.c
+@@ -105,8 +105,6 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev)
+ return -ENODEV;
+
+ dev->adapter.nr = -1;
+- dev->tx_fifo_depth = 32;
+- dev->rx_fifo_depth = 32;
+
+ /*
+ * Try to get SDA hold time and *CNT values from an ACPI method if
+@@ -129,11 +127,6 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
+ { }
+ };
+ 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)
+@@ -191,15 +184,10 @@ static int dw_i2c_probe(struct platform_device *pdev)
+ dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
+ DW_IC_CON_RESTART_EN | 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);
++#ifdef CONFIG_ACPI
++ dw_i2c_acpi_configure(pdev);
++#endif
+
+- 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)
+ return r;
+--
+1.9.1
+
+
diff --git a/features/soc/baytrail/i2c-designware-use-symbolic-names-for-command-bits.patch b/features/soc/baytrail/i2c-designware-use-symbolic-names-for-command-bits.patch
new file mode 100644
index 0000000..7f98525
--- /dev/null
+++ b/features/soc/baytrail/i2c-designware-use-symbolic-names-for-command-bits.patch
@@ -0,0 +1,50 @@
+From 548a004593a14b948af1dcff00ff013137511554 Mon Sep 17 00:00:00 2001
+From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+Date: Wed, 29 Jul 2015 18:14:14 +0800
+Subject: [PATCH 123/164] i2c: designware: use symbolic names for command bits
+
+Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+---
+ drivers/i2c/busses/i2c-designware-core.c | 10 +++++++---
+ 1 files changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
+index f5d4ce3..d60d8da 100644
+--- a/drivers/i2c/busses/i2c-designware-core.c
++++ b/drivers/i2c/busses/i2c-designware-core.c
+@@ -42,6 +42,9 @@
+ #define DW_IC_CON 0x0
+ #define DW_IC_TAR 0x4
+ #define DW_IC_DATA_CMD 0x10
++# define DW_IC_CMD_READ BIT(8)
++# define DW_IC_CMD_STOP BIT(9)
++# define DW_IC_CMD_RESTART BIT(10)
+ #define DW_IC_SS_SCL_HCNT 0x14
+ #define DW_IC_SS_SCL_LCNT 0x18
+ #define DW_IC_FS_SCL_HCNT 0x1c
+@@ -501,10 +504,10 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
+ */
+ if (dev->msg_write_idx == dev->msgs_num - 1 &&
+ buf_len == 1)
+- cmd |= BIT(9);
++ cmd |= DW_IC_CMD_STOP;
+
+ if (need_restart) {
+- cmd |= BIT(10);
++ cmd |= DW_IC_CMD_RESTART;
+ need_restart = false;
+ }
+
+@@ -514,7 +517,8 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
+ if (rx_limit - dev->rx_outstanding <= 0)
+ break;
+
+- dw_writel(dev, cmd | 0x100, DW_IC_DATA_CMD);
++ dw_writel(dev, cmd | DW_IC_CMD_READ,
++ DW_IC_DATA_CMD);
+ rx_limit--;
+ dev->rx_outstanding++;
+ } else
+--
+1.7.7.6
+
--
1.9.1
More information about the linux-yocto
mailing list