public inbox for linux-omap@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] [RFC][OMAP3:I2C]Workaround for OMAP3430 I2C silicon errata 1.153
@ 2009-06-22 16:49 Sonasath, Moiz
  2009-06-22 22:30 ` Kevin Hilman
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Sonasath, Moiz @ 2009-06-22 16:49 UTC (permalink / raw)
  To: linux-omap@vger.kernel.org; +Cc: Pandita, Vikram

This patch includes the workarround for I2C Errata 1.153: When an XRDY/XDR is hit, wait for XUDF before writing data to DATA_REG

Signed-off-by: Jagadeesh Bhaskar Pakaravoor <j-pakaravoor@ti.com>
Signed-off by: Nishant Kamat <nskamat@ti.com>
Signed-off-by: Moiz Sonasath<m-sonasath@ti.com>
---
 drivers/i2c/busses/i2c-omap.c |   54 +++++++++++++++++++++++++++++++++++++---
 1 files changed, 50 insertions(+), 4 deletions(-)

diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index ece0125..e84836b 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -632,6 +632,37 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id)
 #define omap_i2c_rev1_isr		NULL
 #endif
 
+/* I2C Errata 1.153:
+ * When an XRDY/XDR is hit, wait for XUDF before writing data to DATA_REG.
+ * Otherwise some data bytes can be lost while transferring them from the
+ * memory to the I2C interface.
+ */
+
+static int omap_i2c_wait_for_xudf(struct omap_i2c_dev *dev)
+{
+	u16 xudf;
+	int counter = 500;
+
+	/* We are in interrupt context. Wait for XUDF for max 7 msec */
+	xudf = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
+	while (!(xudf & OMAP_I2C_STAT_XUDF) && counter--) {
+		if (xudf & (OMAP_I2C_STAT_ROVR | OMAP_I2C_STAT_NACK |
+			    OMAP_I2C_STAT_AL))
+			return -EINVAL;
+		udelay(10);
+		xudf = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
+	}
+
+	if (!counter) {
+		/* Clear Tx FIFO */
+		omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG,
+				OMAP_I2C_BUF_TXFIF_CLR);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
 static irqreturn_t
 omap_i2c_isr(int this_irq, void *dev_id)
 {
@@ -639,6 +670,7 @@ omap_i2c_isr(int this_irq, void *dev_id)
 	u16 bits;
 	u16 stat, w;
 	int err, count = 0;
+	int error;
 
 	if (dev->idle)
 		return IRQ_NONE;
@@ -647,7 +679,7 @@ omap_i2c_isr(int this_irq, void *dev_id)
 	while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) {
 		dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat);
 		if (count++ == 100) {
-			dev_warn(dev->dev, "Too much work in one IRQ\n");
+			dev_dbg(dev->dev, "Too much work in one IRQ\n");
 			break;
 		}
 
@@ -715,11 +747,22 @@ omap_i2c_isr(int this_irq, void *dev_id)
 							OMAP_I2C_BUFSTAT_REG);
 			}
 			while (num_bytes) {
-				num_bytes--;
 				w = 0;
 				if (dev->buf_len) {
+					if (cpu_is_omap34xx()) {
+						/* OMAP3430 Errata 1.153 */
+						error = omap_i2c_wait_for_xudf(dev);
+						if (error) {
+							omap_i2c_ack_stat(dev, stat &
+								(OMAP_I2C_STAT_XRDY |
+								 OMAP_I2C_STAT_XDR));
+							dev_err(dev->dev, "Transmit error\n");
+							omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_XUDF);
+
+							return IRQ_HANDLED;
+						}
+					}
 					w = *dev->buf++;
-					dev->buf_len--;
 					/* Data reg from  2430 is 8 bit wide */
 					if (!cpu_is_omap2430() &&
 							!cpu_is_omap34xx()) {
@@ -728,6 +771,10 @@ omap_i2c_isr(int this_irq, void *dev_id)
 							dev->buf_len--;
 						}
 					}
+					omap_i2c_write_reg(dev,
+						OMAP_I2C_DATA_REG, w);
+					num_bytes--;
+					dev->buf_len--;
 				} else {
 					if (stat & OMAP_I2C_STAT_XRDY)
 						dev_err(dev->dev,
@@ -739,7 +786,6 @@ omap_i2c_isr(int this_irq, void *dev_id)
 							"data to send\n");
 					break;
 				}
-				omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
 			}
 			omap_i2c_ack_stat(dev,
 				stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
-- 
1.5.6.3


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

* Re: [PATCH] [RFC][OMAP3:I2C]Workaround for OMAP3430 I2C silicon errata 1.153
  2009-06-22 16:49 [PATCH] [RFC][OMAP3:I2C]Workaround for OMAP3430 I2C silicon errata 1.153 Sonasath, Moiz
@ 2009-06-22 22:30 ` Kevin Hilman
  2009-06-23  9:55   ` Kamat, Nishant
  2009-06-23  2:17 ` Paul Walmsley
  2009-06-23  4:20 ` Menon, Nishanth
  2 siblings, 1 reply; 11+ messages in thread
From: Kevin Hilman @ 2009-06-22 22:30 UTC (permalink / raw)
  To: Sonasath, Moiz; +Cc: linux-omap@vger.kernel.org, Pandita, Vikram

"Sonasath, Moiz" <m-sonasath@ti.com> writes:

> This patch includes the workarround for I2C Errata 1.153: When an XRDY/XDR is hit, wait for XUDF before writing data to DATA_REG

How was this tested/validated, on what platforms etc.

> Signed-off-by: Jagadeesh Bhaskar Pakaravoor <j-pakaravoor@ti.com>
> Signed-off by: Nishant Kamat <nskamat@ti.com>
> Signed-off-by: Moiz Sonasath<m-sonasath@ti.com>
> ---
>  drivers/i2c/busses/i2c-omap.c |   54 +++++++++++++++++++++++++++++++++++++---
>  1 files changed, 50 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
> index ece0125..e84836b 100644
> --- a/drivers/i2c/busses/i2c-omap.c
> +++ b/drivers/i2c/busses/i2c-omap.c
> @@ -632,6 +632,37 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id)
>  #define omap_i2c_rev1_isr		NULL
>  #endif
>  
> +/* I2C Errata 1.153:
> + * When an XRDY/XDR is hit, wait for XUDF before writing data to DATA_REG.
> + * Otherwise some data bytes can be lost while transferring them from the
> + * memory to the I2C interface.
> + */
> +
> +static int omap_i2c_wait_for_xudf(struct omap_i2c_dev *dev)
> +{
> +	u16 xudf;
> +	int counter = 500;
> +
> +	/* We are in interrupt context. Wait for XUDF for max 7 msec */

What does being in interrupt context have to do with how long you
wait?  Threaded interrupts are now in mainline and will become the
default, so this ISR may run in thread context.


> +	xudf = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
> +	while (!(xudf & OMAP_I2C_STAT_XUDF) && counter--) {
> +		if (xudf & (OMAP_I2C_STAT_ROVR | OMAP_I2C_STAT_NACK |
> +			    OMAP_I2C_STAT_AL))
> +			return -EINVAL;
> +		udelay(10);
> +		xudf = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
> +	}
> +
> +	if (!counter) {
> +		/* Clear Tx FIFO */
> +		omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG,
> +				OMAP_I2C_BUF_TXFIF_CLR);
> +		return -ETIMEDOUT;
> +	}
> +
> +	return 0;
> +}
> +
>  static irqreturn_t
>  omap_i2c_isr(int this_irq, void *dev_id)
>  {
> @@ -639,6 +670,7 @@ omap_i2c_isr(int this_irq, void *dev_id)
>  	u16 bits;
>  	u16 stat, w;
>  	int err, count = 0;
> +	int error;
>  
>  	if (dev->idle)
>  		return IRQ_NONE;
> @@ -647,7 +679,7 @@ omap_i2c_isr(int this_irq, void *dev_id)
>  	while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) {
>  		dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat);
>  		if (count++ == 100) {
> -			dev_warn(dev->dev, "Too much work in one IRQ\n");
> +			dev_dbg(dev->dev, "Too much work in one IRQ\n");

Should stay as dev_warn I think.

>  			break;
>  		}
>  
> @@ -715,11 +747,22 @@ omap_i2c_isr(int this_irq, void *dev_id)
>  							OMAP_I2C_BUFSTAT_REG);
>  			}
>  			while (num_bytes) {
> -				num_bytes--;
>  				w = 0;
>  				if (dev->buf_len) {
> +					if (cpu_is_omap34xx()) {
> +						/* OMAP3430 Errata 1.153 */
> +						error = omap_i2c_wait_for_xudf(dev);
> +						if (error) {
> +							omap_i2c_ack_stat(dev, stat &
> +								(OMAP_I2C_STAT_XRDY |
> +								 OMAP_I2C_STAT_XDR));
> +							dev_err(dev->dev, "Transmit error\n");
> +							omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_XUDF);
> +
> +							return IRQ_HANDLED;
> +						}
> +					}

Yuck, too much wrapping here.  Running through checkpatch would've warned
you about this.  Looks like you need to break this out into a subroutine.


>  					w = *dev->buf++;
> -					dev->buf_len--;
>  					/* Data reg from  2430 is 8 bit wide */
>  					if (!cpu_is_omap2430() &&
>  							!cpu_is_omap34xx()) {
> @@ -728,6 +771,10 @@ omap_i2c_isr(int this_irq, void *dev_id)
>  							dev->buf_len--;
>  						}
>  					}
> +					omap_i2c_write_reg(dev,
> +						OMAP_I2C_DATA_REG, w);
> +					num_bytes--;
> +					dev->buf_len--;
>  				} else {
>  					if (stat & OMAP_I2C_STAT_XRDY)
>  						dev_err(dev->dev,
> @@ -739,7 +786,6 @@ omap_i2c_isr(int this_irq, void *dev_id)
>  							"data to send\n");
>  					break;
>  				}
> -				omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
>  			}
>  			omap_i2c_ack_stat(dev,
>  				stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
> -- 
> 1.5.6.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH] [RFC][OMAP3:I2C]Workaround for OMAP3430 I2C silicon errata 1.153
  2009-06-22 16:49 [PATCH] [RFC][OMAP3:I2C]Workaround for OMAP3430 I2C silicon errata 1.153 Sonasath, Moiz
  2009-06-22 22:30 ` Kevin Hilman
