/*
 * Copyright 2020-2022 Yuntu Microelectronics Co., Ltd.
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

/*!
* @page misra_violations MISRA-C:2012 violations list
*
* PRQA S 0311 Rule 11.8: Dangerous pointer cast results in loss of const qualification.
*
* PRQA S 0326 Rule 11.6: Cast between a pointer to void and an integral type.
*
* PRQA S 3677 Rule 8.13: The elements of the array parameter 'data' are not modified and so they could be qualified as 'const'.
*
* PRQA S 4395 Rule 11.1:  composite expression of 'essentially floating' type (float) is being cast to a different type category, 'unsigned'.
*
* PRQA S 3493 Rule 14.3:  The first operand of this conditional operator is always constant 'true'.
*
* PRQA S 4700 CMN 0.2:  Metric value out of threshold range: SAI_DRV_TxIRQ() : STCYC = 40.
*
* PRQA S 2985 Rule 2.2:  This operation is redundant. The value of the result is always that of the left-hand operand.
*
* PRQA S 2983 Rule 2.2:  This assignment is redundant. The value of this object is never subsequently used.
*
*/

/*!
 * @file sai_driver.c
 * @version 1.4.0
 */

#include "sai_driver.h"

typedef float float32_t;
/*! @cond DRIVER_INTERNAL_USE_ONLY */

/* default values set by driver */
#define TX_WATERMARK 2U
#define RX_WATERMARK 5U
#define FIFO_SIZE 8U
#define BIT_CLK_SWAP false
#define BIT_CLK_AS_EXTERNAL false
#define WORD_FLAG_INDEX 0
#define CONT_ON_ERROR true
#define PACK_MODE 0
#define TX_FIFO_SIZE (FIFO_SIZE-TX_WATERMARK)
#define RX_FIFO_SIZE (RX_WATERMARK+1U)
#define SAI_IRQS                              { SAI0_IRQn, SAI1_IRQn } 
#define REVERSE_BIT(x,y)  (x)^=(1U<<(y))        
/*******************************************************************************
 * Private Functions
 ******************************************************************************/

static void SAI_DRV_TxResetVar(uint32_t instance);
static void SAI_DRV_RxResetVar(uint32_t instance);
static void SAI_DRV_CompleteSendDataUsingDma(void * parameter,
                                             dma_chn_status_t status);
static void SAI_DRV_CompleteReceiveDataUsingDma(void * parameter,
                                             dma_chn_status_t status);
static void SAI_DRV_TxIRQ(uint32_t instance);
static void SAI_DRV_RxIRQ(uint32_t instance);
static void SAI_DRV_SendInt(uint32_t instance,
                            const uint8_t* const data[],
                            uint32_t count);
static void SAI_DRV_SendDma(uint32_t instance,
                            const uint8_t* const data[],
                            uint32_t count);
static void SAI_DRV_ReceiveDma(uint32_t instance,
                              uint8_t* data[],
                              uint32_t count);
static void SAI_DRV_ReceiveInt(uint32_t instance,
                              uint8_t* data[],
                              uint32_t count);
void SAI0_IRQHandler(void);
void SAI1_IRQHandler(void);
static inline void SAI_DRV_APBReset(uint32_t instance);


/*******************************************************************************
 * Variables
 ******************************************************************************/
/* Channel count for each instance */
#if (SAI_INSTANCE_COUNT == 2U)
static const uint8_t sai_channel_count[SAI_INSTANCE_COUNT] = {SAI0_CHANNEL_COUNT, SAI1_CHANNEL_COUNT};
#elif (SAI_INSTANCE_COUNT == 3U)
static const uint8_t sai_channel_count[SAI_INSTANCE_COUNT] = {SAI0_CHANNEL_COUNT, SAI1_CHANNEL_COUNT, SAI2_CHANNEL_COUNT};
#endif
#if (SAI_INSTANCE_COUNT == 2U)
 __attribute__((unused)) static const clock_names_t SAIClkNames[SAI_INSTANCE_COUNT] = {SAI0_CLK, SAI1_CLK};
#elif (SAI_INSTANCE_COUNT == 3U)
static const clock_names_t SAIClkNames[SAI_INSTANCE_COUNT] = {SAI0_CLK, SAI1_CLK, SAI2_CLK};
#endif

/** Interrupt vectors for the SAI peripheral type */
static SAI_Type * const g_saiBase[SAI_INSTANCE_COUNT] = SAI_BASE_PTRS;
static const IRQn_Type SAIIrqId[SAI_INSTANCE_COUNT] = SAI_IRQS;

/* state variables */
static sai_state_t* g_saiTxState[SAI_INSTANCE_COUNT];
static sai_state_t* g_saiRxState[SAI_INSTANCE_COUNT];

/* IPC INDEX */
static uint8_t g_saiIpcIndex[SAI_INSTANCE_COUNT] = {IPC_SAI0_INDEX, IPC_SAI1_INDEX};

#if (SAI_INSTANCE_COUNT > 0U)
/* Implementation of SAI0 handler named in startup code. */
void SAI0_IRQHandler(void)
{
    if(g_saiTxState[0] != NULL)
    {
        SAI_DRV_TxIRQ(0U);
    }
    if(g_saiRxState[0] != NULL)
    {
        SAI_DRV_RxIRQ(0U);
    }
}
#endif

#if (SAI_INSTANCE_COUNT > 1U)
/* Implementation of SAI1 handler named in startup code. */
void SAI1_IRQHandler(void)
{
    if(g_saiTxState[1] != NULL)
    {
        SAI_DRV_TxIRQ(1U);
    }
    if(g_saiRxState[1] != NULL)
    {
        SAI_DRV_RxIRQ(1U);
    }
}
#endif

/*FUNCTION**********************************************************************
 *
 * Function Name : TO_BIT
 * Description   : Convert bool to interger
 *
 *END**************************************************************************/
static inline uint32_t TO_BIT(bool x)
{
    return x ? 1UL : 0UL;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : SAI_DRV_TxResetVar
 * Description   : Reset driver variable
 *
 *END**************************************************************************/
static void SAI_DRV_TxResetVar(uint32_t instance)
{
    uint8_t j;
    for (j = 0; j < sai_channel_count[instance]; j++)
    {
        g_saiTxState[instance]->ChnState[j].data = NULL;
        g_saiTxState[instance]->ChnState[j].count = 0U;
    }
    /* unsupported means uninitialized */
    g_saiTxState[instance]->status = STATUS_UNSUPPORTED;
    g_saiTxState[instance]->Blocking = false;
    g_saiTxState[instance]->Callback = NULL;
    g_saiTxState[instance]->NextChn = 0U;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : SAI_DRV_RxResetVar
 * Description   : Reset driver variable
 *
 *END**************************************************************************/
static void SAI_DRV_RxResetVar(uint32_t instance)
{
    uint8_t j;
    for (j = 0; j < sai_channel_count[instance]; j++)
    {
        g_saiRxState[instance]->ChnState[j].data = NULL;
        g_saiRxState[instance]->ChnState[j].count = 0U;
    }
    /* unsupported means uninitialized */
    g_saiRxState[instance]->status = STATUS_UNSUPPORTED;
    g_saiRxState[instance]->Blocking = false;
    g_saiRxState[instance]->Callback = NULL;
    g_saiRxState[instance]->NextChn = 0U;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : SAI_DRV_CompleteSendDataUsingDma
 * Description   : Finish sending data using dma
 *
 *END**************************************************************************/
static void SAI_DRV_CompleteSendDataUsingDma(void * parameter,
                                             dma_chn_status_t status)
{
    uint32_t instance = ((uint32_t)parameter & 0xffUL); /* PRQA S 0326 */
    uint8_t ChnNum = (uint8_t)(((uint32_t)parameter >> 16UL) & 0xffUL); /* PRQA S 0326 */
    uint8_t DmaChn = (uint8_t)(((uint32_t)parameter >> 8UL) & 0xffUL); /* PRQA S 0326 */
    uint8_t c = 0;
    SAI_Type* base = g_saiBase[instance];
    uint8_t i;
    bool finish = true;

    /* Release the DMA channel */
    if (status != DMA_CHN_NORMAL)
    {
        g_saiTxState[instance]->status = STATUS_ERROR;
        /* stop all other dma channel*/
        if ((g_saiTxState[instance]->mux == SAI_MUX_DISABLED) || (g_saiTxState[instance]->mux == SAI_MUX_LINE))
        {
            for (i = 0; i < sai_channel_count[instance]; i++)
            {
                if (SAI_DRV_IsTxChannelEnabled(base, i))
                {
                    (void)DMA_DRV_StopChannel(g_saiTxState[instance]->DmaChannel[c]);
                    c++;
                    g_saiTxState[instance]->ChnState[i].count = 0U;
                }
            }
        }
        else
        {
            (void)DMA_DRV_StopChannel(g_saiTxState[instance]->DmaChannel[0]);
            g_saiTxState[instance]->ChnState[0].count = 0U;
        }
        finish = true;
    }
    else
    {
        (void)DMA_DRV_StopChannel(g_saiTxState[instance]->DmaChannel[DmaChn]);
        g_saiTxState[instance]->ChnState[ChnNum].count = 0U;
        /* check if all channel finished */
        if ((g_saiTxState[instance]->mux == SAI_MUX_DISABLED) || (g_saiTxState[instance]->mux == SAI_MUX_LINE))
        {
            for (i = 0; i < sai_channel_count[instance]; i++)
            {
                if (SAI_DRV_IsTxChannelEnabled(base, i))
                {
                    if (g_saiTxState[instance]->ChnState[i].count > 0U)
                    {
                        finish = false;
                        break;
                    }
                }
            }
        }
        else /* mux mem only one channel */
        {
            finish = true;
        }
    }
    if (finish)
    {
        /* Disable tx DMA requests for the current instance */
        SAI_DRV_TxDisableFifoReqDma(base);
        if (g_saiTxState[instance]->status != STATUS_ERROR)
        {
            g_saiTxState[instance]->status = STATUS_SUCCESS;
        }
        if (g_saiTxState[instance]->Blocking)
        {
            (void)OSIF_SemaPost(&g_saiTxState[instance]->Sema);
        }
        else
        {
            /* Invoke callback if there is one */
            if (g_saiTxState[instance]->Callback != NULL)
            {
                g_saiTxState[instance]->Callback(ChnNum, SAI_TRANSFER_COMPLETE, g_saiTxState[instance]->status);
            }
        }
    }
}

/*FUNCTION**********************************************************************
 *
 * Function Name : SAI_DRV_CompleteReceiveDataUsingDma
 * Description   : Finish receiving data using dma
 *
 *END**************************************************************************/
static void SAI_DRV_CompleteReceiveDataUsingDma(void * parameter,
                                             dma_chn_status_t status)
{
    uint32_t instance = ((uint32_t)parameter & 0xffUL); /* PRQA S 0326 */
    uint8_t ChnNum = (uint8_t)(((uint32_t)parameter >> 16U) & 0xffUL); /* PRQA S 0326 */
    uint8_t DmaChn = (uint8_t)(((uint32_t)parameter >> 8U) & 0xffUL); /* PRQA S 0326 */
    uint8_t c = 0;
    SAI_Type* base = g_saiBase[instance];
    uint8_t i;
    bool finish = true;

    /* Release the DMA channel */
    if (status != DMA_CHN_NORMAL)
    {
        g_saiRxState[instance]->status = STATUS_ERROR;
        /* stop all other dma channel*/
        if ((g_saiRxState[instance]->mux == SAI_MUX_DISABLED) || (g_saiRxState[instance]->mux == SAI_MUX_LINE))
        {
            for (i = 0; i < sai_channel_count[instance]; i++)
            {
                if (SAI_DRV_IsRxChannelEnabled(base, i))
                {
                    (void)DMA_DRV_StopChannel(g_saiRxState[instance]->DmaChannel[c]);
                    c++;
                    g_saiRxState[instance]->ChnState[i].count = 0U;
                }
            }
        }
        else
        {
            (void)DMA_DRV_StopChannel(g_saiRxState[instance]->DmaChannel[0]);
            g_saiRxState[instance]->ChnState[0].count = 0U;
        }
        finish = true;
    }
    else
    {
        (void)DMA_DRV_StopChannel(g_saiRxState[instance]->DmaChannel[DmaChn]);
        g_saiRxState[instance]->ChnState[ChnNum].count = 0U;
        /* check if all channel finished */
        if ((g_saiRxState[instance]->mux == SAI_MUX_DISABLED) || (g_saiRxState[instance]->mux == SAI_MUX_LINE))
        {
            for (i = 0; i < sai_channel_count[instance]; i++)
            {
                if (SAI_DRV_IsRxChannelEnabled(base, i))
                {
                    if (g_saiRxState[instance]->ChnState[i].count > 0U)
                    {
                        finish = false;
                        break;
                    }
                }
            }
        }
        else /* mux mem only one channel */
        {
            finish = true;
        }
    }
    if (finish)
    {
        /* Disable Rx DMA requests for the current instance */
        SAI_DRV_RxDisableFifoReqDma(base);
        if (g_saiRxState[instance]->status != STATUS_ERROR)
        {
            g_saiRxState[instance]->status = STATUS_SUCCESS;
        }
        if (g_saiRxState[instance]->Blocking)
        {
            (void)OSIF_SemaPost(&g_saiRxState[instance]->Sema);
        }
        else
        {
            /* Invoke callback if there is one */
            if (g_saiRxState[instance]->Callback != NULL)
            {
                g_saiRxState[instance]->Callback(ChnNum, SAI_TRANSFER_COMPLETE, g_saiRxState[instance]->status);
            }
        }
    }
}

/*******************************************************************************
 * Code
 ******************************************************************************/
/*FUNCTION**********************************************************************
*
* Function Name : SAI_DRV_CalculateParamMCKDiv
* Description   : Get parameters , which is used to configure mclk frequency. Default configuration of mclk frequency is 24.5758MHz
* Implements    : SAI_DRV_CalculateParamMCKDiv_Activity
*END*************************************************************************/
static status_t SAI_DRV_CalculateParamMCKDiv(uint32_t mckClkFreq, uint32_t SourceClock, uint16_t* mckDiv, uint16_t* frac)
{
    status_t status = STATUS_ERROR;
    DEV_ASSERT(SourceClock > 0);
    DEV_ASSERT(mckDiv != NULL);
    DEV_ASSERT(frac != NULL);

    float32_t prescaler = 0.0F;
    uint16_t numerator = 1;
    uint16_t denominator = 1;
    uint16_t optimalNumerator = 1;
    uint16_t optimalDenominator = 1;
    float32_t scaler = 0.0F;
    float32_t scalerDiff = 0.0F;
    float32_t optimalScalerDiff = 1048575.0F;
    /* Judge whether the SourceClock can be split out default frequency*/
    if(SourceClock < mckClkFreq)
    {
        status = STATUS_ERROR;
    }else {
        
        /* Calculate the actual frequency division coefficient */
        prescaler = ((float32_t)SourceClock) / ((float32_t)mckClkFreq);
        /* Judge whether it is out of range */
        if(prescaler > 4096.0F)
        {
            *mckDiv = 0x1000;
            *frac = 0x01;
            status = STATUS_ERROR;
        }
        else if(prescaler < (257.0F/256.0F))
        {
            *mckDiv = 0x101;
            *frac = 0x100;
            status = STATUS_ERROR;
        } else {
            /* Calculate the optimal frequency division mode */
            do
            {
                numerator = (uint16_t)((prescaler * ((float32_t)denominator)) + 0.5F);/* PRQA S 4395 */
                if(numerator <= 0x1000U)
                {
                    scaler = ((float32_t)numerator) / ((float32_t)denominator);
                    scalerDiff = (prescaler >= scaler) ? (prescaler - scaler) : (scaler - prescaler);
                    if(scalerDiff < optimalScalerDiff)
                    {
                        optimalScalerDiff = scalerDiff;
                        optimalNumerator = numerator;
                        optimalDenominator = denominator;
                    }
                    denominator++;            
                }
                else
                {
                    denominator++;
                    continue;
                }
            } while(denominator <= 0x100U);
            *mckDiv = optimalNumerator;
            *frac = optimalDenominator;
            status = STATUS_SUCCESS;
        }
    }
    return status;   
}
/*FUNCTION**********************************************************************
*
* Function Name : SAI_DRV_TxInit
* Description   : Init tx core
* These params are set by driver:
*      bool BIT_CLK_SWAP = false             < Enable or disable bit clock swap mode.>
*      bool BIT_CLK_AS_EXTERNAL = false;      < Delay internal clock as if clock is generated externally.>
*      uint8_t WORD_FLAG_INDEX = 0;          < Index of word in frame that raise word start flag.>
*      bool CONT_ON_ERROR = true;            < Continue on fifo error.>
*      sai_combine_mode CombineMode = combine line or combine memory, user choice
*                                          < Select fifo combine mode.>
*      sai_packing_mode PACK_MODE = false;     < Select fifo pack mode.>
*      bool SYNC_ON_DEMAND; = false             < Generate frame sync only when fifo is not empty (transmit)
*                                             or not full (receive).>
* Implements    : SAI_DRV_TxInit_Activity
*END*************************************************************************/
void SAI_DRV_TxInit(uint32_t instance,
                   const sai_user_config_t* saiUserConfig,
                   sai_state_t* saiState)
{
    SAI_Type* base = g_saiBase[instance];
    DEV_ASSERT(saiUserConfig != NULL);
    DEV_ASSERT(saiState != NULL);
    DEV_ASSERT(instance < SAI_INSTANCE_COUNT);
    DEV_ASSERT((saiUserConfig->FrameSize <= (1U << (SAI_DRV_GetParamFrameSize(instance)))) && (saiUserConfig->FrameSize > 0U));
    /* if sync with other, receiver must be async and enabled */
#ifdef DEV_ERROR_DETECT
    uint32_t temp = base->RCTRL;
    uint32_t temp2 = base->RCFG0;   
    DEV_ASSERT((saiUserConfig->SyncMode != SAI_SYNC_WITH_OTHER) || \
                ((saiUserConfig->SyncMode == SAI_SYNC_WITH_OTHER) && ((temp2 & SAI_RCFG0_SYNC_MASK) == 0U) && (temp & SAI_RCTRL_RE_MASK) != 0U));
#endif /* DEV_ERROR_DETECT */
    DEV_ASSERT(saiUserConfig->Word0Width > 0U);
    DEV_ASSERT(saiUserConfig->WordNWidth > 0U);
    DEV_ASSERT(saiUserConfig->SyncWidth > 0U);
    DEV_ASSERT(saiUserConfig->FirstBitIndex < 32U);
    DEV_ASSERT((saiUserConfig->MuxMode != SAI_MUX_LINE) || \
                (saiUserConfig->TransferType != SAI_INTERRUPT) || \
                ((saiUserConfig->ChannelCount != 0U) && \
                ((saiUserConfig->ChannelEnable == 0x01) || (saiUserConfig->ChannelEnable == 0x02) || (saiUserConfig->ChannelEnable == 0x04) || (saiUserConfig->ChannelEnable == 0x08)) && \
               ((saiUserConfig->FrameSize % saiUserConfig->ChannelCount) == 0U)));
    DEV_ASSERT((saiUserConfig->TransferType != SAI_DMA) ||\
                ((saiUserConfig->ChannelEnable == 0x01) || (saiUserConfig->ChannelEnable == 0x03) || (saiUserConfig->ChannelEnable == 0x07) || (saiUserConfig->ChannelEnable == 0x0F)));
    DEV_ASSERT((saiUserConfig->ElementSize == 1U) || (saiUserConfig->ElementSize == 2U) || (saiUserConfig->ElementSize == 4U));

    uint32_t SourceClock = 0U;
    uint16_t mckDiv = 1U;
    uint16_t mckFrac = 1U;
    uint32_t bitDivisor = 1U;
    uint8_t CombineMode = 0U;
    __attribute__((unused))status_t osifError = STATUS_SUCCESS;   
    bool isMclkEnabe = true;
    /* Get clock as configured in the clock manager */
    if (saiUserConfig->MasterClkSrc == SAI_FXOSC_CLK)
    {
        (void)CLOCK_SYS_GetFreq(IPC_FXOSC_CLK, &SourceClock);
        DEV_ASSERT(SourceClock > 0U);
    }
    else if (saiUserConfig->MasterClkSrc == SAI_BUS_CLK)
    {
        (void)CLOCK_SYS_GetFreq(SLOW_BUS_CLK, &SourceClock);
        DEV_ASSERT(SourceClock > 0U);
    }
    else if (saiUserConfig->MasterClkSrc == SAI_PLL_CLK)
    {
        (void)CLOCK_SYS_GetFreq(IPC_PLL_CLK, &SourceClock);
        DEV_ASSERT(SourceClock > 0U);
    }
    else if (saiUserConfig->MasterClkSrc == SAI_ANOTHER_MCLK)
    {
        SourceClock = saiUserConfig->AnotherSaiMclkFreq;
        DEV_ASSERT(SourceClock > 0U);
    }else {
        /* do nothing */
    }
    /* save state pointer */
    g_saiTxState[instance] = saiState;
    /* Reset driver variable */
    SAI_DRV_TxResetVar(instance);
    /* calculate mck divisor parameter */
    (void)SAI_DRV_CalculateParamMCKDiv(saiUserConfig->MckClkFreq, SourceClock, &mckDiv, &mckFrac);
    /* calculate bit divisor parameter */
    if(saiUserConfig->SyncMode == SAI_ASYNC)
    {
        if(saiUserConfig->BitClkInternal == true)
        {
            DEV_ASSERT(saiUserConfig->BitClkFreq != 0U);
            bitDivisor = ((saiUserConfig->MckClkFreq / saiUserConfig->BitClkFreq) / 2UL);
            if(bitDivisor > 255U)
            {
                bitDivisor = 255U;   
            }
            else if(bitDivisor == 0U)
            {     
                bitDivisor = 0x01;
            }else {
                /* do nothing */
            }
        }
        else
        {
            /* do nothing */
        }
    } 
    g_saiTxState[instance]->ElementSize = saiUserConfig->ElementSize;
    g_saiTxState[instance]->XferType = saiUserConfig->TransferType;
    g_saiTxState[instance]->mux = saiUserConfig->MuxMode;
    if (saiUserConfig->TransferType == SAI_DMA)
    {
        g_saiTxState[instance]->DMAEnable = (g_saiTxState[instance]->mux== SAI_MUX_MEM) ? 
                                                ((uint8_t)0x01U) : saiUserConfig->ChannelEnable;

        for (uint32_t i = 0U; i < sai_channel_count[instance]; i++)
        {
            g_saiTxState[instance]->DmaChannel[i] = saiUserConfig->DmaChannel[i];
        }
        CombineMode = (uint8_t)saiUserConfig->MuxMode;
    }
    else
    {
        CombineMode = 0U; /* emulate combine mode */
        g_saiTxState[instance]->ChannelCount = saiUserConfig->ChannelCount;
    }

    osifError = OSIF_SemaCreate(&g_saiTxState[instance]->Sema, 0U); /* PRQA S 2983 */
    DEV_ASSERT(osifError == STATUS_SUCCESS);
    base->TCTRL = SAI_TCTRL_SR(1);      /* call reset bit, reset fifo and logic */
    base->TINTE = SAI_TINTE_FEIE(TO_BIT(saiUserConfig->RunErrorReport)) | /* PRQA S 2985 */
                  SAI_TINTE_SEIE(TO_BIT(saiUserConfig->SyncErrorReport)) | /* PRQA S 2985 */
                  SAI_TINTE_WSIE(TO_BIT(saiUserConfig->FrameStartReport)); /* PRQA S 2985 */
    base->TFCR =  SAI_TFCR_TFW(TX_WATERMARK) |
                  SAI_TFCR_FCOMB(CombineMode) |
                  SAI_TFCR_FCONT((CONT_ON_ERROR) ? 1U : 0U) | /* PRQA S 3493,2985 */
                  SAI_TFCR_FPACK(PACK_MODE);
    base->TCFG0 = SAI_TCFG0_SYNC(saiUserConfig->SyncMode) | /* PRQA S 2985 */
                  SAI_TCFG0_BCS(TO_BIT(BIT_CLK_SWAP)) |
#if !defined(FEATURE_SAI_HAS_NO_BIT_CLOCK_DELAY)
                  SAI_TCFG0_BCI(TO_BIT(BIT_CLK_AS_EXTERNAL)) |
#endif
                  SAI_TCFG0_BCP(TO_BIT(saiUserConfig->BitClkNegPolar)) | /* PRQA S 2985 */
                  SAI_TCFG0_BCD(TO_BIT(saiUserConfig->BitClkInternal)) | /* PRQA S 2985 */
                  SAI_TCFG0_DIV((bitDivisor-1U) & 0xFFU); /* PRQA S 2985 */
    base->TCFG1 = SAI_TCFG1_TCE(saiUserConfig->ChannelEnable) | /* PRQA S 2985 */
                  SAI_TCFG1_WDFL(WORD_FLAG_INDEX);
    base->TCFG2 = SAI_TCFG2_FRSZ((uint32_t)saiUserConfig->FrameSize - 1U) |
                  SAI_TCFG2_SYWD((uint32_t)saiUserConfig->SyncWidth - 1U) |
                  SAI_TCFG2_CHMOD(saiUserConfig->MaskMode) |
                  SAI_TCFG2_MF(TO_BIT(saiUserConfig->MsbFirst)) | /* PRQA S 2985 */
                  SAI_TCFG2_FSE(TO_BIT(saiUserConfig->SyncEarly)) | /* PRQA S 2985 */
                  SAI_TCFG2_FSP(TO_BIT(saiUserConfig->SyncNegPolar)) | /* PRQA S 2985 */
                  SAI_TCFG2_FSD(TO_BIT(saiUserConfig->SyncInternal)) | /* PRQA S 2985 */
                  SAI_TCFG2_ONDEM(TO_BIT(saiUserConfig->SyncNCONT)); /* PRQA S 2985 */
    base->TCFG3 = SAI_TCFG3_WNW((uint32_t)saiUserConfig->WordNWidth - 1U) |
                  SAI_TCFG3_W0W((uint32_t)saiUserConfig->Word0Width - 1U) |
                  SAI_TCFG3_FBT(saiUserConfig->MsbFirst ? ~(uint32_t)saiUserConfig->FirstBitIndex : (uint32_t)saiUserConfig->FirstBitIndex); /* PRQA S 2985 */
    base->MCLK_FRAC_DIV = SAI_MCLK_FRAC_DIV_DENO((uint32_t)mckDiv-1U) + SAI_MCLK_FRAC_DIV_NUME((uint32_t)mckFrac-1U); /* PRQA S 2985 */
    base->MCLK_CTRL = SAI_MCLK_CTRL_CLKSEL(saiUserConfig->MasterClkSrc) |
                      SAI_MCLK_CTRL_MCKEN(TO_BIT(isMclkEnabe));
    g_saiTxState[instance]->Callback = saiUserConfig->callback;
    if ((saiUserConfig->TransferType == SAI_INTERRUPT) || (saiUserConfig->RunErrorReport) ||
        (saiUserConfig->SyncErrorReport) || (saiUserConfig->FrameStartReport))
    {
        INT_SYS_EnableIRQ(SAIIrqId[instance]);
    };
    base->TCTRL &= ~SAI_TCTRL_SR_MASK;  /* clear SR bit */
    base->TCTRL |= SAI_TCTRL_TE(1U);
}

/*FUNCTION**********************************************************************
*
* Function Name : SAI_DRV_RxInit
* Description   : Init rx core
* These params are set by driver:
*      Others are the same as TxInit
* Implements    : SAI_DRV_RxInit_Activity
*END*************************************************************************/
void SAI_DRV_RxInit(uint32_t instance,
                    const sai_user_config_t* saiUserConfig,
                    sai_state_t* saiState)
{
    SAI_Type* base = g_saiBase[instance];
    DEV_ASSERT(saiUserConfig != NULL);
    DEV_ASSERT(saiState != NULL);
    DEV_ASSERT(instance < SAI_INSTANCE_COUNT);
    DEV_ASSERT((saiUserConfig->FrameSize <= (1U << (SAI_DRV_GetParamFrameSize(instance)))) && (saiUserConfig->FrameSize > 0U));
    /* if sync with other, trasnmiter must be async and enabled */
#ifdef DEV_ERROR_DETECT
    uint32_t temp  = base->TCTRL;
    uint32_t temp2 = base->TCFG0;
    DEV_ASSERT((saiUserConfig->SyncMode != SAI_SYNC_WITH_OTHER) || \
                ((saiUserConfig->SyncMode == SAI_SYNC_WITH_OTHER) && ((temp2 & SAI_TCFG0_SYNC_MASK) == 0U) && ((temp & SAI_TCTRL_TE_MASK) != 0U)));
#endif /* DEV_ERROR_DETECT */
    DEV_ASSERT(saiUserConfig->Word0Width > 0U);
    DEV_ASSERT(saiUserConfig->WordNWidth > 0U);
    DEV_ASSERT(saiUserConfig->SyncWidth > 0U);
    DEV_ASSERT(saiUserConfig->FirstBitIndex < 32U);
    DEV_ASSERT((saiUserConfig->MuxMode != SAI_MUX_LINE) || \
                (saiUserConfig->TransferType != SAI_INTERRUPT) || \
                ((saiUserConfig->ChannelCount != 0U) && \
                ((saiUserConfig->ChannelEnable == 0x01) || (saiUserConfig->ChannelEnable == 0x02) || (saiUserConfig->ChannelEnable == 0x04) || (saiUserConfig->ChannelEnable == 0x08)) && \
               ((saiUserConfig->FrameSize % saiUserConfig->ChannelCount) == 0U)));
    DEV_ASSERT((saiUserConfig->TransferType != SAI_DMA) ||\
                ((saiUserConfig->ChannelEnable == 0x01) || (saiUserConfig->ChannelEnable == 0x03) || (saiUserConfig->ChannelEnable == 0x07) || (saiUserConfig->ChannelEnable == 0x0F)));
    DEV_ASSERT((saiUserConfig->ElementSize == 1U) || (saiUserConfig->ElementSize == 2U) || (saiUserConfig->ElementSize == 4U));

    uint32_t SourceClock = 0U;
    uint16_t mckDiv = 1U;
    uint16_t mckFrac = 1U;
    uint32_t bitDivisor = 1U;
    uint8_t CombineMode = 0U;
 __attribute__((unused))status_t osifError = STATUS_SUCCESS;
    bool isMclkEnabe = true;
    sai_sync_mode_t syncMode = SAI_ASYNC;
    uint32_t tempSync = 0U;

    /* Get clock as configured in the clock manager */
    if (saiUserConfig->MasterClkSrc == SAI_FXOSC_CLK)
    {
        (void)CLOCK_SYS_GetFreq(IPC_FXOSC_CLK, &SourceClock);
        DEV_ASSERT(SourceClock > 0U);
    }
    else if (saiUserConfig->MasterClkSrc == SAI_BUS_CLK)
    {
        (void)CLOCK_SYS_GetFreq(SLOW_BUS_CLK, &SourceClock);
        DEV_ASSERT(SourceClock > 0U);
    }
    else if (saiUserConfig->MasterClkSrc == SAI_PLL_CLK)
    {
        (void)CLOCK_SYS_GetFreq(IPC_PLL_CLK, &SourceClock);
        DEV_ASSERT(SourceClock > 0U);
    }
    else if (saiUserConfig->MasterClkSrc == SAI_ANOTHER_MCLK)
    {
        SourceClock = saiUserConfig->AnotherSaiMclkFreq;
        DEV_ASSERT(SourceClock > 0U);
    }else {
        /* do nothing */
    }
    /* save state pointer */
    g_saiRxState[instance] = saiState;
    /* Reset driver variable */
    SAI_DRV_RxResetVar(instance);
    /* calculate mck divisor parameter */
    (void)SAI_DRV_CalculateParamMCKDiv(saiUserConfig->MckClkFreq, SourceClock, &mckDiv, &mckFrac);
    /* calculate bit divisor parameter */
    if(saiUserConfig->SyncMode == SAI_ASYNC)
    {
        if(saiUserConfig->BitClkInternal == true)
        {
            DEV_ASSERT(saiUserConfig->BitClkFreq != 0U);
            bitDivisor = ((saiUserConfig->MckClkFreq / saiUserConfig->BitClkFreq) / 2UL);
            if(bitDivisor > 255U)
            {
                bitDivisor = 255U;   
            }
            else if(bitDivisor == 0U)
            {     
                bitDivisor = 0x01;
            }else {
                /* do nothing */
            }
        }
        else
        {
            /* do nothing */
        }
    } 
    g_saiRxState[instance]->ElementSize = saiUserConfig->ElementSize;
    g_saiRxState[instance]->XferType = saiUserConfig->TransferType;
    g_saiRxState[instance]->mux = saiUserConfig->MuxMode;
    if (saiUserConfig->TransferType == SAI_DMA)
    {
        g_saiRxState[instance]->DMAEnable = (g_saiRxState[instance]->mux== SAI_MUX_MEM) ? 
                                                (uint8_t)0x01U : saiUserConfig->ChannelEnable;

        for (uint32_t i = 0U; i < sai_channel_count[instance]; i++)
        {
            g_saiRxState[instance]->DmaChannel[i] = saiUserConfig->DmaChannel[i];
        }
        CombineMode = (uint8_t)saiUserConfig->MuxMode;
    }
    else
    {
        CombineMode = 0U; /* emulate combine mode */
        g_saiRxState[instance]->ChannelCount = saiUserConfig->ChannelCount;
    }  
    /* get sync mode */ 
    syncMode = saiUserConfig->SyncMode;
    if(((uint32_t)syncMode & 0x2U) != 0U)
    {
        tempSync = (uint32_t)syncMode;
        REVERSE_BIT(tempSync, 0U);
        syncMode = (sai_sync_mode_t)tempSync;
    }

    osifError = OSIF_SemaCreate(&g_saiRxState[instance]->Sema, 0U); /* PRQA S 2983 */
    DEV_ASSERT(osifError == STATUS_SUCCESS);
    base->RCTRL = SAI_RCTRL_SR(1);      /* call reset bit, reset fifo and logic */
    base->RINTE = SAI_RINTE_FEIE(TO_BIT(saiUserConfig->RunErrorReport)) | /* PRQA S 2985 */
                  SAI_RINTE_SEIE(TO_BIT(saiUserConfig->SyncErrorReport)) | /* PRQA S 2985 */
                  SAI_RINTE_WSIE(TO_BIT(saiUserConfig->FrameStartReport)); /* PRQA S 2985 */
    base->RFCR =  SAI_RFCR_TFW((saiUserConfig->TransferType == SAI_DMA) ? 0UL : RX_WATERMARK) | /* PRQA S 2985 */
                  SAI_RFCR_FCONT((CONT_ON_ERROR) ? 1U : 0U) | /* PRQA S 3493 */
                  SAI_RFCR_FCOMB(CombineMode) | /* PRQA S 2985 */
                  SAI_RFCR_FPACK(PACK_MODE);
    base->RCFG0 = SAI_RCFG0_SYNC(syncMode) | /* PRQA S 2985 */
                  SAI_RCFG0_BCS(TO_BIT(BIT_CLK_SWAP)) |
#if !defined(FEATURE_SAI_HAS_NO_BIT_CLOCK_DELAY)
                  SAI_RCFG0_BCI(TO_BIT(BIT_CLK_AS_EXTERNAL)) |
#endif
                  SAI_RCFG0_BCP(TO_BIT(saiUserConfig->BitClkNegPolar)) | /* PRQA S 2985 */
                  SAI_RCFG0_BCD(TO_BIT(saiUserConfig->BitClkInternal)) | /* PRQA S 2985 */
                  SAI_RCFG0_DIV((bitDivisor-1U) & 0xFFU); /* PRQA S 2985 */
    base->RCFG1 = SAI_RCFG1_RCE(saiUserConfig->ChannelEnable) | /* PRQA S 2985 */
                  SAI_RCFG1_WDFL(WORD_FLAG_INDEX);
    base->RCFG2 = SAI_RCFG2_FRSZ((uint32_t)saiUserConfig->FrameSize - 1U) |
                  SAI_RCFG2_SYWD((uint32_t)saiUserConfig->SyncWidth - 1U) |
                  SAI_RCFG2_MF(TO_BIT(saiUserConfig->MsbFirst)) | /* PRQA S 2985 */
                  SAI_RCFG2_FSE(TO_BIT(saiUserConfig->SyncEarly)) | /* PRQA S 2985 */
                  SAI_RCFG2_FSP(TO_BIT(saiUserConfig->SyncNegPolar)) | /* PRQA S 2985 */
                  SAI_RCFG2_FSD(TO_BIT(saiUserConfig->SyncInternal)) | /* PRQA S 2985 */
                  SAI_RCFG2_ONDEM(TO_BIT(saiUserConfig->SyncNCONT)); /* PRQA S 2985 */
    base->RCFG3 = SAI_RCFG3_WNW((uint32_t)saiUserConfig->WordNWidth - 1U) |
                  SAI_RCFG3_W0W((uint32_t)saiUserConfig->Word0Width - 1U) |
                  SAI_RCFG3_FBT(saiUserConfig->MsbFirst ? ~(uint32_t)saiUserConfig->FirstBitIndex : (uint32_t)saiUserConfig->FirstBitIndex); /* PRQA S 2985 */
    base->MCLK_FRAC_DIV = SAI_MCLK_FRAC_DIV_DENO((uint32_t)mckDiv-1U) + SAI_MCLK_FRAC_DIV_NUME((uint32_t)mckFrac-1U); /* PRQA S 2985 */
    base->MCLK_CTRL = SAI_MCLK_CTRL_CLKSEL(saiUserConfig->MasterClkSrc) |
                      SAI_MCLK_CTRL_MCKEN(TO_BIT(isMclkEnabe));
    g_saiRxState[instance]->Callback = saiUserConfig->callback;
    if ((saiUserConfig->TransferType == SAI_INTERRUPT) || (saiUserConfig->RunErrorReport) ||
        (saiUserConfig->SyncErrorReport) || (saiUserConfig->FrameStartReport))
    {
        INT_SYS_EnableIRQ(SAIIrqId[instance]);
    };
    base->RCTRL &= ~SAI_RCTRL_SR_MASK;  /* clear SR bit */
    base->RCTRL |= SAI_RCTRL_RE(1U);    
}

/*FUNCTION**********************************************************************
 *
 * Function Name : SAI_DRV_TxIRQ
 * Description   : Manage interrupt transfer using fifo request, execute
 *                 other user interrupt func (fifo error, word start,
 *                 sync error)
 *
 *END**************************************************************************/
 /* PRQA S 4700 ++*/
static void SAI_DRV_TxIRQ(uint32_t instance) /* PRQA S 4700 --*/
{
    SAI_Type* base = g_saiBase[instance];
    uint8_t i,j;
    uint32_t temp;
    bool finish;

    if (SAI_DRV_TxGetFifoReqFlag(base))
    {
        if ((g_saiTxState[instance]->XferType == SAI_INTERRUPT) && (g_saiTxState[instance]->status == STATUS_BUSY))
        {
            finish = false;
            if (g_saiTxState[instance]->mux == SAI_MUX_LINE)
            {
                for (i = 0U; i < sai_channel_count[instance]; i++)
                {
                    if (SAI_DRV_IsTxChannelEnabled(base, i))
                    {
                        if (g_saiTxState[instance]->ChnState[0].count < TX_FIFO_SIZE)
                        {
                            temp = g_saiTxState[instance]->ChnState[0].count;
                        }
                        else
                        {
                            temp = TX_FIFO_SIZE;
                        }
                        for (j = 0U; j < temp; j++)
                        {
                            if (g_saiTxState[instance]->ElementSize == 1U)
                            {
                                SAI_DRV_TxWrite(base, i, (uint32_t)*g_saiTxState[instance]->ChnState[g_saiTxState[instance]->NextChn].data);
                            }
                            else if (g_saiTxState[instance]->ElementSize == 2U)
                            {
                                SAI_DRV_TxWrite(base, i, ((uint32_t)g_saiTxState[instance]->ChnState[g_saiTxState[instance]->NextChn].data[1] << 8) |
                                                ((uint32_t)g_saiTxState[instance]->ChnState[g_saiTxState[instance]->NextChn].data[0]));
                            }
                            else if (g_saiTxState[instance]->ElementSize == 4U)
                            {
                                SAI_DRV_TxWrite(base, i, ((uint32_t)g_saiTxState[instance]->ChnState[g_saiTxState[instance]->NextChn].data[3] << 24) |
                                                ((uint32_t)g_saiTxState[instance]->ChnState[g_saiTxState[instance]->NextChn].data[2] << 16) |
                                                ((uint32_t)g_saiTxState[instance]->ChnState[g_saiTxState[instance]->NextChn].data[1] << 8) |
                                                ((uint32_t)g_saiTxState[instance]->ChnState[g_saiTxState[instance]->NextChn].data[0]));
                            }
                            else
                            {
                                DEV_ASSERT(false);
                            }
                            /* Safe pointer advancement within known buffer bounds */
                            uint8_t nextChn = g_saiTxState[instance]->NextChn;
                            uint8_t *currentData = g_saiTxState[instance]->ChnState[nextChn].data;
                            uint8_t elementSize = g_saiTxState[instance]->ElementSize;
                            g_saiTxState[instance]->ChnState[nextChn].data = &currentData[elementSize];
                            g_saiTxState[instance]->NextChn++; /* alternate between data block */
                            if (g_saiTxState[instance]->NextChn == g_saiTxState[instance]->ChannelCount)
                            {
                                g_saiTxState[instance]->NextChn = 0U;
                            }
                        }
                        if (g_saiTxState[instance]->ChnState[0].count <= TX_FIFO_SIZE)
                        {
                            finish = true;
                            g_saiTxState[instance]->ChnState[0].count = 0;
                        }
                        else
                        {
                            g_saiTxState[instance]->ChnState[0].count -= TX_FIFO_SIZE;
                        }
                        break; /* only one channle enabled in this mode */
                    }
                }
            }
            else if (g_saiTxState[instance]->mux == SAI_MUX_MEM)
            {
                if (g_saiTxState[instance]->ChnState[0].count < TX_FIFO_SIZE)
                {
                    temp = g_saiTxState[instance]->ChnState[0].count;
                }
                else
                {
                    temp = TX_FIFO_SIZE;
                }
                for (j = 0U; j < temp; j++)
                {
                    for (i = 0U; i < sai_channel_count[instance]; i++)
                    {
                        if (SAI_DRV_IsTxChannelEnabled(base, i))
                        {
                            if (g_saiTxState[instance]->ElementSize == 1U)
                            {
                                SAI_DRV_TxWrite(base, i, (uint32_t)*g_saiTxState[instance]->ChnState[0].data);
                            }
                            else if (g_saiTxState[instance]->ElementSize == 2U)
                            {
                                SAI_DRV_TxWrite(base, i, ((uint32_t)g_saiTxState[instance]->ChnState[0U].data[1] << 8) |
                                                ((uint32_t)g_saiTxState[instance]->ChnState[0U].data[0]));
                            }
                            else if (g_saiTxState[instance]->ElementSize == 4U)
                            {
                                SAI_DRV_TxWrite(base, i, ((uint32_t)g_saiTxState[instance]->ChnState[0U].data[3] << 24) |
                                                ((uint32_t)g_saiTxState[instance]->ChnState[0U].data[2] << 16) |
                                                ((uint32_t)g_saiTxState[instance]->ChnState[0U].data[1] << 8) |
                                                ((uint32_t)g_saiTxState[instance]->ChnState[0U].data[0]));
                            }
                            else
                            {
                                DEV_ASSERT(false);
                            }
                            /* Safe pointer advancement within known buffer bounds */
                            uint8_t *currentData = g_saiTxState[instance]->ChnState[0U].data;
                            uint8_t elementSize = g_saiTxState[instance]->ElementSize;
                            g_saiTxState[instance]->ChnState[0U].data = &currentData[elementSize];
                        }
                    }
                }
                if (g_saiTxState[instance]->ChnState[0].count <= TX_FIFO_SIZE)
                {
                    finish = true;
                    g_saiTxState[instance]->ChnState[0].count = 0;
                }
                else
                {
                    g_saiTxState[instance]->ChnState[0].count -= TX_FIFO_SIZE;
                }
            }
            else /* mux disabled */
            {
                if (g_saiTxState[instance]->ChnState[0].count < TX_FIFO_SIZE)
                {
                    temp = g_saiTxState[instance]->ChnState[0].count;
                }
                else
                {
                    temp = TX_FIFO_SIZE;
                }
                for (i = 0U; i < sai_channel_count[instance]; i++)
                {
                    if (SAI_DRV_IsTxChannelEnabled(base, i))
                    {
                        for (j = 0U; j < temp; j++)
                        {
                            if (g_saiTxState[instance]->ElementSize == 1U)
                            {
                                SAI_DRV_TxWrite(base, i, (uint32_t)*g_saiTxState[instance]->ChnState[i].data);
                            }
                            else if (g_saiTxState[instance]->ElementSize == 2U)
                            {
                                SAI_DRV_TxWrite(base, i, ((uint32_t)g_saiTxState[instance]->ChnState[i].data[1] << 8) |
                                                ((uint32_t)g_saiTxState[instance]->ChnState[i].data[0]));
                            }
                            else if (g_saiTxState[instance]->ElementSize == 4U)
                            {
                                SAI_DRV_TxWrite(base, i, ((uint32_t)g_saiTxState[instance]->ChnState[i].data[3] << 24) |
                                                ((uint32_t)g_saiTxState[instance]->ChnState[i].data[2] << 16) |
                                                ((uint32_t)g_saiTxState[instance]->ChnState[i].data[1] << 8) |
                                                ((uint32_t)g_saiTxState[instance]->ChnState[i].data[0]));
                            }
                            else
                            {
                                DEV_ASSERT(false);
                            }
                            /* Safe pointer advancement within known buffer bounds */
                            uint8_t *currentData = g_saiTxState[instance]->ChnState[i].data;
                            uint8_t elementSize = g_saiTxState[instance]->ElementSize;
                            g_saiTxState[instance]->ChnState[i].data = &currentData[elementSize];
                        }
                    }
                }
                if (g_saiTxState[instance]->ChnState[0].count <= TX_FIFO_SIZE)
                {
                    finish = true;
                    g_saiTxState[instance]->ChnState[0].count = 0;
                }
                else
                {
                    g_saiTxState[instance]->ChnState[0].count -= TX_FIFO_SIZE;
                }
            }
            if (finish)
            {
                g_saiTxState[instance]->status = STATUS_SUCCESS;
                SAI_DRV_TxDisableFifoReqInt(base);
                if (g_saiTxState[instance]->Blocking)
                {
                    (void)OSIF_SemaPost(&g_saiTxState[instance]->Sema);
                }
                else
                {
                    if (g_saiTxState[instance]->Callback != NULL)
                    {
                        g_saiTxState[instance]->Callback(0U, SAI_TRANSFER_COMPLETE, STATUS_SUCCESS);
                    }
                }
            }
        }
    }
    if (g_saiTxState[instance]->Callback != NULL)
    {
        if (SAI_DRV_TxGetFifoErrorFlag(base))
        {
            for (i = 0; i < sai_channel_count[instance]; i++)
            {
                if (SAI_DRV_IsTxChannelEnabled(base, i))
                {
                    if (SAI_DRV_IsTxFifoEmpty(base, i))
                    {
                        g_saiTxState[instance]->Callback(i, SAI_RUN_ERROR, STATUS_ERROR);
                    }
                }
                SAI_DRV_TxClearFlag (base, SAI_TSTS_FEF_SHIFT);
            }
        }
        if (SAI_DRV_TxGetWordStartFlag(base))
        {
            g_saiTxState[instance]->Callback(0U, SAI_FRAME_START, STATUS_SUCCESS);
            SAI_DRV_TxClearFlag (base, SAI_TSTS_WSF_SHIFT);
        }
        if (SAI_DRV_TxGetSyncErrorFlag(base))
        {
            g_saiTxState[instance]->Callback(0U, SAI_SYNC_ERROR, STATUS_ERROR);
            SAI_DRV_TxClearFlag (base, SAI_TSTS_SEF_SHIFT);
        }
    }
}

/*FUNCTION**********************************************************************
 *
 * Function Name : SAI_DRV_RxIRQ
 * Description   : Manage interrupt transfer using fifo request, execute
 *                 other user interrupt func (fifo error, word start,
 *                 sync error)
 *
 *END**************************************************************************/
 /* PRQA S 4700 ++*/
static void SAI_DRV_RxIRQ(uint32_t instance) /* PRQA S 4700 --*/
{
    SAI_Type* base = g_saiBase[instance];
    uint8_t i, j;
    uint32_t temp;
    bool finish;

    if (SAI_DRV_RxGetFifoReqFlag(base))
    {
        if ((g_saiRxState[instance]->XferType == SAI_INTERRUPT) && (g_saiRxState[instance]->status == STATUS_BUSY))
        {
            finish = false;
            if (g_saiRxState[instance]->mux == SAI_MUX_LINE)
            {
                for (i = 0U; i < sai_channel_count[instance]; i++)
                {
                    if (SAI_DRV_IsRxChannelEnabled(base, i))
                    {
                        if (g_saiRxState[instance]->ChnState[0].count < RX_FIFO_SIZE)
                        {
                            temp = g_saiRxState[instance]->ChnState[0].count;
                        }
                        else
                        {
                            temp = RX_FIFO_SIZE;
                        }
                        for (j = 0U; j < temp; j++)
                        {
                            if (g_saiRxState[instance]->ElementSize == 1U)
                            {
                                *g_saiRxState[instance]->ChnState[g_saiRxState[instance]->NextChn].data = (uint8_t) SAI_DRV_RxRead(base, i);
                            }
                            else if (g_saiRxState[instance]->ElementSize == 2U)
                            {
                                g_saiRxState[instance]->ChnState[g_saiRxState[instance]->NextChn].data[0] = (uint8_t) (SAI_DRV_RxRead(base, i) & 0xFFU);
                                g_saiRxState[instance]->ChnState[g_saiRxState[instance]->NextChn].data[1] = (uint8_t) ((SAI_DRV_RxRead(base, i) >> 8) & 0xFFU);
                            }
                            else if (g_saiRxState[instance]->ElementSize == 4U)
                            {
                                g_saiRxState[instance]->ChnState[g_saiRxState[instance]->NextChn].data[0] = (uint8_t) (SAI_DRV_RxRead(base, i) & 0xFFU);
                                g_saiRxState[instance]->ChnState[g_saiRxState[instance]->NextChn].data[1] = (uint8_t) ((SAI_DRV_RxRead(base, i) >> 8) & 0xFFU);
                                g_saiRxState[instance]->ChnState[g_saiRxState[instance]->NextChn].data[2] = (uint8_t) ((SAI_DRV_RxRead(base, i) >> 16) & 0xFFU);
                                g_saiRxState[instance]->ChnState[g_saiRxState[instance]->NextChn].data[3] = (uint8_t) ((SAI_DRV_RxRead(base, i) >> 24) & 0xFFU); /* PRQA S 2985 */
                            }
                            else
                            {
                                DEV_ASSERT(false);
                            }
                            /* Safe pointer advancement within known buffer bounds */
                            uint8_t nextChn = g_saiRxState[instance]->NextChn;
                            uint8_t *currentData = g_saiRxState[instance]->ChnState[nextChn].data;
                            uint8_t elementSize = g_saiRxState[instance]->ElementSize;
                            g_saiRxState[instance]->ChnState[nextChn].data = &currentData[elementSize];
                            g_saiRxState[instance]->NextChn++; /* alternate between data block */
                            if (g_saiRxState[instance]->NextChn == g_saiRxState[instance]->ChannelCount)
                            {
                                g_saiRxState[instance]->NextChn = 0U;
                            }
                        }
                        if (g_saiRxState[instance]->ChnState[0].count <= RX_FIFO_SIZE)
                        {
                            finish = true;
                            g_saiRxState[instance]->ChnState[0].count = 0;
                        }
                        else
                        {
                            g_saiRxState[instance]->ChnState[0].count -= RX_FIFO_SIZE;
                            if (g_saiRxState[instance]->ChnState[0].count < RX_FIFO_SIZE) /* set watermark below normal level */
                            {
                                SAI_DRV_RxSetWatermark(base, (uint8_t)(g_saiRxState[instance]->ChnState[0].count - 1UL));
                            }
                        }
                        break; /* only one channel is enabled in this mode */
                    }
                }
            }
            else if (g_saiRxState[instance]->mux == SAI_MUX_MEM)
            {
                if (g_saiRxState[instance]->ChnState[0].count < RX_FIFO_SIZE)
                {
                    temp = g_saiRxState[instance]->ChnState[0].count;
                }
                else
                {
                    temp = RX_FIFO_SIZE;
                }
                for (j = 0U; j < temp; j++)
                {
                    for (i = 0U; i < sai_channel_count[instance]; i++)
                    {
                        if (SAI_DRV_IsRxChannelEnabled(base, i))
                        {
                            if (g_saiRxState[instance]->ElementSize == 1U)
                            {
                                *g_saiRxState[instance]->ChnState[0U].data = (uint8_t) SAI_DRV_RxRead(base, i);
                            }
                            else if (g_saiRxState[instance]->ElementSize == 2U)
                            {
                                g_saiRxState[instance]->ChnState[0U].data[0] = (uint8_t) (SAI_DRV_RxRead(base, i) & 0xFFU);
                                g_saiRxState[instance]->ChnState[0U].data[1] = (uint8_t) ((SAI_DRV_RxRead(base, i) >> 8) & 0xFFU);
                            }
                            else if (g_saiRxState[instance]->ElementSize == 4U)
                            {
                                g_saiRxState[instance]->ChnState[0U].data[0] = (uint8_t) (SAI_DRV_RxRead(base, i) & 0xFFU);
                                g_saiRxState[instance]->ChnState[0U].data[1] = (uint8_t) ((SAI_DRV_RxRead(base, i) >> 8) & 0xFFU);
                                g_saiRxState[instance]->ChnState[0U].data[2] = (uint8_t) ((SAI_DRV_RxRead(base, i) >> 16) & 0xFFU);
                                g_saiRxState[instance]->ChnState[0U].data[3] = (uint8_t) ((SAI_DRV_RxRead(base, i) >> 24) & 0xFFU); /* PRQA S 2985 */
                            }
                            else
                            {
                                DEV_ASSERT(false);
                            }
                            uint8_t *currentData = g_saiRxState[instance]->ChnState[0U].data;
                            uint8_t elementSize = g_saiRxState[instance]->ElementSize;
                            g_saiRxState[instance]->ChnState[0U].data = &currentData[elementSize];
                        }
                    }
                }
                if (g_saiRxState[instance]->ChnState[0].count <= RX_FIFO_SIZE)
                {
                    finish = true;
                    g_saiRxState[instance]->ChnState[0].count = 0;
                }
                else
                {
                    g_saiRxState[instance]->ChnState[0].count -= RX_FIFO_SIZE;
                    if (g_saiRxState[instance]->ChnState[0].count < RX_FIFO_SIZE) /* set watermark below normal level */
                    {
                        SAI_DRV_RxSetWatermark(base, (uint8_t)(g_saiRxState[instance]->ChnState[0].count - 1UL));
                    }
                }
            }
            else /* mux disabled */
            {
                if (g_saiRxState[instance]->ChnState[0].count < RX_FIFO_SIZE)
                {
                    temp = g_saiRxState[instance]->ChnState[0].count;
                }
                else
                {
                    temp = RX_FIFO_SIZE;
                }
                for (i = 0U; i < sai_channel_count[instance]; i++)
                {
                    if (SAI_DRV_IsRxChannelEnabled(base, i))
                    {
                        for (j = 0U; j < temp; j++)
                        {
                            if (g_saiRxState[instance]->ElementSize == 1U)
                            {
                                *g_saiRxState[instance]->ChnState[i].data = (uint8_t) SAI_DRV_RxRead(base, i);
                            }
                            else if (g_saiRxState[instance]->ElementSize == 2U)
                            {
                                g_saiRxState[instance]->ChnState[i].data[0] = (uint8_t) (SAI_DRV_RxRead(base, i) & 0xFFU);
                                g_saiRxState[instance]->ChnState[i].data[1] = (uint8_t) ((SAI_DRV_RxRead(base, i) >> 8) & 0xFFU);
                            }
                            else if (g_saiRxState[instance]->ElementSize == 4U)
                            {
                                g_saiRxState[instance]->ChnState[i].data[0] = (uint8_t) (SAI_DRV_RxRead(base, i) & 0xFFU);
                                g_saiRxState[instance]->ChnState[i].data[1] = (uint8_t) ((SAI_DRV_RxRead(base, i) >> 8) & 0xFFU);
                                g_saiRxState[instance]->ChnState[i].data[2] = (uint8_t) ((SAI_DRV_RxRead(base, i) >> 16) & 0xFFU);
                                g_saiRxState[instance]->ChnState[i].data[3] = (uint8_t) ((SAI_DRV_RxRead(base, i) >> 24) & 0xFFU); /* PRQA S 2985 */
                            }
                            else
                            {
                                DEV_ASSERT(false);
                            }
                            /* Safe pointer advancement within known buffer bounds */
                            uint8_t *currentData = g_saiRxState[instance]->ChnState[i].data;
                            uint8_t elementSize = g_saiRxState[instance]->ElementSize;
                            g_saiRxState[instance]->ChnState[i].data = &currentData[elementSize];
                        }
                    }
                }
                if (g_saiRxState[instance]->ChnState[0].count <= RX_FIFO_SIZE)
                {
                    finish = true;
                    g_saiRxState[instance]->ChnState[0].count = 0;
                }
                else
                {
                    g_saiRxState[instance]->ChnState[0].count -= RX_FIFO_SIZE;
                    if (g_saiRxState[instance]->ChnState[0].count < RX_FIFO_SIZE) /* set watermark below normal level */
                    {
                        SAI_DRV_RxSetWatermark(base, (uint8_t)(g_saiRxState[instance]->ChnState[0].count - 1UL));
                    }
                }
            }
            if (finish)
            {
                g_saiRxState[instance]->status = STATUS_SUCCESS;
                SAI_DRV_RxDisableFifoReqInt(base);
                if (g_saiRxState[instance]->Blocking)
                {
                    (void)OSIF_SemaPost(&g_saiRxState[instance]->Sema);
                }
                else
                {
                    if (g_saiRxState[instance]->Callback != NULL)
                    {
                        g_saiRxState[instance]->Callback(0U, SAI_TRANSFER_COMPLETE, STATUS_SUCCESS);
                    }
                }
            }
        }
    }
    if (g_saiRxState[instance]->Callback != NULL)
    {
        if (SAI_DRV_RxGetFifoErrorFlag(base))
        {
            for (i = 0; i < sai_channel_count[instance]; i++)
            {
                if (SAI_DRV_IsRxChannelEnabled(base, i))
                {
                    if (SAI_DRV_IsRxFifoFull(base, i))
                    {
                        g_saiRxState[instance]->Callback(i, SAI_RUN_ERROR, STATUS_ERROR);
                    }
                }
                SAI_DRV_RxClearFlag (base, SAI_RSTS_FEF_SHIFT);
            }
        }
        if (SAI_DRV_RxGetWordStartFlag(base))
        {
            g_saiRxState[instance]->Callback(0U, SAI_FRAME_START, STATUS_SUCCESS);
            SAI_DRV_RxClearFlag (base, SAI_RSTS_WSF_SHIFT);
        }
        if (SAI_DRV_RxGetSyncErrorFlag(base))
        {
            g_saiRxState[instance]->Callback(0U, SAI_SYNC_ERROR, STATUS_ERROR);
            SAI_DRV_RxClearFlag (base, SAI_RSTS_SEF_SHIFT);
        }
    }
}

/*FUNCTION**********************************************************************
 *
 * Function Name : SAI_DRV_SendInt
 * Description   : Start sending data using interrupt, return immediately
 *
 *END**************************************************************************/
static void SAI_DRV_SendInt(uint32_t instance,
                            const uint8_t* const data[],
                            uint32_t count)
{
    SAI_Type* base = g_saiBase[instance];
    uint8_t i;
    uint8_t c = 0;

    g_saiTxState[instance]->status = STATUS_BUSY;
    if (g_saiTxState[instance]->mux == SAI_MUX_LINE)
    {
        for (i = 0; i < g_saiTxState[instance]->ChannelCount; i++)
        {
            DEV_ASSERT(data[i] != NULL);
            /* cast to non-const type to avoid compile error/warning */
            g_saiTxState[instance]->ChnState[i].data = (uint8_t*) data[i]; /* PRQA S 0311 */
        }
        g_saiTxState[instance]->ChnState[0].count = count * g_saiTxState[instance]->ChannelCount;
    }
    else if (g_saiTxState[instance]->mux == SAI_MUX_MEM)
    {
        DEV_ASSERT(data[0] != NULL);
        /* cast to non-const type to avoid compile error/warning */
        g_saiTxState[instance]->ChnState[0].data = (uint8_t*) data[0]; /* PRQA S 0311 */
        g_saiTxState[instance]->ChnState[0].count = count;
    }
    else
    {
        for (i = 0; i < sai_channel_count[instance]; i++)
        {
            if (SAI_DRV_IsTxChannelEnabled(base, i))
            {
                DEV_ASSERT(data[c] != NULL);
                /* cast to non-const type to avoid compile error/warning */
                g_saiTxState[instance]->ChnState[i].data = (uint8_t*) data[c]; /* PRQA S 0311 */
                c++;
            }
        }
        g_saiTxState[instance]->ChnState[0].count = count;
    }
    SAI_DRV_TxEnableFifoReqInt(base);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : SAI_DRV_SendDMA
 * Description   : Start sending data using dma, return immediately
 *
 *END**************************************************************************/
static void SAI_DRV_SendDma(uint32_t instance,
                            const uint8_t* const data[],
                            uint32_t count)
{
    SAI_Type* base = g_saiBase[instance];
    uint8_t i;
    uint8_t c;
    dma_transfer_size_t xferSize = DMA_TRANSFER_SIZE_1B;
    uint8_t numChan = 0;
    uint32_t temp;

    if (g_saiTxState[instance]->ElementSize == 1U)
    {
        xferSize = DMA_TRANSFER_SIZE_1B;
    }
    else if (g_saiTxState[instance]->ElementSize == 2U)
    {
        xferSize = DMA_TRANSFER_SIZE_2B;
    }
    else if (g_saiTxState[instance]->ElementSize == 4U)
    {
        xferSize = DMA_TRANSFER_SIZE_4B;
    }
    else
    {
        DEV_ASSERT(false);
    }
    g_saiTxState[instance]->status = STATUS_BUSY;
    if ((g_saiTxState[instance]->mux == SAI_MUX_LINE) || (g_saiTxState[instance]->mux == SAI_MUX_DISABLED))
    {
        c = 0;
        for (i = 0; i < sai_channel_count[instance]; i++)
        {
            if (SAI_DRV_IsTxChannelEnabled(base, i))
            {
                DEV_ASSERT(data[c] != NULL);
                g_saiTxState[instance]->ChnState[i].count = count;
                (void)DMA_DRV_ConfigMultiBlockTransfer(g_saiTxState[instance]->DmaChannel[c], DMA_TRANSFER_MEM2PERIPH,
                                                        (uint32_t)data[c], (uint32_t)(&(base->TDATA[i])), xferSize,
                                                        g_saiTxState[instance]->ElementSize, count, true);

                /* Call driver function to end the transmission when the DMA transfer is done */
                (void)DMA_DRV_InstallCallback(g_saiTxState[instance]->DmaChannel[c],
                                               (dma_callback_t)(SAI_DRV_CompleteSendDataUsingDma),
                                               (void*)(instance | ((uint32_t)i << 16U) | ((uint32_t)c << 8U))); /* PRQA S 0326 */
                /* Start the DMA channel */
                (void)DMA_DRV_StartChannel(g_saiTxState[instance]->DmaChannel[c]);
                c++;
            }
        }
    }
    else if (g_saiTxState[instance]->mux == SAI_MUX_MEM)
    {
        DEV_ASSERT(data[0] != NULL);
        for (i = 0; i < sai_channel_count[instance]; i++)
        {
            if (SAI_DRV_IsTxChannelEnabled(base, i))
            {
                numChan++;
            }
        }
        temp = count * numChan;
        g_saiTxState[instance]->ChnState[0].count = count;

        (void)DMA_DRV_ConfigMultiBlockTransfer(g_saiTxState[instance]->DmaChannel[0], DMA_TRANSFER_MEM2PERIPH,
                                                (uint32_t)data[0], (uint32_t)(&(base->TDATA[0])), xferSize,
                                                g_saiTxState[instance]->ElementSize, temp, true);

        /* Call driver function to end the transmission when the DMA transfer is done */
        (void)DMA_DRV_InstallCallback(g_saiTxState[instance]->DmaChannel[0],
                                       (dma_callback_t)(SAI_DRV_CompleteSendDataUsingDma),
                                       (void*)(instance)); /* PRQA S 0326 */
        /* Start the DMA channel */
        (void)DMA_DRV_StartChannel(g_saiTxState[instance]->DmaChannel[0]);
    }
    else
    {
        /* do nothing */
    }
    /* Enable tx DMA requests for the current instance */
    SAI_DRV_TxEnableFifoReqDma(base, g_saiTxState[instance]->DMAEnable);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : SAI_DRV_Send
 * Description   : Send block of data, return immediately
 * Implements    : SAI_DRV_Send_Activity
 *
 *END**************************************************************************/
status_t SAI_DRV_Send(uint32_t instance,
                  const uint8_t* const data[],
                  uint32_t count)
{
    DEV_ASSERT(instance < SAI_INSTANCE_COUNT);
    DEV_ASSERT(g_saiTxState[instance]->status != STATUS_BUSY);

    status_t retVal = STATUS_SUCCESS;
    SAI_Type* base = g_saiBase[instance];

    if(g_saiTxState[instance]->status != STATUS_BUSY)
    {   
        /* Reset the internal transmitter logic */
        if(g_saiTxState[instance]->status == STATUS_SAI_ABORTED)
        {
            SAI_DRV_TxReset(base);
        }

        if (g_saiTxState[instance]->XferType == SAI_DMA)
        {
            SAI_DRV_SendDma(instance, data, count);
        }
        else if (g_saiTxState[instance]->XferType == SAI_INTERRUPT)
        {
            SAI_DRV_SendInt(instance, data, count);
        }
        else
        {
            DEV_ASSERT(false);
        }
        retVal = STATUS_SUCCESS;
    }
    else
    {
        retVal = STATUS_BUSY;
    }

    return retVal;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : SAI_DRV_ReceiveInt
 * Description   : Start receiving data using interrupt, return immediately
 *
 *END**************************************************************************/
static void SAI_DRV_ReceiveInt(uint32_t instance,
                              uint8_t* data[], /* PRQA S 3677 */
                              uint32_t count)
{
    SAI_Type* base = g_saiBase[instance];
    uint8_t i;
    uint8_t c = 0;

    g_saiRxState[instance]->status = STATUS_BUSY;
    if (g_saiRxState[instance]->mux == SAI_MUX_LINE)
    {
        for (i = 0; i < g_saiRxState[instance]->ChannelCount; i++)
        {
            DEV_ASSERT(data[i] != NULL);
            g_saiRxState[instance]->ChnState[i].data = data[i];
        }
        g_saiRxState[instance]->ChnState[0].count = g_saiRxState[instance]->ChannelCount * count;
        if (g_saiRxState[instance]->ChnState[0].count < RX_FIFO_SIZE)
        {
            SAI_DRV_RxSetWatermark(base, (uint8_t)(g_saiRxState[instance]->ChnState[0].count - 1UL));
        }
        else
        {
            SAI_DRV_RxSetWatermark(base, RX_WATERMARK);
        }
    }
    else if (g_saiRxState[instance]->mux == SAI_MUX_MEM)
    {
        DEV_ASSERT(data[0] != NULL);
        g_saiRxState[instance]->ChnState[0].data = data[0];
        g_saiRxState[instance]->ChnState[0].count = count;
        if (count < RX_FIFO_SIZE)
        {
            SAI_DRV_RxSetWatermark(base, (uint8_t)(g_saiRxState[instance]->ChnState[0].count - 1UL));
        }
        else
        {
            SAI_DRV_RxSetWatermark(base, RX_WATERMARK);
        }
    }
    else
    {
        for (i = 0; i < sai_channel_count[instance]; i++)
        {
            if (SAI_DRV_IsRxChannelEnabled(base, i))
            {
                DEV_ASSERT(data[c] != NULL);
                g_saiRxState[instance]->ChnState[i].data = data[c];
                c++;
            }
        }
        g_saiRxState[instance]->ChnState[0].count = count;
        if (count < RX_FIFO_SIZE)
        {
            SAI_DRV_RxSetWatermark(base, (uint8_t) (count - 1UL));
        }
        else
        {
            SAI_DRV_RxSetWatermark(base, RX_WATERMARK);
        }
    }
    SAI_DRV_RxEnableFifoReqInt(base);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : SAI_DRV_ReceiveDMA
 * Description   : Start receiving data using dma, return immediately
 *
 *END**************************************************************************/
static void SAI_DRV_ReceiveDma(uint32_t instance,
                               uint8_t* data[], /* PRQA S 3677 */
                               uint32_t count)
{
    SAI_Type* base = g_saiBase[instance];
    uint8_t i;
    uint8_t c;
    dma_transfer_size_t xferSize = DMA_TRANSFER_SIZE_1B;
    uint8_t numChan = 0;
    uint32_t temp;

    if (g_saiRxState[instance]->ElementSize == 1U)
    {
        xferSize = DMA_TRANSFER_SIZE_1B;
    }
    else if (g_saiRxState[instance]->ElementSize == 2U)
    {
        xferSize = DMA_TRANSFER_SIZE_2B;
    }
    else if (g_saiRxState[instance]->ElementSize == 4U)
    {
        xferSize = DMA_TRANSFER_SIZE_4B;
    }
    else
    {
        DEV_ASSERT(false);
    }
    g_saiRxState[instance]->status = STATUS_BUSY;
    if ((g_saiRxState[instance]->mux == SAI_MUX_LINE) || (g_saiRxState[instance]->mux == SAI_MUX_DISABLED))
    {
        c = 0;
        for (i = 0; i < sai_channel_count[instance]; i++)
        {
            if (SAI_DRV_IsRxChannelEnabled(base, i))
            {
                DEV_ASSERT(data[c] != NULL);
                g_saiRxState[instance]->ChnState[i].count = count;
                (void)DMA_DRV_ConfigMultiBlockTransfer(g_saiRxState[instance]->DmaChannel[c], DMA_TRANSFER_PERIPH2MEM,
                                                        (uint32_t)(&(base->RDATA[i])), (uint32_t)data[c], xferSize,
                                                        g_saiRxState[instance]->ElementSize, count, true);

                /* Call driver function to end the transmission when the DMA transfer is done */
                (void)DMA_DRV_InstallCallback(g_saiRxState[instance]->DmaChannel[c],
                                               (dma_callback_t)(SAI_DRV_CompleteReceiveDataUsingDma),
                                               (void*)(instance | ((uint32_t)i << 16U) | ((uint32_t)c << 8U))); /* PRQA S 0326 */
                /* Start the DMA channel */
                (void)DMA_DRV_StartChannel(g_saiRxState[instance]->DmaChannel[c]);
                c++;
            }
        }
    }
    else if (g_saiRxState[instance]->mux == SAI_MUX_MEM)
    {
        DEV_ASSERT(data[0] != NULL);
        for (i = 0; i < sai_channel_count[instance]; i++)
        {
            if (SAI_DRV_IsRxChannelEnabled(base, i))
            {
                numChan++;
            }
        }
        temp = count * numChan;
        g_saiRxState[instance]->ChnState[0].count = count;

        (void)DMA_DRV_ConfigMultiBlockTransfer(g_saiRxState[instance]->DmaChannel[0], DMA_TRANSFER_PERIPH2MEM,
                                                (uint32_t)(&(base->RDATA[0])), (uint32_t)data[0], xferSize,
                                                g_saiRxState[instance]->ElementSize, temp, true);

        /* Call driver function to end the transmission when the DMA transfer is done */
        (void)DMA_DRV_InstallCallback(g_saiRxState[instance]->DmaChannel[0],
                                       (dma_callback_t)(SAI_DRV_CompleteReceiveDataUsingDma),
                                       (void*)(instance)); /* PRQA S 0326 */
        /* Start the DMA channel */
        (void)DMA_DRV_StartChannel(g_saiRxState[instance]->DmaChannel[0]);
    }
    else
    {
        DEV_ASSERT(false);
    }
    /* Enable rx DMA requests for the current instance */
    SAI_DRV_RxEnableFifoReqDma(base, g_saiRxState[instance]->DMAEnable);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : SAI_DRV_Receive
 * Description   : Receive block of data, return immediately
 * Implements    : SAI_DRV_Receive_Activity
 *
 *END**************************************************************************/
status_t SAI_DRV_Receive(uint32_t instance,
                     uint8_t* data[],
                     uint32_t count)
{
    DEV_ASSERT(instance < SAI_INSTANCE_COUNT);
    DEV_ASSERT(g_saiRxState[instance]->status != STATUS_BUSY);

    status_t retVal = STATUS_SUCCESS;
    SAI_Type* base = g_saiBase[instance];

    if(g_saiRxState[instance]->status != STATUS_BUSY)
    {
        /* Reset the internal receiver logic */
        if(g_saiRxState[instance]->status == STATUS_SAI_ABORTED)
        {
            SAI_DRV_RxReset(base);
        }

        if (g_saiRxState[instance]->XferType == SAI_DMA)
        {
            SAI_DRV_ReceiveDma(instance, data, count);
        }
        else if (g_saiRxState[instance]->XferType == SAI_INTERRUPT)
        {
            SAI_DRV_ReceiveInt(instance, data, count);
        }
        else
        {
            DEV_ASSERT(false);
        }
        }
    else
    {
        retVal = STATUS_BUSY;        
    }
    return retVal;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : SAI_DRV_TxDeinit
 * Description   : DeInit tx core
 * Implements    : SAI_DRV_TxDeinit_Activity
 *
 *END**************************************************************************/
void SAI_DRV_TxDeinit(uint32_t instance)
{
    DEV_ASSERT(instance < SAI_INSTANCE_COUNT);
    
    /* ipc software reset */
    SAI_DRV_APBReset(instance);

    if (g_saiTxState[instance]->XferType == SAI_INTERRUPT)
    {
        /* Disable interrupt. */
        INT_SYS_DisableIRQ(SAIIrqId[instance]);
    }
    (void)OSIF_SemaDestroy(&g_saiTxState[instance]->Sema);
    SAI_DRV_TxResetVar(instance);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : SAI_DRV_RxDeinit
 * Description   : DeInit rx core
 * Implements    : SAI_DRV_RxDeinit_Activity
 *
 *END**************************************************************************/
void SAI_DRV_RxDeinit(uint32_t instance)
{
    DEV_ASSERT(instance < SAI_INSTANCE_COUNT);

    /* ipc software reset */
    SAI_DRV_APBReset(instance);

    if (g_saiRxState[instance]->XferType == SAI_INTERRUPT)
    {
        /* Disable interrupt. */
        INT_SYS_DisableIRQ(SAIIrqId[instance]);
    }
    (void)OSIF_SemaDestroy(&g_saiRxState[instance]->Sema);
    SAI_DRV_RxResetVar(instance);
}

/*FUNCTION**********************************************************************
*
* Function Name : SAI_DRV_TxSetNextMaskWords
* Description   : Set next frame masked word index
* Implements    : SAI_DRV_TxSetNextMaskWords_Activity
*
*END**************************************************************************/
void SAI_DRV_TxSetNextMaskWords(uint32_t instance, uint16_t Words)
{
    DEV_ASSERT(instance < SAI_INSTANCE_COUNT);

    SAI_Type* base = g_saiBase[instance];
    base->TMR = Words;
}

/*FUNCTION**********************************************************************
*
* Function Name : SAI_DRV_RxSetNextMaskWords
* Description   : Set next frame masked word index
* Implements : SAI_DRV_RxSetNextMaskWords_Activity
*
*END**************************************************************************/
void SAI_DRV_RxSetNextMaskWords(uint32_t instance, uint16_t Words)
{
    DEV_ASSERT(instance < SAI_INSTANCE_COUNT);

    SAI_Type* base = g_saiBase[instance];
    base->RMR = Words;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : SAI_DRV_AbortSending
 * Description   : Abort ongoing sending (dma or interrupt)
 * Implements    : SAI_DRV_AbortSending_Activity
 *
 *END**************************************************************************/
void SAI_DRV_AbortSending(uint32_t instance)
{
    DEV_ASSERT(instance < SAI_INSTANCE_COUNT);

    SAI_Type* base = g_saiBase[instance];
    uint8_t c = 0;
    uint8_t i;

    if (g_saiTxState[instance]->status == STATUS_BUSY)
    {
        g_saiTxState[instance]->status = STATUS_SAI_ABORTED;
        if (g_saiTxState[instance]->XferType == SAI_DMA)
        {
            g_saiTxState[instance]->ChnState[0].count = DMA_DRV_GetRemainingTriggerIterationsCount(g_saiTxState[instance]->DmaChannel[0]);
            /* Disable tx DMA requests for the current instance */
            SAI_DRV_TxDisableFifoReqDma(base);
            /* stop all dma channel*/
            if ((g_saiTxState[instance]->mux == SAI_MUX_DISABLED) || (g_saiTxState[instance]->mux == SAI_MUX_LINE))
            {
                for (i = 0; i < sai_channel_count[instance]; i++)
                {
                    if (SAI_DRV_IsTxChannelEnabled(base, i))
                    {
                        (void)DMA_DRV_StopChannel(g_saiTxState[instance]->DmaChannel[c]);
                        c++;
                    }
                }
            }
            else
            {
                (void)DMA_DRV_StopChannel(g_saiTxState[instance]->DmaChannel[0]);
            }
        }
        else
        {
            SAI_DRV_TxDisableFifoReqInt(base);
        }
        SAI_DRV_TxResetFifo(base);
        if (g_saiTxState[instance]->Blocking)
        {
            (void)OSIF_SemaPost(&g_saiTxState[instance]->Sema);
        }
    }
}

/*FUNCTION**********************************************************************
 *
 * Function Name : SAI_DRV_AbortReceiving
 * Description   : Abort ongoing receiving (dma or interrupt)
 * Implements    : SAI_DRV_AbortReceiving_Activity
 *
 *END**************************************************************************/
void SAI_DRV_AbortReceiving(uint32_t instance)
{
    DEV_ASSERT(instance < SAI_INSTANCE_COUNT);

    SAI_Type* base = g_saiBase[instance];
    uint8_t c = 0;
    uint8_t i;

    if (g_saiRxState[instance]->status == STATUS_BUSY)
    {
        g_saiRxState[instance]->status = STATUS_SAI_ABORTED;
        if (g_saiRxState[instance]->XferType == SAI_DMA)
        {
            g_saiRxState[instance]->ChnState[0].count = DMA_DRV_GetRemainingTriggerIterationsCount(g_saiRxState[instance]->DmaChannel[0]);
            /* Disable Rx DMA requests for the current instance */
            SAI_DRV_RxDisableFifoReqDma(base);
            /* stop all dma channel*/
            if ((g_saiRxState[instance]->mux == SAI_MUX_DISABLED) || (g_saiRxState[instance]->mux == SAI_MUX_LINE))
            {
                for (i = 0; i < sai_channel_count[instance]; i++)
                {
                    if (SAI_DRV_IsRxChannelEnabled(base, i))
                    {
                        (void)DMA_DRV_StopChannel(g_saiRxState[instance]->DmaChannel[c]);
                        c++;
                    }
                }
            }
            else
            {
                (void)DMA_DRV_StopChannel(g_saiRxState[instance]->DmaChannel[0]);
            }
        }
        else
        {
            SAI_DRV_RxDisableFifoReqInt(base);
        }
        SAI_DRV_RxResetFifo(base);
        if (g_saiRxState[instance]->Blocking)
        {
            (void)OSIF_SemaPost(&g_saiRxState[instance]->Sema);
        }
    }
}

/*****************************SENDING FUNCTIONS************************************************/
/*FUNCTION**********************************************************************
 *
 * Function Name : SAI_DRV_SendBlocking
 * Description   : Send block of data, return when finish sending
 * Implements    : SAI_DRV_SendBlocking_Activity
 *
 *END**************************************************************************/
status_t SAI_DRV_SendBlocking(uint32_t instance,
                            const uint8_t* const data[],
                            uint32_t count,
                            uint32_t timeout)
{
    DEV_ASSERT(instance < SAI_INSTANCE_COUNT);
    DEV_ASSERT(g_saiTxState[instance]->status != STATUS_BUSY);

    status_t res;
    status_t osifError;

    g_saiTxState[instance]->Blocking = true;
    /* Reset signal before transfer */
    (void)OSIF_SemaWait(&g_saiTxState[instance]->Sema, 0);
    (void)SAI_DRV_Send (instance, data, count);
    osifError = OSIF_SemaWait(&g_saiTxState[instance]->Sema, timeout);
    g_saiTxState[instance]->Blocking = false;
    if (osifError == STATUS_TIMEOUT)
    {
        /* abort current transfer */
        SAI_DRV_AbortSending (instance);
        res = STATUS_TIMEOUT;
    }
    else
    {
        /* not time out */
        res = g_saiTxState[instance]->status;
    }

    return res;
}

/*****************************RECEIVING FUNCTIONS*********************************/
/*FUNCTION**********************************************************************
 *
 * Function Name : SAI_DRV_ReceiveBlocking
 * Description   : Receive block of data, return when finish Receiving
 * Implements    : SAI_DRV_ReceiveBlocking_Activity
 *
 *END**************************************************************************/
status_t SAI_DRV_ReceiveBlocking(uint32_t instance,
                                 uint8_t* data[],
                                 uint32_t count,
                                 uint32_t timeout)
{
    DEV_ASSERT(instance < SAI_INSTANCE_COUNT);
    DEV_ASSERT(g_saiRxState[instance]->status != STATUS_BUSY);

    status_t res;
    status_t osifError;

    g_saiRxState[instance]->Blocking = true;
    /* Reset signal before transfer */
    (void)OSIF_SemaWait(&g_saiTxState[instance]->Sema, 0);
    (void)SAI_DRV_Receive (instance, data, count);
    osifError = OSIF_SemaWait(&g_saiRxState[instance]->Sema, timeout);
    g_saiRxState[instance]->Blocking = false;
    if (osifError == STATUS_TIMEOUT)
    {
        /* abort current transfer */
        SAI_DRV_AbortReceiving (instance);
        res = STATUS_TIMEOUT;
    }
    else
    {
        /* not time out */
        res = g_saiRxState[instance]->status;
    }

    return res;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : SAI_DRV_GetSendingStatus
 * Description   : Get sending status (dma or interrupt)
 * Implements    : SAI_DRV_GetSendingStatus_Activity
 *
 *END**************************************************************************/
status_t SAI_DRV_GetSendingStatus(uint32_t instance,
                                  uint32_t *countRemain)
{
    DEV_ASSERT(instance < SAI_INSTANCE_COUNT);

    status_t ret = STATUS_ERROR;
    status_t CurStatus = g_saiTxState[instance]->status;

    if ((CurStatus == STATUS_UNSUPPORTED) || (CurStatus == STATUS_SUCCESS))
    {
        if (countRemain != NULL)
        {
            *countRemain = 0;
        }
        ret = STATUS_SUCCESS;
    }
    else if (CurStatus == STATUS_ERROR)
    {
        if (countRemain != NULL)
        {
            *countRemain = 0;
        }
        ret = STATUS_ERROR;
    }
    else if (CurStatus == STATUS_BUSY)
    {
        if (g_saiTxState[instance]->XferType == SAI_DMA)
        {
            if (countRemain != NULL)
            {
                *countRemain = DMA_DRV_GetRemainingTriggerIterationsCount(g_saiTxState[instance]->DmaChannel[0]);
            }
        }
        else
        {
            if (countRemain != NULL)
            {
                *countRemain = g_saiTxState[instance]->ChnState[0].count;
            }
        }
        ret = STATUS_BUSY;
    }
    else if (CurStatus == STATUS_SAI_ABORTED)
    {
        if (countRemain != NULL)
        {
            *countRemain = g_saiTxState[instance]->ChnState[0].count;
        }
        ret = STATUS_SAI_ABORTED;
    }
    else
    {
        /* undefined value */
        DEV_ASSERT(false);
    }
    return ret;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : SAI_DRV_GetReceivingStatus
 * Description   : Get receiving status (dma or interrupt)
 * Implements    : SAI_DRV_GetReceivingStatus_Activity
 *
 *END**************************************************************************/
status_t SAI_DRV_GetReceivingStatus(uint32_t instance,
                                    uint32_t *countRemain)
{
    DEV_ASSERT(instance < SAI_INSTANCE_COUNT);

    status_t ret = STATUS_ERROR;
    /* temp variable to avoid status change while checking */
    status_t CurStatus = g_saiRxState[instance]->status;

    if ((CurStatus == STATUS_UNSUPPORTED) || (CurStatus == STATUS_SUCCESS))
    {
        if (countRemain != NULL)
        {
            *countRemain = 0;
        }
        ret = STATUS_SUCCESS;
    }
    else if (CurStatus == STATUS_ERROR)
    {
        if (countRemain != NULL)
        {
            *countRemain = 0;
        }
        ret = STATUS_ERROR;
    }
    else if (CurStatus == STATUS_BUSY)
    {
        if (g_saiRxState[instance]->XferType == SAI_DMA)
        {
            if (countRemain != NULL)
            {
                *countRemain = DMA_DRV_GetRemainingTriggerIterationsCount(g_saiRxState[instance]->DmaChannel[0]);
            }
        }
        else
        {
            if (countRemain != NULL)
            {
                *countRemain = g_saiRxState[instance]->ChnState[0].count;
            }
        }
        ret = STATUS_BUSY;
    }
    else if (CurStatus == STATUS_SAI_ABORTED)
    {
        if (countRemain != NULL)
        {
            *countRemain = g_saiRxState[instance]->ChnState[0].count;
        }
        ret = STATUS_SAI_ABORTED;
    }
    else
    {
        /* undefined value */
        DEV_ASSERT(false);
    }
    return ret;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : SAI_DRV_GetDefaultConfig
 * Description   : Init config structure for I2S interface, interrupt,
 *                 internal generated bit clock 1.4112 MHz, 16 bit word,
 *                 2 channel 1 data line (data line 0), msb first
 * Implements    : SAI_DRV_GetDefaultConfig_Activity
 *
 *END**************************************************************************/
void SAI_DRV_GetDefaultConfig(sai_user_config_t* uc)
{
    uc->BitClkInternal = true;
    uc->MasterClkSrc = SAI_BUS_CLK;
    uc->BitClkNegPolar = false;
    uc->BitClkFreq = 1411200U;
    uc->ChannelCount = 2U;              /* 2 buffer, one for each channel */
    uc->ChannelEnable = SAI_CHANNEL_0;  /* select data line 0 */
    uc->ElementSize = 2U;               /* 2 byte to transfer */
    uc->FirstBitIndex = 15U;            /* first bit to transfer is 15 because of msb first */
    uc->FrameSize = 2U;                 /* 2 word per frame */
    uc->FrameStartReport = false;
    uc->MaskMode = SAI_MASK_TRISTATE;
    uc->MsbFirst = true;
    uc->MuxMode = SAI_MUX_LINE;         /* 2 data buffer is muxed in to one data line */
    uc->RunErrorReport = false;
    uc->SyncEarly = false;
    uc->SyncErrorReport = false;
    uc->SyncMode = SAI_ASYNC;
    uc->SyncNegPolar = false;
    uc->SyncInternal = true;
    uc->SyncWidth = 16U;                /* sync width is first word */
    uc->TransferType = SAI_INTERRUPT;
    uc->Word0Width = 16U;
    uc->WordNWidth = 16U;
    uc->callback = NULL;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : SAI_DRV_APBReset
 * Description   : Reset SAI by APB.
 * Implements    : SAI_DRV_APBReset_Activity
 *
 *END**************************************************************************/
static inline void SAI_DRV_APBReset(uint32_t instance)
{
    IPC->CTRL[g_saiIpcIndex[instance]] |=  IPC_CTRL_SWREN_MASK;
    IPC->CTRL[g_saiIpcIndex[instance]] &= ~IPC_CTRL_SWREN_MASK;
}

/*******************************************************************************
 * EOF
 ******************************************************************************/
