[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