/*
 * Copyright (c) 2015, Freescale Semiconductor, Inc.
 * Copyright 2016-2020 NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */
#ifndef _FSL_SDHC_H_
#define _FSL_SDHC_H_

#include "fsl_common.h"

/*!
 * @addtogroup sdhc
 * @{
 */

/******************************************************************************
 * Definitions.
 *****************************************************************************/

/*! @name Driver version */
/*@{*/
/*! @brief Driver version 2.1.12. */
#define FSL_SDHC_DRIVER_VERSION (MAKE_VERSION(2U, 1U, 12U))
/*@}*/

/*! @brief Maximum block count can be set one time */
#define SDHC_MAX_BLOCK_COUNT (SDHC_BLKATTR_BLKCNT_MASK >> SDHC_BLKATTR_BLKCNT_SHIFT)

/*! @brief _sdhc_status SDHC status */
enum
{
    kStatus_SDHC_BusyTransferring            = MAKE_STATUS(kStatusGroup_SDHC, 0U), /*!< Transfer is on-going */
    kStatus_SDHC_PrepareAdmaDescriptorFailed = MAKE_STATUS(kStatusGroup_SDHC, 1U), /*!< Set DMA descriptor failed */
    kStatus_SDHC_SendCommandFailed           = MAKE_STATUS(kStatusGroup_SDHC, 2U), /*!< Send command failed */
    kStatus_SDHC_TransferDataFailed          = MAKE_STATUS(kStatusGroup_SDHC, 3U), /*!< Transfer data failed */
    kStatus_SDHC_DMADataBufferAddrNotAlign =
        MAKE_STATUS(kStatusGroup_SDHC, 4U), /*!< data buffer addr not align in DMA mode */
    kStatus_SDHC_TransferCommandComplete = MAKE_STATUS(kStatusGroup_SDHC, 5U), /*!< command transfer complete */
    kStatus_SDHC_TransferDataComplete    = MAKE_STATUS(kStatusGroup_SDHC, 6U), /*!< data transfer complete */
};

/*! @brief _sdhc_capability_flag Host controller capabilities flag mask */
enum
{
    kSDHC_SupportAdmaFlag          = SDHC_HTCAPBLT_ADMAS_MASK, /*!< Support ADMA */
    kSDHC_SupportHighSpeedFlag     = SDHC_HTCAPBLT_HSS_MASK,   /*!< Support high-speed */
    kSDHC_SupportDmaFlag           = SDHC_HTCAPBLT_DMAS_MASK,  /*!< Support DMA */
    kSDHC_SupportSuspendResumeFlag = SDHC_HTCAPBLT_SRS_MASK,   /*!< Support suspend/resume */
    kSDHC_SupportV330Flag          = SDHC_HTCAPBLT_VS33_MASK,  /*!< Support voltage 3.3V */
#if defined FSL_FEATURE_SDHC_HAS_V300_SUPPORT && FSL_FEATURE_SDHC_HAS_V300_SUPPORT
    kSDHC_SupportV300Flag = SDHC_HTCAPBLT_VS30_MASK, /*!< Support voltage 3.0V */
#endif
#if defined FSL_FEATURE_SDHC_HAS_V180_SUPPORT && FSL_FEATURE_SDHC_HAS_V180_SUPPORT
    kSDHC_SupportV180Flag = SDHC_HTCAPBLT_VS18_MASK, /*!< Support voltage 1.8V */
#endif
    /* Put additional two flags in HTCAPBLT_MBL's position. */
    kSDHC_Support4BitFlag = (SDHC_HTCAPBLT_MBL_SHIFT << 0U), /*!< Support 4 bit mode */
    kSDHC_Support8BitFlag = (SDHC_HTCAPBLT_MBL_SHIFT << 1U), /*!< Support 8 bit mode */
};

/*! @brief _sdhc_wakeup_event Wakeup event mask */
enum
{
    kSDHC_WakeupEventOnCardInt    = SDHC_PROCTL_WECINT_MASK, /*!< Wakeup on card interrupt */
    kSDHC_WakeupEventOnCardInsert = SDHC_PROCTL_WECINS_MASK, /*!< Wakeup on card insertion */
    kSDHC_WakeupEventOnCardRemove = SDHC_PROCTL_WECRM_MASK,  /*!< Wakeup on card removal */

    kSDHC_WakeupEventsAll = (kSDHC_WakeupEventOnCardInt | kSDHC_WakeupEventOnCardInsert |
                             kSDHC_WakeupEventOnCardRemove), /*!< All wakeup events */
};

/*! @brief _sdhc_reset Reset type mask */
enum
{
    kSDHC_ResetAll     = SDHC_SYSCTL_RSTA_MASK, /*!< Reset all except card detection */
    kSDHC_ResetCommand = SDHC_SYSCTL_RSTC_MASK, /*!< Reset command line */
    kSDHC_ResetData    = SDHC_SYSCTL_RSTD_MASK, /*!< Reset data line */

    kSDHC_ResetsAll = (kSDHC_ResetAll | kSDHC_ResetCommand | kSDHC_ResetData), /*!< All reset types */
};

/*! @brief _sdhc_transfer_flag Transfer flag mask */
enum
{
    kSDHC_EnableDmaFlag = SDHC_XFERTYP_DMAEN_MASK, /*!< Enable DMA */

    kSDHC_CommandTypeSuspendFlag = (SDHC_XFERTYP_CMDTYP(1U)), /*!< Suspend command */
    kSDHC_CommandTypeResumeFlag  = (SDHC_XFERTYP_CMDTYP(2U)), /*!< Resume command */
    kSDHC_CommandTypeAbortFlag   = (SDHC_XFERTYP_CMDTYP(3U)), /*!< Abort command */

    kSDHC_EnableBlockCountFlag    = SDHC_XFERTYP_BCEN_MASK,   /*!< Enable block count */
    kSDHC_EnableAutoCommand12Flag = SDHC_XFERTYP_AC12EN_MASK, /*!< Enable auto CMD12 */
    kSDHC_DataReadFlag            = SDHC_XFERTYP_DTDSEL_MASK, /*!< Enable data read */
    kSDHC_MultipleBlockFlag       = SDHC_XFERTYP_MSBSEL_MASK, /*!< Multiple block data read/write */

    kSDHC_ResponseLength136Flag    = SDHC_XFERTYP_RSPTYP(1U), /*!< 136 bit response length */
    kSDHC_ResponseLength48Flag     = SDHC_XFERTYP_RSPTYP(2U), /*!< 48 bit response length */
    kSDHC_ResponseLength48BusyFlag = SDHC_XFERTYP_RSPTYP(3U), /*!< 48 bit response length with busy status */

