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
+28 -16
View File
@@ -74,7 +74,7 @@
* Pre-processor Definitions * 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 #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) static int kinetis_i2c_start(struct kinetis_i2cdev_s *priv)
{ {
struct i2c_msg_s *msg; struct i2c_msg_s *msg;
systime_t start;
i2cinfo("START msg=%p\n", priv->msgs); i2cinfo("START msg=%p\n", priv->msgs);
msg = priv->msgs; msg = priv->msgs;
@@ -816,9 +817,18 @@ static int kinetis_i2c_start(struct kinetis_i2cdev_s *priv)
} }
else 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) */ /* 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 */ 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 */ /* Initiate the transfer, in case restart is required */
kinetis_i2c_start(priv); if (kinetis_i2c_start(priv) < 0)
{
goto timeout;
}
} }
/* Wait for transfer complete */ /* Wait for transfer complete */
@@ -1194,20 +1212,14 @@ static int kinetis_i2c_transfer(struct i2c_master_s *dev,
/* Disable interrupts */ /* Disable interrupts */
timeout:
kinetis_i2c_putreg(priv, I2C_C1_IICEN, KINETIS_I2C_C1_OFFSET); kinetis_i2c_putreg(priv, I2C_C1_IICEN, KINETIS_I2C_C1_OFFSET);
/* Release access to I2C bus */ /* Release access to I2C bus */
kinetis_i2c_sem_post(priv); kinetis_i2c_sem_post(priv);
if (priv->state != STATE_OK) return (priv->state != STATE_OK) ? -EIO : 0;
{
return -EIO;
}
else
{
return 0;
}
} }
/************************************************************************************ /************************************************************************************