From patchwork Wed Aug 30 06:17:34 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Reid X-Patchwork-Id: 807426 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-i2c-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3xhwKT1vhGz9t16 for ; Wed, 30 Aug 2017 16:17:49 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750835AbdH3GRq (ORCPT ); Wed, 30 Aug 2017 02:17:46 -0400 Received: from anchovy2.45ru.net.au ([203.30.46.146]:47402 "EHLO anchovy.45ru.net.au" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1750814AbdH3GRp (ORCPT ); Wed, 30 Aug 2017 02:17:45 -0400 Received: (qmail 10651 invoked by uid 5089); 30 Aug 2017 06:17:42 -0000 Received: by simscan 1.2.0 ppid: 10547, pid: 10550, t: 0.0972s scanners: regex: 1.2.0 attach: 1.2.0 clamav: 0.88.3/m:40/d:1950 X-RBL: $rbltext Received: from unknown (HELO preid-centos7.electromag.com.au) (preid@electromag.com.au@203.59.230.133) by anchovy3.45ru.net.au with ESMTPA; 30 Aug 2017 06:17:41 -0000 Received: by preid-centos7.electromag.com.au (Postfix, from userid 1000) id 31A4E301EBA89; Wed, 30 Aug 2017 14:17:40 +0800 (AWST) From: Phil Reid To: jarkko.nikula@linux.intel.com, andriy.shevchenko@linux.intel.com, mika.westerberg@linux.intel.com, wsa@the-dreams.de, tim@krieglstein.org, preid@electromag.com.au, linux-i2c@vger.kernel.org Subject: [PATCH v3 1/4] i2c: Switch to using gpiod interface for gpio bus recovery Date: Wed, 30 Aug 2017 14:17:34 +0800 Message-Id: <1504073857-122449-2-git-send-email-preid@electromag.com.au> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1504073857-122449-1-git-send-email-preid@electromag.com.au> References: <1504073857-122449-1-git-send-email-preid@electromag.com.au> Sender: linux-i2c-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-i2c@vger.kernel.org Currently the i2c gpio recovery code uses gpio integer interface instead of the gpiod. This change switch the core code to use the gpiod while still retaining compatibility with the gpio integer interface. This will allow individual driver to be updated and tested individual to switch to using the gpiod interface. Signed-off-by: Phil Reid --- drivers/i2c/i2c-core-base.c | 22 ++++++++++++++++++---- include/linux/i2c.h | 2 ++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 56e4658..3f54e25 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -133,17 +133,17 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) /* i2c bus recovery routines */ static int get_scl_gpio_value(struct i2c_adapter *adap) { - return gpio_get_value(adap->bus_recovery_info->scl_gpio); + return gpiod_get_value_cansleep(adap->bus_recovery_info->scl_gpiod); } static void set_scl_gpio_value(struct i2c_adapter *adap, int val) { - gpio_set_value(adap->bus_recovery_info->scl_gpio, val); + gpiod_set_value_cansleep(adap->bus_recovery_info->scl_gpiod, val); } static int get_sda_gpio_value(struct i2c_adapter *adap) { - return gpio_get_value(adap->bus_recovery_info->sda_gpio); + return gpiod_get_value_cansleep(adap->bus_recovery_info->sda_gpiod); } static int i2c_get_gpios_for_recovery(struct i2c_adapter *adap) @@ -158,6 +158,7 @@ static int i2c_get_gpios_for_recovery(struct i2c_adapter *adap) dev_warn(dev, "Can't get SCL gpio: %d\n", bri->scl_gpio); return ret; } + bri->scl_gpiod = gpio_to_desc(bri->scl_gpio); if (bri->get_sda) { if (gpio_request_one(bri->sda_gpio, GPIOF_IN, "i2c-sda")) { @@ -167,6 +168,7 @@ static int i2c_get_gpios_for_recovery(struct i2c_adapter *adap) bri->get_sda = NULL; } } + bri->sda_gpiod = gpio_to_desc(bri->sda_gpio); return ret; } @@ -175,10 +177,13 @@ static void i2c_put_gpios_for_recovery(struct i2c_adapter *adap) { struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; - if (bri->get_sda) + if (bri->get_sda) { gpio_free(bri->sda_gpio); + bri->sda_gpiod = NULL; + } gpio_free(bri->scl_gpio); + bri->scl_gpiod = NULL; } /* @@ -272,6 +277,15 @@ static void i2c_init_recovery(struct i2c_adapter *adap) goto err; } + if ((bri->scl_gpiod) && + (bri->recover_bus == i2c_generic_scl_recovery)) { + bri->get_scl = get_scl_gpio_value; + bri->set_scl = set_scl_gpio_value; + if (bri->sda_gpiod) + bri->get_sda = get_sda_gpio_value; + return; + } + /* Generic GPIO recovery */ if (bri->recover_bus == i2c_generic_gpio_recovery) { if (!gpio_is_valid(bri->scl_gpio)) { diff --git a/include/linux/i2c.h b/include/linux/i2c.h index d501d39..7ad68a1 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -511,6 +511,8 @@ struct i2c_bus_recovery_info { /* gpio recovery */ int scl_gpio; int sda_gpio; + struct gpio_desc *scl_gpiod; + struct gpio_desc *sda_gpiod; }; int i2c_recover_bus(struct i2c_adapter *adap); From patchwork Wed Aug 30 06:17:35 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Reid X-Patchwork-Id: 807423 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-i2c-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3xhwKQ5XvJz9t0M for ; Wed, 30 Aug 2017 16:17:46 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750844AbdH3GRp (ORCPT ); Wed, 30 Aug 2017 02:17:45 -0400 Received: from anchovy1.45ru.net.au ([203.30.46.145]:37980 "EHLO anchovy.45ru.net.au" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1750803AbdH3GRo (ORCPT ); Wed, 30 Aug 2017 02:17:44 -0400 Received: (qmail 26575 invoked by uid 5089); 30 Aug 2017 06:17:41 -0000 Received: by simscan 1.2.0 ppid: 26437, pid: 26438, t: 0.0476s scanners: regex: 1.2.0 attach: 1.2.0 clamav: 0.88.3/m:40/d:1950 X-RBL: $rbltext Received: from unknown (HELO preid-centos7.electromag.com.au) (preid@electromag.com.au@203.59.230.133) by anchovy1.45ru.net.au with ESMTPA; 30 Aug 2017 06:17:41 -0000 Received: by preid-centos7.electromag.com.au (Postfix, from userid 1000) id 32A6D333CE9F6; Wed, 30 Aug 2017 14:17:40 +0800 (AWST) From: Phil Reid To: jarkko.nikula@linux.intel.com, andriy.shevchenko@linux.intel.com, mika.westerberg@linux.intel.com, wsa@the-dreams.de, tim@krieglstein.org, preid@electromag.com.au, linux-i2c@vger.kernel.org Subject: [PATCH v3 2/4] i2c: designware: move i2c_dw_plat_prepare_clk to common Date: Wed, 30 Aug 2017 14:17:35 +0800 Message-Id: <1504073857-122449-3-git-send-email-preid@electromag.com.au> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1504073857-122449-1-git-send-email-preid@electromag.com.au> References: <1504073857-122449-1-git-send-email-preid@electromag.com.au> Sender: linux-i2c-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-i2c@vger.kernel.org Move the i2c_dw_plat_prepare_clk funciton to common file in preparation for its use also by the master driver. Signed-off-by: Phil Reid Acked-by: Jarkko Nikula --- drivers/i2c/busses/i2c-designware-common.c | 13 +++++++++++++ drivers/i2c/busses/i2c-designware-core.h | 1 + drivers/i2c/busses/i2c-designware-platdrv.c | 12 ------------ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index d1a6937..b79f342 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -21,6 +21,7 @@ * ---------------------------------------------------------------------------- * */ +#include #include #include #include @@ -185,6 +186,18 @@ unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev) return dev->get_clk_rate_khz(dev); } +int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare) +{ + if (IS_ERR(i_dev->clk)) + return PTR_ERR(i_dev->clk); + + if (prepare) + return clk_prepare_enable(i_dev->clk); + + clk_disable_unprepare(i_dev->clk); + return 0; +} + int i2c_dw_acquire_lock(struct dw_i2c_dev *dev) { int ret; diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 9fee4c0..b2a31cb 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -299,6 +299,7 @@ struct dw_i2c_dev { void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable); void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable); unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev); +int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare); int i2c_dw_acquire_lock(struct dw_i2c_dev *dev); void i2c_dw_release_lock(struct dw_i2c_dev *dev); int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 56a17fd..14e7fab 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -214,18 +214,6 @@ static void i2c_dw_configure_slave(struct dw_i2c_dev *dev) } } -static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare) -{ - if (IS_ERR(i_dev->clk)) - return PTR_ERR(i_dev->clk); - - if (prepare) - return clk_prepare_enable(i_dev->clk); - - clk_disable_unprepare(i_dev->clk); - return 0; -} - static void dw_i2c_set_fifo_size(struct dw_i2c_dev *dev, int id) { u32 param, tx_fifo_depth, rx_fifo_depth; From patchwork Wed Aug 30 06:17:36 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Reid X-Patchwork-Id: 807425 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-i2c-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3xhwKS4wcwz9t0M for ; Wed, 30 Aug 2017 16:17:48 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750851AbdH3GRp (ORCPT ); Wed, 30 Aug 2017 02:17:45 -0400 Received: from anchovy3.45ru.net.au ([203.30.46.155]:45732 "EHLO anchovy.45ru.net.au" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1750835AbdH3GRo (ORCPT ); Wed, 30 Aug 2017 02:17:44 -0400 Received: (qmail 1146 invoked by uid 5089); 30 Aug 2017 06:17:41 -0000 Received: by simscan 1.2.0 ppid: 1088, pid: 1090, t: 0.0273s scanners: regex: 1.2.0 attach: 1.2.0 clamav: 0.88.3/m:40/d:1950 X-RBL: $rbltext Received: from unknown (HELO preid-centos7.electromag.com.au) (preid@electromag.com.au@203.59.230.133) by anchovy2.45ru.net.au with ESMTPA; 30 Aug 2017 06:17:41 -0000 Received: by preid-centos7.electromag.com.au (Postfix, from userid 1000) id 38BA3333CE9F9; Wed, 30 Aug 2017 14:17:40 +0800 (AWST) From: Phil Reid To: jarkko.nikula@linux.intel.com, andriy.shevchenko@linux.intel.com, mika.westerberg@linux.intel.com, wsa@the-dreams.de, tim@krieglstein.org, preid@electromag.com.au, linux-i2c@vger.kernel.org Subject: [PATCH v3 3/4] i2c: designware: rename i2c_dw_plat_prepare_clk to i2c_dw_prepare_clk Date: Wed, 30 Aug 2017 14:17:36 +0800 Message-Id: <1504073857-122449-4-git-send-email-preid@electromag.com.au> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1504073857-122449-1-git-send-email-preid@electromag.com.au> References: <1504073857-122449-1-git-send-email-preid@electromag.com.au> Sender: linux-i2c-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-i2c@vger.kernel.org For consistency with the reset of the file rename function and parameter to be consistent with the reset of the common file. Signed-off-by: Phil Reid Acked-by: Jarkko Nikula --- drivers/i2c/busses/i2c-designware-common.c | 10 +++++----- drivers/i2c/busses/i2c-designware-core.h | 2 +- drivers/i2c/busses/i2c-designware-platdrv.c | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index b79f342..3d684c6 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -186,15 +186,15 @@ unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev) return dev->get_clk_rate_khz(dev); } -int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare) +int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare) { - if (IS_ERR(i_dev->clk)) - return PTR_ERR(i_dev->clk); + if (IS_ERR(dev->clk)) + return PTR_ERR(dev->clk); if (prepare) - return clk_prepare_enable(i_dev->clk); + return clk_prepare_enable(dev->clk); - clk_disable_unprepare(i_dev->clk); + clk_disable_unprepare(dev->clk); return 0; } diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index b2a31cb..fef44b5 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -299,7 +299,7 @@ struct dw_i2c_dev { void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable); void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable); unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev); -int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare); +int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare); int i2c_dw_acquire_lock(struct dw_i2c_dev *dev); void i2c_dw_release_lock(struct dw_i2c_dev *dev); int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 14e7fab..58f55a8 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -325,7 +325,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) i2c_dw_configure_master(dev); dev->clk = devm_clk_get(&pdev->dev, NULL); - if (!i2c_dw_plat_prepare_clk(dev, true)) { + if (!i2c_dw_prepare_clk(dev, true)) { dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; if (!dev->sda_hold_time && ht) @@ -422,7 +422,7 @@ static int dw_i2c_plat_runtime_suspend(struct device *dev) struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); i_dev->disable(i_dev); - i2c_dw_plat_prepare_clk(i_dev, false); + i2c_dw_prepare_clk(i_dev, false); return 0; } @@ -431,7 +431,7 @@ static int dw_i2c_plat_resume(struct device *dev) { struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); - i2c_dw_plat_prepare_clk(i_dev, true); + i2c_dw_prepare_clk(i_dev, true); i_dev->init(i_dev); return 0; From patchwork Wed Aug 30 06:17:37 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Reid X-Patchwork-Id: 807427 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-i2c-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3xhwKT66czz9t0M for ; Wed, 30 Aug 2017 16:17:49 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750862AbdH3GRr (ORCPT ); Wed, 30 Aug 2017 02:17:47 -0400 Received: from anchovy2.45ru.net.au ([203.30.46.146]:47409 "EHLO anchovy.45ru.net.au" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1750824AbdH3GRp (ORCPT ); Wed, 30 Aug 2017 02:17:45 -0400 Received: (qmail 10648 invoked by uid 5089); 30 Aug 2017 06:17:42 -0000 Received: by simscan 1.2.0 ppid: 10546, pid: 10549, t: 0.0970s scanners: regex: 1.2.0 attach: 1.2.0 clamav: 0.88.3/m:40/d:1950 X-RBL: $rbltext Received: from unknown (HELO preid-centos7.electromag.com.au) (preid@electromag.com.au@203.59.230.133) by anchovy3.45ru.net.au with ESMTPA; 30 Aug 2017 06:17:41 -0000 Received: by preid-centos7.electromag.com.au (Postfix, from userid 1000) id 3FF76333CE9FA; Wed, 30 Aug 2017 14:17:40 +0800 (AWST) From: Phil Reid To: jarkko.nikula@linux.intel.com, andriy.shevchenko@linux.intel.com, mika.westerberg@linux.intel.com, wsa@the-dreams.de, tim@krieglstein.org, preid@electromag.com.au, linux-i2c@vger.kernel.org Subject: [PATCH v3 4/4] i2c: designware: add i2c gpio recovery option Date: Wed, 30 Aug 2017 14:17:37 +0800 Message-Id: <1504073857-122449-5-git-send-email-preid@electromag.com.au> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1504073857-122449-1-git-send-email-preid@electromag.com.au> References: <1504073857-122449-1-git-send-email-preid@electromag.com.au> Sender: linux-i2c-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-i2c@vger.kernel.org From: Tim Sander This patch contains much input from Phil Reid and has been tested on Intel/Altera Cyclone V SOC Hardware with Altera GPIO's for the SCL and SDA GPIO's. I am still a little unsure about the recover in the timeout case (i2c-designware-core.c:770) as i could not test this codepath. Signed-off-by: Tim Sander Signed-off-by: Phil Reid --- drivers/i2c/busses/i2c-designware-common.c | 11 ++++-- drivers/i2c/busses/i2c-designware-core.h | 1 + drivers/i2c/busses/i2c-designware-master.c | 57 ++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index 3d684c6..e3120987 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -230,7 +230,11 @@ int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev) while (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) { if (timeout <= 0) { dev_warn(dev->dev, "timeout waiting for bus ready\n"); - return -ETIMEDOUT; + i2c_recover_bus(&dev->adapter); + + if (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) + return -ETIMEDOUT; + return 0; } timeout--; usleep_range(1000, 1100); @@ -254,9 +258,10 @@ int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev) for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources)) dev_err(dev->dev, "%s: %s\n", __func__, abort_sources[i]); - if (abort_source & DW_IC_TX_ARB_LOST) + if (abort_source & DW_IC_TX_ARB_LOST) { + i2c_recover_bus(&dev->adapter); return -EAGAIN; - else if (abort_source & DW_IC_TX_ABRT_GCALL_READ) + } else if (abort_source & DW_IC_TX_ABRT_GCALL_READ) return -EINVAL; /* wrong msgs[] data */ else return -EIO; diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index fef44b5..8707c76 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -284,6 +284,7 @@ struct dw_i2c_dev { void (*disable_int)(struct dw_i2c_dev *dev); int (*init)(struct dw_i2c_dev *dev); int mode; + struct i2c_bus_recovery_info rinfo; }; #define ACCESS_SWAP 0x00000001 diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 418c233..07e34fe 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -25,11 +25,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include "i2c-designware-core.h" @@ -443,6 +445,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) { dev_err(dev->dev, "controller timed out\n"); /* i2c_dw_init implicitly disables the adapter */ + i2c_recover_bus(&dev->adapter); i2c_dw_init_master(dev); ret = -ETIMEDOUT; goto done; @@ -613,6 +616,57 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) return IRQ_HANDLED; } +static void i2c_dw_prepare_recovery(struct i2c_adapter *adap) +{ + struct dw_i2c_dev *dev = i2c_get_adapdata(adap); + + i2c_dw_disable(dev); + reset_control_assert(dev->rst); + i2c_dw_prepare_clk(dev, false); +} + +static void i2c_dw_unprepare_recovery(struct i2c_adapter *adap) +{ + struct dw_i2c_dev *dev = i2c_get_adapdata(adap); + + i2c_dw_prepare_clk(dev, true); + reset_control_deassert(dev->rst); + i2c_dw_init_master(dev); +} + +static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev) +{ + struct i2c_bus_recovery_info *rinfo = &dev->rinfo; + struct i2c_adapter *adap = &dev->adapter; + struct gpio_desc *gpio; + int r; + + gpio = devm_gpiod_get(dev->dev, "scl", GPIOD_OUT_HIGH); + if (IS_ERR(gpio)) { + r = PTR_ERR(gpio); + if ((r == -ENOENT) || (r == -ENOENT)) + return 0; + return r; + } + rinfo->scl_gpiod = gpio; + + gpio = devm_gpiod_get_optional(dev->dev, "sda", GPIOD_IN); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); + rinfo->sda_gpiod = gpio; + + rinfo->recover_bus = i2c_generic_scl_recovery; + rinfo->prepare_recovery = i2c_dw_prepare_recovery; + rinfo->unprepare_recovery = i2c_dw_unprepare_recovery; + adap->bus_recovery_info = rinfo; + + dev_info(dev->dev, + "adapter: %s running with gpio recovery mode! scl:%i sda:%i\n", + adap->name, !!rinfo->scl_gpiod, !!rinfo->sda_gpiod); + + return 0; +} + int i2c_dw_probe(struct dw_i2c_dev *dev) { struct i2c_adapter *adap = &dev->adapter; @@ -664,6 +718,9 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) dev_err(dev->dev, "failure adding adapter: %d\n", ret); pm_runtime_put_noidle(dev->dev); + if (!ret) + ret = i2c_dw_init_recovery_info(dev); + return ret; } EXPORT_SYMBOL_GPL(i2c_dw_probe);