From patchwork Wed May 11 16:21:59 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Griffin X-Patchwork-Id: 67607 Delivered-To: patch@linaro.org Received: by 10.140.92.199 with SMTP id b65csp311672qge; Wed, 11 May 2016 09:22:09 -0700 (PDT) X-Received: by 10.98.75.154 with SMTP id d26mr6214551pfj.72.1462983729706; Wed, 11 May 2016 09:22:09 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id j2si10731688pat.172.2016.05.11.09.22.09; Wed, 11 May 2016 09:22:09 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932345AbcEKQWH (ORCPT + 29 others); Wed, 11 May 2016 12:22:07 -0400 Received: from mail-wm0-f52.google.com ([74.125.82.52]:37895 "EHLO mail-wm0-f52.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751669AbcEKQWE (ORCPT ); Wed, 11 May 2016 12:22:04 -0400 Received: by mail-wm0-f52.google.com with SMTP id g17so91885714wme.1 for ; Wed, 11 May 2016 09:22:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id; bh=ShZLnoZrdM8gG2Q3FHnDEav59hacCCcHfCITNXE9XN0=; b=cWfWAPZsiBknpDbfSrPkDHAn35okfVQgMAFEIB1vYCFeSkcBcwdzQVTsl+0n8Jljzi +4TDf/Iu9O5nrSXfXKhrH1aATX3oBqEt9S/VvD6VT1dld2XgxDslqnIn9A+CPDL+a9EP DNnekQi4XP7hqs1E23zxxxh5xNvXOSRtKsOwc= 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; bh=ShZLnoZrdM8gG2Q3FHnDEav59hacCCcHfCITNXE9XN0=; b=DCrzEtkEhE/cyOXKqKIN4GFSq1t/mlfWqzCZrI01ax/z4Mzkc9oiytIcNoKecuIVme IANjCkfBjQWcXti9FShymUFc6yAMPJeJEd0Q+I0QxqyNIKFSzXk6+Zh7EfxmnJ1DbRjY zb4iCYmTWMDxzB4XRvxeUvZQMdN6lk48RkyXWh8L8zD9pDyxtdbfAHPaCq66vCkli8uS Ua8kmvEUWP+y06R+OK9LSL5OLt7SymT2NULkJsVmKDwASfZNlWy8+NdfH3XzCaTL9+hA xbeJWZH5ySpwn3Os7yoHIEnSwoJw4bOYGoTuk7jtkMKNqaQ/Fw/QsCwcWMsmRwdW6HOi zbcQ== X-Gm-Message-State: AOPr4FXUMp0XPTlcIuGsSNyoRjzWM+o1Q/BTMTVu4ZURq3lNbtXnav2QI8BGw8mKpYDqJZWj X-Received: by 10.194.234.36 with SMTP id ub4mr4707680wjc.4.1462983722771; Wed, 11 May 2016 09:22:02 -0700 (PDT) Received: from localhost.localdomain (cpc84787-aztw28-2-0-cust15.18-1.cable.virginm.net. [82.37.140.16]) by smtp.gmail.com with ESMTPSA id y91sm9299570wmh.10.2016.05.11.09.22.01 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 11 May 2016 09:22:01 -0700 (PDT) From: Peter Griffin To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, wsa@the-dreams.de, srinivas.kandagatla@gmail.com, maxime.coquelin@st.com, patrice.chotard@st.com Cc: peter.griffin@linaro.org, lee.jones@linaro.org, linux-i2c@vger.kernel.org, Frederic Pillon Subject: [PATCH] i2c: st: Implement bus clear Date: Wed, 11 May 2016 17:21:59 +0100 Message-Id: <1462983719-342-1-git-send-email-peter.griffin@linaro.org> X-Mailer: git-send-email 1.9.1 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org >From I2C specifications: http://www.nxp.com/documents/user_manual/UM10204.pdf Chapter 3.1.16, when the i2c device held the SDA line low, the master should send 9 clocks pulses to try to recover. Signed-off-by: Frederic Pillon Signed-off-by: Peter Griffin --- changes since V1: - Demote debug to dev_dbg - Add comment on how we achieve 9 clock pulses - Remove empty st_i2c_get_scl & st_i2c_set_scl (relies on core patch from Wolfram) - rebase on v4.6-rc6 --- drivers/i2c/busses/i2c-st.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) -- 1.9.1 diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c index 6ee7715..1ad210b 100644 --- a/drivers/i2c/busses/i2c-st.c +++ b/drivers/i2c/busses/i2c-st.c @@ -337,10 +337,42 @@ static void st_i2c_hw_config(struct st_i2c_dev *i2c_dev) writel_relaxed(val, i2c_dev->base + SSC_NOISE_SUPP_WIDTH_DATAOUT); } +static int st_i2c_recover_bus(struct i2c_adapter *i2c_adap) +{ + struct st_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap); + u32 ctl; + + dev_dbg(i2c_dev->dev, "Trying to recover bus\n"); + + /* + * SSP IP is dual role SPI/I2C to generate 9 clock pulses + * we switch to SPI node, 9 bit words and write a 0. This + * has been validate with a oscilloscope and is easier + * than switching to GPIO mode. + */ + + /* Disable interrupts */ + writel_relaxed(0, i2c_dev->base + SSC_IEN); + + st_i2c_hw_config(i2c_dev); + + ctl = SSC_CTL_EN | SSC_CTL_MS | SSC_CTL_EN_RX_FIFO | SSC_CTL_EN_TX_FIFO; + st_i2c_set_bits(i2c_dev->base + SSC_CTL, ctl); + + st_i2c_clr_bits(i2c_dev->base + SSC_I2C, SSC_I2C_I2CM); + usleep_range(8000, 10000); + + writel_relaxed(0, i2c_dev->base + SSC_TBUF); + usleep_range(2000, 4000); + st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_I2CM); + + return 0; +} + static int st_i2c_wait_free_bus(struct st_i2c_dev *i2c_dev) { u32 sta; - int i; + int i, ret; for (i = 0; i < 10; i++) { sta = readl_relaxed(i2c_dev->base + SSC_STA); @@ -352,6 +384,12 @@ static int st_i2c_wait_free_bus(struct st_i2c_dev *i2c_dev) dev_err(i2c_dev->dev, "bus not free (status = 0x%08x)\n", sta); + ret = i2c_recover_bus(&i2c_dev->adap); + if (ret) { + dev_err(i2c_dev->dev, "Failed to recover the bus (%d)\n", ret); + return ret; + } + return -EBUSY; } @@ -744,6 +782,10 @@ static struct i2c_algorithm st_i2c_algo = { .functionality = st_i2c_func, }; +static struct i2c_bus_recovery_info st_i2c_recovery_info = { + .recover_bus = st_i2c_recover_bus, +}; + static int st_i2c_of_get_deglitch(struct device_node *np, struct st_i2c_dev *i2c_dev) { @@ -826,6 +868,7 @@ static int st_i2c_probe(struct platform_device *pdev) adap->timeout = 2 * HZ; adap->retries = 0; adap->algo = &st_i2c_algo; + adap->bus_recovery_info = &st_i2c_recovery_info; adap->dev.parent = &pdev->dev; adap->dev.of_node = pdev->dev.of_node;