@ 2009-06-23  2:17 ` Paul Walmsley
  2009-07-08 16:50   ` Paul Walmsley
  2009-06-23  4:20 ` Menon, Nishanth
  2 siblings, 1 reply; 11+ messages in thread
From: Paul Walmsley @ 2009-06-23  2:17 UTC (permalink / raw)
  To: Sonasath, Moiz
  Cc: linux-omap@vger.kernel.org, j-pakaravoor, nskamat,
	Pandita, Vikram

Moiz, Nishant, Jagadeesh,

Looks like this patch has some serious problems.

On Mon, 22 Jun 2009, Sonasath, Moiz wrote:

> This patch includes the workarround for I2C Errata 1.153: When an 
> XRDY/XDR is hit, wait for XUDF before writing data to DATA_REG
> 
> Signed-off-by: Jagadeesh Bhaskar Pakaravoor <j-pakaravoor@ti.com>
> Signed-off by: Nishant Kamat <nskamat@ti.com>
> Signed-off-by: Moiz Sonasath<m-sonasath@ti.com>
> ---
>  drivers/i2c/busses/i2c-omap.c |   54 +++++++++++++++++++++++++++++++++++++---
>  1 files changed, 50 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
> index ece0125..e84836b 100644
> --- a/drivers/i2c/busses/i2c-omap.c
> +++ b/drivers/i2c/busses/i2c-omap.c
> @@ -632,6 +632,37 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id)
>  #define omap_i2c_rev1_isr		NULL
>  #endif
>  
> +/* I2C Errata 1.153:
> + * When an XRDY/XDR is hit, wait for XUDF before writing data to DATA_REG.
> + * Otherwise some data bytes can be lost while transferring them from the
> + * memory to the I2C interface.
> + */
> +
> +static int omap_i2c_wait_for_xudf(struct omap_i2c_dev *dev)
> +{
> +	u16 xudf;
> +	int counter = 500;

Shouldn't the timeout threshold depend on the I2C bus speed and transmit 
FIFO threshold?

> +
> +	/* We are in interrupt context. Wait for XUDF for max 7 msec */

There's no way an interrupt service routine should loop for up to 7 
milliseconds.  Why does it need to wait this long?  Shouldn't this patch 
zero the transmit FIFO threshold to minimize the amount of time between 
XRDY/XDR and XUDF?

> +	xudf = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
> +	while (!(xudf & OMAP_I2C_STAT_XUDF) && counter--) {

Why is a separate I2C_STAT loop used here?  Shouldn't this patch just use 
the existing I2C_STAT loop in the ISR and use a state variable to indicate 
the current state of the ISR?

> +		if (xudf & (OMAP_I2C_STAT_ROVR | OMAP_I2C_STAT_NACK |
> +			    OMAP_I2C_STAT_AL))
> +			return -EINVAL;
> +		udelay(10);

udelay() in an ISR is a big red flag.  Why is this needed?

> +		xudf = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
> +	}
> +
> +	if (!counter) {
> +		/* Clear Tx FIFO */
> +		omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG,
> +				OMAP_I2C_BUF_TXFIF_CLR);
> +		return -ETIMEDOUT;
> +	}
> +
> +	return 0;
> +}
> +
>  static irqreturn_t
>  omap_i2c_isr(int this_irq, void *dev_id)
>  {
> @@ -639,6 +670,7 @@ omap_i2c_isr(int this_irq, void *dev_id)
>  	u16 bits;
>  	u16 stat, w;
>  	int err, count = 0;
> +	int error;
>  
>  	if (dev->idle)
>  		return IRQ_NONE;
> @@ -647,7 +679,7 @@ omap_i2c_isr(int this_irq, void *dev_id)
>  	while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) {
>  		dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat);
>  		if (count++ == 100) {
> -			dev_warn(dev->dev, "Too much work in one IRQ\n");
> +			dev_dbg(dev->dev, "Too much work in one IRQ\n");
>  			break;
>  		}
>  
> @@ -715,11 +747,22 @@ omap_i2c_isr(int this_irq, void *dev_id)
>  							OMAP_I2C_BUFSTAT_REG);
>  			}
>  			while (num_bytes) {
> -				num_bytes--;
>  				w = 0;
>  				if (dev->buf_len) {
> +					if (cpu_is_omap34xx()) {
> +						/* OMAP3430 Errata 1.153 */

What about this I2C IP block on previous chip versions?  Is this problem 
also present on 2430, which also has FIFO transmit capability?

> +						error = omap_i2c_wait_for_xudf(dev);
> +						if (error) {
> +							omap_i2c_ack_stat(dev, stat &
> +								(OMAP_I2C_STAT_XRDY |
> +								 OMAP_I2C_STAT_XDR));
> +							dev_err(dev->dev, "Transmit error\n");
> +							omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_XUDF);
> +
> +							return IRQ_HANDLED;
> +						}
> +					}
>  					w = *dev->buf++;
> -					dev->buf_len--;
>  					/* Data reg from  2430 is 8 bit wide */
>  					if (!cpu_is_omap2430() &&
>  							!cpu_is_omap34xx()) {
> @@ -728,6 +771,10 @@ omap_i2c_isr(int this_irq, void *dev_id)
>  							dev->buf_len--;
>  						}
>  					}
> +					omap_i2c_write_reg(dev,
> +						OMAP_I2C_DATA_REG, w);
> +					num_bytes--;
> +					dev->buf_len--;
>  				} else {
>  					if (stat & OMAP_I2C_STAT_XRDY)
>  						dev_err(dev->dev,
> @@ -739,7 +786,6 @@ omap_i2c_isr(int this_irq, void *dev_id)
>  							"data to send\n");
>  					break;
>  				}
> -				omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
>  			}
>  			omap_i2c_ack_stat(dev,
>  				stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));


- Paul

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

* RE: [PATCH] [RFC][OMAP3:I2C]Workaround for OMAP3430 I2C silicon errata 1.153
  2009-06-22 16:49 [PATCH] [RFC][OMAP3:I2C]Workaround for OMAP3430 I2C silicon errata 1.153 Sonasath, Moiz
  2009-06-22 22:30 ` Kevin Hilman
  2009-06-23  2:17 ` Paul Walmsley
@ 2009-06-23  4:20 ` Menon, Nishanth
  2009-06-23 13:43   ` Igor Mazanov
  2 siblings, 1 reply; 11+ messages in thread
From: Menon, Nishanth @ 2009-06-23  4:20 UTC (permalink / raw)
  To: Sonasath, Moiz, linux-omap@vger.kernel.org; +Cc: Pandita, Vikram

> -----Original Message-----
> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
> owner@vger.kernel.org] On Behalf Of Sonasath, Moiz
> Sent: Monday, June 22, 2009 7:50 PM
> To: linux-omap@vger.kernel.org
> Cc: Pandita, Vikram
> Subject: [PATCH] [RFC][OMAP3:I2C]Workaround for OMAP3430 I2C silicon
> errata 1.153
> 
> This patch includes the workarround for I2C Errata 1.153: When an XRDY/XDR
> is hit, wait for XUDF before writing data to DATA_REG

Is this workaround valid for omap2430 also?

Regards,
Nishanth Menon

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

* RE: [PATCH] [RFC][OMAP3:I2C]Workaround for OMAP3430 I2C silicon errata 1.153
  2009-06-22 22:30 ` Kevin Hilman
