/*
 *  Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ 
 *  
 *  Redistribution and use in source and binary forms, with or without 
 *  modification, are permitted provided that the following conditions 
 *  are met:
 *
 *    Redistributions of source code must retain the above copyright 
 *    notice, this list of conditions and the following disclaimer.
 *
 *    Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the 
 *    documentation and/or other materials provided with the   
 *    distribution.
 *
 *    Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *  
 */
//*****************************************************************************
//
//  i2s.c
//
//  Driver for the I2S interface.
//
//*****************************************************************************

//*****************************************************************************
//
//! \addtogroup I2S_api
//! @{
//
//*****************************************************************************
#include "inc/hw_types.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_mcasp.h"
#include "inc/hw_apps_config.h"
#include "interrupt.h"
#include "i2s.h"

//*****************************************************************************
// Macros
//*****************************************************************************
#define MCASP_GBL_RCLK		0x00000001
#define MCASP_GBL_RHCLK		0x00000002
#define MCASP_GBL_RSER		0x00000004
#define MCASP_GBL_RSM		0x00000008
#define MCASP_GBL_RFSYNC	0x00000010
#define MCASP_GBL_XCLK		0x00000100
#define MCASP_GBL_XHCLK		0x00000200
#define MCASP_GBL_XSER		0x00000400
#define MCASP_GBL_XSM		0x00000800
#define MCASP_GBL_XFSYNC	0x00001000


//*****************************************************************************
//
//! \internal
//! Releases the specifed submodule out of reset.
//!
//! \param ulBase is the base address of the I2S module.
//! \param ulFlag is one of the valid sub module.
//!
//! This function Releases the specifed submodule out of reset.
//!
//! \return None.
//
//*****************************************************************************
static void I2SGBLEnable(unsigned long ulBase, unsigned long ulFlag)
{
  unsigned long ulReg;

  //
  // Read global control register
  //
  ulReg = HWREG(ulBase + MCASP_O_GBLCTL);

  //
  // Remove the sub modules reset as specified by ulFlag parameter
  //
  ulReg |= ulFlag;

  //
  // Write the configuration
  //
  HWREG(ulBase + MCASP_O_GBLCTL) = ulReg;

  //
  // Wait for write completeion
  //
  while(HWREG(ulBase + MCASP_O_GBLCTL) != ulReg)
  {

  }

}

//*****************************************************************************
//
//! Enables transmit and/or receive.
//!
//! \param ulBase is the base address of the I2S module.
//! \param ulMode is one of the valid modes.
//!
//! This function enables the I2S module in specified mode. The parameter
//! \e ulMode should be one of the following
//!
//! -\b I2S_MODE_TX_ONLY
//! -\b I2S_MODE_TX_RX_SYNC
//!
//! \return None.
//
//*****************************************************************************
void I2SEnable(unsigned long ulBase, unsigned long ulMode)
{
  //
  // FSYNC and Bit clock are output only in master mode
  //
  if( HWREG(ulBase + MCASP_O_ACLKXCTL) & 0x20)
  {
    //
    // Set FSYNC anc BitClk as output
    //
    HWREG(ulBase + MCASP_O_PDIR) |= 0x14000000;
  }


  if(ulMode & 0x2)
  {
    //
    // Remove Rx HCLK reset
    //
    I2SGBLEnable(ulBase, MCASP_GBL_RHCLK);

    //
    // Remove Rx XCLK reset
    //
    I2SGBLEnable(ulBase, MCASP_GBL_RCLK);

    //
    // Enable Rx SERDES(s)
    //
    I2SGBLEnable(ulBase, MCASP_GBL_RSER);

    //
    // Enable Rx state machine
    //
    I2SGBLEnable(ulBase, MCASP_GBL_RSM);

    //
    // Enable FSync generator
    //
    I2SGBLEnable(ulBase, MCASP_GBL_RFSYNC);
  }


  //
  // Remove Tx  HCLK reset
  //
  I2SGBLEnable(ulBase, MCASP_GBL_XHCLK);

  //
  // Remove Tx XCLK reset
  //
  I2SGBLEnable(ulBase, MCASP_GBL_XCLK);


  if(ulMode & 0x1)
  {
    //
    // Enable Tx SERDES(s)
    //
    I2SGBLEnable(ulBase, MCASP_GBL_XSER);

    //
    // Enable Tx state machine
    //
    I2SGBLEnable(ulBase, MCASP_GBL_XSM);
  }

   //
   // Enable FSync generator
   //
   I2SGBLEnable(ulBase, MCASP_GBL_XFSYNC);
}

