From patchwork Thu Jan 1 18:02:13 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Douglas Gilbert X-Patchwork-Id: 5557581 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id E48CCBF6C3 for ; Thu, 1 Jan 2015 18:04:55 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id C4AED20212 for ; Thu, 1 Jan 2015 18:04:54 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 8581B201FE for ; Thu, 1 Jan 2015 18:04:53 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Y6k5E-0005d1-5I; Thu, 01 Jan 2015 18:02:52 +0000 Received: from smtp.infotech.no ([82.134.31.41]) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Y6k5A-0005bD-QK for linux-arm-kernel@lists.infradead.org; Thu, 01 Jan 2015 18:02:49 +0000 Received: from localhost (localhost [127.0.0.1]) by smtp.infotech.no (Postfix) with ESMTP id 368952041B4; Thu, 1 Jan 2015 19:02:24 +0100 (CET) X-Virus-Scanned: by amavisd-new-2.6.6 (20110518) (Debian) at infotech.no Received: from smtp.infotech.no ([127.0.0.1]) by localhost (smtp.infotech.no [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 7vH5FB771VYZ; Thu, 1 Jan 2015 19:02:22 +0100 (CET) Received: from [192.168.48.86] (host-23-251-191-45.dyn.295.ca [23.251.191.45]) by smtp.infotech.no (Postfix) with ESMTPA id 086C7204171; Thu, 1 Jan 2015 19:02:21 +0100 (CET) Message-ID: <54A58BA5.3080003@interlog.com> Date: Thu, 01 Jan 2015 13:02:13 -0500 From: Douglas Gilbert User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.3.0 MIME-Version: 1.0 To: linux-arm-kernel , Linux I2C Subject: [PATCH] at91: i2c-at91: improve time-out handling X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150101_100249_034061_C5AD431E X-CRM114-Status: GOOD ( 11.31 ) X-Spam-Score: 0.0 (/) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: dgilbert@interlog.com 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.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_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 With lk 3.19.0-rc2 and a at91sam9g25 (9x5) based system I connected a NXP SC16IS750 I2C to serial bridge. After routing the 750's IRQ back to the sc16is7xx driver and some simple successful test, it was time for some intense testing: Tx looped back to Rx on the 750, open picocom on /dev/ttySC0 at 38400, and use hexdump to blast a binary file (in hex) at ttySC0. The I2C SCL speed was 200,000 Hz. It worked as expected for a few seconds then it wedged the I2C bus. That was repeatable. In the cases that I checked SCL was high, SDA was low (driven by _both_ the G25's macrocell and the 750!!) and IRQ was active (low). This patch stopped the G25 macrocell from driving SDA low in the above wedge (and stopped copious error reports going to the log). I was surprised that a NXP I2C chip got into this situation, IMO SDA on a slave should have a driven low timeout. IMO all I2C master drivers should have provision to drive a gpio connected to a (or all the) slave's RESET line(s). ChangeLog: when handling an I2C bus time-out, first clean-up the DMA transfer, then do an I2C macrocell software reset and restore some registers, including the interrupt mask Signed-off-by: Douglas Gilbert diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 636fd2e..4d78708 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -382,6 +382,7 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) { int ret; bool has_unre_flag = dev->pdata->has_unre_flag; + bool timed_out = false; dev_dbg(dev->dev, "transfer: %s %d bytes.\n", (dev->msg->flags & I2C_M_RD) ? "read" : "write", dev->buf_len); @@ -440,7 +441,7 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) dev->adapter.timeout); if (ret == 0) { dev_err(dev->dev, "controller timed out\n"); - at91_init_twi_bus(dev); + timed_out = true; ret = -ETIMEDOUT; goto error; } @@ -471,6 +472,11 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) error: at91_twi_dma_cleanup(dev); + if (timed_out) { + at91_twi_irq_save(dev); + at91_init_twi_bus(dev); + at91_twi_irq_restore(dev); + } return ret; }