Tiva I2C: Driver is code complete but untested

This commit is contained in:
Gregory Nutt 2014-12-10 12:43:46 -06:00
parent 03e1ecd6aa
commit 58d0e169c7
2 changed files with 322 additions and 372 deletions

View File

@ -543,7 +543,7 @@
/* I2C Master Interrupt Mask (I2CM_IMR) */
#define I2CM_IMR_IM (1 << 0) /* Bit 0: Interrupt Mask */
#define I2CM_IMR_MIM (1 << 0) /* Bit 0: Master Interrupt Mask */
#if defined(CONFIG_ARCH_CHIP_TM4C123GH6ZRB) || \
defined(CONFIG_ARCH_CHIP_TM4C1294NCPDT)
@ -565,68 +565,68 @@
/* I2C Master Raw Interrupt Status (I2CM_RIS) */
#define I2CM_RIS_RIS (1 << 0) /* Bit 0: Raw Interrupt Status */
#define I2CM_RIS_MRIS (1 << 0) /* Bit 0: Master Raw Interrupt Status */
#if defined(CONFIG_ARCH_CHIP_TM4C123GH6ZRB) || \
defined(CONFIG_ARCH_CHIP_TM4C1294NCPDT)
# define I2CM_RIS_CLKRIS (1 << 1) /* Bit 1: Clock Timeout Raw Interrupt Status */
# define I2CM_RIS_CLKRIS (1 << 1) /* Bit 1: Clock Timeout Raw Interrupt Status */
#endif
#if defined(CONFIG_ARCH_CHIP_TM4C1294NCPDT)
# define I2CM_RIS_DMARXRIS (1 << 2) /* Bit 2: Receive DMA Interrupt Mask */
# define I2CM_RIS_DMATXRIS (1 << 3) /* Bit 3: Transmit DMA Interrupt Mask */
# define I2CM_RIS_NACKRIS (1 << 4) /* Bit 4: Address/Data NACK Interrupt Mask */
# define I2CM_RIS_STARTRIS (1 << 5) /* Bit 5: START Detection Interrupt Mask */
# define I2CM_RIS_STOPRIS (1 << 6) /* Bit 6: STOP Detection Interrupt Mask */
# define I2CM_RIS_ARBLOSTRIS (1 << 7) /* Bit 7: Arbitration Lost Interrupt Mask */
# define I2CM_RIS_TXRIS (1 << 8) /* Bit 8: Transmit FIFO Request Interrupt Mask */
# define I2CM_RIS_RXRIS (1 << 9) /* Bit 9: Receive FIFO Request Interrupt Mask */
# define I2CM_RIS_TXFERIS (1 << 10) /* Bit 10: Transmit FIFO Empty Interrupt Mask */
# define I2CM_RIS_RXFFRIS (1 << 11) /* Bit 11: Receive FIFO Full Interrupt Mask */
# define I2CM_RIS_DMARXRIS (1 << 2) /* Bit 2: Receive DMA Interrupt Status */
# define I2CM_RIS_DMATXRIS (1 << 3) /* Bit 3: Transmit DMA Interrupt Status */
# define I2CM_RIS_NACKRIS (1 << 4) /* Bit 4: Address/Data NACK Interrupt Status */
# define I2CM_RIS_STARTRIS (1 << 5) /* Bit 5: START Detection Interrupt Status */
# define I2CM_RIS_STOPRIS (1 << 6) /* Bit 6: STOP Detection Interrupt Status */
# define I2CM_RIS_ARBLOSTRIS (1 << 7) /* Bit 7: Arbitration Lost Interrupt Status */
# define I2CM_RIS_TXRIS (1 << 8) /* Bit 8: Transmit FIFO Request Interrupt Status */
# define I2CM_RIS_RXRIS (1 << 9) /* Bit 9: Receive FIFO Request Interrupt Status */
# define I2CM_RIS_TXFERIS (1 << 10) /* Bit 10: Transmit FIFO Empty Interrupt Status */
# define I2CM_RIS_RXFFRIS (1 << 11) /* Bit 11: Receive FIFO Full Interrupt Status */
#endif
/* I2C Master Masked Interrupt Status (I2CM_MIS) */
#define I2CM_MIS_MIS (1 << 0) /* Bit 0: Masked Interrupt Status */
#define I2CM_MIS_MMIS (1 << 0) /* Bit 0: Maseter Masked Interrupt Status */
#if defined(CONFIG_ARCH_CHIP_TM4C123GH6ZRB) || \
defined(CONFIG_ARCH_CHIP_TM4C1294NCPDT)
# define I2CM_MIS_CLKMIS (1 << 1) /* Bit 1: Clock Timeout Masked Interrupt Status */
# define I2CM_MIS_CLKMIS (1 << 1) /* Bit 1: Clock Timeout Masked Interrupt Status */
#endif
#if defined(CONFIG_ARCH_CHIP_TM4C1294NCPDT)
# define I2CM_MIS_DMARXMIS (1 << 2) /* Bit 2: Receive DMA Interrupt Mask */
# define I2CM_MIS_DMATXMIS (1 << 3) /* Bit 3: Transmit DMA Interrupt Mask */
# define I2CM_MIS_NACKMIS (1 << 4) /* Bit 4: Address/Data NACK Interrupt Mask */
# define I2CM_MIS_STARTMIS (1 << 5) /* Bit 5: START Detection Interrupt Mask */
# define I2CM_MIS_STOPMIS (1 << 6) /* Bit 6: STOP Detection Interrupt Mask */
# define I2CM_MIS_ARBLOSTMIS (1 << 7) /* Bit 7: Arbitration Lost Interrupt Mask */
# define I2CM_MIS_TXMIS (1 << 8) /* Bit 8: Transmit FIFO Request Interrupt Mask */
# define I2CM_MIS_RXMIS (1 << 9) /* Bit 9: Receive FIFO Request Interrupt Mask */
# define I2CM_MIS_TXFEMIS (1 << 10) /* Bit 10: Transmit FIFO Empty Interrupt Mask */
# define I2CM_MIS_RXFFMIS (1 << 11) /* Bit 11: Receive FIFO Full Interrupt Mask */
# define I2CM_MIS_DMARXMIS (1 << 2) /* Bit 2: Receive DMA Interrupt Status */
# define I2CM_MIS_DMATXMIS (1 << 3) /* Bit 3: Transmit DMA Interrupt Status */
# define I2CM_MIS_NACKMIS (1 << 4) /* Bit 4: Address/Data NACK Interrupt Status */
# define I2CM_MIS_STARTMIS (1 << 5) /* Bit 5: START Detection Interrupt Status */
# define I2CM_MIS_STOPMIS (1 << 6) /* Bit 6: STOP Detection Interrupt Status */
# define I2CM_MIS_ARBLOSTMIS (1 << 7) /* Bit 7: Arbitration Lost Interrupt Status */
# define I2CM_MIS_TXMIS (1 << 8) /* Bit 8: Transmit FIFO Request Interrupt Status */
# define I2CM_MIS_RXMIS (1 << 9) /* Bit 9: Receive FIFO Request Interrupt Status */
# define I2CM_MIS_TXFEMIS (1 << 10) /* Bit 10: Transmit FIFO Empty Interrupt Status */
# define I2CM_MIS_RXFFMIS (1 << 11) /* Bit 11: Receive FIFO Full Interrupt Status */
#endif
/* I2C Master Masked Interrupt Status (I2CM_ICR) */
#define I2CM_ICR_IC (1 << 0) /* Bit 0: Masked Interrupt Status */
#define I2CM_ICR_MIC (1 << 0) /* Bit 0: Master Masked Interrupt Clear */
#if defined(CONFIG_ARCH_CHIP_TM4C123GH6ZRB) || \
defined(CONFIG_ARCH_CHIP_TM4C1294NCPDT)
# define I2CM_ICR_CLKIC (1 << 1) /* Bit 1: Clock Timeout Interrupt Clear */
# define I2CM_ICR_CLKC (1 << 1) /* Bit 1: Clock Timeout Interrupt Clear */
#endif
#if defined(CONFIG_ARCH_CHIP_TM4C1294NCPDT)
# define I2CM_ICR_DMARXIC (1 << 2) /* Bit 2: Receive DMA Interrupt Mask */
# define I2CM_ICR_DMATXIC (1 << 3) /* Bit 3: Transmit DMA Interrupt Mask */
# define I2CM_ICR_NACKIC (1 << 4) /* Bit 4: Address/Data NACK Interrupt Mask */
# define I2CM_ICR_STARTIC (1 << 5) /* Bit 5: START Detection Interrupt Mask */
# define I2CM_ICR_STOPIC (1 << 6) /* Bit 6: STOP Detection Interrupt Mask */
# define I2CM_ICR_ARBLOSTIC (1 << 7) /* Bit 7: Arbitration Lost Interrupt Mask */
# define I2CM_ICR_TXIC (1 << 8) /* Bit 8: Transmit FIFO Request Interrupt Mask */
# define I2CM_ICR_RXIC (1 << 9) /* Bit 9: Receive FIFO Request Interrupt Mask */
# define I2CM_ICR_DMARXIC (1 << 2) /* Bit 2: Receive DMA Interrupt Clear */
# define I2CM_ICR_DMATXIC (1 << 3) /* Bit 3: Transmit DMA Interrupt Clear */
# define I2CM_ICR_NACKIC (1 << 4) /* Bit 4: Address/Data NACK Interrupt Clear */
# define I2CM_ICR_STARTIC (1 << 5) /* Bit 5: START Detection Interrupt Clear */
# define I2CM_ICR_STOPIC (1 << 6) /* Bit 6: STOP Detection Interrupt Clear */
# define I2CM_ICR_ARBLOSTIC (1 << 7) /* Bit 7: Arbitration Lost Interrupt Clear */
# define I2CM_ICR_TXIC (1 << 8) /* Bit 8: Transmit FIFO Request Interrupt Clear */
# define I2CM_ICR_RXIC (1 << 9) /* Bit 9: Receive FIFO Request Interrupt Clear */
# define I2CM_ICR_TXFEIC (1 << 10) /* Bit 10: Transmit FIFO Empty Interrupt Mask */
# define I2CM_ICR_RXFFIC (1 << 11) /* Bit 11: Receive FIFO Full Interrupt Mask */
# define I2CM_ICR_RXFFIC (1 << 11) /* Bit 11: Receive FIFO Full Interrupt Clear */
#endif
/* I2C Master Configuration (I2CM_CR) */

View File

@ -4,7 +4,8 @@
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Derives in spirit if nothing more from the NuttX STM32 I2C driver which has:
* The basic structure of this driver derives in spirit (if nothing more) from the
* NuttX STM32 I2C driver which has:
*
* Copyright (C) 2011 Uros Platise. All rights reserved.
* Author: Uros Platise <uros.platise@isotel.eu>
@ -147,8 +148,9 @@
enum tiva_intstate_e
{
INTSTATE_IDLE = 0, /* No I2C activity */
INTSTATE_WAITING, /* Waiting for completion of interrupt activity */
INTSTATE_DONE, /* Interrupt activity complete */
INTSTATE_ADDRESS, /* Address sent, waiting for completion */
INTSTATE_XFRWAIT, /* Waiting for data transfer to complete */
INTSTATE_DONE /* Interrupt activity complete */
};
/* Trace events */
@ -156,16 +158,15 @@ enum tiva_intstate_e
enum tiva_trace_e
{
I2CEVENT_NONE = 0, /* No events have occurred with this status */
I2CEVENT_SENDADDR, /* Start/Master bit set and address sent, param = msgc */
I2CEVENT_SENDADDRESS, /* Address sent, param = address */
I2CEVENT_ERROR, /* Error occurred, param = MCS */
I2CEVENT_BUSY, /* Still busy, param = MCS */
I2CEVENT_XFRDONE, /* Transfer completed without error, param = dcnt */
I2CEVENT_RECVSETUP, /* Setup to receive the next byte, param = dcnt */
I2CEVENT_SENDBYTE, /* Send byte, param = dcnt */
I2CEVENT_ITBUFEN, /* Enable buffer interrupts, param = 0 */
I2CEVENT_RCVBYTE, /* Read more dta, param = dcnt */
I2CEVENT_REITBUFEN, /* Re-enable buffer interrupts, param = 0 */
I2CEVENT_DISITBUFEN, /* Disable buffer interrupts, param = 0 */
I2CEVENT_BTFNOSTART, /* BTF on last byte with no restart, param = msgc */
I2CEVENT_BTFRESTART, /* Last byte sent, re-starting, param = msgc */
I2CEVENT_BTFSTOP, /* Last byte sten, send stop, param = 0 */
I2CEVENT_ERROR /* Error occurred, param = 0 */
I2CEVENT_SPURIOUS, /* Spurious interrupt received, param = msgc */
I2CEVENT_NEXTMSG, /* Starting next message, param = msgc */
I2CEVENT_DONE /* All messages transferred, param = intstate */
};
/* Trace data */
@ -213,6 +214,7 @@ struct tiva_i2c_priv_s
uint8_t *ptr; /* Current message buffer */
int dcnt; /* Current message length */
uint16_t flags; /* Current message flags */
uint32_t status; /* MCS register at the end of the transfer */
/* I2C trace support */
@ -234,7 +236,7 @@ struct tiva_i2c_inst_s
struct tiva_i2c_priv_s *priv; /* Common driver private data structure */
uint32_t frequency; /* Frequency used in this instantiation */
int address; /* Address used in this instantiation */
uint16_t address; /* Address used in this instantiation */
uint16_t flags; /* Flags used in this instantiation */
};
@ -256,7 +258,6 @@ static useconds_t tiva_i2c_tousecs(int msgc, struct i2c_msg_s *msgs);
#endif /* CONFIG_TIVA_I2C_DYNTIMEO */
static inline int tiva_i2c_sem_waitdone(struct tiva_i2c_priv_s *priv);
static inline void tiva_i2c_sem_waitstop(struct tiva_i2c_priv_s *priv);
static inline void tiva_i2c_sem_post(struct i2c_dev_s *dev);
static inline void tiva_i2c_sem_init(struct i2c_dev_s *dev);
static inline void tiva_i2c_sem_destroy(struct i2c_dev_s *dev);
@ -269,10 +270,8 @@ static void tiva_i2c_traceevent(struct tiva_i2c_priv_s *priv,
static void tiva_i2c_tracedump(struct tiva_i2c_priv_s *priv);
#endif /* CONFIG_I2C_TRACE */
static inline void tiva_i2c_sendstart(struct tiva_i2c_priv_s *priv);
static inline void tiva_i2c_clrstart(struct tiva_i2c_priv_s *priv);
static inline void tiva_i2c_sendstop(struct tiva_i2c_priv_s *priv);
static void tiva_i2c_sendaddress(struct tiva_i2c_priv_s *priv);
static void tiva_i2c_nextxfr(struct tiva_i2c_priv_s *priv);
static int tiva_i2c_interrupt(struct tiva_i2c_priv_s * priv, uint32_t status);
#ifndef CONFIG_I2C_POLLED
@ -565,24 +564,22 @@ static inline int tiva_i2c_sem_waitdone(struct tiva_i2c_priv_s *priv)
{
struct timespec abstime;
irqstate_t flags;
uint32_t regval;
int ret;
flags = irqsave();
/* Enable the master interrupt. The I2C master module generates an interrupt when
/* Enable the master interrupt. The I2C master module generates an interrupt when
* a transaction completes (either transmit or receive), when arbitration is lost,
* or when an error occurs during a transaction.
*/
tiva_i2c_putreg(priv, TIVA_I2CM_IMR_OFFSET, I2CM_IMR_IM);
tiva_i2c_putreg(priv, TIVA_I2CM_IMR_OFFSET, I2CM_IMR_MIM);
/* Signal the interrupt handler that we are waiting. NOTE: Interrupts
* are currently disabled but will be temporarily re-enabled below when
* sem_timedwait() sleeps.
*/
priv->intstate = INTSTATE_WAITING;
do
{
/* Get the current time */
@ -665,7 +662,6 @@ static inline int tiva_i2c_sem_waitdone(struct tiva_i2c_priv_s *priv)
* sem_timedwait() sleeps.
*/
priv->intstate = INTSTATE_WAITING;
start = clock_systimer();
do
@ -700,60 +696,6 @@ static inline int tiva_i2c_sem_waitdone(struct tiva_i2c_priv_s *priv)
}
#endif
/************************************************************************************
* Name: tiva_i2c_sem_waitstop
*
* Description:
* Wait for a STOP to complete
*
************************************************************************************/
static inline void tiva_i2c_sem_waitstop(struct tiva_i2c_priv_s *priv)
{
uint32_t start;
uint32_t elapsed;
uint32_t timeout;
/* Select a timeout */
#ifdef CONFIG_TIVA_I2C_DYNTIMEO
timeout = USEC2TICK(CONFIG_TIVA_I2C_DYNTIMEO_STARTSTOP);
#else
timeout = CONFIG_TIVA_I2CTIMEOTICKS;
#endif
/* Wait as stop might still be in progress; but stop might also
* be set because of a timeout error: "The [STOP] bit is set and
* cleared by software, cleared by hardware when a Stop condition is
* detected, set by hardware when a timeout error is detected."
*/
start = clock_systimer();
do
{
/* Check for STOP condition */
#warning Missing logic
/* Check for timeout error */
#warning Missing logic
/* Calculate the elapsed time */
elapsed = clock_systimer() - start;
}
/* Loop until the stop is complete or a timeout occurs. */
while (elapsed < timeout);
/* If we get here then a timeout occurred with the STOP condition
* still pending.
*/
i2cvdbg("Timeout with CR1: %04x SR1: %04x\n", cr1, sr1);
}
/************************************************************************************
* Name: tiva_i2c_sem_post
*
@ -920,43 +862,115 @@ static void tiva_i2c_tracedump(struct tiva_i2c_priv_s *priv)
#endif /* CONFIG_I2C_TRACE */
/************************************************************************************
* Name: tiva_i2c_sendstart
* Name: tiva_i2c_sendaddress
*
* Description:
* Send the START conditions/force Master mode
*
************************************************************************************/
static inline void tiva_i2c_sendstart(struct tiva_i2c_priv_s *priv)
static void tiva_i2c_sendaddress(struct tiva_i2c_priv_s *priv)
{
/* Disable ACK on receive by default and generate START */
#warning Missing logic
struct i2c_msg_s *msg;
uint32_t regval;
DEBUGASSERT(priv && priv->msgc > 0);
/* Check for new trace setup, post the SENADDRESS event */
tiva_i2c_tracenew(priv, 0);
/* Get run-time data for the next message */
msg = priv->msgv;
priv->ptr = msg->buffer;
priv->dcnt = msg->length;
priv->flags = msg->flags;
/* Set the Master Slave Address */
regval = (uint32_t)msg->addr << I2CM_SA_SA_SHIFT;
if ((msg->flags & I2C_M_READ) != 0)
{
regval |= I2CM_SA_RS;
}
tiva_i2c_putreg(priv, TIVA_I2CM_SA_OFFSET, regval);
/* Write the command to the control register */
regval = I2CM_CS_RUN;
if ((msg->flags & I2C_M_NORESTART) == 0)
{
regval |= I2CM_CS_START;
}
if (priv->dcnt < 1)
{
regval |= I2CM_CS_STOP;
}
tiva_i2c_putreg(priv, TIVA_I2CM_CS_OFFSET, regval);
tiva_i2c_traceevent(priv, I2CEVENT_SENDADDRESS, msg->addr);
priv->intstate = INTSTATE_ADDRESS;
}
/************************************************************************************
* Name: tiva_i2c_clrstart
* Name: tiva_i2c_nextxfr
*
* Description:
* Clear the STOP, START or PEC condition on certain error recovery steps.
* Common Interrupt Service Routine
*
************************************************************************************/
static inline void tiva_i2c_clrstart(struct tiva_i2c_priv_s *priv)
static void tiva_i2c_nextxfr(struct tiva_i2c_priv_s *priv)
{
#warning Missing logic
}
uint32_t cmd;
/************************************************************************************
* Name: tiva_i2c_sendstop
*
* Description:
* Send the STOP conditions
*
************************************************************************************/
/* Set up the basic command. The STOP bit should be set on the last transfer
* UNLESS this there is a repeated start.
*/
static inline void tiva_i2c_sendstop(struct tiva_i2c_priv_s *priv)
{
#warning Missing logic
cmd = I2CM_CS_RUN;
if (priv->msgc < 2 && priv->dcnt < 2)
{
/* This is the last byte of the last message... add the STOP bit */
cmd |= I2CM_CS_STOP;
}
/* Set up to transfer the next byte. Are we sending or receiving? */
if ((priv->flags & I2C_M_READ) != 0)
{
/* We are receiving data. Write the command to the control register to
* receive the next byte.
*/
cmd |= I2CM_CS_ACK;
tiva_i2c_putreg(priv, TIVA_I2CM_CS_OFFSET, cmd);
tiva_i2c_traceevent(priv, I2CEVENT_RECVSETUP, priv->dcnt);
}
else
{
uint32_t dr;
/* We are sending data. Write the data to be sent to the DR register. */
dr = (uint32_t)*priv->ptr++;
tiva_i2c_putreg(priv, TIVA_I2CM_DR_OFFSET, dr << I2CM_DR_SHIFT);
/* Write the command to the control register to send the byte in the DR
* register.
*/
tiva_i2c_putreg(priv, TIVA_I2CM_CS_OFFSET, cmd);
tiva_i2c_traceevent(priv, I2CEVENT_SENDBYTE, priv->dcnt);
}
priv->intstate = INTSTATE_XFRWAIT;
}
/************************************************************************************
@ -973,216 +987,199 @@ static int tiva_i2c_interrupt(struct tiva_i2c_priv_s *priv, uint32_t status)
tiva_i2c_tracenew(priv, status);
/* Was start bit sent */
#warning Missing logic
{
tiva_i2c_traceevent(priv, I2CEVENT_SENDADDR, priv->msgc);
/* We check for msgc > 0 here as an unexpected interrupt with
* due to noise on the I2C cable can otherwise cause msgc to
* wrap causing memory overwrite
*/
if (priv->msgc > 0 && priv->msgv != NULL)
{
/* Get run-time data */
priv->ptr = priv->msgv->buffer;
priv->dcnt = priv->msgv->length;
priv->flags = priv->msgv->flags;
/* Send address byte and define addressing mode */
tiva_i2c_putreg(priv, TIVA_I2CM_SA_OFFSET,
(priv->msgv->addr << 1) | (priv->flags & I2C_M_READ));
/* Set ACK for receive mode */
#warning Missing logic
/* Increment to next pointer and decrement message count */
priv->msgv++;
priv->msgc--;
}
else
{
/* Clear ISR by writing to DR register */
#warning Missing logic
}
}
/* Was address sent, continue with either sending or reading data */
#warning Missing logic
else if ((priv->flags & I2C_M_READ) == 0 && 0 /* ? */ )
{
if (priv->dcnt > 0)
{
/* Send a byte */
#warning Missing logic
priv->dcnt--;
}
}
else if ((priv->flags & I2C_M_READ) != 0 && 0 /* ? */)
{
/* Enable in order to receive one or multiple bytes */
#warning Missing logic
}
/* More bytes to read */
#warning Missing logic
{
/* Read a byte, if dcnt goes < 0, then read dummy bytes to ack ISRs */
if (priv->dcnt > 0)
{
tiva_i2c_traceevent(priv, I2CEVENT_RCVBYTE, priv->dcnt);
/* No interrupts or context switches may occur in the following
* sequence. Otherwise, additional bytes may be sent by the
* device.
*/
#ifdef CONFIG_I2C_POLLED
irqstate_t state = irqsave();
#endif
/* Receive a byte */
#warning Missing logic
/* Disable acknowledge when last byte is to be received */
priv->dcnt--;
if (priv->dcnt == 1)
{
#warning Missing logic
}
#ifdef CONFIG_I2C_POLLED
irqrestore(state);
#endif
}
else
{
/* Throw away the unexpected byte */
#warning Missing logic
}
}
/* Do we have more bytes to send, enable/disable buffer interrupts
* (these ISRs could be replaced by DMAs)
/* Check for a master interrupt? The I2C master module generates an interrupt when
* a transaction completes (either transmit or receive), when arbitration is lost,
* or when an error occurs during a transaction.
*/
#ifndef CONFIG_I2C_POLLED
if (priv->dcnt > 0)
if ((status & I2CM_RIS_MRIS) != 0)
{
tiva_i2c_traceevent(priv, I2CEVENT_REITBUFEN, 0);
#warning Missing logic
}
else if (priv->dcnt == 0)
{
tiva_i2c_traceevent(priv, I2CEVENT_DISITBUFEN, 0);
#warning Missing logic
}
#endif
uint32_t mcs;
/* Was last byte received or sent? */
/* Clear the pending master interrupt */
if (priv->dcnt <= 0 && 0 /* ? */)
{
/* Acknowledge the pending interrupt */
#warning Missing logic
tiva_i2c_putreg(priv, TIVA_I2CM_ICR_OFFSET, I2CM_ICR_MIC);
status &= ~I2CM_RIS_MRIS;
/* Do we need to terminate or restart after this byte?
* If there are more messages to send, then we may:
*
* - continue with repeated start
* - or just continue sending writeable part
* - or we close down by sending the stop bit
/* We need look at the Master Control/Status register to determine the cause
* of the master interrupt.
*/
if (priv->msgc > 0)
{
if (priv->msgv->flags & I2C_M_NORESTART)
{
tiva_i2c_traceevent(priv, I2CEVENT_BTFNOSTART, priv->msgc);
priv->ptr = priv->msgv->buffer;
priv->dcnt = priv->msgv->length;
priv->flags = priv->msgv->flags;
priv->msgv++;
priv->msgc--;
mcs = tiva_i2c_getreg(priv, TIVA_I2CM_CS_OFFSET);
/* Restart this ISR! */
/* If the busy bit is set, then the other bits are not valid */
if ((mcs & I2CM_CS_BUSY) != 0)
{
tiva_i2c_traceevent(priv, I2CEVENT_BUSY, mcs);
}
/* Check for errors, in which case, stop the transfer and return. */
else if ((mcs & I2CM_CS_ERROR) != 0)
{
tiva_i2c_traceevent(priv, I2CEVENT_ERROR, mcs);
/* Disable further interrupts */
tiva_i2c_putreg(priv, TIVA_I2CM_IMR_OFFSET, 0);
#ifndef CONFIG_I2C_POLLED
#warning Missing logic
#endif
}
else
{
tiva_i2c_traceevent(priv, I2CEVENT_BTFRESTART, priv->msgc);
tiva_i2c_sendstart(priv);
}
}
else if (priv->msgv)
{
tiva_i2c_traceevent(priv, I2CEVENT_BTFSTOP, 0);
tiva_i2c_sendstop(priv);
/* Is there a thread waiting for this event (there should be) */
#ifndef CONFIG_I2C_POLLED
if (priv->intstate == INTSTATE_WAITING)
if (priv->intstate != INTSTATE_IDLE &&
priv->intstate != INTSTATE_DONE)
{
/* Yes.. inform the thread that the transfer is complete
* and wake it up.
*/
sem_post(&priv->waitsem);
priv->status = mcs;
priv->intstate = INTSTATE_DONE;
}
#else
priv->status = mcs;
priv->intstate = INTSTATE_DONE;
#endif
/* Mark that we have stopped with this transaction */
priv->msgv = NULL;
}
}
/* Check for errors, in which case, stop the transfer and return
* Note that in master reception mode AF becomes set on last byte
* since ACK is not returned. We should ignore this error.
*/
#warning Missing logic
/* Otherwise, the last transfer must have completed successfully */
{
tiva_i2c_traceevent(priv, I2CEVENT_ERROR, 0);
else
{
int dr;
/* Clear interrupt flags */
#warning Missing logic
tiva_i2c_traceevent(priv, I2CEVENT_XFRDONE, priv->dcnt);
/* Read from the DR register */
/* Is there a thread waiting for this event (there should be) */
dr = tiva_i2c_getreg(priv, TIVA_I2CM_DR_OFFSET);
/* We check for msgc > 0 here as an unexpected interrupt with
* due to noise on the I2C cable can otherwise cause msgc to
* wrap causing memory overwrite
*/
if (priv->msgc > 0 && priv->msgv != NULL)
{
/* Was this the completion of an address or of the data portion
* of the transfer?
*/
DEBUGASSERT(priv->dcnt > 0);
if (priv->intstate == INTSTATE_XFRWAIT)
{
/* Data transfer completed. Are we sending or receiving data? */
if ((priv->flags & I2C_M_READ) != 0)
{
/* We are receiving data. Copy the received data to
* the user buffer
*/
*priv->ptr++ = (uint8_t)dr;
}
/* Decrement the count of bytes remaining to be sent */
priv->dcnt--;
}
/* Was that the last byte of this message? */
if (priv->dcnt > 0)
{
/* Send the next byte */
tiva_i2c_nextxfr(priv);
}
else
{
/* Increment to next pointer and decrement message count */
priv->msgv++;
priv->msgc--;
/* Is there another message to be sent? */
if (priv->msgc > 0)
{
/* Do we need to terminate or restart after this byte?
* If there are more messages to send, then we may
* continue with or without the (repeated) start bit.
*/
tiva_i2c_traceevent(priv, I2CEVENT_NEXTMSG, priv->msgc);
if (priv->msgv->flags & I2C_M_NORESTART)
{
/* Just continue transferring data. In this case,
* no STOP was sent at the end of the last message
* and the there is no new address.
*
* REVISIT: In this case, the address or the
* direction of the transfer cannot be permitted to
* change
*/
tiva_i2c_nextxfr(priv);
}
else
{
/* Set the repeated start. No STOP was sent at the
* end of the previous message.
*/
tiva_i2c_sendaddress(priv);
}
}
else
{
/* No.. then we are finished */
tiva_i2c_traceevent(priv, I2CEVENT_DONE, priv->intstate);
/* Disable further interrupts */
tiva_i2c_putreg(priv, TIVA_I2CM_IMR_OFFSET, 0);
#ifndef CONFIG_I2C_POLLED
if (priv->intstate == INTSTATE_WAITING)
{
/* Yes.. inform the thread that the transfer is complete
* and wake it up.
*/
/* Is there a thread waiting for this event (there
* should be)
*/
sem_post(&priv->waitsem);
priv->intstate = INTSTATE_DONE;
}
if (priv->intstate != INTSTATE_IDLE &&
priv->intstate != INTSTATE_DONE)
{
/* Yes.. inform the thread that the transfer is
* complete and wake it up.
*/
sem_post(&priv->waitsem);
priv->status = mcs;
priv->intstate = INTSTATE_DONE;
}
#else
priv->intstate = INTSTATE_DONE;
priv->status = mcs;
priv->intstate = INTSTATE_DONE;
#endif
}
}
}
/* There is no pending message? Must be a spurious interrupt */
else
{
tiva_i2c_traceevent(priv, I2CEVENT_SPURIOUS, priv->msgc);
}
}
}
/* Make sure that all pending interrupts were handled */
DEBUGASSERT(status == 0);
return OK;
}
@ -1465,8 +1462,8 @@ static uint32_t tiva_i2c_setclock(struct tiva_i2c_priv_s *priv, uint32_t frequen
regval = tiva_i2c_putreg(priv, TIVA_I2CSC_PP_OFFSET);
if ((regval & I2CSC_PP_HS) != 0)
{
regval = ((SYSCLK_FREQUENCY +
(2 * 3 * 3400000) - 1) / (2 * 3 * 3400000)) - 1;
tmp = (2 * 3 * 3400000)
regval = (((SYSCLK_FREQUENCY + tmp - 1) / tmp) - 1) << I2CM_TPR_SHIFT;
tiva_i2c_putreg(priv, TIVA_I2CM_TPR_OFFSET, I2CM_TPR_HS | regval);
}
@ -1535,32 +1532,10 @@ static int tiva_i2c_process(struct i2c_dev_s *dev, struct i2c_msg_s *msgs,
{
struct tiva_i2c_inst_s *inst = (struct tiva_i2c_inst_s *)dev;
struct tiva_i2c_priv_s *priv = inst->priv;
uint32_t status = 0;
int errval = 0;
ASSERT(count);
/* Wait for any STOP in progress. NOTE: If we have to disable the FSMC
* then we cannot do this at the top of the loop, unfortunately. The STOP
* will not complete normally if the FSMC is enabled.
*/
tiva_i2c_sem_waitstop(priv);
/* Clear any pending error interrupts */
#warning Missing logic
/* "Note: When the STOP, START or PEC bit is set, the software must
* not perform any write access to I2C_CR1 before this bit is
* cleared by hardware. Otherwise there is a risk of setting a
* second STOP, START or PEC request." However, if the bits are
* not cleared by hardware, then we will have to do that from hardware.
*/
tiva_i2c_clrstart(priv);
/* Old transfers are done */
/* Reset ptr and dcnt to ensure an unexpected data interrupt doesn't
* overwrite stale data.
*/
@ -1571,6 +1546,8 @@ static int tiva_i2c_process(struct i2c_dev_s *dev, struct i2c_msg_s *msgs,
priv->msgv = msgs;
priv->msgc = count;
priv->status = 0;
/* Reset I2C trace logic */
tiva_i2c_tracereset(priv);
@ -1579,11 +1556,11 @@ static int tiva_i2c_process(struct i2c_dev_s *dev, struct i2c_msg_s *msgs,
tiva_i2c_setclock(priv, inst->frequency);
/* Trigger start condition, then the process moves into the ISR. I2C
/* Send the address, then the process moves into the ISR. I2C
* interrupts will be enabled within tiva_i2c_waitdone().
*/
tiva_i2c_sendstart(priv);
tiva_i2c_sendaddress(priv);
/* Wait for an ISR, if there was a timeout, fetch latest status to get
* the BUSY flag.
@ -1591,64 +1568,36 @@ static int tiva_i2c_process(struct i2c_dev_s *dev, struct i2c_msg_s *msgs,
if (tiva_i2c_sem_waitdone(priv) < 0)
{
/* Read the raw interrupt status */
status = tiva_i2c_getreg(priv, TIVA_I2CM_RIS_OFFSET);
i2cdbg("ERROR: Timed out\n");
errval = ETIMEDOUT;
i2cdbg("Timed out: status: 0x%08x\n", status);
/* "Note: When the STOP, START or PEC bit is set, the software must
* not perform any write access to I2C_CR1 before this bit is
* cleared by hardware. Otherwise there is a risk of setting a
* second STOP, START or PEC request."
*/
tiva_i2c_clrstart(priv);
}
/* Check for error status conditions */
#warning Missing logic
else if ((priv->status & I2CM_CS_ERROR) != 0)
{
if ((priv->status & I2CM_CS_ARBLST) != 0)
{
/* Bus Error */
errval = EIO;
}
{
/* Arbitration Lost (master mode) */
/* Arbitration Lost */
errval = EAGAIN;
}
else if ((priv->status & (I2CM_CS_ADRACK | I2CM_CS_DATACK)) != 0)
{
/* Acknowledge Failure */
errval = ENXIO;
}
#ifdef I2CM_CS_CLKTO
else if ((priv->status & I2CM_CS_CLKTO) != 0)
{
/* Overrun/Underrun */
errval = EIO;
}
{
/* PEC Error in reception */
errval = EPROTO;
}
{
/* Timeout or Tlow Error */
/* Timeout */
errval = ETIME;
}
/* This is not an error and should never happen since SMBus is not enabled */
#endif
else
{
/* SMBus alert is an optional signal with an interrupt line for devices
* that want to trade their ability to master for a pin.
*/
/* Something else? */
errval = EINTR;
errval = EIO;
}
}
@ -1657,7 +1606,8 @@ static int tiva_i2c_process(struct i2c_dev_s *dev, struct i2c_msg_s *msgs,
* NOTE: We will only see this busy indication if tiva_i2c_sem_waitdone()
* fails above; Otherwise it is cleared.
*/
#warning Missing logic
if ((tiva_i2c_getreg(priv, TIVA_I2CM_CS_OFFSET) & (I2CM_CS_BUSY | I2CM_CS_BUSBSY)) != 0)
{
/* I2C Bus is for some reason busy */