summaryrefslogtreecommitdiffstats
path: root/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c.c2608
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c.h1320
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_edma.c616
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_edma.h158
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_freertos.h107
5 files changed, 4809 insertions, 0 deletions
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c.c b/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c.c
new file mode 100644
index 0000000000..bdf4659050
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c.c
@@ -0,0 +1,2608 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_lpi2c.h"
+#include <stdlib.h>
+#include <string.h>
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.lpi2c"
+#endif
+
+/* ! @brief LPI2C master fifo commands. */
+enum
+{
+ kTxDataCmd = LPI2C_MTDR_CMD(0x0U), /*!< Transmit DATA[7:0] */
+ kRxDataCmd = LPI2C_MTDR_CMD(0X1U), /*!< Receive (DATA[7:0] + 1) bytes */
+ kStopCmd = LPI2C_MTDR_CMD(0x2U), /*!< Generate STOP condition */
+ kStartCmd = LPI2C_MTDR_CMD(0x4U), /*!< Generate(repeated) START and transmit address in DATA[[7:0] */
+};
+
+/*!
+ * @brief Default watermark values.
+ *
+ * The default watermarks are set to zero.
+ */
+enum
+{
+ kDefaultTxWatermark = 0,
+ kDefaultRxWatermark = 0,
+};
+
+/*! @brief States for the state machine used by transactional APIs. */
+enum
+{
+ kIdleState = 0,
+ kSendCommandState,
+ kIssueReadCommandState,
+ kTransferDataState,
+ kStopState,
+ kWaitForCompletionState,
+};
+
+/*
+ * <! Structure definition for variables that passed as parameters in LPI2C_RunTransferStateMachine.
+ * The structure is private.
+ */
+typedef struct _lpi2c_state_machine_param
+{
+ bool state_complete;
+ size_t rxCount;
+ size_t txCount;
+ uint32_t status;
+} lpi2c_state_machine_param_t;
+
+/*! @brief Typedef for slave interrupt handler. */
+typedef void (*lpi2c_slave_isr_t)(LPI2C_Type *base, lpi2c_slave_handle_t *handle);
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+static uint32_t LPI2C_GetCyclesForWidth(
+ uint32_t sourceClock_Hz, uint32_t width_ns, uint32_t minCycles, uint32_t maxCycles, uint32_t prescaler);
+
+static status_t LPI2C_MasterWaitForTxReady(LPI2C_Type *base);
+
+static status_t LPI2C_RunTransferStateMachine(LPI2C_Type *base, lpi2c_master_handle_t *handle, bool *isDone);
+
+static void LPI2C_InitTransferStateMachine(lpi2c_master_handle_t *handle);
+
+static status_t LPI2C_SlaveCheckAndClearError(LPI2C_Type *base, uint32_t flags);
+
+static void LPI2C_CommonIRQHandler(LPI2C_Type *base, uint32_t instance);
+
+/*!
+ * @brief introduce function LPI2C_TransferStateMachineSendCommandState.
+ * This function was deal with Send Command State.
+ *
+ * @param base The I2C peripheral base address.
+ * @param handle Master nonblocking driver handle.
+ * @param variable_set Pass the address of the parent function variable.
+ */
+static void LPI2C_TransferStateMachineSendCommand(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_state_machine_param_t *stateParams);
+
+/*!
+ * @brief introduce function LPI2C_TransferStateMachineIssueReadCommandState.
+ * This function was deal with Issue Read Command State.
+ *
+ * @param base The I2C peripheral base address.
+ * @param handle Master nonblocking driver handle.
+ * @param stateParams Pass the address of the parent function variable.
+ */
+static void LPI2C_TransferStateMachineReadCommand(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_state_machine_param_t *stateParams);
+
+/*!
+ * @brief introduce function LPI2C_TransferStateMachineTransferDataState.
+ * This function was deal with init Transfer Data State.
+ *
+ * @param base The I2C peripheral base address.
+ * @param handle Master nonblocking driver handle.
+ * @param stateParams Pass the address of the parent function variable.
+ */
+static void LPI2C_TransferStateMachineTransferData(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_state_machine_param_t *stateParams);
+
+/*!
+ * @brief introduce function LPI2C_TransferStateMachineStopState.
+ * This function was deal with Stop State.
+ *
+ * @param base The I2C peripheral base address.
+ * @param handle Master nonblocking driver handle.
+ * @param stateParams Pass the address of the parent function variable.
+ * @param[out] isDone Set to true if the transfer has completed.
+ */
+static void LPI2C_TransferStateMachineStopState(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_state_machine_param_t *stateParams,
+ bool *isDone);
+
+/*!
+ * @brief introduce function LPI2C_TransferStateMachineWaitState.
+ * This function was deal with Wait For Completion State.
+ *
+ * @param base The I2C peripheral base address.
+ * @param handle Master nonblocking driver handle.
+ * @param stateParams Pass the address of the parent function variable.
+ * @param[out] isDone Set to true if the transfer has completed.
+ */
+static void LPI2C_TransferStateMachineWaitState(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_state_machine_param_t *stateParams,
+ bool *isDone);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*! @brief Array to map LPI2C instance number to base pointer. */
+static LPI2C_Type *const kLpi2cBases[] = LPI2C_BASE_PTRS;
+
+/*! @brief Array to map LPI2C instance number to IRQ number, used internally for LPI2C master interrupt and EDMA
+transactional APIs. */
+IRQn_Type const kLpi2cIrqs[] = LPI2C_IRQS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Array to map LPI2C instance number to clock gate enum. */
+static clock_ip_name_t const kLpi2cClocks[] = LPI2C_CLOCKS;
+
+#if defined(LPI2C_PERIPH_CLOCKS)
+/*! @brief Array to map LPI2C instance number to pheripheral clock gate enum. */
+static const clock_ip_name_t kLpi2cPeriphClocks[] = LPI2C_PERIPH_CLOCKS;
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*! @brief Pointer to master IRQ handler for each instance, used internally for LPI2C master interrupt and EDMA
+transactional APIs. */
+lpi2c_master_isr_t s_lpi2cMasterIsr;
+
+/*! @brief Pointers to master handles for each instance, used internally for LPI2C master interrupt and EDMA
+transactional APIs. */
+void *s_lpi2cMasterHandle[ARRAY_SIZE(kLpi2cBases)];
+
+/*! @brief Pointer to slave IRQ handler for each instance. */
+static lpi2c_slave_isr_t s_lpi2cSlaveIsr;
+
+/*! @brief Pointers to slave handles for each instance. */
+static lpi2c_slave_handle_t *s_lpi2cSlaveHandle[ARRAY_SIZE(kLpi2cBases)];
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * brief Returns an instance number given a base address.
+ *
+ * If an invalid base address is passed, debug builds will assert. Release builds will just return
+ * instance number 0.
+ *
+ * param base The LPI2C peripheral base address.
+ * return LPI2C instance number starting from 0.
+ */
+uint32_t LPI2C_GetInstance(LPI2C_Type *base)
+{
+ uint32_t instance;
+ for (instance = 0U; instance < ARRAY_SIZE(kLpi2cBases); ++instance)
+ {
+ if (kLpi2cBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(kLpi2cBases));
+ return instance;
+}
+
+/*!
+ * @brief Computes a cycle count for a given time in nanoseconds.
+ * @param sourceClock_Hz LPI2C functional clock frequency in Hertz.
+ * @param width_ns Desired with in nanoseconds.
+ * @param minCycles Minimum cycle count.
+ * @param maxCycles Maximum cycle count.
+ * @param prescaler LPI2C prescaler setting. If the cycle period is not affected by the prescaler value, set it to 0.
+ */
+static uint32_t LPI2C_GetCyclesForWidth(
+ uint32_t sourceClock_Hz, uint32_t width_ns, uint32_t minCycles, uint32_t maxCycles, uint32_t prescaler)
+{
+ assert(sourceClock_Hz > 0U);
+
+ uint32_t divider = 1U;
+
+ while (prescaler != 0U)
+ {
+ divider *= 2U;
+ prescaler--;
+ }
+
+ uint32_t busCycle_ns = 1000000U / (sourceClock_Hz / divider / 1000U);
+ /* Calculate the cycle count, round up the calculated value. */
+ uint32_t cycles = (width_ns * 10U / busCycle_ns + 5U) / 10U;
+
+ /* If the calculated value is smaller than the minimum value, use the minimum value */
+ if (cycles < minCycles)
+ {
+ cycles = minCycles;
+ }
+ /* If the calculated value is larger than the maximum value, use the maxmum value */
+ if (cycles > maxCycles)
+ {
+ cycles = maxCycles;
+ }
+
+ return cycles;
+}
+
+/*!
+ * @brief Convert provided flags to status code, and clear any errors if present.
+ * @param base The LPI2C peripheral base address.
+ * @param status Current status flags value that will be checked.
+ * @retval #kStatus_Success
+ * @retval #kStatus_LPI2C_PinLowTimeout
+ * @retval #kStatus_LPI2C_ArbitrationLost
+ * @retval #kStatus_LPI2C_Nak
+ * @retval #kStatus_LPI2C_FifoError
+ */
+/* Not static so it can be used from fsl_lpi2c_edma.c. */
+status_t LPI2C_MasterCheckAndClearError(LPI2C_Type *base, uint32_t status)
+{
+ status_t result = kStatus_Success;
+
+ /* Check for error. These errors cause a stop to automatically be sent. We must */
+ /* clear the errors before a new transfer can start. */
+ status &= (uint32_t)kLPI2C_MasterErrorFlags;
+ if (0U != status)
+ {
+ /* Select the correct error code. Ordered by severity, with bus issues first. */
+ if (0U != (status & (uint32_t)kLPI2C_MasterPinLowTimeoutFlag))
+ {
+ result = kStatus_LPI2C_PinLowTimeout;
+ }
+ else if (0U != (status & (uint32_t)kLPI2C_MasterArbitrationLostFlag))
+ {
+ result = kStatus_LPI2C_ArbitrationLost;
+ }
+ else if (0U != (status & (uint32_t)kLPI2C_MasterNackDetectFlag))
+ {
+ result = kStatus_LPI2C_Nak;
+ }
+ else if (0U != (status & (uint32_t)kLPI2C_MasterFifoErrFlag))
+ {
+ result = kStatus_LPI2C_FifoError;
+ }
+ else
+ {
+ ; /* Intentional empty */
+ }
+
+ /* Clear the flags. */
+ LPI2C_MasterClearStatusFlags(base, status);
+
+ /* Reset fifos. These flags clear automatically. */
+ base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
+ }
+ else
+ {
+ ; /* Intentional empty */
+ }
+
+ return result;
+}
+
+/*!
+ * @brief Wait until there is room in the tx fifo.
+ * @param base The LPI2C peripheral base address.
+ * @retval #kStatus_Success
+ * @retval #kStatus_LPI2C_PinLowTimeout
+ * @retval #kStatus_LPI2C_ArbitrationLost
+ * @retval #kStatus_LPI2C_Nak
+ * @retval #kStatus_LPI2C_FifoError
+ */
+static status_t LPI2C_MasterWaitForTxReady(LPI2C_Type *base)
+{
+ status_t result = kStatus_Success;
+ uint32_t status;
+ size_t txCount;
+ size_t txFifoSize = (size_t)FSL_FEATURE_LPI2C_FIFO_SIZEn(base);
+
+#if I2C_RETRY_TIMES != 0U
+ uint32_t waitTimes = I2C_RETRY_TIMES;
+#endif
+ do
+ {
+ /* Get the number of words in the tx fifo and compute empty slots. */
+ LPI2C_MasterGetFifoCounts(base, NULL, &txCount);
+ txCount = txFifoSize - txCount;
+
+ /* Check for error flags. */
+ status = LPI2C_MasterGetStatusFlags(base);
+ result = LPI2C_MasterCheckAndClearError(base, status);
+ if (kStatus_Success != result)
+ {
+ break;
+ }
+#if I2C_RETRY_TIMES != 0U
+ waitTimes--;
+ } while ((0U == txCount) && (0U != waitTimes));
+
+ if (0U == waitTimes)
+ {
+ result = kStatus_LPI2C_Timeout;
+ }
+#else
+ } while (0U == txCount);
+#endif
+
+ return result;
+}
+
+/*!
+ * @brief Make sure the bus isn't already busy.
+ *
+ * A busy bus is allowed if we are the one driving it.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @retval #kStatus_Success
+ * @retval #kStatus_LPI2C_Busy
+ */
+/* Not static so it can be used from fsl_lpi2c_edma.c. */
+status_t LPI2C_CheckForBusyBus(LPI2C_Type *base)
+{
+ status_t ret = kStatus_Success;
+
+ uint32_t status = LPI2C_MasterGetStatusFlags(base);
+ if ((0U != (status & (uint32_t)kLPI2C_MasterBusBusyFlag)) && (0U == (status & (uint32_t)kLPI2C_MasterBusyFlag)))
+ {
+ ret = kStatus_LPI2C_Busy;
+ }
+
+ return ret;
+}
+
+/*!
+ * brief Provides a default configuration for the LPI2C master peripheral.
+ *
+ * This function provides the following default configuration for the LPI2C master peripheral:
+ * code
+ * masterConfig->enableMaster = true;
+ * masterConfig->debugEnable = false;
+ * masterConfig->ignoreAck = false;
+ * masterConfig->pinConfig = kLPI2C_2PinOpenDrain;
+ * masterConfig->baudRate_Hz = 100000U;
+ * masterConfig->busIdleTimeout_ns = 0U;
+ * masterConfig->pinLowTimeout_ns = 0U;
+ * masterConfig->sdaGlitchFilterWidth_ns = 0U;
+ * masterConfig->sclGlitchFilterWidth_ns = 0U;
+ * masterConfig->hostRequest.enable = false;
+ * masterConfig->hostRequest.source = kLPI2C_HostRequestExternalPin;
+ * masterConfig->hostRequest.polarity = kLPI2C_HostRequestPinActiveHigh;
+ * endcode
+ *
+ * After calling this function, you can override any settings in order to customize the configuration,
+ * prior to initializing the master driver with LPI2C_MasterInit().
+ *
+ * param[out] masterConfig User provided configuration structure for default values. Refer to #lpi2c_master_config_t.
+ */
+void LPI2C_MasterGetDefaultConfig(lpi2c_master_config_t *masterConfig)
+{
+ /* Initializes the configure structure to zero. */
+ (void)memset(masterConfig, 0, sizeof(*masterConfig));
+
+ masterConfig->enableMaster = true;
+ masterConfig->debugEnable = false;
+ masterConfig->enableDoze = true;
+ masterConfig->ignoreAck = false;
+ masterConfig->pinConfig = kLPI2C_2PinOpenDrain;
+ masterConfig->baudRate_Hz = 100000U;
+ masterConfig->busIdleTimeout_ns = 0U; /* Set to 0 to disable the function */
+ masterConfig->pinLowTimeout_ns = 0U; /* Set to 0 to disable the function */
+ masterConfig->sdaGlitchFilterWidth_ns = 0U; /* Set to 0 to disable the function */
+ masterConfig->sclGlitchFilterWidth_ns = 0U; /* Set to 0 to disable the function */
+ masterConfig->hostRequest.enable = false;
+ masterConfig->hostRequest.source = kLPI2C_HostRequestExternalPin;
+ masterConfig->hostRequest.polarity = kLPI2C_HostRequestPinActiveHigh;
+}
+
+/*!
+ * brief Initializes the LPI2C master peripheral.
+ *
+ * This function enables the peripheral clock and initializes the LPI2C master peripheral as described by the user
+ * provided configuration. A software reset is performed prior to configuration.
+ *
+ * param base The LPI2C peripheral base address.
+ * param masterConfig User provided peripheral configuration. Use LPI2C_MasterGetDefaultConfig() to get a set of
+ * defaults
+ * that you can override.
+ * param sourceClock_Hz Frequency in Hertz of the LPI2C functional clock. Used to calculate the baud rate divisors,
+ * filter widths, and timeout periods.
+ */
+void LPI2C_MasterInit(LPI2C_Type *base, const lpi2c_master_config_t *masterConfig, uint32_t sourceClock_Hz)
+{
+ uint32_t prescaler;
+ uint32_t cycles;
+ uint32_t cfgr2;
+ uint32_t value;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+
+ uint32_t instance = LPI2C_GetInstance(base);
+
+ /* Ungate the clock. */
+ (void)CLOCK_EnableClock(kLpi2cClocks[instance]);
+#if defined(LPI2C_PERIPH_CLOCKS)
+ /* Ungate the functional clock in initialize function. */
+ CLOCK_EnableClock(kLpi2cPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Reset peripheral before configuring it. */
+ LPI2C_MasterReset(base);
+
+ /* Doze bit: 0 is enable, 1 is disable */
+ base->MCR = LPI2C_MCR_DBGEN(masterConfig->debugEnable) | LPI2C_MCR_DOZEN(!(masterConfig->enableDoze));
+
+ /* host request */
+ value = base->MCFGR0;
+ value &= (~(LPI2C_MCFGR0_HREN_MASK | LPI2C_MCFGR0_HRPOL_MASK | LPI2C_MCFGR0_HRSEL_MASK));
+ value |= LPI2C_MCFGR0_HREN(masterConfig->hostRequest.enable) |
+ LPI2C_MCFGR0_HRPOL(masterConfig->hostRequest.polarity) |
+ LPI2C_MCFGR0_HRSEL(masterConfig->hostRequest.source);
+ base->MCFGR0 = value;
+
+ /* pin config and ignore ack */
+ value = base->MCFGR1;
+ value &= ~(LPI2C_MCFGR1_PINCFG_MASK | LPI2C_MCFGR1_IGNACK_MASK);
+ value |= LPI2C_MCFGR1_PINCFG(masterConfig->pinConfig);
+ value |= LPI2C_MCFGR1_IGNACK(masterConfig->ignoreAck);
+ base->MCFGR1 = value;
+
+ LPI2C_MasterSetWatermarks(base, (size_t)kDefaultTxWatermark, (size_t)kDefaultRxWatermark);
+
+ /* Configure glitch filters. */
+ cfgr2 = base->MCFGR2;
+ if (0U != (masterConfig->sdaGlitchFilterWidth_ns))
+ {
+ /* Calculate SDA filter width. The width is equal to FILTSDA cycles of functional clock.
+ And set FILTSDA to 0 disables the fileter, so the min value is 1. */
+ cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->sdaGlitchFilterWidth_ns, 1U,
+ (LPI2C_MCFGR2_FILTSDA_MASK >> LPI2C_MCFGR2_FILTSDA_SHIFT), 0U);
+ cfgr2 &= ~LPI2C_MCFGR2_FILTSDA_MASK;
+ cfgr2 |= LPI2C_MCFGR2_FILTSDA(cycles);
+ }
+ if (0U != masterConfig->sclGlitchFilterWidth_ns)
+ {
+ /* Calculate SDL filter width. The width is equal to FILTSCL cycles of functional clock.
+ And set FILTSCL to 0 disables the fileter, so the min value is 1. */
+ cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->sclGlitchFilterWidth_ns, 1U,
+ (LPI2C_MCFGR2_FILTSCL_MASK >> LPI2C_MCFGR2_FILTSCL_SHIFT), 0U);
+ cfgr2 &= ~LPI2C_MCFGR2_FILTSCL_MASK;
+ cfgr2 |= LPI2C_MCFGR2_FILTSCL(cycles);
+ }
+ base->MCFGR2 = cfgr2;
+
+ /* Configure baudrate after the SDA/SCL glitch filter setting,
+ since the baudrate calculation needs them as parameter. */
+ LPI2C_MasterSetBaudRate(base, sourceClock_Hz, masterConfig->baudRate_Hz);
+
+ /* Configure bus idle and pin low timeouts after baudrate setting,
+ since the timeout calculation needs prescaler as parameter. */
+ prescaler = (base->MCFGR1 & LPI2C_MCFGR1_PRESCALE_MASK) >> LPI2C_MCFGR1_PRESCALE_SHIFT;
+
+ if (0U != (masterConfig->busIdleTimeout_ns))
+ {
+ /* Calculate bus idle timeout value. The value is equal to BUSIDLE cycles of functional clock divided by
+ prescaler. And set BUSIDLE to 0 disables the fileter, so the min value is 1. */
+ cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->busIdleTimeout_ns, 1U,
+ (LPI2C_MCFGR2_BUSIDLE_MASK >> LPI2C_MCFGR2_BUSIDLE_SHIFT), prescaler);
+ base->MCFGR2 = (base->MCFGR2 & (~LPI2C_MCFGR2_BUSIDLE_MASK)) | LPI2C_MCFGR2_BUSIDLE(cycles);
+ }
+ if (0U != masterConfig->pinLowTimeout_ns)
+ {
+ /* Calculate bus pin low timeout value. The value is equal to PINLOW cycles of functional clock divided by
+ prescaler. And set PINLOW to 0 disables the fileter, so the min value is 1. */
+ cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->pinLowTimeout_ns / 256U, 1U,
+ (LPI2C_MCFGR2_BUSIDLE_MASK >> LPI2C_MCFGR2_BUSIDLE_SHIFT), prescaler);
+ base->MCFGR3 = (base->MCFGR3 & ~LPI2C_MCFGR3_PINLOW_MASK) | LPI2C_MCFGR3_PINLOW(cycles);
+ }
+
+ LPI2C_MasterEnable(base, masterConfig->enableMaster);
+}
+
+/*!
+ * brief Deinitializes the LPI2C master peripheral.
+ *
+ * This function disables the LPI2C master peripheral and gates the clock. It also performs a software
+ * reset to restore the peripheral to reset conditions.
+ *
+ * param base The LPI2C peripheral base address.
+ */
+void LPI2C_MasterDeinit(LPI2C_Type *base)
+{
+ /* Restore to reset state. */
+ LPI2C_MasterReset(base);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+
+ uint32_t instance = LPI2C_GetInstance(base);
+
+ /* Gate clock. */
+ (void)CLOCK_DisableClock(kLpi2cClocks[instance]);
+#if defined(LPI2C_PERIPH_CLOCKS)
+ /* Gate the functional clock. */
+ CLOCK_DisableClock(kLpi2cPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Configures LPI2C master data match feature.
+ *
+ * param base The LPI2C peripheral base address.
+ * param matchConfig Settings for the data match feature.
+ */
+void LPI2C_MasterConfigureDataMatch(LPI2C_Type *base, const lpi2c_data_match_config_t *matchConfig)
+{
+ /* Disable master mode. */
+ bool wasEnabled = (0U != ((base->MCR & LPI2C_MCR_MEN_MASK) >> LPI2C_MCR_MEN_SHIFT));
+ LPI2C_MasterEnable(base, false);
+
+ base->MCFGR1 = (base->MCFGR1 & ~LPI2C_MCFGR1_MATCFG_MASK) | LPI2C_MCFGR1_MATCFG(matchConfig->matchMode);
+ base->MCFGR0 = (base->MCFGR0 & ~LPI2C_MCFGR0_RDMO_MASK) | LPI2C_MCFGR0_RDMO(matchConfig->rxDataMatchOnly);
+ base->MDMR = LPI2C_MDMR_MATCH0(matchConfig->match0) | LPI2C_MDMR_MATCH1(matchConfig->match1);
+
+ /* Restore master mode. */
+ if (wasEnabled)
+ {
+ LPI2C_MasterEnable(base, true);
+ }
+}
+
+/*!
+ * brief Sets the I2C bus frequency for master transactions.
+ *
+ * The LPI2C master is automatically disabled and re-enabled as necessary to configure the baud
+ * rate. Do not call this function during a transfer, or the transfer is aborted.
+ *
+ * note Please note that the second parameter is the clock frequency of LPI2C module, the third
+ * parameter means user configured bus baudrate, this implementation is different from other I2C drivers
+ * which use baudrate configuration as second parameter and source clock frequency as third parameter.
+ *
+ * param base The LPI2C peripheral base address.
+ * param sourceClock_Hz LPI2C functional clock frequency in Hertz.
+ * param baudRate_Hz Requested bus frequency in Hertz.
+ */
+void LPI2C_MasterSetBaudRate(LPI2C_Type *base, uint32_t sourceClock_Hz, uint32_t baudRate_Hz)
+{
+ bool wasEnabled;
+ uint8_t filtScl = (uint8_t)((base->MCFGR2 & LPI2C_MCFGR2_FILTSCL_MASK) >> LPI2C_MCFGR2_FILTSCL_SHIFT);
+
+ uint8_t divider = 1U;
+ uint8_t bestDivider = 1U;
+ uint8_t prescale = 0U;
+ uint8_t bestPre = 0U;
+
+ uint8_t clkCycle;
+ uint8_t bestclkCycle = 0U;
+
+ uint32_t absError = 0U;
+ uint32_t bestError = 0xffffffffu;
+ uint32_t computedRate;
+
+ uint32_t tmpReg = 0U;
+
+ /* Disable master mode. */
+ wasEnabled = (0U != ((base->MCR & LPI2C_MCR_MEN_MASK) >> LPI2C_MCR_MEN_SHIFT));
+ LPI2C_MasterEnable(base, false);
+
+ /* Baud rate = (sourceClock_Hz / 2 ^ prescale) / (CLKLO + 1 + CLKHI + 1 + SCL_LATENCY)
+ * SCL_LATENCY = ROUNDDOWN((2 + FILTSCL) / (2 ^ prescale))
+ */
+ for (prescale = 0U; prescale <= 7U; prescale++)
+ {
+ /* Calculate the clkCycle, clkCycle = CLKLO + CLKHI, divider = 2 ^ prescale */
+ clkCycle = (uint8_t)((10U * sourceClock_Hz / divider / baudRate_Hz + 5U) / 10U - (2U + filtScl) / divider - 2U);
+ /* According to register description, The max value for CLKLO and CLKHI is 63.
+ however to meet the I2C specification of tBUF, CLKHI should be less than
+ clkCycle - 0.52 x sourceClock_Hz / baudRate_Hz / divider + 1U. Refer to the comment of the tmpHigh's
+ calculation for details. So we have:
+ CLKHI < clkCycle - 0.52 x sourceClock_Hz / baudRate_Hz / divider + 1U,
+ clkCycle = CLKHI + CLKLO and
+ sourceClock_Hz / baudRate_Hz / divider = clkCycle + 2 + ROUNDDOWN((2 + FILTSCL) / divider),
+ we can come up with: CLKHI < 0.92 x CLKLO - ROUNDDOWN(2 + FILTSCL) / divider
+ so the max boundary of CLKHI should be 0.92 x 63 - ROUNDDOWN(2 + FILTSCL) / divider,
+ and the max boundary of clkCycle is 1.92 x 63 - ROUNDDOWN(2 + FILTSCL) / divider. */
+ if (clkCycle > (120U - (2U + filtScl) / divider))
+ {
+ divider *= 2U;
+ continue;
+ }
+ /* Calculate the computed baudrate and compare it with the desired baudrate */
+ computedRate = (sourceClock_Hz / (uint32_t)divider) /
+ ((uint32_t)clkCycle + 2U + (2U + (uint32_t)filtScl) / (uint32_t)divider);
+ absError = baudRate_Hz > computedRate ? baudRate_Hz - computedRate : computedRate - baudRate_Hz;
+ if (absError < bestError)
+ {
+ bestPre = prescale;
+ bestDivider = divider;
+ bestclkCycle = clkCycle;
+ bestError = absError;
+
+ /* If the error is 0, then we can stop searching because we won't find a better match. */
+ if (absError == 0U)
+ {
+ break;
+ }
+ }
+ divider *= 2U;
+ }
+
+ /* SCL low time tLO should be larger than or equal to SCL high time tHI:
+ tLO = ((CLKLO + 1) x (2 ^ PRESCALE)) >= tHI = ((CLKHI + 1 + SCL_LATENCY) x (2 ^ PRESCALE)),
+ which is CLKLO >= CLKHI + (2U + filtScl) / bestDivider.
+ Also since bestclkCycle = CLKLO + CLKHI, bestDivider = 2 ^ PRESCALE
+ which makes CLKHI <= (bestclkCycle - (2U + filtScl) / bestDivider) / 2U.
+
+ The max tBUF should be at least 0.52 times of the SCL clock cycle:
+ tBUF = ((CLKLO + 1) x (2 ^ PRESCALE) / sourceClock_Hz) > (0.52 / baudRate_Hz),
+ plus bestDivider = 2 ^ PRESCALE, bestclkCycle = CLKLO + CLKHI we can come up with
+ CLKHI <= (bestclkCycle - 0.52 x sourceClock_Hz / baudRate_Hz / bestDivider + 1U).
+ In this case to get a safe CLKHI calculation, we can assume:
+ */
+ uint8_t tmpHigh = (bestclkCycle - (2U + filtScl) / bestDivider) / 2U;
+ while (tmpHigh > (bestclkCycle - 52U * sourceClock_Hz / baudRate_Hz / bestDivider / 100U + 1U))
+ {
+ tmpHigh = tmpHigh - 1U;
+ }
+
+ /* Calculate DATAVD and SETHOLD.
+ To meet the timing requirement of I2C spec for standard mode, fast mode and fast mode plus: */
+ /* The min tHD:STA/tSU:STA/tSU:STO should be at least 0.4 times of the SCL clock cycle, use 0.5 to be safe:
+ tHD:STA = ((SETHOLD + 1) x (2 ^ PRESCALE) / sourceClock_Hz) > (0.5 / baudRate_Hz), bestDivider = 2 ^ PRESCALE */
+ uint8_t tmpHold = (uint8_t)(sourceClock_Hz / baudRate_Hz / bestDivider / 2U) - 1U;
+
+ /* The max tVD:DAT/tVD:ACK/tHD:DAT should be at most 0.345 times of the SCL clock cycle, use 0.25 to be safe:
+ tVD:DAT = ((DATAVD + 1) x (2 ^ PRESCALE) / sourceClock_Hz) < (0.25 / baudRate_Hz), bestDivider = 2 ^ PRESCALE */
+ uint8_t tmpDataVd = (uint8_t)(sourceClock_Hz / baudRate_Hz / bestDivider / 4U) - 1U;
+
+ /* The min tSU:DAT should be at least 0.05 times of the SCL clock cycle:
+ tSU:DAT = ((2 + FILTSDA + 2 ^ PRESCALE) / sourceClock_Hz) >= (0.05 / baud),
+ plus bestDivider = 2 ^ PRESCALE, we can come up with:
+ FILTSDA >= (0.05 x sourceClock_Hz / baudRate_Hz - bestDivider - 2) */
+ if ((sourceClock_Hz / baudRate_Hz / 20U) > (bestDivider + 2U))
+ {
+ /* Read out the FILTSDA configuration, if it is smaller than expected, change the setting. */
+ uint8_t filtSda = (uint8_t)((base->MCFGR2 & LPI2C_MCFGR2_FILTSDA_MASK) >> LPI2C_MCFGR2_FILTSDA_SHIFT);
+ if (filtSda < (sourceClock_Hz / baudRate_Hz / 20U - bestDivider - 2U))
+ {
+ filtSda = (uint8_t)(sourceClock_Hz / baudRate_Hz / 20U) - bestDivider - 2U;
+ }
+ base->MCFGR2 = (base->MCFGR2 & ~LPI2C_MCFGR2_FILTSDA_MASK) | LPI2C_MCFGR2_FILTSDA(filtSda);
+ }
+
+ /* Set CLKHI, CLKLO, SETHOLD, DATAVD value. */
+ tmpReg = LPI2C_MCCR0_CLKHI((uint32_t)tmpHigh) |
+ LPI2C_MCCR0_CLKLO((uint32_t)((uint32_t)bestclkCycle - (uint32_t)tmpHigh)) |
+ LPI2C_MCCR0_SETHOLD((uint32_t)tmpHold) | LPI2C_MCCR0_DATAVD((uint32_t)tmpDataVd);
+ base->MCCR0 = tmpReg;
+
+ /* Set PRESCALE value. */
+ base->MCFGR1 = (base->MCFGR1 & ~LPI2C_MCFGR1_PRESCALE_MASK) | LPI2C_MCFGR1_PRESCALE(bestPre);
+
+ /* Restore master mode. */
+ if (wasEnabled)
+ {
+ LPI2C_MasterEnable(base, true);
+ }
+}
+
+/*!
+ * brief Sends a START signal and slave address on the I2C bus.
+ *
+ * This function is used to initiate a new master mode transfer. First, the bus state is checked to ensure
+ * that another master is not occupying the bus. Then a START signal is transmitted, followed by the
+ * 7-bit address specified in the a address parameter. Note that this function does not actually wait
+ * until the START and address are successfully sent on the bus before returning.
+ *
+ * param base The LPI2C peripheral base address.
+ * param address 7-bit slave device address, in bits [6:0].
+ * param dir Master transfer direction, either #kLPI2C_Read or #kLPI2C_Write. This parameter is used to set
+ * the R/w bit (bit 0) in the transmitted slave address.
+ * retval #kStatus_Success START signal and address were successfully enqueued in the transmit FIFO.
+ * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ */
+status_t LPI2C_MasterStart(LPI2C_Type *base, uint8_t address, lpi2c_direction_t dir)
+{
+ /* Return an error if the bus is already in use not by us. */
+ status_t result = LPI2C_CheckForBusyBus(base);
+ if (kStatus_Success == result)
+ {
+ /* Clear all flags. */
+ LPI2C_MasterClearStatusFlags(base, (uint32_t)kLPI2C_MasterClearFlags);
+
+ /* Turn off auto-stop option. */
+ base->MCFGR1 &= ~LPI2C_MCFGR1_AUTOSTOP_MASK;
+
+ /* Wait until there is room in the fifo. */
+ result = LPI2C_MasterWaitForTxReady(base);
+ if (kStatus_Success == result)
+ {
+ /* Issue start command. */
+ base->MTDR = (uint32_t)kStartCmd | (((uint32_t)address << 1U) | (uint32_t)dir);
+ }
+ }
+
+ return result;
+}
+
+/*!
+ * brief Sends a STOP signal on the I2C bus.
+ *
+ * This function does not return until the STOP signal is seen on the bus, or an error occurs.
+ *
+ * param base The LPI2C peripheral base address.
+ * retval #kStatus_Success The STOP signal was successfully sent on the bus and the transaction terminated.
+ * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte.
+ * retval #kStatus_LPI2C_FifoError FIFO under run or overrun.
+ * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error.
+ * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout.
+ */
+status_t LPI2C_MasterStop(LPI2C_Type *base)
+{
+ /* Wait until there is room in the fifo. */
+ status_t result = LPI2C_MasterWaitForTxReady(base);
+ if (kStatus_Success == result)
+ {
+ /* Send the STOP signal */
+ base->MTDR = (uint32_t)kStopCmd;
+
+ /* Wait for the stop detected flag to set, indicating the transfer has completed on the bus. */
+ /* Also check for errors while waiting. */
+#if I2C_RETRY_TIMES != 0U
+ uint32_t waitTimes = I2C_RETRY_TIMES;
+#endif
+
+#if I2C_RETRY_TIMES != 0U
+ while ((result == kStatus_Success) && (0U != waitTimes))
+ {
+ waitTimes--;
+#else
+ while (result == kStatus_Success)
+ {
+#endif
+ uint32_t status = LPI2C_MasterGetStatusFlags(base);
+
+ /* Check for error flags. */
+ result = LPI2C_MasterCheckAndClearError(base, status);
+
+ /* Check if the stop was sent successfully. */
+ if ((0U != (status & (uint32_t)kLPI2C_MasterStopDetectFlag)) &&
+ (0U != (status & (uint32_t)kLPI2C_MasterTxReadyFlag)))
+ {
+ LPI2C_MasterClearStatusFlags(base, (uint32_t)kLPI2C_MasterStopDetectFlag);
+ break;
+ }
+ }
+
+#if I2C_RETRY_TIMES != 0U
+ if (0U == waitTimes)
+ {
+ result = kStatus_LPI2C_Timeout;
+ }
+#endif
+ }
+
+ return result;
+}
+
+/*!
+ * brief Performs a polling receive transfer on the I2C bus.
+ *
+ * param base The LPI2C peripheral base address.
+ * param rxBuff The pointer to the data to be transferred.
+ * param rxSize The length in bytes of the data to be transferred.
+ * retval #kStatus_Success Data was received successfully.
+ * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte.
+ * retval #kStatus_LPI2C_FifoError FIFO under run or overrun.
+ * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error.
+ * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout.
+ */
+status_t LPI2C_MasterReceive(LPI2C_Type *base, void *rxBuff, size_t rxSize)
+{
+ assert(NULL != rxBuff);
+
+ status_t result = kStatus_Success;
+ uint8_t *buf;
+ size_t tmpRxSize = rxSize;
+#if I2C_RETRY_TIMES != 0U
+ uint32_t waitTimes;
+#endif
+
+ /* Check transfer data size. */
+ if (rxSize > ((size_t)256 * (size_t)FSL_FEATURE_LPI2C_FIFO_SIZEn(base)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Handle empty read. */
+ if (rxSize != 0U)
+ {
+ /* Wait until there is room in the command fifo. */
+ result = LPI2C_MasterWaitForTxReady(base);
+ if (kStatus_Success == result)
+ {
+ /* Issue command to receive data. A single write to MTDR can issue read operation of 0xFFU + 1 byte of data
+ at most, so when the rxSize is larger than 0x100U, push multiple read commands to MTDR until rxSize is
+ reached. */
+ while (tmpRxSize != 0U)
+ {
+ if (tmpRxSize > 256U)
+ {
+ base->MTDR = (uint32_t)(kRxDataCmd) | (uint32_t)LPI2C_MTDR_DATA(0xFFU);
+ tmpRxSize -= 256U;
+ }
+ else
+ {
+ base->MTDR = (uint32_t)(kRxDataCmd) | (uint32_t)LPI2C_MTDR_DATA(tmpRxSize - 1U);
+ tmpRxSize = 0U;
+ }
+ }
+
+ /* Receive data */
+ buf = (uint8_t *)rxBuff;
+ while (0U != (rxSize--))
+ {
+#if I2C_RETRY_TIMES != 0U
+ waitTimes = I2C_RETRY_TIMES;
+#endif
+ /* Read LPI2C receive fifo register. The register includes a flag to indicate whether */
+ /* the FIFO is empty, so we can both get the data and check if we need to keep reading */
+ /* using a single register read. */
+ uint32_t value = 0U;
+ do
+ {
+ /* Check for errors. */
+ result = LPI2C_MasterCheckAndClearError(base, LPI2C_MasterGetStatusFlags(base));
+ if (kStatus_Success != result)
+ {
+ break;
+ }
+
+ value = base->MRDR;
+#if I2C_RETRY_TIMES != 0U
+ waitTimes--;
+ } while ((0U != (value & LPI2C_MRDR_RXEMPTY_MASK)) && (0U != waitTimes));
+ if (0U == waitTimes)
+ {
+ result = kStatus_LPI2C_Timeout;
+ }
+#else
+ } while (0U != (value & LPI2C_MRDR_RXEMPTY_MASK));
+#endif
+ if ((status_t)kStatus_Success != result)
+ {
+ break;
+ }
+
+ *buf++ = (uint8_t)(value & LPI2C_MRDR_DATA_MASK);
+ }
+ }
+ }
+
+ return result;
+}
+
+/*!
+ * brief Performs a polling send transfer on the I2C bus.
+ *
+ * Sends up to a txSize number of bytes to the previously addressed slave device. The slave may
+ * reply with a NAK to any byte in order to terminate the transfer early. If this happens, this
+ * function returns #kStatus_LPI2C_Nak.
+ *
+ * param base The LPI2C peripheral base address.
+ * param txBuff The pointer to the data to be transferred.
+ * param txSize The length in bytes of the data to be transferred.
+ * retval #kStatus_Success Data was sent successfully.
+ * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte.
+ * retval #kStatus_LPI2C_FifoError FIFO under run or over run.
+ * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error.
+ * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout.
+ */
+status_t LPI2C_MasterSend(LPI2C_Type *base, void *txBuff, size_t txSize)
+{
+ status_t result = kStatus_Success;
+ uint8_t *buf = (uint8_t *)txBuff;
+
+ assert(NULL != txBuff);
+
+ /* Send data buffer */
+ while (0U != (txSize--))
+ {
+ /* Wait until there is room in the fifo. This also checks for errors. */
+ result = LPI2C_MasterWaitForTxReady(base);
+ if (kStatus_Success != result)
+ {
+ break;
+ }
+
+ /* Write byte into LPI2C master data register. */
+ base->MTDR = *buf++;
+ }
+
+ return result;
+}
+
+/*!
+ * brief Performs a master polling transfer on the I2C bus.
+ *
+ * note The API does not return until the transfer succeeds or fails due
+ * to error happens during transfer.
+ *
+ * param base The LPI2C peripheral base address.
+ * param transfer Pointer to the transfer structure.
+ * retval #kStatus_Success Data was received successfully.
+ * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte.
+ * retval #kStatus_LPI2C_FifoError FIFO under run or overrun.
+ * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error.
+ * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout.
+ */
+status_t LPI2C_MasterTransferBlocking(LPI2C_Type *base, lpi2c_master_transfer_t *transfer)
+{
+ assert(NULL != transfer);
+ assert(transfer->subaddressSize <= sizeof(transfer->subaddress));
+
+ status_t result = kStatus_Success;
+ uint16_t commandBuffer[7];
+ uint32_t cmdCount = 0U;
+
+ /* Check transfer data size in read operation. */
+ if ((transfer->direction == kLPI2C_Read) &&
+ (transfer->dataSize > ((size_t)256 * (size_t)FSL_FEATURE_LPI2C_FIFO_SIZEn(base))))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Enable the master function and disable the slave function. */
+ LPI2C_MasterEnable(base, true);
+ LPI2C_SlaveEnable(base, false);
+
+ /* Return an error if the bus is already in use not by us. */
+ result = LPI2C_CheckForBusyBus(base);
+ if (kStatus_Success == result)
+ {
+ /* Clear all flags. */
+ LPI2C_MasterClearStatusFlags(base, (uint32_t)kLPI2C_MasterClearFlags);
+
+ /* Turn off auto-stop option. */
+ base->MCFGR1 &= ~LPI2C_MCFGR1_AUTOSTOP_MASK;
+
+ lpi2c_direction_t direction = (0U != transfer->subaddressSize) ? kLPI2C_Write : transfer->direction;
+ if (0U == (transfer->flags & (uint32_t)kLPI2C_TransferNoStartFlag))
+ {
+ commandBuffer[cmdCount++] =
+ (uint16_t)kStartCmd |
+ (uint16_t)((uint16_t)((uint16_t)transfer->slaveAddress << 1U) | (uint16_t)direction);
+ }
+
+ /* Subaddress, MSB first. */
+ if (0U != transfer->subaddressSize)
+ {
+ uint32_t subaddressRemaining = transfer->subaddressSize;
+ while (0U != subaddressRemaining--)
+ {
+ uint8_t subaddressByte = (uint8_t)((transfer->subaddress >> (8U * subaddressRemaining)) & 0xffU);
+ commandBuffer[cmdCount++] = subaddressByte;
+ }
+ }
+
+ /* Reads need special handling. */
+ if ((0U != transfer->dataSize) && (transfer->direction == kLPI2C_Read))
+ {
+ /* Need to send repeated start if switching directions to read. */
+ if (direction == kLPI2C_Write)
+ {
+ commandBuffer[cmdCount++] =
+ (uint16_t)kStartCmd |
+ (uint16_t)((uint16_t)((uint16_t)transfer->slaveAddress << 1U) | (uint16_t)kLPI2C_Read);
+ }
+ }
+
+ /* Send command buffer */
+ uint32_t index = 0U;
+ while (0U != cmdCount--)
+ {
+ /* Wait until there is room in the fifo. This also checks for errors. */
+ result = LPI2C_MasterWaitForTxReady(base);
+ if (kStatus_Success != result)
+ {
+ break;
+ }
+
+ /* Write byte into LPI2C master data register. */
+ base->MTDR = commandBuffer[index];
+ index++;
+ }
+
+ if (kStatus_Success == result)
+ {
+ /* Transmit data. */
+ if ((transfer->direction == kLPI2C_Write) && (transfer->dataSize > 0U))
+ {
+ /* Send Data. */
+ result = LPI2C_MasterSend(base, transfer->data, transfer->dataSize);
+ }
+
+ /* Receive Data. */
+ if ((transfer->direction == kLPI2C_Read) && (transfer->dataSize > 0U))
+ {
+ result = LPI2C_MasterReceive(base, transfer->data, transfer->dataSize);
+ }
+
+ if (kStatus_Success == result)
+ {
+ if ((transfer->flags & (uint32_t)kLPI2C_TransferNoStopFlag) == 0U)
+ {
+ result = LPI2C_MasterStop(base);
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/*!
+ * brief Creates a new handle for the LPI2C master non-blocking APIs.
+ *
+ * The creation of a handle is for use with the non-blocking APIs. Once a handle
+ * is created, there is not a corresponding destroy handle. If the user wants to
+ * terminate a transfer, the LPI2C_MasterTransferAbort() API shall be called.
+ *
+ *
+ * note The function also enables the NVIC IRQ for the input LPI2C. Need to notice
+ * that on some SoCs the LPI2C IRQ is connected to INTMUX, in this case user needs to
+ * enable the associated INTMUX IRQ in application.
+ *
+ * param base The LPI2C peripheral base address.
+ * param[out] handle Pointer to the LPI2C master driver handle.
+ * param callback User provided pointer to the asynchronous callback function.
+ * param userData User provided pointer to the application callback data.
+ */
+void LPI2C_MasterTransferCreateHandle(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_master_transfer_callback_t callback,
+ void *userData)
+{
+ uint32_t instance;
+
+ assert(NULL != handle);
+
+ /* Clear out the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Look up instance number */
+ instance = LPI2C_GetInstance(base);
+
+ /* Save base and instance. */
+ handle->completionCallback = callback;
+ handle->userData = userData;
+
+ /* Save this handle for IRQ use. */
+ s_lpi2cMasterHandle[instance] = handle;
+
+ /* Set irq handler. */
+ s_lpi2cMasterIsr = LPI2C_MasterTransferHandleIRQ;
+
+ /* Clear internal IRQ enables and enable NVIC IRQ. */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
+
+ /* Enable NVIC IRQ, this only enables the IRQ directly connected to the NVIC.
+ In some cases the LPI2C IRQ is configured through INTMUX, user needs to enable
+ INTMUX IRQ in application code. */
+ (void)EnableIRQ(kLpi2cIrqs[instance]);
+}
+
+static void LPI2C_TransferStateMachineSendCommand(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_state_machine_param_t *stateParams)
+{
+ assert(stateParams != NULL);
+ uint16_t sendval;
+
+ /* Make sure there is room in the tx fifo for the next command. */
+ if (0U == (stateParams->txCount)--)
+ {
+ stateParams->state_complete = true;
+ return;
+ }
+
+ /* Issue command. buf is a uint8_t* pointing at the uint16 command array. */
+ sendval = ((uint16_t)handle->buf[0]) | (((uint16_t)handle->buf[1]) << 8U);
+ base->MTDR = sendval;
+ handle->buf++;
+ handle->buf++;
+
+ /* Count down until all commands are sent. */
+ if (--handle->remainingBytes == 0U)
+ {
+ /* Choose next state and set up buffer pointer and count. */
+ if (0U != handle->transfer.dataSize)
+ {
+ /* Either a send or receive transfer is next. */
+ handle->state = (uint8_t)kTransferDataState;
+ handle->buf = (uint8_t *)handle->transfer.data;
+ handle->remainingBytes = (uint16_t)handle->transfer.dataSize;
+ if (handle->transfer.direction == kLPI2C_Read)
+ {
+ /* Disable TX interrupt */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterTxReadyFlag);
+ /* Issue command to receive data. A single write to MTDR can issue read operation of
+ 0xFFU + 1 byte of data at most, so when the dataSize is larger than 0x100U, push
+ multiple read commands to MTDR until dataSize is reached. */
+ size_t tmpRxSize = handle->transfer.dataSize;
+ while (tmpRxSize != 0U)
+ {
+ LPI2C_MasterGetFifoCounts(base, NULL, &stateParams->txCount);
+ while ((size_t)FSL_FEATURE_LPI2C_FIFO_SIZEn(base) == stateParams->txCount)
+ {
+ LPI2C_MasterGetFifoCounts(base, NULL, &stateParams->txCount);
+ }
+
+ if (tmpRxSize > 256U)
+ {
+ base->MTDR = (uint32_t)(kRxDataCmd) | (uint32_t)LPI2C_MTDR_DATA(0xFFU);
+ tmpRxSize -= 256U;
+ }
+ else
+ {
+ base->MTDR = (uint32_t)(kRxDataCmd) | (uint32_t)LPI2C_MTDR_DATA(tmpRxSize - 1U);
+ tmpRxSize = 0U;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* No transfer, so move to stop state. */
+ handle->state = (uint8_t)kStopState;
+ }
+ }
+}
+
+static void LPI2C_TransferStateMachineReadCommand(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_state_machine_param_t *stateParams)
+{
+ assert(stateParams != NULL);
+
+ /* Make sure there is room in the tx fifo for the read command. */
+ if (0U == (stateParams->txCount)--)
+ {
+ stateParams->state_complete = true;
+ return;
+ }
+
+ base->MTDR = (uint32_t)kRxDataCmd | LPI2C_MTDR_DATA(handle->transfer.dataSize - 1U);
+
+ /* Move to transfer state. */
+ handle->state = (uint8_t)kTransferDataState;
+ if (handle->transfer.direction == kLPI2C_Read)
+ {
+ /* Disable TX interrupt */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterTxReadyFlag);
+ }
+}
+
+static void LPI2C_TransferStateMachineTransferData(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_state_machine_param_t *stateParams)
+{
+ assert(stateParams != NULL);
+
+ if (handle->transfer.direction == kLPI2C_Write)
+ {
+ /* Make sure there is room in the tx fifo. */
+ if (0U == stateParams->txCount--)
+ {
+ stateParams->state_complete = true;
+ return;
+ }
+
+ /* Put byte to send in fifo. */
+ base->MTDR = *(handle->buf)++;
+ }
+ else
+ {
+ /* XXX handle receive sizes > 256, use kIssueReadCommandState */
+ /* Make sure there is data in the rx fifo. */
+ if (0U == stateParams->rxCount--)
+ {
+ stateParams->state_complete = true;
+ return;
+ }
+
+ /* Read byte from fifo. */
+ *(handle->buf)++ = (uint8_t)(base->MRDR & LPI2C_MRDR_DATA_MASK);
+ }
+
+ /* Move to stop when the transfer is done. */
+ if (--handle->remainingBytes == 0U)
+ {
+ if (handle->transfer.direction == kLPI2C_Write)
+ {
+ stateParams->state_complete = true;
+ }
+ handle->state = (uint8_t)kStopState;
+ }
+}
+
+static void LPI2C_TransferStateMachineStopState(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_state_machine_param_t *stateParams,
+ bool *isDone)
+{
+ assert(stateParams != NULL);
+
+ /* Only issue a stop transition if the caller requested it. */
+ if ((handle->transfer.flags & (uint32_t)kLPI2C_TransferNoStopFlag) == 0U)
+ {
+ /* Make sure there is room in the tx fifo for the stop command. */
+ if (0U == (stateParams->txCount)--)
+ {
+ stateParams->state_complete = true;
+ return;
+ }
+
+ base->MTDR = (uint32_t)kStopCmd;
+ }
+ else
+ {
+ /* If all data is read and no stop flag is required to send, we are done. */
+ if (handle->transfer.direction == kLPI2C_Read)
+ {
+ *isDone = true;
+ }
+ stateParams->state_complete = true;
+ }
+ handle->state = (uint8_t)kWaitForCompletionState;
+}
+
+static void LPI2C_TransferStateMachineWaitState(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_state_machine_param_t *stateParams,
+ bool *isDone)
+{
+ assert(stateParams != NULL);
+
+ if ((handle->transfer.flags & (uint32_t)kLPI2C_TransferNoStopFlag) == 0U)
+ {
+ /* We stay in this state until the stop state is detected. */
+ if (0U != ((stateParams->status) & (uint32_t)kLPI2C_MasterStopDetectFlag))
+ {
+ *isDone = true;
+ }
+ }
+ else
+ {
+ /* If all data is pushed to FIFO and no stop flag is required to send, we need to make sure they
+ are all send out to bus. */
+ if ((handle->transfer.direction == kLPI2C_Write) && ((base->MFSR & LPI2C_MFSR_TXCOUNT_MASK) == 0U))
+ {
+ /* We stay in this state until the data is sent out to bus. */
+ *isDone = true;
+ }
+ }
+ stateParams->state_complete = true;
+}
+
+/*!
+ * @brief Execute states until FIFOs are exhausted.
+ * @param handle Master nonblocking driver handle.
+ * @param[out] isDone Set to true if the transfer has completed.
+ * @retval #kStatus_Success
+ * @retval #kStatus_LPI2C_PinLowTimeout
+ * @retval #kStatus_LPI2C_ArbitrationLost
+ * @retval #kStatus_LPI2C_Nak
+ * @retval #kStatus_LPI2C_FifoError
+ */
+static status_t LPI2C_RunTransferStateMachine(LPI2C_Type *base, lpi2c_master_handle_t *handle, bool *isDone)
+{
+ assert(NULL != base && NULL != handle && NULL != isDone);
+
+ status_t result = kStatus_Success;
+ lpi2c_state_machine_param_t stateParams;
+ (void)memset(&stateParams, 0, sizeof(stateParams));
+
+ stateParams.state_complete = false;
+
+ /* Set default isDone return value. */
+ *isDone = false;
+
+ /* Check for errors. */
+ stateParams.status = LPI2C_MasterGetStatusFlags(base);
+
+ /* Get fifo counts. */
+ LPI2C_MasterGetFifoCounts(base, &stateParams.rxCount, &stateParams.txCount);
+
+ /* For the last byte, nack flag is expected.
+ Do not check and clear kLPI2C_MasterNackDetectFlag for the last byte,
+ in case FIFO is emptied when stop command has not been sent. */
+ if (handle->remainingBytes == 0U)
+ {
+ /* When data size is not zero which means it is not only one byte of address is sent, and */
+ /* when the txfifo is empty, or have one byte which is the stop command, then the nack status can be ignored. */
+ if (((handle->transfer).dataSize != 0U) &&
+ ((stateParams.txCount == 0U) ||
+ (((stateParams.txCount) == 1U) && (handle->state == (uint8_t)kWaitForCompletionState) &&
+ (((handle->transfer).flags & (uint32_t)kLPI2C_TransferNoStopFlag) == 0U))))
+ {
+ (stateParams.status) &= ~(uint32_t)kLPI2C_MasterNackDetectFlag;
+ }
+ }
+
+ result = LPI2C_MasterCheckAndClearError(base, stateParams.status);
+
+ if (kStatus_Success == result)
+ {
+ /* Compute room in tx fifo */
+ stateParams.txCount = (size_t)FSL_FEATURE_LPI2C_FIFO_SIZEn(base) - stateParams.txCount;
+
+ while (!stateParams.state_complete)
+ {
+ /* Execute the state. */
+ switch (handle->state)
+ {
+ case (uint8_t)kSendCommandState:
+ LPI2C_TransferStateMachineSendCommand(base, handle, &stateParams);
+ break;
+
+ case (uint8_t)kIssueReadCommandState:
+ LPI2C_TransferStateMachineReadCommand(base, handle, &stateParams);
+ break;
+
+ case (uint8_t)kTransferDataState:
+ LPI2C_TransferStateMachineTransferData(base, handle, &stateParams);
+ break;
+
+ case (uint8_t)kStopState:
+ LPI2C_TransferStateMachineStopState(base, handle, &stateParams, isDone);
+ break;
+
+ case (uint8_t)kWaitForCompletionState:
+ LPI2C_TransferStateMachineWaitState(base, handle, &stateParams, isDone);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+/*!
+ * @brief Prepares the transfer state machine and fills in the command buffer.
+ * @param handle Master nonblocking driver handle.
+ */
+static void LPI2C_InitTransferStateMachine(lpi2c_master_handle_t *handle)
+{
+ lpi2c_master_transfer_t *xfer = &handle->transfer;
+
+ /* Handle no start option. */
+ if (0U != (xfer->flags & (uint32_t)kLPI2C_TransferNoStartFlag))
+ {
+ if (xfer->direction == kLPI2C_Read)
+ {
+ /* Need to issue read command first. */
+ handle->state = (uint8_t)kIssueReadCommandState;
+ }
+ else
+ {
+ /* Start immediately in the data transfer state. */
+ handle->state = (uint8_t)kTransferDataState;
+ }
+
+ handle->buf = (uint8_t *)xfer->data;
+ handle->remainingBytes = (uint16_t)xfer->dataSize;
+ }
+ else
+ {
+ uint16_t *cmd = (uint16_t *)&handle->commandBuffer;
+ uint32_t cmdCount = 0U;
+
+ /* Initial direction depends on whether a subaddress was provided, and of course the actual */
+ /* data transfer direction. */
+ lpi2c_direction_t direction = (0U != xfer->subaddressSize) ? kLPI2C_Write : xfer->direction;
+
+ /* Start command. */
+ cmd[cmdCount++] =
+ (uint16_t)kStartCmd | (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)direction);
+
+ /* Subaddress, MSB first. */
+ if (0U != xfer->subaddressSize)
+ {
+ uint32_t subaddressRemaining = xfer->subaddressSize;
+ while (0U != (subaddressRemaining--))
+ {
+ uint8_t subaddressByte = (uint8_t)((xfer->subaddress >> (8U * subaddressRemaining)) & 0xffU);
+ cmd[cmdCount++] = subaddressByte;
+ }
+ }
+
+ /* Reads need special handling. */
+ if ((0U != xfer->dataSize) && (xfer->direction == kLPI2C_Read))
+ {
+ /* Need to send repeated start if switching directions to read. */
+ if (direction == kLPI2C_Write)
+ {
+ cmd[cmdCount++] = (uint16_t)kStartCmd |
+ (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)kLPI2C_Read);
+ }
+ }
+
+ /* Set up state machine for transferring the commands. */
+ handle->state = (uint8_t)kSendCommandState;
+ handle->remainingBytes = (uint16_t)cmdCount;
+ handle->buf = (uint8_t *)&handle->commandBuffer;
+ }
+}
+
+/*!
+ * brief Performs a non-blocking transaction on the I2C bus.
+ *
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to the LPI2C master driver handle.
+ * param transfer The pointer to the transfer descriptor.
+ * retval #kStatus_Success The transaction was started successfully.
+ * retval #kStatus_LPI2C_Busy Either another master is currently utilizing the bus, or a non-blocking
+ * transaction is already in progress.
+ */
+status_t LPI2C_MasterTransferNonBlocking(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_master_transfer_t *transfer)
+{
+ assert(NULL != handle);
+ assert(NULL != transfer);
+ assert(transfer->subaddressSize <= sizeof(transfer->subaddress));
+
+ status_t result;
+
+ /* Check transfer data size in read operation. */
+ if ((transfer->direction == kLPI2C_Read) &&
+ (transfer->dataSize > (256U * (uint32_t)FSL_FEATURE_LPI2C_FIFO_SIZEn(base))))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Return busy if another transaction is in progress. */
+ if (handle->state != (uint8_t)kIdleState)
+ {
+ result = kStatus_LPI2C_Busy;
+ }
+ else
+ {
+ result = LPI2C_CheckForBusyBus(base);
+ }
+
+ if ((status_t)kStatus_Success == result)
+ {
+ /* Enable the master function and disable the slave function. */
+ LPI2C_MasterEnable(base, true);
+ LPI2C_SlaveEnable(base, false);
+
+ /* Disable LPI2C IRQ sources while we configure stuff. */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
+
+ /* Reset FIFO in case there are data. */
+ base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
+
+ /* Save transfer into handle. */
+ handle->transfer = *transfer;
+
+ /* Generate commands to send. */
+ LPI2C_InitTransferStateMachine(handle);
+
+ /* Clear all flags. */
+ LPI2C_MasterClearStatusFlags(base, (uint32_t)kLPI2C_MasterClearFlags);
+
+ /* Turn off auto-stop option. */
+ base->MCFGR1 &= ~LPI2C_MCFGR1_AUTOSTOP_MASK;
+
+ /* Enable LPI2C internal IRQ sources. NVIC IRQ was enabled in CreateHandle() */
+ LPI2C_MasterEnableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
+ }
+
+ return result;
+}
+
+/*!
+ * brief Returns number of bytes transferred so far.
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to the LPI2C master driver handle.
+ * param[out] count Number of bytes transferred so far by the non-blocking transaction.
+ * retval #kStatus_Success
+ * retval #kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t LPI2C_MasterTransferGetCount(LPI2C_Type *base, lpi2c_master_handle_t *handle, size_t *count)
+{
+ status_t result = kStatus_Success;
+
+ assert(NULL != handle);
+
+ if (NULL == count)
+ {
+ result = kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ else if (handle->state == (uint8_t)kIdleState)
+ {
+ *count = 0;
+ result = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ uint8_t state;
+ uint16_t remainingBytes;
+ uint32_t dataSize;
+
+ /* Cache some fields with IRQs disabled. This ensures all field values */
+ /* are synchronized with each other during an ongoing transfer. */
+ uint32_t irqs = LPI2C_MasterGetEnabledInterrupts(base);
+ LPI2C_MasterDisableInterrupts(base, irqs);
+ state = handle->state;
+ remainingBytes = handle->remainingBytes;
+ dataSize = handle->transfer.dataSize;
+ LPI2C_MasterEnableInterrupts(base, irqs);
+
+ /* Get transfer count based on current transfer state. */
+ switch (state)
+ {
+ case (uint8_t)kIdleState:
+ case (uint8_t)kSendCommandState:
+ case (uint8_t)
+ kIssueReadCommandState: /* XXX return correct value for this state when >256 reads are supported */
+ *count = 0;
+ break;
+
+ case (uint8_t)kTransferDataState:
+ *count = dataSize - remainingBytes;
+ break;
+
+ case (uint8_t)kStopState:
+ case (uint8_t)kWaitForCompletionState:
+ default:
+ *count = dataSize;
+ break;
+ }
+ }
+
+ return result;
+}
+
+/*!
+ * brief Terminates a non-blocking LPI2C master transmission early.
+ *
+ * note It is not safe to call this function from an IRQ handler that has a higher priority than the
+ * LPI2C peripheral's IRQ priority.
+ *
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to the LPI2C master driver handle.
+ * retval #kStatus_Success A transaction was successfully aborted.
+ * retval #kStatus_LPI2C_Idle There is not a non-blocking transaction currently in progress.
+ */
+void LPI2C_MasterTransferAbort(LPI2C_Type *base, lpi2c_master_handle_t *handle)
+{
+ if (handle->state != (uint8_t)kIdleState)
+ {
+ /* Disable internal IRQ enables. */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
+
+ /* Reset fifos. */
+ base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
+
+ /* If master is still busy and has not send out stop signal yet. */
+ if ((LPI2C_MasterGetStatusFlags(base) & ((uint32_t)kLPI2C_MasterStopDetectFlag |
+ (uint32_t)kLPI2C_MasterBusyFlag)) == (uint32_t)kLPI2C_MasterBusyFlag)
+ {
+ /* Send a stop command to finalize the transfer. */
+ base->MTDR = (uint32_t)kStopCmd;
+ }
+
+ /* Reset handle. */
+ handle->state = (uint8_t)kIdleState;
+ }
+}
+
+/*!
+ * brief Reusable routine to handle master interrupts.
+ * note This function does not need to be called unless you are reimplementing the
+ * nonblocking API's interrupt handler routines to add special functionality.
+ * param base The LPI2C peripheral base address.
+ * param lpi2cMasterHandle Pointer to the LPI2C master driver handle.
+ */
+void LPI2C_MasterTransferHandleIRQ(LPI2C_Type *base, void *lpi2cMasterHandle)
+{
+ assert(lpi2cMasterHandle != NULL);
+
+ lpi2c_master_handle_t *handle = (lpi2c_master_handle_t *)lpi2cMasterHandle;
+ bool isDone = false;
+ status_t result;
+
+ /* Don't do anything if we don't have a valid handle. */
+ if (NULL != handle)
+ {
+ if (handle->state != (uint8_t)kIdleState)
+ {
+ result = LPI2C_RunTransferStateMachine(base, handle, &isDone);
+
+ if ((result != kStatus_Success) || isDone)
+ {
+ /* Handle error, terminate xfer */
+ if (result != kStatus_Success)
+ {
+ LPI2C_MasterTransferAbort(base, handle);
+ }
+
+ /* Disable internal IRQ enables. */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
+
+ /* Set handle to idle state. */
+ handle->state = (uint8_t)kIdleState;
+
+ /* Invoke callback. */
+ if (NULL != handle->completionCallback)
+ {
+ handle->completionCallback(base, handle, result, handle->userData);
+ }
+ }
+ }
+ }
+}
+
+/*!
+ * brief Provides a default configuration for the LPI2C slave peripheral.
+ *
+ * This function provides the following default configuration for the LPI2C slave peripheral:
+ * code
+ * slaveConfig->enableSlave = true;
+ * slaveConfig->address0 = 0U;
+ * slaveConfig->address1 = 0U;
+ * slaveConfig->addressMatchMode = kLPI2C_MatchAddress0;
+ * slaveConfig->filterDozeEnable = true;
+ * slaveConfig->filterEnable = true;
+ * slaveConfig->enableGeneralCall = false;
+ * slaveConfig->sclStall.enableAck = false;
+ * slaveConfig->sclStall.enableTx = true;
+ * slaveConfig->sclStall.enableRx = true;
+ * slaveConfig->sclStall.enableAddress = true;
+ * slaveConfig->ignoreAck = false;
+ * slaveConfig->enableReceivedAddressRead = false;
+ * slaveConfig->sdaGlitchFilterWidth_ns = 0;
+ * slaveConfig->sclGlitchFilterWidth_ns = 0;
+ * slaveConfig->dataValidDelay_ns = 0;
+ * slaveConfig->clockHoldTime_ns = 0;
+ * endcode
+ *
+ * After calling this function, override any settings to customize the configuration,
+ * prior to initializing the master driver with LPI2C_SlaveInit(). Be sure to override at least the a
+ * address0 member of the configuration structure with the desired slave address.
+ *
+ * param[out] slaveConfig User provided configuration structure that is set to default values. Refer to
+ * #lpi2c_slave_config_t.
+ */
+void LPI2C_SlaveGetDefaultConfig(lpi2c_slave_config_t *slaveConfig)
+{
+ /* Initializes the configure structure to zero. */
+ (void)memset(slaveConfig, 0, sizeof(*slaveConfig));
+
+ slaveConfig->enableSlave = true;
+ slaveConfig->address0 = 0U;
+ slaveConfig->address1 = 0U;
+ slaveConfig->addressMatchMode = kLPI2C_MatchAddress0;
+ slaveConfig->filterDozeEnable = true;
+ slaveConfig->filterEnable = true;
+ slaveConfig->enableGeneralCall = false;
+ slaveConfig->sclStall.enableAck = false;
+ slaveConfig->sclStall.enableTx = true;
+ slaveConfig->sclStall.enableRx = true;
+ slaveConfig->sclStall.enableAddress = false;
+ slaveConfig->ignoreAck = false;
+ slaveConfig->enableReceivedAddressRead = false;
+ slaveConfig->sdaGlitchFilterWidth_ns = 0U; /* Set to 0 to disable the function */
+ slaveConfig->sclGlitchFilterWidth_ns = 0U; /* Set to 0 to disable the function */
+ slaveConfig->dataValidDelay_ns = 0U;
+ /* When enabling the slave tx SCL stall, set the default clock hold time to 250ns according
+ to I2C spec for standard mode baudrate(100k). User can manually change it to 100ns or 50ns
+ for fast-mode(400k) or fast-mode+(1m). */
+ slaveConfig->clockHoldTime_ns = 250U;
+}
+
+/*!
+ * brief Initializes the LPI2C slave peripheral.
+ *
+ * This function enables the peripheral clock and initializes the LPI2C slave peripheral as described by the user
+ * provided configuration.
+ *
+ * param base The LPI2C peripheral base address.
+ * param slaveConfig User provided peripheral configuration. Use LPI2C_SlaveGetDefaultConfig() to get a set of defaults
+ * that you can override.
+ * param sourceClock_Hz Frequency in Hertz of the LPI2C functional clock. Used to calculate the filter widths,
+ * data valid delay, and clock hold time.
+ */
+void LPI2C_SlaveInit(LPI2C_Type *base, const lpi2c_slave_config_t *slaveConfig, uint32_t sourceClock_Hz)
+{
+ uint32_t tmpReg;
+ uint32_t tmpCycle;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+
+ uint32_t instance = LPI2C_GetInstance(base);
+
+ /* Ungate the clock. */
+ (void)CLOCK_EnableClock(kLpi2cClocks[instance]);
+#if defined(LPI2C_PERIPH_CLOCKS)
+ /* Ungate the functional clock in initialize function. */
+ CLOCK_EnableClock(kLpi2cPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Restore to reset conditions. */
+ LPI2C_SlaveReset(base);
+
+ /* Configure peripheral. */
+ base->SAMR = LPI2C_SAMR_ADDR0(slaveConfig->address0) | LPI2C_SAMR_ADDR1(slaveConfig->address1);
+
+ base->SCFGR1 =
+ LPI2C_SCFGR1_ADDRCFG(slaveConfig->addressMatchMode) | LPI2C_SCFGR1_IGNACK(slaveConfig->ignoreAck) |
+ LPI2C_SCFGR1_RXCFG(slaveConfig->enableReceivedAddressRead) | LPI2C_SCFGR1_GCEN(slaveConfig->enableGeneralCall) |
+ LPI2C_SCFGR1_ACKSTALL(slaveConfig->sclStall.enableAck) | LPI2C_SCFGR1_TXDSTALL(slaveConfig->sclStall.enableTx) |
+ LPI2C_SCFGR1_RXSTALL(slaveConfig->sclStall.enableRx) |
+ LPI2C_SCFGR1_ADRSTALL(slaveConfig->sclStall.enableAddress);
+
+ /* Calculate SDA filter width. The width is equal to FILTSDA+3 cycles of functional clock.
+ And set FILTSDA to 0 disables the fileter, so the min value is 4. */
+ tmpReg = LPI2C_SCFGR2_FILTSDA(
+ LPI2C_GetCyclesForWidth(sourceClock_Hz, slaveConfig->sdaGlitchFilterWidth_ns, 4U,
+ (LPI2C_SCFGR2_FILTSDA_MASK >> LPI2C_SCFGR2_FILTSDA_SHIFT) + 3U, 0U) -
+ 3U);
+
+ /* Calculate SDL filter width. The width is equal to FILTSCL+3 cycles of functional clock.
+ And set FILTSCL to 0 disables the fileter, so the min value is 4. */
+ tmpCycle = LPI2C_GetCyclesForWidth(sourceClock_Hz, slaveConfig->sclGlitchFilterWidth_ns, 4U,
+ (LPI2C_SCFGR2_FILTSCL_MASK >> LPI2C_SCFGR2_FILTSCL_SHIFT) + 3U, 0U);
+ tmpReg |= LPI2C_SCFGR2_FILTSCL(tmpCycle - 3U);
+
+ /* Calculate data valid time. The time is equal to FILTSCL+DATAVD+3 cycles of functional clock.
+ So the min value is FILTSCL+3. */
+ tmpReg |= LPI2C_SCFGR2_DATAVD(
+ LPI2C_GetCyclesForWidth(sourceClock_Hz, slaveConfig->dataValidDelay_ns, tmpCycle,
+ tmpCycle + (LPI2C_SCFGR2_DATAVD_MASK >> LPI2C_SCFGR2_DATAVD_SHIFT), 0U) -
+ tmpCycle);
+
+ /* Calculate clock hold time. The time is equal to CLKHOLD+3 cycles of functional clock.
+ So the min value is 3. */
+ base->SCFGR2 =
+ tmpReg | LPI2C_SCFGR2_CLKHOLD(
+ LPI2C_GetCyclesForWidth(sourceClock_Hz, slaveConfig->clockHoldTime_ns, 3U,
+ (LPI2C_SCFGR2_CLKHOLD_MASK >> LPI2C_SCFGR2_CLKHOLD_SHIFT) + 3U, 0U) -
+ 3U);
+
+ /* Save SCR to last so we don't enable slave until it is configured */
+ base->SCR = LPI2C_SCR_FILTDZ(!slaveConfig->filterDozeEnable) | LPI2C_SCR_FILTEN(slaveConfig->filterEnable) |
+ LPI2C_SCR_SEN(slaveConfig->enableSlave);
+}
+
+/*!
+ * brief Deinitializes the LPI2C slave peripheral.
+ *
+ * This function disables the LPI2C slave peripheral and gates the clock. It also performs a software
+ * reset to restore the peripheral to reset conditions.
+ *
+ * param base The LPI2C peripheral base address.
+ */
+void LPI2C_SlaveDeinit(LPI2C_Type *base)
+{
+ LPI2C_SlaveReset(base);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+
+ uint32_t instance = LPI2C_GetInstance(base);
+
+ /* Gate the clock. */
+ (void)CLOCK_DisableClock(kLpi2cClocks[instance]);
+
+#if defined(LPI2C_PERIPH_CLOCKS)
+ /* Gate the functional clock. */
+ CLOCK_DisableClock(kLpi2cPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * @brief Convert provided flags to status code, and clear any errors if present.
+ * @param base The LPI2C peripheral base address.
+ * @param status Current status flags value that will be checked.
+ * @retval #kStatus_Success
+ * @retval #kStatus_LPI2C_BitError
+ * @retval #kStatus_LPI2C_FifoError
+ */
+static status_t LPI2C_SlaveCheckAndClearError(LPI2C_Type *base, uint32_t flags)
+{
+ status_t result = kStatus_Success;
+
+ flags &= (uint32_t)kLPI2C_SlaveErrorFlags;
+ if (0U != flags)
+ {
+ if (0U != (flags & (uint32_t)kLPI2C_SlaveBitErrFlag))
+ {
+ result = kStatus_LPI2C_BitError;
+ }
+ else if (0U != (flags & (uint32_t)kLPI2C_SlaveFifoErrFlag))
+ {
+ result = kStatus_LPI2C_FifoError;
+ }
+ else
+ {
+ ; /* Intentional empty */
+ }
+
+ /* Clear the errors. */
+ LPI2C_SlaveClearStatusFlags(base, flags);
+ }
+ else
+ {
+ ; /* Intentional empty */
+ }
+
+ return result;
+}
+
+/*!
+ * brief Performs a polling send transfer on the I2C bus.
+ *
+ * param base The LPI2C peripheral base address.
+ * param txBuff The pointer to the data to be transferred.
+ * param txSize The length in bytes of the data to be transferred.
+ * param[out] actualTxSize
+ * return Error or success status returned by API.
+ */
+status_t LPI2C_SlaveSend(LPI2C_Type *base, void *txBuff, size_t txSize, size_t *actualTxSize)
+{
+ status_t result = kStatus_Success;
+ uint8_t *buf = (uint8_t *)txBuff;
+ size_t remaining = txSize;
+
+ assert(NULL != txBuff);
+
+#if I2C_RETRY_TIMES != 0U
+ uint32_t waitTimes = I2C_RETRY_TIMES;
+#endif
+
+ /* Clear stop flag. */
+ LPI2C_SlaveClearStatusFlags(base,
+ (uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag);
+
+ while (0U != remaining)
+ {
+ uint32_t flags;
+
+ /* Wait until we can transmit. */
+ do
+ {
+ /* Check for errors */
+ flags = LPI2C_SlaveGetStatusFlags(base);
+ result = LPI2C_SlaveCheckAndClearError(base, flags);
+ if (kStatus_Success != result)
+ {
+ if (NULL != actualTxSize)
+ {
+ *actualTxSize = txSize - remaining;
+ }
+ break;
+ }
+#if I2C_RETRY_TIMES != 0U
+ waitTimes--;
+ } while ((0U == (flags & ((uint32_t)kLPI2C_SlaveTxReadyFlag | (uint32_t)kLPI2C_SlaveStopDetectFlag |
+ (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag))) &&
+ (0U != waitTimes));
+ if (0U == waitTimes)
+ {
+ result = kStatus_LPI2C_Timeout;
+ }
+#else
+ } while (0U == (flags & ((uint32_t)kLPI2C_SlaveTxReadyFlag | (uint32_t)kLPI2C_SlaveStopDetectFlag |
+ (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag)));
+#endif
+
+ if (kStatus_Success != result)
+ {
+ break;
+ }
+
+ /* Send a byte. */
+ if (0U != (flags & (uint32_t)kLPI2C_SlaveTxReadyFlag))
+ {
+ base->STDR = *buf++;
+ --remaining;
+ }
+
+ /* Exit loop if we see a stop or restart in transfer*/
+ if ((0U != (flags & ((uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag))) &&
+ (remaining != 0U))
+ {
+ LPI2C_SlaveClearStatusFlags(
+ base, (uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag);
+ break;
+ }
+ }
+
+ if (NULL != actualTxSize)
+ {
+ *actualTxSize = txSize - remaining;
+ }
+
+ return result;
+}
+
+/*!
+ * brief Performs a polling receive transfer on the I2C bus.
+ *
+ * param base The LPI2C peripheral base address.
+ * param rxBuff The pointer to the data to be transferred.
+ * param rxSize The length in bytes of the data to be transferred.
+ * param[out] actualRxSize
+ * return Error or success status returned by API.
+ */
+status_t LPI2C_SlaveReceive(LPI2C_Type *base, void *rxBuff, size_t rxSize, size_t *actualRxSize)
+{
+ status_t result = kStatus_Success;
+ uint8_t *buf = (uint8_t *)rxBuff;
+ size_t remaining = rxSize;
+
+ assert(NULL != rxBuff);
+
+#if I2C_RETRY_TIMES != 0U
+ uint32_t waitTimes = I2C_RETRY_TIMES;
+#endif
+
+ /* Clear stop flag. */
+ LPI2C_SlaveClearStatusFlags(base,
+ (uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag);
+
+ while (0U != remaining)
+ {
+ uint32_t flags;
+
+ /* Wait until we can receive. */
+ do
+ {
+ /* Check for errors */
+ flags = LPI2C_SlaveGetStatusFlags(base);
+ result = LPI2C_SlaveCheckAndClearError(base, flags);
+ if (kStatus_Success != result)
+ {
+ if (NULL != actualRxSize)
+ {
+ *actualRxSize = rxSize - remaining;
+ }
+ break;
+ }
+#if I2C_RETRY_TIMES != 0U
+ waitTimes--;
+ } while ((0U == (flags & ((uint32_t)kLPI2C_SlaveRxReadyFlag | (uint32_t)kLPI2C_SlaveStopDetectFlag |
+ (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag))) &&
+ (0U != waitTimes));
+ if (0U == waitTimes)
+ {
+ result = kStatus_LPI2C_Timeout;
+ }
+#else
+ } while (0U == (flags & ((uint32_t)kLPI2C_SlaveRxReadyFlag | (uint32_t)kLPI2C_SlaveStopDetectFlag |
+ (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag)));
+#endif
+
+ if ((status_t)kStatus_Success != result)
+ {
+ break;
+ }
+
+ /* Receive a byte. */
+ if (0U != (flags & (uint32_t)kLPI2C_SlaveRxReadyFlag))
+ {
+ *buf++ = (uint8_t)(base->SRDR & LPI2C_SRDR_DATA_MASK);
+ --remaining;
+ }
+
+ /* Exit loop if we see a stop or restart */
+ if ((0U != (flags & ((uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag))) &&
+ (remaining != 0U))
+ {
+ LPI2C_SlaveClearStatusFlags(
+ base, (uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag);
+ break;
+ }
+ }
+
+ if (NULL != actualRxSize)
+ {
+ *actualRxSize = rxSize - remaining;
+ }
+
+ return result;
+}
+
+/*!
+ * brief Creates a new handle for the LPI2C slave non-blocking APIs.
+ *
+ * The creation of a handle is for use with the non-blocking APIs. Once a handle
+ * is created, there is not a corresponding destroy handle. If the user wants to
+ * terminate a transfer, the LPI2C_SlaveTransferAbort() API shall be called.
+ *
+ * note The function also enables the NVIC IRQ for the input LPI2C. Need to notice
+ * that on some SoCs the LPI2C IRQ is connected to INTMUX, in this case user needs to
+ * enable the associated INTMUX IRQ in application.
+
+ * param base The LPI2C peripheral base address.
+ * param[out] handle Pointer to the LPI2C slave driver handle.
+ * param callback User provided pointer to the asynchronous callback function.
+ * param userData User provided pointer to the application callback data.
+ */
+void LPI2C_SlaveTransferCreateHandle(LPI2C_Type *base,
+ lpi2c_slave_handle_t *handle,
+ lpi2c_slave_transfer_callback_t callback,
+ void *userData)
+{
+ uint32_t instance;
+
+ assert(NULL != handle);
+
+ /* Clear out the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Look up instance number */
+ instance = LPI2C_GetInstance(base);
+
+ /* Save base and instance. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Save this handle for IRQ use. */
+ s_lpi2cSlaveHandle[instance] = handle;
+
+ /* Set irq handler. */
+ s_lpi2cSlaveIsr = LPI2C_SlaveTransferHandleIRQ;
+
+ /* Clear internal IRQ enables and enable NVIC IRQ. */
+ LPI2C_SlaveDisableInterrupts(base, (uint32_t)kLPI2C_SlaveIrqFlags);
+ (void)EnableIRQ(kLpi2cIrqs[instance]);
+
+ /* Nack by default. */
+ base->STAR = LPI2C_STAR_TXNACK_MASK;
+}
+
+/*!
+ * brief Starts accepting slave transfers.
+ *
+ * Call this API after calling I2C_SlaveInit() and LPI2C_SlaveTransferCreateHandle() to start processing
+ * transactions driven by an I2C master. The slave monitors the I2C bus and pass events to the
+ * callback that was passed into the call to LPI2C_SlaveTransferCreateHandle(). The callback is always invoked
+ * from the interrupt context.
+ *
+ * The set of events received by the callback is customizable. To do so, set the a eventMask parameter to
+ * the OR'd combination of #lpi2c_slave_transfer_event_t enumerators for the events you wish to receive.
+ * The #kLPI2C_SlaveTransmitEvent and #kLPI2C_SlaveReceiveEvent events are always enabled and do not need
+ * to be included in the mask. Alternatively, you can pass 0 to get a default set of only the transmit and
+ * receive events that are always enabled. In addition, the #kLPI2C_SlaveAllEvents constant is provided as
+ * a convenient way to enable all events.
+ *
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to #lpi2c_slave_handle_t structure which stores the transfer state.
+ * param eventMask Bit mask formed by OR'ing together #lpi2c_slave_transfer_event_t enumerators to specify
+ * which events to send to the callback. Other accepted values are 0 to get a default set of
+ * only the transmit and receive events, and #kLPI2C_SlaveAllEvents to enable all events.
+ *
+ * retval #kStatus_Success Slave transfers were successfully started.
+ * retval #kStatus_LPI2C_Busy Slave transfers have already been started on this handle.
+ */
+status_t LPI2C_SlaveTransferNonBlocking(LPI2C_Type *base, lpi2c_slave_handle_t *handle, uint32_t eventMask)
+{
+ status_t result = kStatus_Success;
+
+ assert(NULL != handle);
+
+ /* Return busy if another transaction is in progress. */
+ if (handle->isBusy)
+ {
+ result = kStatus_LPI2C_Busy;
+ }
+ else
+ {
+ /* Enable the slave function and disable the master function. */
+ LPI2C_MasterEnable(base, false);
+ LPI2C_SlaveEnable(base, true);
+ /* Return an error if the bus is already in use not by us. */
+ uint32_t status = LPI2C_SlaveGetStatusFlags(base);
+ if ((0U != (status & (uint32_t)kLPI2C_SlaveBusBusyFlag)) && (0U == (status & (uint32_t)kLPI2C_SlaveBusyFlag)))
+ {
+ result = kStatus_LPI2C_Busy;
+ }
+ }
+
+ if ((status_t)kStatus_Success == result)
+ {
+ /* Disable LPI2C IRQ sources while we configure stuff. */
+ LPI2C_SlaveDisableInterrupts(base, (uint32_t)kLPI2C_SlaveIrqFlags);
+
+ /* Clear transfer in handle. */
+ (void)memset(&handle->transfer, 0, sizeof(handle->transfer));
+
+ /* Record that we're busy. */
+ handle->isBusy = true;
+
+ /* Set up event mask. tx and rx are always enabled. */
+ handle->eventMask = eventMask | (uint32_t)kLPI2C_SlaveTransmitEvent | (uint32_t)kLPI2C_SlaveReceiveEvent;
+
+ /* Ack by default. */
+ base->STAR = 0U;
+
+ /* Clear all flags. */
+ LPI2C_SlaveClearStatusFlags(base, (uint32_t)kLPI2C_SlaveClearFlags);
+
+ /* Enable LPI2C internal IRQ sources. NVIC IRQ was enabled in CreateHandle() */
+ LPI2C_SlaveEnableInterrupts(base, (uint32_t)kLPI2C_SlaveIrqFlags);
+ }
+
+ return result;
+}
+
+/*!
+ * brief Gets the slave transfer status during a non-blocking transfer.
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to i2c_slave_handle_t structure.
+ * param[out] count Pointer to a value to hold the number of bytes transferred. May be NULL if the count is not
+ * required.
+ * retval #kStatus_Success
+ * retval #kStatus_NoTransferInProgress
+ */
+status_t LPI2C_SlaveTransferGetCount(LPI2C_Type *base, lpi2c_slave_handle_t *handle, size_t *count)
+{
+ status_t status = kStatus_Success;
+
+ assert(NULL != handle);
+
+ if (count == NULL)
+ {
+ status = kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ else if (!handle->isBusy)
+ {
+ *count = 0;
+ status = kStatus_NoTransferInProgress;
+ }
+
+ /* For an active transfer, just return the count from the handle. */
+ else
+ {
+ *count = handle->transferredCount;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Aborts the slave non-blocking transfers.
+ * note This API could be called at any time to stop slave for handling the bus events.
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to #lpi2c_slave_handle_t structure which stores the transfer state.
+ * retval #kStatus_Success
+ * retval #kStatus_LPI2C_Idle
+ */
+void LPI2C_SlaveTransferAbort(LPI2C_Type *base, lpi2c_slave_handle_t *handle)
+{
+ assert(NULL != handle);
+
+ /* Return idle if no transaction is in progress. */
+ if (handle->isBusy)
+ {
+ /* Disable LPI2C IRQ sources. */
+ LPI2C_SlaveDisableInterrupts(base, (uint32_t)kLPI2C_SlaveIrqFlags);
+
+ /* Nack by default. */
+ base->STAR = LPI2C_STAR_TXNACK_MASK;
+
+ /* Reset transfer info. */
+ (void)memset(&handle->transfer, 0, sizeof(handle->transfer));
+
+ /* We're no longer busy. */
+ handle->isBusy = false;
+ }
+}
+
+/*!
+ * brief Reusable routine to handle slave interrupts.
+ * note This function does not need to be called unless you are reimplementing the
+ * non blocking API's interrupt handler routines to add special functionality.
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to #lpi2c_slave_handle_t structure which stores the transfer state.
+ */
+void LPI2C_SlaveTransferHandleIRQ(LPI2C_Type *base, lpi2c_slave_handle_t *handle)
+{
+ uint32_t flags;
+ lpi2c_slave_transfer_t *xfer;
+
+ /* Check for a valid handle in case of a spurious interrupt. */
+ if (NULL != handle)
+ {
+ xfer = &handle->transfer;
+
+ /* Get status flags. */
+ flags = LPI2C_SlaveGetStatusFlags(base);
+
+ if (0U != (flags & ((uint32_t)kLPI2C_SlaveBitErrFlag | (uint32_t)kLPI2C_SlaveFifoErrFlag)))
+ {
+ xfer->event = kLPI2C_SlaveCompletionEvent;
+ xfer->completionStatus = LPI2C_SlaveCheckAndClearError(base, flags);
+
+ if ((0U != (handle->eventMask & (uint32_t)kLPI2C_SlaveCompletionEvent)) && (NULL != handle->callback))
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+ }
+ else
+ {
+ if (0U !=
+ (flags & (((uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag) | ((uint32_t)kLPI2C_SlaveStopDetectFlag))))
+ {
+ xfer->event = (0U != (flags & (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag)) ?
+ kLPI2C_SlaveRepeatedStartEvent :
+ kLPI2C_SlaveCompletionEvent;
+ xfer->receivedAddress = 0U;
+ xfer->completionStatus = kStatus_Success;
+ xfer->transferredCount = handle->transferredCount;
+
+ if (xfer->event == kLPI2C_SlaveCompletionEvent)
+ {
+ handle->isBusy = false;
+ }
+
+ if (handle->wasTransmit)
+ {
+ /* Subtract one from the transmit count to offset the fact that LPI2C asserts the */
+ /* tx flag before it sees the nack from the master-receiver, thus causing one more */
+ /* count that the master actually receives. */
+ --xfer->transferredCount;
+ handle->wasTransmit = false;
+ }
+
+ /* Clear the flag. */
+ LPI2C_SlaveClearStatusFlags(base, flags & ((uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag |
+ (uint32_t)kLPI2C_SlaveStopDetectFlag));
+
+ /* Revert to sending an Ack by default, in case we sent a Nack for receive. */
+ base->STAR = 0U;
+
+ if ((0U != (handle->eventMask & (uint32_t)xfer->event)) && (NULL != handle->callback))
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+
+ if (0U != (flags & (uint32_t)kLPI2C_SlaveStopDetectFlag))
+ {
+ /* Clean up transfer info on completion, after the callback has been invoked. */
+ (void)memset(&handle->transfer, 0, sizeof(handle->transfer));
+ }
+ }
+ if (0U != (flags & (uint32_t)kLPI2C_SlaveAddressValidFlag))
+ {
+ xfer->event = kLPI2C_SlaveAddressMatchEvent;
+ xfer->receivedAddress = (uint8_t)(base->SASR & LPI2C_SASR_RADDR_MASK);
+
+ /* Update handle status to busy because slave is addressed. */
+ handle->isBusy = true;
+ if ((0U != (handle->eventMask & (uint32_t)kLPI2C_SlaveAddressMatchEvent)) && (NULL != handle->callback))
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+ }
+ if (0U != (flags & (uint32_t)kLPI2C_SlaveTransmitAckFlag))
+ {
+ xfer->event = kLPI2C_SlaveTransmitAckEvent;
+
+ if ((0U != (handle->eventMask & (uint32_t)kLPI2C_SlaveTransmitAckEvent)) && (NULL != handle->callback))
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+ }
+
+ /* Handle transmit and receive. */
+ if (0U != (flags & (uint32_t)kLPI2C_SlaveTxReadyFlag))
+ {
+ handle->wasTransmit = true;
+
+ /* If we're out of data, invoke callback to get more. */
+ if ((NULL == xfer->data) || (0U == xfer->dataSize))
+ {
+ xfer->event = kLPI2C_SlaveTransmitEvent;
+ if (NULL != handle->callback)
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+
+ /* Clear the transferred count now that we have a new buffer. */
+ handle->transferredCount = 0U;
+ }
+
+ /* Transmit a byte. */
+ if ((NULL != xfer->data) && (0U != xfer->dataSize))
+ {
+ base->STDR = *xfer->data++;
+ --xfer->dataSize;
+ ++handle->transferredCount;
+ }
+ }
+ if (0U != (flags & (uint32_t)kLPI2C_SlaveRxReadyFlag))
+ {
+ /* If we're out of room in the buffer, invoke callback to get another. */
+ if ((NULL == xfer->data) || (0U == xfer->dataSize))
+ {
+ xfer->event = kLPI2C_SlaveReceiveEvent;
+ if (NULL != handle->callback)
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+
+ /* Clear the transferred count now that we have a new buffer. */
+ handle->transferredCount = 0U;
+ }
+
+ /* Receive a byte. */
+ if ((NULL != xfer->data) && (0U != xfer->dataSize))
+ {
+ *xfer->data++ = (uint8_t)base->SRDR;
+ --xfer->dataSize;
+ ++handle->transferredCount;
+ }
+ else
+ {
+ /* We don't have any room to receive more data, so send a nack. */
+ base->STAR = LPI2C_STAR_TXNACK_MASK;
+ }
+ }
+ }
+ }
+}
+
+#if !(defined(FSL_FEATURE_I2C_HAS_NO_IRQ) && FSL_FEATURE_I2C_HAS_NO_IRQ)
+/*!
+ * @brief Shared IRQ handler that can call both master and slave ISRs.
+ *
+ * The master and slave ISRs are called through function pointers in order to decouple
+ * this code from the ISR functions. Without this, the linker would always pull in both
+ * ISRs and every function they call, even if only the functional API was used.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param instance The LPI2C peripheral instance number.
+ */
+static void LPI2C_CommonIRQHandler(LPI2C_Type *base, uint32_t instance)
+{
+ /* Check for master IRQ. */
+ if ((0U != (base->MCR & LPI2C_MCR_MEN_MASK)) && (NULL != s_lpi2cMasterIsr))
+ {
+ /* Master mode. */
+ s_lpi2cMasterIsr(base, s_lpi2cMasterHandle[instance]);
+ }
+
+ /* Check for slave IRQ. */
+ if ((0U != (base->SCR & LPI2C_SCR_SEN_MASK)) && (NULL != s_lpi2cSlaveIsr))
+ {
+ /* Slave mode. */
+ s_lpi2cSlaveIsr(base, s_lpi2cSlaveHandle[instance]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(LPI2C0)
+/* Implementation of LPI2C0 handler named in startup code. */
+void LPI2C0_DriverIRQHandler(void);
+void LPI2C0_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(LPI2C0, 0U);
+}
+#endif
+
+#if defined(LPI2C1)
+/* Implementation of LPI2C1 handler named in startup code. */
+void LPI2C1_DriverIRQHandler(void);
+void LPI2C1_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(LPI2C1, 1U);
+}
+#endif
+
+#if defined(LPI2C2)
+/* Implementation of LPI2C2 handler named in startup code. */
+void LPI2C2_DriverIRQHandler(void);
+void LPI2C2_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(LPI2C2, 2U);
+}
+#endif
+
+#if defined(LPI2C3)
+/* Implementation of LPI2C3 handler named in startup code. */
+void LPI2C3_DriverIRQHandler(void);
+void LPI2C3_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(LPI2C3, 3U);
+}
+#endif
+
+#if defined(LPI2C4)
+/* Implementation of LPI2C4 handler named in startup code. */
+void LPI2C4_DriverIRQHandler(void);
+void LPI2C4_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(LPI2C4, 4U);
+}
+#endif
+
+#if defined(LPI2C5)
+/* Implementation of LPI2C5 handler named in startup code. */
+void LPI2C5_DriverIRQHandler(void);
+void LPI2C5_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(LPI2C5, 5U);
+}
+#endif
+
+#if defined(LPI2C6)
+/* Implementation of LPI2C6 handler named in startup code. */
+void LPI2C6_DriverIRQHandler(void);
+void LPI2C6_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(LPI2C6, 6U);
+}
+#endif
+
+#if defined(CM4_0__LPI2C)
+/* Implementation of CM4_0__LPI2C handler named in startup code. */
+void M4_0_LPI2C_DriverIRQHandler(void);
+void M4_0_LPI2C_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(CM4_0__LPI2C, LPI2C_GetInstance(CM4_0__LPI2C));
+}
+#endif
+
+#if defined(CM4__LPI2C)
+/* Implementation of CM4__LPI2C handler named in startup code. */
+void M4_LPI2C_DriverIRQHandler(void);
+void M4_LPI2C_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(CM4__LPI2C, LPI2C_GetInstance(CM4__LPI2C));
+}
+#endif
+
+#if defined(CM4_1__LPI2C)
+/* Implementation of CM4_1__LPI2C handler named in startup code. */
+void M4_1_LPI2C_DriverIRQHandler(void);
+void M4_1_LPI2C_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(CM4_1__LPI2C, LPI2C_GetInstance(CM4_1__LPI2C));
+}
+#endif
+
+#if defined(DMA__LPI2C0)
+/* Implementation of DMA__LPI2C0 handler named in startup code. */
+void DMA_I2C0_INT_DriverIRQHandler(void);
+void DMA_I2C0_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(DMA__LPI2C0, LPI2C_GetInstance(DMA__LPI2C0));
+}
+#endif
+
+#if defined(DMA__LPI2C1)
+/* Implementation of DMA__LPI2C1 handler named in startup code. */
+void DMA_I2C1_INT_DriverIRQHandler(void);
+void DMA_I2C1_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(DMA__LPI2C1, LPI2C_GetInstance(DMA__LPI2C1));
+}
+#endif
+
+#if defined(DMA__LPI2C2)
+/* Implementation of DMA__LPI2C2 handler named in startup code. */
+void DMA_I2C2_INT_DriverIRQHandler(void);
+void DMA_I2C2_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(DMA__LPI2C2, LPI2C_GetInstance(DMA__LPI2C2));
+}
+#endif
+
+#if defined(DMA__LPI2C3)
+/* Implementation of DMA__LPI2C3 handler named in startup code. */
+void DMA_I2C3_INT_DriverIRQHandler(void);
+void DMA_I2C3_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(DMA__LPI2C3, LPI2C_GetInstance(DMA__LPI2C3));
+}
+#endif
+
+#if defined(DMA__LPI2C4)
+/* Implementation of DMA__LPI2C3 handler named in startup code. */
+void DMA_I2C4_INT_DriverIRQHandler(void);
+void DMA_I2C4_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(DMA__LPI2C4, LPI2C_GetInstance(DMA__LPI2C4));
+}
+#endif
+
+#if defined(ADMA__LPI2C0)
+/* Implementation of DMA__LPI2C0 handler named in startup code. */
+void ADMA_I2C0_INT_DriverIRQHandler(void);
+void ADMA_I2C0_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(ADMA__LPI2C0, LPI2C_GetInstance(ADMA__LPI2C0));
+}
+#endif
+
+#if defined(ADMA__LPI2C1)
+/* Implementation of DMA__LPI2C1 handler named in startup code. */
+void ADMA_I2C1_INT_DriverIRQHandler(void);
+void ADMA_I2C1_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(ADMA__LPI2C1, LPI2C_GetInstance(ADMA__LPI2C1));
+}
+#endif
+
+#if defined(ADMA__LPI2C2)
+/* Implementation of DMA__LPI2C2 handler named in startup code. */
+void ADMA_I2C2_INT_DriverIRQHandler(void);
+void ADMA_I2C2_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(ADMA__LPI2C2, LPI2C_GetInstance(ADMA__LPI2C2));
+}
+#endif
+
+#if defined(ADMA__LPI2C3)
+/* Implementation of DMA__LPI2C3 handler named in startup code. */
+void ADMA_I2C3_INT_DriverIRQHandler(void);
+void ADMA_I2C3_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(ADMA__LPI2C3, LPI2C_GetInstance(ADMA__LPI2C3));
+}
+#endif
+
+#if defined(ADMA__LPI2C4)
+/* Implementation of DMA__LPI2C3 handler named in startup code. */
+void ADMA_I2C4_INT_DriverIRQHandler(void);
+void ADMA_I2C4_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(ADMA__LPI2C4, LPI2C_GetInstance(ADMA__LPI2C4));
+}
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c.h b/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c.h
new file mode 100644
index 0000000000..d61a6eb5cf
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c.h
@@ -0,0 +1,1320 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_LPI2C_H_
+#define _FSL_LPI2C_H_
+
+#include <stddef.h>
+#include "fsl_device_registers.h"
+#include "fsl_common.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*!
+ * @addtogroup lpi2c
+ * @{
+ */
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief LPI2C driver version. */
+#define FSL_LPI2C_DRIVER_VERSION (MAKE_VERSION(2, 4, 1))
+/*@}*/
+
+/*! @brief Retry times for waiting flag. */
+#ifndef I2C_RETRY_TIMES
+#define I2C_RETRY_TIMES 0U /* Define to zero means keep waiting until the flag is assert/deassert. */
+#endif
+
+/*! @brief LPI2C status return codes. */
+enum
+{
+ kStatus_LPI2C_Busy = MAKE_STATUS(kStatusGroup_LPI2C, 0), /*!< The master is already performing a transfer. */
+ kStatus_LPI2C_Idle = MAKE_STATUS(kStatusGroup_LPI2C, 1), /*!< The slave driver is idle. */
+ kStatus_LPI2C_Nak = MAKE_STATUS(kStatusGroup_LPI2C, 2), /*!< The slave device sent a NAK in response to a byte. */
+ kStatus_LPI2C_FifoError = MAKE_STATUS(kStatusGroup_LPI2C, 3), /*!< FIFO under run or overrun. */
+ kStatus_LPI2C_BitError = MAKE_STATUS(kStatusGroup_LPI2C, 4), /*!< Transferred bit was not seen on the bus. */
+ kStatus_LPI2C_ArbitrationLost = MAKE_STATUS(kStatusGroup_LPI2C, 5), /*!< Arbitration lost error. */
+ kStatus_LPI2C_PinLowTimeout =
+ MAKE_STATUS(kStatusGroup_LPI2C, 6), /*!< SCL or SDA were held low longer than the timeout. */
+ kStatus_LPI2C_NoTransferInProgress =
+ MAKE_STATUS(kStatusGroup_LPI2C, 7), /*!< Attempt to abort a transfer when one is not in progress. */
+ kStatus_LPI2C_DmaRequestFail = MAKE_STATUS(kStatusGroup_LPI2C, 8), /*!< DMA request failed. */
+ kStatus_LPI2C_Timeout = MAKE_STATUS(kStatusGroup_LPI2C, 9), /*!< Timeout polling status flags. */
+};
+
+/*! @} */
+
+/*!
+ * @addtogroup lpi2c_master_driver
+ * @{
+ */
+
+/*!
+ * @brief LPI2C master peripheral flags.
+ *
+ * The following status register flags can be cleared:
+ * - #kLPI2C_MasterEndOfPacketFlag
+ * - #kLPI2C_MasterStopDetectFlag
+ * - #kLPI2C_MasterNackDetectFlag
+ * - #kLPI2C_MasterArbitrationLostFlag
+ * - #kLPI2C_MasterFifoErrFlag
+ * - #kLPI2C_MasterPinLowTimeoutFlag
+ * - #kLPI2C_MasterDataMatchFlag
+ *
+ * All flags except #kLPI2C_MasterBusyFlag and #kLPI2C_MasterBusBusyFlag can be enabled as
+ * interrupts.
+ *
+ * @note These enums are meant to be OR'd together to form a bit mask.
+ */
+enum _lpi2c_master_flags
+{
+ kLPI2C_MasterTxReadyFlag = LPI2C_MSR_TDF_MASK, /*!< Transmit data flag */
+ kLPI2C_MasterRxReadyFlag = LPI2C_MSR_RDF_MASK, /*!< Receive data flag */
+ kLPI2C_MasterEndOfPacketFlag = LPI2C_MSR_EPF_MASK, /*!< End Packet flag */
+ kLPI2C_MasterStopDetectFlag = LPI2C_MSR_SDF_MASK, /*!< Stop detect flag */
+ kLPI2C_MasterNackDetectFlag = LPI2C_MSR_NDF_MASK, /*!< NACK detect flag */
+ kLPI2C_MasterArbitrationLostFlag = LPI2C_MSR_ALF_MASK, /*!< Arbitration lost flag */
+ kLPI2C_MasterFifoErrFlag = LPI2C_MSR_FEF_MASK, /*!< FIFO error flag */
+ kLPI2C_MasterPinLowTimeoutFlag = LPI2C_MSR_PLTF_MASK, /*!< Pin low timeout flag */
+ kLPI2C_MasterDataMatchFlag = LPI2C_MSR_DMF_MASK, /*!< Data match flag */
+ kLPI2C_MasterBusyFlag = LPI2C_MSR_MBF_MASK, /*!< Master busy flag */
+ kLPI2C_MasterBusBusyFlag = LPI2C_MSR_BBF_MASK, /*!< Bus busy flag */
+
+ /*! All flags which are cleared by the driver upon starting a transfer. */
+ kLPI2C_MasterClearFlags = kLPI2C_MasterEndOfPacketFlag | kLPI2C_MasterStopDetectFlag | kLPI2C_MasterNackDetectFlag |
+ kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterFifoErrFlag |
+ kLPI2C_MasterPinLowTimeoutFlag | kLPI2C_MasterDataMatchFlag,
+ /*! IRQ sources enabled by the non-blocking transactional API. */
+ kLPI2C_MasterIrqFlags = kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterTxReadyFlag | kLPI2C_MasterRxReadyFlag |
+ kLPI2C_MasterStopDetectFlag | kLPI2C_MasterNackDetectFlag | kLPI2C_MasterPinLowTimeoutFlag |
+ kLPI2C_MasterFifoErrFlag,
+ /*! Errors to check for. */
+ kLPI2C_MasterErrorFlags = kLPI2C_MasterNackDetectFlag | kLPI2C_MasterArbitrationLostFlag |
+ kLPI2C_MasterFifoErrFlag | kLPI2C_MasterPinLowTimeoutFlag
+};
+
+/*! @brief Direction of master and slave transfers. */
+typedef enum _lpi2c_direction
+{
+ kLPI2C_Write = 0U, /*!< Master transmit. */
+ kLPI2C_Read = 1U /*!< Master receive. */
+} lpi2c_direction_t;
+
+/*! @brief LPI2C pin configuration. */
+typedef enum _lpi2c_master_pin_config
+{
+ kLPI2C_2PinOpenDrain = 0x0U, /*!< LPI2C Configured for 2-pin open drain mode */
+ kLPI2C_2PinOutputOnly = 0x1U, /*!< LPI2C Configured for 2-pin output only mode (ultra-fast mode) */
+ kLPI2C_2PinPushPull = 0x2U, /*!< LPI2C Configured for 2-pin push-pull mode */
+ kLPI2C_4PinPushPull = 0x3U, /*!< LPI2C Configured for 4-pin push-pull mode */
+ kLPI2C_2PinOpenDrainWithSeparateSlave =
+ 0x4U, /*!< LPI2C Configured for 2-pin open drain mode with separate LPI2C slave */
+ kLPI2C_2PinOutputOnlyWithSeparateSlave =
+ 0x5U, /*!< LPI2C Configured for 2-pin output only mode(ultra-fast mode) with separate LPI2C slave */
+ kLPI2C_2PinPushPullWithSeparateSlave =
+ 0x6U, /*!< LPI2C Configured for 2-pin push-pull mode with separate LPI2C slave */
+ kLPI2C_4PinPushPullWithInvertedOutput = 0x7U /*!< LPI2C Configured for 4-pin push-pull mode(inverted outputs) */
+} lpi2c_master_pin_config_t;
+
+/*! @brief LPI2C master host request selection. */
+typedef enum _lpi2c_host_request_source
+{
+ kLPI2C_HostRequestExternalPin = 0x0U, /*!< Select the LPI2C_HREQ pin as the host request input */
+ kLPI2C_HostRequestInputTrigger = 0x1U, /*!< Select the input trigger as the host request input */
+} lpi2c_host_request_source_t;
+
+/*! @brief LPI2C master host request pin polarity configuration. */
+typedef enum _lpi2c_host_request_polarity
+{
+ kLPI2C_HostRequestPinActiveLow = 0x0U, /*!< Configure the LPI2C_HREQ pin active low */
+ kLPI2C_HostRequestPinActiveHigh = 0x1U /*!< Configure the LPI2C_HREQ pin active high */
+} lpi2c_host_request_polarity_t;
+
+/*!
+ * @brief Structure with settings to initialize the LPI2C master module.
+ *
+ * This structure holds configuration settings for the LPI2C peripheral. To initialize this
+ * structure to reasonable defaults, call the LPI2C_MasterGetDefaultConfig() function and
+ * pass a pointer to your configuration structure instance.
+ *
+ * The configuration structure can be made constant so it resides in flash.
+ */
+typedef struct _lpi2c_master_config
+{
+ bool enableMaster; /*!< Whether to enable master mode. */
+ bool enableDoze; /*!< Whether master is enabled in doze mode. */
+ bool debugEnable; /*!< Enable transfers to continue when halted in debug mode. */
+ bool ignoreAck; /*!< Whether to ignore ACK/NACK. */
+ lpi2c_master_pin_config_t pinConfig; /*!< The pin configuration option. */
+ uint32_t baudRate_Hz; /*!< Desired baud rate in Hertz. */
+ uint32_t busIdleTimeout_ns; /*!< Bus idle timeout in nanoseconds. Set to 0 to disable. */
+ uint32_t pinLowTimeout_ns; /*!< Pin low timeout in nanoseconds. Set to 0 to disable. */
+ uint8_t sdaGlitchFilterWidth_ns; /*!< Width in nanoseconds of glitch filter on SDA pin. Set to 0 to disable. */
+ uint8_t sclGlitchFilterWidth_ns; /*!< Width in nanoseconds of glitch filter on SCL pin. Set to 0 to disable. */
+ struct
+ {
+ bool enable; /*!< Enable host request. */
+ lpi2c_host_request_source_t source; /*!< Host request source. */
+ lpi2c_host_request_polarity_t polarity; /*!< Host request pin polarity. */
+ } hostRequest; /*!< Host request options. */
+} lpi2c_master_config_t;
+
+/*! @brief LPI2C master data match configuration modes. */
+typedef enum _lpi2c_data_match_config_mode
+{
+ kLPI2C_MatchDisabled = 0x0U, /*!< LPI2C Match Disabled */
+ kLPI2C_1stWordEqualsM0OrM1 = 0x2U, /*!< LPI2C Match Enabled and 1st data word equals MATCH0 OR MATCH1 */
+ kLPI2C_AnyWordEqualsM0OrM1 = 0x3U, /*!< LPI2C Match Enabled and any data word equals MATCH0 OR MATCH1 */
+ kLPI2C_1stWordEqualsM0And2ndWordEqualsM1 =
+ 0x4U, /*!< LPI2C Match Enabled and 1st data word equals MATCH0, 2nd data equals MATCH1 */
+ kLPI2C_AnyWordEqualsM0AndNextWordEqualsM1 =
+ 0x5U, /*!< LPI2C Match Enabled and any data word equals MATCH0, next data equals MATCH1 */
+ kLPI2C_1stWordAndM1EqualsM0AndM1 =
+ 0x6U, /*!< LPI2C Match Enabled and 1st data word and MATCH0 equals MATCH0 and MATCH1 */
+ kLPI2C_AnyWordAndM1EqualsM0AndM1 =
+ 0x7U /*!< LPI2C Match Enabled and any data word and MATCH0 equals MATCH0 and MATCH1 */
+} lpi2c_data_match_config_mode_t;
+
+/*! @brief LPI2C master data match configuration structure. */
+typedef struct _lpi2c_match_config
+{
+ lpi2c_data_match_config_mode_t matchMode; /*!< Data match configuration setting. */
+ bool rxDataMatchOnly; /*!< When set to true, received data is ignored until a successful match. */
+ uint32_t match0; /*!< Match value 0. */
+ uint32_t match1; /*!< Match value 1. */
+} lpi2c_data_match_config_t;
+
+/* Forward declaration of the transfer descriptor and handle typedefs. */
+typedef struct _lpi2c_master_transfer lpi2c_master_transfer_t;
+typedef struct _lpi2c_master_handle lpi2c_master_handle_t;
+
+/*!
+ * @brief Master completion callback function pointer type.
+ *
+ * This callback is used only for the non-blocking master transfer API. Specify the callback you wish to use
+ * in the call to LPI2C_MasterTransferCreateHandle().
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param completionStatus Either kStatus_Success or an error code describing how the transfer completed.
+ * @param userData Arbitrary pointer-sized value passed from the application.
+ */
+typedef void (*lpi2c_master_transfer_callback_t)(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ status_t completionStatus,
+ void *userData);
+
+/*!
+ * @brief Transfer option flags.
+ *
+ * @note These enumerations are intended to be OR'd together to form a bit mask of options for
+ * the #_lpi2c_master_transfer::flags field.
+ */
+enum _lpi2c_master_transfer_flags
+{
+ kLPI2C_TransferDefaultFlag = 0x00U, /*!< Transfer starts with a start signal, stops with a stop signal. */
+ kLPI2C_TransferNoStartFlag = 0x01U, /*!< Don't send a start condition, address, and sub address */
+ kLPI2C_TransferRepeatedStartFlag = 0x02U, /*!< Send a repeated start condition */
+ kLPI2C_TransferNoStopFlag = 0x04U, /*!< Don't send a stop condition. */
+};
+
+/*!
+ * @brief Non-blocking transfer descriptor structure.
+ *
+ * This structure is used to pass transaction parameters to the LPI2C_MasterTransferNonBlocking() API.
+ */
+struct _lpi2c_master_transfer
+{
+ uint32_t flags; /*!< Bit mask of options for the transfer. See enumeration #_lpi2c_master_transfer_flags for
+ available options. Set to 0 or #kLPI2C_TransferDefaultFlag for normal transfers. */
+ uint16_t slaveAddress; /*!< The 7-bit slave address. */
+ lpi2c_direction_t direction; /*!< Either #kLPI2C_Read or #kLPI2C_Write. */
+ uint32_t subaddress; /*!< Sub address. Transferred MSB first. */
+ size_t subaddressSize; /*!< Length of sub address to send in bytes. Maximum size is 4 bytes. */
+ void *data; /*!< Pointer to data to transfer. */
+ size_t dataSize; /*!< Number of bytes to transfer. */
+};
+
+/*!
+ * @brief Driver handle for master non-blocking APIs.
+ * @note The contents of this structure are private and subject to change.
+ */
+struct _lpi2c_master_handle
+{
+ uint8_t state; /*!< Transfer state machine current state. */
+ uint16_t remainingBytes; /*!< Remaining byte count in current state. */
+ uint8_t *buf; /*!< Buffer pointer for current state. */
+ uint16_t commandBuffer[6]; /*!< LPI2C command sequence. When all 6 command words are used:
+ Start&addr&write[1 word] + subaddr[4 words] + restart&addr&read[1 word] */
+ lpi2c_master_transfer_t transfer; /*!< Copy of the current transfer info. */
+ lpi2c_master_transfer_callback_t completionCallback; /*!< Callback function pointer. */
+ void *userData; /*!< Application data passed to callback. */
+};
+
+/*! @brief Typedef for master interrupt handler, used internally for LPI2C master interrupt and EDMA transactional APIs.
+ */
+typedef void (*lpi2c_master_isr_t)(LPI2C_Type *base, void *handle);
+
+/*! @} */
+
+/*!
+ * @addtogroup lpi2c_slave_driver
+ * @{
+ */
+
+/*!
+ * @brief LPI2C slave peripheral flags.
+ *
+ * The following status register flags can be cleared:
+ * - #kLPI2C_SlaveRepeatedStartDetectFlag
+ * - #kLPI2C_SlaveStopDetectFlag
+ * - #kLPI2C_SlaveBitErrFlag
+ * - #kLPI2C_SlaveFifoErrFlag
+ *
+ * All flags except #kLPI2C_SlaveBusyFlag and #kLPI2C_SlaveBusBusyFlag can be enabled as
+ * interrupts.
+ *
+ * @note These enumerations are meant to be OR'd together to form a bit mask.
+ */
+enum _lpi2c_slave_flags
+{
+ kLPI2C_SlaveTxReadyFlag = LPI2C_SSR_TDF_MASK, /*!< Transmit data flag */
+ kLPI2C_SlaveRxReadyFlag = LPI2C_SSR_RDF_MASK, /*!< Receive data flag */
+ kLPI2C_SlaveAddressValidFlag = LPI2C_SSR_AVF_MASK, /*!< Address valid flag */
+ kLPI2C_SlaveTransmitAckFlag = LPI2C_SSR_TAF_MASK, /*!< Transmit ACK flag */
+ kLPI2C_SlaveRepeatedStartDetectFlag = LPI2C_SSR_RSF_MASK, /*!< Repeated start detect flag */
+ kLPI2C_SlaveStopDetectFlag = LPI2C_SSR_SDF_MASK, /*!< Stop detect flag */
+ kLPI2C_SlaveBitErrFlag = LPI2C_SSR_BEF_MASK, /*!< Bit error flag */
+ kLPI2C_SlaveFifoErrFlag = LPI2C_SSR_FEF_MASK, /*!< FIFO error flag */
+ kLPI2C_SlaveAddressMatch0Flag = LPI2C_SSR_AM0F_MASK, /*!< Address match 0 flag */
+ kLPI2C_SlaveAddressMatch1Flag = LPI2C_SSR_AM1F_MASK, /*!< Address match 1 flag */
+ kLPI2C_SlaveGeneralCallFlag = LPI2C_SSR_GCF_MASK, /*!< General call flag */
+ kLPI2C_SlaveBusyFlag = LPI2C_SSR_SBF_MASK, /*!< Master busy flag */
+ kLPI2C_SlaveBusBusyFlag = LPI2C_SSR_BBF_MASK, /*!< Bus busy flag */
+ /*! All flags which are cleared by the driver upon starting a transfer. */
+ kLPI2C_SlaveClearFlags = kLPI2C_SlaveRepeatedStartDetectFlag | kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveBitErrFlag |
+ kLPI2C_SlaveFifoErrFlag,
+ /*! IRQ sources enabled by the non-blocking transactional API. */
+ kLPI2C_SlaveIrqFlags = kLPI2C_SlaveTxReadyFlag | kLPI2C_SlaveRxReadyFlag | kLPI2C_SlaveStopDetectFlag |
+ kLPI2C_SlaveRepeatedStartDetectFlag | kLPI2C_SlaveFifoErrFlag | kLPI2C_SlaveBitErrFlag |
+ kLPI2C_SlaveTransmitAckFlag | kLPI2C_SlaveAddressValidFlag,
+ /*! Errors to check for. */
+ kLPI2C_SlaveErrorFlags = kLPI2C_SlaveFifoErrFlag | kLPI2C_SlaveBitErrFlag
+};
+
+/*! @brief LPI2C slave address match options. */
+typedef enum _lpi2c_slave_address_match
+{
+ kLPI2C_MatchAddress0 = 0U, /*!< Match only address 0. */
+ kLPI2C_MatchAddress0OrAddress1 = 2U, /*!< Match either address 0 or address 1. */
+ kLPI2C_MatchAddress0ThroughAddress1 = 6U, /*!< Match a range of slave addresses from address 0 through address 1. */
+} lpi2c_slave_address_match_t;
+
+/*!
+ * @brief Structure with settings to initialize the LPI2C slave module.
+ *
+ * This structure holds configuration settings for the LPI2C slave peripheral. To initialize this
+ * structure to reasonable defaults, call the LPI2C_SlaveGetDefaultConfig() function and
+ * pass a pointer to your configuration structure instance.
+ *
+ * The configuration structure can be made constant so it resides in flash.
+ */
+typedef struct _lpi2c_slave_config
+{
+ bool enableSlave; /*!< Enable slave mode. */
+ uint8_t address0; /*!< Slave's 7-bit address. */
+ uint8_t address1; /*!< Alternate slave 7-bit address. */
+ lpi2c_slave_address_match_t addressMatchMode; /*!< Address matching options. */
+ bool filterDozeEnable; /*!< Enable digital glitch filter in doze mode. */
+ bool filterEnable; /*!< Enable digital glitch filter. */
+ bool enableGeneralCall; /*!< Enable general call address matching. */
+ struct
+ {
+ bool enableAck; /*!< Enables SCL clock stretching during slave-transmit address byte(s)
+ and slave-receiver address and data byte(s) to allow software to
+ write the Transmit ACK Register before the ACK or NACK is transmitted.
+ Clock stretching occurs when transmitting the 9th bit. When
+ enableAckSCLStall is enabled, there is no need to set either
+ enableRxDataSCLStall or enableAddressSCLStall. */
+ bool enableTx; /*!< Enables SCL clock stretching when the transmit data flag is set
+ during a slave-transmit transfer. */
+ bool enableRx; /*!< Enables SCL clock stretching when receive data flag is set during
+ a slave-receive transfer. */
+ bool enableAddress; /*!< Enables SCL clock stretching when the address valid flag is asserted. */
+ } sclStall;
+ bool ignoreAck; /*!< Continue transfers after a NACK is detected. */
+ bool enableReceivedAddressRead; /*!< Enable reading the address received address as the first byte of data. */
+ uint32_t sdaGlitchFilterWidth_ns; /*!< Width in nanoseconds of the digital filter on the SDA signal. Set to 0 to
+ disable. */
+ uint32_t sclGlitchFilterWidth_ns; /*!< Width in nanoseconds of the digital filter on the SCL signal. Set to 0 to
+ disable. */
+ uint32_t dataValidDelay_ns; /*!< Width in nanoseconds of the data valid delay. */
+ uint32_t clockHoldTime_ns; /*!< Width in nanoseconds of the clock hold time. */
+} lpi2c_slave_config_t;
+
+/*!
+ * @brief Set of events sent to the callback for non blocking slave transfers.
+ *
+ * These event enumerations are used for two related purposes. First, a bit mask created by OR'ing together
+ * events is passed to LPI2C_SlaveTransferNonBlocking() in order to specify which events to enable.
+ * Then, when the slave callback is invoked, it is passed the current event through its @a transfer
+ * parameter.
+ *
+ * @note These enumerations are meant to be OR'd together to form a bit mask of events.
+ */
+typedef enum _lpi2c_slave_transfer_event
+{
+ kLPI2C_SlaveAddressMatchEvent = 0x01U, /*!< Received the slave address after a start or repeated start. */
+ kLPI2C_SlaveTransmitEvent = 0x02U, /*!< Callback is requested to provide data to transmit
+ (slave-transmitter role). */
+ kLPI2C_SlaveReceiveEvent = 0x04U, /*!< Callback is requested to provide a buffer in which to place received
+ data (slave-receiver role). */
+ kLPI2C_SlaveTransmitAckEvent = 0x08U, /*!< Callback needs to either transmit an ACK or NACK. */
+ kLPI2C_SlaveRepeatedStartEvent = 0x10U, /*!< A repeated start was detected. */
+ kLPI2C_SlaveCompletionEvent = 0x20U, /*!< A stop was detected, completing the transfer. */
+
+ /*! Bit mask of all available events. */
+ kLPI2C_SlaveAllEvents = kLPI2C_SlaveAddressMatchEvent | kLPI2C_SlaveTransmitEvent | kLPI2C_SlaveReceiveEvent |
+ kLPI2C_SlaveTransmitAckEvent | kLPI2C_SlaveRepeatedStartEvent | kLPI2C_SlaveCompletionEvent,
+} lpi2c_slave_transfer_event_t;
+
+/*! @brief LPI2C slave transfer structure */
+typedef struct _lpi2c_slave_transfer
+{
+ lpi2c_slave_transfer_event_t event; /*!< Reason the callback is being invoked. */
+ uint8_t receivedAddress; /*!< Matching address send by master. */
+ uint8_t *data; /*!< Transfer buffer */
+ size_t dataSize; /*!< Transfer size */
+ status_t completionStatus; /*!< Success or error code describing how the transfer completed. Only applies for
+ #kLPI2C_SlaveCompletionEvent. */
+ size_t transferredCount; /*!< Number of bytes actually transferred since start or last repeated start. */
+} lpi2c_slave_transfer_t;
+
+/* Forward declaration. */
+typedef struct _lpi2c_slave_handle lpi2c_slave_handle_t;
+
+/*!
+ * @brief Slave event callback function pointer type.
+ *
+ * This callback is used only for the slave non-blocking transfer API. To install a callback,
+ * use the LPI2C_SlaveSetCallback() function after you have created a handle.
+ *
+ * @param base Base address for the LPI2C instance on which the event occurred.
+ * @param transfer Pointer to transfer descriptor containing values passed to and/or from the callback.
+ * @param userData Arbitrary pointer-sized value passed from the application.
+ */
+typedef void (*lpi2c_slave_transfer_callback_t)(LPI2C_Type *base, lpi2c_slave_transfer_t *transfer, void *userData);
+
+/*!
+ * @brief LPI2C slave handle structure.
+ * @note The contents of this structure are private and subject to change.
+ */
+struct _lpi2c_slave_handle
+{
+ lpi2c_slave_transfer_t transfer; /*!< LPI2C slave transfer copy. */
+ bool isBusy; /*!< Whether transfer is busy. */
+ bool wasTransmit; /*!< Whether the last transfer was a transmit. */
+ uint32_t eventMask; /*!< Mask of enabled events. */
+ uint32_t transferredCount; /*!< Count of bytes transferred. */
+ lpi2c_slave_transfer_callback_t callback; /*!< Callback function called at transfer event. */
+ void *userData; /*!< Callback parameter passed to callback. */
+};
+
+/*! @} */
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! Array to map LPI2C instance number to IRQ number, used internally for LPI2C master interrupt and EDMA transactional
+APIs. */
+extern IRQn_Type const kLpi2cIrqs[];
+
+/*! Pointer to master IRQ handler for each instance, used internally for LPI2C master interrupt and EDMA transactional
+APIs. */
+extern lpi2c_master_isr_t s_lpi2cMasterIsr;
+
+/*! Pointers to master handles for each instance, used internally for LPI2C master interrupt and EDMA transactional
+APIs. */
+extern void *s_lpi2cMasterHandle[];
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @brief Returns an instance number given a base address.
+ *
+ * If an invalid base address is passed, debug builds will assert. Release builds will just return
+ * instance number 0.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @return LPI2C instance number starting from 0.
+ */
+uint32_t LPI2C_GetInstance(LPI2C_Type *base);
+
+/*!
+ * @addtogroup lpi2c_master_driver
+ * @{
+ */
+
+/*! @name Initialization and deinitialization */
+/*@{*/
+
+/*!
+ * @brief Provides a default configuration for the LPI2C master peripheral.
+ *
+ * This function provides the following default configuration for the LPI2C master peripheral:
+ * @code
+ * masterConfig->enableMaster = true;
+ * masterConfig->debugEnable = false;
+ * masterConfig->ignoreAck = false;
+ * masterConfig->pinConfig = kLPI2C_2PinOpenDrain;
+ * masterConfig->baudRate_Hz = 100000U;
+ * masterConfig->busIdleTimeout_ns = 0;
+ * masterConfig->pinLowTimeout_ns = 0;
+ * masterConfig->sdaGlitchFilterWidth_ns = 0;
+ * masterConfig->sclGlitchFilterWidth_ns = 0;
+ * masterConfig->hostRequest.enable = false;
+ * masterConfig->hostRequest.source = kLPI2C_HostRequestExternalPin;
+ * masterConfig->hostRequest.polarity = kLPI2C_HostRequestPinActiveHigh;
+ * @endcode
+ *
+ * After calling this function, you can override any settings in order to customize the configuration,
+ * prior to initializing the master driver with LPI2C_MasterInit().
+ *
+ * @param[out] masterConfig User provided configuration structure for default values. Refer to #lpi2c_master_config_t.
+ */
+void LPI2C_MasterGetDefaultConfig(lpi2c_master_config_t *masterConfig);
+
+/*!
+ * @brief Initializes the LPI2C master peripheral.
+ *
+ * This function enables the peripheral clock and initializes the LPI2C master peripheral as described by the user
+ * provided configuration. A software reset is performed prior to configuration.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param masterConfig User provided peripheral configuration. Use LPI2C_MasterGetDefaultConfig() to get a set of
+ * defaults
+ * that you can override.
+ * @param sourceClock_Hz Frequency in Hertz of the LPI2C functional clock. Used to calculate the baud rate divisors,
+ * filter widths, and timeout periods.
+ */
+void LPI2C_MasterInit(LPI2C_Type *base, const lpi2c_master_config_t *masterConfig, uint32_t sourceClock_Hz);
+
+/*!
+ * @brief Deinitializes the LPI2C master peripheral.
+ *
+ * This function disables the LPI2C master peripheral and gates the clock. It also performs a software
+ * reset to restore the peripheral to reset conditions.
+ *
+ * @param base The LPI2C peripheral base address.
+ */
+void LPI2C_MasterDeinit(LPI2C_Type *base);
+
+/*!
+ * @brief Configures LPI2C master data match feature.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param matchConfig Settings for the data match feature.
+ */
+void LPI2C_MasterConfigureDataMatch(LPI2C_Type *base, const lpi2c_data_match_config_t *matchConfig);
+
+/* Not static so it can be used from fsl_lpi2c_edma.c. */
+status_t LPI2C_MasterCheckAndClearError(LPI2C_Type *base, uint32_t status);
+
+/* Not static so it can be used from fsl_lpi2c_edma.c. */
+status_t LPI2C_CheckForBusyBus(LPI2C_Type *base);
+
+/*!
+ * @brief Performs a software reset.
+ *
+ * Restores the LPI2C master peripheral to reset conditions.
+ *
+ * @param base The LPI2C peripheral base address.
+ */
+static inline void LPI2C_MasterReset(LPI2C_Type *base)
+{
+ base->MCR = LPI2C_MCR_RST_MASK;
+ base->MCR = 0;
+}
+
+/*!
+ * @brief Enables or disables the LPI2C module as master.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param enable Pass true to enable or false to disable the specified LPI2C as master.
+ */
+static inline void LPI2C_MasterEnable(LPI2C_Type *base, bool enable)
+{
+ base->MCR = (base->MCR & ~LPI2C_MCR_MEN_MASK) | LPI2C_MCR_MEN(enable);
+}
+
+/*@}*/
+
+/*! @name Status */
+/*@{*/
+
+/*!
+ * @brief Gets the LPI2C master status flags.
+ *
+ * A bit mask with the state of all LPI2C master status flags is returned. For each flag, the corresponding bit
+ * in the return value is set if the flag is asserted.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @return State of the status flags:
+ * - 1: related status flag is set.
+ * - 0: related status flag is not set.
+ * @see _lpi2c_master_flags
+ */
+static inline uint32_t LPI2C_MasterGetStatusFlags(LPI2C_Type *base)
+{
+ return base->MSR;
+}
+
+/*!
+ * @brief Clears the LPI2C master status flag state.
+ *
+ * The following status register flags can be cleared:
+ * - #kLPI2C_MasterEndOfPacketFlag
+ * - #kLPI2C_MasterStopDetectFlag
+ * - #kLPI2C_MasterNackDetectFlag
+ * - #kLPI2C_MasterArbitrationLostFlag
+ * - #kLPI2C_MasterFifoErrFlag
+ * - #kLPI2C_MasterPinLowTimeoutFlag
+ * - #kLPI2C_MasterDataMatchFlag
+ *
+ * Attempts to clear other flags has no effect.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param statusMask A bitmask of status flags that are to be cleared. The mask is composed of
+ * _lpi2c_master_flags enumerators OR'd together. You may pass the result of a previous call to
+ * LPI2C_MasterGetStatusFlags().
+ * @see _lpi2c_master_flags.
+ */
+static inline void LPI2C_MasterClearStatusFlags(LPI2C_Type *base, uint32_t statusMask)
+{
+ base->MSR = statusMask;
+}
+
+/*@}*/
+
+/*! @name Interrupts */
+/*@{*/
+
+/*!
+ * @brief Enables the LPI2C master interrupt requests.
+ *
+ * All flags except #kLPI2C_MasterBusyFlag and #kLPI2C_MasterBusBusyFlag can be enabled as
+ * interrupts.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param interruptMask Bit mask of interrupts to enable. See _lpi2c_master_flags for the set
+ * of constants that should be OR'd together to form the bit mask.
+ */
+static inline void LPI2C_MasterEnableInterrupts(LPI2C_Type *base, uint32_t interruptMask)
+{
+ base->MIER |= interruptMask;
+}
+
+/*!
+ * @brief Disables the LPI2C master interrupt requests.
+ *
+ * All flags except #kLPI2C_MasterBusyFlag and #kLPI2C_MasterBusBusyFlag can be enabled as
+ * interrupts.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param interruptMask Bit mask of interrupts to disable. See _lpi2c_master_flags for the set
+ * of constants that should be OR'd together to form the bit mask.
+ */
+static inline void LPI2C_MasterDisableInterrupts(LPI2C_Type *base, uint32_t interruptMask)
+{
+ base->MIER &= ~interruptMask;
+}
+
+/*!
+ * @brief Returns the set of currently enabled LPI2C master interrupt requests.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @return A bitmask composed of _lpi2c_master_flags enumerators OR'd together to indicate the
+ * set of enabled interrupts.
+ */
+static inline uint32_t LPI2C_MasterGetEnabledInterrupts(LPI2C_Type *base)
+{
+ return base->MIER;
+}
+
+/*@}*/
+
+/*! @name DMA control */
+/*@{*/
+
+/*!
+ * @brief Enables or disables LPI2C master DMA requests.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param enableTx Enable flag for transmit DMA request. Pass true for enable, false for disable.
+ * @param enableRx Enable flag for receive DMA request. Pass true for enable, false for disable.
+ */
+static inline void LPI2C_MasterEnableDMA(LPI2C_Type *base, bool enableTx, bool enableRx)
+{
+ base->MDER = LPI2C_MDER_TDDE(enableTx) | LPI2C_MDER_RDDE(enableRx);
+}
+
+/*!
+ * @brief Gets LPI2C master transmit data register address for DMA transfer.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @return The LPI2C Master Transmit Data Register address.
+ */
+static inline uint32_t LPI2C_MasterGetTxFifoAddress(LPI2C_Type *base)
+{
+ return (uint32_t)&base->MTDR;
+}
+
+/*!
+ * @brief Gets LPI2C master receive data register address for DMA transfer.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @return The LPI2C Master Receive Data Register address.
+ */
+static inline uint32_t LPI2C_MasterGetRxFifoAddress(LPI2C_Type *base)
+{
+ return (uint32_t)&base->MRDR;
+}
+
+/*@}*/
+
+/*! @name FIFO control */
+/*@{*/
+
+/*!
+ * @brief Sets the watermarks for LPI2C master FIFOs.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param txWords Transmit FIFO watermark value in words. The #kLPI2C_MasterTxReadyFlag flag is set whenever
+ * the number of words in the transmit FIFO is equal or less than @a txWords. Writing a value equal or
+ * greater than the FIFO size is truncated.
+ * @param rxWords Receive FIFO watermark value in words. The #kLPI2C_MasterRxReadyFlag flag is set whenever
+ * the number of words in the receive FIFO is greater than @a rxWords. Writing a value equal or greater
+ * than the FIFO size is truncated.
+ */
+static inline void LPI2C_MasterSetWatermarks(LPI2C_Type *base, size_t txWords, size_t rxWords)
+{
+ base->MFCR = LPI2C_MFCR_TXWATER(txWords) | LPI2C_MFCR_RXWATER(rxWords);
+}
+
+/*!
+ * @brief Gets the current number of words in the LPI2C master FIFOs.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param[out] txCount Pointer through which the current number of words in the transmit FIFO is returned.
+ * Pass NULL if this value is not required.
+ * @param[out] rxCount Pointer through which the current number of words in the receive FIFO is returned.
+ * Pass NULL if this value is not required.
+ */
+static inline void LPI2C_MasterGetFifoCounts(LPI2C_Type *base, size_t *rxCount, size_t *txCount)
+{
+ if (NULL != txCount)
+ {
+ *txCount = (base->MFSR & LPI2C_MFSR_TXCOUNT_MASK) >> LPI2C_MFSR_TXCOUNT_SHIFT;
+ }
+ if (NULL != rxCount)
+ {
+ *rxCount = (base->MFSR & LPI2C_MFSR_RXCOUNT_MASK) >> LPI2C_MFSR_RXCOUNT_SHIFT;
+ }
+}
+
+/*@}*/
+
+/*! @name Bus operations */
+/*@{*/
+
+/*!
+ * @brief Sets the I2C bus frequency for master transactions.
+ *
+ * The LPI2C master is automatically disabled and re-enabled as necessary to configure the baud
+ * rate. Do not call this function during a transfer, or the transfer is aborted.
+ *
+ * @note Please note that the second parameter is the clock frequency of LPI2C module, the third
+ * parameter means user configured bus baudrate, this implementation is different from other I2C drivers
+ * which use baudrate configuration as second parameter and source clock frequency as third parameter.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param sourceClock_Hz LPI2C functional clock frequency in Hertz.
+ * @param baudRate_Hz Requested bus frequency in Hertz.
+ */
+void LPI2C_MasterSetBaudRate(LPI2C_Type *base, uint32_t sourceClock_Hz, uint32_t baudRate_Hz);
+
+/*!
+ * @brief Returns whether the bus is idle.
+ *
+ * Requires the master mode to be enabled.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @retval true Bus is busy.
+ * @retval false Bus is idle.
+ */
+static inline bool LPI2C_MasterGetBusIdleState(LPI2C_Type *base)
+{
+ return ((base->MSR & LPI2C_MSR_BBF_MASK) >> LPI2C_MSR_BBF_SHIFT) == 1U ? true : false;
+}
+
+/*!
+ * @brief Sends a START signal and slave address on the I2C bus.
+ *
+ * This function is used to initiate a new master mode transfer. First, the bus state is checked to ensure
+ * that another master is not occupying the bus. Then a START signal is transmitted, followed by the
+ * 7-bit address specified in the @a address parameter. Note that this function does not actually wait
+ * until the START and address are successfully sent on the bus before returning.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param address 7-bit slave device address, in bits [6:0].
+ * @param dir Master transfer direction, either #kLPI2C_Read or #kLPI2C_Write. This parameter is used to set
+ * the R/w bit (bit 0) in the transmitted slave address.
+ * @retval kStatus_Success START signal and address were successfully enqueued in the transmit FIFO.
+ * @retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ */
+status_t LPI2C_MasterStart(LPI2C_Type *base, uint8_t address, lpi2c_direction_t dir);
+
+/*!
+ * @brief Sends a repeated START signal and slave address on the I2C bus.
+ *
+ * This function is used to send a Repeated START signal when a transfer is already in progress. Like
+ * LPI2C_MasterStart(), it also sends the specified 7-bit address.
+ *
+ * @note This function exists primarily to maintain compatible APIs between LPI2C and I2C drivers,
+ * as well as to better document the intent of code that uses these APIs.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param address 7-bit slave device address, in bits [6:0].
+ * @param dir Master transfer direction, either #kLPI2C_Read or #kLPI2C_Write. This parameter is used to set
+ * the R/w bit (bit 0) in the transmitted slave address.
+ * @retval kStatus_Success Repeated START signal and address were successfully enqueued in the transmit FIFO.
+ * @retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ */
+static inline status_t LPI2C_MasterRepeatedStart(LPI2C_Type *base, uint8_t address, lpi2c_direction_t dir)
+{
+ return LPI2C_MasterStart(base, address, dir);
+}
+
+/*!
+ * @brief Performs a polling send transfer on the I2C bus.
+ *
+ * Sends up to @a txSize number of bytes to the previously addressed slave device. The slave may
+ * reply with a NAK to any byte in order to terminate the transfer early. If this happens, this
+ * function returns #kStatus_LPI2C_Nak.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param txBuff The pointer to the data to be transferred.
+ * @param txSize The length in bytes of the data to be transferred.
+ * @retval kStatus_Success Data was sent successfully.
+ * @retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ * @retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte.
+ * @retval #kStatus_LPI2C_FifoError FIFO under run or over run.
+ * @retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error.
+ * @retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout.
+ */
+status_t LPI2C_MasterSend(LPI2C_Type *base, void *txBuff, size_t txSize);
+
+/*!
+ * @brief Performs a polling receive transfer on the I2C bus.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param rxBuff The pointer to the data to be transferred.
+ * @param rxSize The length in bytes of the data to be transferred.
+ * @retval kStatus_Success Data was received successfully.
+ * @retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ * @retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte.
+ * @retval #kStatus_LPI2C_FifoError FIFO under run or overrun.
+ * @retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error.
+ * @retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout.
+ */
+status_t LPI2C_MasterReceive(LPI2C_Type *base, void *rxBuff, size_t rxSize);
+
+/*!
+ * @brief Sends a STOP signal on the I2C bus.
+ *
+ * This function does not return until the STOP signal is seen on the bus, or an error occurs.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @retval kStatus_Success The STOP signal was successfully sent on the bus and the transaction terminated.
+ * @retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ * @retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte.
+ * @retval #kStatus_LPI2C_FifoError FIFO under run or overrun.
+ * @retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error.
+ * @retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout.
+ */
+status_t LPI2C_MasterStop(LPI2C_Type *base);
+
+/*!
+ * @brief Performs a master polling transfer on the I2C bus.
+ *
+ * @note The API does not return until the transfer succeeds or fails due
+ * to error happens during transfer.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param transfer Pointer to the transfer structure.
+ * @retval kStatus_Success Data was received successfully.
+ * @retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ * @retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte.
+ * @retval #kStatus_LPI2C_FifoError FIFO under run or overrun.
+ * @retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error.
+ * @retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout.
+ */
+status_t LPI2C_MasterTransferBlocking(LPI2C_Type *base, lpi2c_master_transfer_t *transfer);
+
+/*@}*/
+
+/*! @name Non-blocking */
+/*@{*/
+
+/*!
+ * @brief Creates a new handle for the LPI2C master non-blocking APIs.
+ *
+ * The creation of a handle is for use with the non-blocking APIs. Once a handle
+ * is created, there is not a corresponding destroy handle. If the user wants to
+ * terminate a transfer, the LPI2C_MasterTransferAbort() API shall be called.
+ *
+ *
+ * @note The function also enables the NVIC IRQ for the input LPI2C. Need to notice
+ * that on some SoCs the LPI2C IRQ is connected to INTMUX, in this case user needs to
+ * enable the associated INTMUX IRQ in application.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param[out] handle Pointer to the LPI2C master driver handle.
+ * @param callback User provided pointer to the asynchronous callback function.
+ * @param userData User provided pointer to the application callback data.
+ */
+void LPI2C_MasterTransferCreateHandle(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_master_transfer_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief Performs a non-blocking transaction on the I2C bus.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param handle Pointer to the LPI2C master driver handle.
+ * @param transfer The pointer to the transfer descriptor.
+ * @retval kStatus_Success The transaction was started successfully.
+ * @retval #kStatus_LPI2C_Busy Either another master is currently utilizing the bus, or a non-blocking
+ * transaction is already in progress.
+ */
+status_t LPI2C_MasterTransferNonBlocking(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_master_transfer_t *transfer);
+
+/*!
+ * @brief Returns number of bytes transferred so far.
+ * @param base The LPI2C peripheral base address.
+ * @param handle Pointer to the LPI2C master driver handle.
+ * @param[out] count Number of bytes transferred so far by the non-blocking transaction.
+ * @retval kStatus_Success
+ * @retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t LPI2C_MasterTransferGetCount(LPI2C_Type *base, lpi2c_master_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Terminates a non-blocking LPI2C master transmission early.
+ *
+ * @note It is not safe to call this function from an IRQ handler that has a higher priority than the
+ * LPI2C peripheral's IRQ priority.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param handle Pointer to the LPI2C master driver handle.
+ * @retval kStatus_Success A transaction was successfully aborted.
+ * @retval #kStatus_LPI2C_Idle There is not a non-blocking transaction currently in progress.
+ */
+void LPI2C_MasterTransferAbort(LPI2C_Type *base, lpi2c_master_handle_t *handle);
+
+/*@}*/
+
+/*! @name IRQ handler */
+/*@{*/
+
+/*!
+ * @brief Reusable routine to handle master interrupts.
+ * @note This function does not need to be called unless you are reimplementing the
+ * nonblocking API's interrupt handler routines to add special functionality.
+ * @param base The LPI2C peripheral base address.
+ * @param lpi2cMasterHandle Pointer to the LPI2C master driver handle.
+ */
+void LPI2C_MasterTransferHandleIRQ(LPI2C_Type *base, void *lpi2cMasterHandle);
+
+/*@}*/
+
+/*! @} */
+
+/*!
+ * @addtogroup lpi2c_slave_driver
+ * @{
+ */
+
+/*! @name Slave initialization and deinitialization */
+/*@{*/
+
+/*!
+ * @brief Provides a default configuration for the LPI2C slave peripheral.
+ *
+ * This function provides the following default configuration for the LPI2C slave peripheral:
+ * @code
+ * slaveConfig->enableSlave = true;
+ * slaveConfig->address0 = 0U;
+ * slaveConfig->address1 = 0U;
+ * slaveConfig->addressMatchMode = kLPI2C_MatchAddress0;
+ * slaveConfig->filterDozeEnable = true;
+ * slaveConfig->filterEnable = true;
+ * slaveConfig->enableGeneralCall = false;
+ * slaveConfig->sclStall.enableAck = false;
+ * slaveConfig->sclStall.enableTx = true;
+ * slaveConfig->sclStall.enableRx = true;
+ * slaveConfig->sclStall.enableAddress = true;
+ * slaveConfig->ignoreAck = false;
+ * slaveConfig->enableReceivedAddressRead = false;
+ * slaveConfig->sdaGlitchFilterWidth_ns = 0;
+ * slaveConfig->sclGlitchFilterWidth_ns = 0;
+ * slaveConfig->dataValidDelay_ns = 0;
+ * slaveConfig->clockHoldTime_ns = 0;
+ * @endcode
+ *
+ * After calling this function, override any settings to customize the configuration,
+ * prior to initializing the master driver with LPI2C_SlaveInit(). Be sure to override at least the @a
+ * address0 member of the configuration structure with the desired slave address.
+ *
+ * @param[out] slaveConfig User provided configuration structure that is set to default values. Refer to
+ * #lpi2c_slave_config_t.
+ */
+void LPI2C_SlaveGetDefaultConfig(lpi2c_slave_config_t *slaveConfig);
+
+/*!
+ * @brief Initializes the LPI2C slave peripheral.
+ *
+ * This function enables the peripheral clock and initializes the LPI2C slave peripheral as described by the user
+ * provided configuration.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param slaveConfig User provided peripheral configuration. Use LPI2C_SlaveGetDefaultConfig() to get a set of defaults
+ * that you can override.
+ * @param sourceClock_Hz Frequency in Hertz of the LPI2C functional clock. Used to calculate the filter widths,
+ * data valid delay, and clock hold time.
+ */
+void LPI2C_SlaveInit(LPI2C_Type *base, const lpi2c_slave_config_t *slaveConfig, uint32_t sourceClock_Hz);
+
+/*!
+ * @brief Deinitializes the LPI2C slave peripheral.
+ *
+ * This function disables the LPI2C slave peripheral and gates the clock. It also performs a software
+ * reset to restore the peripheral to reset conditions.
+ *
+ * @param base The LPI2C peripheral base address.
+ */
+void LPI2C_SlaveDeinit(LPI2C_Type *base);
+
+/*!
+ * @brief Performs a software reset of the LPI2C slave peripheral.
+ *
+ * @param base The LPI2C peripheral base address.
+ */
+static inline void LPI2C_SlaveReset(LPI2C_Type *base)
+{
+ base->SCR = LPI2C_SCR_RST_MASK;
+ base->SCR = 0;
+}
+
+/*!
+ * @brief Enables or disables the LPI2C module as slave.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param enable Pass true to enable or false to disable the specified LPI2C as slave.
+ */
+static inline void LPI2C_SlaveEnable(LPI2C_Type *base, bool enable)
+{
+ base->SCR = (base->SCR & ~LPI2C_SCR_SEN_MASK) | LPI2C_SCR_SEN(enable);
+}
+
+/*@}*/
+
+/*! @name Slave status */
+/*@{*/
+
+/*!
+ * @brief Gets the LPI2C slave status flags.
+ *
+ * A bit mask with the state of all LPI2C slave status flags is returned. For each flag, the corresponding bit
+ * in the return value is set if the flag is asserted.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @return State of the status flags:
+ * - 1: related status flag is set.
+ * - 0: related status flag is not set.
+ * @see _lpi2c_slave_flags
+ */
+static inline uint32_t LPI2C_SlaveGetStatusFlags(LPI2C_Type *base)
+{
+ return base->SSR;
+}
+
+/*!
+ * @brief Clears the LPI2C status flag state.
+ *
+ * The following status register flags can be cleared:
+ * - #kLPI2C_SlaveRepeatedStartDetectFlag
+ * - #kLPI2C_SlaveStopDetectFlag
+ * - #kLPI2C_SlaveBitErrFlag
+ * - #kLPI2C_SlaveFifoErrFlag
+ *
+ * Attempts to clear other flags has no effect.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param statusMask A bitmask of status flags that are to be cleared. The mask is composed of
+ * #_lpi2c_slave_flags enumerators OR'd together. You may pass the result of a previous call to
+ * LPI2C_SlaveGetStatusFlags().
+ * @see _lpi2c_slave_flags.
+ */
+static inline void LPI2C_SlaveClearStatusFlags(LPI2C_Type *base, uint32_t statusMask)
+{
+ base->SSR = statusMask;
+}
+
+/*@}*/
+
+/*! @name Slave interrupts */
+/*@{*/
+
+/*!
+ * @brief Enables the LPI2C slave interrupt requests.
+ *
+ * All flags except #kLPI2C_SlaveBusyFlag and #kLPI2C_SlaveBusBusyFlag can be enabled as
+ * interrupts.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param interruptMask Bit mask of interrupts to enable. See #_lpi2c_slave_flags for the set
+ * of constants that should be OR'd together to form the bit mask.
+ */
+static inline void LPI2C_SlaveEnableInterrupts(LPI2C_Type *base, uint32_t interruptMask)
+{
+ base->SIER |= interruptMask;
+}
+
+/*!
+ * @brief Disables the LPI2C slave interrupt requests.
+ *
+ * All flags except #kLPI2C_SlaveBusyFlag and #kLPI2C_SlaveBusBusyFlag can be enabled as
+ * interrupts.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param interruptMask Bit mask of interrupts to disable. See #_lpi2c_slave_flags for the set
+ * of constants that should be OR'd together to form the bit mask.
+ */
+static inline void LPI2C_SlaveDisableInterrupts(LPI2C_Type *base, uint32_t interruptMask)
+{
+ base->SIER &= ~interruptMask;
+}
+
+/*!
+ * @brief Returns the set of currently enabled LPI2C slave interrupt requests.
+ * @param base The LPI2C peripheral base address.
+ * @return A bitmask composed of #_lpi2c_slave_flags enumerators OR'd together to indicate the
+ * set of enabled interrupts.
+ */
+static inline uint32_t LPI2C_SlaveGetEnabledInterrupts(LPI2C_Type *base)
+{
+ return base->SIER;
+}
+
+/*@}*/
+
+/*! @name Slave DMA control */
+/*@{*/
+
+/*!
+ * @brief Enables or disables the LPI2C slave peripheral DMA requests.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param enableAddressValid Enable flag for the address valid DMA request. Pass true for enable, false for disable.
+ * The address valid DMA request is shared with the receive data DMA request.
+ * @param enableRx Enable flag for the receive data DMA request. Pass true for enable, false for disable.
+ * @param enableTx Enable flag for the transmit data DMA request. Pass true for enable, false for disable.
+ */
+static inline void LPI2C_SlaveEnableDMA(LPI2C_Type *base, bool enableAddressValid, bool enableRx, bool enableTx)
+{
+ base->SDER = (base->SDER & ~(LPI2C_SDER_AVDE_MASK | LPI2C_SDER_RDDE_MASK | LPI2C_SDER_TDDE_MASK)) |
+ LPI2C_SDER_AVDE(enableAddressValid) | LPI2C_SDER_RDDE(enableRx) | LPI2C_SDER_TDDE(enableTx);
+}
+
+/*@}*/
+
+/*! @name Slave bus operations */
+/*@{*/
+
+/*!
+ * @brief Returns whether the bus is idle.
+ *
+ * Requires the slave mode to be enabled.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @retval true Bus is busy.
+ * @retval false Bus is idle.
+ */
+static inline bool LPI2C_SlaveGetBusIdleState(LPI2C_Type *base)
+{
+ return ((base->SSR & LPI2C_SSR_BBF_MASK) >> LPI2C_SSR_BBF_SHIFT) == 1U ? true : false;
+}
+
+/*!
+ * @brief Transmits either an ACK or NAK on the I2C bus in response to a byte from the master.
+ *
+ * Use this function to send an ACK or NAK when the #kLPI2C_SlaveTransmitAckFlag is asserted. This
+ * only happens if you enable the sclStall.enableAck field of the ::lpi2c_slave_config_t configuration
+ * structure used to initialize the slave peripheral.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param ackOrNack Pass true for an ACK or false for a NAK.
+ */
+static inline void LPI2C_SlaveTransmitAck(LPI2C_Type *base, bool ackOrNack)
+{
+ base->STAR = LPI2C_STAR_TXNACK(!ackOrNack);
+}
+
+/*!
+ * @brief Returns the slave address sent by the I2C master.
+ *
+ * This function should only be called if the #kLPI2C_SlaveAddressValidFlag is asserted.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @return The 8-bit address matched by the LPI2C slave. Bit 0 contains the R/w direction bit, and
+ * the 7-bit slave address is in the upper 7 bits.
+ */
+static inline uint32_t LPI2C_SlaveGetReceivedAddress(LPI2C_Type *base)
+{
+ return base->SASR & LPI2C_SASR_RADDR_MASK;
+}
+
+/*!
+ * @brief Performs a polling send transfer on the I2C bus.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param txBuff The pointer to the data to be transferred.
+ * @param txSize The length in bytes of the data to be transferred.
+ * @param[out] actualTxSize
+ * @return Error or success status returned by API.
+ */
+status_t LPI2C_SlaveSend(LPI2C_Type *base, void *txBuff, size_t txSize, size_t *actualTxSize);
+
+/*!
+ * @brief Performs a polling receive transfer on the I2C bus.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param rxBuff The pointer to the data to be transferred.
+ * @param rxSize The length in bytes of the data to be transferred.
+ * @param[out] actualRxSize
+ * @return Error or success status returned by API.
+ */
+status_t LPI2C_SlaveReceive(LPI2C_Type *base, void *rxBuff, size_t rxSize, size_t *actualRxSize);
+
+/*@}*/
+
+/*! @name Slave non-blocking */
+/*@{*/
+
+/*!
+ * @brief Creates a new handle for the LPI2C slave non-blocking APIs.
+ *
+ * The creation of a handle is for use with the non-blocking APIs. Once a handle
+ * is created, there is not a corresponding destroy handle. If the user wants to
+ * terminate a transfer, the LPI2C_SlaveTransferAbort() API shall be called.
+ *
+ * @note The function also enables the NVIC IRQ for the input LPI2C. Need to notice
+ * that on some SoCs the LPI2C IRQ is connected to INTMUX, in this case user needs to
+ * enable the associated INTMUX IRQ in application.
+
+ * @param base The LPI2C peripheral base address.
+ * @param[out] handle Pointer to the LPI2C slave driver handle.
+ * @param callback User provided pointer to the asynchronous callback function.
+ * @param userData User provided pointer to the application callback data.
+ */
+void LPI2C_SlaveTransferCreateHandle(LPI2C_Type *base,
+ lpi2c_slave_handle_t *handle,
+ lpi2c_slave_transfer_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief Starts accepting slave transfers.
+ *
+ * Call this API after calling I2C_SlaveInit() and LPI2C_SlaveTransferCreateHandle() to start processing
+ * transactions driven by an I2C master. The slave monitors the I2C bus and pass events to the
+ * callback that was passed into the call to LPI2C_SlaveTransferCreateHandle(). The callback is always invoked
+ * from the interrupt context.
+ *
+ * The set of events received by the callback is customizable. To do so, set the @a eventMask parameter to
+ * the OR'd combination of #lpi2c_slave_transfer_event_t enumerators for the events you wish to receive.
+ * The #kLPI2C_SlaveTransmitEvent and #kLPI2C_SlaveReceiveEvent events are always enabled and do not need
+ * to be included in the mask. Alternatively, you can pass 0 to get a default set of only the transmit and
+ * receive events that are always enabled. In addition, the #kLPI2C_SlaveAllEvents constant is provided as
+ * a convenient way to enable all events.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param handle Pointer to lpi2c_slave_handle_t structure which stores the transfer state.
+ * @param eventMask Bit mask formed by OR'ing together #lpi2c_slave_transfer_event_t enumerators to specify
+ * which events to send to the callback. Other accepted values are 0 to get a default set of
+ * only the transmit and receive events, and #kLPI2C_SlaveAllEvents to enable all events.
+ *
+ * @retval kStatus_Success Slave transfers were successfully started.
+ * @retval #kStatus_LPI2C_Busy Slave transfers have already been started on this handle.
+ */
+status_t LPI2C_SlaveTransferNonBlocking(LPI2C_Type *base, lpi2c_slave_handle_t *handle, uint32_t eventMask);
+
+/*!
+ * @brief Gets the slave transfer status during a non-blocking transfer.
+ * @param base The LPI2C peripheral base address.
+ * @param handle Pointer to i2c_slave_handle_t structure.
+ * @param[out] count Pointer to a value to hold the number of bytes transferred. May be NULL if the count is not
+ * required.
+ * @retval kStatus_Success
+ * @retval kStatus_NoTransferInProgress
+ */
+status_t LPI2C_SlaveTransferGetCount(LPI2C_Type *base, lpi2c_slave_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Aborts the slave non-blocking transfers.
+ * @note This API could be called at any time to stop slave for handling the bus events.
+ * @param base The LPI2C peripheral base address.
+ * @param handle Pointer to lpi2c_slave_handle_t structure which stores the transfer state.
+ * @retval kStatus_Success
+ * @retval #kStatus_LPI2C_Idle
+ */
+void LPI2C_SlaveTransferAbort(LPI2C_Type *base, lpi2c_slave_handle_t *handle);
+
+/*@}*/
+
+/*! @name Slave IRQ handler */
+/*@{*/
+
+/*!
+ * @brief Reusable routine to handle slave interrupts.
+ * @note This function does not need to be called unless you are reimplementing the
+ * non blocking API's interrupt handler routines to add special functionality.
+ * @param base The LPI2C peripheral base address.
+ * @param handle Pointer to lpi2c_slave_handle_t structure which stores the transfer state.
+ */
+void LPI2C_SlaveTransferHandleIRQ(LPI2C_Type *base, lpi2c_slave_handle_t *handle);
+
+/*@}*/
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* _FSL_LPI2C_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_edma.c b/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_edma.c
new file mode 100644
index 0000000000..7e28c7e693
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_edma.c
@@ -0,0 +1,616 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2021 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_lpi2c_edma.h"
+#include <stdlib.h>
+#include <string.h>
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.lpi2c_edma"
+#endif
+
+/* @brief Mask to align an address to 32 bytes. */
+#define ALIGN_32_MASK (0x1fU)
+
+/* ! @brief LPI2C master fifo commands. */
+enum _lpi2c_master_fifo_cmd
+{
+ kTxDataCmd = LPI2C_MTDR_CMD(0x0U), /*!< Transmit DATA[7:0] */
+ kRxDataCmd = LPI2C_MTDR_CMD(0X1U), /*!< Receive (DATA[7:0] + 1) bytes */
+ kStopCmd = LPI2C_MTDR_CMD(0x2U), /*!< Generate STOP condition */
+ kStartCmd = LPI2C_MTDR_CMD(0x4U), /*!< Generate(repeated) START and transmit address in DATA[[7:0] */
+};
+
+/*! @brief States for the state machine used by transactional APIs. */
+enum _lpi2c_transfer_states
+{
+ kIdleState = 0,
+ kSendCommandState,
+ kIssueReadCommandState,
+ kTransferDataState,
+ kStopState,
+ kWaitForCompletionState,
+};
+
+/*! @brief Typedef for interrupt handler. */
+typedef void (*lpi2c_isr_t)(LPI2C_Type *base, void *handle);
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Prepares the command buffer with the sequence of commands needed to send the requested transaction.
+ * @param handle Master DMA driver handle.
+ * @return Number of command words.
+ */
+static uint32_t LPI2C_GenerateCommands(lpi2c_master_edma_handle_t *handle);
+
+/*!
+ * @brief DMA completion callback.
+ * @param dmaHandle DMA channel handle for the channel that completed.
+ * @param userData User data associated with the channel handle. For this callback, the user data is the
+ * LPI2C DMA driver handle.
+ * @param isTransferDone Whether the DMA transfer has completed.
+ * @param tcds Number of TCDs that completed.
+ */
+static void LPI2C_MasterEDMACallback(edma_handle_t *dmaHandle, void *userData, bool isTransferDone, uint32_t tcds);
+
+/*!
+ * @brief LPI2C master edma transfer IRQ handle routine.
+ *
+ * This API handles the LPI2C bus error status and invoke callback if needed.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param lpi2cMasterEdmaHandle Pointer to the LPI2C master edma handle.
+ */
+static void LPI2C_MasterTransferEdmaHandleIRQ(LPI2C_Type *base, void *lpi2cMasterEdmaHandle);
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+static uint32_t lpi2c_edma_RecSetting = 0x02;
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * brief Create a new handle for the LPI2C master DMA APIs.
+ *
+ * The creation of a handle is for use with the DMA APIs. Once a handle
+ * is created, there is not a corresponding destroy handle. If the user wants to
+ * terminate a transfer, the LPI2C_MasterTransferAbortEDMA() API shall be called.
+ *
+ * For devices where the LPI2C send and receive DMA requests are OR'd together, the a txDmaHandle
+ * parameter is ignored and may be set to NULL.
+ *
+ * param base The LPI2C peripheral base address.
+ * param[out] handle Pointer to the LPI2C master driver handle.
+ * param rxDmaHandle Handle for the eDMA receive channel. Created by the user prior to calling this function.
+ * param txDmaHandle Handle for the eDMA transmit channel. Created by the user prior to calling this function.
+ * param callback User provided pointer to the asynchronous callback function.
+ * param userData User provided pointer to the application callback data.
+ */
+void LPI2C_MasterCreateEDMAHandle(LPI2C_Type *base,
+ lpi2c_master_edma_handle_t *handle,
+ edma_handle_t *rxDmaHandle,
+ edma_handle_t *txDmaHandle,
+ lpi2c_master_edma_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle != NULL);
+ assert(rxDmaHandle != NULL);
+ assert(txDmaHandle != NULL);
+
+ /* Look up instance number */
+ uint32_t instance = LPI2C_GetInstance(base);
+
+ /* Clear out the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set up the handle. For combined rx/tx DMA requests, the tx channel handle is set to the rx handle */
+ /* in order to make the transfer API code simpler. */
+ handle->base = base;
+ handle->completionCallback = callback;
+ handle->userData = userData;
+ handle->rx = rxDmaHandle;
+ handle->tx = (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) > 0) ? txDmaHandle : rxDmaHandle;
+
+ /* Save the handle in global variables to support the double weak mechanism. */
+ s_lpi2cMasterHandle[instance] = handle;
+
+ /* Set LPI2C_MasterTransferEdmaHandleIRQ as LPI2C DMA IRQ handler */
+ s_lpi2cMasterIsr = LPI2C_MasterTransferEdmaHandleIRQ;
+
+ /* Enable interrupt in NVIC. */
+ (void)EnableIRQ(kLpi2cIrqs[instance]);
+
+ /* Set DMA channel completion callbacks. */
+ EDMA_SetCallback(handle->rx, LPI2C_MasterEDMACallback, handle);
+ if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
+ {
+ EDMA_SetCallback(handle->tx, LPI2C_MasterEDMACallback, handle);
+ }
+}
+
+static uint32_t LPI2C_GenerateCommands(lpi2c_master_edma_handle_t *handle)
+{
+ lpi2c_master_transfer_t *xfer = &handle->transfer;
+ uint16_t *cmd = (uint16_t *)&handle->commandBuffer;
+ uint32_t cmdCount = 0;
+
+ /* Handle no start option. */
+ if ((xfer->flags & (uint32_t)kLPI2C_TransferNoStartFlag) != 0U)
+ {
+ if (xfer->direction == kLPI2C_Read)
+ {
+ /* Need to issue read command first. */
+ cmd[cmdCount++] = (uint16_t)kRxDataCmd | (uint16_t)LPI2C_MTDR_DATA(xfer->dataSize - 1U);
+ }
+ }
+ else
+ {
+ /*
+ * Initial direction depends on whether a subaddress was provided, and of course the actual
+ * data transfer direction.
+ */
+ lpi2c_direction_t direction = (xfer->subaddressSize != 0U) ? kLPI2C_Write : xfer->direction;
+
+ /* Start command. */
+ cmd[cmdCount++] =
+ (uint16_t)kStartCmd | (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)direction);
+
+ /* Subaddress, MSB first. */
+ if (xfer->subaddressSize != 0U)
+ {
+ uint32_t subaddressRemaining = xfer->subaddressSize;
+ while (0U != subaddressRemaining--)
+ {
+ uint8_t subaddressByte = (uint8_t)(xfer->subaddress >> (8U * subaddressRemaining)) & 0xffU;
+ cmd[cmdCount++] = subaddressByte;
+ }
+ }
+
+ /* Reads need special handling because we have to issue a read command and maybe a repeated start. */
+ if ((xfer->dataSize != 0U) && (xfer->direction == kLPI2C_Read))
+ {
+ /* Need to send repeated start if switching directions to read. */
+ if (direction == kLPI2C_Write)
+ {
+ cmd[cmdCount++] = (uint16_t)kStartCmd |
+ (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)kLPI2C_Read);
+ }
+
+ /* Read command. A single write to MTDR can issue read operation of 0xFFU + 1 byte of data at most, so when
+ the dataSize is larger than 0x100U, push multiple read commands to MTDR until dataSize is reached. */
+ size_t tmpRxSize = xfer->dataSize;
+ while (tmpRxSize != 0U)
+ {
+ if (tmpRxSize > 256U)
+ {
+ cmd[cmdCount++] = (uint16_t)kRxDataCmd | (uint16_t)LPI2C_MTDR_DATA(0xFFU);
+ tmpRxSize -= 256U;
+ }
+ else
+ {
+ cmd[cmdCount++] = (uint16_t)kRxDataCmd | (uint16_t)LPI2C_MTDR_DATA(tmpRxSize - 1U);
+ tmpRxSize = 0U;
+ }
+ }
+ }
+ }
+
+ return cmdCount;
+}
+
+/*!
+ * brief Performs a non-blocking DMA-based transaction on the I2C bus.
+ *
+ * The callback specified when the a handle was created is invoked when the transaction has
+ * completed.
+ *
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to the LPI2C master driver handle.
+ * param transfer The pointer to the transfer descriptor.
+ * retval #kStatus_Success The transaction was started successfully.
+ * retval #kStatus_LPI2C_Busy Either another master is currently utilizing the bus, or another DMA
+ * transaction is already in progress.
+ */
+status_t LPI2C_MasterTransferEDMA(LPI2C_Type *base,
+ lpi2c_master_edma_handle_t *handle,
+ lpi2c_master_transfer_t *transfer)
+{
+ status_t result;
+
+ assert(handle != NULL);
+ assert(transfer != NULL);
+ assert(transfer->subaddressSize <= sizeof(transfer->subaddress));
+
+ /* Check transfer data size in read operation. */
+ /* A single write to MTDR can issue read operation of 0xFFU + 1 byte of data at most, so when the dataSize is larger
+ than 0x100U, push multiple read commands to MTDR until dataSize is reached. LPI2C edma transfer uses linked
+ descriptor to transfer command and data, the command buffer is stored in handle. Allocate 4 command words to
+ carry read command which can cover nearly all use cases. */
+ if ((transfer->direction == kLPI2C_Read) && (transfer->dataSize > (256U * 4U)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Return busy if another transaction is in progress. */
+ if (handle->isBusy)
+ {
+ return kStatus_LPI2C_Busy;
+ }
+
+ /* Enable the master function and disable the slave function. */
+ LPI2C_MasterEnable(base, true);
+ LPI2C_SlaveEnable(base, false);
+
+ /* Return an error if the bus is already in use not by us. */
+ result = LPI2C_CheckForBusyBus(base);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+
+ /* We're now busy. */
+ handle->isBusy = true;
+
+ /* Disable LPI2C IRQ and DMA sources while we configure stuff. */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
+ LPI2C_MasterEnableDMA(base, false, false);
+
+ /* Clear all flags. */
+ LPI2C_MasterClearStatusFlags(base, (uint32_t)kLPI2C_MasterClearFlags);
+
+ /* Save transfer into handle. */
+ handle->transfer = *transfer;
+
+ /* Generate commands to send. */
+ uint32_t commandCount = LPI2C_GenerateCommands(handle);
+
+ /* If the user is transmitting no data with no start or stop, then just go ahead and invoke the callback. */
+ if ((0U == commandCount) && (transfer->dataSize == 0U))
+ {
+ if (handle->completionCallback != NULL)
+ {
+ handle->completionCallback(base, handle, kStatus_Success, handle->userData);
+ }
+ return kStatus_Success;
+ }
+
+ /* Reset DMA channels. */
+ EDMA_ResetChannel(handle->rx->base, handle->rx->channel);
+ if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
+ {
+ EDMA_ResetChannel(handle->tx->base, handle->tx->channel);
+ }
+
+ /* Get a 32-byte aligned TCD pointer. */
+ edma_tcd_t *tcd = (edma_tcd_t *)((uint32_t)(&handle->tcds[1]) & (~ALIGN_32_MASK));
+
+ bool hasSendData = (transfer->direction == kLPI2C_Write) && (transfer->dataSize != 0U);
+ bool hasReceiveData = (transfer->direction == kLPI2C_Read) && (transfer->dataSize != 0U);
+
+ edma_transfer_config_t transferConfig = {0};
+ edma_tcd_t *linkTcd = NULL;
+
+ /* Set up data transmit. */
+ if (hasSendData)
+ {
+ uint32_t *srcAddr = (uint32_t *)transfer->data;
+ transferConfig.srcAddr = (uint32_t)srcAddr;
+ transferConfig.destAddr = (uint32_t)LPI2C_MasterGetTxFifoAddress(base);
+ transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfig.srcOffset = (int16_t)sizeof(uint8_t);
+ transferConfig.destOffset = 0;
+ transferConfig.minorLoopBytes = sizeof(uint8_t); /* TODO optimize to fill fifo */
+ transferConfig.majorLoopCounts = transfer->dataSize;
+
+ /* Store the initially configured eDMA minor byte transfer count into the LPI2C handle */
+ handle->nbytes = (uint8_t)transferConfig.minorLoopBytes;
+
+ if (commandCount != 0U)
+ {
+ /* Create a software TCD, which will be chained after the commands. */
+ EDMA_TcdReset(tcd);
+ EDMA_TcdSetTransferConfig(tcd, &transferConfig, NULL);
+ EDMA_TcdEnableInterrupts(tcd, (uint32_t)kEDMA_MajorInterruptEnable);
+ linkTcd = tcd;
+ }
+ else
+ {
+ /* User is only transmitting data with no required commands, so this transfer can stand alone. */
+ EDMA_SetTransferConfig(handle->tx->base, handle->tx->channel, &transferConfig, NULL);
+ EDMA_EnableChannelInterrupts(handle->tx->base, handle->tx->channel, (uint32_t)kEDMA_MajorInterruptEnable);
+ }
+ }
+ else if (hasReceiveData)
+ {
+ uint32_t *srcAddr = (uint32_t *)transfer->data;
+ /* Set up data receive. */
+ transferConfig.srcAddr = (uint32_t)LPI2C_MasterGetRxFifoAddress(base);
+ transferConfig.destAddr = (uint32_t)srcAddr;
+ transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfig.srcOffset = 0;
+ transferConfig.destOffset = (int16_t)sizeof(uint8_t);
+ transferConfig.minorLoopBytes = sizeof(uint8_t); /* TODO optimize to empty fifo */
+ transferConfig.majorLoopCounts = transfer->dataSize;
+
+ /* Store the initially configured eDMA minor byte transfer count into the LPI2C handle */
+ handle->nbytes = (uint8_t)transferConfig.minorLoopBytes;
+
+ if ((FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0) || (0U == commandCount))
+ {
+ /* We can put this receive transfer on its own DMA channel. */
+ EDMA_SetTransferConfig(handle->rx->base, handle->rx->channel, &transferConfig, NULL);
+ EDMA_EnableChannelInterrupts(handle->rx->base, handle->rx->channel, (uint32_t)kEDMA_MajorInterruptEnable);
+ }
+ else
+ {
+ /* For shared rx/tx DMA requests, when there are commands, create a software TCD of
+ enabling rx dma and disabling tx dma, which will be chained onto the commands transfer,
+ and create another software TCD of transfering data and chain it onto the last TCD.
+ Notice that in this situation assume tx/rx uses same channel */
+ EDMA_TcdReset(tcd);
+ EDMA_TcdSetTransferConfig(tcd, &transferConfig, NULL);
+ EDMA_TcdEnableInterrupts(tcd, (uint32_t)kEDMA_MajorInterruptEnable);
+
+ transferConfig.srcAddr = (uint32_t)&lpi2c_edma_RecSetting;
+ transferConfig.destAddr = (uint32_t) & (base->MDER);
+ transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfig.srcOffset = 0;
+ transferConfig.destOffset = (int16_t)sizeof(uint8_t);
+ transferConfig.minorLoopBytes = sizeof(uint8_t);
+ transferConfig.majorLoopCounts = 1;
+
+ edma_tcd_t *tcdSetRxClearTxDMA = (edma_tcd_t *)((uint32_t)(&handle->tcds[2]) & (~ALIGN_32_MASK));
+
+ EDMA_TcdReset(tcdSetRxClearTxDMA);
+ EDMA_TcdSetTransferConfig(tcdSetRxClearTxDMA, &transferConfig, tcd);
+ linkTcd = tcdSetRxClearTxDMA;
+ }
+ }
+ else
+ {
+ /* No data to send */
+ }
+
+ /* Set up commands transfer. */
+ if (commandCount != 0U)
+ {
+ transferConfig.srcAddr = (uint32_t)handle->commandBuffer;
+ transferConfig.destAddr = (uint32_t)LPI2C_MasterGetTxFifoAddress(base);
+ transferConfig.srcTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfig.destTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfig.srcOffset = (int16_t)sizeof(uint16_t);
+ transferConfig.destOffset = 0;
+ transferConfig.minorLoopBytes = sizeof(uint16_t); /* TODO optimize to fill fifo */
+ transferConfig.majorLoopCounts = commandCount;
+
+ EDMA_SetTransferConfig(handle->tx->base, handle->tx->channel, &transferConfig, linkTcd);
+ }
+
+ /* Start DMA transfer. */
+ if (hasReceiveData || (0 == FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base)))
+ {
+ EDMA_StartTransfer(handle->rx);
+ }
+
+ if ((hasSendData || (commandCount != 0U)) && (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0))
+ {
+ EDMA_StartTransfer(handle->tx);
+ }
+
+ /* Enable DMA in both directions. This actually kicks of the transfer. */
+ LPI2C_MasterEnableDMA(base, true, true);
+
+ /* Enable all LPI2C master interrupts */
+ LPI2C_MasterEnableInterrupts(base,
+ (uint32_t)kLPI2C_MasterArbitrationLostFlag | (uint32_t)kLPI2C_MasterNackDetectFlag |
+ (uint32_t)kLPI2C_MasterPinLowTimeoutFlag | (uint32_t)kLPI2C_MasterFifoErrFlag);
+
+ return result;
+}
+
+/*!
+ * brief Returns number of bytes transferred so far.
+ *
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to the LPI2C master driver handle.
+ * param[out] count Number of bytes transferred so far by the non-blocking transaction.
+ * retval #kStatus_Success
+ * retval #kStatus_NoTransferInProgress There is not a DMA transaction currently in progress.
+ */
+status_t LPI2C_MasterTransferGetCountEDMA(LPI2C_Type *base, lpi2c_master_edma_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ if (NULL == count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ if (!handle->isBusy)
+ {
+ *count = 0;
+ return kStatus_NoTransferInProgress;
+ }
+
+ uint32_t remaining = handle->transfer.dataSize;
+
+ /* If the DMA is still on a commands transfer that chains to the actual data transfer, */
+ /* we do nothing and return the number of transferred bytes as zero. */
+ if (EDMA_GetNextTCDAddress(handle->tx) == 0U)
+ {
+ if (handle->transfer.direction == kLPI2C_Write)
+ {
+ remaining =
+ (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->tx->base, handle->tx->channel);
+ }
+ else
+ {
+ remaining =
+ (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->rx->base, handle->rx->channel);
+ }
+ }
+
+ *count = handle->transfer.dataSize - remaining;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Terminates a non-blocking LPI2C master transmission early.
+ *
+ * note It is not safe to call this function from an IRQ handler that has a higher priority than the
+ * eDMA peripheral's IRQ priority.
+ *
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to the LPI2C master driver handle.
+ * retval #kStatus_Success A transaction was successfully aborted.
+ * retval #kStatus_LPI2C_Idle There is not a DMA transaction currently in progress.
+ */
+status_t LPI2C_MasterTransferAbortEDMA(LPI2C_Type *base, lpi2c_master_edma_handle_t *handle)
+{
+ /* Catch when there is not an active transfer. */
+ if (!handle->isBusy)
+ {
+ return kStatus_LPI2C_Idle;
+ }
+
+ /* Terminate DMA transfers. */
+ EDMA_AbortTransfer(handle->rx);
+ if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
+ {
+ EDMA_AbortTransfer(handle->tx);
+ }
+
+ /* Reset fifos. */
+ base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
+
+ /* Disable LPI2C interrupts. */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
+
+ /* If master is still busy and has not send out stop signal yet. */
+ if ((LPI2C_MasterGetStatusFlags(base) &
+ ((uint32_t)kLPI2C_MasterStopDetectFlag | (uint32_t)kLPI2C_MasterBusyFlag)) == (uint32_t)kLPI2C_MasterBusyFlag)
+ {
+ /* Send a stop command to finalize the transfer. */
+ base->MTDR = (uint32_t)kStopCmd;
+ }
+
+ /* Reset handle. */
+ handle->isBusy = false;
+
+ return kStatus_Success;
+}
+
+static void LPI2C_MasterEDMACallback(edma_handle_t *dmaHandle, void *userData, bool isTransferDone, uint32_t tcds)
+{
+ lpi2c_master_edma_handle_t *handle = (lpi2c_master_edma_handle_t *)userData;
+
+ if (NULL == handle)
+ {
+ return;
+ }
+
+ /* Check for errors. */
+ status_t result = LPI2C_MasterCheckAndClearError(handle->base, LPI2C_MasterGetStatusFlags(handle->base));
+
+ /* Done with this transaction. */
+ handle->isBusy = false;
+
+ if (0U == (handle->transfer.flags & (uint32_t)kLPI2C_TransferNoStopFlag))
+ {
+ /* Send a stop command to finalize the transfer. */
+ handle->base->MTDR = (uint32_t)kStopCmd;
+ }
+
+ /* Invoke callback. */
+ if (handle->completionCallback != NULL)
+ {
+ handle->completionCallback(handle->base, handle, result, handle->userData);
+ }
+}
+
+static void LPI2C_MasterTransferEdmaHandleIRQ(LPI2C_Type *base, void *lpi2cMasterEdmaHandle)
+{
+ assert(lpi2cMasterEdmaHandle != NULL);
+
+ lpi2c_master_edma_handle_t *handle = (lpi2c_master_edma_handle_t *)lpi2cMasterEdmaHandle;
+ uint32_t status = LPI2C_MasterGetStatusFlags(base);
+ status_t result = kStatus_Success;
+
+ /* Terminate DMA transfers. */
+ EDMA_AbortTransfer(handle->rx);
+ if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
+ {
+ EDMA_AbortTransfer(handle->tx);
+ }
+
+ /* Done with this transaction. */
+ handle->isBusy = false;
+
+ /* Disable LPI2C interrupts. */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
+
+ /* Check error status */
+ if (0U != (status & (uint32_t)kLPI2C_MasterPinLowTimeoutFlag))
+ {
+ result = kStatus_LPI2C_PinLowTimeout;
+ }
+ else if (0U != (status & (uint32_t)kLPI2C_MasterArbitrationLostFlag))
+ {
+ result = kStatus_LPI2C_ArbitrationLost;
+ }
+ else if (0U != (status & (uint32_t)kLPI2C_MasterNackDetectFlag))
+ {
+ result = kStatus_LPI2C_Nak;
+ }
+ else if (0U != (status & (uint32_t)kLPI2C_MasterFifoErrFlag))
+ {
+ result = kStatus_LPI2C_FifoError;
+ }
+ else
+ {
+ ; /* Intentional empty */
+ }
+
+ /* Clear error status. */
+ (void)LPI2C_MasterCheckAndClearError(base, status);
+
+ /* Send stop flag if needed */
+ if (0U == (handle->transfer.flags & (uint32_t)kLPI2C_TransferNoStopFlag))
+ {
+ status = LPI2C_MasterGetStatusFlags(base);
+ /* If bus is still busy and the master has not generate stop flag */
+ if ((status & ((uint32_t)kLPI2C_MasterBusBusyFlag | (uint32_t)kLPI2C_MasterStopDetectFlag)) ==
+ (uint32_t)kLPI2C_MasterBusBusyFlag)
+ {
+ /* Send a stop command to finalize the transfer. */
+ handle->base->MTDR = (uint32_t)kStopCmd;
+ }
+ }
+
+ /* Invoke callback. */
+ if (handle->completionCallback != NULL)
+ {
+ handle->completionCallback(base, handle, result, handle->userData);
+ }
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_edma.h b/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_edma.h
new file mode 100644
index 0000000000..f579086af2
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_edma.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_LPI2C_EDMA_H_
+#define _FSL_LPI2C_EDMA_H_
+
+#include "fsl_lpi2c.h"
+#include "fsl_edma.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief LPI2C EDMA driver version. */
+#define FSL_LPI2C_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 4, 1))
+/*@}*/
+
+/*!
+ * @addtogroup lpi2c_master_edma_driver
+ * @{
+ */
+
+/* Forward declaration of the transfer descriptor and handle typedefs. */
+typedef struct _lpi2c_master_edma_handle lpi2c_master_edma_handle_t;
+
+/*!
+ * @brief Master DMA completion callback function pointer type.
+ *
+ * This callback is used only for the non-blocking master transfer API. Specify the callback you wish to use
+ * in the call to LPI2C_MasterCreateEDMAHandle().
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param handle Handle associated with the completed transfer.
+ * @param completionStatus Either kStatus_Success or an error code describing how the transfer completed.
+ * @param userData Arbitrary pointer-sized value passed from the application.
+ */
+typedef void (*lpi2c_master_edma_transfer_callback_t)(LPI2C_Type *base,
+ lpi2c_master_edma_handle_t *handle,
+ status_t completionStatus,
+ void *userData);
+
+/*!
+ * @brief Driver handle for master DMA APIs.
+ * @note The contents of this structure are private and subject to change.
+ */
+struct _lpi2c_master_edma_handle
+{
+ LPI2C_Type *base; /*!< LPI2C base pointer. */
+ bool isBusy; /*!< Transfer state machine current state. */
+ uint8_t nbytes; /*!< eDMA minor byte transfer count initially configured. */
+ uint16_t commandBuffer[10]; /*!< LPI2C command sequence. When all 10 command words are used:
+ Start&addr&write[1 word] + subaddr[4 words] + restart&addr&read[1 word] + receive&Size[4 words] */
+ lpi2c_master_transfer_t transfer; /*!< Copy of the current transfer info. */
+ lpi2c_master_edma_transfer_callback_t completionCallback; /*!< Callback function pointer. */
+ void *userData; /*!< Application data passed to callback. */
+ edma_handle_t *rx; /*!< Handle for receive DMA channel. */
+ edma_handle_t *tx; /*!< Handle for transmit DMA channel. */
+ edma_tcd_t tcds[3]; /*!< Software TCD. Three are allocated to provide enough room to align to 32-bytes. */
+};
+
+/*! @} */
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @addtogroup lpi2c_master_edma_driver
+ * @{
+ */
+
+/*! @name Master DMA */
+/*@{*/
+
+/*!
+ * @brief Create a new handle for the LPI2C master DMA APIs.
+ *
+ * The creation of a handle is for use with the DMA APIs. Once a handle
+ * is created, there is not a corresponding destroy handle. If the user wants to
+ * terminate a transfer, the LPI2C_MasterTransferAbortEDMA() API shall be called.
+ *
+ * For devices where the LPI2C send and receive DMA requests are OR'd together, the @a txDmaHandle
+ * parameter is ignored and may be set to NULL.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param[out] handle Pointer to the LPI2C master driver handle.
+ * @param rxDmaHandle Handle for the eDMA receive channel. Created by the user prior to calling this function.
+ * @param txDmaHandle Handle for the eDMA transmit channel. Created by the user prior to calling this function.
+ * @param callback User provided pointer to the asynchronous callback function.
+ * @param userData User provided pointer to the application callback data.
+ */
+void LPI2C_MasterCreateEDMAHandle(LPI2C_Type *base,
+ lpi2c_master_edma_handle_t *handle,
+ edma_handle_t *rxDmaHandle,
+ edma_handle_t *txDmaHandle,
+ lpi2c_master_edma_transfer_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief Performs a non-blocking DMA-based transaction on the I2C bus.
+ *
+ * The callback specified when the @a handle was created is invoked when the transaction has
+ * completed.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param handle Pointer to the LPI2C master driver handle.
+ * @param transfer The pointer to the transfer descriptor.
+ * @retval kStatus_Success The transaction was started successfully.
+ * @retval #kStatus_LPI2C_Busy Either another master is currently utilizing the bus, or another DMA
+ * transaction is already in progress.
+ */
+status_t LPI2C_MasterTransferEDMA(LPI2C_Type *base,
+ lpi2c_master_edma_handle_t *handle,
+ lpi2c_master_transfer_t *transfer);
+
+/*!
+ * @brief Returns number of bytes transferred so far.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param handle Pointer to the LPI2C master driver handle.
+ * @param[out] count Number of bytes transferred so far by the non-blocking transaction.
+ * @retval kStatus_Success
+ * @retval kStatus_NoTransferInProgress There is not a DMA transaction currently in progress.
+ */
+status_t LPI2C_MasterTransferGetCountEDMA(LPI2C_Type *base, lpi2c_master_edma_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Terminates a non-blocking LPI2C master transmission early.
+ *
+ * @note It is not safe to call this function from an IRQ handler that has a higher priority than the
+ * eDMA peripheral's IRQ priority.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param handle Pointer to the LPI2C master driver handle.
+ * @retval kStatus_Success A transaction was successfully aborted.
+ * @retval #kStatus_LPI2C_Idle There is not a DMA transaction currently in progress.
+ */
+status_t LPI2C_MasterTransferAbortEDMA(LPI2C_Type *base, lpi2c_master_edma_handle_t *handle);
+
+/*@}*/
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* _FSL_LPI2C_EDMA_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_freertos.h b/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_freertos.h
new file mode 100644
index 0000000000..1b989326e2
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpi2c/fsl_lpi2c_freertos.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __FSL_LPI2C_FREERTOS_H__
+#define __FSL_LPI2C_FREERTOS_H__
+
+#include "FreeRTOS.h"
+#include "portable.h"
+#include "semphr.h"
+
+#include "fsl_lpi2c.h"
+
+/*!
+ * @addtogroup lpi2c_freertos_driver LPI2C FreeRTOS Driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief LPI2C FreeRTOS driver version. */
+#define FSL_LPI2C_FREERTOS_DRIVER_VERSION (MAKE_VERSION(2, 3, 2))
+/*@}*/
+
+/*!
+ * @cond RTOS_PRIVATE
+ * @brief LPI2C FreeRTOS handle
+ */
+typedef struct _lpi2c_rtos_handle
+{
+ LPI2C_Type *base; /*!< LPI2C base address */
+ lpi2c_master_handle_t drv_handle; /*!< Handle of the underlying driver, treated as opaque by the RTOS layer */
+ status_t async_status;
+ SemaphoreHandle_t mutex; /*!< Mutex to lock the handle during a trasfer */
+ SemaphoreHandle_t semaphore; /*!< Semaphore to notify and unblock task when transfer ends */
+} lpi2c_rtos_handle_t;
+/*! \endcond */
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name LPI2C RTOS Operation
+ * @{
+ */
+
+/*!
+ * @brief Initializes LPI2C.
+ *
+ * This function initializes the LPI2C module and related RTOS context.
+ *
+ * @param handle The RTOS LPI2C handle, the pointer to an allocated space for RTOS context.
+ * @param base The pointer base address of the LPI2C instance to initialize.
+ * @param masterConfig Configuration structure to set-up LPI2C in master mode.
+ * @param srcClock_Hz Frequency of input clock of the LPI2C module.
+ * @return status of the operation.
+ */
+status_t LPI2C_RTOS_Init(lpi2c_rtos_handle_t *handle,
+ LPI2C_Type *base,
+ const lpi2c_master_config_t *masterConfig,
+ uint32_t srcClock_Hz);
+
+/*!
+ * @brief Deinitializes the LPI2C.
+ *
+ * This function deinitializes the LPI2C module and related RTOS context.
+ *
+ * @param handle The RTOS LPI2C handle.
+ */
+status_t LPI2C_RTOS_Deinit(lpi2c_rtos_handle_t *handle);
+
+/*!
+ * @brief Performs I2C transfer.
+ *
+ * This function performs an I2C transfer using LPI2C module according to data given in the transfer structure.
+ *
+ * @param handle The RTOS LPI2C handle.
+ * @param transfer Structure specifying the transfer parameters.
+ * @return status of the operation.
+ */
+status_t LPI2C_RTOS_Transfer(lpi2c_rtos_handle_t *handle, lpi2c_master_transfer_t *transfer);
+
+/*!
+ * @}
+ */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+
+#endif /* __FSL_LPI2C_FREERTOS_H__ */