From patchwork Fri Dec 14 16:34:08 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Felipe Balbi X-Patchwork-Id: 1879771 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork1.kernel.org (Postfix) with ESMTP id B8BFD40079 for ; Fri, 14 Dec 2012 16:46:51 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TjYLM-0000b4-9o; Fri, 14 Dec 2012 16:42:36 +0000 Received: from arroyo.ext.ti.com ([192.94.94.40]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1TjYKJ-0000Ir-Fs for linux-arm-kernel@lists.infradead.org; Fri, 14 Dec 2012 16:41:34 +0000 Received: from dlelxv30.itg.ti.com ([172.17.2.17]) by arroyo.ext.ti.com (8.13.7/8.13.7) with ESMTP id qBEGfS0g031013; Fri, 14 Dec 2012 10:41:28 -0600 Received: from DFLE73.ent.ti.com (dfle73.ent.ti.com [128.247.5.110]) by dlelxv30.itg.ti.com (8.13.8/8.13.8) with ESMTP id qBEGfSVm031710; Fri, 14 Dec 2012 10:41:28 -0600 Received: from dlelxv22.itg.ti.com (172.17.1.197) by dfle73.ent.ti.com (128.247.5.110) with Microsoft SMTP Server id 14.1.323.3; Fri, 14 Dec 2012 10:41:28 -0600 Received: from localhost (h79-2.vpn.ti.com [172.24.79.2]) by dlelxv22.itg.ti.com (8.13.8/8.13.8) with ESMTP id qBEGfRtW013176; Fri, 14 Dec 2012 10:41:28 -0600 From: Felipe Balbi To: Wolfram Sang Subject: [PATCH REBASE 5/6] i2c: omap: wait for transfer completion before sending STP bit Date: Fri, 14 Dec 2012 18:34:08 +0200 Message-ID: <1355502849-9289-6-git-send-email-balbi@ti.com> X-Mailer: git-send-email 1.8.1.rc1.5.g7e0651a In-Reply-To: <1355502849-9289-1-git-send-email-balbi@ti.com> References: <1355502849-9289-1-git-send-email-balbi@ti.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20121214_114131_755504_9A05E4EB X-CRM114-Status: GOOD ( 19.71 ) X-Spam-Score: -7.6 (-------) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-7.6 points) pts rule name description ---- ---------------------- -------------------------------------------------- -5.0 RCVD_IN_DNSWL_HI RBL: Sender listed at http://www.dnswl.org/, high trust [192.94.94.40 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -0.7 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: Tony Lindgren , Linux OMAP Mailing List , Felipe Balbi , linux-i2c@vger.kernel.org, Linux ARM Kernel Mailing List X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org Later patches will come adding support for reporting amount of bytes transferred so that client drivers can count how many bytes are left to transfer. This is useful mostly in case of NACKs when client driver wants to know exactly which byte got NACKed so it doesn't have to resend all bytes again. In order to make that work with OMAP's I2C controller, we need to prevent sending STP bit until message is transferred. The reason behind that is because OMAP_I2C_CNT_REG gets reset to original value after STP bit is shifted through I2C_SDA line and that would prevent us from reading the correct number of bytes left to transfer. The full programming model suggested by IP owner was the following: - start I2C transfer (without STP bit) - upon completion or NACK, read I2C_CNT register - write STP bit to I2C_CON register - wait for ARDY bit With this patch we're implementing all steps except step #2 which will come in a later patch series. In order to implement full NACK reporting we need to add a new field to struct i2c_msg, but that's still under discussion on what's the best way to do it. For now, we can prepare the driver to receive that piece of code. Signed-off-by: Felipe Balbi --- drivers/i2c/busses/i2c-omap.c | 92 ++++++++++++++++++------------------------- 1 file changed, 38 insertions(+), 54 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 039edc2..4d90f08 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -479,9 +479,9 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) } dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY | - OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK | - OMAP_I2C_IE_AL) | ((dev->fifo_size) ? - (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0); + OMAP_I2C_IE_NACK | OMAP_I2C_IE_AL) | + ((dev->fifo_size) ? (OMAP_I2C_IE_RDR | + OMAP_I2C_IE_XDR) : 0); dev->pscstate = psc; dev->scllstate = scll; @@ -511,6 +511,22 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev) return 0; } +static int omap_i2c_wait_for_ardy(struct omap_i2c_dev *dev) +{ + unsigned long timeout; + + timeout = jiffies + OMAP_I2C_TIMEOUT; + while (!(omap_i2c_read_irqstatus(dev) & OMAP_I2C_STAT_ARDY)) { + if (time_after(jiffies, timeout)) { + dev_warn(dev->dev, "timeout waiting for access ready\n"); + return -ETIMEDOUT; + } + usleep_range(800, 1200); + } + + return 0; +} + static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx) { u16 buf; @@ -558,6 +574,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, { struct omap_i2c_dev *dev = i2c_get_adapdata(adap); unsigned long timeout; + int ret = 0; u16 w; dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n", @@ -601,35 +618,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, if (!(msg->flags & I2C_M_RD)) w |= OMAP_I2C_CON_TRX; - if (!dev->b_hw && stop) - w |= OMAP_I2C_CON_STP; - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w); /* - * Don't write stt and stp together on some hardware. - */ - if (dev->b_hw && stop) { - unsigned long delay = jiffies + OMAP_I2C_TIMEOUT; - u16 con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG); - while (con & OMAP_I2C_CON_STT) { - con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG); - - /* Let the user know if i2c is in a bad state */ - if (time_after(jiffies, delay)) { - dev_err(dev->dev, "controller timed out " - "waiting for start condition to finish\n"); - return -ETIMEDOUT; - } - cpu_relax(); - } - - w |= OMAP_I2C_CON_STP; - w &= ~OMAP_I2C_CON_STT; - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w); - } - - /* * REVISIT: We should abort the transfer on signals, but the bus goes * into arbitration and we're currently unable to recover from it. */ @@ -639,31 +630,37 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, dev_err(dev->dev, "controller timed out\n"); omap_i2c_reset(dev); __omap_i2c_init(dev); - return -ETIMEDOUT; + ret = -ETIMEDOUT; + goto out; } - if (likely(!dev->cmd_err)) - return 0; - /* We have an error */ if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR | OMAP_I2C_STAT_XUDF)) { omap_i2c_reset(dev); __omap_i2c_init(dev); - return -EIO; + ret = -EIO; + goto out; } if (dev->cmd_err & OMAP_I2C_STAT_NACK) { if (msg->flags & I2C_M_IGNORE_NAK) return 0; - if (stop) { - w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG); - w |= OMAP_I2C_CON_STP; - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w); - } - return -EREMOTEIO; + + ret = -EREMOTEIO; + } + +out: + + if (stop) { + w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG); + w |= OMAP_I2C_CON_STP; + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w); + + ret = omap_i2c_wait_for_ardy(dev); } - return -EIO; + + return ret; } @@ -977,19 +974,6 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) break; } - /* - * ProDB0017052: Clear ARDY bit twice - */ - if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK | - OMAP_I2C_STAT_AL)) { - omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY | - OMAP_I2C_STAT_RDR | - OMAP_I2C_STAT_XRDY | - OMAP_I2C_STAT_XDR | - OMAP_I2C_STAT_ARDY)); - break; - } - if (stat & OMAP_I2C_STAT_RDR) { u8 num_bytes = 1;