in arch/arm/src/gd32f4/gd32f4xx_i2c.c [1177:1995]
static int gd32_i2c_isr_process(struct gd32_i2c_priv_s *priv)
{
uint32_t status;
#ifndef CONFIG_I2C_POLLED
uint32_t regval;
#endif
#ifdef CONFIG_GD32F4_I2C_DMA
uint16_t ctl1;
#endif
i2cinfo("I2C ISR called\n");
/* Get state of the I2C controller (register STAT0 only)
*
* Get control register STAT0 only as reading both STAT0 and STAT1
* clears the ADDR flag(possibly others) causing the hardware to
* advance to the next state without the proper action being taken.
*/
status = gd32_i2c_getreg(priv, GD32_I2C_STAT0_OFFSET);
/* Update private version of the state */
priv->status = status;
/* Check if this is a new transmission so to set up the
* trace table accordingly.
*/
gd32_i2c_tracenew(priv, status);
gd32_i2c_traceevent(priv, I2CEVENT_ISR_CALL, 0);
/* Messages handling (1/2)
*
* Message handling should only operate when a message has been completely
* sent and after the ISR had the chance to run to set bits after the last
* written/read byte, i.e. priv->dcnt == -1. This is also the case in when
* the ISR is called for the first time. This can seen in
* gd32_i2c_process() before entering the gd32_i2c_sem_waitdone() waiting
* process.
*
* Message handling should only operate when:
* - A message has been completely sent and there are still messages
* to send(i.e. msgc > 0).
* - After the ISR had the chance to run to set start bit or
* termination flags after the last written/read byte(after last byte
* dcnt=0, msg handling dcnt = -1).
*
* When the ISR is called for the first time the same conditions hold.
* This can seen in gd32_i2c_process() before entering the
* gd32_i2c_sem_waitdone() waiting process.
*/
#ifdef CONFIG_GD32F4_I2C_DMA
/* If ISR gets called (ex. polling mode) while DMA is still in
* progress, we should just return and let the DMA finish.
*/
ctl1 = gd32_i2c_getreg(priv, GD32_I2C_CTL1_OFFSET);
if ((ctl1 & I2C_CTL1_DMAON) != 0)
{
#ifdef CONFIG_DEBUG_I2C_INFO
size_t left = gd32_dma_tansnum_get(priv->rxdma);
i2cinfo("DMA in progress: %ld [bytes] remainining. Returning.\n",
left);
#endif
return OK;
}
#endif
if (priv->dcnt == -1 && priv->msgc > 0)
{
/* Any new message should begin with "Start" condition
* However there were 2 situations where that was not true
* Situation 1:
* Next message continue transmission sequence of previous message
*
* Situation 2: If an error is injected that looks like a STOP the
* interrupt will be reentered with some status that will be incorrect.
* This will ensure that the error handler will clear the interrupt
* enables and return the error to the waiting task.
*/
if (((priv->msgv[0].flags & I2C_M_NOSTART) != 0 &&
(status & I2C_STAT0_TBE) == 0) ||
((priv->msgv[0].flags & I2C_M_NOSTART) == 0 &&
(status & I2C_STAT0_SBSEND) == 0))
{
#if defined(CONFIG_GD32F4_I2C_DMA) || defined(CONFIG_I2C_POLLED)
return OK;
#else
priv->status |= I2C_STAT0_SMBTO;
goto state_error;
#endif
}
i2cinfo("Switch to new message\n");
/* Get current message to process data and copy to private structure */
priv->ptr = priv->msgv->buffer; /* Copy buffer to private struct */
priv->dcnt = priv->msgv->length; /* Set counter of current msg length */
priv->flags = priv->msgv->flags; /* Copy flags to private struct */
i2cinfo("Current flags %i\n", priv->flags);
/* Decrease counter to indicate the number of messages left to
* process
*/
priv->msgc--;
/* Decrease message pointer.
* If last message set next message vector to null
*/
if (priv->msgc == 0)
{
/* No more messages, don't need to increment msgv. This pointer
* will be set to zero when reaching the termination of the ISR
* calls, i.e. Messages handling(2/2).
*/
}
else
{
/* If not last message increment to next message to process */
priv->msgv++;
}
/* Trace event */
gd32_i2c_traceevent(priv, I2CEVENT_MSG_HANDLING, priv->msgc);
}
/* Note the event where we are on the last message and after the last
* byte is handled at the bottom of this function, as it terminates
* the repeated calls to the ISR.
*/
/* I2C protocol logic
*
* I2C protocol logic follows. It's organized in an if else chain such that
* only one mode of operation is executed every time the ISR is called.
*/
/* Address Handling
*
* Check if a start bit was set and transmit address with proper format.
*
* Note:
* On first call the start bit has been set by gd32_i2c_waitdone()
* Otherwise it will be set from this ISR.
*
* Remember that after a start bit an address has always to be sent.
*/
if ((status & I2C_STAT0_SBSEND) != 0)
{
/* Start bit is set */
i2cinfo("Entering address handling, status = %" PRIi32 "\n", status);
/* Check for empty message (for robustness) */
if (priv->dcnt > 0)
{
/* Send address byte with correct 8th bit set
* (for writing or reading)
* Transmission happens after having written to the data register
* GD32_I2C_DATA
*/
gd32_i2c_putreg(priv, GD32_I2C_DATA_OFFSET,
(priv->flags & I2C_M_TEN) ?
0 : ((priv->msgv->addr << 1) |
(priv->flags & I2C_M_READ)));
i2cinfo("Address sent. Addr=%#02x Write/Read bit=%i\n",
priv->msgv->addr, (priv->flags & I2C_M_READ));
/* Flag that address has just been sent */
priv->check_addr_ack = true;
gd32_i2c_traceevent(priv, I2CEVENT_SENDADDR, priv->msgv->addr);
}
else
{
/* TODO: untested!! */
i2cwarn(" An empty message has been detected, "
"ignoring and passing to next message.\n");
/* Trace event */
gd32_i2c_traceevent(priv, I2CEVENT_EMPTY_MSG, 0);
/* Set condition to activate msg handling */
priv->dcnt = -1;
#ifndef CONFIG_I2C_POLLED
/* Restart ISR by setting an interrupt buffer bit */
gd32_i2c_modifyreg(priv,
GD32_I2C_CTL1_OFFSET, 0, I2C_CTL1_BUFIE);
#endif
}
}
/* Address cleared event
*
* Check if the address cleared, i.e. the driver found a valid address.
* If a NACK was received the address is invalid, if an ACK was
* received the address is valid and transmission can continue.
*/
/* Check for NACK after an address */
#ifndef CONFIG_I2C_POLLED
/* When polling the i2c ISR it's not possible to determine when
* an address has been ACKed(i.e. the address is valid).
*
* The mechanism to deal a NACKed address is to wait for the I2C
* call to timeout (value defined in defconfig by one of the
* following: CONFIG_GD32F4_I2C_DYNTIMEO, CONFIG_GD32F4_I2C_TIMEOSEC,
* CONFIG_GD32F4_I2C_TIMEOMS, CONFIG_GD32F4_I2C_TIMEOTICKS).
*
* To be safe in the case of a timeout/NACKed address a stop bit
* is set on the bus to clear it. In POLLED operation it's done
* gd32_i2c_process() after the call to gd32_i2c_sem_waitdone().
*
* In ISR driven operation the stop bit in case of a NACKed address
* is set in the ISR itself.
*
* Note: this commentary is found in both places.
*/
else if ((status & I2C_STAT0_ADDSEND) == 0 && priv->check_addr_ack)
{
i2cinfo("Invalid Address. Setting stop bit and clearing message\n");
i2cinfo("status %" PRIi32 "\n", status);
/* Set condition to terminate msg chain transmission as address is
* invalid.
*/
priv->dcnt = -1;
priv->msgc = 0;
i2cinfo("dcnt %i , msgc %i\n", priv->dcnt, priv->msgc);
/* Reset flag to check for valid address */
priv->check_addr_ack = false;
/* Send stop bit to clear bus */
gd32_i2c_sendstop(priv);
/* Trace event */
gd32_i2c_traceevent(priv, I2CEVENT_ADDRESS_NACKED, priv->msgv->addr);
}
#endif
/* ACK in read mode, ACK in write mode is handled separately */
else if ((priv->flags & I2C_M_READ) != 0 && \
(status & I2C_STAT0_ADDSEND) != 0 && \
priv->check_addr_ack)
{
/* Reset check addr flag as we are handling this event */
priv->check_addr_ack = false;
/* Note:
*
* When reading a single byte the stop condition has to be set
* immediately after clearing the state flags, which happens
* when reading STAT1(as STAT0 has already been read).
*
* Similarly when reading 2 bytes the NACK bit has to be set as just
* after the clearing of the address.
*/
if (priv->dcnt == 1)
{
/* this should only happen when receiving a message of length 1 */
i2cinfo("short read N=1: setting NACK\n");
/* Set POS bit to zero (can be up from a previous 2 byte receive) */
gd32_i2c_modifyreg(priv, GD32_I2C_CTL0_OFFSET, I2C_CTL0_POAP, 0);
/* Immediately set NACK */
gd32_i2c_modifyreg(priv, GD32_I2C_CTL0_OFFSET, I2C_CTL0_ACKEN, 0);
#ifndef CONFIG_I2C_POLLED
/* Enable RxNE and TxE buffers in order to receive one or multiple
* bytes
*/
gd32_i2c_modifyreg(priv,
GD32_I2C_CTL1_OFFSET, 0, I2C_CTL1_BUFIE);
#endif
/* Clear ADDR flag by reading CTL1 and adding it to status */
status |= (gd32_i2c_getreg(priv, GD32_I2C_STAT1_OFFSET) << 16);
/* Send Stop/Restart */
if (priv->msgc > 0)
{
gd32_i2c_sendstart(priv);
}
else
{
gd32_i2c_sendstop(priv);
}
i2cinfo("Address ACKed beginning data reception\n");
i2cinfo("short read N=1: programming stop bit\n");
/* Trace */
gd32_i2c_traceevent(priv, I2CEVENT_ADDRESS_ACKED_READ_1, 0);
}
else if (priv->dcnt == 2)
{
/* This should only happen when receiving a message of length 2 */
/* Set POS bit to zero (can be up from a previous 2 byte receive) */
gd32_i2c_modifyreg(priv, GD32_I2C_CTL0_OFFSET, 0, I2C_CTL0_POAP);
/* Immediately set NACK */
gd32_i2c_modifyreg(priv, GD32_I2C_CTL0_OFFSET, I2C_CTL0_ACKEN, 0);
/* Clear ADDR flag by reading STAT1 and adding it to status */
status |= (gd32_i2c_getreg(priv, GD32_I2C_STAT1_OFFSET) << 16);
i2cinfo("Address ACKed beginning data reception\n");
i2cinfo("short read N=2: programming NACK\n");
/* Trace */
gd32_i2c_traceevent(priv, I2CEVENT_ADDRESS_ACKED_READ_2, 0);
}
else
{
i2cinfo("Address ACKed beginning data reception\n");
/* Clear ADDR flag by reading STAT1 and adding it to status */
status |= (gd32_i2c_getreg(priv, GD32_I2C_STAT1_OFFSET) << 16);
/* Trace */
gd32_i2c_traceevent(priv, I2CEVENT_ADDRESS_ACKED, 0);
#ifdef CONFIG_GD32F4_I2C_DMA
/* DMA only when not doing a short read */
dma_single_data_parameter_struct dma_init_struct;
i2cinfo("Starting dma transfer and disabling interrupts\n");
/* The DMA must be initialized and enabled before the I2C data
* transfer.
* The DMAEN bit must be set in the I2C_CTL1 register before the
* ADDR event.
*/
dma_init_struct.periph_memory_width = DMA_WIDTH_8BITS_SELECT;
dma_init_struct.direction = DMA_PERIPH_TO_MEMORY;
dma_init_struct.memory0_addr = (uint32_t)priv->ptr;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.number = priv->dcnt;
dma_init_struct.periph_addr = \
GD32_I2C_DATA(priv->config->i2c_base);
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.priority = I2C_DMA_PRIO;
/* Configure the RX DMA */
gd32_dma_setup(priv->rxdma, &dma_init_struct, 1);
/* Do not enable the ITBUFEN bit in the I2C_CTL1 register if DMA is
* used.
*/
gd32_i2c_modifyreg(priv,
GD32_I2C_CTL1_OFFSET, I2C_CTL1_BUFIE, 0);
#ifndef CONFIG_I2C_POLLED
/* Now let DMA do all the work, disable i2c interrupts */
regval = gd32_i2c_getreg(priv, GD32_I2C_CTL1_OFFSET);
regval &= ~I2C_CTL1_INTS_MASK;
gd32_i2c_putreg(priv, GD32_I2C_CTL1_OFFSET, regval);
#endif
/* The user can generate a Stop condition in the DMA Transfer
* Complete interrupt routine if enabled. This will be done in
* the dma rx callback Start DMA.
*/
gd32_dma_start(priv->rxdma, gd32_i2c_dmarxcallback, priv, \
I2C_RX_DMA_INTEN);
gd32_i2c_modifyreg(priv, GD32_I2C_CTL1_OFFSET, 0, I2C_CTL1_DMAON);
#else
#ifndef CONFIG_I2C_POLLED
if (priv->dcnt > 3)
{
/* Don't enable I2C_CTL1_BUFIE for messages longer than 3
* bytes
*/
gd32_i2c_modifyreg(priv,
GD32_I2C_CTL1_OFFSET, 0, I2C_CTL1_BUFIE);
}
#endif
#endif
}
}
/* Write mode
*
* Handles all write related I2C protocol logic. Also handles the
* ACK event after clearing the ADDR flag as the write has to
* begin immediately after.
*/
else if ((priv->flags & I2C_M_READ) == 0 &&
(status & I2C_STAT0_BTC) != 0 &&
priv->dcnt == 0)
{
/* After last byte, check what to do based on next message flags */
if (priv->msgc == 0)
{
/* If last message send stop bit */
gd32_i2c_sendstop(priv);
i2cinfo("Stop sent dcnt = %i msgc = %i\n", priv->dcnt, priv->msgc);
/* Decrease counter to get to next message */
priv->dcnt--;
i2cinfo("dcnt %i\n", priv->dcnt);
gd32_i2c_traceevent(priv, I2CEVENT_WRITE_STOP, priv->dcnt);
}
/* If there is a next message with no flags or the read flag
* a restart sequence has to be sent.
* Note msgv already points to the next message.
*/
else if (priv->msgc > 0 &&
(priv->msgv->flags == 0 ||
(priv->msgv[0].flags & I2C_M_READ) != 0))
{
/* Send start */
gd32_i2c_sendstart(priv);
gd32_i2c_getreg(priv, GD32_I2C_DATA_OFFSET);
i2cinfo("Restart detected!\n");
i2cinfo("Nextflag %i\n", priv->msgv[0].flags);
/* Decrease counter to get to next message */
priv->dcnt--;
i2cinfo("dcnt %i\n", priv->dcnt);
gd32_i2c_traceevent(priv, I2CEVENT_WRITE_RESTART, priv->dcnt);
}
else
{
i2cinfo("Write mode: next message has an unrecognized flag.\n");
gd32_i2c_traceevent(priv,
I2CEVENT_WRITE_FLAG_ERROR, priv->msgv->flags);
}
status |= (gd32_i2c_getreg(priv, GD32_I2C_STAT1_OFFSET) << 16);
}
else if ((priv->flags & I2C_M_READ) == 0 &&
(status & (I2C_STAT0_ADDSEND | I2C_STAT0_TBE)) != 0 &&
priv->dcnt != 0)
{
/* The has cleared(ADDR is set, ACK was received after the address)
* or the transmit buffer is empty flag has been set(TxE) then we can
* transmit the next byte.
*/
i2cinfo("Entering write mode dcnt = %i msgc = %i\n",
priv->dcnt, priv->msgc);
/* Clear ADDR flag by reading STAT1 and adding it to status */
status |= (gd32_i2c_getreg(priv, GD32_I2C_STAT1_OFFSET) << 16);
/* Address has cleared so don't check on next call */
priv->check_addr_ack = false;
/* Check if we have transmitted the whole message or we are after
* the last byte where the stop condition or else(according to the
* msg flags) has to be set.
*/
#ifdef CONFIG_GD32F4_I2C_DMA
/* if DMA is enabled, only makes sense to make use of it for longer
* than 1 B transfers.
*/
if (priv->dcnt > 1)
{
i2cinfo("Starting DMA transfer and disabling interrupts\n");
/* The DMA must be initialized and enabled before the I2C data
* transfer. The DMAEN bit must be set in the I2C_CR2 register
* before the ADDR event.
*/
dma_init_struct.periph_memory_width = DMA_WIDTH_8BITS_SELECT;
dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;
dma_init_struct.memory0_addr = (uint32_t)priv->ptr;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.number = priv->dcnt;
dma_init_struct.periph_addr = \
GD32_I2C_DATA(priv->config->i2c_base);
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.priority = I2C_DMA_PRIO;
/* Configure the RX DMA */
gd32_dma_setup(priv->rxdma, &dma_init_struct, 1);
/* Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is
* used.
*/
gd32_i2c_modifyreg(priv,
GD32_I2C_CTL1_OFFSET, I2C_CTL1_BUFIE, 0);
#ifndef CONFIG_I2C_POLLED
/* Now let DMA do all the work, disable i2c interrupts */
regval = gd32_i2c_getreg(priv, GD32_I2C_CTL1_OFFSET);
regval &= ~I2C_CTL1_INTS_MASK;
gd32_i2c_putreg(priv, GD32_I2C_CTL1_OFFSET, regval);
#endif
/* In the interrupt routine after the EOT interrupt, disable DMA
* requests then wait for a BTF event before programming the Stop
* condition. To do this, we'll just call the ISR again in
* DMA tx callback, in which point we fall into the msgc==0 case
* which ultimately sends the stop..TODO: but we don't explicitly
* wait for BTF bit being set...
* Start DMA.
*/
gd32_i2c_modifyreg(priv, GD32_I2C_CTL1_OFFSET, 0, I2C_CTL1_DMAON);
gd32_dma_start(priv->rxdma, gd32_i2c_dmarxcallback, priv, \
I2C_TX_DMA_INTEN);
}
else
#endif /* CONFIG_GD32F4_I2C_DMA */
{
#ifndef CONFIG_I2C_POLLED
if (priv->dcnt == 1 &&
(priv->msgc == 0 || (priv->msgv->flags & I2C_M_NOSTART) == 0))
{
gd32_i2c_modifyreg(priv,
GD32_I2C_CTL1_OFFSET, I2C_CTL1_BUFIE, 0);
}
#endif
/* Transmitting message.
* Send byte == write data into write register
*/
gd32_i2c_putreg(priv, GD32_I2C_DATA_OFFSET, *priv->ptr++);
/* Decrease current message length */
gd32_i2c_traceevent(priv, I2CEVENT_WRITE_TO_DR, priv->dcnt);
priv->dcnt--;
if ((status & I2C_STAT0_ADDSEND) != 0 && priv->dcnt > 0)
{
/* Transmitting message.
* ADDR -> BTC & TBE - Send one more byte
*/
gd32_i2c_putreg(priv, GD32_I2C_DATA_OFFSET, *priv->ptr++);
/* Decrease current message length */
gd32_i2c_traceevent(priv, I2CEVENT_WRITE_TO_DR, priv->dcnt);
priv->dcnt--;
}
#ifndef CONFIG_I2C_POLLED
if (((status & I2C_STAT0_ADDSEND) != 0 && priv->dcnt > 0) ||
(priv->msgc > 0 && (priv->msgv->flags & I2C_M_NOSTART) != 0))
{
gd32_i2c_modifyreg(priv,
GD32_I2C_CTL1_OFFSET, 0, I2C_CTL1_BUFIE);
}
#endif
if (priv->dcnt == 0 &&
priv->msgc > 0 && (priv->msgv->flags & I2C_M_NOSTART) != 0)
{
/* Set condition to get to next message */
priv->dcnt = -1;
gd32_i2c_traceevent(priv,
I2CEVENT_WRITE_NO_RESTART, priv->dcnt);
}
}
}
else if ((priv->flags & (I2C_M_READ)) != 0 &&
(status & (I2C_STAT0_RBNE | I2C_STAT0_BTC)) != 0)
{
/* When read flag is set and the receive buffer is not empty
* (RBNE is set) then the driver can read from the data register.
*/
status |= (gd32_i2c_getreg(priv, GD32_I2C_STAT1_OFFSET) << 16);
i2cinfo("Entering read mode dcnt = %i msgc = %i, "
"status 0x%04" PRIx32 "\n",
priv->dcnt, priv->msgc, status);
/* Byte #N-3W, we don't want to manage RBNE interrupt anymore, bytes
* N, N-1, N-2 will be read with BTC:
*/
#ifndef CONFIG_I2C_POLLED
if (priv->dcnt < 5)
{
gd32_i2c_modifyreg(priv,
GD32_I2C_CTL1_OFFSET, I2C_CTL1_BUFIE, 0);
}
#else
if (priv->dcnt == 1 ||
priv->dcnt > 3 || (status & I2C_STAT0_BTC) != 0)
#endif
{
/* BTF: N-2/N-1, set NACK, read N-2 */
if (priv->dcnt == 3)
{
gd32_i2c_modifyreg(priv,
GD32_I2C_CTL0_OFFSET, I2C_CTL0_ACKEN, 0);
}
/* BTF: N-1/N, STOP/START, read N-1, N */
else if (priv->dcnt == 2)
{
if (priv->msgc > 0)
{
gd32_i2c_sendstart(priv);
}
else
{
gd32_i2c_sendstop(priv);
}
/* Read byte #N-1 */
*priv->ptr++ = gd32_i2c_getreg(priv, GD32_I2C_DATA_OFFSET);
priv->dcnt--;
}
/* Read last or current byte */
*priv->ptr++ = gd32_i2c_getreg(priv, GD32_I2C_DATA_OFFSET);
priv->dcnt--;
if (priv->dcnt == 0)
{
priv->dcnt = -1;
}
}
}
/* Empty call handler
*
* Case to handle an empty call to the ISR where it only has to
* Shutdown
*/
else if (priv->dcnt == -1 && priv->msgc == 0)
{
/* Read rest of the state */
status |= (gd32_i2c_getreg(priv, GD32_I2C_STAT1_OFFSET) << 16);
i2cinfo("Empty call to ISR: Stopping ISR\n");
gd32_i2c_traceevent(priv, I2CEVENT_ISR_EMPTY_CALL, 0);
}
/* Error handler
*
* Gets triggered if the driver does not recognize a situation(state)
* it can deal with.
* This should not happen in interrupt based operation(i.e. when
* CONFIG_I2C_POLLED is not set in the defconfig file).
* During polled operation(i.e. CONFIG_I2C_POLLED=y in defconfig)
* this case should do nothing but tracing the event that the
* device wasn't ready yet.
*/
else
{
#ifdef CONFIG_I2C_POLLED
gd32_i2c_traceevent(priv, I2CEVENT_POLL_DEV_NOT_RDY, 0);
#else
/* Read rest of the state */
status |= (gd32_i2c_getreg(priv, GD32_I2C_STAT1_OFFSET) << 16);
/* No any error bit is set, but driver is in incorrect state, signal
* it with "Bus error" bit.
*/
if ((status & I2C_STAT0_ERROR_MASK) != 0)
{
priv->status |= I2C_STAT0_BERR;
}
i2cinfo(" No correct state detected(start bit, read or write)\n");
i2cinfo(" state %" PRIi32 "\n", status);
/* Set condition to terminate ISR and wake waiting thread */
priv->dcnt = -1;
priv->msgc = 0;
gd32_i2c_traceevent(priv, I2CEVENT_STATE_ERROR, 0);
#endif
}
/* Messages handling(2/2)
*
* Transmission of the whole message chain has been completed. We have to
* terminate the ISR and wake up gd32_i2c_process() that is waiting for
* the ISR cycle to handle the sending/receiving of the messages.
*/
/* First check for errors */
if ((status & I2C_STAT0_ERROR_MASK) != 0)
{
gd32_i2c_traceevent(priv, I2CEVENT_ERROR, \
status & I2C_STAT0_ERROR_MASK);
/* Clear interrupt flags */
#if !defined(CONFIG_GD32F4_I2C_DMA) && !defined(CONFIG_I2C_POLLED)
state_error:
#endif
gd32_i2c_putreg(priv, GD32_I2C_STAT0_OFFSET, 0);
priv->dcnt = -1;
priv->msgc = 0;
}
if (priv->dcnt == -1 && priv->msgc == 0)
{
i2cinfo("Shutting down I2C ISR\n");
gd32_i2c_traceevent(priv, I2CEVENT_ISR_SHUTDOWN, 0);
/* Clear internal pointer to the message content.
* Good practice + done by last implementation when messages are
* finished (compatibility concerns)
*/
priv->msgv = NULL;
#ifdef CONFIG_I2C_POLLED
priv->intstate = INTSTATE_DONE;
#else
/* Clear all interrupts */
regval = gd32_i2c_getreg(priv, GD32_I2C_CTL1_OFFSET);
regval &= ~I2C_CTL1_INTS_MASK;
gd32_i2c_putreg(priv, GD32_I2C_CTL1_OFFSET, regval);
/* Is there a thread waiting for this event(there should be) */
if (priv->intstate == INTSTATE_WAITING)
{
/* Yes.. inform the thread that the transfer is complete
* and wake it up.
*/
nxsem_post(&priv->sem_isr);
priv->intstate = INTSTATE_DONE;
}
#endif
}
return OK;
}