@ 2009-06-23  9:55   ` Kamat, Nishant
  2009-06-23 10:05     ` Menon, Nishanth
  0 siblings, 1 reply; 11+ messages in thread
From: Kamat, Nishant @ 2009-06-23  9:55 UTC (permalink / raw)
  To: Kevin Hilman, Sonasath, Moiz; +Cc: linux-omap@vger.kernel.org, Pandita, Vikram

Kevin, 

> -----Original Message-----
> From: Kevin Hilman
>
> "Sonasath, Moiz" <m-sonasath@ti.com> writes:
> 
> > This patch includes the workarround for I2C Errata 1.153: 
[...]

> > +static int omap_i2c_wait_for_xudf(struct omap_i2c_dev *dev)
> > +{
> > +	u16 xudf;
> > +	int counter = 500;
> > +
> > +	/* We are in interrupt context. Wait for XUDF for max 7 msec */
> 
> What does being in interrupt context have to do with how long you
> wait?  Threaded interrupts are now in mainline and will become the
> default, so this ISR may run in thread context.

The interrupt context comment was meant to say that we can't sleep. Perhaps, with threaded interrupts that might not be true (I am not sure). We can remove the interrupt context comment.


> > @@ -647,7 +679,7 @@ omap_i2c_isr(int this_irq, void *dev_id)
> >  	while ((stat = (omap_i2c_read_reg(dev, 
> OMAP_I2C_STAT_REG))) & bits) {
> >  		dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat);
> >  		if (count++ == 100) {
> > -			dev_warn(dev->dev, "Too much work in 
> one IRQ\n");
> > +			dev_dbg(dev->dev, "Too much work in one IRQ\n");
> 
> Should stay as dev_warn I think.
> 

When I2C is used to transfer a large number of bytes continuously (e.g. during some camera sensor firmware update), we hit the max count more often now (because of the delay introduced by the workaround implementation). In this case, its undesirable to see the dev_warn messages fill up the console. Changing this to dev_dbg means that this message is not printed in the expected case.


Regards,
Nishant

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

* RE: [PATCH] [RFC][OMAP3:I2C]Workaround for OMAP3430 I2C silicon errata 1.153
  2009-06-23  9:55   ` Kamat, Nishant
@ 2009-06-23 10:05     ` Menon, Nishanth
  0 siblings, 0 replies; 11+ messages in thread
From: Menon, Nishanth @ 2009-06-23 10:05 UTC (permalink / raw)
  To: Kamat, Nishant, Kevin Hilman, Sonasath, Moiz
  Cc: linux-omap@vger.kernel.org, Pandita, Vikram

> -----Original Message-----
> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
> owner@vger.kernel.org] On Behalf Of Kamat, Nishant
> Sent: Tuesday, June 23, 2009 12:55 PM
> 
> > > @@ -647,7 +679,7 @@ omap_i2c_isr(int this_irq, void *dev_id)
> > >  	while ((stat = (omap_i2c_read_reg(dev,
> > OMAP_I2C_STAT_REG))) & bits) {
> > >  		dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat);
> > >  		if (count++ == 100) {
> > > -			dev_warn(dev->dev, "Too much work in
> > one IRQ\n");
> > > +			dev_dbg(dev->dev, "Too much work in one IRQ\n");
> >
> > Should stay as dev_warn I think.
> >
> 
> When I2C is used to transfer a large number of bytes continuously (e.g.
> during some camera sensor firmware update), we hit the max count more
> often now (because of the delay introduced by the workaround
> implementation). In this case, its undesirable to see the dev_warn
> messages fill up the console. Changing this to dev_dbg means that this
> message is not printed in the expected case.
Just wondering on this -> cant I do a multibyte write upto 255 bytes? Is count==100 not enough given that we used buffered writes? The real question is this:
Are devices expected to trigger retry logic to the extent where the error condition is triggered?

I think this might be an indication of something else being at fault with the sensor /configuration of sensor - hiding the error messages by moving warn->dbg is not correct IMHO.

Regards,
Nishanth Menon

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

* Re: [PATCH] [RFC][OMAP3:I2C]Workaround for OMAP3430 I2C silicon errata 1.153
  2009-06-23  4:20 ` Menon, Nishanth
@ 2009-06-23 13:43   ` Igor Mazanov
  2009-06-23 19:06     ` Menon, Nishanth
  0 siblings, 1 reply; 11+ messages in thread
From: Igor Mazanov @ 2009-06-23 13:43 UTC (permalink / raw)
  To: linux-omap

Hello,

Menon, Nishanth wrote:
>> -----Original Message-----
>> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
>> owner@vger.kernel.org] On Behalf Of Sonasath, Moiz
>> Sent: Monday, June 22, 2009 7:50 PM
>> To: linux-omap@vger.kernel.org
>> Cc: Pandita, Vikram
>> Subject: [PATCH] [RFC][OMAP3:I2C]Workaround for OMAP3430 I2C silicon
>> errata 1.153
>>
>> This patch includes the workarround for I2C Errata 1.153: When an XRDY/XDR
>> is hit, wait for XUDF before writing data to DATA_REG
> 
> Is this workaround valid for omap2430 also?

Some kind of such workaround needs to be applied and for OMAP1 ISR too. 
I had
the same problem on our OMAP5910 based custom made board. While writing 
a large contiguous amount of data constantly occurs a situation when 
dev->buf_len = 0, but I2C_CNT register != 0, and, as result, I2C 
controller doesn't generate ARDY IRQ, no complete_cmd occurs in ISR, and 
we get "controller timed out" issues then...

So, here is a part of modified OMAP1 ISR. It works for me at least.

/*
  * Is there a bug in the OMAP5910 I2C controller? It
  * generates a bunch of fake XRDY interrupts under high load.
  * As result, there is a very high chance to have a situation
  * when dev->buf_len = 0 already, but I2C_CNT != 0. So, there
  * is no ARDY irq then, no complete_cmd, controller timed out
  * issues...
  *
  * Workaround:
  *
  * When we get XRDY interrupt without transmit underflow flag
  * (XUDF bit in the I2C_STAT register), delay for 100 microsecs
  * and ignore it.
  *
  * We write data into I2C_DATA register in case of transmit
  * underflow condition ONLY.
  */
if (stat & OMAP_I2C_STAT_XRDY) {
	if (!(stat & OMAP_I2C_STAT_XUDF)) {
		udelay(100);
		continue;
	} else {
		w = 0;
		if (dev->buf_len) {
			w = *dev->buf++;
			dev->buf_len--;
			if (dev->buf_len) {
				w |= *dev->buf++ << 8;
				dev->buf_len--;
			}
			omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
		} else {
			dev_err(dev->dev, "XRDY IRQ while no "
						"data to send\n");
			break;
		}
		continue;
	}
}	

Regards,
Igor.


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

* RE: [PATCH] [RFC][OMAP3:I2C]Workaround for OMAP3430 I2C silicon errata 1.153
  2009-06-23 13:43   ` Igor Mazanov
@ 2009-06-23 19:06     ` Menon, Nishanth
  2009-06-25 17:17       ` Igor Mazanov
  0 siblings, 1 reply; 11+ messages in thread
From: Menon, Nishanth @ 2009-06-23 19:06 UTC (permalink / raw)
  To: i.mazanov@gmail.com, linux-omap@vger.kernel.org

> -----Original Message-----
> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
> owner@vger.kernel.org] On Behalf Of Igor Mazanov
> Sent: Tuesday, June 23, 2009 4:43 PM
> To: linux-omap@vger.kernel.org
> Subject: Re: [PATCH] [RFC][OMAP3:I2C]Workaround for OMAP3430 I2C silicon
> errata 1.153
> 
> /*
>   * Is there a bug in the OMAP5910 I2C controller? It
>   * generates a bunch of fake XRDY interrupts under high load.
>   * As result, there is a very high chance to have a situation
>   * when dev->buf_len = 0 already, but I2C_CNT != 0. So, there
>   * is no ARDY irq then, no complete_cmd, controller timed out
>   * issues...
>   *
>   * Workaround:
>   *
>   * When we get XRDY interrupt without transmit underflow flag
>   * (XUDF bit in the I2C_STAT register), delay for 100 microsecs
>   * and ignore it.
>   *
>   * We write data into I2C_DATA register in case of transmit
>   * underflow condition ONLY.
>   */
> if (stat & OMAP_I2C_STAT_XRDY) {
> 	if (!(stat & OMAP_I2C_STAT_XUDF)) {
> 		udelay(100);
> 		continue;
> 	} else {
> 		w = 0;
> 		if (dev->buf_len) {
> 			w = *dev->buf++;
> 			dev->buf_len--;
> 			if (dev->buf_len) {
> 				w |= *dev->buf++ << 8;
> 				dev->buf_len--;
> 			}
> 			omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
> 		} else {
> 			dev_err(dev->dev, "XRDY IRQ while no "
> 						"data to send\n");
> 			break;
> 		}
> 		continue;
> 	}
> }
> 
Could you submit a patch please?


Regards,
Nishanth Menon

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

* Re: [PATCH] [RFC][OMAP3:I2C]Workaround for OMAP3430 I2C silicon errata 1.153
  2009-06-23 19:06     ` Menon, Nishanth
@ 2009-06-25 17:17       ` Igor Mazanov
  0 siblings, 0 replies; 11+ messages in thread
From: Igor Mazanov @ 2009-06-25 17:17 UTC (permalink / raw)
  To: linux-omap

Menon, Nishanth wrote:
>> -----Original Message-----
>> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
>> owner@vger.kernel.org] On Behalf Of Igor Mazanov
>> Sent: Tuesday, June 23, 2009 4:43 PM
>> To: linux-omap@vger.kernel.org
>> Subject: Re: [PATCH] [RFC][OMAP3:I2C]Workaround for OMAP3430 I2C silicon
>> errata 1.153
>>
>> /*
>>   * Is there a bug in the OMAP5910 I2C controller? It
>>   * generates a bunch of fake XRDY interrupts under high load.
>>   * As result, there is a very high chance to have a situation
>>   * when dev->buf_len = 0 already, but I2C_CNT != 0. So, there
>>   * is no ARDY irq then, no complete_cmd, controller timed out
>>   * issues...
>>   *
>>   * Workaround:
>>   *
>>   * When we get XRDY interrupt without transmit underflow flag
>>   * (XUDF bit in the I2C_STAT register), delay for 100 microsecs
>>   * and ignore it.
>>   *
>>   * We write data into I2C_DATA register in case of transmit
>>   * underflow condition ONLY.
>>   */
>> if (stat & OMAP_I2C_STAT_XRDY) {
>> 	if (!(stat & OMAP_I2C_STAT_XUDF)) {
>> 		udelay(100);
>> 		continue;
>> 	} else {
>> 		w = 0;
>> 		if (dev->buf_len) {
>> 			w = *dev->buf++;
>> 			dev->buf_len--;
>> 			if (dev->buf_len) {
>> 				w |= *dev->buf++ << 8;
>> 				dev->buf_len--;
>> 			}
>> 			omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
>> 		} else {
>> 			dev_err(dev->dev, "XRDY IRQ while no "
>> 						"data to send\n");
>> 			break;
>> 		}
>> 		continue;
>> 	}
>> }
>>
> Could you submit a patch please?
>

OMAP1 I2C controller generates a huge amount of fake XRDY interrupts when large 
continuous blocks of data are transmitted via I2C. As result data have no time 
to be transmitted physically over I2C data line if we just look on XRDY bit 
before writing to I2C_DATA register. Taking into account a transmit underrun 
condition (XUDF bit in the I2C_STAT register) help us to transmit in more 
predictable way.

So,

Signed-off-by: Igor Mazanov <i.mazanov@gmail.com>
---
  drivers/i2c/busses/i2c-omap.c |  140 ++++++++++++++++++++++++++++------------
  1 files changed, 98 insertions(+), 42 deletions(-)

diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index ece0125..7464848 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -436,10 +436,15 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,

  	omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len);

-	/* Clear the FIFO Buffers */
-	w = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG);
-	w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR;
-	omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w);
+	/* Clear the FIFO Buffers
+	 * Useless for OMAP1 family - according TRMs (spru681b, spru760c),
+	 * FIFO are not controllable in this way
+	 */
+	if (!cpu_class_is_omap1()) {
+		w = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG);
+		w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR;
+		omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w);
+	}

  	init_completion(&dev->cmd_complete);
  	dev->cmd_err = 0;
