All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] i2c: designware: Avoid aborted transfers with fast reacting I2C slaves
@ 2016-09-29 13:04 Jarkko Nikula
  2016-09-30  7:05 ` Jukka Laitinen
  2016-10-25 10:10 ` Wolfram Sang
  0 siblings, 2 replies; 3+ messages in thread
From: Jarkko Nikula @ 2016-09-29 13:04 UTC (permalink / raw)
  To: linux-i2c
  Cc: Wolfram Sang, Andy Shevchenko, Mika Westerberg, Jukka Laitinen,
	Jarkko Nikula

I2C DesignWare may abort transfer with arbitration lost if I2C slave pulls
SDA down quickly after falling edge of SCL. Reason for this is unknown but
after trial and error it was found this can be avoided by enabling non-zero
SDA RX hold time for the receiver.

By the specification SDA RX hold time extends incoming SDA low to high
transition by n * ic_clk cycles but only when SCL is high. However it
seems to help avoid above faulty arbitration lost error.

Bits 23:16 in IC_SDA_HOLD register define the SDA RX hold time for the
receiver. Be conservative and enable 1 ic_clk cycle long hold time in
case boot firmware hasn't set it up.

Reported-by: Jukka Laitinen <jukka.laitinen@intel.com>
Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
---
 drivers/i2c/busses/i2c-designware-core.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
index 1fe93c43215c..11e866d05368 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -95,6 +95,9 @@
 #define DW_IC_STATUS_TFE		BIT(2)
 #define DW_IC_STATUS_MST_ACTIVITY	BIT(5)
 
+#define DW_IC_SDA_HOLD_RX_SHIFT		16
+#define DW_IC_SDA_HOLD_RX_MASK		GENMASK(23, DW_IC_SDA_HOLD_RX_SHIFT)
+
 #define DW_IC_ERR_TX_ABRT	0x1
 
 #define DW_IC_TAR_10BITADDR_MASTER BIT(12)
