From patchwork Fri Feb 7 08:54:09 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naveen Krishna Chatradhi X-Patchwork-Id: 3600321 Return-Path: X-Original-To: patchwork-linux-samsung-soc@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 7DDA99F344 for ; Fri, 7 Feb 2014 08:54:32 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 8E6C020117 for ; Fri, 7 Feb 2014 08:54:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 0052C20115 for ; Fri, 7 Feb 2014 08:54:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751233AbaBGIy3 (ORCPT ); Fri, 7 Feb 2014 03:54:29 -0500 Received: from mailout3.samsung.com ([203.254.224.33]:27423 "EHLO mailout3.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751077AbaBGIy2 (ORCPT ); Fri, 7 Feb 2014 03:54:28 -0500 Received: from epcpsbgr5.samsung.com (u145.gpu120.samsung.co.kr [203.254.230.145]) by mailout3.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0N0M005YFBEQU060@mailout3.samsung.com>; Fri, 07 Feb 2014 17:54:26 +0900 (KST) Received: from epcpsbgm2.samsung.com ( [172.20.52.123]) by epcpsbgr5.samsung.com (EPCPMTA) with SMTP id 1C.2D.14803.24F94F25; Fri, 07 Feb 2014 17:54:26 +0900 (KST) X-AuditID: cbfee691-b7efc6d0000039d3-a2-52f49f42a84b Received: from epmmp2 ( [203.254.227.17]) by epcpsbgm2.samsung.com (EPCPMTA) with SMTP id BF.A3.28157.24F94F25; Fri, 07 Feb 2014 17:54:26 +0900 (KST) Received: from chnaveen-ubuntu.sisodomain.com ([107.108.83.161]) by mmp2.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0N0M00F6IBELA530@mmp2.samsung.com>; Fri, 07 Feb 2014 17:54:26 +0900 (KST) From: Naveen Krishna Chatradhi To: linux-i2c@vger.kernel.org Cc: linux-samsung-soc@vger.kernel.org, naveenkrishna.ch@gmail.com, wsa@the-dreams.de, ben-linux@fluff.org, cpgs@samsung.com, sjg@chromium.org, grundler@chromium.org Subject: [PATCH] i2c-s3c2410: Leave the bus disabled unless it is in use Date: Fri, 07 Feb 2014 14:24:09 +0530 Message-id: <1391763249-28964-1-git-send-email-ch.naveen@samsung.com> X-Mailer: git-send-email 1.7.9.5 In-reply-to: <1354165536-18529-2-git-send-email-ch.naveen@samsung.com> References: <1354165536-18529-2-git-send-email-ch.naveen@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFvrHLMWRmVeSWpSXmKPExsWyRsSkWtdp/pcgg+UHNSwmrTvAZPHykKbF qyM/mCw6/n5htJhxfh+TxaJt/5ktvm3Zxmix8sQsZgcOj9kNF1k8/q56weyxc9Zddo++LasY PU6eesLi8XmTXABbFJdNSmpOZllqkb5dAlfG3tOtjAUHFCpOfrrE3MC4S6qLkZNDQsBEYkbD B1YIW0ziwr31bF2MXBxCAksZJaZMfsUEU3Rw0jywIiGB6YwS/+ebQxT1M0l87/gLlmATMJM4 uGg1O4gtIiAr0fpgDTOIzSywglFi6TJJEFtYwEPiSttpsBoWAVWJvt4FYL28Aq4SH7cvY+li 5ABapiAxZ5INSJhTwE3i5u4rzBB7XSXuLT4FdpyEwCp2iWuvZrNCzBGQ+Db5EFSvrMSmA8wQ N0tKHFxxg2UCo/ACRoZVjKKpBckFxUnpRaZ6xYm5xaV56XrJ+bmbGIFhf/rfs4k7GO8fsD7E mAw0biKzlGhyPjBu8kriDY3NjCxMTUyNjcwtzUgTVhLnTX+UFCQkkJ5YkpqdmlqQWhRfVJqT WnyIkYmDU6qBUfDg06o/W7wTLeUV2qVyHy3933TzAef2pYanDh469cdYa/0pfYbyf9M3q5zZ vFb/RNbUisnzn53ruZN5pYih7/jBjAsPelirJhlNN+lgvOp+K3hSe1P8qmNWKve641L1JovW v59f4xO0Y4td+bzdNwW3xfdN/firtJ1zMtu+mQJsb/WkeIVlu5VYijMSDbWYi4oTAS0RzpeR AgAA X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFrrNIsWRmVeSWpSXmKPExsVy+t9jQV2n+V+CDFZ+lrWYtO4Ak8XLQ5oW r478YLLo+PuF0WLG+X1MFou2/We2+LZlG6PFyhOzmB04PGY3XGTx+LvqBbPHzll32T36tqxi 9Dh56gmLx+dNcgFsUQ2MNhmpiSmpRQqpecn5KZl56bZK3sHxzvGmZgaGuoaWFuZKCnmJuam2 Si4+AbpumTlABykplCXmlAKFAhKLi5X07TBNCA1x07WAaYzQ9Q0JgusxMkADCWsYM/aebmUs OKBQcfLTJeYGxl1SXYycHBICJhIHJ81jhbDFJC7cW88GYgsJTGeU+D/fvIuRC8juZ5L43vEX rIhNwEzi4KLV7CC2iICsROuDNcwgNrPACkaJpcskQWxhAQ+JK22nwWpYBFQl+noXgPXyCrhK fNy+jKWLkQNomYLEnEk2IGFOATeJm7uvMEPsdZW4t/gU2wRG3gWMDKsYRVMLkguKk9JzjfSK E3OLS/PS9ZLzczcxgqPqmfQOxlUNFocYBTgYlXh4O2d+CRJiTSwrrsw9xCjBwawkwjt5BlCI NyWxsiq1KD++qDQntfgQYzLQUROZpUST84ERn1cSb2hsYm5qbGppYmFiZkmasJI478FW60Ah gfTEktTs1NSC1CKYLUwcnFINjIKzumIUgqU1S813eqrsOrNPY9qDtgN3sje/l3RZZXsoKXqr nezuOY+f1XtLtfBPMXkUVmm498W2mtC59iZZdx/eefPW5r9oe0XMlqcJQYE6+bfv8p/LdNFj feaV8PhO6JXr+R8VNEOrrz6fIT9FYY9eRH6K82y2x51RYodsTn3yeninwoDvkhJLcUaioRZz UXEiACZLjfzuAgAA DLP-Filter: Pass X-MTR: 20000000000000000@CPGS X-CFilter-Loop: Reflected Sender: linux-samsung-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-samsung-soc@vger.kernel.org X-Spam-Status: No, score=-7.4 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, 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 From: Simon Glass There is a rather odd feature of the exynos i2c controller that if it is left enabled, it can lock itself up with the clk line held low. This makes the bus unusable. Unfortunately, the s3c24xx_i2c_set_master() function does not notice this, and reports a timeout. From then on the bus cannot be used until the AP is rebooted. The problem happens when any sort of interrupt occurs (e.g. due to a bus transition) when we are not in the middle of a transaction. We have seen many instances of this when U-Boot leaves the bus apparently happy, but Linux cannot access it. The current code is therefore pretty fragile. This fixes things by leaving the bus disabled unless we are actually in a transaction. We enable the bus at the start of the transaction and disable it at the end. That way we won't get interrupts and will not lock up the bus. It might be possible to clear pending interrupts on start-up, but this seems to be a more robust solution. We can't service interrupts when we are not in a transaction, and anyway would rather not lock up the bus while we try. Signed-off-by: Simon Glass Cc: Grant Grundler Signed-off-by: Naveen Krishna Chatradhi Acked-by: Kyungmin Park --- drivers/i2c/busses/i2c-s3c2410.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 684d21e..9d39511 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -601,6 +601,31 @@ static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id) return IRQ_HANDLED; } +/* + * Disable the bus so that we won't get any interrupts from now on, or try + * to drive any lines. This is the default state when we don't have + * anything to send/receive. + * + * If there is an event on the bus, or we have a pre-existing event at + * kernel boot time, we may not notice the event and the I2C controller + * will lock the bus with the I2C clock line low indefinitely. + */ +static inline void s3c24xx_i2c_disable_bus(struct s3c24xx_i2c *i2c) +{ + unsigned long tmp; + + /* Stop driving the I2C pins */ + tmp = readl(i2c->regs + S3C2410_IICSTAT); + tmp &= ~S3C2410_IICSTAT_TXRXEN; + writel(tmp, i2c->regs + S3C2410_IICSTAT); + + /* We don't expect any interrupts now, and don't want send acks */ + tmp = readl(i2c->regs + S3C2410_IICCON); + tmp &= ~(S3C2410_IICCON_IRQEN | S3C2410_IICCON_IRQPEND | + S3C2410_IICCON_ACKEN); + writel(tmp, i2c->regs + S3C2410_IICCON); +} + /* s3c24xx_i2c_set_master * @@ -735,7 +760,11 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, s3c24xx_i2c_wait_idle(i2c); + s3c24xx_i2c_disable_bus(i2c); + out: + i2c->state = STATE_IDLE; + return ret; } @@ -1004,7 +1033,6 @@ static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c) static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) { - unsigned long iicon = S3C2410_IICCON_IRQEN | S3C2410_IICCON_ACKEN; struct s3c2410_platform_i2c *pdata; unsigned int freq; @@ -1018,12 +1046,12 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr); - writel(iicon, i2c->regs + S3C2410_IICCON); + writel(0, i2c->regs + S3C2410_IICCON); + writel(0, i2c->regs + S3C2410_IICSTAT); /* we need to work out the divisors for the clock... */ if (s3c24xx_i2c_clockrate(i2c, &freq) != 0) { - writel(0, i2c->regs + S3C2410_IICCON); dev_err(i2c->dev, "cannot meet bus frequency required\n"); return -EINVAL; } @@ -1031,7 +1059,8 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) /* todo - check that the i2c lines aren't being dragged anywhere */ dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq); - dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon); + dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02x\n", + readl(i2c->regs + S3C2410_IICCON)); return 0; }