@@ -578,55 +583,106 @@ static irqreturn_t
  omap_i2c_rev1_isr(int this_irq, void *dev_id)
  {
  	struct omap_i2c_dev *dev = dev_id;
-	u16 iv, w;
+	u16 bits;
+	u16 stat, w;
+	int err, count = 0;

  	if (dev->idle)
  		return IRQ_NONE;

-	iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);
-	switch (iv) {
-	case 0x00:	/* None */
-		break;
-	case 0x01:	/* Arbitration lost */
-		dev_err(dev->dev, "Arbitration lost\n");
-		omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL);
-		break;
-	case 0x02:	/* No acknowledgement */
-		omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK);
-		omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_STP);
-		break;
-	case 0x03:	/* Register access ready */
-		omap_i2c_complete_cmd(dev, 0);
-		break;
-	case 0x04:	/* Receive data ready */
-		if (dev->buf_len) {
+	bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
+	while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) {
+		dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat);
+		if (count++ == 200) {
+			dev_warn(dev->dev, "Too much work in one IRQ\n");
+			break;
+		}
+
+		omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);
+
+		err = 0;
+		if (stat & OMAP_I2C_STAT_NACK) {
+			err |= OMAP_I2C_STAT_NACK;
+			omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
+					   OMAP_I2C_CON_STP);
+		}
+		if (stat & OMAP_I2C_STAT_AL) {
+			dev_err(dev->dev, "Arbitration lost\n");
+			err |= OMAP_I2C_STAT_AL;
+		}
+		if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
+							OMAP_I2C_STAT_AL)) {
+				omap_i2c_complete_cmd(dev, err);
+				break;
+		}
+		if (stat & OMAP_I2C_STAT_RRDY) {
  			w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
-			*dev->buf++ = w;
-			dev->buf_len--;
  			if (dev->buf_len) {
-				*dev->buf++ = w >> 8;
+				*dev->buf++ = w;
  				dev->buf_len--;
+				if (dev->buf_len) {
+					*dev->buf++ = w >> 8;
+					dev->buf_len--;
+				}
+			} else {
+				dev_err(dev->dev, "RRDY IRQ while no data"
+							" requested\n");
+				break;
  			}
-		} else
-			dev_err(dev->dev, "RRDY IRQ while no data requested\n");
-		break;
-	case 0x05:	/* Transmit data ready */
-		if (dev->buf_len) {
-			w = *dev->buf++;
-			dev->buf_len--;
-			if (dev->buf_len) {
-				w |= *dev->buf++ << 8;
-				dev->buf_len--;
+			continue;
+		}
+		/*
+		 * Is there a bug in the OMAP5910 I2C controller? It
+		 * generates a bunch of fake XRDY interrupts under high load.
+		 * As result, there is a very high chance to have a situation
+		 * when dev->buf_len = 0 already, but I2C_CNT != 0. So, there
+		 * is no ARDY irq then, no complete_cmd, controller timed out
+		 * issues...
+		 *
+		 * Workaround:
+		 *
+		 * When we get XRDY interrupt without transmit underflow flag
+		 * (XUDF bit in the I2C_STAT register), delay for 100 microsecs
+		 * and ignore it.
+		 *
+		 * We write data into I2C_DATA register in case of transmit
+		 * underflow condition ONLY.
+		 */
+		if (stat & OMAP_I2C_STAT_XRDY) {
+			if (!(stat & OMAP_I2C_STAT_XUDF)) {
+				udelay(100);
+				continue;
+			} else {
+				w = 0;
+				if (dev->buf_len) {
+					w = *dev->buf++;
+					dev->buf_len--;
+					if (dev->buf_len) {
+						w |= *dev->buf++ << 8;
+						dev->buf_len--;
+					}
+					omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+				} else {
+					dev_err(dev->dev, "XRDY IRQ while no "
+							"data to send\n");
+					break;
+				}
+				continue;
  			}
-			omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
-		} else
-			dev_err(dev->dev, "XRDY IRQ while no data to send\n");
-		break;
-	default:
-		return IRQ_NONE;
+		}
+		/* REVISIT: Are this checks useful?
+		 * It looks like we will never hit in it... */
+		if (stat & OMAP_I2C_STAT_ROVR) {
+			dev_err(dev->dev, "Receive overrun\n");
+			dev->cmd_err |= OMAP_I2C_STAT_ROVR;
+		}
+		if (stat & OMAP_I2C_STAT_XUDF) {
+			dev_err(dev->dev, "Transmit underflow\n");
+			dev->cmd_err |= OMAP_I2C_STAT_XUDF;
+		}
  	}

