/*****************************************************************************
 * $Revision: 423 $
 * $Date: 2015-09-10 17:33:56 +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 i2s.c
 **
 ** A detailed description is available at
 ** @link I2SGroup I2S Module description @endlink
 **
 ** History:
 ** - 2015-03-31  1.0   MAs  First version 
 *****************************************************************************/

/*****************************************************************************/
/* Include files                                                             */
/*****************************************************************************/
#include "common_include.h"



/*****************************************************************************/
/* Local pre-processor symbols/macros ('define')                             */
/*****************************************************************************/


/*****************************************************************************/
/* Global variable definitions (declared in header file with 'extern')       */
/*****************************************************************************/


/*****************************************************************************/
/* Local type definitions ('typedef')                                        */
/*****************************************************************************/




/*****************************************************************************/
/* Local function prototypes ('static')                                      */
/*****************************************************************************/

static void I2sIrqHandler(volatile stc_i2sn_t* pstcI2s,
                          stc_i2s_intern_data_t* pstcI2sInternData);

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

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

#include "i2s_generated.c"

/**
 *****************************************************************************
 ** \brief I2s Interrupt service routine.
 **
 ** This Fct is called on each event detected.
 **
 ** \param pstcI2s            Pointer to I2s instance register area
 ** \param pstcI2sInternData  Pointer to internal data structure of the instance
 **
 *****************************************************************************/
void I2sIrqHandler(volatile stc_i2sn_t* pstcI2s, stc_i2s_intern_data_t* pstcI2sInternData)
{    
    // Call callback, if setup
    if (( pstcI2sInternData->pfnInterruptCbFunction != NULL ) && ( !(pstcI2s->unINTCNT.stcField.u1TXFIM)))
    {
        pstcI2sInternData->pfnInterruptCbFunction() ;
    }
    
    // Note: Tx FIFO Empty flag is cleared by HW
}  /* I2sIrqHandler */

/**
 *****************************************************************************
 ** This function initialises one specific I2S module with the parameters
 ** provided in the given config structure 'stc_i2s_config'.
 **
 ** I2s_Init() has to be called with the parameter pstcConfig of type
 ** stc_i2s_config_t for standard I2S settings which are suitable for most 
 ** audio codecs.
 **
 ** All values in pstcConfig have to be in valid range (see i2s.h for allowed
 ** ranges of dedicated parameters). The error and status change callback
 ** functions can be NULL. In this case no information of error or status
 ** changes will be reported to the API.
 **
 ** To reset and disable the I2S module the function I2s_DeInit() has to be used.
 **
 ** \param [in] pstcI2s         Pointer to I2s instance register area
 ** \param [in] pstcConfig      I2S configuration parameters
 **
 ** \return - Ok on successful init
 **         - ErrorInvalidParameter if bit rate is 0 or pointers are NULL
 *****************************************************************************/
en_result_t I2s_Init(volatile stc_i2sn_t* pstcI2s,
                     const stc_i2s_config_t* pstcConfig)
{
    stc_i2s_intern_data_t* pstcI2sInternData ; 
    uint8_t clockdiv;
    boolean_t bStereoMode;  
    
    // Check for valid pointers
    if ( pstcI2s == NULL )
    {
        return ErrorInvalidParameter ;
    }
  
    // Get ptr to internal data struct
    pstcI2sInternData = I2sGetInternDataPtr( pstcI2s ) ;
    
    // Check for NULL
    if ( pstcI2sInternData == NULL )
    {
        return ErrorInvalidParameter ;
    }

    // Store the callback that shall be called within the interrupt routine in
    // the internal data structure.
    pstcI2sInternData->pfnInterruptCbFunction = pstcConfig->pfnCallback ;    
    
    // Disable I²s channel for configuration
    pstcI2s->unOPRREG.stcField.u1START = 0 ;     

    // Evaluate Mono/Stereo mode
    if ( pstcConfig->u8SampleRate >= I2sSampleRate22K05Stereo )
    {
         bStereoMode = TRUE ;
    }
    else
    {
         bStereoMode = FALSE ;
    }
      
    // Evaluation of sample rate settings dependent on clock source
    // Note: For those standard sample rates an adequate external clock source is recommended
    // 48KHz:             ext clock = 12,2880MHz
    // 44.1KHz/22.05KHz : ext clock = 11,2896MHz
    if ( pstcConfig->bExternalClock == TRUE )
    {
        switch( pstcConfig->u8SampleRate )
        {
            // bit clock = 12,288MHz / 8 = 1,536MHz --> Frame-Frequency: 1,536MHz/(2*16) = 48Khz
            case I2sSampleRate48KStereo: 
                clockdiv = 4;
            break;
        
           // bit clock = 11,2896MHz / 8 = 1,4112MHz --> Frame-Frequency: 1,4112MHz/(2*16) = 44.1Khz
            case I2sSampleRate44K1Stereo: 
                clockdiv = 4;
            break;

            // bit clock = 11,2896MHz / 16 = 0,7056MHz --> Frame-Frequency: 0,7056MHz/(2*16) = 22.05Khz
            case I2sSampleRate22K05Stereo: 
                clockdiv = 8;
            break;
            
            // bit clock = 12,288MHz / 8 = 1,536MHz --> Frame-Frequency: 1,536MHz/(2*16) = 48Khz
            case I2sSampleRate48KMono: 
                clockdiv = 4;
            break;
        
            // bit clock = 11,2896MHz / 8 = 1,4112MHz --> Frame-Frequency: 1,4112MHz/(2*16) = 44.1Khz
            case I2sSampleRate44K1Mono: 
                clockdiv = 4;
            break;
        
            // bit clock = 11,2896MHz / 16 = 0,7056MHz --> Frame-Frequency: 0,7056MHz/(2*16) = 22.05Khz
            case I2sSampleRate22K05Mono: 
                clockdiv = 8;
            break;
                
            default:
                clockdiv = 4;
            break;
        }
    }
   else
   {
     ; // Internal clock usage: Note, that the standard sample rates cannot be generated by the MCU 
   }
    
    // Clock divider configuration
    pstcI2s->unCNTREG.stcField.u6CKRT  =  clockdiv ;  
    // Output data in case of Invalid/Empty Frame
    pstcI2s->unCNTREG.stcField.u1MSKB  =  0 ;
    // Master - Slave configuration 
    pstcI2s->unCNTREG.stcField.u1MSMD = (FALSE == pstcConfig->bMasterMode) ? 0 : 1 ;    
    // Number of Subframe constructions
    pstcI2s->unCNTREG.stcField.u1SBFN  =  pstcConfig->eFrameConstuction ;
    // Word construction of FIFO (one 32bit word or two 16bit half words
    pstcI2s->unCNTREG.stcField.u1RHLL  =  pstcConfig->u8OneWordOrTwoHalfWordConstruct ; 
    // Clock source selector (internal clock CLK_PERI4_PD2 or external clock ECLK)
    pstcI2s->unCNTREG.stcField.u1ECKM = (FALSE == pstcConfig->bExternalClock) ? 0 : 1 ;     
    // Bit extension
    pstcI2s->unCNTREG.stcField.u1BEXT  =  pstcConfig->u8BitExtendByZeroOrSign ; 
    // Output Mode of Frame Synchronous Signal
    pstcI2s->unCNTREG.stcField.u1FRUN  =  pstcConfig->u8OutputModeOfFrameSignal ; 
    // Shifting order
    pstcI2s->unCNTREG.stcField.u1MSLB  =  pstcConfig->u8ShiftingOrder ; 
    // Sampling point of data reception
    pstcI2s->unCNTREG.stcField.u1SMPL  =  pstcConfig->u8SamplingPoint ; 
    // Clock polarity
    pstcI2s->unCNTREG.stcField.u1CPOL  =  pstcConfig->u8ClockPolarity ; 
    // Frame Sync Phase
    pstcI2s->unCNTREG.stcField.u1FSPH  =  pstcConfig->u8FrameSyncPhase ; 
    // Frame Sync Pulse Width
    pstcI2s->unCNTREG.stcField.u1FSLN  =  pstcConfig->u8FrameSyncPulseWidth ; 
    // Frame Sync Polarity
    pstcI2s->unCNTREG.stcField.u1FSPL  =  pstcConfig->u8FrameSyncPolarity ; 

    // in case of a mono signal one channel will be filled with overhead bits
    if ( FALSE == bStereoMode )    
    {
        // Number of overhead bits for generating mono frame data.
        pstcI2s->unCNTREG.stcField.u10OVHD =  pstcConfig->stc_SubFrameConfig0.u8SubframeNWordLength + 1 ; 
    }
    else
    {
        // No overhead bits in standard stereo format 
        pstcI2s->unCNTREG.stcField.u10OVHD =  0x0 ; 
    }    
    
    // Configuration for Sub Frame 0
    pstcI2s->unMCR0REG.stcField.u5S0CHN  =  pstcConfig->stc_SubFrameConfig0.u8SubframeNChNumber ; 
    pstcI2s->unMCR0REG.stcField.u5S0WDL  =  pstcConfig->stc_SubFrameConfig0.u8SubframeNWordLength ;   
    pstcI2s->unMCR0REG.stcField.u5S0CHL  =  pstcConfig->stc_SubFrameConfig0.u8SubframeNChLength ; 

    // Configuration for Sub Frame 1
    pstcI2s->unMCR0REG.stcField.u5S1CHN  =  pstcConfig->stc_SubFrameConfig1.u8SubframeNChNumber ; 
    pstcI2s->unMCR0REG.stcField.u5S1CHL  =  pstcConfig->stc_SubFrameConfig1.u8SubframeNChLength ; 
    pstcI2s->unMCR0REG.stcField.u5S1WDL  =  pstcConfig->stc_SubFrameConfig1.u8SubframeNWordLength ; 

    return Ok ;
    
}  /* I2s_Init */

/**
 *****************************************************************************
 ** \brief Start of a I2S module.
 **      
 ** This Function Starts the I2S Commincation. 
 **
 ** \pre I2s_Init() must be called
 **
 ** \param [in]  pstcI2s                Pointer to I2C instance register area
 **
 ** \retval Ok                          Communication started  successfully
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **         - pstcI2s == NULL
 ** 
*****************************************************************************/
en_result_t I2s_Start(volatile stc_i2sn_t* pstcI2s)
{
    // Check for valid pointers
    if ( pstcI2s == NULL )
    {
        return ErrorInvalidParameter ;
    }

    // Start I2s
    pstcI2s->unOPRREG.stcField.u1START  = 1 ;
    
    return Ok ;
} /* I2s_Start */


/**
 *****************************************************************************
 ** \brief Write data to I2S transmission register
 **      
 ** \pre I2s_Init() and I2s_Start() must be called
 **
 ** \param [in] pstcI2s           Pointer to register area of a I2S unit.
 ** \param [in] i2sdata           Data to be send.
 **
 ** \retval Ok                          Communication started  successfully
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **         - pstcI2s == NULL
 ** 
*****************************************************************************/
en_result_t I2s_WriteData(volatile stc_i2sn_t* pstcI2s,
                          uint32_t i2sdata)
{
    // Check for valid pointers
    if ( pstcI2s == NULL )
    {
        return ErrorInvalidParameter ;
    }
    
    // Write the data to  Transmission FIFO Data Register
    pstcI2s->unTXFDAT0.u32Register = i2sdata ;
    
    return Ok ;
    
 } /* I2s_WriteData */


/**
 *****************************************************************************
 ** \brief Enables I2S Channel for subframe 0
 **      
 ** This Function Starts the I2S Commincation. 
 **
 ** \pre I2s_Init() must be called
 **
 ** \param [in] pstcI2s           Pointer to register area of a I2S unit.
 ** \param [in] channel           Channel(s) to be enabled.
 **
 ** \retval Ok                          Communication started  successfully
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **         - pstcI2s == NULL
 ** 
*****************************************************************************/
en_result_t I2s_EnableSubframe0Channel(volatile stc_i2sn_t* pstcI2s,
                                       en_i2s_channel_t channel)
{   
    // Check for valid pointers
    if ( pstcI2s == NULL )
    {
        return ErrorInvalidParameter ;
    }
     
    pstcI2s->unMCR1REG.u32Register |= (uint32_t)channel ;

    return Ok ;
    
} /* I2s_Subframe0ChannelEnable */

/**
 *****************************************************************************
 ** \brief Disables I2S Channel for subframe 0
 **      
 ** This Function closes the I2S Commincation. 
 **
 ** \pre I2s_Init() must be called
 **
 ** \param [in] pstcI2s           Pointer to register area of a I2S unit.
 ** \param [in] channel           Channel(s) to be disabled.
 **
 ** \retval Ok                          Communication closed  successfully
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **         - pstcI2s == NULL
 ** 
*****************************************************************************/
en_result_t I2s_DisableSubframe0Channel(volatile stc_i2sn_t* pstcI2s,
                                        en_i2s_channel_t channel)
{   
    // Check for valid pointers
    if ( pstcI2s == NULL )
    {
        return ErrorInvalidParameter ;
    }
   
    pstcI2s->unMCR1REG.u32Register &= ~(uint32_t)channel ;

    return Ok ;
    
} /* I2s_Subframe0ChannelDisable */


/**
 *****************************************************************************
 ** \brief Enables I2S Channel for subframe 1
 **      
 ** \pre I2s_Init() and I2s_Start() must be called
 **
 ** \param [in] pstcI2s           Pointer to register area of a I2S unit.
 ** \param [in] channel           Channel(s) to be enabled.
 **
 ** \retval Ok                         Enabled  successfully
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **         - pstcI2s == NULL
 ** 
*****************************************************************************/
en_result_t I2s_EnableSubframe1Channel(volatile stc_i2sn_t* pstcI2s,
                                       en_i2s_channel_t channel)
{   
    // Check for valid pointers
    if ( pstcI2s == NULL )
    {
        return ErrorInvalidParameter ;
    }
    
    pstcI2s->unMCR2REG.u32Register |= (uint32_t)channel ;

    return Ok ;
    
} /* I2s_Subframe1ChannelEnable */

/**
 *****************************************************************************
 ** \brief Disables I2S Channel for subframe 1
 **      
 ** \pre I2s_Init() and I2s_Start() must be called
 **
 ** \param [in] pstcI2s           Pointer to register area of a I2S unit.
 ** \param [in] channel           Channel(s) to be disabled.
 **
 ** \retval Ok                         Disabled  successfully
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **         - pstcI2s == NULL
 ** 
*****************************************************************************/
en_result_t I2s_DisableSubframe1Channel(volatile stc_i2sn_t* pstcI2s,
                                        en_i2s_channel_t channel)
{   
    // Check for valid pointers
    if ( pstcI2s == NULL )
    {
        return ErrorInvalidParameter ;
    }

    pstcI2s->unMCR2REG.u32Register &= ~(uint32_t)channel ;

    return Ok ;
    
} /* I2s_Subframe1ChannelDisable */

/**
 *****************************************************************************
 ** \brief Enables I2S Receiver
 **      
 ** \pre I2s_Init() and I2s_Start() must be called
 **
 ** \param [in] pstcI2s           Pointer to register area of a I2S unit.
 **
 ** \retval Ok                         Enabled  successfully
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **         - pstcI2s == NULL
 ** 
*****************************************************************************/
en_result_t I2s_EnableReceiver(volatile stc_i2sn_t* pstcI2s)
{
    // Check for valid pointers
    if ( pstcI2s == NULL )
    {
        return ErrorInvalidParameter ;
    }
    
    // Enable functions of receiving operation
    pstcI2s->unOPRREG.stcField.u1RXENB = 1 ;
    
    // Receiver Enable 
    pstcI2s->unCNTREG.stcField.u1RXDIS = 0 ;

    return Ok;
    
} /* I2s_ReceiverEnable */

/**
 *****************************************************************************
 ** \brief Disables I2S Receiver
 **      
 ** \pre I2s_Init() and I2s_Start() must be called
 **
 ** \param [in] pstcI2s           Pointer to register area of a I2S unit.
 **
 ** \retval Ok                         Disabled  successfully
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **         - pstcI2s == NULL
 ** 
*****************************************************************************/
en_result_t I2s_DisableReceiver(volatile stc_i2sn_t* pstcI2s)
{
    // Check for valid pointers
    if ( pstcI2s == NULL )
    {
        return ErrorInvalidParameter ;
    }
    
    // Disable functions of receiving operation
    pstcI2s->unOPRREG.stcField.u1RXENB = 0 ;
    
    // Receiver Disable 
    pstcI2s->unCNTREG.stcField.u1RXDIS = 1 ;
    
    return Ok;
    
} /* I2s_ReceiverDisable */

/**
 *****************************************************************************
 ** \brief Enables I2S Transmitter
 **      
 ** \pre I2s_Init() and I2s_Start() must be called
 **
 ** \param [in] pstcI2s           Pointer to register area of a I2S unit.
 **
 ** \retval Ok                         Enabled  successfully
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **         - pstcI2s == NULL
 ** 
*****************************************************************************/
en_result_t I2s_EnableTransmitter(volatile stc_i2sn_t* pstcI2s)
{
    // Check for valid pointers
    if ( pstcI2s == NULL )
    {
        return ErrorInvalidParameter ;
    }
    
    // Enable functions of Transmitter operation
    pstcI2s->unOPRREG.stcField.u1TXENB = 1 ;
    
     // Transmitter Enable 
    pstcI2s->unCNTREG.stcField.u1TXDIS = 0 ;  

    return Ok;
    
} /* I2s_TransmitterEnable */

/**
 *****************************************************************************
 ** \brief Disables I2S Transmitter
 **      
 ** \pre I2s_Init() and I2s_Start() must be called
 **
 ** \param [in] pstcI2s           Pointer to register area of a I2S unit.
 **
 ** \retval Ok                         Disabled  successfully
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **         - pstcI2s == NULL
 ** 
*****************************************************************************/
en_result_t I2s_DisableTransmitter(volatile stc_i2sn_t* pstcI2s)
{
    // Check for valid pointers
    if ( pstcI2s == NULL )
    {
        return ErrorInvalidParameter ;
    }
    
    // Disable functions of Transmitter operation
    pstcI2s->unOPRREG.stcField.u1TXENB = 0 ;
    
    // Transmitter Disable 
    pstcI2s->unCNTREG.stcField.u1TXDIS = 1 ;  
    
    return Ok;
    
} /* I2s_TransmitterDisable */

/**
 *****************************************************************************
 ** \brief Deinitializes the I2S module.
 **
 ** Any pending transmission or receiption will be aborted and all I2S related
 ** registers are reset to their default values.
 **
 ** \param [in] pstcI2s           Pointer to register area of a I2S unit.
 **
 ** \retval Ok                    on successful init
 ** \retval ErrorInvalidParameter if invalid instance pointer; 
 *****************************************************************************/
en_result_t I2s_DeInit( volatile stc_i2sn_t* pstcI2s )
{

    // Check for valid pointers
    if ( pstcI2s == NULL )
    {
        return ErrorInvalidParameter ;
    }
        
    // Get ptr to internal data struct
    stc_i2s_intern_data_t* pstcI2sInternData ; 
    pstcI2sInternData = I2sGetInternDataPtr( pstcI2s ) ;
    
    // Check for NULL
    if ( pstcI2sInternData == NULL )
    {
        return ErrorInvalidParameter ;
    }
    
    // Disable I2S channel for configuration
    pstcI2s->unOPRREG.stcField.u1START = 0 ;     

    // Reset CNTREG to initial values
    pstcI2s->unCNTREG.u32Register = 0x00000060;

    // Reset MCR0REG to initial value
    pstcI2s->unMCR0REG.u32Register = 0;

    // Disable all channels for Sub Frame 0   
    pstcI2s->unMCR1REG.u32Register  =  0 ; 

    // Disable all channels for Sub Frame 1
    pstcI2s->unMCR2REG.u32Register  =  0 ; 
        
    // Reset internal data for the instance
    // Clear the callback ISR
    pstcI2sInternData->pfnInterruptCbFunction  =  NULL;          
       
    return Ok ;
	
}  /* I2s_DeInit */

/**
 *****************************************************************************
 ** \brief Configures I2s for playing a sound via dma transfer.
 **
 ** \note The dma configuration must be done in application SW
 **
 ** \param [in] pstcI2s           Pointer to register area of a I2S unit.
 **
 ** \retval Ok                    on successful init
 ** \retval ErrorInvalidParameter if invalid instance pointer
 *****************************************************************************/
en_result_t I2s_ConfigureI2sSoundPlayViaDma(volatile stc_i2sn_t* pstcI2s)
{
    // Check for valid pointers
    if ( pstcI2s == NULL )
    {
        return ErrorInvalidParameter ;
    }
  
    pstcI2s->unINTCNT.stcField.u1TXFDM  = 0 ;
    
    // Tx FIFO thresold 
    pstcI2s->unINTCNT.stcField.u4TFTH   = 0xF ;
    
    // Transfer DMA enable 1 = enable; 0 = disable
    pstcI2s->unDMAACT.stcField.u1TDMACT = 1 ;
    
    // Start I2s
    pstcI2s->unOPRREG.stcField.u1START  = 1 ;
    
    return Ok ;    
    
}  /* I2s_PlaySoundInit */

/**
 *****************************************************************************
 ** \brief Enable of I2S Dma transmission channel 
 **      
 ** \pre I2s_Init() and I2s_Start() must be called
 **
 ** \param [in] pstcI2s           Pointer to register area of a I2S unit.
 **
 ** \retval Ok                         Enabled  successfully
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **         - pstcI2s == NULL
 ** 
*****************************************************************************/
en_result_t I2s_EnableDma(volatile stc_i2sn_t* pstcI2s)
{
    // Check for valid pointers
    if ( pstcI2s == NULL )
    {
        return ErrorInvalidParameter ;
    }
    
    // Enable DMA transmission channel 
    pstcI2s->unDMAACT.stcField.u1TDMACT = 1 ;
    
    return Ok;
    
} /* I2s_DmaEnable */

/**
 *****************************************************************************
 ** \brief Disable of I2S Dma transmission channel 
 **      
 ** \pre I2s_Init() and I2s_Start() must be called
 **
 ** \param [in] pstcI2s           Pointer to register area of a I2S unit.
 **
 ** \retval Ok                         Enabled  successfully
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **         - pstcI2s == NULL
 ** 
*****************************************************************************/
en_result_t I2s_DisableDma(volatile stc_i2sn_t* pstcI2s)
{
    // Check for valid pointers
    if ( pstcI2s == NULL )
    {
        return ErrorInvalidParameter ;
    }
    
    // Disable DMA transmission channel 
    pstcI2s->unDMAACT.stcField.u1TDMACT = 0 ;
    
    return Ok;
    
} /* I2s_DmaDisable */

/**
 *****************************************************************************
 ** \brief This function waits until enough space in I2s transmission FiFo is 
 **        available. No timeout is generated!   
 ** \pre I2s_Init() and I2s_Start() must be called
 **
 ** \param [in] pstcI2s           Pointer to register area of a I2S unit.
 **
 ** \retval Ok                         Enabled  successfully
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **         - pstcI2s == NULL
 ** 
*****************************************************************************/
en_result_t I2s_WaitForEmptyTxFifoSpace(volatile stc_i2sn_t* pstcI2s)
{
    // Check for valid pointers
    if ( pstcI2s == NULL )
    {
        return ErrorInvalidParameter ;
    }
    
    // wait until Fifo empty space.
    while( 0 == pstcI2s->unSTATUS.stcField.u1TXFI )
    {
        // Maintain Watchdog
        PDL_WAIT_LOOP_HOOK();
    }

    return Ok;
    
} /* I2s_WaitForEmptyTxFifoSpace */
                                                        
/**
 *****************************************************************************
 ** \brief Enable or disable Tx Interupt
 **
 ** This Function Enables interupts if corresponding ISR are provided to 
 ** handle at the time of configuration.
 ** \pre  Bt_PpgInit() must have run before.
 **
 ** \param [in]  pstcPpg                   Pointer to PPG instance register area
 ** \param [in]  bMaskEmptyFifo            1=> interupt is masked to cpu
 **                                        0 => interupt is not masked to cpu
 **
 ** \retval Ok                             Interrupt Enabled successfully
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **         - pstcPpg == NULL
 **         - pstcInternData == NULL
 **
 *****************************************************************************/
extern en_result_t I2s_EnableOrDisableTxInterupt(volatile stc_i2sn_t* pstcI2s,
                                                boolean_t bMaskEmptyFifo)
{
  
    // Check for valid pointers
    if ( pstcI2s == NULL )
    {
        return ErrorInvalidParameter ;
    }
    
    // Get ptr to internal data struct 
    stc_i2s_intern_data_t* pstcI2sInternData ; 
    pstcI2sInternData = I2sGetInternDataPtr( pstcI2s ) ;
    
    // Check for NULL pointer
    if ( pstcI2sInternData == NULL )
    {
        return ErrorInvalidParameter ;
    }

    // Enable interupts
    if (( pstcI2sInternData->pfnInterruptCbFunction != NULL ))
    {
        // enable FIFO interrupt 
        // bEnableEmptyFifo=1 => Interrupt to CPU by I2Sn_STATUS:TXFI is masked 
        pstcI2s->unINTCNT.stcField.u1TXFIM = !bMaskEmptyFifo;
    }
    
    return Ok;
}


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