mirror of
https://github.com/apache/nuttx.git
synced 2026-05-27 11:26:12 +08:00
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:
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
|
|||||||
Reference in New Issue
Block a user