From patchwork Mon Apr 6 12:38:41 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "Grygorii.Strashko@linaro.org" X-Patchwork-Id: 46783 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-lb0-f200.google.com (mail-lb0-f200.google.com [209.85.217.200]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 47352214B1 for ; Mon, 6 Apr 2015 12:39:10 +0000 (UTC) Received: by lbbrr5 with SMTP id rr5sf3174867lbb.3 for ; Mon, 06 Apr 2015 05:39:09 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-type :content-transfer-encoding:sender:precedence:list-id :x-original-sender:x-original-authentication-results:mailing-list :list-post:list-help:list-archive:list-unsubscribe; bh=nuG3+mc2fE7boBLe+6ND2ulBUwErMtCw+nMoq+UqWyc=; b=mvcf8G/7MLbqLuqqcLS2s0cOojweoaay9i+Pt4wWYR2a9B8oLRUdTXjx8AYAE+I0Aw wJh1aae1BgPFIeSApy5FWyoWZQbnAUOTsJFvWLUD6dMXIIVMz+TVs7Ee6mJq3U49wkx3 krv1PazH9iBXOtOUsHpvFwl1akRX2Te0ot2+yrW4F1nZGDHPpG+f+u3nyVlKzg7NSV/o Q+tU+NwUQ5sya3ys1qFErD7qTw83gq5NMeRSXicYtikai8B9QH0d2/c1IZTVrzh33mjr HcOqMlZd/0J5nEJ33/qhK7YH8n72+EbMWWVPeH821uJeH5kkmvtyh/RV/hY8cnAGv3Go omZQ== X-Gm-Message-State: ALoCoQnU77u/mQBbTVoGflmdfM7WnE+erAQA9neA26JMAAgawM1T2sRzvmRqBroDMUMxhjJ2NGqu X-Received: by 10.180.211.168 with SMTP id nd8mr2939163wic.4.1428323949242; Mon, 06 Apr 2015 05:39:09 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.37.194 with SMTP id a2ls497039lak.88.gmail; Mon, 06 Apr 2015 05:39:08 -0700 (PDT) X-Received: by 10.112.140.38 with SMTP id rd6mr13350449lbb.116.1428323948875; Mon, 06 Apr 2015 05:39:08 -0700 (PDT) Received: from mail-la0-f47.google.com (mail-la0-f47.google.com. [209.85.215.47]) by mx.google.com with ESMTPS id p2si3454359lag.109.2015.04.06.05.39.08 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 06 Apr 2015 05:39:08 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.47 as permitted sender) client-ip=209.85.215.47; Received: by lagv1 with SMTP id v1so18792712lag.3 for ; Mon, 06 Apr 2015 05:39:08 -0700 (PDT) X-Received: by 10.112.8.101 with SMTP id q5mr13549548lba.19.1428323948746; Mon, 06 Apr 2015 05:39:08 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.112.57.201 with SMTP id k9csp3329976lbq; Mon, 6 Apr 2015 05:39:07 -0700 (PDT) X-Received: by 10.70.130.132 with SMTP id oe4mr26937630pdb.153.1428323943484; Mon, 06 Apr 2015 05:39:03 -0700 (PDT) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id fh5si6509881pdb.24.2015.04.06.05.39.02 for ; Mon, 06 Apr 2015 05:39:03 -0700 (PDT) Received-SPF: none (google.com: linux-i2c-owner@vger.kernel.org does not designate permitted sender hosts) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752853AbbDFMi7 (ORCPT ); Mon, 6 Apr 2015 08:38:59 -0400 Received: from mail-la0-f46.google.com ([209.85.215.46]:34481 "EHLO mail-la0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753130AbbDFMir (ORCPT ); Mon, 6 Apr 2015 08:38:47 -0400 Received: by laat2 with SMTP id t2so11742332laa.1 for ; Mon, 06 Apr 2015 05:38:45 -0700 (PDT) X-Received: by 10.112.199.133 with SMTP id jk5mr6201965lbc.32.1428323925692; Mon, 06 Apr 2015 05:38:45 -0700 (PDT) Received: from localhost ([195.238.92.128]) by mx.google.com with ESMTPSA id m1sm958517lbg.36.2015.04.06.05.38.45 (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Mon, 06 Apr 2015 05:38:45 -0700 (PDT) From: To: Wolfram Sang , Sekhar Nori , =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Cc: grygorii.strashko@ti.com, linux-i2c@vger.kernel.org, , , Kevin Hilman , Santosh Shilimkar , Murali Karicheri , Mike Looijmans , Subject: [PATCH v4 3/3] i2c: davinci: use ICPFUNC to toggle I2C as gpio for bus recovery Date: Mon, 6 Apr 2015 15:38:41 +0300 Message-Id: <1428323921-25832-4-git-send-email-grygorii.strashko@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1428323921-25832-1-git-send-email-grygorii.strashko@linaro.org> References: <1428323921-25832-1-git-send-email-grygorii.strashko@linaro.org> MIME-Version: 1.0 Sender: linux-i2c-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: linux-i2c@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: grygorii.strashko@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.47 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , From: Grygorii Strashko Having a board where the I2C bus locks up occasionally made it clear that the bus recovery in the i2c-davinci driver will only work on some boards, because on regular boards, this will only toggle GPIO lines that aren't muxed to the actual pins. The I2C controller on SoCs like da850 (and da830), Keystone 2 has the built-in capability to bit-bang its lines by using the ICPFUNC registers of the i2c controller. Implement the suggested procedure by toggling SCL and checking SDA using the ICPFUNC registers of the I2C controller when present. Allow platforms to indicate the presence of the ICPFUNC registers with a has_pfunc platform data flag and add optional DT property "ti,has-pfunc" to indicate the same in DT. CC: Sekhar Nori CC: Kevin Hilman CC: Santosh Shilimkar CC: Murali Karicheri CC: Mike Looijmans CC: Reviewed-by: Uwe Kleine-König Acked-by: Alexander Sverdlin Tested-by: Michael Lawnick Signed-off-by: Ben Gardiner Signed-off-by: Mike Looijmans [grygorii.strashko@ti.com: combined patches from Ben Gardiner and Mike Looijmans and reimplemented ICPFUNC bus recovery using I2C bus recovery infrastructure] Signed-off-by: Grygorii Strashko --- .../devicetree/bindings/i2c/i2c-davinci.txt | 3 + drivers/i2c/busses/i2c-davinci.c | 102 ++++++++++++++++++++- include/linux/platform_data/i2c-davinci.h | 1 + 3 files changed, 105 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/i2c/i2c-davinci.txt b/Documentation/devicetree/bindings/i2c/i2c-davinci.txt index 2dc935b..a4e1cbc 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-davinci.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-davinci.txt @@ -10,6 +10,9 @@ Required properties: Recommended properties : - interrupts : standard interrupt property. - clock-frequency : desired I2C bus clock frequency in Hz. +- ti,has-pfunc: boolean; if defined, it indicates that SoC supports PFUNC + registers. PFUNC registers allow to switch I2C pins to function as + GPIOs, so they can by toggled manually. Example (enbw_cmc board): i2c@1c22000 { diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 54819fb..4788a32 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -60,6 +60,12 @@ #define DAVINCI_I2C_IVR_REG 0x28 #define DAVINCI_I2C_EMDR_REG 0x2c #define DAVINCI_I2C_PSC_REG 0x30 +#define DAVINCI_I2C_FUNC_REG 0x48 +#define DAVINCI_I2C_DIR_REG 0x4c +#define DAVINCI_I2C_DIN_REG 0x50 +#define DAVINCI_I2C_DOUT_REG 0x54 +#define DAVINCI_I2C_DSET_REG 0x58 +#define DAVINCI_I2C_DCLR_REG 0x5c #define DAVINCI_I2C_IVR_AAS 0x07 #define DAVINCI_I2C_IVR_SCD 0x06 @@ -93,6 +99,29 @@ #define DAVINCI_I2C_IMR_NACK BIT(1) #define DAVINCI_I2C_IMR_AL BIT(0) +/* set SDA and SCL as GPIO */ +#define DAVINCI_I2C_FUNC_PFUNC0 BIT(0) + +/* set SCL as output when used as GPIO*/ +#define DAVINCI_I2C_DIR_PDIR0 BIT(0) +/* set SDA as output when used as GPIO*/ +#define DAVINCI_I2C_DIR_PDIR1 BIT(1) + +/* read SCL GPIO level */ +#define DAVINCI_I2C_DIN_PDIN0 BIT(0) +/* read SDA GPIO level */ +#define DAVINCI_I2C_DIN_PDIN1 BIT(1) + +/*set the SCL GPIO high */ +#define DAVINCI_I2C_DSET_PDSET0 BIT(0) +/*set the SDA GPIO high */ +#define DAVINCI_I2C_DSET_PDSET1 BIT(1) + +/* set the SCL GPIO low */ +#define DAVINCI_I2C_DCLR_PDCLR0 BIT(0) +/* set the SDA GPIO low */ +#define DAVINCI_I2C_DCLR_PDCLR1 BIT(1) + struct davinci_i2c_dev { struct device *dev; void __iomem *base; @@ -253,6 +282,71 @@ static struct i2c_bus_recovery_info davinci_i2c_gpio_recovery_info = { .unprepare_recovery = davinci_i2c_unprepare_recovery, }; +static void davinci_i2c_set_scl(struct i2c_adapter *adap, int val) +{ + struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); + + if (val) + davinci_i2c_write_reg(dev, DAVINCI_I2C_DSET_REG, + DAVINCI_I2C_DSET_PDSET0); + else + davinci_i2c_write_reg(dev, DAVINCI_I2C_DCLR_REG, + DAVINCI_I2C_DCLR_PDCLR0); +} + +static int davinci_i2c_get_scl(struct i2c_adapter *adap) +{ + struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); + int val; + + /* read the state of SCL */ + val = davinci_i2c_read_reg(dev, DAVINCI_I2C_DIN_REG); + return val & DAVINCI_I2C_DIN_PDIN0; +} + +static int davinci_i2c_get_sda(struct i2c_adapter *adap) +{ + struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); + int val; + + /* read the state of SDA */ + val = davinci_i2c_read_reg(dev, DAVINCI_I2C_DIN_REG); + return val & DAVINCI_I2C_DIN_PDIN1; +} + +static void davinci_i2c_scl_prepare_recovery(struct i2c_adapter *adap) +{ + struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); + + davinci_i2c_prepare_recovery(adap); + + /* SCL output, SDA input */ + davinci_i2c_write_reg(dev, DAVINCI_I2C_DIR_REG, DAVINCI_I2C_DIR_PDIR0); + + /* change to GPIO mode */ + davinci_i2c_write_reg(dev, DAVINCI_I2C_FUNC_REG, + DAVINCI_I2C_FUNC_PFUNC0); +} + +static void davinci_i2c_scl_unprepare_recovery(struct i2c_adapter *adap) +{ + struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); + + /* change back to I2C mode */ + davinci_i2c_write_reg(dev, DAVINCI_I2C_FUNC_REG, 0); + + davinci_i2c_unprepare_recovery(adap); +} + +static struct i2c_bus_recovery_info davinci_i2c_scl_recovery_info = { + .recover_bus = i2c_generic_scl_recovery, + .set_scl = davinci_i2c_set_scl, + .get_scl = davinci_i2c_get_scl, + .get_sda = davinci_i2c_get_sda, + .prepare_recovery = davinci_i2c_scl_prepare_recovery, + .unprepare_recovery = davinci_i2c_scl_unprepare_recovery, +}; + /* * Waiting for bus not busy */ @@ -660,6 +754,10 @@ static int davinci_i2c_probe(struct platform_device *pdev) if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency", &prop)) dev->pdata->bus_freq = prop / 1000; + + dev->pdata->has_pfunc = + of_property_read_bool(pdev->dev.of_node, + "ti,has-pfunc"); } else if (!dev->pdata) { dev->pdata = &davinci_i2c_platform_data_default; } @@ -701,7 +799,9 @@ static int davinci_i2c_probe(struct platform_device *pdev) adap->timeout = DAVINCI_I2C_TIMEOUT; adap->dev.of_node = pdev->dev.of_node; - if (dev->pdata->scl_pin) { + if (dev->pdata->has_pfunc) + adap->bus_recovery_info = &davinci_i2c_scl_recovery_info; + else if (dev->pdata->scl_pin) { adap->bus_recovery_info = &davinci_i2c_gpio_recovery_info; adap->bus_recovery_info->scl_gpio = dev->pdata->scl_pin; adap->bus_recovery_info->sda_gpio = dev->pdata->sda_pin; diff --git a/include/linux/platform_data/i2c-davinci.h b/include/linux/platform_data/i2c-davinci.h index 2312d19..89fd347 100644 --- a/include/linux/platform_data/i2c-davinci.h +++ b/include/linux/platform_data/i2c-davinci.h @@ -18,6 +18,7 @@ struct davinci_i2c_platform_data { unsigned int bus_delay; /* post-transaction delay (usec) */ unsigned int sda_pin; /* GPIO pin ID to use for SDA */ unsigned int scl_pin; /* GPIO pin ID to use for SCL */ + bool has_pfunc; /*chip has a ICPFUNC register */ }; /* for board setup code */