    kSDHC_EnableCrcCheckFlag   = SDHC_XFERTYP_CCCEN_MASK, /*!< Enable CRC check */
    kSDHC_EnableIndexCheckFlag = SDHC_XFERTYP_CICEN_MASK, /*!< Enable index check */
    kSDHC_DataPresentFlag      = SDHC_XFERTYP_DPSEL_MASK, /*!< Data present flag */
};

/*! @brief _sdhc_present_status_flag Present status flag mask */
enum
{
    kSDHC_CommandInhibitFlag      = SDHC_PRSSTAT_CIHB_MASK,  /*!< Command inhibit */
    kSDHC_DataInhibitFlag         = SDHC_PRSSTAT_CDIHB_MASK, /*!< Data inhibit */
    kSDHC_DataLineActiveFlag      = SDHC_PRSSTAT_DLA_MASK,   /*!< Data line active */
    kSDHC_SdClockStableFlag       = SDHC_PRSSTAT_SDSTB_MASK, /*!< SD bus clock stable */
    kSDHC_WriteTransferActiveFlag = SDHC_PRSSTAT_WTA_MASK,   /*!< Write transfer active */
    kSDHC_ReadTransferActiveFlag  = SDHC_PRSSTAT_RTA_MASK,   /*!< Read transfer active */
    kSDHC_BufferWriteEnableFlag   = SDHC_PRSSTAT_BWEN_MASK,  /*!< Buffer write enable */
    kSDHC_BufferReadEnableFlag    = SDHC_PRSSTAT_BREN_MASK,  /*!< Buffer read enable */
    kSDHC_CardInsertedFlag        = SDHC_PRSSTAT_CINS_MASK,  /*!< Card inserted */
    kSDHC_CommandLineLevelFlag    = SDHC_PRSSTAT_CLSL_MASK,  /*!< Command line signal level */

    kSDHC_Data0LineLevelFlag = (1U << 24U),      /*!< Data0 line signal level */
    kSDHC_Data1LineLevelFlag = (1U << 25U),      /*!< Data1 line signal level */
    kSDHC_Data2LineLevelFlag = (1U << 26U),      /*!< Data2 line signal level */
    kSDHC_Data3LineLevelFlag = (1U << 27U),      /*!< Data3 line signal level */
    kSDHC_Data4LineLevelFlag = (1U << 28U),      /*!< Data4 line signal level */
    kSDHC_Data5LineLevelFlag = (1U << 29U),      /*!< Data5 line signal level */
    kSDHC_Data6LineLevelFlag = (1U << 30U),      /*!< Data6 line signal level */
    kSDHC_Data7LineLevelFlag = (int)(1U << 31U), /*!< Data7 line signal level */
};

/*! @brief _sdhc_interrupt_status_flag Interrupt status flag mask */
enum
{
    kSDHC_CommandCompleteFlag    = SDHC_IRQSTAT_CC_MASK,    /*!< Command complete */
    kSDHC_DataCompleteFlag       = SDHC_IRQSTAT_TC_MASK,    /*!< Data complete */
    kSDHC_BlockGapEventFlag      = SDHC_IRQSTAT_BGE_MASK,   /*!< Block gap event */
    kSDHC_DmaCompleteFlag        = SDHC_IRQSTAT_DINT_MASK,  /*!< DMA interrupt */
    kSDHC_BufferWriteReadyFlag   = SDHC_IRQSTAT_BWR_MASK,   /*!< Buffer write ready */
    kSDHC_BufferReadReadyFlag    = SDHC_IRQSTAT_BRR_MASK,   /*!< Buffer read ready */
    kSDHC_CardInsertionFlag      = SDHC_IRQSTAT_CINS_MASK,  /*!< Card inserted */
    kSDHC_CardRemovalFlag        = SDHC_IRQSTAT_CRM_MASK,   /*!< Card removed */
    kSDHC_CardInterruptFlag      = SDHC_IRQSTAT_CINT_MASK,  /*!< Card interrupt */
    kSDHC_CommandTimeoutFlag     = SDHC_IRQSTAT_CTOE_MASK,  /*!< Command timeout error */
    kSDHC_CommandCrcErrorFlag    = SDHC_IRQSTAT_CCE_MASK,   /*!< Command CRC error */
    kSDHC_CommandEndBitErrorFlag = SDHC_IRQSTAT_CEBE_MASK,  /*!< Command end bit error */
    kSDHC_CommandIndexErrorFlag  = SDHC_IRQSTAT_CIE_MASK,   /*!< Command index error */
    kSDHC_DataTimeoutFlag        = SDHC_IRQSTAT_DTOE_MASK,  /*!< Data timeout error */
    kSDHC_DataCrcErrorFlag       = SDHC_IRQSTAT_DCE_MASK,   /*!< Data CRC error */
    kSDHC_DataEndBitErrorFlag    = SDHC_IRQSTAT_DEBE_MASK,  /*!< Data end bit error */
    kSDHC_AutoCommand12ErrorFlag = SDHC_IRQSTAT_AC12E_MASK, /*!< Auto CMD12 error */
    kSDHC_DmaErrorFlag           = SDHC_IRQSTAT_DMAE_MASK,  /*!< DMA error */

    kSDHC_CommandErrorFlag = (kSDHC_CommandTimeoutFlag | kSDHC_CommandCrcErrorFlag | kSDHC_CommandEndBitErrorFlag |
                              kSDHC_CommandIndexErrorFlag), /*!< Command error */
    kSDHC_DataErrorFlag    = (kSDHC_DataTimeoutFlag | kSDHC_DataCrcErrorFlag | kSDHC_DataEndBitErrorFlag |
                           kSDHC_AutoCommand12ErrorFlag),                                      /*!< Data error */
    kSDHC_ErrorFlag        = (kSDHC_CommandErrorFlag | kSDHC_DataErrorFlag | kSDHC_DmaErrorFlag), /*!< All error */
    kSDHC_DataFlag         = (kSDHC_DataCompleteFlag | kSDHC_BufferWriteReadyFlag | kSDHC_BufferReadReadyFlag |
                      kSDHC_DataErrorFlag),                                             /*!< Data interrupts */
    kSDHC_DataDMAFlag    = (kSDHC_DataCompleteFlag | kSDHC_DataErrorFlag | kSDHC_DmaErrorFlag), /*!< Data interrupts */
    kSDHC_CommandFlag    = (kSDHC_CommandErrorFlag | kSDHC_CommandCompleteFlag), /*!< Command interrupts */
    kSDHC_CardDetectFlag = (kSDHC_CardInsertionFlag | kSDHC_CardRemovalFlag),    /*!< Card detection interrupts */

