From: Igor Mazanov <i.mazanov@gmail.com>
To: linux-omap@vger.kernel.org
Subject: Re: [PATCH] [RFC][OMAP3:I2C]Workaround for OMAP3430 I2C silicon errata 1.153
Date: Thu, 25 Jun 2009 21:17:32 +0400 [thread overview]
Message-ID: <h20bam$vnp$1@ger.gmane.org> (raw)
In-Reply-To: <7A436F7769CA33409C6B44B358BFFF0C0116011AC7@dlee02.ent.ti.com>
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
prev parent reply other threads:[~2009-06-25 17:15 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
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 message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='h20bam$vnp$1@ger.gmane.org' \
--to=i.mazanov@gmail.com \
--cc=linux-omap@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox