From patchwork Sat Dec 28 12:16:05 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 3413881 Return-Path: X-Original-To: patchwork-linux-media@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 8668DC02DD for ; Sat, 28 Dec 2013 12:17:36 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id A17EF2012B for ; Sat, 28 Dec 2013 12:17:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id BD02A20163 for ; Sat, 28 Dec 2013 12:17:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755276Ab3L1MQt (ORCPT ); Sat, 28 Dec 2013 07:16:49 -0500 Received: from bombadil.infradead.org ([198.137.202.9]:50199 "EHLO bombadil.infradead.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755245Ab3L1MQ2 (ORCPT ); Sat, 28 Dec 2013 07:16:28 -0500 Received: from [177.28.171.132] (helo=smtp.w2.samsung.com) by bombadil.infradead.org with esmtpsa (Exim 4.80.1 #2 (Red Hat Linux)) id 1Vwsoc-0002UM-2m; Sat, 28 Dec 2013 12:16:26 +0000 Received: from mchehab by smtp.w2.samsung.com with local (Exim 4.80.1) (envelope-from ) id 1VwsoU-0007sm-PZ; Sat, 28 Dec 2013 10:16:18 -0200 From: Mauro Carvalho Chehab Cc: Mauro Carvalho Chehab , Linux Media Mailing List , Mauro Carvalho Chehab Subject: [PATCH v3 13/24] em28xx: retry I2C ops if failed by timeout Date: Sat, 28 Dec 2013 10:16:05 -0200 Message-Id: <1388232976-20061-14-git-send-email-mchehab@redhat.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1388232976-20061-1-git-send-email-mchehab@redhat.com> References: <1388232976-20061-1-git-send-email-mchehab@redhat.com> To: unlisted-recipients:; (no To-header on input) Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Spam-Status: No, score=-7.5 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham 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: Mauro Carvalho Chehab At least on HVR-950, sometimes an I2C operation fails. This seems to be more frequent when the device is connected into an USB 3.0 port. Instead of report an error, try to repeat it, for up to 20 ms. That makes the code more reliable. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-i2c.c | 67 ++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 9fa7ed51e5b1..26f7b0a2e83a 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -181,6 +181,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, * Zero length reads always succeed, even if no device is connected */ +retry: /* Write to i2c device */ ret = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len); if (ret != len) { @@ -200,11 +201,8 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, ret = dev->em28xx_read_reg(dev, 0x05); if (ret == 0) /* success */ return len; - if (ret == 0x10) { - em28xx_warn("I2C transfer timeout on writing to addr 0x%02x", - addr); - return -ENODEV; - } + if (ret == 0x10) + goto retry; if (ret < 0) { em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n", ret); @@ -218,6 +216,11 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, */ } + if (ret == 0x10) { + em28xx_warn("I2C transfer timeout on writing to addr 0x%02x", + addr); + return -ENODEV; + } em28xx_warn("write to i2c device at 0x%x timed out\n", addr); return -EIO; } @@ -228,6 +231,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, */ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) { + unsigned long timeout = jiffies + msecs_to_jiffies(EM2800_I2C_XFER_TIMEOUT); int ret; if (len < 1 || len > 64) @@ -237,30 +241,35 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) * Zero length reads always succeed, even if no device is connected */ - /* Read data from i2c device */ - ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len); - if (ret < 0) { - em28xx_warn("reading from i2c device at 0x%x failed (error=%i)\n", - addr, ret); - return ret; - } - /* - * NOTE: some devices with two i2c busses have the bad habit to return 0 - * bytes if we are on bus B AND there was no write attempt to the - * specified slave address before AND no device is present at the - * requested slave address. - * Anyway, the next check will fail with -ENODEV in this case, so avoid - * spamming the system log on device probing and do nothing here. - */ - - /* Check success of the i2c operation */ - ret = dev->em28xx_read_reg(dev, 0x05); - if (ret == 0) /* success */ - return len; - if (ret < 0) { - em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n", - ret); - return ret; + while (time_is_after_jiffies(timeout)) { + /* Read data from i2c device */ + ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len); + if (ret < 0) { + em28xx_warn("reading from i2c device at 0x%x failed (error=%i)\n", + addr, ret); + return ret; + } + /* + * NOTE: some devices with two i2c busses have the bad habit to return 0 + * bytes if we are on bus B AND there was no write attempt to the + * specified slave address before AND no device is present at the + * requested slave address. + * Anyway, the next check will fail with -ENODEV in this case, so avoid + * spamming the system log on device probing and do nothing here. + */ + + /* Check success of the i2c operation */ + ret = dev->em28xx_read_reg(dev, 0x05); + if (ret == 0) /* success */ + return len; + if (ret < 0) { + em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n", + ret); + return ret; + } + if (ret != 0x10) + break; + msleep(5); } if (ret == 0x10) { em28xx_warn("I2C transfer timeout on read from addr 0x%02x", addr);