Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753799AbbDAOjB (ORCPT ); Wed, 1 Apr 2015 10:39:01 -0400 Received: from demumfd001.nsn-inter.net ([93.183.12.32]:54288 "EHLO demumfd001.nsn-inter.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753269AbbDAOi6 (ORCPT ); Wed, 1 Apr 2015 10:38:58 -0400 Message-ID: <551C02D3.4080107@nokia.com> Date: Wed, 01 Apr 2015 16:38:11 +0200 From: Alexander Sverdlin User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.5.0 MIME-Version: 1.0 To: Grygorii Strashko , Wolfram Sang , Sekhar Nori , =?UTF-8?B?VXdlIEtsZWluZS1Lw7ZuaWc=?= CC: linux-i2c@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Kevin Hilman , Santosh Shilimkar , Lawnick Michael Subject: Re: [PATCH 5/5] i2c: davinci: use ICPFUNC to toggle I2C as gpio for bus recovery References: <1417448047-15236-1-git-send-email-grygorii.strashko@ti.com> <1417448047-15236-6-git-send-email-grygorii.strashko@ti.com> In-Reply-To: <1417448047-15236-6-git-send-email-grygorii.strashko@ti.com> Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-purgate-type: clean X-purgate-Ad: Categorized by eleven eXpurgate (R) http://www.eleven.de X-purgate: clean X-purgate: This mail is considered clean (visit http://www.eleven.de for further information) X-purgate-size: 8138 X-purgate-ID: 151667::1427899095-0000328B-138F336B/0/0 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 8168 Lines: 220 Hello Grygorii, On 01/12/14 16:34, Grygorii Strashko wrote: > 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 > 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 We have tested it on a custom Keystone2-based board, recovery seems to work when SDA is held low externally. Acked-by: Alexander Sverdlin Tested-by: Michael Lawnick > --- > .../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 00aed63..a1bb587 100644 > --- a/drivers/i2c/busses/i2c-davinci.c > +++ b/drivers/i2c/busses/i2c-davinci.c > @@ -64,6 +64,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 > @@ -97,6 +103,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; > @@ -257,6 +286,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 > */ > @@ -669,6 +763,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; > } > @@ -710,7 +808,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 */ -- Best regards, Alexander Sverdlin. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/