You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2022/08/06 07:32:13 UTC

[incubator-nuttx] 02/04: imxrt:Add LPI2C DMA

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 85ec2e1446b55f679cdf0aad6cfcd521eeceb6db
Author: David Sidrane <Da...@NscDg.com>
AuthorDate: Wed Jun 1 14:01:30 2022 -0700

    imxrt:Add LPI2C DMA
---
 arch/arm/src/imxrt/Kconfig       |  39 +++
 arch/arm/src/imxrt/imxrt_lpi2c.c | 543 ++++++++++++++++++++++++++++++++++++---
 2 files changed, 548 insertions(+), 34 deletions(-)

diff --git a/arch/arm/src/imxrt/Kconfig b/arch/arm/src/imxrt/Kconfig
index 4b7c010a9e..b8608c1511 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 d5537a080f..6310594139 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;
+          priv->status = status;
 
-              /* inform the thread that transfer is complete
-               * and wake it up
-               */
+          /* inform the thread that transfer is complete
+           * and wake it up
+           */
 
-              nxsem_post(&priv->sem_isr);
-              priv->intstate = INTSTATE_DONE;
-            }
-#else
-          priv->status = status;
           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 */