-	return IRQ_HANDLED;
+	return count ? IRQ_HANDLED : IRQ_NONE;
  }
  #else
  #define omap_i2c_rev1_isr		NULL
-- 
1.6.0.1



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

* Re: [PATCH] [RFC][OMAP3:I2C]Workaround for OMAP3430 I2C silicon errata 1.153
  2009-06-23  2:17 ` Paul Walmsley
@ 2009-07-08 16:50   ` Paul Walmsley
  2009-07-08 18:21     ` Sonasath, Moiz
  0 siblings, 1 reply; 11+ messages in thread
From: Paul Walmsley @ 2009-07-08 16:50 UTC (permalink / raw)
  To: Sonasath, Moiz
  Cc: linux-omap@vger.kernel.org, j-pakaravoor, nskamat,
	Pandita, Vikram

Hello Moiz, Nishant, Jagadeesh,

Any plans to respond to these comments?  

- Paul

On Mon, 22 Jun 2009, Paul Walmsley wrote:

> Moiz, Nishant, Jagadeesh,
> 
> Looks like this patch has some serious problems.
> 
> On Mon, 22 Jun 2009, Sonasath, Moiz wrote:
> 
> > This patch includes the workarround for I2C Errata 1.153: When an 
> > XRDY/XDR is hit, wait for XUDF before writing data to DATA_REG
> > 
> > Signed-off-by: Jagadeesh Bhaskar Pakaravoor <j-pakaravoor@ti.com>
> > Signed-off by: Nishant Kamat <nskamat@ti.com>
> > Signed-off-by: Moiz Sonasath<m-sonasath@ti.com>
> > ---
> >  drivers/i2c/busses/i2c-omap.c |   54 +++++++++++++++++++++++++++++++++++++---
> >  1 files changed, 50 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
> > index ece0125..e84836b 100644
> > --- a/drivers/i2c/busses/i2c-omap.c
> > +++ b/drivers/i2c/busses/i2c-omap.c
> > @@ -632,6 +632,37 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id)
> >  #define omap_i2c_rev1_isr		NULL
> >  #endif
> >  
> > +/* I2C Errata 1.153:
> > + * When an XRDY/XDR is hit, wait for XUDF before writing data to DATA_REG.
> > + * Otherwise some data bytes can be lost while transferring them from the
> > + * memory to the I2C interface.
> > + */
> > +
> > +static int omap_i2c_wait_for_xudf(struct omap_i2c_dev *dev)
> > +{
> > +	u16 xudf;
> > +	int counter = 500;
> 
> Shouldn't the timeout threshold depend on the I2C bus speed and transmit 
> FIFO threshold?
> 
> > +
> > +	/* We are in interrupt context. Wait for XUDF for max 7 msec */
> 
> There's no way an interrupt service routine should loop for up to 7 
> milliseconds.  Why does it need to wait this long?  Shouldn't this patch 
> zero the transmit FIFO threshold to minimize the amount of time between 
> XRDY/XDR and XUDF?
> 
> > +	xudf = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
> > +	while (!(xudf & OMAP_I2C_STAT_XUDF) && counter--) {
> 
> Why is a separate I2C_STAT loop used here?  Shouldn't this patch just use 
> the existing I2C_STAT loop in the ISR and use a state variable to indicate 
> the current state of the ISR?
> 
> > +		if (xudf & (OMAP_I2C_STAT_ROVR | OMAP_I2C_STAT_NACK |
> > +			    OMAP_I2C_STAT_AL))
> > +			return -EINVAL;
> > +		udelay(10);
> 
> udelay() in an ISR is a big red flag.  Why is this needed?
> 
> > +		xudf = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
> > +	}
> > +
> > +	if (!counter) {
> > +		/* Clear Tx FIFO */
> > +		omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG,
> > +				OMAP_I2C_BUF_TXFIF_CLR);
> > +		return -ETIMEDOUT;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> >  static irqreturn_t
> >  omap_i2c_isr(int this_irq, void *dev_id)
> >  {
> > @@ -639,6 +670,7 @@ omap_i2c_isr(int this_irq, void *dev_id)
> >  	u16 bits;
> >  	u16 stat, w;
> >  	int err, count = 0;
> > +	int error;
> >  
> >  	if (dev->idle)
> >  		return IRQ_NONE;
> > @@ -647,7 +679,7 @@ omap_i2c_isr(int this_irq, void *dev_id)
> >  	while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) {
> >  		dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat);
> >  		if (count++ == 100) {
> > -			dev_warn(dev->dev, "Too much work in one IRQ\n");
> > +			dev_dbg(dev->dev, "Too much work in one IRQ\n");
> >  			break;
> >  		}
> >  
> > @@ -715,11 +747,22 @@ omap_i2c_isr(int this_irq, void *dev_id)
> >  							OMAP_I2C_BUFSTAT_REG);
> >  			}
> >  			while (num_bytes) {
> > -				num_bytes--;
> >  				w = 0;
> >  				if (dev->buf_len) {
> > +					if (cpu_is_omap34xx()) {
> > +						/* OMAP3430 Errata 1.153 */
> 
> What about this I2C IP block on previous chip versions?  Is this problem 
> also present on 2430, which also has FIFO transmit capability?
> 
> > +						error = omap_i2c_wait_for_xudf(dev);
> > +						if (error) {
> > +							omap_i2c_ack_stat(dev, stat &
> > +								(OMAP_I2C_STAT_XRDY |
> > +								 OMAP_I2C_STAT_XDR));
> > +							dev_err(dev->dev, "Transmit error\n");
> > +							omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_XUDF);
> > +
> > +							return IRQ_HANDLED;
> > +						}
> > +					}
> >  					w = *dev->buf++;
> > -					dev->buf_len--;
> >  					/* Data reg from  2430 is 8 bit wide */
> >  					if (!cpu_is_omap2430() &&
> >  							!cpu_is_omap34xx()) {
> > @@ -728,6 +771,10 @@ omap_i2c_isr(int this_irq, void *dev_id)
> >  							dev->buf_len--;
> >  						}
> >  					}
> > +					omap_i2c_write_reg(dev,
> > +						OMAP_I2C_DATA_REG, w);
> > +					num_bytes--;
> > +					dev->buf_len--;
> >  				} else {
> >  					if (stat & OMAP_I2C_STAT_XRDY)
> >  						dev_err(dev->dev,
> > @@ -739,7 +786,6 @@ omap_i2c_isr(int this_irq, void *dev_id)
> >  							"data to send\n");
> >  					break;
> >  				}
> > -				omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
> >  			}
> >  			omap_i2c_ack_stat(dev,
> >  				stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
> 
> 
> - Paul
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

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

* RE: [PATCH] [RFC][OMAP3:I2C]Workaround for OMAP3430 I2C silicon errata 1.153
  2009-07-08 16:50   ` Paul Walmsley
