imxrt:Add LPI2C DMA

This commit is contained in:
David Sidrane 2022-06-01 14:01:30 -07:00 committed by Xiang Xiao
parent f34acdb936
commit 85ec2e1446
2 changed files with 549 additions and 35 deletions

View file

@ -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

View file

@ -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 */