From patchwork Tue May 10 23:47:45 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Linus Walleij X-Patchwork-Id: 1440 Return-Path: Delivered-To: unknown Received: from imap.gmail.com (74.125.159.109) by localhost6.localdomain6 with IMAP4-SSL; 08 Jun 2011 14:51:59 -0000 Delivered-To: patches@linaro.org Received: by 10.224.61.3 with SMTP id r3cs38937qah; Tue, 10 May 2011 16:47:46 -0700 (PDT) Received: by 10.42.66.207 with SMTP id q15mr281994ici.359.1305071266176; Tue, 10 May 2011 16:47:46 -0700 (PDT) Received: from mail-iy0-f178.google.com (mail-iy0-f178.google.com [209.85.210.178]) by mx.google.com with ESMTPS id vt18si21273919icb.33.2011.05.10.16.47.46 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 10 May 2011 16:47:46 -0700 (PDT) Received-SPF: pass (google.com: domain of linus.ml.walleij@gmail.com designates 209.85.210.178 as permitted sender) client-ip=209.85.210.178; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linus.ml.walleij@gmail.com designates 209.85.210.178 as permitted sender) smtp.mail=linus.ml.walleij@gmail.com; dkim=pass (test mode) header.i=@gmail.com Received: by iyi12 with SMTP id 12so7230691iyi.37 for ; Tue, 10 May 2011 16:47:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:in-reply-to:references:date :message-id:subject:from:to:content-type:content-transfer-encoding; bh=Da2alk3QdbRhmVGXotfi+g5QYxzdUnANLAdQMCb+rvk=; b=fxf96AVsiRb0psNVP7390cz8AvVcAP4+uenadEAS/IUUSEZBSvaQbl1FzUDG2cnkGN ejk0atleWrXzQgDFAVY04ST4aCENIjRYy1xAVDbqgm2k/Z44OWZeg4nSAP1GVSU04Pi0 0MCQbkSU76WVHrTEodtd1O/2WceRXcZDe5mpA= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :content-type:content-transfer-encoding; b=WOeZ44agyhQqC1KCfEVD34AEouP6UK4+hVcfcVq14fEwkdLDGAK4gbUnQbmzh47Tuf 9ZBu0Gxw4pOmYiAK14MRx1dqnw/PQ92XIBnfJiOLwyfpfDQt1Hizo60NmNCcEczc7MDO 7BiaUEWx8rZNQuNJTYZJgayv9YzH1uhkU0D4Q= MIME-Version: 1.0 Received: by 10.231.41.66 with SMTP id n2mr6158420ibe.76.1305071265717; Tue, 10 May 2011 16:47:45 -0700 (PDT) Received: by 10.231.20.3 with HTTP; Tue, 10 May 2011 16:47:45 -0700 (PDT) In-Reply-To: <1304977099-31694-1-git-send-email-linus.walleij@linaro.org> References: <1304977099-31694-1-git-send-email-linus.walleij@linaro.org> Date: Wed, 11 May 2011 01:47:45 +0200 Message-ID: Subject: Fwd: [PATCH 09/13] i2c/i2c-nomadik: add code to retry on timeout failure From: Linus Walleij To: patches@linaro.org ---------- Forwarded message ---------- From: Linus Walleij Date: 2011/5/9 Subject: [PATCH 09/13] i2c/i2c-nomadik: add code to retry on timeout failure To: Ben Dooks , linux-i2c@vger.kernel.org Kopia: Virupax Sadashivpetimath , Linus Walleij From: Virupax Sadashivpetimath It is seen that i2c-nomadik controller randomly stops generating the interrupts leading to a i2c timeout. As a workaround to this problem, add retries to the on going transfer on failure. Signed-off-by: Virupax Sadashivpetimath Reviewed-by: Jonas ABERG Signed-off-by: Linus Walleij ---  drivers/i2c/busses/i2c-nomadik.c |   97 +++++++++++++++++++-------------------  1 files changed, 49 insertions(+), 48 deletions(-) -- 1.7.5.1 -- To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to majordomo@vger.kernel.org More majordomo info at  http://vger.kernel.org/majordomo-info.html diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index f3a0af0..bf061e1 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -255,8 +255,6 @@ static int init_hw(struct nmk_i2c_dev *dev)  {        int stat; -       clk_enable(dev->clk); -        stat = flush_i2c_fifo(dev);        if (stat)                goto exit; @@ -271,8 +269,6 @@ static int init_hw(struct nmk_i2c_dev *dev)        dev->cli.operation = I2C_NO_OPERATION;  exit: -       /* TODO: Why disable clocks after init hw? */ -       clk_disable(dev->clk);        /*         * TODO: What is this delay for?         * Must be pretty pointless since the hw block @@ -572,6 +568,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,        u32 cause;        struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap);        u32 i2c_sr; +       int j;        dev->busy = true; @@ -579,63 +576,67 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,                regulator_enable(dev->regulator);        pm_runtime_get_sync(&dev->pdev->dev); +       clk_enable(dev->clk); +        status = init_hw(dev);        if (status) -               goto out2; +               goto out; -       clk_enable(dev->clk); - -       /* setup the i2c controller */ -       setup_i2c_controller(dev); +       for (j = 0; j < 3; j++) { +               /* setup the i2c controller */ +               setup_i2c_controller(dev); -       for (i = 0; i < num_msgs; i++) { -               if (unlikely(msgs[i].flags & I2C_M_TEN)) { -                       dev_err(&dev->pdev->dev, "10 bit addressing" -                                       "not supported\n"); +               for (i = 0; i < num_msgs; i++) { +                       if (unlikely(msgs[i].flags & I2C_M_TEN)) { +                               dev_err(&dev->pdev->dev, "10 bit addressing" +                                               "not supported\n"); -                       status = -EINVAL; -                       goto out; -               } -               dev->cli.slave_adr      = msgs[i].addr; -               dev->cli.buffer         = msgs[i].buf; -               dev->cli.count          = msgs[i].len; -               dev->stop = (i < (num_msgs - 1)) ? 0 : 1; -               dev->result = 0; - -               if (msgs[i].flags & I2C_M_RD) { -                       /* it is a read operation */ -                       dev->cli.operation = I2C_READ; -                       status = read_i2c(dev); -               } else { -                       /* write operation */ -                       dev->cli.operation = I2C_WRITE; -                       status = write_i2c(dev); -               } -               if (status || (dev->result)) { -                       i2c_sr = readl(dev->virtbase + I2C_SR); -                       /* -                        * Check if the controller I2C operation status is set -                        * to ABORT(11b). -                        */ -                       if (((i2c_sr >> 2) & 0x3) == 0x3) { -                               /* get the abort cause */ -                               cause = (i2c_sr >> 4) -                                       & 0x7; -                               dev_err(&dev->pdev->dev, "%s\n", cause >= -                                               ARRAY_SIZE(abort_causes) ? +                               status = -EINVAL; +                               goto out; +                       } +                       dev->cli.slave_adr      = msgs[i].addr; +                       dev->cli.buffer         = msgs[i].buf; +                       dev->cli.count          = msgs[i].len; +                       dev->stop = (i < (num_msgs - 1)) ? 0 : 1; +                       dev->result = 0; + +                       if (msgs[i].flags & I2C_M_RD) { +                               /* it is a read operation */ +                               dev->cli.operation = I2C_READ; +                               status = read_i2c(dev); +                       } else { +                               /* write operation */ +                               dev->cli.operation = I2C_WRITE; +                               status = write_i2c(dev); +                       } +                       if (status || (dev->result)) { +                               i2c_sr = readl(dev->virtbase + I2C_SR); +                               /* +                                * Check if the controller I2C operation status +                                * is set to ABORT(11b). +                                */ +                               if (((i2c_sr >> 2) & 0x3) == 0x3) { +                                       /* get the abort cause */ +                                       cause = (i2c_sr >> 4) +                                               & 0x7; +                                       dev_err(&dev->pdev->dev, "%s\n", cause +                                               >= ARRAY_SIZE(abort_causes) ?                                                "unknown reason" :                                                abort_causes[cause]); -                       } +                               } -                       status = status ? status : dev->result; -                       goto out; +                               status = status ? status : dev->result; + +                               break; +                       } +                       udelay(I2C_DELAY);                } -               udelay(I2C_DELAY); +               if (status == 0) +                       break;        }  out:        clk_disable(dev->clk); -out2:        pm_runtime_put_sync(&dev->pdev->dev);        if (dev->regulator)                regulator_disable(dev->regulator);