    kSDHC_AllInterruptFlags = (kSDHC_BlockGapEventFlag | kSDHC_CardInterruptFlag | kSDHC_CommandFlag | kSDHC_DataFlag |
                               kSDHC_ErrorFlag), /*!< All flags mask */
};

/*! @brief _sdhc_auto_command12_error_status_flag Auto CMD12 error status flag mask */
enum
{
    kSDHC_AutoCommand12NotExecutedFlag = SDHC_AC12ERR_AC12NE_MASK,    /*!< Not executed error */
    kSDHC_AutoCommand12TimeoutFlag     = SDHC_AC12ERR_AC12TOE_MASK,   /*!< Timeout error */
    kSDHC_AutoCommand12EndBitErrorFlag = SDHC_AC12ERR_AC12EBE_MASK,   /*!< End bit error */
    kSDHC_AutoCommand12CrcErrorFlag    = SDHC_AC12ERR_AC12CE_MASK,    /*!< CRC error */
    kSDHC_AutoCommand12IndexErrorFlag  = SDHC_AC12ERR_AC12IE_MASK,    /*!< Index error */
    kSDHC_AutoCommand12NotIssuedFlag   = SDHC_AC12ERR_CNIBAC12E_MASK, /*!< Not issued error */
};

/*! @brief _sdhc_adma_error_status_flag ADMA error status flag mask */
enum
{
    kSDHC_AdmaLenghMismatchFlag   = SDHC_ADMAES_ADMALME_MASK, /*!< Length mismatch error */
    kSDHC_AdmaDescriptorErrorFlag = SDHC_ADMAES_ADMADCE_MASK, /*!< Descriptor error */
};

/*!
 * @brief ADMA error state
 *
 * This state is the detail state when ADMA error has occurred.
 */
typedef enum _sdhc_adma_error_state
{
    kSDHC_AdmaErrorStateStopDma         = 0x00U, /*!< Stop DMA */
    kSDHC_AdmaErrorStateFetchDescriptor = 0x01U, /*!< Fetch descriptor */
    kSDHC_AdmaErrorStateChangeAddress   = 0x02U, /*!< Change address */
    kSDHC_AdmaErrorStateTransferData    = 0x03U, /*!< Transfer data */
} sdhc_adma_error_state_t;

/*! @brief _sdhc_force_event Force event bit position */
enum
{
    kSDHC_ForceEventAutoCommand12NotExecuted = SDHC_FEVT_AC12NE_MASK,    /*!< Auto CMD12 not executed error */
    kSDHC_ForceEventAutoCommand12Timeout     = SDHC_FEVT_AC12TOE_MASK,   /*!< Auto CMD12 timeout error */
    kSDHC_ForceEventAutoCommand12CrcError    = SDHC_FEVT_AC12CE_MASK,    /*!< Auto CMD12 CRC error */
    kSDHC_ForceEventEndBitError              = SDHC_FEVT_AC12EBE_MASK,   /*!< Auto CMD12 end bit error */
    kSDHC_ForceEventAutoCommand12IndexError  = SDHC_FEVT_AC12IE_MASK,    /*!< Auto CMD12 index error */
    kSDHC_ForceEventAutoCommand12NotIssued   = SDHC_FEVT_CNIBAC12E_MASK, /*!< Auto CMD12 not issued error */
    kSDHC_ForceEventCommandTimeout           = SDHC_FEVT_CTOE_MASK,      /*!< Command timeout error */
    kSDHC_ForceEventCommandCrcError          = SDHC_FEVT_CCE_MASK,       /*!< Command CRC error */
    kSDHC_ForceEventCommandEndBitError       = SDHC_FEVT_CEBE_MASK,      /*!< Command end bit error */
    kSDHC_ForceEventCommandIndexError        = SDHC_FEVT_CIE_MASK,       /*!< Command index error */
    kSDHC_ForceEventDataTimeout              = SDHC_FEVT_DTOE_MASK,      /*!< Data timeout error */
    kSDHC_ForceEventDataCrcError             = SDHC_FEVT_DCE_MASK,       /*!< Data CRC error */
    kSDHC_ForceEventDataEndBitError          = SDHC_FEVT_DEBE_MASK,      /*!< Data end bit error */
    kSDHC_ForceEventAutoCommand12Error       = SDHC_FEVT_AC12E_MASK,     /*!< Auto CMD12 error */
    kSDHC_ForceEventCardInt                  = (int)SDHC_FEVT_CINT_MASK, /*!< Card interrupt */
    kSDHC_ForceEventDmaError                 = SDHC_FEVT_DMAE_MASK,      /*!< Dma error */

    kSDHC_ForceEventsAll = (int)(SDHC_FEVT_AC12NE_MASK | SDHC_FEVT_AC12TOE_MASK | SDHC_FEVT_AC12CE_MASK |
                                 SDHC_FEVT_AC12EBE_MASK | SDHC_FEVT_AC12IE_MASK | SDHC_FEVT_CNIBAC12E_MASK |
                                 SDHC_FEVT_CTOE_MASK | SDHC_FEVT_CCE_MASK | SDHC_FEVT_CEBE_MASK | SDHC_FEVT_CIE_MASK |
                                 SDHC_FEVT_DTOE_MASK | SDHC_FEVT_DCE_MASK | SDHC_FEVT_DEBE_MASK | SDHC_FEVT_AC12E_MASK |
                                 SDHC_FEVT_CINT_MASK | SDHC_FEVT_DMAE_MASK), /*!< All force event flags mask */
};

/*! @brief Data transfer width */
typedef enum _sdhc_data_bus_width
{
    kSDHC_DataBusWidth1Bit = 0U, /*!< 1-bit mode */
    kSDHC_DataBusWidth4Bit = 1U, /*!< 4-bit mode */
    kSDHC_DataBusWidth8Bit = 2U, /*!< 8-bit mode */
} sdhc_data_bus_width_t;

/*! @brief Endian mode */
typedef enum _sdhc_endian_mode
{
    kSDHC_EndianModeBig         = 0U, /*!< Big endian mode */
    kSDHC_EndianModeHalfWordBig = 1U, /*!< Half word big endian mode */
    kSDHC_EndianModeLittle      = 2U, /*!< Little endian mode */
} sdhc_endian_mode_t;

/*! @brief DMA mode */
typedef enum _sdhc_dma_mode
{
    kSDHC_DmaModeNo    = 0U, /*!< No DMA */
    kSDHC_DmaModeAdma1 = 1U, /*!< ADMA1 is selected */
    kSDHC_DmaModeAdma2 = 2U, /*!< ADMA2 is selected */
} sdhc_dma_mode_t;

/*! @brief _sdhc_sdio_control_flag SDIO control flag mask */
enum
{
    kSDHC_StopAtBlockGapFlag       = 0x01, /*!< Stop at block gap */
    kSDHC_ReadWaitControlFlag      = 0x02, /*!< Read wait control */
    kSDHC_InterruptAtBlockGapFlag  = 0x04, /*!< Interrupt at block gap */
    kSDHC_ExactBlockNumberReadFlag = 0x08, /*!< Exact block number read */
};

/*! @brief MMC card boot mode */
typedef enum _sdhc_boot_mode
{
    kSDHC_BootModeNormal      = 0U, /*!< Normal boot */
    kSDHC_BootModeAlternative = 1U, /*!< Alternative boot */
} sdhc_boot_mode_t;

/*! @brief The command type */
typedef enum _sdhc_card_command_type
{
    kCARD_CommandTypeNormal  = 0U, /*!< Normal command */
    kCARD_CommandTypeSuspend = 1U, /*!< Suspend command */
    kCARD_CommandTypeResume  = 2U, /*!< Resume command */
    kCARD_CommandTypeAbort   = 3U, /*!< Abort command */
} sdhc_card_command_type_t;

/*!
 * @brief The command response type.
 *
 * Define the command response type from card to host controller.
 */
typedef enum _sdhc_card_response_type
{
    kCARD_ResponseTypeNone = 0U, /*!< Response type: none */
    kCARD_ResponseTypeR1   = 1U, /*!< Response type: R1 */
    kCARD_ResponseTypeR1b  = 2U, /*!< Response type: R1b */
    kCARD_ResponseTypeR2   = 3U, /*!< Response type: R2 */
    kCARD_ResponseTypeR3   = 4U, /*!< Response type: R3 */
    kCARD_ResponseTypeR4   = 5U, /*!< Response type: R4 */
    kCARD_ResponseTypeR5   = 6U, /*!< Response type: R5 */
    kCARD_ResponseTypeR5b  = 7U, /*!< Response type: R5b */
    kCARD_ResponseTypeR6   = 8U, /*!< Response type: R6 */
    kCARD_ResponseTypeR7   = 9U, /*!< Response type: R7 */
} sdhc_card_response_type_t;

/*! @brief The alignment size for ADDRESS filed in ADMA1's descriptor */
#define SDHC_ADMA1_ADDRESS_ALIGN (4096U)
/*! @brief The alignment size for LENGTH field in ADMA1's descriptor */
#define SDHC_ADMA1_LENGTH_ALIGN (4096U)
/*! @brief The alignment size for ADDRESS field in ADMA2's descriptor */
#define SDHC_ADMA2_ADDRESS_ALIGN (4U)
/*! @brief The alignment size for LENGTH filed in ADMA2's descriptor */
#define SDHC_ADMA2_LENGTH_ALIGN (4U)

/* ADMA1 descriptor table
 * |------------------------|---------|--------------------------|
 * | Address/page field     |Reserved |         Attribute        |
 * |------------------------|---------|--------------------------|
 * |31                    12|11      6|05  |04  |03|02 |01 |00   |
 * |------------------------|---------|----|----|--|---|---|-----|
 * | address or data length | 000000  |Act2|Act1| 0|Int|End|Valid|
 * |------------------------|---------|----|----|--|---|---|-----|
 *
 *
 * |------|------|-----------------|-------|-------------|
 * | Act2 | Act1 |     Comment     | 31-28 | 27 - 12     |
 * |------|------|-----------------|---------------------|
 * |   0  |   0  | No op           | Don't care          |
 * |------|------|-----------------|-------|-------------|
 * |   0  |   1  | Set data length |  0000 | Data Length |
 * |------|------|-----------------|-------|-------------|
 * |   1  |   0  | Transfer data   | Data address        |
 * |------|------|-----------------|---------------------|
 * |   1  |   1  | Link descriptor | Descriptor address  |
 * |------|------|-----------------|---------------------|
 */
/*! @brief The bit shift for ADDRESS filed in ADMA1's descriptor */
#define SDHC_ADMA1_DESCRIPTOR_ADDRESS_SHIFT (12U)
/*! @brief The bit mask for ADDRESS field in ADMA1's descriptor */
#define SDHC_ADMA1_DESCRIPTOR_ADDRESS_MASK (0xFFFFFU)
/*! @brief The bit shift for LENGTH filed in ADMA1's descriptor */
#define SDHC_ADMA1_DESCRIPTOR_LENGTH_SHIFT (12U)
/*! @brief The mask for LENGTH field in ADMA1's descriptor */
#define SDHC_ADMA1_DESCRIPTOR_LENGTH_MASK (0xFFFFU)
/*! @brief The maximum value of LENGTH filed in ADMA1's descriptor */
#define SDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY (SDHC_ADMA1_DESCRIPTOR_LENGTH_MASK + 1U - 4096U)

/*! @brief _sdhc_adma1_descriptor_flag The mask for the control/status field in ADMA1 descriptor */
enum
{
    kSDHC_Adma1DescriptorValidFlag     = (1U << 0U),                       /*!< Valid flag */
    kSDHC_Adma1DescriptorEndFlag       = (1U << 1U),                       /*!< End flag */
    kSDHC_Adma1DescriptorInterrupFlag  = (1U << 2U),                       /*!< Interrupt flag */
    kSDHC_Adma1DescriptorActivity1Flag = (1U << 4U),                       /*!< Activity 1 flag */
    kSDHC_Adma1DescriptorActivity2Flag = (1U << 5U),                       /*!< Activity 2 flag */
    kSDHC_Adma1DescriptorTypeNop       = (kSDHC_Adma1DescriptorValidFlag), /*!< No operation */
    kSDHC_Adma1DescriptorTypeTransfer =
        (kSDHC_Adma1DescriptorActivity2Flag | kSDHC_Adma1DescriptorValidFlag), /*!< Transfer data */
    kSDHC_Adma1DescriptorTypeLink = (kSDHC_Adma1DescriptorActivity1Flag | kSDHC_Adma1DescriptorActivity2Flag |
                                     kSDHC_Adma1DescriptorValidFlag), /*!< Link descriptor */
    kSDHC_Adma1DescriptorTypeSetLength =
        (kSDHC_Adma1DescriptorActivity1Flag | kSDHC_Adma1DescriptorValidFlag), /*!< Set data length */
};

