[PATCH v2 5/7] i2c: omap: wait for transfer completion before sending STP bit

Felipe Balbi balbi at ti.com
Thu Oct 25 08:32:20 EDT 2012


Hi,

On Thu, Oct 25, 2012 at 03:25:13PM +0300, Felipe Balbi wrote:
> Later patches will come adding support for
> reporting amount of bytes transferred so that
> client drivers can count how many bytes are
> left to transfer.
> 
> This is useful mostly in case of NACKs when
> client driver wants to know exactly which
> byte got NACKed so it doesn't have to resend
> all bytes again.
> 
> In order to make that work with OMAP's I2C
> controller, we need to prevent sending STP
> bit until message is transferred. The reason
> behind that is because OMAP_I2C_CNT_REG gets
> reset to original value after STP bit is
> shifted through I2C_SDA line and that would
> prevent us from reading the correct number of
> bytes left to transfer.
> 
> The full programming model suggested by IP
> owner was the following:
> 
> - start I2C transfer (without STP bit)
> - upon completion or NACK, read I2C_CNT register
> - write STP bit to I2C_CON register
> - wait for ARDY bit
> 
> With this patch we're implementing all steps
> except step #2 which will come in a later
> patch adding such support.
> 
> Signed-off-by: Felipe Balbi <balbi at ti.com>
> ---
>  drivers/i2c/busses/i2c-omap.c | 89 ++++++++++++++++---------------------------
>  1 file changed, 33 insertions(+), 56 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
> index 20f9ad6..699fa12 100644
> --- a/drivers/i2c/busses/i2c-omap.c
> +++ b/drivers/i2c/busses/i2c-omap.c
> @@ -438,9 +438,9 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
>  
>  	/* Enable interrupts */
>  	dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
> -			OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
> -			OMAP_I2C_IE_AL)  | ((dev->fifo_size) ?
> -				(OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0);
> +			OMAP_I2C_IE_NACK | OMAP_I2C_IE_AL)  |
> +			((dev->fifo_size) ? (OMAP_I2C_IE_RDR |
> +				OMAP_I2C_IE_XDR) : 0);
>  	omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
>  	if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
>  		dev->pscstate = psc;
> @@ -470,6 +470,22 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev)
>  	return 0;
>  }
>  
> +static int omap_i2c_wait_for_ardy(struct omap_i2c_dev *dev)
> +{
> +	unsigned long timeout;
> +
> +	timeout = jiffies + OMAP_I2C_TIMEOUT;
> +	while (!(omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_ARDY)) {
> +		if (time_after(jiffies, timeout)) {
> +			dev_warn(dev->dev, "timeout waiting for access ready\n");
> +			return -ETIMEDOUT;
> +		}
> +		usleep_range(800, 1200);
> +	}
> +
> +	return 0;
> +}
> +
>  static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx)
>  {
>  	u16		buf;
> @@ -515,7 +531,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
>  {
>  	struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
>  	unsigned long timeout;
> -	int ret;
> +	int ret = 0;
>  	u16 w;
>  
>  	dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
> @@ -556,35 +572,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
>  	if (!(msg->flags & I2C_M_RD))
>  		w |= OMAP_I2C_CON_TRX;
>  
> -	if (!dev->b_hw && stop)
> -		w |= OMAP_I2C_CON_STP;
> -
>  	omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
>  
>  	/*
> -	 * Don't write stt and stp together on some hardware.
> -	 */
> -	if (dev->b_hw && stop) {
> -		unsigned long delay = jiffies + OMAP_I2C_TIMEOUT;
> -		u16 con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
> -		while (con & OMAP_I2C_CON_STT) {
> -			con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
> -
> -			/* Let the user know if i2c is in a bad state */
> -			if (time_after(jiffies, delay)) {
> -				dev_err(dev->dev, "controller timed out "
> -				"waiting for start condition to finish\n");
> -				return -ETIMEDOUT;
> -			}
> -			cpu_relax();
> -		}
> -
> -		w |= OMAP_I2C_CON_STP;
> -		w &= ~OMAP_I2C_CON_STT;
> -		omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
> -	}
> -
> -	/*
>  	 * REVISIT: We should abort the transfer on signals, but the bus goes
>  	 * into arbitration and we're currently unable to recover from it.
>  	 */
> @@ -594,36 +584,36 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
>  	if (timeout == 0) {
>  		dev_err(dev->dev, "controller timed out\n");
>  		ret = -ETIMEDOUT;
> -		goto err_i2c_init;
> +		omap_i2c_init(dev);
> +		goto out;
>  	}
>  
>  	/* We have an error */
>  	if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR |
>  			    OMAP_I2C_STAT_XUDF)) {
>  		ret = -EIO;
> -		goto err_i2c_init;
> +		omap_i2c_init(dev);
> +		goto out;
>  	}
>  
>  	if (dev->cmd_err & OMAP_I2C_STAT_NACK) {
>  		if (msg->flags & I2C_M_IGNORE_NAK)
>  			return 0;
>  
> -		if (stop) {
> -			w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
> -			w |= OMAP_I2C_CON_STP;
> -			omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
> -		}
> -
>  		ret = -EREMOTEIO;
> -		goto err;
> +		omap_i2c_init(dev);

this is wrong. I will resend this patch alone. My bad.

-- 
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121025/d51dc1cc/attachment.sig>


More information about the linux-arm-kernel mailing list