/*
 * Copyright 2019-2021 NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "fsl_asrc.h"
#include "fsl_asrc_firmware.h"

/* Component ID definition, used by tools. */
#ifndef FSL_COMPONENT_ID
#define FSL_COMPONENT_ID "platform.drivers.easrc"
#endif

/*******************************************************************************
 * Definitions
 ******************************************************************************/
/*! @brief asrc sample rate ratio format */
typedef enum _asrc_samplerate_ratio_format
{
    kASRC_SampleRateRatio5Int39Frac = 32,  /*!< sample rate ratio 5 integer bits and 39 fractional bits */
    kASRC_SampleRateRatio6Int38Frac = 64,  /*!< sample rate ratio 6 integer bits and 38 fractional bits */
    kASRC_SampleRateRatio7Int37Frac = 128, /*!< sample rate ratio 7 integer bits and 37 fractional bits */
} asrc_samplerate_ratio_format_t;

/*! @brief ASRC support maximum channel number */
#define ASRC_SUPPORT_MAXIMUM_CHANNEL_NUMBER 32U
/*! @brief ASRC support maximum channel number of one context process pipe line */
#define ASRC_SUPPORT_CONTEXT_PROCESSOR_MAXIMUM_CHANNEL_NUMBER 8U
/*! @brief ASRC support maximum channel number of context */
#define ASRC_SUPPORT_MAXIMUM_CONTEXT_PROCESSOR_NUMBER 4U

/*! @brief ASRC macro to get register field value*/
#define ASRC_GET_SLOT0_CONTEXT_INDEX(context)                                            \
    ((base->PROC_CTRL_SLOT0_R0[context] & ASRC_PROC_CTRL_SLOT0_R0_SLOT0_CTX_NUM_MASK) >> \
     ASRC_PROC_CTRL_SLOT0_R0_SLOT0_CTX_NUM_SHIFT)
#define ASRC_GET_SLOT0_CHANNEL_NUMBER(context)                                          \
    ((base->PROC_CTRL_SLOT0_R0[context] & ASRC_PROC_CTRL_SLOT0_R0_SLOT0_NUM_CH_MASK) >> \
     ASRC_PROC_CTRL_SLOT0_R0_SLOT0_NUM_CH_SHIFT)
#define ASRC_GET_SLOT1_CONTEXT_INDEX(context)                                            \
    ((base->PROC_CTRL_SLOT1_R0[context] & ASRC_PROC_CTRL_SLOT1_R0_SLOT1_CTX_NUM_MASK) >> \
     ASRC_PROC_CTRL_SLOT1_R0_SLOT1_CTX_NUM_SHIFT)
#define ASRC_GET_SLOT1_CHANNEL_NUMBER(context)                                          \
    ((base->PROC_CTRL_SLOT1_R0[context] & ASRC_PROC_CTRL_SLOT1_R0_SLOT1_NUM_CH_MASK) >> \
     ASRC_PROC_CTRL_SLOT1_R0_SLOT1_NUM_CH_SHIFT)
#define ASRC_IS_CONTEXT_ENABLED(index) ((base->CTX_CTRL[index] & ASRC_CTX_CTRL_RUN_EN_MASK) != 0U)
#define ASRC_IS_SLOT0_ENABLED(context) \
    ((base->PROC_CTRL_SLOT0_R0[context] & ASRC_PROC_CTRL_SLOT0_R0_SLOT0_EN_MASK) != 0U)
#define ASRC_IS_SLOT1_ENABLED(context) \
    ((base->PROC_CTRL_SLOT1_R0[context] & ASRC_PROC_CTRL_SLOT1_R0_SLOT1_EN_MASK) != 0U)

/*******************************************************************************
 * Prototypes
 ******************************************************************************/
/*!
 * @brief ASRC get greatest common divisor between the input and output sample rate.
 *
 * @param inputSampleRate input sample rate.
 * @param outputSampleRate output sample rate.
 * @retval GCD between the input and output sample rate.
 */
static uint32_t ASRC_GetSampleRateGCD(uint32_t inputSampleRate, uint32_t outputSampleRate);

/*!
 * @brief ASRC get available context slot channel.
 *
 * @param base ASRC base address.
 * @param contextProcessor context processor number.
 * @param slot0UsedChannel slot0 used channel number.
 * @param slot1UsedChannel slot1 used channel number.
 */
static void ASRC_GetAvailableContextSlot(ASRC_Type *base,
                                         uint32_t contextProcessor,
                                         uint32_t *slot0UsedChannel,
                                         uint32_t *slot1UsedChannel);

/*!
 * @brief ASRC enable context slot.
 *
 * @param base ASRC base address.
 * @param contextProcessor context processor number.
 * @param slot slot number.
 * @param channelNums channel number
 * @param startChannel start channel number running on this slot.
 * @param context context number running on this slot.
 */
static void ASRC_EnableContextSlot(ASRC_Type *base,
                                   uint32_t contextProcessor,
                                   uint32_t slot,
                                   uint32_t channelNums,
                                   uint32_t startChannel,
                                   asrc_context_t runningContext);

/*!
 * @brief ASRC config the sample rate ratio.
 *
 * @param base ASRC base address.
 * @param context context number.
 * @param inputSampleRate input sample rate.
 * @param outputSampleRate output sample rate.
 * @param format sample rate ratio format.
 * @retval kStatus_Success, else configure failed.
 */
static status_t ASRC_SetSampleRateRatioConfig(ASRC_Type *base,
                                              asrc_context_t context,
                                              uint32_t inputSampleRate,
                                              uint32_t outputSampleRate,
                                              asrc_samplerate_ratio_format_t format);

/*!
 * @brief ASRC load prefilter configuration.
 *
 * @param config prefilter pointer.
 * @param inputSampleRate input sample rate.
 * @param outputSampleRate output sample rate.
 * @retval kStatus_Success, else configure failed.
 */
static status_t ASRC_GetPrefilterConfig(asrc_context_prefilter_config_t *config,
                                        uint32_t inputSampleRate,
                                        uint32_t outputSampleRate);

/*!
 * @brief ASRC load resample configuration.
 *
 * @param config resamplefilter pointer.
 * @param interpolationTap resampler taps
 * @retval kStatus_Success, else configure failed.
 */
static status_t ASRC_GetResamplerConfig(asrc_context_resampler_config_t *config,
                                        asrc_resampler_taps_t interpolationTap);

/*!
 * @brief ASRC reset prefilter coeff memory pointer reset.
 *
 * @param base ASRC base address.
 * @param context context number.
 */
static void ASRC_SetPrefilterCoeffMemReset(ASRC_Type *base, asrc_context_t context);

/*!
 * @brief ASRC set prefilter configuration.
 *
 * @param base ASRC base address.
 * @param context context number.
 * @param config prefilter configuration.
 * @param filter filter configuration load from firmware.
 * @retval kStatus_Success, else configure failed.
 */
static status_t ASRC_SetPrefilterConfig(ASRC_Type *base,
                                        asrc_context_t context,
                                        asrc_context_prefilter_config_t *config);

/*!
 * @brief ASRC set resampler configuration.
 *
 * @param base ASRC base address.
 * @param context context number.
 * @param config resampler configuration.
 * @param filter filter configuration load from firmware.
 * @retval kStatus_Success, else configure failed.
 */
static status_t ASRC_SetResamplerConfig(ASRC_Type *base,
                                        asrc_context_t context,
                                        asrc_context_resampler_config_t *config);

/*!
 * @brief ASRC set slot config.
 *
 * @param base ASRC base address.
 * @param context context number.
 * @param requestChannel request channel number need to run on this slot.
 * @param filter filter configuration load from firmware.
 * @retval kStatus_Success, else configure failed.
 */
static status_t ASRC_SetSlotConfig(ASRC_Type *base,
                                   asrc_context_t context,
                                   uint32_t requestChannel,
                                   asrc_context_prefilter_config_t *config);

/*!
 * @brief ASRC set context processor config.
 *
 * @param base ASRC base address.
 * @param context context number.
 * @param config context configuration.
 * @retval kStatus_Success, else configure failed.
 */
static status_t ASRC_SetContextProcessorConfig(ASRC_Type *base, asrc_context_t context, asrc_context_config_t *config);

/*******************************************************************************
 * Variables
 ******************************************************************************/
/* Base pointer array */
static ASRC_Type *const s_asrcBases[] = ASRC_BASE_PTRS;

#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/* Clock name array */
static const clock_ip_name_t s_asrcClock[] = ASRC_CLOCKS;
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
/*! @brief ASRC filter firmware table */
static const uint32_t s_asrcFirmware[] = ASRC_FILTER_FIRMWARE;
/*******************************************************************************
 * Code
 ******************************************************************************/
uint32_t ASRC_GetInstance(ASRC_Type *base)
{
    uint32_t instance;

    /* Find the instance index from base address mappings. */
    for (instance = 0; instance < ARRAY_SIZE(s_asrcBases); instance++)
    {
        if (s_asrcBases[instance] == base)
        {
            break;
        }
    }

    assert(instance < ARRAY_SIZE(s_asrcBases));

    return instance;
}

static uint32_t ASRC_GetSampleRateGCD(uint32_t inputSampleRate, uint32_t outputSampleRate)
{
    uint32_t temp = 0U, gcd = inputSampleRate;

    while (outputSampleRate != 0U)
    {
        temp             = outputSampleRate;
        outputSampleRate = gcd % outputSampleRate;
        gcd              = temp;
    }

    return gcd;
}

static void ASRC_GetAvailableContextSlot(ASRC_Type *base,
                                         uint32_t contextProcessor,
                                         uint32_t *slot0UsedChannel,
                                         uint32_t *slot1UsedChannel)
{
    uint32_t contextIndex = 0U;

    /* looking for available context processor */
    if (ASRC_IS_SLOT0_ENABLED(contextProcessor))
    {
        contextIndex = ASRC_GET_SLOT0_CONTEXT_INDEX(contextProcessor);
        if (ASRC_IS_CONTEXT_ENABLED(contextIndex))
        {
            *slot0UsedChannel = ASRC_GET_SLOT0_CHANNEL_NUMBER(contextProcessor);
        }
    }

    if (ASRC_IS_SLOT1_ENABLED(contextProcessor))
    {
        contextIndex = ASRC_GET_SLOT1_CONTEXT_INDEX(contextProcessor);
        if (ASRC_IS_CONTEXT_ENABLED(contextIndex))
        {
            *slot1UsedChannel = ASRC_GET_SLOT1_CHANNEL_NUMBER(contextProcessor);
        }
    }
}

static void ASRC_EnableContextSlot(ASRC_Type *base,
                                   uint32_t contextProcessor,
                                   uint32_t slot,
                                   uint32_t channelNums,
                                   uint32_t startChannel,
                                   asrc_context_t runningContext)
{
    assert(channelNums <= ASRC_SUPPORT_CONTEXT_PROCESSOR_MAXIMUM_CHANNEL_NUMBER);

    if (slot == 0U)
    {
        base->PROC_CTRL_SLOT0_R0[contextProcessor] =
            ASRC_PROC_CTRL_SLOT0_R0_SLOT0_EN_MASK | ASRC_PROC_CTRL_SLOT0_R0_SLOT0_CTX_NUM(runningContext) |
            ASRC_PROC_CTRL_SLOT0_R0_SLOT0_NUM_CH(channelNums - 1U) |
            ASRC_PROC_CTRL_SLOT0_R0_SLOT0_MIN_CH(startChannel) |
            ASRC_PROC_CTRL_SLOT0_R0_SLOT0_MAX_CH(startChannel + channelNums - 1U);
    }
    else
    {
        base->PROC_CTRL_SLOT1_R0[contextProcessor] =
            ASRC_PROC_CTRL_SLOT1_R0_SLOT1_EN_MASK | ASRC_PROC_CTRL_SLOT1_R0_SLOT1_CTX_NUM(runningContext) |
            ASRC_PROC_CTRL_SLOT1_R0_SLOT1_NUM_CH(channelNums - 1U) |
            ASRC_PROC_CTRL_SLOT1_R0_SLOT1_MIN_CH(startChannel) |
            ASRC_PROC_CTRL_SLOT1_R0_SLOT1_MAX_CH(startChannel + channelNums - 1U);
    }
}

static status_t ASRC_SetSampleRateRatioConfig(ASRC_Type *base,
                                              asrc_context_t context,
                                              uint32_t inputSampleRate,
                                              uint32_t outputSampleRate,
                                              asrc_samplerate_ratio_format_t format)
{
    uint64_t ratio    = 0U;
    uint32_t fracBits = 0U;

    uint32_t gcd     = ASRC_GetSampleRateGCD(inputSampleRate, outputSampleRate);
    uint32_t inRate  = inputSampleRate / gcd;
    uint32_t outRate = outputSampleRate / gcd;

    if (format == kASRC_SampleRateRatio5Int39Frac)
    {
        fracBits = 39U;
    }
    else if (format == kASRC_SampleRateRatio6Int38Frac)
    {
        fracBits = 38U;
    }
    else
    {
        fracBits = 37U;
    }

    ratio = ((uint64_t)inRate << fracBits) / outRate;

    base->RS_RATIO_LOW[context].RS_RATIO_LOW  = (uint32_t)ratio & 0xFFFFFFFFU;
    base->RS_RATIO_LOW[context].RS_RATIO_HIGH = ((uint32_t)(ratio >> 32U)) & 0xFFFFFFFFU;

    return kStatus_Success;
}

static status_t ASRC_GetPrefilterConfig(asrc_context_prefilter_config_t *config,
                                        uint32_t inputSampleRate,
                                        uint32_t outputSampleRate)
{
    assert(config != NULL);

    uint32_t gcd           = ASRC_GetSampleRateGCD(inputSampleRate, outputSampleRate);
    uint32_t inSampleRate  = inputSampleRate / gcd;
    uint32_t outSampleRate = outputSampleRate / gcd;
    uint32_t i = 0U, offset = 0U;
    const uint32_t *firmware = s_asrcFirmware;

    /* while performing a up-conversion, the prefilter should be bypassed */
    if (inputSampleRate <= outputSampleRate)
    {
        return kStatus_Success;
    }

    offset = (ASRC_FILTER_INTERPOLATION_FIRMWARE_LEN + 5U) * ASRC_FILTER_INTERPOLATION_FILTER_NUM;

    /* load interpolation filter */
    for (i = 0U; i < ASRC_FILTER_PREFILTER_FILTER_NUM; i++)
    {
        if (firmware[offset] != ASRC_FILTER_FIRMWARE_HEAD)
        {
            return kStatus_InvalidArgument;
        }

        if ((firmware[offset + ASRC_FILTER_PREFILTER_IN_SAMPLE_RATE_INDEX] == inSampleRate) &&
            ((firmware[offset + ASRC_FILTER_PREFILTER_OUT_SAMPLE_RATE_INDEX] == outSampleRate)))
        {
            config->filterSt1Taps      = firmware[offset + ASRC_FILTER_PREFILTER_STAGE_1_TAPS_INDEX];
            config->filterSt2Taps      = firmware[offset + ASRC_FILTER_PREFILTER_STAGE_2_TAPS_INDEX];
            config->filterSt1Exp       = firmware[offset + ASRC_FILTER_PREFILTER_STAGE_1_EXPANSION_FACTOR_INDEX];
            config->filterCoeffAddress = &firmware[offset + ASRC_FILTER_PREFILTER_STAGE_1_DATA_INDEX];
            break;
        }
        offset += ASRC_FILTER_PREFILTER_FIRMWARE_LEN + ASRC_FILTER_PREFILTER_STAGE_1_DATA_INDEX;
    }

    /* check if the interpolation filter firmware is founded */
    if (config->filterCoeffAddress == NULL)
    {
        return kStatus_InvalidArgument;
    }

    return kStatus_Success;
}

static status_t ASRC_GetResamplerConfig(asrc_context_resampler_config_t *config, asrc_resampler_taps_t interpolationTap)
{
    assert(config != NULL);

    uint32_t i = 0U, offset = 0U;
    const uint32_t *firmware = s_asrcFirmware;

    /* load prefilter firmware */
    for (i = 0U; i < ASRC_FILTER_INTERPOLATION_FILTER_NUM; i++)
    {
        if (firmware[offset] != ASRC_FILTER_FIRMWARE_HEAD)
        {
            return kStatus_InvalidArgument;
        }

        if (firmware[offset + ASRC_FILTER_INTERPOLATION_TAP_INDEX] == ((uint32_t)interpolationTap + 1U))
        {
            config->filterPhases = firmware[offset + ASRC_FILTER_INTERPOLATION_PHASE_INDEX];
            config->filterCenterTap =
                ((uint64_t)firmware[offset + 1U + ASRC_FILTER_INTERPOLATION_CENTER_TAP_INDEX] << 32U) +
                firmware[offset + ASRC_FILTER_INTERPOLATION_CENTER_TAP_INDEX];
            config->filterCoeffAddress = &firmware[offset + +1U + ASRC_FILTER_INTERPOLATION_DATA_INDEX];
            break;
        }
        offset += ASRC_FILTER_INTERPOLATION_FIRMWARE_LEN + ASRC_FILTER_INTERPOLATION_DATA_INDEX + 1U;
    }

    /* check if the interpolation filter firmware is founded */
    if (config->filterCoeffAddress == NULL)
    {
        return kStatus_InvalidArgument;
    }

    return kStatus_Success;
}

static void ASRC_SetPrefilterCoeffMemReset(ASRC_Type *base, asrc_context_t context)
{
    base->CTX_CTRL_EXT1[context] &= ~ASRC_CTX_CTRL_EXT1_PF_COEFF_MEM_RST_MASK;
    base->CTX_CTRL_EXT1[context] |= ASRC_CTX_CTRL_EXT1_PF_COEFF_MEM_RST_MASK;
    base->CTX_CTRL_EXT1[context] &= ~ASRC_CTX_CTRL_EXT1_PF_COEFF_MEM_RST_MASK;
}

static status_t ASRC_SetPrefilterConfig(ASRC_Type *base,
                                        asrc_context_t context,
                                        asrc_context_prefilter_config_t *config)
{
    uint32_t contextReg          = base->CTX_CTRL_EXT1[context];
    const uint32_t *coeffPointer = config->filterCoeffAddress;
    uint32_t i = 0U, j = 0U;

    if (coeffPointer == NULL)
    {
        return kStatus_InvalidArgument;
    }

    contextReg &= ~(ASRC_CTX_CTRL_EXT1_PF_INIT_MODE_MASK | ASRC_CTX_CTRL_EXT1_PF_STOP_MODE_MASK |
                    ASRC_CTX_CTRL_EXT1_PF_EXPANSION_FACTOR_MASK | ASRC_CTX_CTRL_EXT1_PF_ST1_WB_FLOAT_MASK |
                    ASRC_CTX_CTRL_EXT1_PF_TWO_STAGE_EN_MASK);

    contextReg |= ASRC_CTX_CTRL_EXT1_PF_INIT_MODE(config->initMode) |
                  ASRC_CTX_CTRL_EXT1_PF_STOP_MODE(config->stopMode) |
                  ASRC_CTX_CTRL_EXT1_PF_EXPANSION_FACTOR(config->filterSt1Exp - 1U) |
                  ASRC_CTX_CTRL_EXT1_PF_ST1_WB_FLOAT(config->stage1Result) |
                  ASRC_CTX_CTRL_EXT1_PF_TWO_STAGE_EN(config->filterSt2Taps != 0U ? 1U : 0U);

    base->CTX_CTRL_EXT1[context] = contextReg;
    base->CTX_CTRL_EXT2[context] = ASRC_CTX_CTRL_EXT2_ST1_NUM_TAPS(config->filterSt1Taps - 1U) |
                                   ASRC_CTX_CTRL_EXT2_ST2_NUM_TAPS(config->filterSt2Taps - 1U);

    /* reset prefilter coefficient memory */
    ASRC_SetPrefilterCoeffMemReset(base, context);
    /* load stage1 */
    base->CTX_CTRL_EXT1[context] &= ~ASRC_CTX_CTRL_EXT1_PF_COEFF_STAGE_WR_MASK;

    for (i = 0; i < ((config->filterSt1Taps + 1U) / 2U) * 2U; i++)
    {
        base->PRE_COEFF_FIFO[context] = coeffPointer[i];
    }

    /* reset prefilter coefficient memory */
    ASRC_SetPrefilterCoeffMemReset(base, context);
    /* load stage2 */
    if (config->filterSt2Taps != 0U)
    {
        base->CTX_CTRL_EXT1[context] |= ASRC_CTX_CTRL_EXT1_PF_COEFF_STAGE_WR_MASK;
        for (j = 0; j < ((config->filterSt2Taps + 1U) / 2U) * 2U; j++)
        {
            base->PRE_COEFF_FIFO[context] = coeffPointer[i + j];
        }
    }

    return kStatus_Success;
}

static status_t ASRC_SetResamplerConfig(ASRC_Type *base,
                                        asrc_context_t context,
                                        asrc_context_resampler_config_t *config)
{
    uint32_t contextReg          = base->CTX_CTRL_EXT1[context];
    uint32_t i                   = 0U;
    const uint32_t *coeffPointer = config->filterCoeffAddress;

    contextReg &= ~(ASRC_CTX_CTRL_EXT1_RS_INIT_MODE_MASK | ASRC_CTX_CTRL_EXT1_RS_STOP_MODE_MASK);
    contextReg |= ASRC_CTX_CTRL_EXT1_RS_INIT_MODE(config->initMode) | ASRC_CTX_CTRL_EXT1_RS_STOP_MODE(config->stopMode);
    base->CTX_CTRL_EXT1[context] = contextReg;

    /* center tap */
    base->RS_CT_LOW  = (uint32_t)config->filterCenterTap & 0xFFFFFFFFU;
    base->RS_CT_HIGH = (uint32_t)(config->filterCenterTap >> 32U) & 0xFFFFFFFFU;

    /* resampler taps */
    contextReg = base->CTX_RS_COEFF_CTRL;
    contextReg &= ~ASRC_CTX_RS_COEFF_CTRL_NUM_RES_TAPS_MASK;

    if (config->tap == kASRC_ResamplerTaps_32)
    {
        contextReg |= ASRC_CTX_RS_COEFF_CTRL_NUM_RES_TAPS(0);
    }
    else if (config->tap == kASRC_ResamplerTaps_64)
    {
        contextReg |= ASRC_CTX_RS_COEFF_CTRL_NUM_RES_TAPS(1);
    }
    else
    {
        contextReg |= ASRC_CTX_RS_COEFF_CTRL_NUM_RES_TAPS(2);
    }
    base->CTX_RS_COEFF_CTRL = contextReg;

    /* load coefficient */
    /* reset coefficient memory firstly */
    base->CTX_RS_COEFF_CTRL &= ~ASRC_CTX_RS_COEFF_CTRL_RS_COEFF_PTR_RST_MASK;
    base->CTX_RS_COEFF_CTRL |= ASRC_CTX_RS_COEFF_CTRL_RS_COEFF_PTR_RST_MASK;
    base->CTX_RS_COEFF_CTRL &= ~ASRC_CTX_RS_COEFF_CTRL_RS_COEFF_PTR_RST_MASK;

    for (i = 0U; i < ASRC_FILTER_INTERPOLATION_FIRMWARE_LEN; i++)
    {
        base->CTX_RS_COEFF_MEM = coeffPointer[i];
    }

    return kStatus_Success;
}

static status_t ASRC_SetSlotConfig(ASRC_Type *base,
                                   asrc_context_t context,
                                   uint32_t requestChannel,
                                   asrc_context_prefilter_config_t *config)
{
    uint32_t availableSlot = 0U, availableContext = 0U, availableChannel = 0U, startChannel = 0U;
    uint32_t i                = 0U;
    uint32_t slot0UsedChannel = 0U, slot1UsedChannel = 0U;
    uint32_t stage1MemSize = 0U, stage1MemAddr = 0U, stage2MemSize = 0U, stage2MemAddr = 0U, stage1Exp = 0U;
    uint32_t leftChannel = requestChannel;

    for (i = 0U; i < ASRC_SUPPORT_MAXIMUM_CONTEXT_PROCESSOR_NUMBER; i++)
    {
        /* record start channel */
        startChannel += availableChannel;

        ASRC_GetAvailableContextSlot(base, i, &slot0UsedChannel, &slot1UsedChannel);

        /* context is busy */
        if ((slot0UsedChannel != 0U) && ((slot1UsedChannel != 0U)))
        {
            continue;
        }
        /* context is idle */
        if ((slot0UsedChannel == 0U) && (slot1UsedChannel == 0U))
        {
            availableSlot    = 0U;
            availableChannel = ASRC_SUPPORT_CONTEXT_PROCESSOR_MAXIMUM_CHANNEL_NUMBER;
            availableContext = i;
        }
        /* context slot 0 is busy, slot 1 is idle */
        else if (slot0UsedChannel != 0U)
        {
            availableSlot    = 1U;
            availableChannel = ASRC_SUPPORT_CONTEXT_PROCESSOR_MAXIMUM_CHANNEL_NUMBER - slot0UsedChannel;
            availableContext = i;
        }
        /* context slot0 is idle, slot 1 is busy, ((slot0UsedChannel == 0U) && (slot1UsedChannel != 0U))*/
        else
        {
            availableSlot    = 0U;
            availableChannel = ASRC_SUPPORT_CONTEXT_PROCESSOR_MAXIMUM_CHANNEL_NUMBER - slot1UsedChannel;
            availableContext = i;
        }

        availableChannel = availableChannel > leftChannel ? leftChannel : availableChannel;
        leftChannel -= availableChannel;
        /* enable the available slot */
        ASRC_EnableContextSlot(base, availableContext, availableSlot, availableChannel, startChannel, context);

        if (availableSlot == 0U)
        {
            if (config->filterSt2Taps != 0U)
            {
                stage1Exp = (config->filterSt1Exp - 1U) * availableChannel;
                stage1MemSize =
                    (config->filterSt1Taps - 1U) * config->filterSt1Exp * availableChannel + availableChannel;
                stage1MemAddr = 0U;
                stage2MemSize = availableChannel * config->filterSt2Taps;
                stage2MemAddr = stage1MemSize;
            }
            else
            {
                stage1MemSize = availableChannel * config->filterSt1Taps;
                stage1MemAddr = 0U;
            }

            base->PROC_CTRL_SLOT0_R1[availableContext] = stage1Exp;
            base->PROC_CTRL_SLOT0_R2[availableContext] = ASRC_PROC_CTRL_SLOT0_R2_SLOT0_ST1_ST_ADDR(stage1MemAddr) |
                                                         ASRC_PROC_CTRL_SLOT0_R2_SLOT0_ST1_MEM_ALLOC(stage1MemSize);
            base->PROC_CTRL_SLOT0_R3[availableContext] = ASRC_PROC_CTRL_SLOT0_R3_SLOT0_ST2_ST_ADDR(stage2MemAddr) |
                                                         ASRC_PROC_CTRL_SLOT0_R3_SLOT0_ST2_MEM_ALLOC(stage2MemSize);
        }
        else
        {
            if (config->filterSt2Taps != 0U)
            {
                stage1Exp = (config->filterSt1Exp - 1U) * availableChannel;
                stage1MemSize =
                    (config->filterSt1Taps - 1U) * config->filterSt1Exp * availableChannel + availableChannel;
                stage1MemAddr = 0x1800U - stage1MemSize;
                stage2MemSize = availableChannel * config->filterSt2Taps;
                stage2MemAddr = 0x1800U - stage1MemSize - stage2MemSize;
            }
            else
            {
                stage1MemSize = availableChannel * config->filterSt1Taps;
                stage1MemAddr = 0x1800U - stage1MemSize;
            }

            base->PROC_CTRL_SLOT1_R1[availableContext] = stage1Exp;
            base->PROC_CTRL_SLOT1_R2[availableContext] = ASRC_PROC_CTRL_SLOT1_R2_SLOT1_ST1_ST_ADDR(stage1MemAddr) |
                                                         ASRC_PROC_CTRL_SLOT1_R2_SLOT1_ST1_MEM_ALLOC(stage1MemSize);
            base->PROC_CTRL_SLOT1_R3[availableContext] = ASRC_PROC_CTRL_SLOT1_R3_SLOT1_ST2_ST_ADDR(stage2MemAddr) |
                                                         ASRC_PROC_CTRL_SLOT1_R3_SLOT1_ST2_MEM_ALLOC(stage2MemSize);
        }

        /* one context processor can satisfy the channel requirement*/
        if (leftChannel == 0U)
        {
            return kStatus_Success;
        }
        /* multiple slot across context processor is required */
        else
        {
            continue;
        }
    }

    return kStatus_Fail;
}

static status_t ASRC_SetContextProcessorConfig(ASRC_Type *base, asrc_context_t context, asrc_context_config_t *config)
{
    assert(config != NULL);

    /* bypass resampler */
    if (config->contextInput.sampleRate == config->contextOutput.sampleRate)
    {
        ASRC_EnableResamplerBypass(base, context, true);
    }
    else
    {
        /* ensure resampler is not bypassed */
        ASRC_EnableResamplerBypass(base, context, false);

        if (config->contextResampler.filterCoeffAddress == NULL)
        {
            if (ASRC_GetResamplerConfig(&config->contextResampler, config->contextResampler.tap) != kStatus_Success)
            {
                return kStatus_InvalidArgument;
            }
        }
        /* resampler configuration */
        if (ASRC_SetResamplerConfig(base, context, &config->contextResampler) != kStatus_Success)
        {
            return kStatus_ASRCResamplerConfigureFailed;
        }
    }

    /* up conversion should bypass the prefilter */
    if (config->contextInput.sampleRate <= config->contextOutput.sampleRate)
    {
        /* prefilter bypass mode */
        ASRC_EnablePreFilterBypass(base, context, true);
    }
    else
    {
        /* ensure prefilter not in bypass mode */
        ASRC_EnablePreFilterBypass(base, context, false);
        /* load default configuration if not assigned by application */
        if (config->contextPrefilter.filterCoeffAddress == NULL)
        {
            if (ASRC_GetPrefilterConfig(&config->contextPrefilter, config->contextInput.sampleRate,
                                        config->contextOutput.sampleRate) == kStatus_InvalidArgument)
            {
                return kStatus_InvalidArgument;
            }
        }
        if (ASRC_SetPrefilterConfig(base, context, &config->contextPrefilter) != kStatus_Success)
        {
            return kStatus_ASRCPrefilterConfigureFailed;
        }
    }

    /* set channel number in context */
    ASRC_SetContextChannelNumber(base, context, config->contextChannelNums);

    return ASRC_SetSlotConfig(base, context, config->contextChannelNums, &config->contextPrefilter);
}

/*!
 * brief Initializes the asrc peripheral.
 *
 * This API gates the asrc clock. The asrc module can't operate unless ASRC_Init is called to enable the clock.
 *
 * param base asrc base pointer.
 */
void ASRC_Init(ASRC_Type *base)
{
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
    /* Enable the asrc clock */
    CLOCK_EnableClock(s_asrcClock[ASRC_GetInstance(base)]);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */

    for (uint32_t i = 0U; i < ASRC_SUPPORT_MAXIMUM_CONTEXT_PROCESSOR_NUMBER; i++)
    {
        /* disable ASRC module and reset ASRC slot configurations*/
        base->CTX_CTRL[i]           = 0U;
        base->CTX_OUT_CTRL[i]       = 0U;
        base->PROC_CTRL_SLOT0_R0[i] = 0U;
        base->PROC_CTRL_SLOT1_R0[i] = 0U;
    }

    /* disable all the interrupt */
    base->IRQ_CTRL  = 0U;
    base->IRQ_FLAGS = 0xFFFU;
}

/*!
 * brief De-initializes the ASRC peripheral.
 *
 * This API gates the ASRC clock and disable ASRC module. The ASRC module can't operate unless ASRC_Init
 *
 * param base ASRC base pointer.
 */
void ASRC_Deinit(ASRC_Type *base)
{
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
    CLOCK_DisableClock(s_asrcClock[ASRC_GetInstance(base)]);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
}

/*!
 * brief ASRC configure context input.
 *
 * param base ASRC base pointer.
 * param context index of asrc context, reference asrc_context_t.
 * param config ASRC context input configuration pointer.
 */
status_t ASRC_SetContextInputConfig(ASRC_Type *base, asrc_context_t context, asrc_context_input_config_t *config)
{
    assert(config != NULL);

    uint32_t contextReg = base->CTX_CTRL[context];

    contextReg &= ~(ASRC_CTX_CTRL_SIGN_IN_MASK | ASRC_CTX_CTRL_FLOAT_FMT_MASK | ASRC_CTX_CTRL_BITS_PER_SAMPLE_MASK |
                    ASRC_CTX_CTRL_BIT_REV_MASK | ASRC_CTX_CTRL_SAMPLE_POSITION_MASK | ASRC_CTX_CTRL_FIFO_WTMK_MASK);

    contextReg |= ASRC_CTX_CTRL_FIFO_WTMK(config->watermark);

    contextReg |= ASRC_CTX_CTRL_SIGN_IN(config->dataFormat.dataSign) |
                  ASRC_CTX_CTRL_FLOAT_FMT(config->dataFormat.dataType) |
                  ASRC_CTX_CTRL_BITS_PER_SAMPLE(config->dataFormat.dataWidth) |
                  ASRC_CTX_CTRL_BIT_REV(config->dataFormat.dataEndianness) |
                  ASRC_CTX_CTRL_SAMPLE_POSITION(config->dataFormat.dataPosition);

    base->CTX_CTRL[context] = contextReg;

    base->CTRL_IN_ACCESS[context] = ASRC_CTRL_IN_ACCESS_ACCESS_LENGTH(config->accessCtrl.accessLen) |
                                    ASRC_CTRL_IN_ACCESS_ITERATIONS(config->accessCtrl.accessIterations) |
                                    ASRC_CTRL_IN_ACCESS_GROUP_LENGTH(config->accessCtrl.accessGroupLen);

    return kStatus_Success;
}

/*!
 * brief ASRC configure context output.
 *
 * param base ASRC base pointer.
 * param context index of asrc context, reference asrc_context_t.
 * param config ASRC context output configuration pointer.
 */
status_t ASRC_SetContextOutputConfig(ASRC_Type *base, asrc_context_t context, asrc_context_output_config_t *config)
{
    assert(config != NULL);

    uint32_t contextReg     = base->CTX_OUT_CTRL[context];
    uint32_t samplePosition = config->dataFormat.dataPosition;

    contextReg &=
        ~(ASRC_CTX_OUT_CTRL_SIGN_OUT_MASK | ASRC_CTX_OUT_CTRL_FLOAT_FMT_MASK | ASRC_CTX_OUT_CTRL_IEC_V_DATA_MASK |
          ASRC_CTX_OUT_CTRL_DITHER_EN_MASK | ASRC_CTX_OUT_CTRL_BITS_PER_SAMPLE_MASK | ASRC_CTX_OUT_CTRL_BIT_REV_MASK |
          ASRC_CTX_OUT_CTRL_SAMPLE_POSITION_MASK | ASRC_CTX_OUT_CTRL_FIFO_WTMK_MASK);

    contextReg |= ASRC_CTX_OUT_CTRL_FIFO_WTMK(config->watermark);

    if (config->enableIEC60958)
    {
        if (config->dataFormat.dataWidth == kASRC_DataWidth16Bit)
        {
            samplePosition = 12U;
        }
        else if (config->dataFormat.dataWidth == kASRC_DataWidth20Bit)
        {
            samplePosition = 8U;
        }
        else if (config->dataFormat.dataWidth == kASRC_DataWidth24Bit)
        {
            samplePosition = 4U;
        }
        else
        {
            return kStatus_InvalidArgument;
        }

        contextReg |= ASRC_CTX_OUT_CTRL_IEC_V_DATA_MASK;
    }

    contextReg |= ASRC_CTX_OUT_CTRL_DITHER_EN(config->enableDither);

    contextReg |= ASRC_CTX_OUT_CTRL_SIGN_OUT(config->dataFormat.dataSign) |
                  ASRC_CTX_OUT_CTRL_FLOAT_FMT(config->dataFormat.dataType) |
                  ASRC_CTX_OUT_CTRL_BITS_PER_SAMPLE(config->dataFormat.dataWidth) |
                  ASRC_CTX_OUT_CTRL_BIT_REV(config->dataFormat.dataEndianness) |
                  ASRC_CTX_OUT_CTRL_SAMPLE_POSITION(samplePosition);

    base->CTX_OUT_CTRL[context] = contextReg;

    base->CTRL_OUT_ACCESS[context] = ASRC_CTRL_OUT_ACCESS_ACCESS_LENGTH(config->accessCtrl.accessLen) |
                                     ASRC_CTRL_OUT_ACCESS_ITERATIONS(config->accessCtrl.accessIterations) |
                                     ASRC_CTRL_OUT_ACCESS_GROUP_LENGTH(config->accessCtrl.accessGroupLen);

    return kStatus_Success;
}

/*!
 * brief ASRC get context default configuration.
 *
 * param config ASRC context configuration pointer.
 * param channels input audio data channel numbers.
 * param inSampleRate input sample rate.
 * param outSampleRate output sample rate.
 */
void ASRC_GetContextDefaultConfig(asrc_context_config_t *config,
                                  uint32_t channels,
                                  uint32_t inSampleRate,
                                  uint32_t outSampleRate)
{
    assert(config != NULL);

    (void)memset(config, 0, sizeof(asrc_context_config_t));

    config->contextChannelNums = (uint8_t)channels;

    /* input configuration */
    config->contextInput.sampleRate                  = inSampleRate;
    config->contextInput.watermark                   = FSL_ASRC_INPUT_FIFO_DEPTH / 2U;
    config->contextInput.accessCtrl.accessIterations = 1;
    config->contextInput.accessCtrl.accessGroupLen   = (uint8_t)channels;
    config->contextInput.accessCtrl.accessLen        = (uint8_t)channels;
    config->contextInput.dataFormat.dataPosition     = 0U;
    config->contextInput.dataFormat.dataEndianness   = kASRC_DataEndianLittle;
    config->contextInput.dataFormat.dataWidth        = kASRC_DataWidth16Bit;
    config->contextInput.dataFormat.dataType         = kASRC_DataTypeInteger;
    config->contextInput.dataFormat.dataSign         = kASRC_DataSigned;
    /* output configuration */
    config->contextOutput.sampleRate                  = outSampleRate;
    config->contextOutput.watermark                   = FSL_ASRC_OUTPUT_FIFO_DEPTH / 8U;
    config->contextOutput.accessCtrl.accessIterations = 1;
    config->contextOutput.accessCtrl.accessGroupLen   = (uint8_t)channels;
    config->contextOutput.accessCtrl.accessLen        = (uint8_t)channels;
    config->contextOutput.dataFormat.dataPosition     = 0;
    config->contextOutput.dataFormat.dataEndianness   = kASRC_DataEndianLittle;
    config->contextOutput.dataFormat.dataWidth        = kASRC_DataWidth16Bit;
    config->contextOutput.dataFormat.dataType         = kASRC_DataTypeInteger;
    config->contextOutput.dataFormat.dataSign         = kASRC_DataSigned;
    config->contextOutput.enableDither                = false;
    config->contextOutput.enableIEC60958              = false;
    /* prefilter configuration */
    config->contextPrefilter.initMode     = kASRC_SampleBufferFillZeroOnInit;
    config->contextPrefilter.stopMode     = kASRC_SampleBufferFillLastSampleOnStop;
    config->contextPrefilter.stage1Result = kASRC_PrefilterStage1ResultFloat;
    /* resampler configuration */
    config->contextResampler.initMode = kASRC_SampleBufferFillZeroOnInit;
    config->contextResampler.stopMode = kASRC_SampleBufferFillLastSampleOnStop;
    config->contextResampler.tap      = kASRC_ResamplerTaps_128;
}

/*!
 * brief ASRC configure context.
 *
 * param base ASRC base pointer.
 * param context index of asrc context, reference asrc_context_t.
 * param config ASRC context configuration pointer.
 * retval kStatus_InvalidArgument invalid parameters.
 *        kStatus_ASRCConfigureFailed context configure failed.
 *        kStatus_Success context configure success.
 */
status_t ASRC_SetContextConfig(ASRC_Type *base, asrc_context_t context, asrc_context_config_t *config)
{
    assert(config != NULL);

    if ((config->contextChannelNums == 0U) || (config->contextChannelNums > ASRC_SUPPORT_MAXIMUM_CHANNEL_NUMBER))
    {
        return kStatus_InvalidArgument;
    }

    if (((config->contextInput.sampleRate < (uint32_t)kASRC_SampleRate_8000) ||
         (config->contextInput.sampleRate > (uint32_t)kASRC_SampleRate_768000)) ||
        ((config->contextOutput.sampleRate < (uint32_t)kASRC_SampleRate_8000) ||
         (config->contextOutput.sampleRate > (uint32_t)kASRC_SampleRate_768000)))
    {
        return kStatus_InvalidArgument;
    }

    /* sampel ratio configure */
    if (ASRC_SetSampleRateRatioConfig(base, context, config->contextInput.sampleRate, config->contextOutput.sampleRate,
                                      (asrc_samplerate_ratio_format_t)config->contextResampler.tap) != kStatus_Success)
    {
        return kStatus_ASRCConfigureFailed;
    }

    /* configure context input */
    if (ASRC_SetContextInputConfig(base, context, &config->contextInput) != kStatus_Success)
    {
        return kStatus_ASRCConfigureFailed;
    }

    /* allocate context processor */
    if (ASRC_SetContextProcessorConfig(base, context, config) != kStatus_Success)
    {
        return kStatus_ASRCConfigureFailed;
    }

    /* configure context output */
    if (ASRC_SetContextOutputConfig(base, context, &config->contextOutput) != kStatus_Success)
    {
        return kStatus_ASRCConfigureFailed;
    }

    return kStatus_Success;
}

/*!
 * brief ASRC get output sample count.
 *
 * param inSampleRate output sample rate.
 * param inSamplesSize input sample rate.
 * param inWidth input samples buffer size, the size of buffer should be converted to align with 4 byte .
 * param outSampleRate input sample width.
 * param outWidth Output width.
 * retval output samples size.
 */
uint32_t ASRC_GetContextOutSampleSize(
    uint32_t inSampleRate, uint32_t inSamplesSize, uint32_t inWidth, uint32_t outSampleRate, uint32_t outWidth)
{
    uint32_t reminder = (((uint64_t)inSamplesSize / inWidth) * outSampleRate % inSampleRate) == 0U ? 0U : 1U;
    uint32_t quotient = (uint32_t)(((uint64_t)inSamplesSize / inWidth) * outSampleRate / inSampleRate);

    return (reminder + quotient) * outWidth;
}

/*!
 * brief Get the ASRC read fifo remained samples.
 * Since the DMA request will be triggered only when the sample group in read fifo is bigger then the watermark, so when
 * the data size cannot be divisible by the (watermark + 1), then part of sample will left in read fifo, application
 * should call this api to get the left samples.
 *
 * param base ASRC base pointer.
 * param context context id.
 * param outAddr address to receive remained sample in read fifo.
 * param outWidth output data width.
 * param sampleCount specify the read sample count.
 * retval sample counts actual read from output fifo.
 */
uint32_t ASRC_ReadFIFORemainedSample(
    ASRC_Type *base, asrc_context_t context, uint32_t *outAddr, uint32_t outWidth, uint32_t sampleCount)
{
    uint32_t remainSample = base->SAMPLE_FIFO_STATUS[context] & ASRC_SAMPLE_FIFO_STATUS_NUM_SAMPLE_GROUPS_OUT_MASK;
    uint32_t channel      = (base->CTX_CTRL[context] & ASRC_CTX_CTRL_NUM_CH_EN_MASK) + 1U;
    uint32_t i = 0U, sizeToRead = remainSample * channel;

    if (sizeToRead == 0U)
    {
        return 0U;
    }

    if (sampleCount < sizeToRead)
    {
        sizeToRead = sampleCount;
    }

    for (i = 0U; i < sizeToRead; i++)
    {
        *outAddr = ASRC_ReadContextFifo(base, context);
        outAddr  = (uint32_t *)((size_t)outAddr + outWidth);
    }

    return sizeToRead;
}

/*!
 * brief ASRC blocking convert audio sample rate.
 * This function depends on the configuration of input and output, so it should be called after the
 * ASRC_SetContextConfig. The data format it supports:
 * 1.16bit 16bit per sample in input buffer, input buffer size
 * should be calculate as: samples 2U output buffer size can be calculated by call function
 * ASRC_GetContextOutSampleSize, the parameter outWidth should be 2
 * 2.20bit 24bit per sample in input buffer, input buffer size should be calculate as: samples 3U output buffer size can
 * be calculated by call function ASRC_GetContextOutSampleSize, the outWidth should be 3. 3.24bit 24bit per sample in
 * input buffer, input buffer size should be calculate as: samples * 3U output buffer size can be calculated by call
 * function ASRC_GetContextOutSampleSize, the outWidth should be 3. 4.32bit 32bit per sample in input buffer, input
 * buffer size should be calculate as: samples * 4U output buffer size can be calculated by call function
 * ASRC_GetContextOutSampleSize, the outWidth should be 4.
 *
 * param base ASRC base pointer.
 * param context context id.
 * param xfer .xfer configuration.
 * retval kStatus_Success.
 */
status_t ASRC_TransferBlocking(ASRC_Type *base, asrc_context_t context, asrc_transfer_t *xfer)
{
    assert((xfer->inDataAddr != NULL) && (xfer->outDataAddr != NULL));
    assert(xfer->inDataSize % sizeof(uint32_t) == 0U);

    uint32_t inWatermarkSamples =
        (((base->CTX_CTRL[context] & ASRC_CTX_CTRL_FIFO_WTMK_MASK) >> ASRC_CTX_CTRL_FIFO_WTMK_SHIFT) + 1U) *
        ((base->CTX_CTRL[context] & ASRC_CTX_CTRL_NUM_CH_EN_MASK) + 1U);
    uint32_t outWatermarkSamples =
        (((base->CTX_OUT_CTRL[context] & ASRC_CTX_OUT_CTRL_FIFO_WTMK_MASK) >> ASRC_CTX_OUT_CTRL_FIFO_WTMK_SHIFT) + 1U) *
        ((base->CTX_CTRL[context] & ASRC_CTX_CTRL_NUM_CH_EN_MASK) + 1U);
    uint32_t inWidth =
        ((base->CTX_CTRL[context] & ASRC_CTX_CTRL_BITS_PER_SAMPLE_MASK) >> ASRC_CTX_CTRL_BITS_PER_SAMPLE_SHIFT);
    uint32_t outWidth = ((base->CTX_OUT_CTRL[context] & ASRC_CTX_OUT_CTRL_BITS_PER_SAMPLE_MASK) >>
                         ASRC_CTX_OUT_CTRL_BITS_PER_SAMPLE_SHIFT);
    uint32_t inMask =
        (inWidth == (uint32_t)kASRC_DataWidth32Bit ? 0xFFFFFFFFU :
                                                     inWidth == (uint32_t)kASRC_DataWidth24Bit ?
                                                     0xFFFFFFU :
                                                     inWidth == (uint32_t)kASRC_DataWidth20Bit ? 0xFFFFFU : 0xFFFFU);
    inWidth =
        (inWidth == (uint32_t)kASRC_DataWidth32Bit ?
             4U :
             inWidth == (uint32_t)kASRC_DataWidth24Bit ? 3U : inWidth == (uint32_t)kASRC_DataWidth20Bit ? 3U : 2U);
    outWidth =
        (outWidth == (uint32_t)kASRC_DataWidth32Bit ?
             4U :
             outWidth == (uint32_t)kASRC_DataWidth24Bit ? 3U : outWidth == (uint32_t)kASRC_DataWidth20Bit ? 3U : 2U);
    uint32_t inSamples     = xfer->inDataSize / inWidth;
    uint32_t outSamples    = xfer->outDataSize / outWidth;
    uint32_t *writePointer = xfer->inDataAddr;
    uint32_t *readPointer  = xfer->outDataAddr;

    uint32_t writtenSamples = 0U, readSamples = 0U, i = 0U, j = 0U;
    /* enable context run */
    ASRC_EnableContextRun(base, context, true);
    ASRC_EnableContextRunStop(base, context, false);

    while ((inSamples != 0U) || (outSamples != 0U))
    {
        if (inSamples != 0U)
        {
            if (inSamples < inWatermarkSamples)
            {
                writtenSamples = inSamples;
            }
            else
            {
                writtenSamples = inWatermarkSamples;
            }

            if ((ASRC_GetFifoStatus(base, context) & (uint32_t)kASRC_FifoStatusInputFifoWatermarkFlag) != 0U)
            {
                for (i = 0U; i < writtenSamples; i++)
                {
                    ASRC_WriteContextFifo(base, context, *writePointer & inMask);
                    writePointer = (uint32_t *)((size_t)writePointer + inWidth);
                }

                inSamples -= writtenSamples;
            }
        }

        if (outSamples <= outWatermarkSamples)
        {
            readSamples = ASRC_ReadFIFORemainedSample(base, context, readPointer, outWidth, outSamples);
            /* for the case that all the output samples have write to the output fifo and all the fifo samples has been
             * read */
            if (((ASRC_GetInterruptStatus(base) & ((uint32_t)kASRC_Context0RunStopDone << (uint32_t)context)) != 0U) &&
                (readSamples == 0U))
            {
                ASRC_ClearInterruptStatus(base, ((uint32_t)kASRC_Context0RunStopDone << (uint32_t)context));
                break;
            }
            outSamples -= readSamples;
            continue;
        }
        else
        {
            readSamples = outWatermarkSamples;
        }

        if ((ASRC_GetFifoStatus(base, context) & (uint32_t)kASRC_FifoStatusOutputFifoWatermarkFlag) != 0U)
        {
            for (j = 0U; j < readSamples; j++)
            {
                *readPointer = ASRC_ReadContextFifo(base, context);
                readPointer  = (uint32_t *)((size_t)readPointer + outWidth);
            }
            outSamples -= readSamples;
        }
        else
        {
            /* flush all the samples out */
            if ((inSamples == 0U) && (outSamples > outWatermarkSamples))
            {
                ASRC_EnableContextRunStop(base, context, true);
            }
        }
    }

    /* disable context run */
    ASRC_EnableContextRun(base, context, false);
    ASRC_EnableContextRunStop(base, context, false);

    return kStatus_Success;
}
