From patchwork Sun Sep 29 23:23:55 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 2962181 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 3790C9F288 for ; Sun, 29 Sep 2013 23:25:58 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 44CEC20263 for ; Sun, 29 Sep 2013 23:25:57 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 0F8FE20259 for ; Sun, 29 Sep 2013 23:25:56 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1VQQMZ-00039v-IV; Sun, 29 Sep 2013 23:25:19 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1VQQMQ-00056P-1S; Sun, 29 Sep 2013 23:25:10 +0000 Received: from mail-out.m-online.net ([212.18.0.9]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1VQQMI-00054Q-ED for linux-arm-kernel@lists.infradead.org; Sun, 29 Sep 2013 23:25:04 +0000 Received: from frontend1.mail.m-online.net (unknown [192.168.8.180]) by mail-out.m-online.net (Postfix) with ESMTP id 3cp2rP1Rt5z4KK47; Mon, 30 Sep 2013 01:24:21 +0200 (CEST) X-Auth-Info: A0pUEMOepLGrxDt4d1I9RTtTOELCDYQZHoq8wMQi7G8= Received: from chi.lan (unknown [195.140.253.167]) by smtp-auth.mnet-online.de (Postfix) with ESMTPA id 3cp2rN64lNzbbft; Mon, 30 Sep 2013 01:24:20 +0200 (CEST) From: Marek Vasut To: linux-i2c@vger.kernel.org Subject: [PATCH 3/3 V3] i2c: mxs: Fix PIO mode on i.MX23 Date: Mon, 30 Sep 2013 01:23:55 +0200 Message-Id: <1380497035-7457-3-git-send-email-marex@denx.de> X-Mailer: git-send-email 1.8.4.rc3 In-Reply-To: <1380497035-7457-1-git-send-email-marex@denx.de> References: <1380497035-7457-1-git-send-email-marex@denx.de> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130929_192502_827192_416E1077 X-CRM114-Status: GOOD ( 15.04 ) X-Spam-Score: -1.9 (-) Cc: Marek Vasut , Christoph Baumann , Wolfram Sang , Torsten Fleischer , Fabio Estevam , Alexandre Belloni , Shawn Guo , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.8 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The i.MX23 I2C controller is also capable of PIO, but needs a little harder push to behave. The controller needs to be reset after every PIO/DMA operation for some reason, otherwise in rare cases, the controller can hang or emit bytes onto the bus. Signed-off-by: Marek Vasut Cc: Alexandre Belloni Cc: Christoph Baumann Cc: Fabio Estevam Cc: Shawn Guo Cc: Torsten Fleischer Cc: Wolfram Sang --- drivers/i2c/busses/i2c-mxs.c | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) V3: No change diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index f986ff8..0e297e4 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -35,10 +35,12 @@ #define MXS_I2C_CTRL0 (0x00) #define MXS_I2C_CTRL0_SET (0x04) +#define MXS_I2C_CTRL0_CLR (0x08) #define MXS_I2C_CTRL0_SFTRST 0x80000000 #define MXS_I2C_CTRL0_RUN 0x20000000 #define MXS_I2C_CTRL0_SEND_NAK_ON_LAST 0x02000000 +#define MXS_I2C_CTRL0_PIO_MODE 0x01000000 #define MXS_I2C_CTRL0_RETAIN_CLOCK 0x00200000 #define MXS_I2C_CTRL0_POST_SEND_STOP 0x00100000 #define MXS_I2C_CTRL0_PRE_SEND_START 0x00080000 @@ -69,10 +71,9 @@ #define MXS_I2C_STAT_BUS_BUSY 0x00000800 #define MXS_I2C_STAT_CLK_GEN_BUSY 0x00000400 -#define MXS_I2C_DATA (0xa0) +#define MXS_I2C_DATA(i2c) ((i2c->dev_type == MXS_I2C_V1) ? 0x60 : 0xa0) -#define MXS_I2C_DEBUG0 (0xb0) -#define MXS_I2C_DEBUG0_CLR (0xb8) +#define MXS_I2C_DEBUG0_CLR(i2c) ((i2c->dev_type == MXS_I2C_V1) ? 0x78 : 0xb8) #define MXS_I2C_DEBUG0_DMAREQ 0x80000000 @@ -355,7 +356,11 @@ static void mxs_i2c_pio_trigger_write_cmd(struct mxs_i2c_dev *i2c, u32 cmd, u32 data) { writel(cmd, i2c->regs + MXS_I2C_CTRL0); - writel(data, i2c->regs + MXS_I2C_DATA); + + if (i2c->dev_type == MXS_I2C_V1) + writel(MXS_I2C_CTRL0_PIO_MODE, i2c->regs + MXS_I2C_CTRL0_SET); + + writel(data, i2c->regs + MXS_I2C_DATA(i2c)); writel(MXS_I2C_CTRL0_RUN, i2c->regs + MXS_I2C_CTRL0_SET); } @@ -388,7 +393,6 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, * NOTE: The CTRL0::PIO_MODE description is important, since * it outlines how the PIO mode is really supposed to work. */ - if (msg->flags & I2C_M_RD) { /* * PIO READ transfer: @@ -428,7 +432,7 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, goto cleanup; } - data = readl(i2c->regs + MXS_I2C_DATA); + data = readl(i2c->regs + MXS_I2C_DATA(i2c)); for (i = 0; i < msg->len; i++) { msg->buf[i] = data & 0xff; data >>= 8; @@ -507,7 +511,7 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, start & MXS_I2C_CTRL0_RETAIN_CLOCK ? "C": ""); writel(MXS_I2C_DEBUG0_DMAREQ, - i2c->regs + MXS_I2C_DEBUG0_CLR); + i2c->regs + MXS_I2C_DEBUG0_CLR(i2c)); mxs_i2c_pio_trigger_write_cmd(i2c, start | MXS_I2C_CTRL0_MASTER_MODE | @@ -543,6 +547,10 @@ cleanup: writel(MXS_I2C_IRQ_MASK, i2c->regs + MXS_I2C_CTRL1_CLR); writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET); + /* Clear the PIO_MODE on i.MX23 */ + if (i2c->dev_type == MXS_I2C_V1) + writel(MXS_I2C_CTRL0_PIO_MODE, i2c->regs + MXS_I2C_CTRL0_CLR); + return ret; } @@ -575,10 +583,6 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, if (!(msg->flags & I2C_M_RD) && (msg->len < 7)) use_pio = 1; - /* Disable PIO on MX23. */ - if (i2c->dev_type == MXS_I2C_V1) - use_pio = 0; - i2c->cmd_err = 0; if (use_pio) { ret = mxs_i2c_pio_setup_xfer(adap, msg, flags); @@ -608,6 +612,20 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, i2c->regs + MXS_I2C_CTRL1_SET); } + /* + * WARNING! + * The i.MX23 is strange. After each and every operation, it's I2C IP + * block must be reset, otherwise the IP block will misbehave. This can + * be observed on the bus by the block sending out one single byte onto + * the bus. In case such an error happens, bit 27 will be set in the + * DEBUG0 register. This bit is not documented in the i.MX23 datasheet + * and is marked as "TBD" instead. To reset this bit to a correct state, + * reset the whole block. Since the block reset does not take long, do + * reset the block after every transfer to play safe. + */ + if (i2c->dev_type == MXS_I2C_V1) + mxs_i2c_reset(i2c); + dev_dbg(i2c->dev, "Done with err=%d\n", ret); return ret;