@@ -420,12 +423,20 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
 	/* Configure SDA Hold Time if required */
 	reg = dw_readl(dev, DW_IC_COMP_VERSION);
 	if (reg >= DW_IC_SDA_HOLD_MIN_VERS) {
-		if (dev->sda_hold_time) {
-			dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
-		} else {
+		if (!dev->sda_hold_time) {
 			/* Keep previous hold time setting if no one set it */
 			dev->sda_hold_time = dw_readl(dev, DW_IC_SDA_HOLD);
 		}
+		/*
+		 * Workaround for avoiding TX arbitration lost in case I2C
+		 * slave pulls SDA down "too quickly" after falling egde of
+		 * SCL by enabling non-zero SDA RX hold. Specification says it
+		 * extends incoming SDA low to high transition while SCL is
+		 * high but it apprears to help also above issue.
+		 */
+		if (!(dev->sda_hold_time & DW_IC_SDA_HOLD_RX_MASK))
+			dev->sda_hold_time |= 1 << DW_IC_SDA_HOLD_RX_SHIFT;
+		dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
 	} else {
 		dev_warn(dev->dev,
 			"Hardware too old to adjust SDA hold time.\n");
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] i2c: designware: Avoid aborted transfers with fast reacting I2C slaves
  2016-09-29 13:04 [PATCH] i2c: designware: Avoid aborted transfers with fast reacting I2C slaves Jarkko Nikula
@ 2016-09-30  7:05 ` Jukka Laitinen
  2016-10-25 10:10 ` Wolfram Sang
  1 sibling, 0 replies; 3+ messages in thread
From: Jukka Laitinen @ 2016-09-30  7:05 UTC (permalink / raw)
  To: Jarkko Nikula, linux-i2c; +Cc: Wolfram Sang, Andy Shevchenko, Mika Westerberg

On 29.09.2016 16:04, Jarkko Nikula wrote:
> By the specification SDA RX hold time extends incoming SDA low to high
> transition by n * ic_clk cycles but only when SCL is high. However it
> seems to help avoid above faulty arbitration lost error.
> 
> Bits 23:16 in IC_SDA_HOLD register define the SDA RX hold time for the
> receiver. Be conservative and enable 1 ic_clk cycle long hold time in
> case boot firmware hasn't set it up.
> 
> Reported-by: Jukka Laitinen <jukka.laitinen@intel.com>
> Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
> ---
>  drivers/i2c/busses/i2c-designware-core.c | 17 ++++++++++++++---
>  1 file changed, 14 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
> index 1fe93c43215c..11e866d05368 100644
> --- a/drivers/i2c/busses/i2c-designware-core.c
> +++ b/drivers/i2c/busses/i2c-designware-core.c
> @@ -95,6 +95,9 @@
>  #define DW_IC_STATUS_TFE		BIT(2)
>  #define DW_IC_STATUS_MST_ACTIVITY	BIT(5)
>  
> +#define DW_IC_SDA_HOLD_RX_SHIFT		16
> +#define DW_IC_SDA_HOLD_RX_MASK		GENMASK(23, DW_IC_SDA_HOLD_RX_SHIFT)
> +
>  #define DW_IC_ERR_TX_ABRT	0x1
>  
>  #define DW_IC_TAR_10BITADDR_MASTER BIT(12)
> @@ -420,12 +423,20 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
>  	/* Configure SDA Hold Time if required */
>  	reg = dw_readl(dev, DW_IC_COMP_VERSION);
>  	if (reg >= DW_IC_SDA_HOLD_MIN_VERS) {
> -		if (dev->sda_hold_time) {
> -			dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
> -		} else {
> +		if (!dev->sda_hold_time) {
>  			/* Keep previous hold time setting if no one set it */
>  			dev->sda_hold_time = dw_readl(dev, DW_IC_SDA_HOLD);
>  		}
> +		/*
> +		 * Workaround for avoiding TX arbitration lost in case I2C
> +		 * slave pulls SDA down "too quickly" after falling egde of
> +		 * SCL by enabling non-zero SDA RX hold. Specification says it
> +		 * extends incoming SDA low to high transition while SCL is
> +		 * high but it apprears to help also above issue.
> +		 */
> +		if (!(dev->sda_hold_time & DW_IC_SDA_HOLD_RX_MASK))
> +			dev->sda_hold_time |= 1 << DW_IC_SDA_HOLD_RX_SHIFT;
> +		dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
>  	} else {
>  		dev_warn(dev->dev,
>  			"Hardware too old to adjust SDA hold time.\n");
> 

Tested-by: Jukka Laitinen <jukka.laitinen@intel.com>

Tested with kabylake cpu and Ubuntu 16.04 + kernel 4.8-rc6 + ubuntu
sauce from http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.8-rc6/

Regards,
Jukka Laitinen

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] i2c: designware: Avoid aborted transfers with fast reacting I2C slaves
  2016-09-29 13:04 [PATCH] i2c: designware: Avoid aborted transfers with fast reacting I2C slaves Jarkko Nikula
  2016-09-30  7:05 ` Jukka Laitinen
@ 2016-10-25 10:10 ` Wolfram Sang
  1 sibling, 0 replies; 3+ messages in thread
From: Wolfram Sang @ 2016-10-25 10:10 UTC (permalink / raw)
  To: Jarkko Nikula; +Cc: linux-i2c, Andy Shevchenko, Mika Westerberg, Jukka Laitinen

[-- Attachment #1: Type: text/plain, Size: 902 bytes --]

On Thu, Sep 29, 2016 at 04:04:59PM +0300, Jarkko Nikula wrote:
> I2C DesignWare may abort transfer with arbitration lost if I2C slave pulls
> SDA down quickly after falling edge of SCL. Reason for this is unknown but
> after trial and error it was found this can be avoided by enabling non-zero
> SDA RX hold time for the receiver.
> 
> By the specification SDA RX hold time extends incoming SDA low to high
> transition by n * ic_clk cycles but only when SCL is high. However it
> seems to help avoid above faulty arbitration lost error.
> 
> Bits 23:16 in IC_SDA_HOLD register define the SDA RX hold time for the
> receiver. Be conservative and enable 1 ic_clk cycle long hold time in
> case boot firmware hasn't set it up.
> 
> Reported-by: Jukka Laitinen <jukka.laitinen@intel.com>
> Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>

Applied to for-current, thanks!


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2016-10-25 10:10 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-29 13:04 [PATCH] i2c: designware: Avoid aborted transfers with fast reacting I2C slaves Jarkko Nikula
2016-09-30  7:05 ` Jukka Laitinen
2016-10-25 10:10 ` Wolfram Sang

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.