//*****************************************************************************
//
//! Disables transmit and/or receive.
//!
//! \param ulBase is the base address of the I2S module.
//!
//! This function disables transmit and/or receive from I2S module.
//!
//! \return None.
//
//*****************************************************************************
void I2SDisable(unsigned long ulBase)
{
  //
  // Reset all sub modules
  //
  HWREG(ulBase + MCASP_O_GBLCTL) = 0;

  //
  // Wait for write to complete
  //
  while( HWREG(ulBase + MCASP_O_GBLCTL) != 0)
  {

  }
}

//*****************************************************************************
//
//! Waits to send data over the specified data line
//!
//! \param ulBase is the base address of the I2S module.
//! \param ulDataLine is one of the valid data lines.
//! \param ulData is the data to be transmitted.
//!
//! This function sends the \e ucData to the transmit register for the
//! specified data line. If there is no space available, this
//! function waits until there is space available before returning.
//!
//! \return None.
//
//*****************************************************************************
void I2SDataPut(unsigned long ulBase, unsigned long ulDataLine,
                unsigned long ulData)
{
  //
  // Compute register the offeset
  //
  ulDataLine = (ulDataLine-1) << 2;

  //
  // Wait for free space in fifo
  //
  while(!( HWREG(ulBase + MCASP_O_TXSTAT) & MCASP_TXSTAT_XDATA))
  {

  }

  //
  // Write Data into the FIFO
  //
  HWREG(ulBase + MCASP_O_TXBUF0 + ulDataLine) = ulData;
}

//*****************************************************************************
//
//! Sends data over the specified data line
//!
//! \param ulBase is the base address of the I2S module.
//! \param ulDataLine is one of the valid data lines.
//! \param ulData is the data to be transmitted.
//!
//! This function writes the \e ucData to the transmit register for
//! the specified data line. This function does not block, so if there is no
//! space available, then \b -1 is returned, and the application must retry the
//! function later.
//!
//! \return Returns 0 on success, -1 otherwise.
//
//*****************************************************************************
long I2SDataPutNonBlocking(unsigned long ulBase,  unsigned long ulDataLine,
                           unsigned long ulData)
{

  //
  // Compute register the offeset
  //
  ulDataLine = (ulDataLine-1) << 2;

  //
  // Send Data if fifo has free space
  //
  if( HWREG(ulBase + MCASP_O_TXSTAT) & MCASP_TXSTAT_XDATA)
  {
    //
    // Write data into the FIFO
    //
    HWREG(ulBase + MCASP_O_TXBUF0 + ulDataLine) = ulData;
    return 0;
  }

  //
  // FIFO is full
  //
  return(-1);
}

//*****************************************************************************
//
//! Waits for data from the specified data line.
//!
//! \param ulBase is the base address of the I2S module.
//! \param ulDataLine is one of the valid data lines.
//! \param pulData is pointer to receive data variable.
//!
//! This function gets data from the receive register for the specified
//! data line. If there are no data available, this function waits until a
//! receive before returning.
//!
//! \return None.
//
//*****************************************************************************
void I2SDataGet(unsigned long ulBase, unsigned long ulDataLine,
                unsigned long *pulData)
{

  //
  // Compute register the offeset
  //
  ulDataLine = (ulDataLine-1) << 2;

  //
  // Wait for atleat on word in FIFO
  //
  while(!(HWREG(ulBase + MCASP_O_RXSTAT) & MCASP_RXSTAT_RDATA))
  {

  }

  //
  // Read the Data
  //
  *pulData = HWREG(ulBase + MCASP_O_RXBUF0 + ulDataLine);
}


//*****************************************************************************
//
//! Receives data from the specified data line.
//!
//! \param ulBase is the base address of the I2S module.
//! \param ulDataLine is one of the valid data lines.
//! \param pulData is pointer to receive data variable.
//!
//! This function gets data from the receive register for the specified
//! data line.
//!
//!
//! \return Returns 0 on success, -1 otherwise.
//
//*****************************************************************************
long I2SDataGetNonBlocking(unsigned long ulBase, unsigned long ulDataLine,
                unsigned long *pulData)
{

  //
  // Compute register the offeset
  //
  ulDataLine = (ulDataLine-1) << 2;

  //
  // Check if data is available in FIFO
  //
  if(HWREG(ulBase + MCASP_O_RXSTAT) & MCASP_RXSTAT_RDATA)
  {
    //
    // Read the Data
    //
    *pulData = HWREG(ulBase + MCASP_O_RXBUF0 + ulDataLine);
    return 0;
  }

  //
  // FIFO is empty
  //
  return -1;
}


//*****************************************************************************
//
//! Sets the configuration of the I2S module.
//!
//! \param ulBase is the base address of the I2S module.
//! \param ulI2SClk is the rate of the clock supplied to the I2S module.
//! \param ulBitClk is the desired bit rate.
//! \param ulConfig is the data format.
//!
//! This function configures the I2S for operation in the specified data
//! format.  The bit rate is provided in the \e ulBitClk parameter and the data
//! format in the \e ulConfig parameter.
//!
//! The \e ulConfig parameter is the logical OR of three values: the slot size
//! the data read/write port select, Master or Slave mode
//!
//! Follwoing selects the Master-Slave mode
//! -\b I2S_MODE_MASTER
//! -\b I2S_MODE_SLAVE
//!
//! Following selects the slot size:
//! -\b I2S_SLOT_SIZE_24
//! -\b I2S_SLOT_SIZE_16
//!
//! Following selects the data read/write port:
//! -\b I2S_PORT_DMA
//! -\b I2S_PORT_CPU
//!
//! \return None.
//
//*****************************************************************************
void I2SConfigSetExpClk(unsigned long ulBase, unsigned long ulI2SClk,
                               unsigned long ulBitClk, unsigned long ulConfig)
{
  unsigned long ulHClkDiv;
  unsigned long ulClkDiv;
  unsigned long ulSlotSize;
  unsigned long ulBitMask;

  //
  // Calculate clock dividers
  //
  ulHClkDiv = ((ulI2SClk/ulBitClk)-1);
  ulClkDiv  = 0;

  //
  // Check if HCLK divider is overflowing
  //
  if(ulHClkDiv > 0xFFF)
  {
    ulHClkDiv = 0xFFF;

    //
    // Calculate clock divider
    //
    ulClkDiv = ((ulI2SClk/(ulBitClk * (ulHClkDiv + 1))) & 0x1F);
  }

  //
  //
  //
  ulClkDiv = ((ulConfig & I2S_MODE_SLAVE )?0x80:0xA0|ulClkDiv);

  HWREG(ulBase + MCASP_O_ACLKXCTL) = ulClkDiv;

  HWREG(ulBase + MCASP_O_AHCLKXCTL) = (0x8000|ulHClkDiv);

  //
  // Write the Tx format register
  //
  HWREG(ulBase + MCASP_O_TXFMT) = (0x18000 | (ulConfig & 0x7FFF));

  //
  // Write the Rx format register
  //
  HWREG(ulBase + MCASP_O_RXFMT) = (0x18000 | ((ulConfig >> 16) &0x7FFF));

  //
  // Check if in master mode
  //
  if( ulConfig & I2S_MODE_SLAVE)
  {
    //
    // Configure Tx FSync generator in I2S mode
    //
    HWREG(ulBase + MCASP_O_TXFMCTL) = 0x111;

    //
    // Configure Rx FSync generator in I2S mode
    //
    HWREG(ulBase + MCASP_O_RXFMCTL) = 0x111;
  }
  else
  {
    //
    // Configure Tx FSync generator in I2S mode
    //
    HWREG(ulBase + MCASP_O_TXFMCTL) = 0x113;

    //
    // Configure Rx FSync generator in I2S mode
    //
    HWREG(ulBase + MCASP_O_RXFMCTL) = 0x113;
  }

  //
  // Compute Slot Size
  //
  ulSlotSize = ((((ulConfig & 0xFF) >> 4) + 1) * 2);

  //
  // Creat the bit mask
  //
  ulBitMask = (0xFFFFFFFF >> (32 - ulSlotSize));

  //
  // Set Tx bit valid mask
  //
  HWREG(ulBase + MCASP_O_TXMASK) = ulBitMask;

  //
  // Set Rx bit valid mask
  //
  HWREG(ulBase + MCASP_O_RXMASK) = ulBitMask;

  //
  // Set Tx slot valid mask
  //
  HWREG(ulBase + MCASP_O_TXTDM) = 0x3;

  //
  // Set Rx slot valid mask
  //
  HWREG(ulBase + MCASP_O_RXTDM) = 0x3;
}