/* ADMA2 descriptor table
 * |----------------|---------------|-------------|--------------------------|
 * | Address field  |     Length    | Reserved    |         Attribute        |
 * |----------------|---------------|-------------|--------------------------|
 * |63            32|31           16|15         06|05  |04  |03|02 |01 |00   |
 * |----------------|---------------|-------------|----|----|--|---|---|-----|
 * | 32-bit address | 16-bit length | 0000000000  |Act2|Act1| 0|Int|End|Valid|
 * |----------------|---------------|-------------|----|----|--|---|---|-----|
 *
 *
 * | Act2 | Act1 |     Comment     | Operation                                                         |
 * |------|------|-----------------|-------------------------------------------------------------------|
 * |   0  |   0  | No op           | Don't care                                                        |
 * |------|------|-----------------|-------------------------------------------------------------------|
 * |   0  |   1  | Reserved        | Read this line and go to next one                                 |
 * |------|------|-----------------|-------------------------------------------------------------------|
 * |   1  |   0  | Transfer data   | Transfer data with address and length set in this descriptor line |
 * |------|------|-----------------|-------------------------------------------------------------------|
 * |   1  |   1  | Link descriptor | Link to another descriptor                                        |
 * |------|------|-----------------|-------------------------------------------------------------------|
 */
/*! @brief The bit shift for LENGTH field in ADMA2's descriptor */
#define SDHC_ADMA2_DESCRIPTOR_LENGTH_SHIFT (16U)
/*! @brief The bit mask for LENGTH field in ADMA2's descriptor */
#define SDHC_ADMA2_DESCRIPTOR_LENGTH_MASK (0xFFFFUL)
/*! @brief The maximum value of LENGTH field in ADMA2's descriptor */
#define SDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY (SDHC_ADMA2_DESCRIPTOR_LENGTH_MASK)

/*! @brief _sdhc_adma2_descriptor_flag ADMA1 descriptor control and status mask */
enum
{
    kSDHC_Adma2DescriptorValidFlag     = (1U << 0U), /*!< Valid flag */
    kSDHC_Adma2DescriptorEndFlag       = (1U << 1U), /*!< End flag */
    kSDHC_Adma2DescriptorInterruptFlag = (1U << 2U), /*!< Interrupt flag */
    kSDHC_Adma2DescriptorActivity1Flag = (1U << 4U), /*!< Activity 1 mask */
    kSDHC_Adma2DescriptorActivity2Flag = (1U << 5U), /*!< Activity 2 mask */

    kSDHC_Adma2DescriptorTypeNop = (kSDHC_Adma2DescriptorValidFlag), /*!< No operation */
    kSDHC_Adma2DescriptorTypeReserved =
        (kSDHC_Adma2DescriptorActivity1Flag | kSDHC_Adma2DescriptorValidFlag), /*!< Reserved */
    kSDHC_Adma2DescriptorTypeTransfer =
        (kSDHC_Adma2DescriptorActivity2Flag | kSDHC_Adma2DescriptorValidFlag), /*!< Transfer type */
    kSDHC_Adma2DescriptorTypeLink = (kSDHC_Adma2DescriptorActivity1Flag | kSDHC_Adma2DescriptorActivity2Flag |
                                     kSDHC_Adma2DescriptorValidFlag), /*!< Link type */
};

/*! @brief Defines the adma1 descriptor structure. */
typedef uint32_t sdhc_adma1_descriptor_t;

/*! @brief Defines the ADMA2 descriptor structure. */
typedef struct _sdhc_adma2_descriptor
{
    uint32_t attribute;      /*!< The control and status field */
    const uint32_t *address; /*!< The address field */
} sdhc_adma2_descriptor_t;

/*!
 * @brief SDHC capability information.
 *
 * Defines a structure to save the capability information of SDHC.
 */
typedef struct _sdhc_capability
{
    uint32_t specVersion;    /*!< Specification version */
    uint32_t vendorVersion;  /*!< Vendor version */
    uint32_t maxBlockLength; /*!< Maximum block length united as byte */
    uint32_t maxBlockCount;  /*!< Maximum block count can be set one time */
    uint32_t flags;          /*!< Capability flags to indicate the support information(_sdhc_capability_flag) */
} sdhc_capability_t;

/*! @brief Card transfer configuration.
 *
 * Define structure to configure the transfer-related command index/argument/flags and data block
 * size/data block numbers. This structure needs to be filled each time a command is sent to the card.
 */
typedef struct _sdhc_transfer_config
{
    size_t dataBlockSize;     /*!< Data block size */
    uint32_t dataBlockCount;  /*!< Data block count */
    uint32_t commandArgument; /*!< Command argument */
    uint32_t commandIndex;    /*!< Command index */
    uint32_t flags;           /*!< Transfer flags(_sdhc_transfer_flag) */
} sdhc_transfer_config_t;

/*! @brief Data structure to configure the MMC boot feature */
typedef struct _sdhc_boot_config
{
    uint32_t ackTimeoutCount;      /*!< Timeout value for the boot ACK. The available range is 0 ~ 15. */
    sdhc_boot_mode_t bootMode;     /*!< Boot mode selection. */
    uint32_t blockCount;           /*!< Stop at block gap value of automatic mode. Available range is 0 ~ 65535. */
    bool enableBootAck;            /*!< Enable or disable boot ACK */
    bool enableBoot;               /*!< Enable or disable fast boot */
    bool enableAutoStopAtBlockGap; /*!< Enable or disable auto stop at block gap function in boot period */
} sdhc_boot_config_t;

/*! @brief Data structure to initialize the SDHC */
typedef struct _sdhc_config
{
    bool cardDetectDat3;           /*!< Enable DAT3 as card detection pin */
    sdhc_endian_mode_t endianMode; /*!< Endian mode */
    sdhc_dma_mode_t dmaMode;       /*!< DMA mode */
    uint32_t readWatermarkLevel;   /*!< Watermark level for DMA read operation. Available range is 1 ~ 128. */
    uint32_t writeWatermarkLevel;  /*!< Watermark level for DMA write operation. Available range is 1 ~ 128. */
} sdhc_config_t;

/*!
 * @brief Card data descriptor
 *
 * Defines a structure to contain data-related attribute. 'enableIgnoreError' is used for the case that upper card
 * driver
 * want to ignore the error event to read/write all the data not to stop read/write immediately when error event
 * happen for example bus testing procedure for MMC card.
 */
typedef struct _sdhc_data
{
    bool enableAutoCommand12; /*!< Enable auto CMD12 */
    bool enableIgnoreError;   /*!< Enable to ignore error event to read/write all the data */
    size_t blockSize;         /*!< Block size */
    uint32_t blockCount;      /*!< Block count */
    uint32_t *rxData;         /*!< Buffer to save data read */
    const uint32_t *txData;   /*!< Data buffer to write */
} sdhc_data_t;

/*!
 * @brief Card command descriptor
 *
 * Define card command-related attribute.
 */
typedef struct _sdhc_command
{
    uint32_t index;                         /*!< Command index */
    uint32_t argument;                      /*!< Command argument */
    sdhc_card_command_type_t type;          /*!< Command type */
    sdhc_card_response_type_t responseType; /*!< Command response type */
    uint32_t response[4U];                  /*!< Response for this command */
    uint32_t responseErrorFlags;            /*!< response error flag, the flag which need to check
                                                the command reponse*/
} sdhc_command_t;

/*! @brief Transfer state */
typedef struct _sdhc_transfer
{
    sdhc_data_t *data;       /*!< Data to transfer */
    sdhc_command_t *command; /*!< Command to send */
} sdhc_transfer_t;

/*! @brief SDHC handle typedef */
typedef struct _sdhc_handle sdhc_handle_t;

/*! @brief SDHC callback functions. */
typedef struct _sdhc_transfer_callback
{
    void (*CardInserted)(SDHC_Type *base,
                         void *userData); /*!< Card inserted occurs when DAT3/CD pin is for card detect */
    void (*CardRemoved)(SDHC_Type *base, void *userData);   /*!< Card removed occurs */
    void (*SdioInterrupt)(SDHC_Type *base, void *userData); /*!< SDIO card interrupt occurs */
    void (*SdioBlockGap)(SDHC_Type *base, void *userData);  /*!< SDIO card stopped at block gap occurs */
    void (*TransferComplete)(SDHC_Type *base,
                             sdhc_handle_t *handle,
                             status_t status,
                             void *userData); /*!< Transfer complete callback */
} sdhc_transfer_callback_t;

/*!
 * @brief SDHC handle
 *
 * Defines the structure to save the SDHC state information and callback function. The detailed interrupt status when
 * sending a command or transfering data can be obtained from the interruptFlags field by using the mask defined in
 * sdhc_interrupt_flag_t.
 *
 * @note All the fields except interruptFlags and transferredWords must be allocated by the user.
 */
struct _sdhc_handle
{
    /* Transfer parameter */
    sdhc_data_t *volatile data;       /*!< Data to transfer */
    sdhc_command_t *volatile command; /*!< Command to send */

    /* Transfer status */
    volatile uint32_t transferredWords; /*!< Words transferred by DATAPORT way */

    /* Callback functions */
    sdhc_transfer_callback_t callback; /*!< Callback function */
    void *userData;                    /*!< Parameter for transfer complete callback */
};

/*! @brief SDHC transfer function. */
typedef status_t (*sdhc_transfer_function_t)(SDHC_Type *base, sdhc_transfer_t *content);

/*! @brief SDHC host descriptor */
typedef struct _sdhc_host
{
    SDHC_Type *base;                   /*!< SDHC peripheral base address */
    uint32_t sourceClock_Hz;           /*!< SDHC source clock frequency united in Hz */
    sdhc_config_t config;              /*!< SDHC configuration */
    sdhc_capability_t capability;      /*!< SDHC capability information */
    sdhc_transfer_function_t transfer; /*!< SDHC transfer function */
} sdhc_host_t;

/*************************************************************************************************
 * API
 ************************************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif

/*!
 * @name Initialization and deinitialization
 * @{
 */

/*!
 * @brief SDHC module initialization function.
 *
 * Configures the SDHC according to the user configuration.
 *
 * Example:
   @code
   sdhc_config_t config;
   config.cardDetectDat3 = false;
   config.endianMode = kSDHC_EndianModeLittle;
   config.dmaMode = kSDHC_DmaModeAdma2;
   config.readWatermarkLevel = 128U;
   config.writeWatermarkLevel = 128U;
   SDHC_Init(SDHC, &config);
   @endcode
 *
 * @param base SDHC peripheral base address.
 * @param config SDHC configuration information.
 * @retval kStatus_Success Operate successfully.
 */
void SDHC_Init(SDHC_Type *base, const sdhc_config_t *config);

/*!
 * @brief Deinitializes the SDHC.
 *
 * @param base SDHC peripheral base address.
 */
void SDHC_Deinit(SDHC_Type *base);

/*!
 * @brief Resets the SDHC.
 *
 * @param base SDHC peripheral base address.
 * @param mask The reset type mask(_sdhc_reset).
 * @param timeout Timeout for reset.
 * @retval true Reset successfully.
 * @retval false Reset failed.
 */
bool SDHC_Reset(SDHC_Type *base, uint32_t mask, uint32_t timeout);

/* @} */

/*!
 * @name DMA Control
 * @{
 */

/*!
 * @brief Sets the ADMA descriptor table configuration.
 *
 * @param base SDHC peripheral base address.
 * @param dmaMode DMA mode.
 * @param table ADMA table address.
 * @param tableWords ADMA table buffer length united as Words.
 * @param data Data buffer address.
 * @param dataBytes Data length united as bytes.
 * @retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
 * @retval kStatus_Success Operate successfully.
 */
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);

/* @} */

/*!
 * @name Interrupts
 * @{
 */

/*!
 * @brief Enables the interrupt status.
 *
 * @param base SDHC peripheral base address.
 * @param mask Interrupt status flags mask(_sdhc_interrupt_status_flag).
 */
static inline void SDHC_EnableInterruptStatus(SDHC_Type *base, uint32_t mask)
{
    base->IRQSTATEN |= mask;
}

/*!
 * @brief Disables the interrupt status.
 *
 * @param base SDHC peripheral base address.
 * @param mask The interrupt status flags mask(_sdhc_interrupt_status_flag).
 */
static inline void SDHC_DisableInterruptStatus(SDHC_Type *base, uint32_t mask)
{
    base->IRQSTATEN &= ~mask;
}

/*!
 * @brief Enables the interrupt signal corresponding to the interrupt status flag.
 *
 * @param base SDHC peripheral base address.
 * @param mask The interrupt status flags mask(_sdhc_interrupt_status_flag).
 */
static inline void SDHC_EnableInterruptSignal(SDHC_Type *base, uint32_t mask)
{
    base->IRQSIGEN |= mask;
}

/*!
 * @brief Disables the interrupt signal corresponding to the interrupt status flag.
 *
 * @param base SDHC peripheral base address.
 * @param mask The interrupt status flags mask(_sdhc_interrupt_status_flag).
 */
static inline void SDHC_DisableInterruptSignal(SDHC_Type *base, uint32_t mask)
{
    base->IRQSIGEN &= ~mask;
}

/* @} */

/*!
 * @name Status
 * @{
 */

/*!
 * @brief Gets the enabled interrupt status.
 *
 * @param base SDHC peripheral base address.
 * @return Current interrupt status flags mask(_sdhc_interrupt_status_flag).
 */
