From patchwork Mon Jun 22 16:49:56 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Sonasath, Moiz" X-Patchwork-Id: 31822 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n5MGoBCY032312 for ; Mon, 22 Jun 2009 16:50:11 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750931AbZFVQuE (ORCPT ); Mon, 22 Jun 2009 12:50:04 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1751010AbZFVQuD (ORCPT ); Mon, 22 Jun 2009 12:50:03 -0400 Received: from devils.ext.ti.com ([198.47.26.153]:57476 "EHLO devils.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750931AbZFVQuB convert rfc822-to-8bit (ORCPT ); Mon, 22 Jun 2009 12:50:01 -0400 Received: from dlep33.itg.ti.com ([157.170.170.112]) by devils.ext.ti.com (8.13.7/8.13.7) with ESMTP id n5MGnxvD016581 for ; Mon, 22 Jun 2009 11:50:04 -0500 Received: from dlep20.itg.ti.com (localhost [127.0.0.1]) by dlep33.itg.ti.com (8.13.7/8.13.7) with ESMTP id n5MGnxTL014995 for ; Mon, 22 Jun 2009 11:49:59 -0500 (CDT) Received: from dlee75.ent.ti.com (localhost [127.0.0.1]) by dlep20.itg.ti.com (8.12.11/8.12.11) with ESMTP id n5MGnxew023962 for ; Mon, 22 Jun 2009 11:49:59 -0500 (CDT) Received: from dlee06.ent.ti.com ([157.170.170.11]) by dlee75.ent.ti.com ([157.170.170.72]) with mapi; Mon, 22 Jun 2009 11:49:59 -0500 From: "Sonasath, Moiz" To: "linux-omap@vger.kernel.org" CC: "Pandita, Vikram" Date: Mon, 22 Jun 2009 11:49:56 -0500 Subject: [PATCH] [RFC][OMAP3:I2C]Workaround for OMAP3430 I2C silicon errata 1.153 Thread-Topic: [PATCH] [RFC][OMAP3:I2C]Workaround for OMAP3430 I2C silicon errata 1.153 Thread-Index: AcnzWT2fRP+BJrSBSJ2HgAIzSLRejwAAA9UQ Message-ID: Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: acceptlanguage: en-US MIME-Version: 1.0 Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org 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 Signed-off by: Nishant Kamat Signed-off-by: Moiz Sonasath --- 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));