diff --git a/arch/arm/src/imxrt/Kconfig b/arch/arm/src/imxrt/Kconfig index 4b7c010a9e5..b8608c1511e 100644 --- a/arch/arm/src/imxrt/Kconfig +++ b/arch/arm/src/imxrt/Kconfig @@ -804,6 +804,11 @@ config LPI2C1_BUSYIDLE int "Bus idle timeout period in clock cycles" default 0 +config LPI2C1_DMA + bool "Enable DMA for I2C1" + default n + depends on IMXRT_LPI2C_DMA + config LPI2C1_FILTSCL int "I2C master digital glitch filters for SCL input in clock cycles" default 0 @@ -825,6 +830,11 @@ config LPI2C2_BUSYIDLE int "Bus idle timeout period in clock cycles" default 0 +config LPI2C2_DMA + bool "Enable DMA for I2C2" + default n + depends on IMXRT_LPI2C_DMA + config LPI2C2_FILTSCL int "I2C master digital glitch filters for SCL input in clock cycles" default 0 @@ -846,6 +856,11 @@ config LPI2C3_BUSYIDLE int "Bus idle timeout period in clock cycles" default 0 +config LPI2C3_DMA + bool "Enable DMA for I2C3" + default n + depends on IMXRT_LPI2C_DMA + config LPI2C3_FILTSCL int "I2C master digital glitch filters for SCL input in clock cycles" default 0 @@ -867,6 +882,11 @@ config LPI2C4_BUSYIDLE int "Bus idle timeout period in clock cycles" default 0 +config LPI2C4_DMA + bool "Enable DMA for I2C4" + default n + depends on IMXRT_LPI2C_DMA + config LPI2C4_FILTSCL int "I2C master digital glitch filters for SCL input in clock cycles" default 0 @@ -1591,6 +1611,25 @@ endmenu # Memory Configuration menu "LPI2C Configuration" depends on IMXRT_LPI2C +config IMXRT_LPI2C_DMA + bool "I2C DMA Support" + default n + depends on IMXRT_LPI2C && IMXRT_EDMA && !I2C_POLLED + ---help--- + This option enables the DMA for I2C transfers. + Note: The user can define CONFIG_I2C_DMAPRIO: a custom priority value + for the I2C dma streams, else the default priority level is set to + medium. + +config IMXRT_LPI2C_DMA_MAXMSG + int "Maximum number messages that will be DMAed" + default 8 + depends on IMXRT_LPI2C_DMA + ---help--- + This option set the mumber of mesg that can be in a transfer. + It is used to allocate space for the 16 bit LPI2C commands + that will be DMA-ed to the LPI2C device. + config IMXRT_LPI2C_DYNTIMEO bool "Use dynamic timeouts" default n diff --git a/arch/arm/src/imxrt/imxrt_lpi2c.c b/arch/arm/src/imxrt/imxrt_lpi2c.c index d5537a080f9..6310594139a 100644 --- a/arch/arm/src/imxrt/imxrt_lpi2c.c +++ b/arch/arm/src/imxrt/imxrt_lpi2c.c @@ -44,8 +44,11 @@ #include "arm_internal.h" #include "imxrt_lpi2c.h" +#include "imxrt_edma.h" #include "imxrt_gpio.h" +#include "imxrt_lpi2c.h" +#include "hardware/imxrt_dmamux.h" #include "hardware/imxrt_pinmux.h" #include "hardware/imxrt_ccm.h" #include "imxrt_periphclks.h" @@ -171,6 +174,9 @@ struct imxrt_lpi2c_config_s #ifndef CONFIG_I2C_POLLED uint32_t irq; /* Event IRQ */ #endif +#ifdef CONFIG_IMXRT_LPI2C_DMA + uint32_t dma_reqsrc; /* DMA mux source */ +#endif }; /* I2C Device Private Data */ @@ -211,6 +217,11 @@ struct imxrt_lpi2c_priv_s #endif uint32_t status; /* End of transfer SR2|SR1 status */ + +#ifdef CONFIG_IMXRT_LPI2C_DMA + DMACH_HANDLE dma; /* DMA handle */ + uint16_t cmnds[CONFIG_IMXRT_LPI2C_DMA_MAXMSG]; /* Commands */ +#endif }; /**************************************************************************** @@ -278,6 +289,11 @@ static int imxrt_lpi2c_transfer(struct i2c_master_s *dev, static int imxrt_lpi2c_reset(struct i2c_master_s *dev); #endif +#ifdef CONFIG_IMXRT_LPI2C_DMA +static void imxrt_dma_callback(DMACH_HANDLE handle, void *arg, bool done, + int result); +#endif + /**************************************************************************** * Private Data ****************************************************************************/ @@ -302,12 +318,18 @@ static const char *g_trace_names[] = static const struct i2c_ops_s imxrt_lpi2c_ops = { - .transfer = imxrt_lpi2c_transfer + .transfer = imxrt_lpi2c_transfer, #ifdef CONFIG_I2C_RESET - , .reset = imxrt_lpi2c_reset + .reset = imxrt_lpi2c_reset, #endif }; +#ifdef CONFIG_IMXRT_LPI2C_DMA +/* Receive Data DMA Enable */ + +static uint32_t g_lpi2c_mder_rdde = LPI2C_MDER_RDDE; +#endif + /* I2C device structures */ #ifdef CONFIG_IMXRT_LPI2C1 @@ -331,6 +353,9 @@ static const struct imxrt_lpi2c_config_s imxrt_lpi2c1_config = #ifndef CONFIG_I2C_POLLED .irq = IMXRT_IRQ_LPI2C1, #endif +#ifdef CONFIG_LPI2C1_DMA + .dma_reqsrc = IMXRT_DMACHAN_LPI2C1, +#endif }; static struct imxrt_lpi2c_priv_s imxrt_lpi2c1_priv = @@ -369,6 +394,9 @@ static const struct imxrt_lpi2c_config_s imxrt_lpi2c2_config = #ifndef CONFIG_I2C_POLLED .irq = IMXRT_IRQ_LPI2C2, #endif +#ifdef CONFIG_LPI2C2_DMA + .dma_reqsrc = IMXRT_DMACHAN_LPI2C2, +#endif }; static struct imxrt_lpi2c_priv_s imxrt_lpi2c2_priv = @@ -407,6 +435,9 @@ static const struct imxrt_lpi2c_config_s imxrt_lpi2c3_config = #ifndef CONFIG_I2C_POLLED .irq = IMXRT_IRQ_LPI2C3, #endif +#ifdef CONFIG_LPI2C3_DMA + .dma_reqsrc = IMXRT_DMACHAN_LPI2C3, +#endif }; static struct imxrt_lpi2c_priv_s imxrt_lpi2c3_priv = @@ -445,6 +476,9 @@ static const struct imxrt_lpi2c_config_s imxrt_lpi2c4_config = #ifndef CONFIG_I2C_POLLED .irq = IMXRT_IRQ_LPI2C4, #endif +#ifdef CONFIG_LPI2C4_DMA + .dma_reqsrc = IMXRT_DMACHAN_LPI2C4, +#endif }; static struct imxrt_lpi2c_priv_s imxrt_lpi2c4_priv = @@ -587,30 +621,43 @@ imxrt_lpi2c_sem_waitdone(struct imxrt_lpi2c_priv_s *priv) flags = enter_critical_section(); - /* Enable Interrupts when master mode */ - - if (priv->config->mode == LPI2C_MASTER) +#ifdef CONFIG_IMXRT_LPI2C_DMA + if (priv->dma == NULL) { - if ((priv->flags & I2C_M_READ) != 0) +#endif + /* Enable Interrupts when master mode */ + + if (priv->config->mode == LPI2C_MASTER) { - regval = LPI2C_MIER_TDIE | LPI2C_MIER_RDIE | LPI2C_MIER_NDIE | \ - LPI2C_MIER_ALIE | LPI2C_MIER_SDIE; - imxrt_lpi2c_putreg(priv, IMXRT_LPI2C_MIER_OFFSET, regval); + if ((priv->flags & I2C_M_READ) != 0) + { + regval = LPI2C_MIER_TDIE | LPI2C_MIER_RDIE | + LPI2C_MIER_NDIE | LPI2C_MIER_ALIE | + LPI2C_MIER_SDIE; + imxrt_lpi2c_putreg(priv, IMXRT_LPI2C_MIER_OFFSET, regval); + } + else + { + regval = LPI2C_MIER_TDIE | LPI2C_MIER_NDIE | \ + LPI2C_MIER_ALIE | LPI2C_MIER_SDIE; + imxrt_lpi2c_putreg(priv, IMXRT_LPI2C_MIER_OFFSET, regval); + } } + + /* Enable Interrupts when slave mode */ + else { - regval = LPI2C_MIER_TDIE | LPI2C_MIER_NDIE | \ - LPI2C_MIER_ALIE | LPI2C_MIER_SDIE; - imxrt_lpi2c_putreg(priv, IMXRT_LPI2C_MIER_OFFSET, regval); + #warning Missing logic for I2C Slave mode } - } - /* Enable Interrupts when slave mode */ - - else - { -#warning Missing logic for I2C Slave mode + /* Signal the interrupt handler that we are waiting. NOTE: Interrupts + * are currently disabled but will be temporarily re-enabled below when + * nxsem_timedwait() sleeps. + */ +#ifdef CONFIG_IMXRT_LPI2C_DMA } +#endif /* Signal the interrupt handler that we are waiting. NOTE: Interrupts * are currently disabled but will be temporarily re-enabled below when @@ -861,6 +908,59 @@ imxrt_lpi2c_sem_destroy(struct imxrt_lpi2c_priv_s *priv) #endif } +/**************************************************************************** + * Name: imxrt_dma_callback + * + * Description: + * This function performs the next I2C operation + * + ****************************************************************************/ +#ifdef CONFIG_IMXRT_LPI2C_DMA +static void imxrt_dma_callback(DMACH_HANDLE handle, void *arg, bool done, + int result) +{ + struct imxrt_lpi2c_priv_s *priv = (struct imxrt_lpi2c_priv_s *)arg; + + imxrt_lpi2c_modifyreg(priv, IMXRT_LPI2C_MIER_OFFSET, 0, + LPI2C_MIER_SDIE); + + if (result != OK) + { + priv->status = imxrt_lpi2c_getstatus(priv); + + if ((priv->status & LPI2C_MSR_ERROR_MASK) != 0) + { + i2cerr("ERROR: MSR: status: 0x0%" PRIx32 "\n", priv->status); + + imxrt_lpi2c_traceevent(priv, I2CEVENT_ERROR, 0); + + /* Clear the TX and RX FIFOs */ + + imxrt_lpi2c_modifyreg(priv, IMXRT_LPI2C_MCR_OFFSET, 0, + LPI2C_MCR_RTF | LPI2C_MCR_RRF); + + /* Clear the error */ + + imxrt_lpi2c_putreg(priv, IMXRT_LPI2C_MSR_OFFSET, + (priv->status & (LPI2C_MSR_NDF | + LPI2C_MSR_ALF | + LPI2C_MSR_FEF | + LPI2C_MSR_PLTF))); + + if (priv->intstate == INTSTATE_WAITING) + { + /* inform the thread that transfer is complete + * and wake it up + */ + + priv->intstate = INTSTATE_DONE; + nxsem_post(&priv->sem_isr); + } + } + } +} +#endif + /**************************************************************************** * Name: imxrt_lpi2c_trace* * @@ -1217,6 +1317,20 @@ imxrt_lpi2c_getstatus(struct imxrt_lpi2c_priv_s *priv) return imxrt_lpi2c_getreg(priv, IMXRT_LPI2C_MSR_OFFSET); } +/**************************************************************************** + * Name: imxrt_lpi2c_getenabledints + * + * Description: + * Get 32-bit status + * + ****************************************************************************/ + +static inline uint32_t +imxrt_lpi2c_getenabledints(FAR struct imxrt_lpi2c_priv_s *priv) +{ + return imxrt_lpi2c_getreg(priv, IMXRT_LPI2C_MIER_OFFSET); +} + /**************************************************************************** * Name: imxrt_lpi2c_isr_process * @@ -1229,6 +1343,79 @@ static int imxrt_lpi2c_isr_process(struct imxrt_lpi2c_priv_s *priv) { uint32_t status = imxrt_lpi2c_getstatus(priv); +#ifdef CONFIG_IMXRT_LPI2C_DMA + uint32_t current_status = status; + + /* Condition the status with only the enabled interrupts */ + + status &= imxrt_lpi2c_getenabledints(priv); + + if (priv->dma != NULL) + { + /* End of packet or Stop */ + + if ((status & (LPI2C_MSR_SDF | LPI2C_MSR_EPF)) != 0) + { + imxrt_lpi2c_traceevent(priv, I2CEVENT_STOP, 0); + + /* Acknowledge End of packet or Stop */ + + imxrt_lpi2c_putreg(priv, IMXRT_LPI2C_MSR_OFFSET, status & + (LPI2C_MSR_SDF | + LPI2C_MSR_EPF)); + } + + /* Is there an Error condition */ + + if (current_status & LPI2C_MSR_ERROR_MASK) + { + imxrt_lpi2c_traceevent(priv, I2CEVENT_ERROR, 0); + + /* Shutdown DMA */ + + imxrt_dmach_stop(priv->dma); + + /* Clear the TX and RX FIFOs */ + + imxrt_lpi2c_modifyreg(priv, IMXRT_LPI2C_MCR_OFFSET, 0, + LPI2C_MCR_RTF | LPI2C_MCR_RRF); + + /* Clear the error */ + + imxrt_lpi2c_putreg(priv, IMXRT_LPI2C_MSR_OFFSET, + (current_status & (LPI2C_MSR_NDF | + LPI2C_MSR_ALF | + LPI2C_MSR_FEF))); + + /* Return the full error status */ + + status = current_status; + } + + /* Mark that this transaction stopped */ + + priv->msgv = NULL; + priv->msgc = 0; + priv->dcnt = -1; + + if (priv->intstate == INTSTATE_WAITING) + { + /* Update Status once at the end */ + + priv->status = status; + + /* inform the thread that transfer is complete + * and wake it up + */ + + priv->intstate = INTSTATE_DONE; + nxsem_post(&priv->sem_isr); + } + + return OK; + } + +#endif /* Check for new trace setup */ imxrt_lpi2c_tracenew(priv, status); @@ -1369,8 +1556,8 @@ static int imxrt_lpi2c_isr_process(struct imxrt_lpi2c_priv_s *priv) * and wake it up */ - nxsem_post(&priv->sem_isr); priv->intstate = INTSTATE_DONE; + nxsem_post(&priv->sem_isr); } #else priv->status = status; @@ -1412,22 +1599,22 @@ static int imxrt_lpi2c_isr_process(struct imxrt_lpi2c_priv_s *priv) LPI2C_MSR_FEF))); #ifndef CONFIG_I2C_POLLED - if (priv->intstate == INTSTATE_WAITING) - { - /* Update Status once at the end */ + if (priv->intstate == INTSTATE_WAITING) + { + /* Update Status once at the end */ - priv->status = status; - - /* inform the thread that transfer is complete - * and wake it up - */ - - nxsem_post(&priv->sem_isr); - priv->intstate = INTSTATE_DONE; - } -#else priv->status = status; + + /* inform the thread that transfer is complete + * and wake it up + */ + priv->intstate = INTSTATE_DONE; + nxsem_post(&priv->sem_isr); + } +#else + priv->status = status; + priv->intstate = INTSTATE_DONE; #endif } @@ -1448,7 +1635,8 @@ static int imxrt_lpi2c_isr(int irq, void *context, void *arg) struct imxrt_lpi2c_priv_s *priv = (struct imxrt_lpi2c_priv_s *)arg; DEBUGASSERT(priv != NULL); - return imxrt_lpi2c_isr_process(priv); + int rv = imxrt_lpi2c_isr_process(priv); + return rv; } #endif @@ -1547,7 +1735,7 @@ static int imxrt_lpi2c_init(struct imxrt_lpi2c_priv_s *priv) /* Pin config and ignore NACK disable */ imxrt_lpi2c_modifyreg(priv, IMXRT_LPI2C_MCFGR1_OFFSET, - LPI2C_MCFGR1_IGNACK | LPI2C_MCFGR1_PINCFG_MASK, 0); + LPI2C_MCFGR1_IGNACK, LPI2C_MCFGR1_AUTOSTOP); /* Set tx and rx watermarks */ @@ -1621,6 +1809,260 @@ static int imxrt_lpi2c_deinit(struct imxrt_lpi2c_priv_s *priv) * Device Driver Operations ****************************************************************************/ +/**************************************************************************** + * Name: imxrt_lpi2c_dma_configure + * + * Description: + * Create a TCD to change from TX to RX + * + ****************************************************************************/ + +#ifdef CONFIG_IMXRT_LPI2C_DMA +static int imxrt_lpi2c_dma_configure_mder(FAR struct imxrt_lpi2c_priv_s * + priv) +{ + struct imxrt_edma_xfrconfig_s config; + memset(&config, 0, sizeof(config)); + + config.saddr = (uint32_t) &g_lpi2c_mder_rdde; + config.daddr = priv->config->base + IMXRT_LPI2C_MDER_OFFSET; + config.soff = 0; + config.doff = sizeof(uint8_t); + config.iter = 1; + config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE; + config.ssize = EDMA_8BIT; + config.dsize = EDMA_8BIT; + config.nbytes = sizeof(uint8_t); + + up_clean_dcache((uintptr_t)config.saddr , + (uintptr_t)config.saddr + config.nbytes); + + return imxrt_dmach_xfrsetup(priv->dma, &config); +} +#endif + +/**************************************************************************** + * Name: imxrt_lpi2c_dma_command_configure + * + * Description: + * Create a command TCD + * + ****************************************************************************/ + +#ifdef CONFIG_IMXRT_LPI2C_DMA +static int imxrt_lpi2c_dma_command_configure(FAR struct imxrt_lpi2c_priv_s + *priv, uint16_t *ccmd, + uint32_t ncmd) +{ + struct imxrt_edma_xfrconfig_s config; + memset(&config, 0, sizeof(config)); + + config.saddr = (uint32_t) ccmd; + config.daddr = priv->config->base + IMXRT_LPI2C_MTDR_OFFSET; + config.soff = sizeof(uint16_t); + config.doff = 0; + config.iter = 1; + config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE; + config.ssize = EDMA_16BIT; + config.dsize = EDMA_16BIT; + config.nbytes = sizeof(uint16_t) * ncmd; + + up_clean_dcache((uintptr_t)config.saddr , + (uintptr_t)config.saddr + config.nbytes); + + return imxrt_dmach_xfrsetup(priv->dma, &config); +} +#endif + +/**************************************************************************** + * Name: imxrt_lpi2c_dma_data_configure + * + * Description: + * Create a data TCD + * + ****************************************************************************/ + +#ifdef CONFIG_IMXRT_LPI2C_DMA +static int imxrt_lpi2c_dma_data_configure(FAR struct imxrt_lpi2c_priv_s + *priv, + struct i2c_msg_s *msg) +{ + struct imxrt_edma_xfrconfig_s config; + memset(&config, 0, sizeof(config)); + + config.iter = msg->length; + config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE; + config.ssize = EDMA_8BIT; + config.dsize = EDMA_8BIT; + config.nbytes = sizeof(msg->buffer[0]); + + if (msg->flags & I2C_M_READ) + { + config.saddr = priv->config->base + IMXRT_LPI2C_MRDR_OFFSET; + config.daddr = (uint32_t) msg->buffer; + config.soff = 0; + config.doff = sizeof(msg->buffer[0]); + up_invalidate_dcache((uintptr_t)msg->buffer, + (uintptr_t)msg->buffer + msg->length); + } + else + { + config.saddr = (uint32_t) msg->buffer; + config.daddr = priv->config->base + IMXRT_LPI2C_MTDR_OFFSET; + config.soff = sizeof(msg->buffer[0]); + config.doff = 0; + up_clean_dcache((uintptr_t)msg->buffer, + (uintptr_t)msg->buffer + msg->length); + } + + return imxrt_dmach_xfrsetup(priv->dma, &config) ? 0 : msg->length; +} +#endif + +/**************************************************************************** + * Name: imxrt_lpi2c_configure_dma_transfer + * + * Description: + * DMA based I2C transfer function + * + ****************************************************************************/ + +#ifdef CONFIG_IMXRT_LPI2C_DMA +static int imxrt_lpi2c_form_command_list(FAR struct imxrt_lpi2c_priv_s + *priv, struct i2c_msg_s *msg, + int ncmds) +{ + ssize_t length = 0; + + if (priv->flags & I2C_M_NOSTART) + { + if (priv->flags & I2C_M_READ) + { + /* No start read operation */ + + priv->cmnds[ncmds++] = LPI2C_MTDR_CMD_RXD | + LPI2C_MTDR_DATA(msg->length - 1); + } + } + else + { + /* A start based read or write operation */ + + /* Create bus address with R/W */ + + uint16_t badd = (priv->flags & I2C_M_READ) ? I2C_READADDR8(msg->addr) : + I2C_WRITEADDR8(msg->addr); + + priv->cmnds[ncmds++] = LPI2C_MTDR_CMD_START | LPI2C_MTDR_DATA(badd); + + if (badd & I2C_READBIT) + { + length = msg->length; + while (length) + { + if (length > 256u) + { + priv->cmnds[ncmds++] = LPI2C_MTDR_CMD_RXD | + LPI2C_MTDR_DATA(256u - 1); + length -= 256u; + } + else + { + priv->cmnds[ncmds++] = LPI2C_MTDR_CMD_RXD | + LPI2C_MTDR_DATA(length - 1); + length = 0; + } + } + } + } + + return ncmds; +} +#endif + +/**************************************************************************** + * Name: imxrt_lpi2c_dma_transfer + * + * Description: + * DMA based I2C transfer function + * + ****************************************************************************/ + +#ifdef CONFIG_IMXRT_LPI2C_DMA +static int imxrt_lpi2c_dma_transfer(FAR struct imxrt_lpi2c_priv_s *priv) +{ + int m; + int ntotcmds = 0; + int ncmds = 0; + uint16_t *ccmnd = NULL; + + /* Disable Interrupts */ + + imxrt_lpi2c_modifyreg(priv, IMXRT_LPI2C_MIER_OFFSET, + LPI2C_MIER_RDIE | LPI2C_MIER_TDIE, 0); + + /* Disable DMA */ + + imxrt_lpi2c_modifyreg(priv, IMXRT_LPI2C_MDER_OFFSET, LPI2C_MDER_TDDE | + LPI2C_MDER_RDDE, 0); + + /* Turn off auto_stop option */ + + imxrt_lpi2c_modifyreg(priv, IMXRT_LPI2C_MCFGR1_OFFSET, 0, + LPI2C_MCFGR1_IGNACK | LPI2C_MCFGR1_AUTOSTOP); + + /* Form chains of tcd to process the messages */ + + for (m = 0; m < priv->msgc; m++) + { + ncmds = 0; + priv->flags = priv->msgv[m].flags; + + /* Form a command list */ + + ccmnd = &priv->cmnds[ntotcmds]; + + ncmds = imxrt_lpi2c_form_command_list(priv, &priv->msgv[m], ntotcmds); + + /* Have commands for this message ? */ + + if (ncmds != 0) + { + /* Build up a TCD with the command from this message */ + + imxrt_lpi2c_dma_command_configure(priv, ccmnd, ncmds - ntotcmds); + + ntotcmds += ncmds; + + DEBUGASSERT(ntotcmds < CONFIG_IMXRT_LPI2C_DMA_MAXMSG); + + if (priv->flags & I2C_M_READ) + { + /* We have commands and this message is a read. + * Since there is only one DMA request line for both TX/RX + * we must insert a DMA operation to switch to the LSI2C from + * TX to RX DMA + */ + + imxrt_lpi2c_dma_configure_mder(priv); + } + + imxrt_lpi2c_dma_data_configure(priv, &priv->msgv[m]); + } + } + + imxrt_lpi2c_putreg(priv, IMXRT_LPI2C_MIER_OFFSET, + LPI2C_MIER_NDIE | LPI2C_MIER_ALIE | + LPI2C_MIER_PLTIE | LPI2C_MIER_FEIE); + + imxrt_dmach_start(priv->dma, imxrt_dma_callback, (void *)priv); + + imxrt_lpi2c_modifyreg(priv, IMXRT_LPI2C_MDER_OFFSET, 0, + LPI2C_MDER_TDDE | LPI2C_MDER_RDDE); + return OK; +} +#endif + /**************************************************************************** * Name: imxrt_lpi2c_transfer * @@ -1678,11 +2120,26 @@ static int imxrt_lpi2c_transfer(struct i2c_master_s *dev, * the BUSY flag. */ +#ifdef CONFIG_IMXRT_LPI2C_DMA + if (priv->dma) + { + imxrt_lpi2c_dma_transfer(priv); + } +#endif + if (imxrt_lpi2c_sem_waitdone(priv) < 0) { +#ifdef CONFIG_IMXRT_LPI2C_DMA + if (priv->dma) + { + imxrt_dmach_stop(priv->dma); + } + +#endif ret = -ETIMEDOUT; - i2cerr("ERROR: Timed out: MCR: status: 0x%" PRIx32 "\n", priv->status); + i2cerr("ERROR: Timed out: MSR: status: 0x0%" PRIx32 "\n", + priv->status); } /* Check for error status conditions */ @@ -1920,6 +2377,15 @@ struct i2c_master_s *imxrt_i2cbus_initialize(int port) { imxrt_lpi2c_sem_init(priv); imxrt_lpi2c_init(priv); + +#ifdef CONFIG_IMXRT_LPI2C_DMA + if (priv->config->dma_reqsrc != 0) + { + priv->dma = imxrt_dmach_alloc(priv->config->dma_reqsrc | + DMAMUX_CHCFG_ENBL, 0); + DEBUGASSERT(priv->dma != NULL); + } +#endif } leave_critical_section(flags); @@ -1961,6 +2427,15 @@ int imxrt_i2cbus_uninitialize(struct i2c_master_s *dev) /* Disable power and other HW resource (GPIO's) */ +#ifdef CONFIG_IMXRT_LPI2C_DMA + if (priv->dma != NULL) + { + imxrt_dmach_stop(priv->dma); + imxrt_dmach_free(priv->dma); + priv->dma = NULL; + } +#endif + imxrt_lpi2c_deinit(priv); /* Release unused resources */