You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ma...@apache.org on 2016/10/11 16:25:30 UTC

[11/45] incubator-mynewt-core git commit: add Kinetis SDK 2.0 built for FRDM-K64F

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f8f2ebbf/hw/mcu/nxp/src/ext/sdk-2.0-frdm-k64f_b160321/devices/MK64F12/drivers/fsl_sai_edma.h
----------------------------------------------------------------------
diff --git a/hw/mcu/nxp/src/ext/sdk-2.0-frdm-k64f_b160321/devices/MK64F12/drivers/fsl_sai_edma.h b/hw/mcu/nxp/src/ext/sdk-2.0-frdm-k64f_b160321/devices/MK64F12/drivers/fsl_sai_edma.h
new file mode 100644
index 0000000..44506fa
--- /dev/null
+++ b/hw/mcu/nxp/src/ext/sdk-2.0-frdm-k64f_b160321/devices/MK64F12/drivers/fsl_sai_edma.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ *   of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ *   list of conditions and the following disclaimer in the documentation and/or
+ *   other materials provided with the distribution.
+ *
+ * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _FSL_SAI_EDMA_H_
+#define _FSL_SAI_EDMA_H_
+
+#include "fsl_sai.h"
+#include "fsl_edma.h"
+
+/*!
+ * @addtogroup sai_edma
+ * @{
+ */
+
+/*! @file */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+typedef struct _sai_edma_handle sai_edma_handle_t;
+
+/*! @brief SAI eDMA transfer callback function for finish and error */
+typedef void (*sai_edma_callback_t)(I2S_Type *base, sai_edma_handle_t *handle, status_t status, void *userData);
+
+/*! @brief SAI DMA transfer handle, users should not touch the content of the handle.*/
+struct _sai_edma_handle
+{
+    edma_handle_t *dmaHandle;                     /*!< DMA handler for SAI send */
+    uint8_t bytesPerFrame;                        /*!< Bytes in a frame */
+    uint8_t channel;                              /*!< Which data channel */
+    uint8_t count;                                /*!< The transfer data count in a DMA request */
+    uint32_t state;                               /*!< Internal state for SAI eDMA transfer */
+    sai_edma_callback_t callback;                 /*!< Callback for users while transfer finish or error occurs */
+    void *userData;                               /*!< User callback parameter */
+    edma_tcd_t tcd[SAI_XFER_QUEUE_SIZE + 1U];     /*!< TCD pool for eDMA transfer. */
+    sai_transfer_t saiQueue[SAI_XFER_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer. */
+    size_t transferSize[SAI_XFER_QUEUE_SIZE];     /*!< Data bytes need to transfer */
+    volatile uint8_t queueUser;                   /*!< Index for user to queue transfer. */
+    volatile uint8_t queueDriver;                 /*!< Index for driver to get the transfer data and size */
+};
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name eDMA Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the SAI eDMA handle.
+ *
+ * This function initializes the SAI master DMA handle, which can be used for other SAI master transactional APIs.
+ * Usually, for a specified SAI instance, call this API once to get the initialized handle.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ * @param base SAI peripheral base address.
+ * @param callback Pointer to user callback function.
+ * @param userData User parameter passed to the callback function.
+ * @param dmaHandle eDMA handle pointer, this handle shall be static allocated by users.
+ */
+void SAI_TransferTxCreateHandleEDMA(
+    I2S_Type *base, sai_edma_handle_t *handle, sai_edma_callback_t callback, void *userData, edma_handle_t *dmaHandle);
+
+/*!
+ * @brief Initializes the SAI Rx eDMA handle.
+ *
+ * This function initializes the SAI slave DMA handle, which can be used for other SAI master transactional APIs.
+ * Usually, for a specified SAI instance, call this API once to get the initialized handle.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ * @param base SAI peripheral base address.
+ * @param callback Pointer to user callback function.
+ * @param userData User parameter passed to the callback function.
+ * @param dmaHandle eDMA handle pointer, this handle shall be static allocated by users.
+ */
+void SAI_TransferRxCreateHandleEDMA(
+    I2S_Type *base, sai_edma_handle_t *handle, sai_edma_callback_t callback, void *userData, edma_handle_t *dmaHandle);
+
+/*!
+ * @brief Configures the SAI Tx audio format.
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred. This function also sets the eDMA parameter according to formatting requirements.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ * @param format Pointer to SAI audio data format structure.
+ * @param mclkSourceClockHz SAI master clock source frequency in Hz.
+ * @param bclkSourceClockHz SAI bit clock source frequency in Hz. If bit clock source is master
+ * clock, this value should equals to masterClockHz in format.
+ * @retval kStatus_Success Audio format set successfully.
+ * @retval kStatus_InvalidArgument The input argument is invalid.
+*/
+void SAI_TransferTxSetFormatEDMA(I2S_Type *base,
+                                 sai_edma_handle_t *handle,
+                                 sai_transfer_format_t *format,
+                                 uint32_t mclkSourceClockHz,
+                                 uint32_t bclkSourceClockHz);
+
+/*!
+ * @brief Configures the SAI Rx audio format.
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred. This function also sets the eDMA parameter according to formatting requirements.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ * @param format Pointer to SAI audio data format structure.
+ * @param mclkSourceClockHz SAI master clock source frequency in Hz.
+ * @param bclkSourceClockHz SAI bit clock source frequency in Hz. If a bit clock source is the master
+ * clock, this value should equal to masterClockHz in format.
+ * @retval kStatus_Success Audio format set successfully.
+ * @retval kStatus_InvalidArgument The input argument is invalid.
+*/
+void SAI_TransferRxSetFormatEDMA(I2S_Type *base,
+                                 sai_edma_handle_t *handle,
+                                 sai_transfer_format_t *format,
+                                 uint32_t mclkSourceClockHz,
+                                 uint32_t bclkSourceClockHz);
+
+/*!
+ * @brief Performs a non-blocking SAI transfer using DMA.
+ *
+ * @note This interface returns immediately after the transfer initiates. Call
+ * SAI_GetTransferStatus to poll the transfer status and check whether the SAI transfer is finished.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ * @param xfer Pointer to the DMA transfer structure.
+ * @retval kStatus_Success Start a SAI eDMA send successfully.
+ * @retval kStatus_InvalidArgument The input argument is invalid.
+ * @retval kStatus_TxBusy SAI is busy sending data.
+ */
+status_t SAI_TransferSendEDMA(I2S_Type *base, sai_edma_handle_t *handle, sai_transfer_t *xfer);
+
+/*!
+ * @brief Performs a non-blocking SAI receive using eDMA.
+ *
+ * @note This interface returns immediately after the transfer initiates. Call
+ * the SAI_GetReceiveRemainingBytes to poll the transfer status and check whether the SAI transfer is finished.
+ *
+ * @param base SAI base pointer
+ * @param handle SAI eDMA handle pointer.
+ * @param xfer Pointer to DMA transfer structure.
+ * @retval kStatus_Success Start a SAI eDMA receive successfully.
+ * @retval kStatus_InvalidArgument The input argument is invalid.
+ * @retval kStatus_RxBusy SAI is busy receiving data.
+ */
+status_t SAI_TransferReceiveEDMA(I2S_Type *base, sai_edma_handle_t *handle, sai_transfer_t *xfer);
+
+/*!
+ * @brief Aborts a SAI transfer using eDMA.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ */
+void SAI_TransferAbortSendEDMA(I2S_Type *base, sai_edma_handle_t *handle);
+
+/*!
+ * @brief Aborts a SAI receive using eDMA.
+ *
+ * @param base SAI base pointer
+ * @param handle SAI eDMA handle pointer.
+ */
+void SAI_TransferAbortReceiveEDMA(I2S_Type *base, sai_edma_handle_t *handle);
+
+/*!
+ * @brief Gets byte count sent by SAI.
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ * @param count Bytes count sent by SAI.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
+ */
+status_t SAI_TransferGetSendCountEDMA(I2S_Type *base, sai_edma_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Gets byte count received by SAI.
+ *
+ * @param base SAI base pointer
+ * @param handle SAI eDMA handle pointer.
+ * @param count Bytes count received by SAI.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
+ */
+status_t SAI_TransferGetReceiveCountEDMA(I2S_Type *base, sai_edma_handle_t *handle, size_t *count);
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+#endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f8f2ebbf/hw/mcu/nxp/src/ext/sdk-2.0-frdm-k64f_b160321/devices/MK64F12/drivers/fsl_sdhc.c
----------------------------------------------------------------------
diff --git a/hw/mcu/nxp/src/ext/sdk-2.0-frdm-k64f_b160321/devices/MK64F12/drivers/fsl_sdhc.c b/hw/mcu/nxp/src/ext/sdk-2.0-frdm-k64f_b160321/devices/MK64F12/drivers/fsl_sdhc.c
new file mode 100644
index 0000000..0c5dd2b
--- /dev/null
+++ b/hw/mcu/nxp/src/ext/sdk-2.0-frdm-k64f_b160321/devices/MK64F12/drivers/fsl_sdhc.c
@@ -0,0 +1,1294 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this
+ * list
+ *   of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice,
+ * this
+ *   list of conditions and the following disclaimer in the documentation and/or
+ *   other materials provided with the distribution.
+ *
+ * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_sdhc.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+/*! @brief Clock setting */
+/* Max SD clock divisor from base clock */
+#define SDHC_MAX_DVS ((SDHC_SYSCTL_DVS_MASK >> SDHC_SYSCTL_DVS_SHIFT) + 1U)
+#define SDHC_INITIAL_DVS (1U)   /* Initial value of SD clock divisor */
+#define SDHC_INITIAL_CLKFS (2U) /* Initial value of SD clock frequency selector */
+#define SDHC_NEXT_DVS(x) ((x) += 1U)
+#define SDHC_PREV_DVS(x) ((x) -= 1U)
+#define SDHC_MAX_CLKFS ((SDHC_SYSCTL_SDCLKFS_MASK >> SDHC_SYSCTL_SDCLKFS_SHIFT) + 1U)
+#define SDHC_NEXT_CLKFS(x) ((x) <<= 1U)
+#define SDHC_PREV_CLKFS(x) ((x) >>= 1U)
+
+/*! @brief ADMA table configuration */
+typedef struct _sdhc_adma_table_config
+{
+    uint32_t *admaTable;     /*!< ADMA table address, can't be null if transfer way is ADMA1/ADMA2 */
+    uint32_t admaTableWords; /*!< ADMA table length united as words, can't be 0 if transfer way is ADMA1/ADMA2 */
+} sdhc_adma_table_config_t;
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get the instance.
+ *
+ * @param base SDHC peripheral base address.
+ * @return Instance number.
+ */
+static uint32_t SDHC_GetInstance(SDHC_Type *base);
+
+/*!
+ * @brief Set transfer interrupt.
+ *
+ * @param base SDHC peripheral base address.
+ * @param usingInterruptSignal True to use IRQ signal.
+ */
+static void SDHC_SetTransferInterrupt(SDHC_Type *base, bool usingInterruptSignal);
+
+/*!
+ * @brief Start transfer according to current transfer state
+ *
+ * @param base SDHC peripheral base address.
+ * @param command Command to be sent.
+ * @param data Data to be transferred.
+ */
+static void SDHC_StartTransfer(SDHC_Type *base, sdhc_command_t *command, sdhc_data_t *data);
+
+/*!
+ * @brief Receive command response
+ *
+ * @param base SDHC peripheral base address.
+ * @param command Command to be sent.
+ */
+static void SDHC_ReceiveCommandResponse(SDHC_Type *base, sdhc_command_t *command);
+
+/*!
+ * @brief Read DATAPORT when buffer enable bit is set.
+ *
+ * @param base SDHC peripheral base address.
+ * @param data Data to be read.
+ * @param transferredWords The number of data words have been transferred last time transaction.
+ * @return The number of total data words have been transferred after this time transaction.
+ */
+static uint32_t SDHC_ReadDataPort(SDHC_Type *base, sdhc_data_t *data, uint32_t transferredWords);
+
+/*!
+ * @brief Read data by using DATAPORT polling way.
+ *
+ * @param base SDHC peripheral base address.
+ * @param data Data to be read.
+ * @retval kStatus_Fail Read DATAPORT failed.
+ * @retval kStatus_Success Operate successfully.
+ */
+static status_t SDHC_ReadByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data);
+
+/*!
+ * @brief Write DATAPORT when buffer enable bit is set.
+ *
+ * @param base SDHC peripheral base address.
+ * @param data Data to be read.
+ * @param transferredWords The number of data words have been transferred last time.
+ * @return The number of total data words have been transferred after this time transaction.
+ */
+static uint32_t SDHC_WriteDataPort(SDHC_Type *base, sdhc_data_t *data, uint32_t transferredWords);
+
+/*!
+ * @brief Write data by using DATAPORT polling way.
+ *
+ * @param base SDHC peripheral base address.
+ * @param data Data to be transferred.
+ * @retval kStatus_Fail Write DATAPORT failed.
+ * @retval kStatus_Success Operate successfully.
+ */
+static status_t SDHC_WriteByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data);
+
+/*!
+ * @brief Send command by using polling way.
+ *
+ * @param base SDHC peripheral base address.
+ * @param command Command to be sent.
+ * @retval kStatus_Fail Send command failed.
+ * @retval kStatus_Success Operate successfully.
+ */
+static status_t SDHC_SendCommandBlocking(SDHC_Type *base, sdhc_command_t *command);
+
+/*!
+ * @brief Transfer data by DATAPORT and polling way.
+ *
+ * @param base SDHC peripheral base address.
+ * @param data Data to be transferred.
+ * @retval kStatus_Fail Transfer data failed.
+ * @retval kStatus_Success Operate successfully.
+ */
+static status_t SDHC_TransferByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data);
+
+/*!
+ * @brief Transfer data by ADMA2 and polling way.
+ *
+ * @param base SDHC peripheral base address.
+ * @param data Data to be transferred.
+ * @retval kStatus_Fail Transfer data failed.
+ * @retval kStatus_Success Operate successfully.
+ */
+static status_t SDHC_TransferByAdma2Blocking(SDHC_Type *base, sdhc_data_t *data);
+
+/*!
+ * @brief Transfer data by polling way.
+ *
+ * @param dmaMode DMA mode.
+ * @param base SDHC peripheral base address.
+ * @param data Data to be transferred.
+ * @retval kStatus_Fail Transfer data failed.
+ * @retval kStatus_InvalidArgument Argument is invalid.
+ * @retval kStatus_Success Operate successfully.
+ */
+static status_t SDHC_TransferDataBlocking(sdhc_dma_mode_t dmaMode, SDHC_Type *base, sdhc_data_t *data);
+
+/*!
+ * @brief Handle card detect interrupt.
+ *
+ * @param handle SDHC handle.
+ * @param interruptFlags Card detect related interrupt flags.
+ */
+static void SDHC_TransferHandleCardDetect(sdhc_handle_t *handle, uint32_t interruptFlags);
+
+/*!
+ * @brief Handle command interrupt.
+ *
+ * @param base SDHC peripheral base address.
+ * @param handle SDHC handle.
+ * @param interruptFlags Command related interrupt flags.
+ */
+static void SDHC_TransferHandleCommand(SDHC_Type *base, sdhc_handle_t *handle, uint32_t interruptFlags);
+
+/*!
+ * @brief Handle data interrupt.
+ *
+ * @param base SDHC peripheral base address.
+ * @param handle SDHC handle.
+ * @param interruptFlags Data related interrupt flags.
+ */
+static void SDHC_TransferHandleData(SDHC_Type *base, sdhc_handle_t *handle, uint32_t interruptFlags);
+
+/*!
+ * @brief Handle SDIO card interrupt signal.
+ *
+ * @param handle SDHC handle.
+ */
+static void SDHC_TransferHandleSdioInterrupt(sdhc_handle_t *handle);
+
+/*!
+ * @brief Handle SDIO block gap event.
+ *
+ * @param handle SDHC handle.
+ */
+static void SDHC_TransferHandleSdioBlockGap(sdhc_handle_t *handle);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief SDHC internal handle pointer array */
+static sdhc_handle_t *s_sdhcHandle[FSL_FEATURE_SOC_SDHC_COUNT];
+
+/*! @brief SDHC base pointer array */
+static SDHC_Type *const s_sdhcBase[] = SDHC_BASE_PTRS;
+
+/*! @brief SDHC IRQ name array */
+static const IRQn_Type s_sdhcIRQ[] = SDHC_IRQS;
+
+/*! @brief SDHC clock array name */
+static const clock_ip_name_t s_sdhcClock[] = SDHC_CLOCKS;
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t SDHC_GetInstance(SDHC_Type *base)
+{
+    uint8_t instance = 0;
+
+    while ((instance < FSL_FEATURE_SOC_SDHC_COUNT) && (s_sdhcBase[instance] != base))
+    {
+        instance++;
+    }
+
+    assert(instance < FSL_FEATURE_SOC_SDHC_COUNT);
+
+    return instance;
+}
+
+static void SDHC_SetTransferInterrupt(SDHC_Type *base, bool usingInterruptSignal)
+{
+    uint32_t interruptEnabled; /* The Interrupt status flags to be enabled */
+    sdhc_dma_mode_t dmaMode = (sdhc_dma_mode_t)((base->PROCTL & SDHC_PROCTL_DMAS_MASK) >> SDHC_PROCTL_DMAS_SHIFT);
+    bool cardDetectDat3 = (bool)(base->PROCTL & SDHC_PROCTL_D3CD_MASK);
+
+    /* Disable all interrupts */
+    SDHC_DisableInterruptStatus(base, (uint32_t)kSDHC_AllInterruptFlags);
+    SDHC_DisableInterruptSignal(base, (uint32_t)kSDHC_AllInterruptFlags);
+    DisableIRQ(s_sdhcIRQ[SDHC_GetInstance(base)]);
+
+    interruptEnabled =
+        (kSDHC_CommandIndexErrorFlag | kSDHC_CommandCrcErrorFlag | kSDHC_CommandEndBitErrorFlag |
+         kSDHC_CommandTimeoutFlag | kSDHC_CommandCompleteFlag | kSDHC_DataTimeoutFlag | kSDHC_DataCrcErrorFlag |
+         kSDHC_DataEndBitErrorFlag | kSDHC_DataCompleteFlag | kSDHC_AutoCommand12ErrorFlag);
+    if (cardDetectDat3)
+    {
+        interruptEnabled |= (kSDHC_CardInsertionFlag | kSDHC_CardRemovalFlag);
+    }
+    switch (dmaMode)
+    {
+        case kSDHC_DmaModeAdma1:
+        case kSDHC_DmaModeAdma2:
+            interruptEnabled |= (kSDHC_DmaErrorFlag | kSDHC_DmaCompleteFlag);
+            break;
+        case kSDHC_DmaModeNo:
+            interruptEnabled |= (kSDHC_BufferReadReadyFlag | kSDHC_BufferWriteReadyFlag);
+            break;
+        default:
+            break;
+    }
+
+    SDHC_EnableInterruptStatus(base, interruptEnabled);
+    if (usingInterruptSignal)
+    {
+        SDHC_EnableInterruptSignal(base, interruptEnabled);
+    }
+}
+
+static void SDHC_StartTransfer(SDHC_Type *base, sdhc_command_t *command, sdhc_data_t *data)
+{
+    assert(command);
+
+    uint32_t flags = 0U;
+    sdhc_transfer_config_t sdhcTransferConfig;
+    sdhc_dma_mode_t dmaMode;
+
+    /* Define the flag corresponding to each response type. */
+    switch (command->responseType)
+    {
+        case kSDHC_ResponseTypeNone:
+            break;
+        case kSDHC_ResponseTypeR1: /* Response 1 */
+            flags |= (kSDHC_ResponseLength48Flag | kSDHC_EnableCrcCheckFlag | kSDHC_EnableIndexCheckFlag);
+            break;
+        case kSDHC_ResponseTypeR1b: /* Response 1 with busy */
+            flags |= (kSDHC_ResponseLength48BusyFlag | kSDHC_EnableCrcCheckFlag | kSDHC_EnableIndexCheckFlag);
+            break;
+        case kSDHC_ResponseTypeR2: /* Response 2 */
+            flags |= (kSDHC_ResponseLength136Flag | kSDHC_EnableCrcCheckFlag);
+            break;
+        case kSDHC_ResponseTypeR3: /* Response 3 */
+            flags |= (kSDHC_ResponseLength48Flag);
+            break;
+        case kSDHC_ResponseTypeR4: /* Response 4 */
+            flags |= (kSDHC_ResponseLength48Flag);
+            break;
+        case kSDHC_ResponseTypeR5: /* Response 5 */
+            flags |= (kSDHC_ResponseLength48Flag | kSDHC_EnableCrcCheckFlag);
+            break;
+        case kSDHC_ResponseTypeR5b: /* Response 5 with busy */
+            flags |= (kSDHC_ResponseLength48BusyFlag | kSDHC_EnableCrcCheckFlag | kSDHC_EnableIndexCheckFlag);
+            break;
+        case kSDHC_ResponseTypeR6: /* Response 6 */
+            flags |= (kSDHC_ResponseLength48Flag | kSDHC_EnableCrcCheckFlag | kSDHC_EnableIndexCheckFlag);
+            break;
+        case kSDHC_ResponseTypeR7: /* Response 7 */
+            flags |= (kSDHC_ResponseLength48Flag | kSDHC_EnableCrcCheckFlag | kSDHC_EnableIndexCheckFlag);
+            break;
+        default:
+            break;
+    }
+    if (command->type == kSDHC_CommandTypeAbort)
+    {
+        flags |= kSDHC_CommandTypeAbortFlag;
+    }
+
+    if (data)
+    {
+        flags |= kSDHC_DataPresentFlag;
+        dmaMode = (sdhc_dma_mode_t)((base->PROCTL & SDHC_PROCTL_DMAS_MASK) >> SDHC_PROCTL_DMAS_SHIFT);
+        if (dmaMode != kSDHC_DmaModeNo)
+        {
+            flags |= kSDHC_EnableDmaFlag;
+        }
+        if (data->rxData)
+        {
+            flags |= kSDHC_DataReadFlag;
+        }
+        if (data->blockCount > 1U)
+        {
+            flags |= (kSDHC_MultipleBlockFlag | kSDHC_EnableBlockCountFlag);
+            if (data->enableAutoCommand12)
+            {
+                /* Enable Auto command 12. */
+                flags |= kSDHC_EnableAutoCommand12Flag;
+            }
+        }
+        if (data->blockCount > SDHC_MAX_BLOCK_COUNT)
+        {
+            sdhcTransferConfig.dataBlockSize = data->blockSize;
+            sdhcTransferConfig.dataBlockCount = SDHC_MAX_BLOCK_COUNT;
+
+            flags &= ~(uint32_t)kSDHC_EnableBlockCountFlag;
+        }
+        else
+        {
+            sdhcTransferConfig.dataBlockSize = data->blockSize;
+            sdhcTransferConfig.dataBlockCount = data->blockCount;
+        }
+    }
+    else
+    {
+        sdhcTransferConfig.dataBlockSize = 0U;
+        sdhcTransferConfig.dataBlockCount = 0U;
+    }
+
+    sdhcTransferConfig.commandArgument = command->argument;
+    sdhcTransferConfig.commandIndex = command->index;
+    sdhcTransferConfig.flags = flags;
+    SDHC_SetTransferConfig(base, &sdhcTransferConfig);
+}
+
+static void SDHC_ReceiveCommandResponse(SDHC_Type *base, sdhc_command_t *command)
+{
+    assert(command);
+
+    uint32_t i;
+
+    if (command->responseType != kSDHC_ResponseTypeNone)
+    {
+        command->response[0U] = SDHC_GetCommandResponse(base, 0U);
+        if (command->responseType == kSDHC_ResponseTypeR2)
+        {
+            command->response[1U] = SDHC_GetCommandResponse(base, 1U);
+            command->response[2U] = SDHC_GetCommandResponse(base, 2U);
+            command->response[3U] = SDHC_GetCommandResponse(base, 3U);
+
+            i = 4U;
+            /* R3-R2-R1-R0(lowest 8 bit is invalid bit) has the same format as R2 format in SD specification document
+            after removed internal CRC7 and end bit. */
+            do
+            {
+                command->response[i - 1U] <<= 8U;
+                if (i > 1U)
+                {
+                    command->response[i - 1U] |= ((command->response[i - 2U] & 0xFF000000U) >> 24U);
+                }
+            } while (i--);
+        }
+    }
+}
+
+static uint32_t SDHC_ReadDataPort(SDHC_Type *base, sdhc_data_t *data, uint32_t transferredWords)
+{
+    assert(data);
+
+    uint32_t i;
+    uint32_t totalWords;
+    uint32_t wordsCanBeRead; /* The words can be read at this time. */
+    uint32_t readWatermark = ((base->WML & SDHC_WML_RDWML_MASK) >> SDHC_WML_RDWML_SHIFT);
+
+    totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
+
+    /* If watermark level is equal or bigger than totalWords, transfers totalWords data. */
+    if (readWatermark >= totalWords)
+    {
+        wordsCanBeRead = totalWords;
+    }
+    /* If watermark level is less than totalWords and left words to be sent is equal or bigger than readWatermark,
+    transfers watermark level words. */
+    else if ((readWatermark < totalWords) && ((totalWords - transferredWords) >= readWatermark))
+    {
+        wordsCanBeRead = readWatermark;
+    }
+    /* If watermark level is less than totalWords and left words to be sent is less than readWatermark, transfers left
+    words. */
+    else
+    {
+        wordsCanBeRead = (totalWords - transferredWords);
+    }
+
+    i = 0U;
+    while (i < wordsCanBeRead)
+    {
+        data->rxData[transferredWords++] = SDHC_ReadData(base);
+        i++;
+    }
+
+    return transferredWords;
+}
+
+static status_t SDHC_ReadByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data)
+{
+    assert(data);
+
+    uint32_t totalWords;
+    uint32_t transferredWords = 0U;
+    status_t error = kStatus_Success;
+
+    totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
+
+    while ((error == kStatus_Success) && (transferredWords < totalWords))
+    {
+        while (!(SDHC_GetInterruptStatusFlags(base) & (kSDHC_BufferReadReadyFlag | kSDHC_DataErrorFlag)))
+        {
+        }
+
+        if (SDHC_GetInterruptStatusFlags(base) & kSDHC_DataErrorFlag)
+        {
+            if (!(data->enableIgnoreError))
+            {
+                error = kStatus_Fail;
+            }
+        }
+        if (error == kStatus_Success)
+        {
+            transferredWords = SDHC_ReadDataPort(base, data, transferredWords);
+        }
+
+        /* Clear buffer enable flag to trigger transfer. Clear data error flag when SDHC encounter error */
+        SDHC_ClearInterruptStatusFlags(base, (kSDHC_BufferReadReadyFlag | kSDHC_DataErrorFlag));
+    }
+
+    /* Clear data complete flag after the last read operation. */
+    SDHC_ClearInterruptStatusFlags(base, kSDHC_DataCompleteFlag);
+
+    return error;
+}
+
+static uint32_t SDHC_WriteDataPort(SDHC_Type *base, sdhc_data_t *data, uint32_t transferredWords)
+{
+    assert(data);
+
+    uint32_t i;
+    uint32_t totalWords;
+    uint32_t wordsCanBeWrote; /* Words can be wrote at this time. */
+    uint32_t writeWatermark = ((base->WML & SDHC_WML_WRWML_MASK) >> SDHC_WML_WRWML_SHIFT);
+
+    totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
+
+    /* If watermark level is equal or bigger than totalWords, transfers totalWords data.*/
+    if (writeWatermark >= totalWords)
+    {
+        wordsCanBeWrote = totalWords;
+    }
+    /* If watermark level is less than totalWords and left words to be sent is equal or bigger than watermark,
+    transfers watermark level words. */
+    else if ((writeWatermark < totalWords) && ((totalWords - transferredWords) >= writeWatermark))
+    {
+        wordsCanBeWrote = writeWatermark;
+    }
+    /* If watermark level is less than totalWords and left words to be sent is less than watermark, transfers left
+    words. */
+    else
+    {
+        wordsCanBeWrote = (totalWords - transferredWords);
+    }
+
+    i = 0U;
+    while (i < wordsCanBeWrote)
+    {
+        SDHC_WriteData(base, data->txData[transferredWords++]);
+        i++;
+    }
+
+    return transferredWords;
+}
+
+static status_t SDHC_WriteByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data)
+{
+    assert(data);
+
+    uint32_t totalWords;
+    uint32_t transferredWords = 0U;
+    status_t error = kStatus_Success;
+
+    totalWords = (data->blockCount * data->blockSize) / sizeof(uint32_t);
+
+    while ((error == kStatus_Success) && (transferredWords < totalWords))
+    {
+        while (!(SDHC_GetInterruptStatusFlags(base) & (kSDHC_BufferWriteReadyFlag | kSDHC_DataErrorFlag)))
+        {
+        }
+
+        if (SDHC_GetInterruptStatusFlags(base) & kSDHC_DataErrorFlag)
+        {
+            if (!(data->enableIgnoreError))
+            {
+                error = kStatus_Fail;
+            }
+        }
+        if (error == kStatus_Success)
+        {
+            transferredWords = SDHC_WriteDataPort(base, data, transferredWords);
+        }
+
+        /* Clear buffer enable flag to trigger transfer. Clear error flag when SDHC encounter error. */
+        SDHC_ClearInterruptStatusFlags(base, (kSDHC_BufferWriteReadyFlag | kSDHC_DataErrorFlag));
+    }
+
+    /* Wait write data complete or data transfer error after the last writing operation. */
+    while (!(SDHC_GetInterruptStatusFlags(base) & (kSDHC_DataCompleteFlag | kSDHC_DataErrorFlag)))
+    {
+    }
+    if (SDHC_GetInterruptStatusFlags(base) & kSDHC_DataErrorFlag)
+    {
+        if (!(data->enableIgnoreError))
+        {
+            error = kStatus_Fail;
+        }
+    }
+    SDHC_ClearInterruptStatusFlags(base, (kSDHC_DataCompleteFlag | kSDHC_DataErrorFlag));
+
+    return error;
+}
+
+static status_t SDHC_SendCommandBlocking(SDHC_Type *base, sdhc_command_t *command)
+{
+    assert(command);
+
+    status_t error = kStatus_Success;
+
+    /* Wait command complete or SDHC encounters error. */
+    while (!(SDHC_GetInterruptStatusFlags(base) & (kSDHC_CommandCompleteFlag | kSDHC_CommandErrorFlag)))
+    {
+    }
+
+    if (SDHC_GetInterruptStatusFlags(base) & kSDHC_CommandErrorFlag)
+    {
+        error = kStatus_Fail;
+    }
+    /* Receive response when command completes successfully. */
+    if (error == kStatus_Success)
+    {
+        SDHC_ReceiveCommandResponse(base, command);
+    }
+
+    SDHC_ClearInterruptStatusFlags(base, (kSDHC_CommandCompleteFlag | kSDHC_CommandErrorFlag));
+
+    return error;
+}
+
+static status_t SDHC_TransferByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data)
+{
+    assert(data);
+
+    status_t error = kStatus_Success;
+
+    if (data->rxData)
+    {
+        error = SDHC_ReadByDataPortBlocking(base, data);
+    }
+    else
+    {
+        error = SDHC_WriteByDataPortBlocking(base, data);
+    }
+
+    return error;
+}
+
+static status_t SDHC_TransferByAdma2Blocking(SDHC_Type *base, sdhc_data_t *data)
+{
+    status_t error = kStatus_Success;
+
+    /* Wait data complete or SDHC encounters error. */
+    while (!(SDHC_GetInterruptStatusFlags(base) & (kSDHC_DataCompleteFlag | kSDHC_DataErrorFlag | kSDHC_DmaErrorFlag)))
+    {
+    }
+    if (SDHC_GetInterruptStatusFlags(base) & (kSDHC_DataErrorFlag | kSDHC_DmaErrorFlag))
+    {
+        if (!(data->enableIgnoreError))
+        {
+            error = kStatus_Fail;
+        }
+    }
+    SDHC_ClearInterruptStatusFlags(
+        base, (kSDHC_DataCompleteFlag | kSDHC_DmaCompleteFlag | kSDHC_DataErrorFlag | kSDHC_DmaErrorFlag));
+    return error;
+}
+
+#if defined FSL_SDHC_ENABLE_ADMA1
+#define SDHC_TransferByAdma1Blocking(base, data) SDHC_TransferByAdma2Blocking(base, data)
+#endif /* FSL_SDHC_ENABLE_ADMA1 */
+
+static status_t SDHC_TransferDataBlocking(sdhc_dma_mode_t dmaMode, SDHC_Type *base, sdhc_data_t *data)
+{
+    status_t error = kStatus_Success;
+
+    switch (dmaMode)
+    {
+        case kSDHC_DmaModeNo:
+            error = SDHC_TransferByDataPortBlocking(base, data);
+            break;
+#if defined FSL_SDHC_ENABLE_ADMA1
+        case kSDHC_DmaModeAdma1:
+            error = SDHC_TransferByAdma1Blocking(base, data);
+            break;
+#endif /* FSL_SDHC_ENABLE_ADMA1 */
+        case kSDHC_DmaModeAdma2:
+            error = SDHC_TransferByAdma2Blocking(base, data);
+            break;
+        default:
+            error = kStatus_InvalidArgument;
+            break;
+    }
+
+    return error;
+}
+
+static void SDHC_TransferHandleCardDetect(sdhc_handle_t *handle, uint32_t interruptFlags)
+{
+    assert(interruptFlags & kSDHC_CardDetectFlag);
+
+    if (interruptFlags & kSDHC_CardInsertionFlag)
+    {
+        if (handle->callback.CardInserted)
+        {
+            handle->callback.CardInserted();
+        }
+    }
+    else
+    {
+        if (handle->callback.CardRemoved)
+        {
+            handle->callback.CardRemoved();
+        }
+    }
+}
+
+static void SDHC_TransferHandleCommand(SDHC_Type *base, sdhc_handle_t *handle, uint32_t interruptFlags)
+{
+    assert(interruptFlags & kSDHC_CommandFlag);
+
+    if ((interruptFlags & kSDHC_CommandErrorFlag) && (!(handle->data)) && (handle->callback.TransferComplete))
+    {
+        handle->callback.TransferComplete(base, handle, kStatus_SDHC_SendCommandFailed, handle->userData);
+    }
+    else
+    {
+        /* Receive response */
+        SDHC_ReceiveCommandResponse(base, handle->command);
+        if ((!(handle->data)) && (handle->callback.TransferComplete))
+        {
+            handle->callback.TransferComplete(base, handle, kStatus_Success, handle->userData);
+        }
+    }
+}
+
+static void SDHC_TransferHandleData(SDHC_Type *base, sdhc_handle_t *handle, uint32_t interruptFlags)
+{
+    assert(handle->data);
+    assert(interruptFlags & kSDHC_DataFlag);
+
+    if ((!(handle->data->enableIgnoreError)) && (interruptFlags & (kSDHC_DataErrorFlag | kSDHC_DmaErrorFlag)) &&
+        (handle->callback.TransferComplete))
+    {
+        handle->callback.TransferComplete(base, handle, kStatus_SDHC_TransferDataFailed, handle->userData);
+    }
+    else
+    {
+        if (interruptFlags & kSDHC_BufferReadReadyFlag)
+        {
+            handle->transferredWords = SDHC_ReadDataPort(base, handle->data, handle->transferredWords);
+        }
+        else if (interruptFlags & kSDHC_BufferWriteReadyFlag)
+        {
+            handle->transferredWords = SDHC_WriteDataPort(base, handle->data, handle->transferredWords);
+        }
+        else if ((interruptFlags & kSDHC_DataCompleteFlag) && (handle->callback.TransferComplete))
+        {
+            handle->callback.TransferComplete(base, handle, kStatus_Success, handle->userData);
+        }
+        else
+        {
+            /* Do nothing when DMA complete flag is set. Wait until data complete flag is set. */
+        }
+    }
+}
+
+static void SDHC_TransferHandleSdioInterrupt(sdhc_handle_t *handle)
+{
+    if (handle->callback.SdioInterrupt)
+    {
+        handle->callback.SdioInterrupt();
+    }
+}
+
+static void SDHC_TransferHandleSdioBlockGap(sdhc_handle_t *handle)
+{
+    if (handle->callback.SdioBlockGap)
+    {
+        handle->callback.SdioBlockGap();
+    }
+}
+
+void SDHC_Init(SDHC_Type *base, const sdhc_config_t *config)
+{
+    assert(config);
+#if !defined FSL_SDHC_ENABLE_ADMA1
+    assert(config->dmaMode != kSDHC_DmaModeAdma1);
+#endif /* FSL_SDHC_ENABLE_ADMA1 */
+
+    uint32_t proctl;
+    uint32_t wml;
+
+    /* Enable SDHC clock. */
+    CLOCK_EnableClock(s_sdhcClock[SDHC_GetInstance(base)]);
+
+    /* Reset SDHC. */
+    SDHC_Reset(base, kSDHC_ResetAll, 100);
+
+    proctl = base->PROCTL;
+    wml = base->WML;
+
+    proctl &= ~(SDHC_PROCTL_D3CD_MASK | SDHC_PROCTL_EMODE_MASK | SDHC_PROCTL_DMAS_MASK);
+    /* Set DAT3 as card detection pin */
+    if (config->cardDetectDat3)
+    {
+        proctl |= SDHC_PROCTL_D3CD_MASK;
+    }
+    /* Endian mode and DMA mode */
+    proctl |= (SDHC_PROCTL_EMODE(config->endianMode) | SDHC_PROCTL_DMAS(config->dmaMode));
+
+    /* Watermark level */
+    wml &= ~(SDHC_WML_RDWML_MASK | SDHC_WML_WRWML_MASK);
+    wml |= (SDHC_WML_RDWML(config->readWatermarkLevel) | SDHC_WML_WRWML(config->writeWatermarkLevel));
+
+    base->WML = wml;
+    base->PROCTL = proctl;
+
+    /* Disable all clock auto gated off feature because of DAT0 line logic(card buffer full status) can't be updated
+    correctly when clock auto gated off is enabled. */
+    base->SYSCTL |= (SDHC_SYSCTL_PEREN_MASK | SDHC_SYSCTL_HCKEN_MASK | SDHC_SYSCTL_IPGEN_MASK);
+
+    /* Enable interrupt status but doesn't enable interrupt signal. */
+    SDHC_SetTransferInterrupt(base, false);
+}
+
+void SDHC_Deinit(SDHC_Type *base)
+{
+    /* Disable clock. */
+    CLOCK_DisableClock(s_sdhcClock[SDHC_GetInstance(base)]);
+}
+
+bool SDHC_Reset(SDHC_Type *base, uint32_t mask, uint32_t timeout)
+{
+    base->SYSCTL |= (mask & (SDHC_SYSCTL_RSTA_MASK | SDHC_SYSCTL_RSTC_MASK | SDHC_SYSCTL_RSTD_MASK));
+    /* Delay some time to wait reset success. */
+    while ((base->SYSCTL & mask))
+    {
+        if (!timeout)
+        {
+            break;
+        }
+        timeout--;
+    }
+
+    return ((!timeout) ? false : true);
+}
+
+void SDHC_GetCapability(SDHC_Type *base, sdhc_capability_t *capability)
+{
+    assert(capability);
+
+    uint32_t htCapability;
+    uint32_t hostVer;
+    uint32_t maxBlockLength;
+
+    hostVer = base->HOSTVER;
+    htCapability = base->HTCAPBLT;
+
+    /* Get the capability of SDHC. */
+    capability->specVersion = ((hostVer & SDHC_HOSTVER_SVN_MASK) >> SDHC_HOSTVER_SVN_SHIFT);
+    capability->vendorVersion = ((hostVer & SDHC_HOSTVER_VVN_MASK) >> SDHC_HOSTVER_VVN_SHIFT);
+    maxBlockLength = ((htCapability & SDHC_HTCAPBLT_MBL_MASK) >> SDHC_HTCAPBLT_MBL_SHIFT);
+    capability->maxBlockLength = (512U << maxBlockLength);
+    /* Other attributes not in HTCAPBLT register. */
+    capability->maxBlockCount = SDHC_MAX_BLOCK_COUNT;
+    capability->flags = (htCapability & (kSDHC_SupportAdmaFlag | kSDHC_SupportHighSpeedFlag | kSDHC_SupportDmaFlag |
+                                         kSDHC_SupportSuspendResumeFlag | kSDHC_SupportV330Flag));
+#if defined FSL_FEATURE_SDHC_HAS_V300_SUPPORT && FSL_FEATURE_SDHC_HAS_V300_SUPPORT
+    capability->flags |= (htCapability & kSDHC_SupportV300Flag);
+#endif
+#if defined FSL_FEATURE_SDHC_HAS_V180_SUPPORT && FSL_FEATURE_SDHC_HAS_V180_SUPPORT
+    capability->flags |= (htCapability & kSDHC_SupportV180Flag);
+#endif
+    /* eSDHC on all kinetis boards will support 4/8 bit data bus width. */
+    capability->flags |= (kSDHC_Support4BitFlag | kSDHC_Support8BitFlag);
+}
+
+uint32_t SDHC_SetSdClock(SDHC_Type *base, uint32_t srcClock_Hz, uint32_t busClock_Hz)
+{
+    assert(busClock_Hz && (busClock_Hz < srcClock_Hz));
+
+    uint32_t divisor;
+    uint32_t prescaler;
+    uint32_t sysctl;
+    uint32_t nearestFrequency = 0;
+
+    divisor = SDHC_INITIAL_DVS;
+    prescaler = SDHC_INITIAL_CLKFS;
+
+    /* Disable SD clock. It should be disabled before changing the SD clock frequency.*/
+    base->SYSCTL &= ~SDHC_SYSCTL_SDCLKEN_MASK;
+
+    if (busClock_Hz > 0U)
+    {
+        while ((srcClock_Hz / prescaler / SDHC_MAX_DVS > busClock_Hz) && (prescaler < SDHC_MAX_CLKFS))
+        {
+            SDHC_NEXT_CLKFS(prescaler);
+        }
+        while ((srcClock_Hz / prescaler / divisor > busClock_Hz) && (divisor < SDHC_MAX_DVS))
+        {
+            SDHC_NEXT_DVS(divisor);
+        }
+        nearestFrequency = srcClock_Hz / prescaler / divisor;
+        SDHC_PREV_CLKFS(prescaler);
+        SDHC_PREV_DVS(divisor);
+
+        /* Set the SD clock frequency divisor, SD clock frequency select, data timeout counter value. */
+        sysctl = base->SYSCTL;
+        sysctl &= ~(SDHC_SYSCTL_DVS_MASK | SDHC_SYSCTL_SDCLKFS_MASK | SDHC_SYSCTL_DTOCV_MASK);
+        sysctl |= (SDHC_SYSCTL_DVS(divisor) | SDHC_SYSCTL_SDCLKFS(prescaler) | SDHC_SYSCTL_DTOCV(0xEU));
+        base->SYSCTL = sysctl;
+
+        /* Wait until the SD clock is stable. */
+        while (!(base->PRSSTAT & SDHC_PRSSTAT_SDSTB_MASK))
+        {
+        }
+        /* Enable the SD clock. */
+        base->SYSCTL |= SDHC_SYSCTL_SDCLKEN_MASK;
+    }
+
+    return nearestFrequency;
+}
+
+bool SDHC_SetCardActive(SDHC_Type *base, uint32_t timeout)
+{
+    base->SYSCTL |= SDHC_SYSCTL_INITA_MASK;
+    /* Delay some time to wait card become active state. */
+    while (!(base->SYSCTL & SDHC_SYSCTL_INITA_MASK))
+    {
+        if (!timeout)
+        {
+            break;
+        }
+        timeout--;
+    }
+
+    return ((!timeout) ? false : true);
+}
+
+void SDHC_SetTransferConfig(SDHC_Type *base, const sdhc_transfer_config_t *config)
+{
+    assert(config);
+
+    base->BLKATTR = ((base->BLKATTR & ~(SDHC_BLKATTR_BLKSIZE_MASK | SDHC_BLKATTR_BLKCNT_MASK)) |
+                     (SDHC_BLKATTR_BLKSIZE(config->dataBlockSize) | SDHC_BLKATTR_BLKCNT(config->dataBlockCount)));
+    base->CMDARG = config->commandArgument;
+    base->XFERTYP = (((config->commandIndex << SDHC_XFERTYP_CMDINX_SHIFT) & SDHC_XFERTYP_CMDINX_MASK) |
+                     (config->flags & (SDHC_XFERTYP_DMAEN_MASK | SDHC_XFERTYP_MSBSEL_MASK | SDHC_XFERTYP_DPSEL_MASK |
+                                       SDHC_XFERTYP_CMDTYP_MASK | SDHC_XFERTYP_BCEN_MASK | SDHC_XFERTYP_CICEN_MASK |
+                                       SDHC_XFERTYP_CCCEN_MASK | SDHC_XFERTYP_RSPTYP_MASK | SDHC_XFERTYP_DTDSEL_MASK |
+                                       SDHC_XFERTYP_AC12EN_MASK)));
+}
+
+void SDHC_EnableSdioControl(SDHC_Type *base, uint32_t mask, bool enable)
+{
+    uint32_t proctl = base->PROCTL;
+    uint32_t vendor = base->VENDOR;
+
+    if (enable)
+    {
+        if (mask & kSDHC_StopAtBlockGapFlag)
+        {
+            proctl |= SDHC_PROCTL_SABGREQ_MASK;
+        }
+        if (mask & kSDHC_ReadWaitControlFlag)
+        {
+            proctl |= SDHC_PROCTL_RWCTL_MASK;
+        }
+        if (mask & kSDHC_InterruptAtBlockGapFlag)
+        {
+            proctl |= SDHC_PROCTL_IABG_MASK;
+        }
+        if (mask & kSDHC_ExactBlockNumberReadFlag)
+        {
+            vendor |= SDHC_VENDOR_EXBLKNU_MASK;
+        }
+    }
+    else
+    {
+        if (mask & kSDHC_StopAtBlockGapFlag)
+        {
+            proctl &= ~SDHC_PROCTL_SABGREQ_MASK;
+        }
+        if (mask & kSDHC_ReadWaitControlFlag)
+        {
+            proctl &= ~SDHC_PROCTL_RWCTL_MASK;
+        }
+        if (mask & kSDHC_InterruptAtBlockGapFlag)
+        {
+            proctl &= ~SDHC_PROCTL_IABG_MASK;
+        }
+        if (mask & kSDHC_ExactBlockNumberReadFlag)
+        {
+            vendor &= ~SDHC_VENDOR_EXBLKNU_MASK;
+        }
+    }
+
+    base->PROCTL = proctl;
+    base->VENDOR = vendor;
+}
+
+void SDHC_SetMmcBootConfig(SDHC_Type *base, const sdhc_boot_config_t *config)
+{
+    assert(config);
+
+    uint32_t mmcboot;
+
+    mmcboot = base->MMCBOOT;
+    mmcboot |= (SDHC_MMCBOOT_DTOCVACK(config->ackTimeoutCount) | SDHC_MMCBOOT_BOOTMODE(config->bootMode) |
+                SDHC_MMCBOOT_BOOTBLKCNT(config->blockCount));
+    if (config->enableBootAck)
+    {
+        mmcboot |= SDHC_MMCBOOT_BOOTACK_MASK;
+    }
+    if (config->enableBoot)
+    {
+        mmcboot |= SDHC_MMCBOOT_BOOTEN_MASK;
+    }
+    if (config->enableAutoStopAtBlockGap)
+    {
+        mmcboot |= SDHC_MMCBOOT_AUTOSABGEN_MASK;
+    }
+    base->MMCBOOT = mmcboot;
+}
+
+status_t SDHC_SetAdmaTableConfig(SDHC_Type *base,
+                                 sdhc_dma_mode_t dmaMode,
+                                 uint32_t *table,
+                                 uint32_t tableWords,
+                                 const uint32_t *data,
+                                 uint32_t dataBytes)
+{
+    status_t error = kStatus_Success;
+    const uint32_t *startAddress;
+    uint32_t entries;
+    uint32_t i;
+#if defined FSL_SDHC_ENABLE_ADMA1
+    sdhc_adma1_descriptor_t *adma1EntryAddress;
+#endif
+    sdhc_adma2_descriptor_t *adma2EntryAddress;
+
+    if ((((!table) || (!tableWords)) && ((dmaMode == kSDHC_DmaModeAdma1) || (dmaMode == kSDHC_DmaModeAdma2))) ||
+        (!data) || (!dataBytes)
+#if !defined FSL_SDHC_ENABLE_ADMA1
+        || (dmaMode == kSDHC_DmaModeAdma1)
+#endif /* FSL_SDHC_ENABLE_ADMA1 */
+            )
+    {
+        error = kStatus_InvalidArgument;
+    }
+    else
+    {
+        switch (dmaMode)
+        {
+            case kSDHC_DmaModeNo:
+                break;
+#if defined FSL_SDHC_ENABLE_ADMA1
+            case kSDHC_DmaModeAdma1:
+                startAddress = data;
+                /* Check if ADMA descriptor's number is enough. */
+                entries = ((dataBytes / SDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1U);
+                /* ADMA1 needs two descriptors to finish a transfer */
+                entries <<= 1U;
+                if (entries > ((tableWords * sizeof(uint32_t)) / sizeof(sdhc_adma1_descriptor_t)))
+                {
+                    error = kStatus_OutOfRange;
+                }
+                else
+                {
+                    adma1EntryAddress = (sdhc_adma1_descriptor_t *)(table);
+                    for (i = 0U; i < entries; i += 2U)
+                    {
+                        /* Each descriptor for ADMA1 is 32-bit in length */
+                        if ((dataBytes - sizeof(uint32_t) * (startAddress - data)) <=
+                            SDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY)
+                        {
+                            /* The last piece of data, setting end flag in descriptor */
+                            adma1EntryAddress[i] = ((uint32_t)(dataBytes - sizeof(uint32_t) * (startAddress - data))
+                                                    << SDHC_ADMA1_DESCRIPTOR_LENGTH_SHIFT);
+                            adma1EntryAddress[i] |= kSDHC_Adma1DescriptorTypeSetLength;
+                            adma1EntryAddress[i + 1U] =
+                                ((uint32_t)(startAddress) << SDHC_ADMA1_DESCRIPTOR_ADDRESS_SHIFT);
+                            adma1EntryAddress[i + 1U] |=
+                                (SDHC_ADMA1_DESCRIPTOR_TYPE_TRANSFER | SDHC_ADMA1_DESCRIPTOR_END_MASK);
+                        }
+                        else
+                        {
+                            adma1EntryAddress[i] = ((uint32_t)SDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY
+                                                    << SDHC_ADMA1_DESCRIPTOR_LENGTH_SHIFT);
+                            adma1EntryAddress[i] |= kSDHC_Adma1DescriptorTypeSetLength;
+                            adma1EntryAddress[i + 1U] =
+                                ((uint32_t)(startAddress) << SDHC_ADMA1_DESCRIPTOR_ADDRESS_SHIFT);
+                            adma1EntryAddress[i + 1U] |= kSDHC_Adma1DescriptorTypeTransfer;
+                            startAddress += SDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY / sizeof(uint32_t);
+                        }
+                    }
+
+                    /* When use ADMA, disable simple DMA */
+                    base->DSADDR = 0U;
+                    base->ADSADDR = (uint32_t)table;
+                }
+                break;
+#endif /* FSL_SDHC_ENABLE_ADMA1 */
+            case kSDHC_DmaModeAdma2:
+                startAddress = data;
+                /* Check if ADMA descriptor's number is enough. */
+                entries = ((dataBytes / SDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1U);
+                if (entries > ((tableWords * sizeof(uint32_t)) / sizeof(sdhc_adma2_descriptor_t)))
+                {
+                    error = kStatus_OutOfRange;
+                }
+                else
+                {
+                    adma2EntryAddress = (sdhc_adma2_descriptor_t *)(table);
+                    for (i = 0U; i < entries; i++)
+                    {
+                        /* Each descriptor for ADMA2 is 64-bit in length */
+                        if ((dataBytes - sizeof(uint32_t) * (startAddress - data)) <=
+                            SDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY)
+                        {
+                            /* The last piece of data, setting end flag in descriptor */
+                            adma2EntryAddress[i].address = startAddress;
+                            adma2EntryAddress[i].attribute = ((dataBytes - sizeof(uint32_t) * (startAddress - data))
+                                                              << SDHC_ADMA2_DESCRIPTOR_LENGTH_SHIFT);
+                            adma2EntryAddress[i].attribute |=
+                                (kSDHC_Adma2DescriptorTypeTransfer | kSDHC_Adma2DescriptorEndFlag);
+                        }
+                        else
+                        {
+                            adma2EntryAddress[i].address = startAddress;
+                            adma2EntryAddress[i].attribute =
+                                (((SDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY / sizeof(uint32_t)) * sizeof(uint32_t))
+                                 << SDHC_ADMA2_DESCRIPTOR_LENGTH_SHIFT);
+                            adma2EntryAddress[i].attribute |= kSDHC_Adma2DescriptorTypeTransfer;
+                            startAddress += (SDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY / sizeof(uint32_t));
+                        }
+                    }
+
+                    /* When use ADMA, disable simple DMA */
+                    base->DSADDR = 0U;
+                    base->ADSADDR = (uint32_t)table;
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    return error;
+}
+
+status_t SDHC_TransferBlocking(SDHC_Type *base, uint32_t *admaTable, uint32_t admaTableWords, sdhc_transfer_t *transfer)
+{
+    assert(transfer);
+    assert(transfer->command); /* Command must not be NULL, data can be NULL. */
+
+    status_t error = kStatus_Success;
+    sdhc_dma_mode_t dmaMode = (sdhc_dma_mode_t)((base->PROCTL & SDHC_PROCTL_DMAS_MASK) >> SDHC_PROCTL_DMAS_SHIFT);
+    sdhc_command_t *command = transfer->command;
+    sdhc_data_t *data = transfer->data;
+
+    /* DATA-PORT is 32-bit align, ADMA2 4 bytes align, ADMA1 is 4096 bytes align */
+    if ((!command) || (data && (data->blockSize % 4U)))
+    {
+        error = kStatus_InvalidArgument;
+    }
+    else
+    {
+        /* Wait until command/data bus out of busy status. */
+        while (SDHC_GetPresentStatusFlags(base) & kSDHC_CommandInhibitFlag)
+        {
+        }
+        while (data && (SDHC_GetPresentStatusFlags(base) & kSDHC_DataInhibitFlag))
+        {
+        }
+
+        /* Update ADMA descriptor table if data isn't NULL. */
+        if (data && (kStatus_Success != SDHC_SetAdmaTableConfig(base, dmaMode, admaTable, admaTableWords,
+                                                                (data->rxData ? data->rxData : data->txData),
+                                                                (data->blockCount * data->blockSize))))
+        {
+            error = kStatus_SDHC_PrepareAdmaDescriptorFailed;
+        }
+        else
+        {
+            SDHC_StartTransfer(base, command, data);
+
+            /* Send command and receive data. */
+            if (kStatus_Success != SDHC_SendCommandBlocking(base, command))
+            {
+                error = kStatus_SDHC_SendCommandFailed;
+            }
+            else if (data && (kStatus_Success != SDHC_TransferDataBlocking(dmaMode, base, data)))
+            {
+                error = kStatus_SDHC_TransferDataFailed;
+            }
+            else
+            {
+            }
+        }
+    }
+
+    return error;
+}
+
+void SDHC_TransferCreateHandle(SDHC_Type *base,
+                               sdhc_handle_t *handle,
+                               const sdhc_transfer_callback_t *callback,
+                               void *userData)
+{
+    assert(handle);
+    assert(callback);
+
+    /* Zero the handle. */
+    memset(handle, 0, sizeof(*handle));
+
+    /* Set the callback. */
+    handle->callback.CardInserted = callback->CardInserted;
+    handle->callback.CardRemoved = callback->CardRemoved;
+    handle->callback.SdioInterrupt = callback->SdioInterrupt;
+    handle->callback.SdioBlockGap = callback->SdioBlockGap;
+    handle->callback.TransferComplete = callback->TransferComplete;
+    handle->userData = userData;
+
+    /* Save the handle in global variables to support the double weak mechanism. */
+    s_sdhcHandle[SDHC_GetInstance(base)] = handle;
+
+    /* Enable interrupt in NVIC. */
+    SDHC_SetTransferInterrupt(base, true);
+    EnableIRQ(s_sdhcIRQ[SDHC_GetInstance(base)]);
+}
+
+status_t SDHC_TransferNonBlocking(
+    SDHC_Type *base, sdhc_handle_t *handle, uint32_t *admaTable, uint32_t admaTableWords, sdhc_transfer_t *transfer)
+{
+    assert(transfer);
+
+    sdhc_dma_mode_t dmaMode = (sdhc_dma_mode_t)((base->PROCTL & SDHC_PROCTL_DMAS_MASK) >> SDHC_PROCTL_DMAS_SHIFT);
+    status_t error = kStatus_Success;
+    sdhc_command_t *command = transfer->command;
+    sdhc_data_t *data = transfer->data;
+
+    /* DATA-PORT is 32-bit align, ADMA2 4 bytes align, ADMA1 is 4096 bytes align */
+    if ((!(transfer->command)) || ((transfer->data) && (transfer->data->blockSize % 4U)))
+    {
+        error = kStatus_InvalidArgument;
+    }
+    else
+    {
+        /* Wait until command/data bus out of busy status. */
+        if ((SDHC_GetPresentStatusFlags(base) & kSDHC_CommandInhibitFlag) ||
+            (data && (SDHC_GetPresentStatusFlags(base) & kSDHC_DataInhibitFlag)))
+        {
+            error = kStatus_SDHC_BusyTransferring;
+        }
+        else
+        {
+            /* Update ADMA descriptor table and reset transferred words if data isn't NULL. */
+            if (data && (kStatus_Success != SDHC_SetAdmaTableConfig(base, dmaMode, admaTable, admaTableWords,
+                                                                    (data->rxData ? data->rxData : data->txData),
+                                                                    (data->blockCount * data->blockSize))))
+            {
+                error = kStatus_SDHC_PrepareAdmaDescriptorFailed;
+            }
+            else
+            {
+                /* Save command and data into handle before transferring. */
+                handle->command = command;
+                handle->data = data;
+                handle->interruptFlags = 0U;
+                /* transferredWords will only be updated in ISR when transfer way is DATAPORT. */
+                handle->transferredWords = 0U;
+                SDHC_StartTransfer(base, command, data);
+            }
+        }
+    }
+
+    return error;
+}
+
+void SDHC_TransferHandleIRQ(SDHC_Type *base, sdhc_handle_t *handle)
+{
+    assert(handle);
+
+    uint32_t interruptFlags;
+
+    interruptFlags = SDHC_GetInterruptStatusFlags(base);
+    handle->interruptFlags = interruptFlags;
+
+    if (interruptFlags & kSDHC_CardDetectFlag)
+    {
+        SDHC_TransferHandleCardDetect(handle, (interruptFlags & kSDHC_CardDetectFlag));
+    }
+    if (interruptFlags & kSDHC_CommandFlag)
+    {
+        SDHC_TransferHandleCommand(base, handle, (interruptFlags & kSDHC_CommandFlag));
+    }
+    if (interruptFlags & kSDHC_DataFlag)
+    {
+        SDHC_TransferHandleData(base, handle, (interruptFlags & kSDHC_DataFlag));
+    }
+    if (interruptFlags & kSDHC_CardInterruptFlag)
+    {
+        SDHC_TransferHandleSdioInterrupt(handle);
+    }
+    if (interruptFlags & kSDHC_BlockGapEventFlag)
+    {
+        SDHC_TransferHandleSdioBlockGap(handle);
+    }
+
+    SDHC_ClearInterruptStatusFlags(base, interruptFlags);
+}
+
+#if defined(SDHC)
+void SDHC_DriverIRQHandler(void)
+{
+    assert(s_sdhcHandle[0]);
+
+    SDHC_TransferHandleIRQ(SDHC, s_sdhcHandle[0]);
+}
+#endif