//*****************************************************************************
//
//! Configure and enable transmit FIFO.
//!
//! \param ulBase is the base address of the I2S module.
//! \param ulTxLevel is the transmit FIFO DMA request level.
//! \param ulWordsPerTransfer is the nuber of words transferred from the FIFO.
//!
//! This function configures and enable I2S transmit FIFO.
//!
//! The parameter \e ulTxLevel sets the level at which transmit DMA requests
//! are generated. This should be non-zero integer multiple of number of
//! serializers enabled as transmitters
//!
//! The parameter \e ulWordsPerTransfer sets the number of words that are
//! transferred from the transmit FIFO to the data line(s). This value must
//! equal the number of serializers used as transmitters.
//!
//! \return None.
//
//*****************************************************************************
void I2STxFIFOEnable(unsigned long ulBase, unsigned long ulTxLevel,
                     unsigned long ulWordsPerTransfer)
{
  //
  // Set transmit FIFO configuration and
  // enable it
  //
  HWREG(ulBase + MCASP_0_WFIFOCTL) = ((1 <<16) | ((ulTxLevel & 0xFF) << 8)
					| (ulWordsPerTransfer & 0x1F));

}

//*****************************************************************************
//
//! Disables transmit FIFO.
//!
//! \param ulBase is the base address of the I2S module.
//!
//! This function disables the I2S transmit FIFO.
//!
//! \return None.
//
//*****************************************************************************
void I2STxFIFODisable(unsigned long ulBase)
{
  //
  // Disable transmit FIFO.
  //
  HWREG(ulBase + MCASP_0_WFIFOCTL) = 0;
}

//*****************************************************************************
//
//! Configure and enable receive FIFO.
//!
//! \param ulBase is the base address of the I2S module.
//! \param ulRxLevel is the receive FIFO DMA request level.
//! \param ulWordsPerTransfer is the nuber of words transferred from the FIFO.
//!
//! This function configures and enable I2S receive FIFO.
//!
//! The parameter \e ulRxLevel sets the level at which receive DMA requests
//! are generated. This should be non-zero integer multiple of number of
//! serializers enabled as receivers.
//!
//! The parameter \e ulWordsPerTransfer sets the number of words that are
//! transferred to the receive FIFO from the data line(s). This value must
//! equal the number of serializers used as receivers.
//!
//! \return None.
//
//*****************************************************************************
void I2SRxFIFOEnable(unsigned long ulBase, unsigned long ulRxLevel,
                     unsigned long ulWordsPerTransfer)
{
  //
  // Set FIFO configuration
  //
  HWREG(ulBase + MCASP_0_RFIFOCTL) = ( (1 <<16) | ((ulRxLevel & 0xFF) << 8)
					| (ulWordsPerTransfer & 0x1F));

}