@ 2009-07-08 18:21     ` Sonasath, Moiz
  0 siblings, 0 replies; 11+ messages in thread
From: Sonasath, Moiz @ 2009-07-08 18:21 UTC (permalink / raw)
  To: Paul Walmsley
  Cc: linux-omap@vger.kernel.org, Pakaravoor, Jagadeesh, Kamat, Nishant,
	Pandita, Vikram

Hello Paul!

I am working on this issue and will get back soon.

Regards
Moiz Sonasath
Linux Baseport Team, Dallas
214-567-5514


-----Original Message-----
From: Paul Walmsley [mailto:paul@pwsan.com] 
Sent: Wednesday, July 08, 2009 11:51 AM
To: Sonasath, Moiz
Cc: linux-omap@vger.kernel.org; Pakaravoor, Jagadeesh; Kamat, Nishant; Pandita, Vikram
Subject: Re: [PATCH] [RFC][OMAP3:I2C]Workaround for OMAP3430 I2C silicon errata 1.153

Hello Moiz, Nishant, Jagadeesh,

Any plans to respond to these comments?  

- Paul

On Mon, 22 Jun 2009, Paul Walmsley wrote:

> Moiz, Nishant, Jagadeesh,
> 
> Looks like this patch has some serious problems.
> 
> On Mon, 22 Jun 2009, Sonasath, Moiz wrote:
> 
> > This patch includes the workarround for I2C Errata 1.153: When an 
> > XRDY/XDR is hit, wait for XUDF before writing data to DATA_REG
> > 
> > Signed-off-by: Jagadeesh Bhaskar Pakaravoor <j-pakaravoor@ti.com>
> > Signed-off by: Nishant Kamat <nskamat@ti.com>
> > Signed-off-by: Moiz Sonasath<m-sonasath@ti.com>
> > ---
> >  drivers/i2c/busses/i2c-omap.c |   54 +++++++++++++++++++++++++++++++++++++---
> >  1 files changed, 50 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
> > index ece0125..e84836b 100644
> > --- a/drivers/i2c/busses/i2c-omap.c
> > +++ b/drivers/i2c/busses/i2c-omap.c
> > @@ -632,6 +632,37 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id)
> >  #define omap_i2c_rev1_isr		NULL
> >  #endif
> >  
> > +/* I2C Errata 1.153:
> > + * When an XRDY/XDR is hit, wait for XUDF before writing data to DATA_REG.
> > + * Otherwise some data bytes can be lost while transferring them from the
> > + * memory to the I2C interface.
> > + */
> > +
> > +static int omap_i2c_wait_for_xudf(struct omap_i2c_dev *dev)
> > +{
> > +	u16 xudf;
> > +	int counter = 500;
> 
> Shouldn't the timeout threshold depend on the I2C bus speed and transmit 
> FIFO threshold?
> 
> > +
> > +	/* We are in interrupt context. Wait for XUDF for max 7 msec */
> 
> There's no way an interrupt service routine should loop for up to 7 
> milliseconds.  Why does it need to wait this long?  Shouldn't this patch 
> zero the transmit FIFO threshold to minimize the amount of time between 
> XRDY/XDR and XUDF?
> 
> > +	xudf = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
> > +	while (!(xudf & OMAP_I2C_STAT_XUDF) && counter--) {
> 
> Why is a separate I2C_STAT loop used here?  Shouldn't this patch just use 
> the existing I2C_STAT loop in the ISR and use a state variable to indicate 
> the current state of the ISR?
> 
> > +		if (xudf & (OMAP_I2C_STAT_ROVR | OMAP_I2C_STAT_NACK |
> > +			    OMAP_I2C_STAT_AL))
> > +			return -EINVAL;
> > +		udelay(10);
> 
> udelay() in an ISR is a big red flag.  Why is this needed?
> 
> > +		xudf = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
> > +	}
> > +
> > +	if (!counter) {
> > +		/* Clear Tx FIFO */
> > +		omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG,
> > +				OMAP_I2C_BUF_TXFIF_CLR);
> > +		return -ETIMEDOUT;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> >  static irqreturn_t
> >  omap_i2c_isr(int this_irq, void *dev_id)
> >  {
> > @@ -639,6 +670,7 @@ omap_i2c_isr(int this_irq, void *dev_id)
> >  	u16 bits;
> >  	u16 stat, w;
> >  	int err, count = 0;
> > +	int error;
> >  
> >  	if (dev->idle)
> >  		return IRQ_NONE;
> > @@ -647,7 +679,7 @@ omap_i2c_isr(int this_irq, void *dev_id)
> >  	while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) {
> >  		dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat);
> >  		if (count++ == 100) {
> > -			dev_warn(dev->dev, "Too much work in one IRQ\n");
> > +			dev_dbg(dev->dev, "Too much work in one IRQ\n");
> >  			break;
> >  		}
> >  
> > @@ -715,11 +747,22 @@ omap_i2c_isr(int this_irq, void *dev_id)
> >  							OMAP_I2C_BUFSTAT_REG);
> >  			}
> >  			while (num_bytes) {
> > -				num_bytes--;
> >  				w = 0;
> >  				if (dev->buf_len) {
> > +					if (cpu_is_omap34xx()) {
> > +						/* OMAP3430 Errata 1.153 */
> 
> What about this I2C IP block on previous chip versions?  Is this problem 
> also present on 2430, which also has FIFO transmit capability?
> 
> > +						error = omap_i2c_wait_for_xudf(dev);
> > +						if (error) {
> > +							omap_i2c_ack_stat(dev, stat &
> > +								(OMAP_I2C_STAT_XRDY |
> > +								 OMAP_I2C_STAT_XDR));
> > +							dev_err(dev->dev, "Transmit error\n");
> > +							omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_XUDF);
> > +
> > +							return IRQ_HANDLED;
> > +						}
> > +					}
> >  					w = *dev->buf++;
> > -					dev->buf_len--;
> >  					/* Data reg from  2430 is 8 bit wide */
> >  					if (!cpu_is_omap2430() &&
> >  							!cpu_is_omap34xx()) {
> > @@ -728,6 +771,10 @@ omap_i2c_isr(int this_irq, void *dev_id)
> >  							dev->buf_len--;
> >  						}
> >  					}
> > +					omap_i2c_write_reg(dev,
> > +						OMAP_I2C_DATA_REG, w);
> > +					num_bytes--;
> > +					dev->buf_len--;
> >  				} else {
> >  					if (stat & OMAP_I2C_STAT_XRDY)
> >  						dev_err(dev->dev,
> > @@ -739,7 +786,6 @@ omap_i2c_isr(int this_irq, void *dev_id)
> >  							"data to send\n");
> >  					break;
> >  				}
> > -				omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
> >  			}
> >  			omap_i2c_ack_stat(dev,
> >  				stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
> 
> 
> - Paul
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


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

end of thread, other threads:[~2009-07-08 18:22 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-06-22 16:49 [PATCH] [RFC][OMAP3:I2C]Workaround for OMAP3430 I2C silicon errata 1.153 Sonasath, Moiz
2009-06-22 22:30 ` Kevin Hilman
2009-06-23  9:55   ` Kamat, Nishant
2009-06-23 10:05     ` Menon, Nishanth
2009-06-23  2:17 ` Paul Walmsley
2009-07-08 16:50   ` Paul Walmsley
2009-07-08 18:21     ` Sonasath, Moiz
2009-06-23  4:20 ` Menon, Nishanth
2009-06-23 13:43   ` Igor Mazanov
2009-06-23 19:06     ` Menon, Nishanth
2009-06-25 17:17       ` Igor Mazanov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox