From patchwork Wed Apr 27 09:44:39 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Glauber X-Patchwork-Id: 615489 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3qvw6v1xJ0z9t50 for ; Wed, 27 Apr 2016 19:45:11 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753577AbcD0JpJ (ORCPT ); Wed, 27 Apr 2016 05:45:09 -0400 Received: from mail-wm0-f68.google.com ([74.125.82.68]:36640 "EHLO mail-wm0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752438AbcD0JpI (ORCPT ); Wed, 27 Apr 2016 05:45:08 -0400 Received: by mail-wm0-f68.google.com with SMTP id w143so11119176wmw.3; Wed, 27 Apr 2016 02:45:07 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=uUQ3XY7KsZ13txg+nWwnoSAAzssY9CbXJRlXzElNW4U=; b=URYcORGiWdC2dwv8OR5tRn/syMJCKWmKooT5BqMEFEGFR7tuctsVwqqlWpfjrwJ24E L+KIw2m2HyK85e2t2h2mblYeki0FKqbXU7clTy0q+Rpi1YB7Ss1BJN6CkXIuAvlUy/WL U/Xyz/tVMZuD6dTQqPPVb3hBTczZIcIU4waGfHULIEM/yCjwt4fokOUxS9uI/v9KT8B4 T+9xYNwmSHZBUxi1uVPgSeg6g6vUhtSZuGY5CToCIv5Hz2PGDG7JUb+EDmD0IUgCTeKj TWL2deDw92Ah24m5t1z8ltfimkkfpLQs9gJrvzENHYtZ8tZ1Z1Zma83AeBaG0NXViJlN aKCA== X-Gm-Message-State: AOPr4FWC72oFASGP/u6YuVThpqSs7tz1+yzw7F71hqzfQDndSB/T4l7r+BqSQC5Bi1EBow== X-Received: by 10.28.158.15 with SMTP id h15mr8477031wme.35.1461750306694; Wed, 27 Apr 2016 02:45:06 -0700 (PDT) Received: from wintermute.fritz.box (HSI-KBW-46-223-158-165.hsi.kabel-badenwuerttemberg.de. [46.223.158.165]) by smtp.gmail.com with ESMTPSA id n66sm4965349wmf.6.2016.04.27.02.45.05 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 27 Apr 2016 02:45:06 -0700 (PDT) From: Jan Glauber To: Wolfram Sang Cc: linux-kernel@vger.kernel.org, linux-i2c@vger.kernel.org, David Daney , David Daney , Jan Glauber Subject: [PATCH] i2c: octeon: Add workaround for broken irqs on CN3860 Date: Wed, 27 Apr 2016 11:44:39 +0200 Message-Id: <1461750279-23654-1-git-send-email-jglauber@cavium.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <20160426211759.GD4587@katana> References: <20160426211759.GD4587@katana> Sender: linux-i2c-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-i2c@vger.kernel.org From: David Daney CN3860 does not interrupt the CPU when the i2c status changes. If we get a timeout, and see the status has in fact changed, we know we have this problem, and drop back to polling. Signed-off-by: David Daney Signed-off-by: Jan Glauber --- drivers/i2c/busses/i2c-octeon.c | 53 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c index 3144fe9..5b32a02 100644 --- a/drivers/i2c/busses/i2c-octeon.c +++ b/drivers/i2c/busses/i2c-octeon.c @@ -121,6 +121,8 @@ struct octeon_i2c { void __iomem *twsi_base; struct device *dev; bool hlc_enabled; + bool broken_irq_mode; + bool broken_irq_check; void (*int_enable)(struct octeon_i2c *); void (*int_disable)(struct octeon_i2c *); void (*hlc_int_enable)(struct octeon_i2c *); @@ -376,10 +378,32 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c) long time_left; bool first = 1; + /* + * Some chip revisions don't assert the irq in the interrupt + * controller. So we must poll for the IFLG change. + */ + if (i2c->broken_irq_mode) { + u64 end = get_jiffies_64() + i2c->adap.timeout; + + while (!octeon_i2c_test_iflg(i2c) && + time_before64(get_jiffies_64(), end)) + usleep_range(I2C_OCTEON_EVENT_WAIT / 2, I2C_OCTEON_EVENT_WAIT); + + return octeon_i2c_test_iflg(i2c) ? 0 : -ETIMEDOUT; + } + i2c->int_enable(i2c); time_left = wait_event_timeout(i2c->queue, octeon_i2c_test_ready(i2c, &first), i2c->adap.timeout); i2c->int_disable(i2c); + + if (i2c->broken_irq_check && !time_left && + octeon_i2c_test_iflg(i2c)) { + dev_err(i2c->dev, "broken irq connection detected, switching to polling mode.\n"); + i2c->broken_irq_mode = true; + return 0; + } + if (!time_left) return -ETIMEDOUT; @@ -493,15 +517,37 @@ static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c) bool first = 1; int time_left; + /* + * Some cn38xx boards don't assert the irq in the interrupt + * controller. So we must poll for the valid bit change. + */ + if (i2c->broken_irq_mode) { + u64 end = get_jiffies_64() + i2c->adap.timeout; + + while (!octeon_i2c_hlc_test_valid(i2c) && + time_before64(get_jiffies_64(), end)) + usleep_range(I2C_OCTEON_EVENT_WAIT / 2, I2C_OCTEON_EVENT_WAIT); + + return octeon_i2c_hlc_test_valid(i2c) ? 0 : -ETIMEDOUT; + } + i2c->hlc_int_enable(i2c); time_left = wait_event_timeout(i2c->queue, octeon_i2c_hlc_test_ready(i2c, &first), i2c->adap.timeout); i2c->hlc_int_disable(i2c); - if (!time_left) { + if (!time_left) octeon_i2c_hlc_int_clear(i2c); - return -ETIMEDOUT; + + if (i2c->broken_irq_check && !time_left && + octeon_i2c_hlc_test_valid(i2c)) { + dev_err(i2c->dev, "broken irq connection detected, switching to polling mode.\n"); + i2c->broken_irq_mode = true; + return 0; } + + if (!time_left) + return -ETIMEDOUT; return 0; } @@ -1136,6 +1182,9 @@ static int octeon_i2c_probe(struct platform_device *pdev) goto out; } + if (OCTEON_IS_MODEL(OCTEON_CN38XX)) + i2c->broken_irq_check = true; + result = octeon_i2c_init_lowlevel(i2c); if (result) { dev_err(i2c->dev, "init low level failed\n");