//*****************************************************************************
//
//! Disables receive FIFO.
//!
//! \param ulBase is the base address of the I2S module.
//!
//! This function disables the I2S receive FIFO.
//!
//! \return None.
//
//*****************************************************************************
void I2SRxFIFODisable(unsigned long ulBase)
{
  //
  // Disable receive FIFO.
  //
  HWREG(ulBase + MCASP_0_RFIFOCTL) = 0;
}

//*****************************************************************************
//
//! Get the transmit FIFO status.
//!
//! \param ulBase is the base address of the I2S module.
//!
//! This function gets the number of 32-bit words currently in the transmit
//! FIFO.
//!
//! \return Returns transmit FIFO status.
//
//*****************************************************************************
unsigned long I2STxFIFOStatusGet(unsigned long ulBase)
{
  //
  // Return transmit FIFO level
  //
  return HWREG(ulBase + MCASP_0_WFIFOSTS);
}

//*****************************************************************************
//
//! Get the receive FIFO status.
//!
//! \param ulBase is the base address of the I2S module.
//!
//! This function gets the number of 32-bit words currently in the receive
//! FIFO.
//!
//! \return Returns receive FIFO status.
//
//*****************************************************************************
unsigned long I2SRxFIFOStatusGet(unsigned long ulBase)
{
  //
  // Return receive FIFO level
  //
  return HWREG(ulBase + MCASP_0_RFIFOSTS);
}

//*****************************************************************************
//
//! Configure the serializer in specified mode.
//!
//! \param ulBase is the base address of the I2S module.
//! \param ulDataLine is the data line (serilizer) to be configured.
//! \param ulSerMode is the required serializer mode.
//! \param ulInActState sets the inactive state of the data line.
//!
//! This function configure and enable the serializer associated with the given
//! data line in specified mode.
//!
//! The paramenter \e ulDataLine selects to data line to be configured and
//! can be one of the following:
//! -\b I2S_DATA_LINE_0
//! -\b I2S_DATA_LINE_1
//!
//! The parameter \e ulSerMode can be one of the following:
//! -\b I2S_SER_MODE_TX
//! -\b I2S_SER_MODE_RX
//! -\b I2S_SER_MODE_DISABLE
//!
//! The parameter \e ulInActState can be one of the following
//! -\b I2S_INACT_TRI_STATE
//! -\b I2S_INACT_LOW_LEVEL
//! -\b I2S_INACT_LOW_HIGH
//!
//! \return Returns receive FIFO status.
//
//*****************************************************************************
void I2SSerializerConfig(unsigned long ulBase, unsigned long ulDataLine,
                         unsigned long ulSerMode, unsigned long ulInActState)
{
  if( ulSerMode == I2S_SER_MODE_TX)
  {
    //
    // Set the data line in output mode
    //
    HWREG(ulBase + MCASP_O_PDIR) |= ulDataLine;
  }
  else
  {
    //
    // Set the data line in input mode
    //
    HWREG(ulBase + MCASP_O_PDIR) &= ~ulDataLine;
  }

  //
  // Set the serializer configuration.
  //
  HWREG(ulBase + MCASP_O_XRSRCTL0 + ((ulDataLine-1) << 2))
                                            = (ulSerMode | ulInActState);
}

//*****************************************************************************
//
//! Enables individual I2S interrupt sources.
//!
//! \param ulBase is the base address of the I2S module.
//! \param ulIntFlags is the bit mask of the interrupt sources to be enabled.
//!
//! This function enables the indicated I2S interrupt sources.  Only the
//! sources that are enabled can be reflected to the processor interrupt;
//! disabled sources have no effect on the processor.
//!
//! The \e ulIntFlags parameter is the logical OR of any of the following:
//!
//! -\b I2S_INT_XUNDRN
//! -\b I2S_INT_XSYNCERR
//! -\b I2S_INT_XLAST
//! -\b I2S_INT_XDATA
//! -\b I2S_INT_XSTAFRM
//! -\b I2S_INT_XDMA
//! -\b I2S_INT_ROVRN
//! -\b I2S_INT_RSYNCERR
//! -\b I2S_INT_RLAST
//! -\b I2S_INT_RDATA
//! -\b I2S_INT_RSTAFRM
//! -\b I2S_INT_RDMA
//!
//! \return None.
//
//*****************************************************************************
void I2SIntEnable(unsigned long ulBase, unsigned long ulIntFlags)
{

  //
  // Enable DMA done interrupts
  //
  HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_MASK_CLR )
     |= ((ulIntFlags &0xC0000000) >> 20);

  //
  // Enable specific Tx Interrupts
  //
  HWREG(ulBase + MCASP_O_EVTCTLX) |= (ulIntFlags & 0xFF);

  //
  // Enable specific Rx Interrupts
  //
  HWREG(ulBase + MCASP_O_EVTCTLR) |= ((ulIntFlags >> 16) & 0xFF);
}

//*****************************************************************************
//
//! Disables individual I2S interrupt sources.
//!
//! \param ulBase is the base address of the I2S module.
//! \param ulIntFlags is the bit mask of the interrupt sources to be disabled.
//!
//! This function disables the indicated I2S interrupt sources.  Only the
//! sources that are enabled can be reflected to the processor interrupt;
//! disabled sources have no effect on the processor.
//!
//! The \e ulIntFlags parameter has the same definition as the \e ulIntFlags
//! parameter to I2SIntEnable().
//!
//! \return None.
//
//*****************************************************************************
void I2SIntDisable(unsigned long ulBase, unsigned long ulIntFlags)
{
  //
  // Disable DMA done interrupts
  //
  HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_MASK_SET)
     |= ((ulIntFlags &0xC0000000) >> 20);

  //
  // Disable specific Tx Interrupts
  //
  HWREG(ulBase + MCASP_O_EVTCTLX) &= ~(ulIntFlags & 0xFF);

  //
  // Disable specific Rx Interrupts
  //
  HWREG(ulBase + MCASP_O_EVTCTLR) &= ~((ulIntFlags >> 16) & 0xFF);
}


//*****************************************************************************
//
//! Gets the current interrupt status.
//!
//! \param ulBase is the base address of the I2S module.
//!
//! This function returns the raw interrupt status for I2S enumerated
//! as a bit field of values:
//! -\b I2S_STS_XERR
//! -\b I2S_STS_XDMAERR
//! -\b I2S_STS_XSTAFRM
//! -\b I2S_STS_XDATA
//! -\b I2S_STS_XLAST
//! -\b I2S_STS_XSYNCERR
//! -\b I2S_STS_XUNDRN
//! -\b I2S_STS_XDMA
//! -\b I2S_STS_RERR
//! -\b I2S_STS_RDMAERR
//! -\b I2S_STS_RSTAFRM
//! -\b I2S_STS_RDATA
//! -\b I2S_STS_RLAST
//! -\b I2S_STS_RSYNCERR
//! -\b I2S_STS_ROVERN
//! -\b I2S_STS_RDMA
//!
//! \return Returns the current interrupt status, enumerated as a bit field of
//! values described above.
//
//*****************************************************************************
unsigned long I2SIntStatus(unsigned long ulBase)
{
  unsigned long ulStatus;

  //
  // Get DMA interrupt status
  //
  ulStatus =
    HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_STS_RAW) << 20;

  ulStatus &= 0xC0000000;

  //
  // Read Tx Interrupt status
  //
  ulStatus |= HWREG(ulBase + MCASP_O_TXSTAT);

  //
  // Read Rx Interrupt status
  //
  ulStatus |= HWREG(ulBase + MCASP_O_RXSTAT) << 16;

  //
  // Return the status
  //
  return ulStatus;
}

//*****************************************************************************
//
//! Clears I2S interrupt sources.
//!
//! \param ulBase is the base address of the I2S module.
//! \param ulStatFlags is a bit mask of the interrupt sources to be cleared.
//!
//! The specified I2S interrupt sources are cleared, so that they no longer
//! assert.  This function must be called in the interrupt handler to keep the
//! interrupt from being recognized again immediately upon exit.
//!
//! The \e ulIntFlags parameter is the logical OR of any of the value
//! describe in I2SIntStatus().
//!
//! \return None.
//
//*****************************************************************************
void I2SIntClear(unsigned long ulBase, unsigned long ulStatFlags)
{
  //
  // Clear DMA done interrupts
  //
  HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_ACK)
     |= ((ulStatFlags &0xC0000000) >> 20);

  //
  // Clear Tx Interrupt
  //
  HWREG(ulBase + MCASP_O_TXSTAT) = ulStatFlags & 0x1FF ;

  //
  // Clear Rx Interrupt
  //
  HWREG(ulBase + MCASP_O_RXSTAT) = (ulStatFlags >> 16) & 0x1FF;
}

//*****************************************************************************
//
//! Registers an interrupt handler for a I2S interrupt.
//!
//! \param ulBase is the base address of the I2S module.
//! \param pfnHandler is a pointer to the function to be called when the
//! I2S interrupt occurs.
//!
//! This function does the actual registering of the interrupt handler.  This
//! function enables the global interrupt in the interrupt controller; specific
//! I2S interrupts must be enabled via I2SIntEnable().  It is the interrupt
//! handler's responsibility to clear the interrupt source.
//!
//! \sa IntRegister() for important information about registering interrupt
//! handlers.
//!
//! \return None.
//
//*****************************************************************************
void I2SIntRegister(unsigned long ulBase, void (*pfnHandler)(void))
{
  //
  // Register the interrupt handler
  //
  IntRegister(INT_I2S,pfnHandler);

  //
  // Enable the interrupt
  //
  IntEnable(INT_I2S);
}

//*****************************************************************************
//
//! Unregisters an interrupt handler for a I2S interrupt.
//!
//! \param ulBase is the base address of the I2S module.
//!
//! This function does the actual unregistering of the interrupt handler.  It
//! clears the handler to be called when a I2S interrupt occurs.  This
//! function also masks off the interrupt in the interrupt controller so that
//! the interrupt handler no longer is called.
//!
//! \sa IntRegister() for important information about registering interrupt
//! handlers.
//!
//! \return None.
//
//*****************************************************************************
void I2SIntUnregister(unsigned long ulBase)
{
  //
  // Disable interrupt
  //
  IntDisable(INT_I2S);

  //
  // Unregister the handler
  //
  IntUnregister(INT_I2S);

}

//*****************************************************************************
//
//! Set the active slots for Trasmitter
//!
//! \param ulBase is the base address of the I2S module.
//! \param ulActSlot is the bit-mask of activ slots
//!
//! This function sets the active slots for the transmitter. By default both
//! the slots are active. The parameter \e ulActSlot is logical OR follwoing
//! values:
//! -\b I2S_ACT_SLOT_EVEN
//! -\b I2S_ACT_SLOT_ODD
//!
//! \return None.
//
//*****************************************************************************
void I2STxActiveSlotSet(unsigned long ulBase, unsigned long ulActSlot)
{
   HWREG(ulBase + MCASP_O_TXTDM) = ulActSlot;
}

//*****************************************************************************
//
//! Set the active slots for Receiver
//!
//! \param ulBase is the base address of the I2S module.
//! \param ulActSlot is the bit-mask of activ slots
//!
//! This function sets the active slots for the receiver. By default both
//! the slots are active. The parameter \e ulActSlot is logical OR follwoing
//! values:
//! -\b I2S_ACT_SLOT_EVEN
//! -\b I2S_ACT_SLOT_ODD
//!
//! \return None.
//
//*****************************************************************************
void I2SRxActiveSlotSet(unsigned long ulBase, unsigned long ulActSlot)
{
   HWREG(ulBase + MCASP_O_RXTDM) = ulActSlot;
}

//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************
