Re: [PATCH V6 2/2] i2c/designware: Provide i2c bus recovery support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Oct 04, 2012 at 04:34:54PM +0530, Viresh Kumar wrote:
> Add bus recovery support for designware_i2c controller. It uses generic gpio
> based i2c_gpio_recover_bus() routine.
> 
> Signed-off-by: Vincenzo Frascino <vincenzo.frascino@xxxxxx>
> Signed-off-by: Shiraz Hashim <shiraz.hashim@xxxxxx>
> Signed-off-by: Viresh Kumar <viresh.kumar@xxxxxxxxxx>
> ---
> V5->V6:
> - removed sda_gpio_flags
> 
>  drivers/i2c/busses/i2c-designware-core.c    |  7 ++++-
>  drivers/i2c/busses/i2c-designware-platdrv.c | 38 ++++++++++++++++++++++--
>  include/linux/i2c/i2c-designware.h          | 46 +++++++++++++++++++++++++++++
>  3 files changed, 88 insertions(+), 3 deletions(-)
>  create mode 100644 include/linux/i2c/i2c-designware.h
> 
> diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
> index cbba7db..9b7c9bf 100644
> --- a/drivers/i2c/busses/i2c-designware-core.c
> +++ b/drivers/i2c/busses/i2c-designware-core.c
> @@ -538,7 +538,12 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
>  	ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ);
>  	if (ret == 0) {
>  		dev_err(dev->dev, "controller timed out\n");
> -		i2c_dw_init(dev);
> +		if (adap->bus_recovery_info &&
> +				adap->bus_recovery_info->recover_bus) {
> +			dev_dbg(dev->dev, "try i2c bus recovery\n");
> +			adap->bus_recovery_info->recover_bus(adap);
> +		}
> +

This should be in the core?

>  		ret = -ETIMEDOUT;
>  		goto done;
>  	} else if (ret < 0)
> diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
> index 0506fef..afa0df9 100644
> --- a/drivers/i2c/busses/i2c-designware-platdrv.c
> +++ b/drivers/i2c/busses/i2c-designware-platdrv.c
> @@ -29,6 +29,7 @@
>  #include <linux/module.h>
>  #include <linux/delay.h>
>  #include <linux/i2c.h>
> +#include <linux/i2c/i2c-designware.h>
>  #include <linux/clk.h>
>  #include <linux/errno.h>
>  #include <linux/sched.h>
> @@ -45,6 +46,7 @@ static struct i2c_algorithm i2c_dw_algo = {
>  	.master_xfer	= i2c_dw_xfer,
>  	.functionality	= i2c_dw_func,
>  };
> +
>  static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
>  {
>  	return clk_get_rate(dev->clk)/1000;
> @@ -55,6 +57,8 @@ static int __devinit dw_i2c_probe(struct platform_device *pdev)
>  	struct dw_i2c_dev *dev;
>  	struct i2c_adapter *adap;
>  	struct resource *mem, *ioarea;
> +	struct i2c_dw_pdata *pdata;
> +	struct i2c_bus_recovery_info *recovery_info = NULL;
>  	int irq, r;
>  
>  	/* NOTE: driver uses the static register mapping */
> @@ -141,17 +145,45 @@ static int __devinit dw_i2c_probe(struct platform_device *pdev)
>  	adap->dev.parent = &pdev->dev;
>  	adap->dev.of_node = pdev->dev.of_node;
>  
> +	/* Bus recovery support */
> +	pdata = dev_get_platdata(&pdev->dev);
> +	if (pdata) {
> +		recovery_info = kzalloc(sizeof(*recovery_info), GFP_KERNEL);
> +		if (!recovery_info) {
> +			adap->bus_recovery_info = NULL;
> +			dev_err(&pdev->dev,
> +				"failure to allocate memory for bus recovery\n");
> +			goto skip_recovery;
> +		}
> +
> +		recovery_info->is_gpio_recovery = true;
> +		recovery_info->get_gpio = pdata->get_gpio;
> +		recovery_info->put_gpio = pdata->put_gpio;
> +		recovery_info->scl_gpio = pdata->scl_gpio;
> +		recovery_info->scl_gpio_flags = pdata->scl_gpio_flags;
> +		recovery_info->clock_rate_khz = clk_get_rate(dev->clk) / 1000;

It is probably easier to define the whole bri structure in the platform
and simply pass it on here? Hmm, now devicetree also comes to my mind.
Will think about that a little, too, but main implementation should be
left for someone needing that.

> +
> +		if (!pdata->skip_sda_polling)
> +			recovery_info->sda_gpio = pdata->sda_gpio;
> +
> +		adap->bus_recovery_info = recovery_info;
> +	} else {
> +		adap->bus_recovery_info = NULL;
> +	}
> +
> +skip_recovery:
>  	adap->nr = pdev->id;
>  	r = i2c_add_numbered_adapter(adap);
>  	if (r) {
>  		dev_err(&pdev->dev, "failure adding adapter\n");
> -		goto err_free_irq;
> +		goto err_free_recovery_info;
>  	}
>  	of_i2c_register_devices(adap);
>  
>  	return 0;
>  
> -err_free_irq:
> +err_free_recovery_info:
> +	kfree(recovery_info);
>  	free_irq(dev->irq, dev);
>  err_iounmap:
>  	iounmap(dev->base);
> @@ -174,6 +206,8 @@ static int __devexit dw_i2c_remove(struct platform_device *pdev)
>  	struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
>  	struct resource *mem;
>  
> +	kfree(dev->adapter.bus_recovery_info);
> +
>  	platform_set_drvdata(pdev, NULL);
>  	i2c_del_adapter(&dev->adapter);
>  	put_device(&pdev->dev);
> diff --git a/include/linux/i2c/i2c-designware.h b/include/linux/i2c/i2c-designware.h
> new file mode 100644
> index 0000000..522dec0
> --- /dev/null
> +++ b/include/linux/i2c/i2c-designware.h
> @@ -0,0 +1,46 @@
> +/*
> + * Synopsys DesignWare I2C adapter driver's platform data
> + *
> + * Copyright (C) 2012 ST Microelectronics.
> + * Author: Vincenzo Frascino <vincenzo.frascino@xxxxxx>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +#ifndef I2C_DESIGNWARE_H
> +#define I2C_DESIGNWARE_H
> +
> +#include <linux/platform_device.h>
> +
> +/*
> + * struct i2c_dw_pdata - Designware I2c platform data
> + * @scl_gpio: gpio number of the scl line.
> + * @scl_gpio_flags: flag for gpio_request_one of scl_gpio. 0 implies
> + *	GPIOF_OUT_INIT_LOW.
> + * @get_gpio: called before recover_bus() to get padmux configured for scl line
> + *	as gpio. Only required if is_gpio_recovery == true
> + * @put_gpio: called after recover_bus() to get padmux configured for scl line
> + *	as scl. Only required if is_gpio_recovery == true
> + * @skip_sda_polling: if true, bus recovery will not poll sda line to check if
> + *	it became high or not. Below are required only if this is false.
> + * @sda_gpio: gpio number of the sda line.
> + */
> +struct i2c_dw_pdata {
> +	int scl_gpio;
> +	int scl_gpio_flags;
> +	int (*get_gpio)(unsigned gpio);
> +	void (*put_gpio)(unsigned gpio);
> +
> +	/* sda polling specific */
> +	bool skip_sda_polling;
> +	int sda_gpio;
> +};
> +
> +#endif /* I2C_DESIGNWARE_H */
> -- 
> 1.7.12.rc2.18.g61b472e
> 
> 

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

Attachment: signature.asc
Description: Digital signature


[Index of Archives]     [Linux GPIO]     [Linux SPI]     [Linux Hardward Monitoring]     [LM Sensors]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux