/******************************************************************************
 * $Revision: 423 $
 * $Date:: 2017-04-07 16:03:30 +0900#$
 *****************************************************************************/
/* __DISCLAIMER_START__                                                      */
/******************************************************************************
* (c)2017, Cypress Semiconductor Corporation
* or a subsidiary of Cypress Semiconductor Corporation. All rights
* reserved.
*
* This software, including source code, documentation and related
* materials ( "Software" ), is owned by Cypress Semiconductor
* Corporation or one of its subsidiaries ( "Cypress" ) and is protected by
* and subject to worldwide patent protection (United States and foreign),
* United States copyright laws and international treaty provisions.
* Therefore, you may use this Software only as provided in the license
* agreement accompanying the software package from which you
* obtained this Software ( "EULA" ).
*
* If no EULA applies, Cypress hereby grants you a personal, nonexclusive,
* non-transferable license to copy, modify, and compile the
* Software source code solely for use in connection with Cypress' s
* integrated circuit products. Any reproduction, modification, translation,
* compilation, or representation of this Software except as specified
* above is prohibited without the express written permission of Cypress.
*
* Disclaimer: THIS SOFTWARE IS PROVIDED AS-IS, WITH NO
* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING,
* BUT NOT LIMITED TO, NONINFRINGEMENT, IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. Cypress reserves the right to make
* changes to the Software without notice. Cypress does not assume any
* liability arising out of the application or use of the Software or any
* product or circuit described in the Software. Cypress does not
* authorize its products for use in any products where a malfunction or
* failure of the Cypress product may reasonably be expected to result in
* significant property damage, injury or death ( "High Risk Product" ). By
* including Cypress' s product in a High Risk Product, the manufacturer
* of such system or application assumes all risk of such use and in doing
* so agrees to indemnify Cypress against all liability.
******************************************************************************/
/* __DISCLAIMER_END__                                                        */
/*****************************************************************************
 ** \file mfs_csio.c
 **
 ** A detailed description is available at
 ** @link CsioGroup CSIO Module description @endlink
 ** 
 **
 ** History:
 ** - 2014-12-18  0.01  HSh  First version
 *****************************************************************************/

/*****************************************************************************/
/* Include files                                                             */
/*****************************************************************************/
#include "pdl.h"
#include "interrupts.h"

#if defined(PDL_PERIPHERAL_CSIO_ACTIVE)

/**
 *****************************************************************************
 ** \addtogroup CsioGroup
 *****************************************************************************/
/** @{ */

/*****************************************************************************/
/* Local type definitions ('typedef')                                        */
/*****************************************************************************/
#define CSIO_FIFO_MAX_VAL               32

/**
 *****************************************************************************
 ** \brief CSIO module internal data,
 **        storing internal information for each enabled CSIO instance.
 *****************************************************************************/

typedef struct stc_csio_intern_data
{
    stc_csio_irq_cb_t     pstcIrqCb;                  /*!< call back function addresses   */      
    stc_mfs_csio_status_t stcStatus;                  /*!< status of different errors     */
} stc_csio_intern_data_t;

/*****************************************************************************/
/* Local variable definitions ('static')                                     */
/*****************************************************************************/

static void MfsCsioIrqHandlerTx(volatile stc_cpg_mfsn_csio_t * pstcCsio, stc_csio_intern_data_t * pstcCsioIntrnData);
static void MfsCsioIrqHandlerRx(volatile stc_cpg_mfsn_csio_t * pstcCsio, stc_csio_intern_data_t * pstcCsioIntrnData);
static void MfsCsioIrqHandlerStatus(volatile stc_cpg_mfsn_csio_t * pstcCsio, stc_csio_intern_data_t * pstcCsioIntrnData);
en_result_t Mfs_Csio_SetCsTransferByteCount(volatile stc_cpg_mfsn_csio_t* pstcCsio, en_cs_pin_sel_t enCsPin, uint8_t u8ByteCnt);

/*****************************************************************************/
/* Function implementation - global ('extern') and local ('static')          */
/*****************************************************************************/

#include "mfs_csio_generated.c" 

/**
 *****************************************************************************
 ** \brief Csio Transmission interrupt service routine.
 **
 ** \param [in] pstcCsio            Pointer to CSIO instance   
 ** \param [in] pstcCsioIntrnData   Pointer to internal data structure
 ** This function is called on each Receive Interrupt set by the Csio. It stores
 ** the data from the FIFO into the internal Ring Buffer and triggers a callback
 ** function if the specific Fill Level of the internal Ring Buffer is reached.
 *****************************************************************************/
static void MfsCsioIrqHandlerTx(volatile stc_cpg_mfsn_csio_t * pstcCsio, stc_csio_intern_data_t * pstcCsioIntrnData)
{ 
    if ((NULL != pstcCsio) && (NULL != pstcCsioIntrnData))
    {
        if(pstcCsio->unSSR.stcField.u1TDRE == 1)
        {
            if (NULL != pstcCsioIntrnData->pstcIrqCb.pfnTxIrqCb)
            {
                pstcCsioIntrnData->pstcIrqCb.pfnTxIrqCb();
            }
        }
        
        if(pstcCsio->unSSR.stcField.u1TBI == 1)
        {
            if (NULL != pstcCsioIntrnData->pstcIrqCb.pfnTxIdleCb)
            {
                pstcCsioIntrnData->pstcIrqCb.pfnTxIdleCb();
            }
        }
        
        if(pstcCsio->unFCR1.stcField.u1FDRQ == 1)
        {
            if (NULL != pstcCsioIntrnData->pstcIrqCb.pfnTxFifoIrqCb)
            {
                pstcCsioIntrnData->pstcIrqCb.pfnTxFifoIrqCb();
            }
            
            pstcCsio->unFCR1.stcField.u1FDRQ = 0;
        }
        
        if(pstcCsio->unSACSR.stcField.u1CSE == 1)
        {
            if (NULL != pstcCsioIntrnData->pstcIrqCb.pfnCsErrIrqCb)
            {
                pstcCsioIntrnData->pstcIrqCb.pfnCsErrIrqCb();
            }
            
            pstcCsio->unSACSR.stcField.u1CSE = 0;
        }         
    }    
} // MfsCsioIrqHandlerTx

/**
 *****************************************************************************
 ** \brief Csio receive interrupt service routine.
 **
 ** \param [in] pstcCsio            Pointer to CSIO instance   
 ** \param [in] pstcCsioIntrnData   Pointer to internal data structure
 **
 ** This function is called on each Transmit Interrupt set by the Csio. This highly
 ** depends on the Configuration of the INT Sources. Interrupts might occur on
 ** TX FIFO empty, last bit has been shifted out, ...
 ** The data from the internal Ring Buffer is put into the FIFO until there's
 ** no more space left or all data has been transferred to the FIFO
 *****************************************************************************/
static void MfsCsioIrqHandlerRx(volatile stc_cpg_mfsn_csio_t * pstcCsio, stc_csio_intern_data_t * pstcCsioIntrnData)
{
    if ((NULL != pstcCsio) && (NULL != pstcCsioIntrnData))
    {
        if (NULL != pstcCsioIntrnData->pstcIrqCb.pfnRxIrqCb)
        {
            pstcCsioIntrnData->pstcIrqCb.pfnRxIrqCb();
        }
    }
} // MfsCsioIrqHandlerRx

/**
 ******************************************************************************
 ** \brief CSIO status interrupt service routine.
 ** 
 ** \param pstcCsio Pointer to CSIO instance   
 ** \param pstcMfsInternData Pointer to MFS internal data structure       
 ** 
 ** This function is called on transfer Interrupt set by the MFS. 
 **
 ******************************************************************************/
void MfsCsioIrqHandlerStatus( volatile stc_cpg_mfsn_csio_t*   pstcCsio, 
                              stc_csio_intern_data_t* pstcCsioIntrnData)
{
    if ((NULL != pstcCsio) && (NULL != pstcCsioIntrnData))
    {
        if(pstcCsio->unSACSR.stcField.u1TINT == 1)
        {
            if (NULL != pstcCsioIntrnData->pstcIrqCb.pfnSerialTimerIrqCb)
            {
                pstcCsioIntrnData->pstcIrqCb.pfnSerialTimerIrqCb();
            }
            
            pstcCsio->unSACSR.stcField.u1TINT = 0;
        }
    }
} // MfsCsioIrqHandlerStatus


/**
 ******************************************************************************
 ** \brief Enable CSIO interrupts
 **
 ** \param [in] pstcCsio   Pointer to CSIO instance   
 ** \param [in] enIrqSel   CSIO interrupt selection
 ** \arg CsioTxIrq         TX interrupt of CSIO
 ** \arg CsioRxIrq         RX interrupt of CSIO
 ** \arg CsioTxIdleIrq     TX idle interrupt of CSIO
 ** \arg CsioTxFifoIrq     TX FIFO interrupt of CSIO
 ** \arg CsioCsErrIrq      Chip selection error interrupt of CSIO
 ** \arg CsioSerialTimerIrq  Seriel timer interrupt of CSIO
 ** 
 ** \retval Ok                    Interrupts has been enabled
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **                               - pstcCsio == NULL
 **                               - enIrqSel == NULL           
 ** 
 ******************************************************************************/
en_result_t Mfs_Csio_EnableIrq(volatile stc_cpg_mfsn_csio_t* pstcCsio, 
                               en_csio_irq_sel_t enIrqSel)
{
    stc_csio_intern_data_t* pstcCsioInternData;

    /* Check for valid pointer and get pointer to internal data struct ... */
    pstcCsioInternData = CsioGetInternDataPtr(pstcCsio);
  
    if (NULL == pstcCsioInternData)
    {
        return (ErrorInvalidParameter);
    }
    
    switch (enIrqSel)
    {
        case CsioTxIrq:
            pstcCsio->unSCR.stcField.u1TIE = 1;
            break;
        case CsioRxIrq:
            pstcCsio->unSCR.stcField.u1RIE = 1;
            break;
        case CsioTxIdleIrq:
            pstcCsio->unSCR.stcField.u1TBIE = 1;
            break;
        case CsioTxFifoIrq:
            pstcCsio->unFCR1.stcField.u1FTIE = 1;
            break;
        case CsioCsErrIrq:
            pstcCsio->unSACSR.stcField.u1CSEIE = 1;
            break;
        case CsioSerialTimerIrq:
            pstcCsio->unSACSR.stcField.u1TINTE = 1;
            break;
        default:
            return (ErrorInvalidParameter);
    }
    
    return Ok;
}

/**
 ******************************************************************************
 ** \brief Disable CSIO interrupts
 **
 ** \param [in] pstcCsio   Pointer to CSIO instance   
 ** \param [in] pstcIrqSel    Pointer to the selection structure of CSIO interrupt
 ** 
 ** \retval Ok                    Interrupts has been disabled and callback 
 **                               fucntion pointers are set to NULL 
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **                               - pstcCsio == NULL
 **                               - pstcInt == NULL                
 **
 ** 
 ******************************************************************************/
en_result_t Mfs_Csio_DisableIrq(volatile stc_cpg_mfsn_csio_t* pstcCsio, 
                                en_csio_irq_sel_t enIrqSel)
{  
    if (NULL == pstcCsio)
    {
        return (ErrorInvalidParameter);
    }
    
    switch (enIrqSel)
    {
        case CsioTxIrq:
            pstcCsio->unSCR.stcField.u1TIE = 0;
            break;
        case CsioRxIrq:
            pstcCsio->unSCR.stcField.u1RIE = 0;
            break;
        case CsioTxIdleIrq:
            pstcCsio->unSCR.stcField.u1TBIE = 0;
            break;
        case CsioTxFifoIrq:
            pstcCsio->unFCR1.stcField.u1FTIE = 0;
            break;
        case CsioCsErrIrq:
            pstcCsio->unSACSR.stcField.u1CSEIE = 0;
            break;
        case CsioSerialTimerIrq:
            pstcCsio->unSACSR.stcField.u1TINTE = 0;
            break;
        default:
            return (ErrorInvalidParameter);
    }
    
    return Ok;
}

/**
 *****************************************************************************
 ** \brief Initialization of the CSIO module
 **        At the end of the funciton Transmission and Reception is enabled
 ** 
 ** \retval Ok                    CSIO module successfully inializaed
 ** \retval ErrorInvalidParameter If one of the following conditions are met:
 **             - pstcSpi == NULL
 **             - pstcConfig == NULL
 **             - pstcSpiInternData == NULL (invalid or disabled CSIO unit (PDL_PERIPHERAL_ENABLE_CSIO??CSIOn))
 **             - pstcConfig->enMsMode value out of range
 **             - pstcConfig->enActMode value out of range
 **             - pstcConfig->enSyncWaitTime value out of range
 **             - pstcConfig->enDataLength value out of range
 **             - pstcConfig->enBitDirection value out of range
 **             - pstcConfig->enAWCbit > 1
 **             - pstcConfig->pstcSerialTimer->enClkDiv value out of range
 **             - pstcConfig->pstcCsConfig->enCsStartPin value out of range
 **             - pstcConfig->pstcCsConfig->enCsEndPin value out of range
 **             - pstcConfig->pstcCsConfig->enClkDiv value out of range 
 **             - pstcConfig->pstcFifoConfig->enFifoSel value out of range
 **             - pstcConfig->u16BaudRate < 3
 *****************************************************************************/
en_result_t Mfs_Csio_Init (volatile stc_cpg_mfsn_csio_t * pstcCsio, const stc_mfs_csio_config_t * pstcConfig)
{
    en_result_t enRetVal = Ok;
    stc_csio_intern_data_t * pstcCsioInternData;
    
    /* Preset local register variables to zero */
    un_cpg_mfsn_csio_smr_t    unSMR    = { 0 };
    un_cpg_mfsn_csio_scr_t    unSCR    = { 0 };
    un_cpg_mfsn_csio_ssr_t    unSSR    = { 0 };
    un_cpg_mfsn_csio_escr_t   unESCR   = { 0 };
    un_cpg_mfsn_csio_sacsr_t  unSACSR  = { 0 };
    un_cpg_mfsn_csio_scscr_t  unSCSCR  = { 0 };
    un_cpg_mfsn_csio_scsfr0_t unSCSFR0 = { 0 };
    un_cpg_mfsn_csio_scsfr0_t unSCSFR1 = { 0 };
    un_cpg_mfsn_csio_scsfr0_t unSCSFR2 = { 0 };
    un_cpg_mfsn_csio_fcr0_t   unFCR0   = { 0 };
    
    /* check for the parameters  */
    if (NULL == pstcCsio ||
        NULL == pstcConfig)
    {
        return ErrorInvalidParameter;
    }
    
    /* get pointer to internal data structure */
    pstcCsioInternData = CsioGetInternDataPtr(pstcCsio);
    
    if (NULL == pstcCsioInternData)
    {
        return ErrorInvalidParameter;
    }
           
    /* CSIO configuration */
    /* Set CSIO mode */
    unSMR.stcField.u3MD = 2;
    
    /* disable RX and TX before configutation starts */
    unSCR.stcField.u1RXE  = 0;
    unSCR.stcField.u1TXE  = 0;
    unSCR.stcField.u1UPCL = 0;         
    pstcCsio->unSCR.u8Register = unSCR.u8Register;
    
    /* Set master/slave mode */
    switch(pstcConfig->enMsMode)
    {
        case CsioMaster:
            unSCR.stcField.u1MS = FALSE;  /* Master mode */
            /* Enable SOE */
            unSMR.stcField.u1SOE = TRUE;  
            /* Enable SCKE */
            unSMR.stcField.u1SCKE = TRUE;
            break;
        case CsioSlave:
            unSCR.stcField.u1MS = TRUE;   /* Slave mode */
            /* Enable SOE */
            unSMR.stcField.u1SOE = TRUE;  
            /* Enable SCKE */
            unSMR.stcField.u1SCKE = FALSE; /* Disable clock output in slave mode */
            break;
        default:
            return ErrorInvalidParameter;
    }
    
    /* Set normal/SPI mode */
    switch (pstcConfig->enActMode)
    {
        case CsioActNormalMode:
            unSCR.stcField.u1SPI = FALSE; /* Normal mode */
            break;
        case CsioActSpiMode:
            unSCR.stcField.u1SPI = TRUE;  /* SPI mode */
            break;
        default:
            return (ErrorInvalidParameter);
    }    
    
    /* Set Baudrate */
    enRetVal = Mfs_Csio_SetBaudRate(pstcCsio, pstcConfig->u16BaudRate);
    if (enRetVal != Ok)
    {
        return enRetVal;
    }
        
    /* Wait time insertion */
    switch(pstcConfig->enSyncWaitTime)
    {
        case CsioSyncWaitZero:
            unESCR.stcField.u2WT = 0u;    /* 0bit */
            break;
        case CsioSyncWaitOne:
            unESCR.stcField.u2WT = 1u;    /* 1bit */
            break;
        case CsioSyncWaitTwo:
            unESCR.stcField.u2WT = 2u;   /* 2bits */
            break;
        case CsioSyncWaitThree:
            unESCR.stcField.u2WT = 3u;   /* 3bits */
            break;
        default:
            return (ErrorInvalidParameter);
    }
        
    switch (pstcConfig->enDataLength)
    {
        case CsioFiveBits:
            unESCR.stcField.u3L2_0 = 1;
            unESCR.stcField.u1L3   = 0;
            break;
        case CsioSixBits:
            unESCR.stcField.u3L2_0 = 2;
            unESCR.stcField.u1L3   = 0;
            break;
        case CsioSevenBits:
            unESCR.stcField.u3L2_0 = 3;
            unESCR.stcField.u1L3   = 0;
            break;   
        case CsioEightBits:
            unESCR.stcField.u3L2_0 = 0;
            unESCR.stcField.u1L3   = 0;
            break;
        case CsioNineBits:
            unESCR.stcField.u3L2_0 = 4;
            unESCR.stcField.u1L3   = 0;
            break;
        case CsioTenBits:
            unESCR.stcField.u3L2_0 = 5;
            unESCR.stcField.u1L3   = 0;
            break;
        case CsioElevenBits:
            unESCR.stcField.u3L2_0 = 6;
            unESCR.stcField.u1L3   = 0;
            break;
        case CsioTwelveBits:
            unESCR.stcField.u3L2_0 = 7;
            unESCR.stcField.u1L3   = 0;
            break;
        case CsioThirteenBits:
            unESCR.stcField.u3L2_0 = 0;
            unESCR.stcField.u1L3   = 1;            
            break;
        case CsioFourteenBits:
            unESCR.stcField.u3L2_0 = 1;
            unESCR.stcField.u1L3   = 1;
            break;
        case CsioFifteenBits:
            unESCR.stcField.u3L2_0 = 2;
            unESCR.stcField.u1L3   = 1;
            break;
        case CsioSixteenBits:
            unESCR.stcField.u3L2_0 = 3;
            unESCR.stcField.u1L3   = 1;
            break;
        case CsioTwentyBits:
            unESCR.stcField.u3L2_0 = 4;
            unESCR.stcField.u1L3   = 1;
            break;
        case CsioTwentyfourBits:
            unESCR.stcField.u3L2_0 = 5;
            unESCR.stcField.u1L3   = 1;
            break;
        case CsioThirtytwoBits:
            unESCR.stcField.u3L2_0 = 6;
            unESCR.stcField.u1L3   = 1;
            break;
        default:
            return (ErrorInvalidParameter);
    }
    
    /* Set Bit direction (LSB/MSB) */    
    switch(pstcConfig->enBitDirection)
    {
        case CsioDataLsbFirst:
            unSMR.stcField.u1BDS = FALSE;
            break;
        case CsioDataMsbFirst:
            unSMR.stcField.u1BDS = TRUE;
            break;
        default:
            return ErrorInvalidParameter;
    }
    
    /* Set Signal system (SCK Mark Level) */
    if (TRUE == pstcConfig->bInvertClk)
    {
        unSMR.stcField.u1SCINV = TRUE;    /* SCK Make Level : Low */
    }
    else
    {
        unSMR.stcField.u1SCINV = FALSE;   /* SCK Make Level : High */
    }
    
    /* Clear receive error flag */
    unSSR.stcField.u1REC = 1;
    
    /* Access width control bit */
    if (pstcConfig->enAWCbit > 1)
      return ErrorInvalidParameter;
    
    unSSR.stcField.u1AWC = pstcConfig->enAWCbit;               // 0 = 16 bits & 1 = 32 bits
       
    pstcCsio->unSMR  = unSMR;
    pstcCsio->unSCR  = unSCR;
    pstcCsio->unESCR = unESCR;
    pstcCsio->unSSR  = unSSR;
    
    /* Timer configuration      */
    if(NULL != pstcConfig->pstcSerialTimer)  /* Use serial timer? */
    {
        pstcCsio->unSACSR.stcField.u1TMRE = 0;
        /* Set serial timer clock */
        switch(pstcConfig->pstcSerialTimer->enClkDiv)
        {
            case CsioTimerNoDiv:
                pstcCsio->unSACSR.stcField.u4TDIV = 0u;
                break;
            case CsioTimerDiv2:
                pstcCsio->unSACSR.stcField.u4TDIV = 1u;
                break;
            case CsioTimerDiv4:
                pstcCsio->unSACSR.stcField.u4TDIV = 2u;
                break;
            case CsioTimerDiv8: 
                pstcCsio->unSACSR.stcField.u4TDIV = 3u;
                break;
            case CsioTimerDiv16:
                pstcCsio->unSACSR.stcField.u4TDIV = 4u;
                break;
            case CsioTimerDiv32: 
                pstcCsio->unSACSR.stcField.u4TDIV = 5u;
                break;
            case CsioTimerDiv64:
                pstcCsio->unSACSR.stcField.u4TDIV = 6u;
                break;
            case CsioTimerDiv128: 
                pstcCsio->unSACSR.stcField.u4TDIV = 7u;
                break;
            case CsioTimerDiv256: 
                pstcCsio->unSACSR.stcField.u4TDIV = 8u;
                break;
            default:
                return ErrorInvalidParameter;
        }
        
        /* Transfer count */
        pstcCsio->unTBYTE0.u8Register = pstcConfig->pstcSerialTimer->u8TransferByteCnt;
        
        /* Timer compare value */
        pstcCsio->unSTMCR.u16Register = pstcConfig->pstcSerialTimer->u16CompareVal;
        
        /* Enable sync transfer */
        pstcCsio->unSACSR.stcField.u1TSYNE = 1;
    }
    
    /* Chip select configuration        */    
    if(NULL != pstcConfig->pstcCsConfig)  /* Use chip selection function? */
    {
        if(pstcConfig->enMsMode == CsioMaster)
        {
            pstcCsio->unESCR.stcField.u1CSFE  = 1;
            
            /* Select CS start pin */
            switch(pstcConfig->pstcCsConfig->enCsStartPin)
            {
                case CsPinScs0:
                    unSCSCR.stcField.u2SST = 0;
                    break;
                case CsPinScs1:
                    unSCSCR.stcField.u2SST = 1;
                    break;
                case CsPinScs2:
                    unSCSCR.stcField.u2SST = 2;
                    break;
                case CsPinScs3:
                    unSCSCR.stcField.u2SST = 3;
                    break;
                default:
                    return ErrorInvalidParameter;
            }
            
            /* Select CS end pin */
            switch(pstcConfig->pstcCsConfig->enCsEndPin)
            {
                case CsPinScs0:
                    unSCSCR.stcField.u2SED = 0;
                    break;
                case CsPinScs1:
                    unSCSCR.stcField.u2SED = 1;
                    break;
                case CsPinScs2:
                    unSCSCR.stcField.u2SED = 2;
                    break;
                case CsPinScs3:
                    unSCSCR.stcField.u2SED = 3;
                    break;
                default:
                    return ErrorInvalidParameter;
            }
            
            /* Active hold or not */
            unSCSCR.stcField.u1SCAM = pstcConfig->pstcCsConfig->bActiveHold;             
            
            /* Set chip selection clock */
            switch(pstcConfig->pstcCsConfig->enClkDiv)
            {
                case CsClkNoDiv:
                    unSCSCR.stcField.u3CDIV = 0;
                    break;
                case CsClkDiv2:
                    unSCSCR.stcField.u3CDIV = 1;
                    break;
                case CsClkDiv4:
                    unSCSCR.stcField.u3CDIV = 2;
                    break;
                case CsClkDiv8:
                    unSCSCR.stcField.u3CDIV = 3;
                    break;
                case CsClkDiv16:
                    unSCSCR.stcField.u3CDIV = 4;
                    break;
                case CsClkDiv32:
                    unSCSCR.stcField.u3CDIV = 5;
                    break;
                case CsClkDiv64:
                    unSCSCR.stcField.u3CDIV = 6;
                    break;
                default:
                    return ErrorInvalidParameter;
            }
            
            /* Set chip selection timing */
            pstcCsio->unSCSTR1.u8Register   = pstcConfig->pstcCsConfig->u8CsSetupDelayTime;
            pstcCsio->unSCSTR0.u8Register   = pstcConfig->pstcCsConfig->u8CsHoldDelayTime;
            pstcCsio->unSCSTR23.u16Register = pstcConfig->pstcCsConfig->u16CsDeselectTime;
             
            if (pstcConfig->pstcCsConfig->enLevel > 1)
            {
                return ErrorInvalidParameter;
            }
            
            if (TRUE == pstcConfig->pstcCsConfig->bScs0En)
            {
                unSCSCR.stcField.u1CSEN0 = 1;
                pstcCsio->unTBYTE0.u8Register  = pstcConfig->pstcCsConfig->u8Scs0TransferByteCnt;  /* Set transfer count of each SCS pin */
                unSCSCR.stcField.u1CSLVL       = pstcConfig->pstcCsConfig->enLevel;                /* set inactive level to 0: Low; 1: High */
                pstcCsio->unSMR.stcField.u1BDS = unSMR.stcField.u1BDS;
            } 
            else 
            {
                unSCSCR.stcField.u1CSEN0 = 0;
            }
            
            if (TRUE == pstcConfig->pstcCsConfig->bScs1En)
            {   
                unSCSCR.stcField.u1CSEN1 = 1;
                pstcCsio->unTBYTE1.u8Register = pstcConfig->pstcCsConfig->u8Scs1TransferByteCnt;
                pstcCsio->unSCSFR0.stcField.u1CS1CSLVL = pstcConfig->pstcCsConfig->enLevel;
                pstcCsio->unSCSFR0.stcField.u1CS1BDS   = pstcConfig->enBitDirection;
            }
            else 
            {
                unSCSCR.stcField.u1CSEN1 = 0;
            }
            
            if (TRUE == pstcConfig->pstcCsConfig->bScs2En)
            {
                unSCSCR.stcField.u1CSEN2 = 1;
                pstcCsio->unTBYTE2.u8Register = pstcConfig->pstcCsConfig->u8Scs2TransferByteCnt;
                pstcCsio->unSCSFR1.stcField.u1CS2CSLVL = pstcConfig->pstcCsConfig->enLevel;
                pstcCsio->unSCSFR1.stcField.u1CS2BDS   = pstcConfig->enBitDirection;
            }
            else 
            {
                unSCSCR.stcField.u1CSEN2 = 0;
            }
            
            if (TRUE == pstcConfig->pstcCsConfig->bScs3En)
            {
                unSCSCR.stcField.u1CSEN3 = 1;
                pstcCsio->unTBYTE3.u8Register = pstcConfig->pstcCsConfig->u8Scs3TransferByteCnt;
                pstcCsio->unSCSFR2.stcField.u1CS3CSLVL = pstcConfig->pstcCsConfig->enLevel;
                pstcCsio->unSCSFR2.stcField.u1CS3BDS   = pstcConfig->enBitDirection;
            }
            else 
            {
                unSCSCR.stcField.u1CSEN3 = 0;
            }
            
            unSCSCR.stcField.u1CSOE = 1;        /* Enable CS pins output */                        
        }
        else 
        {
            unSCSCR.stcField.u1CSOE = 0;       /* Disable CS pins output */
        }
        
        pstcCsio->unSCSCR = unSCSCR;
    }
    
    /* FIFO configuration       */
    if(pstcConfig->pstcFifoConfig != NULL) /* Use FIFO function? */
    {        
        /* Enable FIFO receive Idle detection */
        pstcCsio->unFCR1.stcField.u1FRIIE = 1;          // find the purpose
        
        /* Selection TX and RX FIFO  */
        switch(pstcConfig->pstcFifoConfig->enFifoSel)
        {
            case MfsTxFifo1RxFifo2:
                pstcCsio->unFCR1.stcField.u1FSEL = 0;
                break;
            case MfsTxFifo2RxFifo1:
                pstcCsio->unFCR1.stcField.u1FSEL = 1;
                break;
            default:
               return (ErrorInvalidParameter);
        }
        
        /* Set FIFO count */
        pstcCsio->unFBYTE.stcField.u8FBYTE1 = pstcConfig->pstcFifoConfig->u8ByteCount1;
        pstcCsio->unFBYTE.stcField.u8FBYTE2 = pstcConfig->pstcFifoConfig->u8ByteCount2;
        
        /* Enable FIFO  */
        unFCR0.stcField.u1FE1 = 1;
        unFCR0.stcField.u1FE2 = 1;
        pstcCsio->unFCR0 = unFCR0;
        
        /* Note : FIFO will be cleared when it transmits any thing      */
    }
    
    /* Configure interrupts */
    if(pstcConfig->pstcIrqEn != NULL)
    { 
        if(pstcConfig->pstcIrqEn->bRxIrq == TRUE)
        {
            pstcCsio->unSCR.stcField.u1RIE = 1;
        }
        
        if(pstcConfig->pstcIrqEn->bTxIrq == TRUE)
        {
            pstcCsio->unSCR.stcField.u1TIE = 1;
        }
        
        if(pstcConfig->pstcIrqEn->bTxIdleIrq == TRUE)
        {
            pstcCsio->unSCR.stcField.u1TBIE = 1;
        }
        
        if(pstcConfig->pstcIrqEn->bTxFifoIrq == TRUE)
        {
            pstcCsio->unFCR1.stcField.u1FTIE = 1;
        }
        
        if(pstcConfig->pstcIrqEn->bCsErrIrq == TRUE) 
        {
            pstcCsio->unSACSR.stcField.u1CSEIE = 1;
        }
        
        if(pstcConfig->pstcIrqEn->bSerialTimerIrq == TRUE)
        {
            pstcCsio->unSACSR.stcField.u1TINTE = 1;
        }    
    }
    
    /* Configuration of internal data structure */
    /* Interrupt callback functions */
    if(NULL != pstcConfig->pstcIrqCb)
    {
        pstcCsioInternData->pstcIrqCb.pfnRxIrqCb          = pstcConfig->pstcIrqCb->pfnRxIrqCb;
        pstcCsioInternData->pstcIrqCb.pfnTxIrqCb          = pstcConfig->pstcIrqCb->pfnTxIrqCb;
        pstcCsioInternData->pstcIrqCb.pfnTxIdleCb         = pstcConfig->pstcIrqCb->pfnTxIdleCb;
        pstcCsioInternData->pstcIrqCb.pfnTxFifoIrqCb      = pstcConfig->pstcIrqCb->pfnTxFifoIrqCb;
        pstcCsioInternData->pstcIrqCb.pfnCsErrIrqCb       = pstcConfig->pstcIrqCb->pfnCsErrIrqCb;
        pstcCsioInternData->pstcIrqCb.pfnSerialTimerIrqCb = pstcConfig->pstcIrqCb->pfnSerialTimerIrqCb;
    }
    
    enRetVal = Mfs_Csio_EnableFunc(pstcCsio, CsioTx);
    if (enRetVal != Ok)
    {
        return enRetVal;
    }
    enRetVal = Mfs_Csio_EnableFunc(pstcCsio, CsioRx);
    if (enRetVal != Ok)
    {
        return enRetVal;
    }
    
    return Ok;
}

/**
 ******************************************************************************
 ** \brief Deinitialisation of a CSIO.
 **
 ** All used CSIO register are reset to their default values.
 **  
 ** \param [in]   pstcCsio        Pointer to CSIO instance register area
 ** 
 ** \retval Ok                        Process successfully done.
 ** \retval ErrorInvalidParameter     If one of following conditions are met:
 **             - pstcCsio == NULL
 **             - pstcMfsInternData == NULL (invalid or disabled MFS unit
 **                                          (PDL_PERIPHERAL_ENABLE_MFS)) 
 **
 ******************************************************************************/
en_result_t Mfs_Csio_DeInit(volatile stc_cpg_mfsn_csio_t* pstcCsio)
{
    stc_csio_intern_data_t* pstcCsioInternData;
    
    if (NULL == pstcCsio)
    {
        return ErrorInvalidParameter;
    }
    
    /* get pointer to internal data structure */
    pstcCsioInternData = CsioGetInternDataPtr(pstcCsio);
    
    if (pstcCsioInternData == NULL)
    {
        return ErrorInvalidParameter;
    } 
    
    /* disable receiver transmitter and interrupts      */
    pstcCsio->unSCR.stcField.u1TXE = 0;
    pstcCsio->unSCR.stcField.u1RXE = 0;
    
    /* reset baudrate generator */
    pstcCsio->unBGR.u16Register = 0;
    
    /* serial mode register clear all bits      */
    pstcCsio->unSMR.u8Register = 0;
    
    /* reset MFS receive and transmit bit to default condition  */
    pstcCsio->unSCR.u8Register = 0;
    
    pstcCsio->unFCR0.stcField.u1FCL1 = 1;                       /* clear FIFO 1 */
    pstcCsio->unFCR0.stcField.u1FCL2 = 1;                       /* clear FIFO 2 */
    
    pstcCsio->unSSR.u8Register      = 0;
    pstcCsio->unESCR.u8Register     = 0;
    pstcCsio->unFCR0.u8Register     = 0;
    pstcCsio->unFCR1.u8Register     = 0;
    pstcCsio->unSACSR.u16Register   = 0;
    pstcCsio->unSTMCR.u16Register   = 0;
    pstcCsio->unSCSCR.u16Register   = 0;
    pstcCsio->unSCSTR0.u8Register   = 0;
    pstcCsio->unSCSTR1.u8Register   = 0;
    pstcCsio->unSCSTR23.u16Register = 0;
    pstcCsio->unTBYTE0.u8Register   = 0;
    pstcCsio->unTBYTE1.u8Register   = 0;
    pstcCsio->unTBYTE2.u8Register   = 0;
    pstcCsio->unTBYTE3.u8Register   = 0;    
    return Ok;
} /* Mfs_Csio_DeInit */

/**
 ******************************************************************************
 ** \brief Set the compare value of CSIO serial timer
 **
 ** \param [in] pstcCsio        Pointer to CSIO instance   
 ** \param [in] u16CompareValue Compare value
 ** 
 ** \retval Ok                    Compare value has been successfully modified
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **                               - pstcCsio == NULL
 **
 ** \note
 ** The compare value of CSIO serial timer can be initialized in 
 ** the Mfs_Csio_Init() and be modified in this function.
 ** 
 ******************************************************************************/
en_result_t Mfs_Csio_SetTimerCompareValue(volatile stc_cpg_mfsn_csio_t* pstcCsio,
                                          uint16_t u16CompareValue)
{
    stc_csio_intern_data_t* pstcCsioInternData;
    
    pstcCsioInternData = CsioGetInternDataPtr(pstcCsio);
    
    if (NULL == pstcCsioInternData)
    {
        return (ErrorInvalidParameter);
    }
    
    pstcCsio->unSTMCR.u16Register = u16CompareValue;
    
    return Ok;
}

/**
 ******************************************************************************
 ** \brief Set the transfer byte count of a selected chip selection pin
 **
 ** \param [in] pstcCsio        Pointer to CSIO instance   
 ** \param [in] enCsPin         CS pin index
 ** \param [in] u8ByteCnt       Transfer byte count of a CS pin 
 ** 
 ** \retval Ok                    Transfer byte count has been successfully modified
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **                               - pstcCsio == NULL
 **
 ** \note
 ** The transfer byte count of chip selection pin can be initialized in 
 ** the Mfs_Csio_Init() and be modified in this function.
 ** 
 ******************************************************************************/
en_result_t Mfs_Csio_SetCsTransferByteCount(volatile stc_cpg_mfsn_csio_t* pstcCsio,
                                            en_cs_pin_sel_t enCsPin,
                                            uint8_t u8ByteCnt)
{
    stc_csio_intern_data_t* pstcCsioInternData;
    
    pstcCsioInternData = CsioGetInternDataPtr(pstcCsio);
    
    if (NULL == pstcCsioInternData)
    {
        return (ErrorInvalidParameter);
    }
    
    switch(enCsPin)
    {
        case CsPinScs0:
            pstcCsio->unTBYTE0.u8Register = u8ByteCnt;
            break;
        case CsPinScs1:
            pstcCsio->unTBYTE1.u8Register = u8ByteCnt;
            break;
        case CsPinScs2:
            pstcCsio->unTBYTE2.u8Register = u8ByteCnt;
            break;
        case CsPinScs3:
            pstcCsio->unTBYTE3.u8Register = u8ByteCnt;
            break;
        default:  
            return ErrorInvalidParameter;
    }
    
    return Ok;
}

/**
 ******************************************************************************
 ** \brief Set the hold status of chip selection pin
 **
 ** \param [in] pstcCsio        Pointer to CSIO instance   
 ** \param [in] bHold 
 ** \arg  FALSE    Make the CS pin inactive if specified count bytes are 
 **                transferred
 ** \arg  TRUE     Hold the CS pin status even if specified count bytes are 
 **                transferred
 ** 
 ** \retval Ok                    Hold status of chip selection pin is set
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **                               - pstcCsio == NULL
 **
 ******************************************************************************/                                  
en_result_t Mfs_Csio_SetCsHoldStatus(volatile stc_cpg_mfsn_csio_t* pstcCsio, 
                                     boolean_t bHold)
{
    stc_csio_intern_data_t* pstcCsioInternData;
    
    pstcCsioInternData = CsioGetInternDataPtr(pstcCsio);
    
    if (NULL == pstcCsioInternData)
    {
        return (ErrorInvalidParameter);
    }
    
    pstcCsio->unSCSCR.stcField.u1SCAM = (bHold == TRUE) ? 1 : 0;
    
    return Ok;
}

/**
 ******************************************************************************
 ** \brief Set the transfer byte count of CSIO serial timer
 **
 ** \param [in] pstcCsio        Pointer to CSIO instance   
 ** \param [in] u8ByteCnt       Transfer byte count
 ** 
 ** \retval Ok                    Transfer byte count has been successfully modified
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **                               - pstcCsio == NULL
 **
 ** \note
 ** The transfer byte count of CSIO serial timer can be initialized in 
 ** the Mfs_Csio_Init() and be modified in this function.
 ** 
 ******************************************************************************/
en_result_t Mfs_Csio_SetTimerTransferByteCount(volatile stc_cpg_mfsn_csio_t* pstcCsio,
                                               uint8_t u8ByteCnt)
{
    stc_csio_intern_data_t* pstcCsioInternData;
    
    pstcCsioInternData = CsioGetInternDataPtr(pstcCsio);
    
    if (NULL == pstcCsioInternData)
    {
        return (ErrorInvalidParameter);
    }
    
    pstcCsio->unTBYTE0.u8Register = u8ByteCnt;
    
    return Ok;
}

/**
 ******************************************************************************
 ** \brief Set the baudrate of CSIO
 **
 ** \param [in] pstcCsio    Pointer to CSIO instance   
 ** \param [in] u32BaudRate Baudrate value [bps]
 ** 
 ** \retval Ok                    CSIO baud rate has been successfully modified
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **                               - pstcCsio == NULL
 **                               - u32BaudRate < 3         
 ** \note
 ** The CSIO baud rate can be initialized in the Mfs_Csio_Init() and be modified
 ** in the function.
 ** 
 ******************************************************************************/
en_result_t Mfs_Csio_SetBaudRate(volatile stc_cpg_mfsn_csio_t* pstcCsio,
                                 uint16_t u16BaudRate)
{
    if ((NULL == pstcCsio) || (u16BaudRate < 3))
    {
        return ErrorInvalidParameter;
    }
    
    pstcCsio->unBGR.u16Register = u16BaudRate;                     // Baudrate setting
    
    return Ok;  
}

/**
 ******************************************************************************
 ** \brief Enable CSIO functions
 **
 ** \param [in] pstcCsio   Pointer to CSIO instance   
 ** \param [in] enFunc     CSIO function types
 ** \arg   CsioTx            CSIO transfer function
 ** \arg   CsioRx            CSIO receive function
 ** \arg   CsioSerialTimer   CSIO serial timer function
 ** \arg   CsioCsErrOccur    CSIO chip selection error detection function 
 ** 
 ** \retval Ok                    Function has been enabled normally
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **                               - pstcCsio == NULL                
 ** 
 ******************************************************************************/
en_result_t Mfs_Csio_EnableFunc(volatile stc_cpg_mfsn_csio_t* pstcCsio, en_csio_func_t enFunc)
{
    stc_csio_intern_data_t* pstcCsioInternData;
    
    pstcCsioInternData = CsioGetInternDataPtr(pstcCsio);
    
    if (NULL == pstcCsioInternData)
    {
        return (ErrorInvalidParameter);
    }
    
    switch(enFunc)
    {
        case CsioTx:
            pstcCsio->unSMR.stcField.u1SOE = 1;
            pstcCsio->unSCR.stcField.u1TXE = 1;
            break;
        case CsioRx:
            pstcCsio->unSCR.stcField.u1RXE = 1;
            break;
        case CsioSerialTimer:
            pstcCsio->unSACSR.stcField.u1TMRE = 1;
            break;
        case CsioCsErrOccur:
            pstcCsio->unSACSR.stcField.u1TBEEN = 1;
            break;
        default:
            return ErrorInvalidParameter;
    }
    
    return Ok;
}

/**
 ******************************************************************************
 ** \brief Disable CSIO functions
 **
 ** \param [in] pstcCsio   Pointer to CSIO instance   
 ** \param [in] enFunc     CSIO function types
 ** \arg   CsioTx            CSIO transfer function
 ** \arg   CsioRx            CSIO receive function
 ** \arg   CsioSerialTimer   CSIO transfer function
 ** \arg   CsioCsErrOccur    CSIO receive function 
 ** 
 ** \retval Ok                    Function has been disabled normally
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **                               - pstcCsio == NULL              
 ** 
 ******************************************************************************/
en_result_t Mfs_Csio_DisableFunc(volatile stc_cpg_mfsn_csio_t* pstcCsio, en_csio_func_t enFunc)
{
    stc_csio_intern_data_t* pstcCsioInternData;
    
    pstcCsioInternData = CsioGetInternDataPtr(pstcCsio);
    
    if (NULL == pstcCsioInternData)
    {
        return (ErrorInvalidParameter);
    }
    
    switch(enFunc)
    {
        case CsioTx:
            pstcCsio->unSMR.stcField.u1SOE = 0;
            pstcCsio->unSCR.stcField.u1TXE = 0;
            break;
        case CsioRx:
            pstcCsio->unSCR.stcField.u1RXE = 0;
            break;
        case CsioSerialTimer:
            pstcCsio->unSACSR.stcField.u1TMRE = 0;
            break;
        case CsioCsErrOccur:
            pstcCsio->unSACSR.stcField.u1TBEEN = 0;
            break;
        default:
            return ErrorInvalidParameter;
    }
    
    return Ok;
}

/**
 ******************************************************************************
 ** \brief Get status of CSIO according to status type
 ** \param [in] pstcCsio     Pointer to CSIO instance   
 ** 
 **
 ** \param [in] pstcCsio     Pointer to CSIO instance   
 ** \param [in] enStatus     CSIO status type
 ** \arg   CsioOverrunError  CSIO parity error
 ** \arg   CsioRxFull        CSIO receive buffer full
 ** \arg   CsioTxEmpty       CSIO tranfer buffer empty
 ** \arg   CsioTxIdle        CSIO tranfer idle status
 ** \arg   CsioTxFifoRequest CSIO transfer FIFO request
 ** \arg   CsioCsErrIntFlag  CSIO chip selection error occurrance
 ** \arg   CsioTimerIntFlag  CSIO serial timer interrupt flag
 ** 
 ** \retval FALSE                 If one of following conditions are met:
 **                               - No CSIO overrun error [enStatus = CsioOverrunError]
 **                               - CSIO receive buffer is not full [enStatus = CsioRxFull]
 **                               - CSIO tranfer buffer is not empty [enStatus = CsioTxEmpty]
 **                               - CSIO tranfer is on-going [enStatus = CsioTxIdle]
 **                               - No CSIO transfer FIFO request [enStatus = CsioTxFifoRequest]
 **                               - CSIO chip selection error doesn't occur [enStatus = CsioCsErrIntFlag]
 **                               - CSIO serial timer interrupt doesn't occur [enStatus = CsioTimerIntFlag]
 ** \retval TRUE                 If one of following conditions are met:
 **                               - CSIO overrun error occurs [enStatus = CsioOverrunError]
 **                               - CSIO receive buffer is full [enStatus = CsioRxFull]
 **                               - CSIO tranfer buffer is empty [enStatus = CsioTxEmpty]
 **                               - CSIO tranfer is idle [enStatus = CsioTxIdle]
 **                               - CSIO transfer FIFO request issues [enStatus = CsioTxFifoRequest]
 **                               - CSIO chip selection error occurs  [enStatus = CsioCsErrIntFlag]
 **                               - CSIO serial timer interrupt occurs [enStatus = CsioTimerIntFlag]
 ** 
 ******************************************************************************/
stc_mfs_csio_status_t* Mfs_Csio_GetStatus(volatile stc_cpg_mfsn_csio_t* pstcCsio)
{
    stc_csio_intern_data_t* pstcCsioInternData;
    
    pstcCsioInternData = CsioGetInternDataPtr(pstcCsio);
    
    if (NULL == pstcCsioInternData)
    {
        return NULL;
    }
    
    pstcCsioInternData->stcStatus.bOREStatus  = (pstcCsio->unSSR.stcField.u1ORE == 1) ? TRUE : FALSE;
    pstcCsioInternData->stcStatus.bRDRFStatus = (pstcCsio->unSSR.stcField.u1RDRF == 1) ? TRUE : FALSE;
    pstcCsioInternData->stcStatus.bTDREStatus = (pstcCsio->unSSR.stcField.u1TDRE == 1) ? TRUE : FALSE;
    pstcCsioInternData->stcStatus.bTBIStatus  = (pstcCsio->unSSR.stcField.u1TBI == 1) ? TRUE : FALSE;
    pstcCsioInternData->stcStatus.bFDRQStatus = (pstcCsio->unFCR1.stcField.u1FDRQ == 1) ? TRUE : FALSE;
    pstcCsioInternData->stcStatus.bCSEStatus  = (pstcCsio->unSACSR.stcField.u1CSE == 1) ? TRUE : FALSE;
    pstcCsioInternData->stcStatus.bTINTStatus = (pstcCsio->unSACSR.stcField.u1TINT == 1) ? TRUE : FALSE;
    
    
    
    return &pstcCsioInternData->stcStatus;
}

/**
 ******************************************************************************
 ** \brief Clear status of CSIO according to status type
 **
 ** \param [in] pstcCsio     Pointer to CSIO instance   
 ** \param [in] enStatus     UART status type
 ** \arg   CsioOverrunError  CSIO overrun error
 ** \arg   CsioRxFull        CSIO receive buffer full
 ** \arg   CsioTxEmpty       CSIO tranfer buffer empty
 ** \arg   CsioTxIdle        CSIO tranfer idle status
 ** \arg   CsioTxFifoRequest CSIO transfer FIFO request
 ** \arg   CsioCsErrIntFlag  CSIO chip selection error occurrance
 ** 
 ** \retval Ok                    Status has been cleared normally
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **                               - pstcUart == NULL
 ** \note  The following status can only be cleared by hardware behavior:
 **        - CsioRxFull
 **        - CsioTxEmpty
 **        - CsioTxIdle
 ** 
 ******************************************************************************/
en_result_t Mfs_Csio_ClrStatus(volatile stc_cpg_mfsn_csio_t* pstcCsio,
                               en_csio_status_t enStatus)
{
    stc_csio_intern_data_t* pstcCsioInternData;
    
    pstcCsioInternData = CsioGetInternDataPtr(pstcCsio);
    
    if (NULL == pstcCsioInternData)
    {
        return (ErrorInvalidParameter);
    }
    
    switch(enStatus)
    {
        case CsioOverrunError:
            pstcCsio->unSSR.stcField.u1REC = 1;
            break;
        case CsioRxFull:
        case CsioTxEmpty:
        case CsioTxIdle:
            break;
        case CsioTxFifoRequest:
            pstcCsio->unFCR1.stcField.u1FDRQ = 0;
            break;
        case CsioCsErrIntFlag:
            pstcCsio->unSACSR.stcField.u1CSE = 0;
            break;
        case CsioTimerIntFlag:
            pstcCsio->unSACSR.stcField.u1TINT = 0;
            break;
        default:
            return ErrorInvalidParameter;
    }
    
    return Ok;
}

/**
 ******************************************************************************
 ** \brief Reset CSIO FIFO
 **
 ** \param [in] pstcCsio   Pointer to CSIO instance   
 ** \param [in] enFifo     FIFO1 or FIFO2
 ** 
 ** \retval Ok                    FIFO has been successfully reset
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **                               - pstcCsio == NULL           
 ** 
 ******************************************************************************/
en_result_t Mfs_Csio_ResetFifo (volatile stc_cpg_mfsn_csio_t* pstcCsio, 
                                en_mfs_fifo_t enFifo)
{
    stc_csio_intern_data_t* pstcCsioInternData;
    
    pstcCsioInternData = CsioGetInternDataPtr(pstcCsio);
    
    if (NULL == pstcCsioInternData)
    {
        return (ErrorInvalidParameter);
    }
    
    switch(enFifo)
    {
        case MfsFifo1:
            pstcCsio->unFCR0.stcField.u1FCL1 = 1;
            break;
        case MfsFifo2:
            pstcCsio->unFCR0.stcField.u1FCL2 = 1;
            break;
        default:
            return ErrorInvalidParameter;
    }
    
    return Ok;
}

/**
 ******************************************************************************
 ** \brief Set CSIO FIFO count
 **
 ** \param [in] pstcCsio   Pointer to CSIO instance   
 ** \param [in] enFifo     FIFO1 or FIFO2
 ** \param [in] u8Count    FIFO count
 ** 
 ** \retval Ok                    FIFO count has been successfully set
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **                               - pstcCsio == NULL           
 ** 
 ******************************************************************************/
en_result_t Mfs_Csio_SetFifoCount(volatile stc_cpg_mfsn_csio_t* pstcCsio,
                                  en_mfs_fifo_t enFifo,
                                  uint8_t u8Count)
{
    stc_csio_intern_data_t* pstcCsioInternData;
    
    pstcCsioInternData = CsioGetInternDataPtr(pstcCsio);
    
    if (NULL == pstcCsioInternData)
    {
        return (ErrorInvalidParameter);
    }
    
    switch(enFifo)
    {
        case MfsFifo1:
            pstcCsio->unFBYTE.stcField.u8FBYTE1 = u8Count;
            break;
        case MfsFifo2:
            pstcCsio->unFBYTE.stcField.u8FBYTE2 = u8Count;
            break;
        default:
           return ErrorInvalidParameter;
    }
    
    return Ok;
}

/**
 ******************************************************************************
 ** \brief Get CSIO FIFO count
 **
 ** \param [in] pstcCsio   Pointer to CSIO instance   
 ** \param [in] enFifo     FIFO1 or FIFO2
 ** 
 ** \retval FIFO count      
 ** 
 ** This function gets the current data count in selected FIFO.
 **
 ** \note 0xFF will be return value if FIFO index is error.
 **
 ******************************************************************************/
uint8_t Mfs_Csio_GetFifoCount(volatile stc_cpg_mfsn_csio_t* pstcCsio,
                              en_mfs_fifo_t enFifo)
{
    uint8_t u8FifoCnt = 0xFFu;
    stc_csio_intern_data_t* pstcCsioInternData;
    
    pstcCsioInternData = CsioGetInternDataPtr(pstcCsio);
    
    if (NULL != pstcCsioInternData)
    {
        switch(enFifo)
        {
            case MfsFifo1:
                u8FifoCnt = pstcCsio->unFBYTE.stcField.u8FBYTE1;
                break;
            case MfsFifo2:
                u8FifoCnt = pstcCsio->unFBYTE.stcField.u8FBYTE2;
                break;
            default:
               break;
        }
    }
    
    return u8FifoCnt;
}

/**
 *****************************************************************************
 ** \brief Transfers data in direct half-duplex mode.
 ** 
 ** \param [in] pstcCsio              Csio module instance (register
 **                                   start address of CSIO module).
 ** \param [in] u8DeviceNumber        Slave which is connected to corresponding
 **                                   signal SSEL0..3.
 ** \param [in] pu16TxData            Pointer to first item of transmit data list
 **                                   The total size of transmit data must be greater than 0
 ** \param [in] pu8RxData             Pointer to receive buffer, can be NULL.
 ** \param [in] u16RxSize             Number of data bytes to receive, can be 0
 ** \param [in] u16TxSize             Number of data bytes to be transmitted
 ** \retval Ok                        Setup or transmission of data successful.
 ** \retval ErrorOperationInProgress  A transmission is still ongoing.
 ** \retval ErrorInvalidParameter     If one of following conditions are met:
 **          - pstcCsio == NULL
 **          - pu16TxData == NULL
 **          - u8DeviceNumber > 3
 **          - total size of transmit data == 0
 **          - total size of transmit data + u16RxSize > (2^16 - 1)
 *****************************************************************************/
en_result_t Mfs_Csio_HalfDuplexComm(volatile stc_cpg_mfsn_csio_t* pstcCsio, en_cs_pin_sel_t enDeviceNumber, uint16_t* pu16TxData, uint16_t u16TxSize, uint16_t* pu16RxData, uint16_t u16RxSize)
{
    uint8_t  u8Index;
    uint8_t  u8LoopEndIndex;
    uint16_t u16TransmissionLength;
    uint16_t u16RxDataCount = 0;
    uint16_t u16TxDataCount = 0;
    en_result_t enRetVal = Ok;
    
    /* Check for NULL-Pointer */
    if (pstcCsio   == NULL ||
        pu16TxData == NULL)
    {
        return ErrorInvalidParameter;
    }
    
    /* Check for slave number in range */
    if (enDeviceNumber > 3)
    {
        return ErrorInvalidParameter;
    }
    
    /* Check for valid transfer size */
    if (u16TxSize == 0)
    {
        return ErrorInvalidParameter;
    }
    
    /* Check for valid total transmission size */
    if (((uint32_t) u16TxSize + (uint32_t) u16RxSize) > 65535)
    {
        return ErrorInvalidParameter;
    }
    
    /* check whether start and stop bits of CS setting can support this selected device or not */
    if ((enDeviceNumber >= pstcCsio->unSCSCR.stcField.u2SST) && (enDeviceNumber <= pstcCsio->unSCSCR.stcField.u2SED))
    {
        /* check whether chip select is enabled or not */
        switch (enDeviceNumber)
        {
            case 0:
                if (pstcCsio->unSCSCR.stcField.u1CSEN0 == 0)
                {
                    return ErrorInvalidMode;
                }
                break;
            case 1:
                if (pstcCsio->unSCSCR.stcField.u1CSEN1 == 0)
                {
                    return ErrorInvalidMode;
                }
                break;
            case 2:
                if (pstcCsio->unSCSCR.stcField.u1CSEN2 == 0)
                {
                    return ErrorInvalidMode;
                }
                break;
            case 3:
                if (pstcCsio->unSCSCR.stcField.u1CSEN3 == 0)
                {
                    return ErrorInvalidMode;
                }
                break;
            default:
                return ErrorInvalidMode;
        }
        
    }
    else 
    {
        return ErrorInvalidMode;
    }    
    
    /* In half-duplex mode the number of bytes in this transaction is the sum of TX and RX */
    u16TransmissionLength = u16TxSize + u16RxSize;
    
    /* Loop until whole transmission has finished */
    while(u16TxDataCount < u16TransmissionLength)
    {
        /* Reset transmit and receive FIFOs */
        pstcCsio->unFCR0.stcField.u1FCL1 = 1;
        pstcCsio->unFCR0.stcField.u1FCL2 = 1;
        
        /* Put max FIFO size or remaining bytes of transmission (whichever is less) in TX FIFO */
        u8LoopEndIndex = MIN(CSIO_FIFO_MAX_VAL, (u16TransmissionLength - u16TxDataCount));
        enRetVal = Mfs_Csio_SetCsTransferByteCount(pstcCsio, enDeviceNumber, u8LoopEndIndex);
        
        if (Ok != enRetVal)
        {
            return enRetVal;
        }       
        for (u8Index = 0; u8Index < u8LoopEndIndex; u8Index++)
        {
            /*Put actual transmit data in FIFO or just dummy data for second part (=receive part) of half duplex transaction    */
            pstcCsio->unRDR.au16Halfword[0] = (u16TxDataCount < u16TxSize) ? pu16TxData[u16TxDataCount] : 0;
            u16TxDataCount++;
        }
        
        /* Wait until transfer is finished (no more data in FIFO and shift register empty)*/
        while (pstcCsio->unSSR.stcField.u1TBI == 0)
        {
            PDL_WAIT_LOOP_HOOK();
        }
        
        /* Check if receive data has been requested */
        if (pu16RxData != NULL && u16RxSize > 0)
        { 
            /* Data from FIFO is stored in user buffer if RX phase has been reached */
            while (pstcCsio->unFBYTE.u16Register > 0)
            {
                if(u16RxDataCount >= u16TxSize)
                {
                    pu16RxData[u16RxDataCount - u16TxSize] = pstcCsio->unRDR.au16Halfword[0];
                }
                else
                {
                    pstcCsio->unRDR.u32Register;
                }
                u16RxDataCount++;
            }
        }
    }
    
    return Ok;
} // Mfs_Csio_HalfDuplexComm

/**
 *****************************************************************************
 ** \brief Transfers data in direct full-duplex mode.
 **
 ** The length of data to be transmitted with pu16TxData may exceed
 ** #SPI_MAX_FIFO_DEPTH but the function works synchronously and hence it may
 ** run for a long time depending on CSIO clock and data amount.
 ** If data shall be received the application is responsible for disregarding
 ** any meaningless bytes from the receive buffer (e.g. byte(s) received while
 ** command byte(s) is/are transmitted)
 **
 ** \param [in] pstcCsio              CSIO module instance (register
 **                                   start address of (high speed) CSIO module).
 ** \param [in] u8DeviceNumber        Slave which is connected to corresponding
 **                                   signal SSEL0..3.
 ** \param [in] pu16TxData            Pointer to first item of linked transmit data list
 **                                   (must contain actual "payload" + possible "dummy bytes")
 **                                   The total size of transmit data must be greater than 0
 ** \param [in] u16TxSize             Number of data bytes to transmit.
 ** \param [in] pu8RxData             Pointer to receive buffer, MUST NOT be NULL
 **
 ** \retval Ok                        Setup or transmission of data successful.
 ** \retval ErrorOperationInProgress  A transmission is still ongoing.
 ** \retval ErrorInvalidParameter     If one of following conditions are met:
 **          - pstcSpi == NULL
 **          - pu16TxData == NULL
 **          - u8DeviceNumber > 3
 **          - total size of transmit data == 0
 **          - pstcSpiInternData == NULL
 **             (invalid or disabled SPI unit (L3_PERIPHERAL_ENABLE_??SPIn))
 *****************************************************************************/
en_result_t Mfs_Csio_FullDuplexComm(volatile stc_cpg_mfsn_csio_t* pstcCsio, en_cs_pin_sel_t enDeviceNumber, uint16_t* pu16TxData, uint16_t u16TxSize, uint16_t* pu16RxData)
{
    uint8_t  u8Index;
    uint8_t  u8LoopEndIndex;
    uint16_t u16TxDataCount = 0;
    uint16_t u16RxDataCount = 0;
    en_result_t enRetVal = Ok;

    // Check for NULL-Pointer
    if (pstcCsio            == NULL ||
        pu16TxData          == NULL ||
        pu16RxData          == NULL
     )
    {
        return ErrorInvalidParameter;
    }

    // Check for slave number in range
    if (enDeviceNumber > 3)
    {
        return ErrorInvalidParameter;
    }
    
    // Check for valid transfer size
    if (u16TxSize == 0)
    {
        return ErrorInvalidParameter;
    }
    
    // Check if there is a pending transmission
    if (pstcCsio->unSSR.stcField.u1TBI == 0)
    {
        return ErrorOperationInProgress;
    }
    
    // check whether start and stop bits of CS setting can support this selected device or not
    if ((enDeviceNumber >= pstcCsio->unSCSCR.stcField.u2SST) && (enDeviceNumber <= pstcCsio->unSCSCR.stcField.u2SED))
    {
        // check whether chip select is enabled or not 
        switch (enDeviceNumber)
        {
            case 0:
                if (pstcCsio->unSCSCR.stcField.u1CSEN0 == 0)
                {
                    return ErrorInvalidMode;
                }
                break;
            case 1:
                if (pstcCsio->unSCSCR.stcField.u1CSEN1 == 0)
                {
                    return ErrorInvalidMode;
                }
                break;
            case 2:
                if (pstcCsio->unSCSCR.stcField.u1CSEN2 == 0)
                {
                    return ErrorInvalidMode;
                }
                break;
            case 3:
                if (pstcCsio->unSCSCR.stcField.u1CSEN3 == 0)
                {
                    return ErrorInvalidMode;
                }
                break;
            default:
                return ErrorInvalidMode;
        }
        
    }
    else 
    {
        return ErrorInvalidMode;
    }         
    
    // Fill FIFO with new data
    while(u16TxDataCount < u16TxSize)
    {
        // Reset transmit and receive FIFOs
        pstcCsio->unFCR0.stcField.u1FCL1 = 1;
        pstcCsio->unFCR0.stcField.u1FCL2 = 1;
    
        // Put max FIFO size or remaining bytes of transmission (whichever is less) in TX FIFO
        u8LoopEndIndex = MIN(CSIO_FIFO_MAX_VAL, (u16TxSize - u16TxDataCount));
        
        enRetVal = Mfs_Csio_SetCsTransferByteCount(pstcCsio, enDeviceNumber, u8LoopEndIndex);
        
        if (Ok != enRetVal)
        {
            return enRetVal;
        }
        
        for (u8Index = 0; u8Index < u8LoopEndIndex; u8Index++)
        {
            pstcCsio->unRDR.u32Register = pu16TxData[u16TxDataCount++];
        }
        
        // Wait until transfer is finished (no more data in FIFO and shift register empty)
        while (pstcCsio->unSSR.stcField.u1TBI == 0)
        {
            PDL_WAIT_LOOP_HOOK();
        }
                
        // Reads up to the number of requested data from the RX FIFO
        while (pstcCsio->unFBYTE.u16Register > 0)
        {
            pu16RxData[u16RxDataCount++] = pstcCsio->unRDR.au16Halfword[0];
        }        
    }
    
    return enRetVal;
} // Mfs_Csio_FullDuplexComm

/*!@} */
#endif /* (PDL_PERIPHERAL_CSIO_ACTIVE) */

/*****************************************************************************/
/* EOF (not truncated)                                                       */
/*****************************************************************************/

