Merged in david_s5/nuttx/master_kinetis_i2c_fix (pull request #711)

kinetis:i2c ensure timeout on bus error

The code had a dead wait on I2C_S_BUSY. Noise on the
   bus would cause the driver to hang.

   Add timeout on invalid states of I2C_S_BUSY to allow
   the upper layers do deal with restart or abort.

Approved-by: GregoryN <gnutt@nuttx.org>
This commit is contained in:
David Sidrane 2018-08-25 12:48:29 +00:00 committed by GregoryN
parent 324e1412ef
commit aa409f46ab

View File

@ -74,7 +74,7 @@
* Pre-processor Definitions
****************************************************************************/
#define I2C_TIMEOUT (20*1000/CONFIG_USEC_PER_TICK) /* 20 mS */
#define I2C_TIMEOUT USEC2TICK(20*1000) /* 20 mS */
#define I2C_DEFAULT_FREQUENCY 400000
@ -801,6 +801,7 @@ static void kinetis_i2c_setfrequency(struct kinetis_i2cdev_s *priv,
static int kinetis_i2c_start(struct kinetis_i2cdev_s *priv)
{
struct i2c_msg_s *msg;
systime_t start;
i2cinfo("START msg=%p\n", priv->msgs);
msg = priv->msgs;
@ -816,9 +817,18 @@ static int kinetis_i2c_start(struct kinetis_i2cdev_s *priv)
}
else
{
/* We are not currently the bus master, so wait for bus ready */
/* We are not currently the bus master, wait for bus ready or timeout */
while (kinetis_i2c_getreg(priv, KINETIS_I2C_S_OFFSET) & I2C_S_BUSY);
start = clock_systimer();
while (kinetis_i2c_getreg(priv, KINETIS_I2C_S_OFFSET) & I2C_S_BUSY)
{
if (clock_systimer() - start > I2C_TIMEOUT)
{
priv->state = STATE_TIMEOUT;
return -EIO;
}
}
/* Become the bus master in transmit mode (send start) */
@ -828,13 +838,18 @@ static int kinetis_i2c_start(struct kinetis_i2cdev_s *priv)
if (I2C_M_READ & msg->flags) /* DEBUG: should happen always */
{
/* Wait until start condition establishes control of the bus */
/* Wait until start condition establishes control of the bus or
* a timeout occurs
*/
while (1)
start = clock_systimer();
while ((kinetis_i2c_getreg(priv, KINETIS_I2C_S_OFFSET) & I2C_S_BUSY) == 0)
{
if (kinetis_i2c_getreg(priv, KINETIS_I2C_S_OFFSET) & I2C_S_BUSY)
if (clock_systimer() - start > I2C_TIMEOUT)
{
break;
priv->state = STATE_TIMEOUT;
return -EIO;
}
}
}
@ -1178,7 +1193,10 @@ static int kinetis_i2c_transfer(struct i2c_master_s *dev,
{
/* Initiate the transfer, in case restart is required */
kinetis_i2c_start(priv);
if (kinetis_i2c_start(priv) < 0)
{
goto timeout;
}
}
/* Wait for transfer complete */
@ -1194,20 +1212,14 @@ static int kinetis_i2c_transfer(struct i2c_master_s *dev,
/* Disable interrupts */
timeout:
kinetis_i2c_putreg(priv, I2C_C1_IICEN, KINETIS_I2C_C1_OFFSET);
/* Release access to I2C bus */
kinetis_i2c_sem_post(priv);
if (priv->state != STATE_OK)
{
return -EIO;
}
else
{
return 0;
}
return (priv->state != STATE_OK) ? -EIO : 0;
}
/************************************************************************************