arch/arm/src/samd2l2/sam_i2c_master.c: Corrects behavior of the I2C_M_NOSTART flag. Also adds a release a bus on RXNACK and corrects typo priv->flags to msg->flags as priv->flags is never set.

This commit is contained in:
Alexander Vasiliev 2018-12-22 08:03:29 -06:00 committed by Gregory Nutt
parent ebbfb225f6
commit b1110ba91c

View File

@ -168,6 +168,7 @@ struct sam_i2c_dev_s
struct i2c_msg_s *msg; /* Current message being processed */
uint32_t frequency; /* I2C transfer clock frequency */
uint16_t flags; /* Transfer flags */
uint16_t nextflags; /* Next message flags */
sem_t exclsem; /* Only one thread can access at a time */
sem_t waitsem; /* Wait for I2C transfer completion */
@ -707,11 +708,13 @@ static int i2c_interrupt(int irq, FAR void *context, FAR void *arg)
i2c_wait_synchronization(priv);
/* STOP */
regval = i2c_getreg32(priv, SAM_I2C_CTRLB_OFFSET);
regval |= I2C_CTRLB_CMD_ACKSTOP;
i2c_putreg32(priv, regval, SAM_I2C_CTRLB_OFFSET);
i2c_wait_synchronization(priv);
if ((priv->nextflags & I2C_M_NOSTART) == 0)
{
regval = i2c_getreg32(priv, SAM_I2C_CTRLB_OFFSET);
regval |= I2C_CTRLB_CMD_ACKSTOP;
i2c_putreg32(priv, regval, SAM_I2C_CTRLB_OFFSET);
i2c_wait_synchronization(priv);
}
msg->buffer[priv->xfrd++] = i2c_getreg8(priv, SAM_I2C_DATA_OFFSET);
i2c_wait_synchronization(priv);
@ -754,6 +757,13 @@ static int i2c_interrupt(int irq, FAR void *context, FAR void *arg)
if ((i2c_getreg16(priv, SAM_I2C_STATUS_OFFSET) & I2C_STATUS_RXNACK) ==
I2C_STATUS_RXNACK)
{
/* Send STOP condition */
regval = i2c_getreg32(priv, SAM_I2C_CTRLB_OFFSET);
regval |= I2C_CTRLB_CMD_ACKSTOP;
i2c_putreg32(priv, regval, SAM_I2C_CTRLB_OFFSET);
i2c_wait_synchronization(priv);
i2c_wakeup(priv, -ENODEV);
return OK;
}
@ -762,10 +772,13 @@ static int i2c_interrupt(int irq, FAR void *context, FAR void *arg)
{
/* Send STOP condition */
regval = i2c_getreg32(priv, SAM_I2C_CTRLB_OFFSET);
regval |= I2C_CTRLB_CMD_ACKSTOP;
i2c_putreg32(priv, regval, SAM_I2C_CTRLB_OFFSET);
i2c_wait_synchronization(priv);
if ((priv->nextflags & I2C_M_NOSTART) == 0)
{
regval = i2c_getreg32(priv, SAM_I2C_CTRLB_OFFSET);
regval |= I2C_CTRLB_CMD_ACKSTOP;
i2c_putreg32(priv, regval, SAM_I2C_CTRLB_OFFSET);
i2c_wait_synchronization(priv);
}
i2c_wakeup(priv, OK);
}
@ -867,18 +880,26 @@ static void i2c_startwrite(struct sam_i2c_dev_s *priv, struct i2c_msg_s *msg)
/* 7 or 10 bits ? */
if (priv->flags & I2C_M_TEN)
if ((msg->flags & I2C_M_TEN) != 0)
{
regval |= I2C_ADDR_TENBITEN;
}
/* Is it a read or write? */
regval |= (priv->flags & I2C_M_READ);
regval |= (msg->flags & I2C_M_READ);
/* Set the ADDR register */
i2c_putreg32(priv, regval, SAM_I2C_ADDR_OFFSET);
if ((msg->flags & I2C_M_NOSTART) == 0)
{
i2c_putreg32(priv, regval, SAM_I2C_ADDR_OFFSET);
}
else
{
i2c_putreg8(priv, msg->buffer[priv->xfrd++], SAM_I2C_DATA_OFFSET);
}
i2c_wait_synchronization(priv);
}
@ -966,6 +987,7 @@ static int sam_i2c_transfer(FAR struct i2c_master_s *dev,
while (count--)
{
priv->msg = msgs;
priv->nextflags = count == 0 ? 0 : msgs[1].flags;
flags = enter_critical_section();
i2c_startmessage(priv, msgs);