static inline uint32_t SDHC_GetEnabledInterruptStatusFlags(SDHC_Type *base)
{
    uint32_t intStatus = base->IRQSTAT;

    return intStatus & base->IRQSIGEN;
}

/*!
 * @brief Gets the current interrupt status.
 *
 * @param base SDHC peripheral base address.
 * @return Current interrupt status flags mask(_sdhc_interrupt_status_flag).
 */
static inline uint32_t SDHC_GetInterruptStatusFlags(SDHC_Type *base)
{
    return base->IRQSTAT;
}

/*!
 * @brief Clears a specified interrupt status.
 *
 * @param base SDHC peripheral base address.
 * @param mask The interrupt status flags mask(_sdhc_interrupt_status_flag).
 */
static inline void SDHC_ClearInterruptStatusFlags(SDHC_Type *base, uint32_t mask)
{
    base->IRQSTAT = mask;
}

/*!
 * @brief Gets the status of auto command 12 error.
 *
 * @param base SDHC peripheral base address.
 * @return Auto command 12 error status flags mask(_sdhc_auto_command12_error_status_flag).
 */
static inline uint32_t SDHC_GetAutoCommand12ErrorStatusFlags(SDHC_Type *base)
{
    return base->AC12ERR;
}

/*!
 * @brief Gets the status of the ADMA error.
 *
 * @param base SDHC peripheral base address.
 * @return ADMA error status flags mask(_sdhc_adma_error_status_flag).
 */
static inline uint32_t SDHC_GetAdmaErrorStatusFlags(SDHC_Type *base)
{
    return base->ADMAES;
}

/*!
 * @brief Gets a present status.
 *
 * This function gets the present SDHC's status except for an interrupt status and an error status.
 *
 * @param base SDHC peripheral base address.
 * @return Present SDHC's status flags mask(_sdhc_present_status_flag).
 */
static inline uint32_t SDHC_GetPresentStatusFlags(SDHC_Type *base)
{
    return base->PRSSTAT;
}

/* @} */

/*!
 * @name Bus Operations
 * @{
 */

/*!
 * @brief Gets the capability information.
 *
 * @param base SDHC peripheral base address.
 * @param capability Structure to save capability information.
 */
void SDHC_GetCapability(SDHC_Type *base, sdhc_capability_t *capability);

/*!
 * @brief Enables or disables the SD bus clock.
 *
 * @param base SDHC peripheral base address.
 * @param enable True to enable, false to disable.
 */
static inline void SDHC_EnableSdClock(SDHC_Type *base, bool enable)
{
    if (enable)
    {
        base->SYSCTL |= SDHC_SYSCTL_SDCLKEN_MASK;
    }
    else
    {
        base->SYSCTL &= ~SDHC_SYSCTL_SDCLKEN_MASK;
    }
}

/*!
 * @brief Sets the SD bus clock frequency.
 *
 * @param base SDHC peripheral base address.
 * @param srcClock_Hz SDHC source clock frequency united in Hz.
 * @param busClock_Hz SD bus clock frequency united in Hz.
 *
 * @return The nearest frequency of busClock_Hz configured to SD bus.
 */
uint32_t SDHC_SetSdClock(SDHC_Type *base, uint32_t srcClock_Hz, uint32_t busClock_Hz);

/*!
 * @brief Sends 80 clocks to the card to set it to the active state.
 *
 * This function must be called each time the card is inserted to ensure that the card can receive the command
 * correctly.
 *
 * @param base SDHC peripheral base address.
 * @param timeout Timeout to initialize card.
 * @retval true Set card active successfully.
 * @retval false Set card active failed.
 */
bool SDHC_SetCardActive(SDHC_Type *base, uint32_t timeout);

/*!
 * @brief Sets the data transfer width.
 *
 * @param base SDHC peripheral base address.
 * @param width Data transfer width.
 */
static inline void SDHC_SetDataBusWidth(SDHC_Type *base, sdhc_data_bus_width_t width)
{
    base->PROCTL = ((base->PROCTL & ~SDHC_PROCTL_DTW_MASK) | SDHC_PROCTL_DTW(width));
}

/*!
 * @brief detect card insert status.
 *
 * @param base SDHC peripheral base address.
 * @param enable Enable/disable flag.
 */
static inline void SDHC_CardDetectByData3(SDHC_Type *base, bool enable)
{
    if (enable)
    {
        base->PROCTL |= SDHC_PROCTL_D3CD_MASK;
    }
    else
    {
        base->PROCTL &= ~SDHC_PROCTL_D3CD_MASK;
    }
}

/*!
 * @brief Sets the card transfer-related configuration.
 *
 * This function fills the card transfer-related command argument/transfer flag/data size. The command and data are
 sent by
 * SDHC after calling this function.
 *
 * Example:
   @code
   sdhc_transfer_config_t transferConfig;
   transferConfig.dataBlockSize = 512U;
   transferConfig.dataBlockCount = 2U;
   transferConfig.commandArgument = 0x01AAU;
   transferConfig.commandIndex = 8U;
   transferConfig.flags |= (kSDHC_EnableDmaFlag | kSDHC_EnableAutoCommand12Flag | kSDHC_MultipleBlockFlag);
   SDHC_SetTransferConfig(SDHC, &transferConfig);
   @endcode
 *
 * @param base SDHC peripheral base address.
 * @param config Command configuration structure.
 */
void SDHC_SetTransferConfig(SDHC_Type *base, const sdhc_transfer_config_t *config);

/*!
 * @brief Gets the command response.
 *
 * @param base SDHC peripheral base address.
 * @param index The index of response register, range from 0 to 3.
 * @return Response register transfer.
 */
static inline uint32_t SDHC_GetCommandResponse(SDHC_Type *base, uint32_t index)
{
    assert(index < 4UL);

    return base->CMDRSP[index];
}

/*!
 * @brief Fills the data port.
 *
 * This function is used to implement the data transfer by Data Port instead of DMA.
 *
 * @param base SDHC peripheral base address.
 * @param data The data about to be sent.
 */
static inline void SDHC_WriteData(SDHC_Type *base, uint32_t data)
{
    base->DATPORT = data;
}

/*!
 * @brief Retrieves the data from the data port.
 *
 * This function is used to implement the data transfer by Data Port instead of DMA.
 *
 * @param base SDHC peripheral base address.
 * @return The data has been read.
 */
static inline uint32_t SDHC_ReadData(SDHC_Type *base)
{
    return base->DATPORT;
}

/*!
 * @brief Enables or disables a wakeup event in low-power mode.
 *
 * @param base SDHC peripheral base address.
 * @param mask Wakeup events mask(_sdhc_wakeup_event).
 * @param enable True to enable, false to disable.
 */
static inline void SDHC_EnableWakeupEvent(SDHC_Type *base, uint32_t mask, bool enable)
{
    if (enable)
    {
        base->PROCTL |= mask;
    }
    else
    {
        base->PROCTL &= ~mask;
    }
}

/*!
 * @brief Enables or disables the card detection level for testing.
 *
 * @param base SDHC peripheral base address.
 * @param enable True to enable, false to disable.
 */
static inline void SDHC_EnableCardDetectTest(SDHC_Type *base, bool enable)
{
    if (enable)
    {
        base->PROCTL |= SDHC_PROCTL_CDSS_MASK;
    }
    else
    {
        base->PROCTL &= ~SDHC_PROCTL_CDSS_MASK;
    }
}

/*!
 * @brief Sets the card detection test level.
 *
 * This function sets the card detection test level to indicate whether the card is inserted into the SDHC when
 * DAT[3]/ CD pin is selected as a card detection pin. This function can also assert the pin logic when DAT[3]/CD
 * pin is selected as the card detection pin.
 *
 * @param base SDHC peripheral base address.
 * @param high True to set the card detect level to high.
 */
static inline void SDHC_SetCardDetectTestLevel(SDHC_Type *base, bool high)
{
    if (high)
    {
        base->PROCTL |= SDHC_PROCTL_CDTL_MASK;
    }
    else
    {
        base->PROCTL &= ~SDHC_PROCTL_CDTL_MASK;
    }
}

/*!
 * @brief Enables or disables the SDIO card control.
 *
 * @param base SDHC peripheral base address.
 * @param mask SDIO card control flags mask(_sdhc_sdio_control_flag).
 * @param enable True to enable, false to disable.
 */
void SDHC_EnableSdioControl(SDHC_Type *base, uint32_t mask, bool enable);

/*!
 * @brief Restarts a transaction which has stopped at the block GAP for the SDIO card.
 *
 * @param base SDHC peripheral base address.
 */
static inline void SDHC_SetContinueRequest(SDHC_Type *base)
{
    base->PROCTL |= SDHC_PROCTL_CREQ_MASK;
}

/*!
 * @brief Configures the MMC boot feature.
 *
 * Example:
   @code
   sdhc_boot_config_t config;
   config.ackTimeoutCount = 4;
   config.bootMode = kSDHC_BootModeNormal;
   config.blockCount = 5;
   config.enableBootAck = true;
   config.enableBoot = true;
   config.enableAutoStopAtBlockGap = true;
   SDHC_SetMmcBootConfig(SDHC, &config);
   @endcode
 *
 * @param base SDHC peripheral base address.
 * @param config The MMC boot configuration information.
 */
void SDHC_SetMmcBootConfig(SDHC_Type *base, const sdhc_boot_config_t *config);

/*!
 * @brief Forces generating events according to the given mask.
 *
 * @param base SDHC peripheral base address.
 * @param mask The force events mask(_sdhc_force_event).
 */
static inline void SDHC_SetForceEvent(SDHC_Type *base, uint32_t mask)
{
    base->FEVT = mask;
}

/* @} */

/*!
 * @name Transactional
 * @{
 */

/*!
 * @brief Transfers the command/data using a blocking method.
 *
 * This function waits until the command response/data is received or the SDHC encounters an error by polling the
 * status flag. This function support non word align data addr transfer support, if data buffer addr is not align in
 * DMA mode, the API will continue finish the transfer by polling IO directly The application must not call this API
 * in multiple threads at the same time. Because of that this API doesn't support the re-entry mechanism.
 *
 * @note There is no need to call the API 'SDHC_TransferCreateHandle' when calling this API.
 *
 * @param base SDHC peripheral base address.
 * @param admaTable ADMA table address, can't be null if transfer way is ADMA1/ADMA2.
 * @param admaTableWords ADMA table length united as words, can't be 0 if transfer way is ADMA1/ADMA2.
 * @param transfer Transfer content.
 * @retval kStatus_InvalidArgument Argument is invalid.
 * @retval kStatus_SDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed.
 * @retval kStatus_SDHC_SendCommandFailed Send command failed.
 * @retval kStatus_SDHC_TransferDataFailed Transfer data failed.
 * @retval kStatus_Success Operate successfully.
 */
status_t SDHC_TransferBlocking(SDHC_Type *base,
                               uint32_t *admaTable,
                               uint32_t admaTableWords,
                               sdhc_transfer_t *transfer);

/*!
 * @brief Creates the SDHC handle.
 *
 * @param base SDHC peripheral base address.
 * @param handle SDHC handle pointer.
 * @param callback Structure pointer to contain all callback functions.
 * @param userData Callback function parameter.
 */
void SDHC_TransferCreateHandle(SDHC_Type *base,
                               sdhc_handle_t *handle,
                               const sdhc_transfer_callback_t *callback,
                               void *userData);

/*!
 * @brief Transfers the command/data using an interrupt and an asynchronous method.
 *
 * This function sends a command and data and returns immediately. It doesn't wait the transfer complete or
 * encounter an error. This function support non word align data addr transfer support, if data buffer addr is not
 * align in DMA mode, the API will continue finish the transfer by polling IO directly The application must not call
 * this API in multiple threads at the same time. Because of that this API doesn't support the re-entry mechanism.
 *
 * @note Call the API 'SDHC_TransferCreateHandle' when calling this API.
 *
 * @param base SDHC peripheral base address.
 * @param handle SDHC handle.
 * @param admaTable ADMA table address, can't be null if transfer way is ADMA1/ADMA2.
 * @param admaTableWords ADMA table length united as words, can't be 0 if transfer way is ADMA1/ADMA2.
 * @param transfer Transfer content.
 * @retval kStatus_InvalidArgument Argument is invalid.
 * @retval kStatus_SDHC_BusyTransferring Busy transferring.
 * @retval kStatus_SDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed.
 * @retval kStatus_Success Operate successfully.
 */
status_t SDHC_TransferNonBlocking(
    SDHC_Type *base, sdhc_handle_t *handle, uint32_t *admaTable, uint32_t admaTableWords, sdhc_transfer_t *transfer);

/*!
 * @brief IRQ handler for the SDHC.
 *
 * This function deals with the IRQs on the given host controller.
 *
 * @param base SDHC peripheral base address.
 * @param handle SDHC handle.
 */
void SDHC_TransferHandleIRQ(SDHC_Type *base, sdhc_handle_t *handle);

/* @} */

#if defined(__cplusplus)
}
#endif
/*! @} */

#endif /* _FSL_SDHC_H_*/
