Merged in v01d/nuttx/kinetis-i2c-norestart (pull request #114)

support NORESTART on kinetis i2c
This commit is contained in:
Gregory Nutt 2016-08-14 13:27:39 -06:00
commit 2b32869b49

View File

@ -102,6 +102,8 @@ struct kinetis_i2cdev_s
WDOG_ID timeout; /* watchdog to timeout when bus hung */
uint32_t frequency; /* Current I2C frequency */
int restart; /* Should next transfer restart or not */
struct i2c_msg_s *msgs; /* remaining transfers - first one is in
* progress */
unsigned int nmsg; /* number of transfer remaining */
@ -523,7 +525,13 @@ void kinetis_i2c_nextmsg(struct kinetis_i2cdev_s *priv)
if (priv->nmsg > 0)
{
priv->msgs++;
sem_post(&priv->wait);
priv->wrcnt = 0;
priv->rdcnt = 0;
if (priv->restart)
{
sem_post(&priv->wait);
}
}
else
{
@ -601,6 +609,16 @@ static int kinetis_i2c_interrupt(int irq, FAR void *context)
/* Continue with next message */
kinetis_i2c_nextmsg(priv);
if (!priv->restart)
{
/* Initiate transfer of following message */
putreg8(priv->msgs->buffer[priv->wrcnt], KINETIS_I2C0_D);
priv->wrcnt++;
sem_post(&priv->wait);
}
}
else
{
@ -615,7 +633,8 @@ static int kinetis_i2c_interrupt(int irq, FAR void *context)
else
{
if (msg->length == 1) /* go to RX mode, do not send ACK */
if (msg->length == 1 && priv->restart) /* go to RX mode,
do not send ACK */
{
putreg8(I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST |
I2C_C1_TXAK, KINETIS_I2C0_C1);
@ -642,14 +661,28 @@ static int kinetis_i2c_interrupt(int irq, FAR void *context)
if (priv->rdcnt == (msg->length - 1))
{
/* go to TX mode before last read, otherwise a new read is
* triggered.
*/
if (priv->restart)
{
/* go to TX mode before last read, otherwise a new read is
* triggered.
*/
/* Go to TX mode */
/* Go to TX mode */
putreg8(I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TX,
KINETIS_I2C0_C1);
putreg8(I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TX,
KINETIS_I2C0_C1);
}
else if ((priv->msgs + 1)->length == 1)
{
/* we will continue reception on next message.
* if next message is length == 1, this is actually the 2nd to
* last byte, so do not send ACK */
/* Do not ACK any more */
putreg8(I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TXAK,
KINETIS_I2C0_C1);
}
msg->buffer[priv->rdcnt] = getreg8(KINETIS_I2C0_D);
priv->rdcnt++;
@ -661,10 +694,13 @@ static int kinetis_i2c_interrupt(int irq, FAR void *context)
else if (priv->rdcnt == (msg->length - 2))
{
/* Do not ACK any more */
if (priv->restart)
{
/* Do not ACK any more */
putreg8(I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TXAK,
KINETIS_I2C0_C1);
putreg8(I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TXAK,
KINETIS_I2C0_C1);
}
msg->buffer[priv->rdcnt] = getreg8(KINETIS_I2C0_D);
priv->rdcnt++;
@ -692,6 +728,7 @@ static int kinetis_i2c_transfer(FAR struct i2c_master_s *dev,
FAR struct i2c_msg_s *msgs, int count)
{
struct kinetis_i2cdev_s *priv = (struct kinetis_i2cdev_s *)dev;
int msg_n;
DEBUGASSERT(dev != NULL);
@ -701,9 +738,12 @@ static int kinetis_i2c_transfer(FAR struct i2c_master_s *dev,
/* Set up for the transfer */
msg_n = 0;
priv->msgs = msgs;
priv->nmsg = count;
priv->state = STATE_OK;
priv->wrcnt = 0;
priv->rdcnt = 0;
/* Configure the I2C frequency. REVISIT: Note that the frequency is set
* only on the first message. This could be extended to support
@ -720,12 +760,37 @@ static int kinetis_i2c_transfer(FAR struct i2c_master_s *dev,
while (priv->nmsg && priv->state == STATE_OK)
{
priv->wrcnt = 0;
priv->rdcnt = 0;
priv->restart = 1;
/* Initiate the transfer */
/* process NORESTART flag */
kinetis_i2c_start(priv);
if (priv->nmsg > 1)
{
struct i2c_msg_s* nextmsg = (priv->msgs + 1);
/* if there is a following message with "norestart" flag of
* the same type as the current one, we can avoid the restart
*/
if ((nextmsg->flags & I2C_M_NORESTART) &&
nextmsg->addr == priv->msgs->addr &&
nextmsg->frequency == priv->msgs->frequency &&
(nextmsg->flags & I2C_M_READ) == (priv->msgs->flags & I2C_M_READ))
{
/* "no restart" can be performed */
priv->restart = 0;
}
}
/* only send start when required (we are trusting the flags setting to be correctly used here) */
if (!(priv->msgs->flags & I2C_M_NORESTART))
{
/* Initiate the transfer, in case restart is required */
kinetis_i2c_start(priv);
}
/* Wait for transfer complete */
@ -734,6 +799,8 @@ static int kinetis_i2c_transfer(FAR struct i2c_master_s *dev,
sem_wait(&priv->wait);
wd_cancel(priv->timeout);
msg_n++;
}
/* Disable interrupts */