/******************************************************************************

Copyright (C) 2013-2017, Fujitsu Electronics Europe GmbH or a               
subsidiary of Fujitsu Electronics Europe GmbH.  All rights reserved.        
                                                                            
This software, including source code, documentation and related             
materials ("Software"), is owned by Fujitsu Electronics Europe GmbH or      
one of its subsidiaries ("Fujitsu").
                                                                            
If no EULA applies, Fujitsu hereby grants you a personal, non-exclusive,    
non-transferable license to copy, modify, and compile the                   
Software source code solely for use in connection with Fujitsu'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 Fujitsu.      
                                                                            
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. Fujitsu reserves the right to make                      
changes to the Software without notice. Fujitsu does not assume any         
liability arising out of the application or use of the Software or any      
product or circuit described in the Software. Fujitsu does not              
authorize its products for use in any products where a malfunction or       
failure of the Fujitsu product may reasonably be expected to result in      
significant property damage, injury or death ("High Risk Product"). By      
including Fujitsu'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 Fujitsu against all liability.                       

 ******************************************************************************/
/******************************************************************************/
/** \file main.c
 **
 ** This example demonstrates with use of STGL5000 how to generate 
 ** I2S audio-output by use of two timer with one timer configured as pattern generator.
 **
 **  Connection:
 **  STGL5000   <->    Apollo3Blue  Function
 **  SYS_MCLK   <-     GPIO7        (Master Clock)
 **  I2S_SCLK    ->    GPIO25       (I2S Bit Clock)
 **  I2S_LRCLK   ->    GPIO13       (I2S Word-Select Clock)
 **  I2S_DIN    <-     GPIO25       (I2S Data)  
 **  CTRL_DATA  <->    GPIO9        (I2C SDA)
 **  CTRL_CLK   <->    GPIO8        (I2C SCL)
 **
 **  
 **                                 -----------        -----------  CLKOUT             PAD7
 **                                 |  HFRC   |________|  DIV4    |________________________   MCLK
 **                                 |  48MHz  |        |          |
 **                                 -----------        -----------
 **                 
 **        PAD25                                A0IN    --------------------
 **  BCLK  ___________________________________________|CLK                 |
 **                                                   |                    |  A0OUT    PAD25
 **                                                   |     CTIMER A0  OUT |________________  DOUT
 **                                                   |                    |
 **                                                  _|TRIGGER             |
 **        PAD13 B0IN   --------------------        |  ---------------------
 **  LRCLK ____________|CLK                 |       |   64-bit pattern generator
 **                    |                    | B0OUT |  
 **                    |     CTIMER B0  OUT |_______|      
 **                    |                    |          
 **                    |                    |          
 **                    ---------------------     
 **                     single-count
 **
 **
 **  Audio-Sequence by Manuel Schreiner, generated by iMachine 2
 **
 **
 ** History:
 **   - 2019-08-01 Manuel Schreiner First Version

 *****************************************************************************/
#define __MAIN_C__
/*****************************************************************************/
/* Include files                                                             */
/*****************************************************************************/
#include "mcu.h"
#include "base_types.h"
#include "string.h"


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

#define CHIP_ID				0x0000
#define CHIP_DIG_POWER			0x0002
#define CHIP_CLK_CTRL			0x0004
#define CHIP_I2S_CTRL			0x0006
#define CHIP_SSS_CTRL			0x000A
#define CHIP_ADCDAC_CTRL		0x000E
#define CHIP_DAC_VOL			0x0010
#define CHIP_PAD_STRENGTH		0x0014
#define CHIP_ANA_ADC_CTRL		0x0020
#define CHIP_ANA_HP_CTRL		0x0022
#define CHIP_ANA_CTRL			0x0024
#define CHIP_LINREG_CTRL		0x0026
#define CHIP_REF_CTRL			0x0028 
#define CHIP_MIC_CTRL			0x002A 
#define CHIP_LINE_OUT_CTRL		0x002C
#define CHIP_LINE_OUT_VOL		0x002E
#define CHIP_ANA_POWER			0x0030 
#define CHIP_PLL_CTRL			0x0032
#define CHIP_CLK_TOP_CTRL		0x0034
#define CHIP_ANA_STATUS			0x0036
#define CHIP_ANA_TEST1			0x0038 
#define CHIP_ANA_TEST2			0x003A 
#define CHIP_SHORT_CTRL			0x003C
#define DAP_CONTROL			0x0100
#define DAP_PEQ				0x0102
#define DAP_BASS_ENHANCE		0x0104
#define DAP_BASS_ENHANCE_CTRL		0x0106
#define DAP_AUDIO_EQ			0x0108
#define DAP_SGTL_SURROUND		0x010A
#define DAP_FILTER_COEF_ACCESS		0x010C
#define DAP_COEF_WR_B0_MSB		0x010E
#define DAP_COEF_WR_B0_LSB		0x0110
#define DAP_AUDIO_EQ_BASS_BAND0		0x0116 
#define DAP_AUDIO_EQ_BAND1		0x0118
#define DAP_AUDIO_EQ_BAND2		0x011A 
#define DAP_AUDIO_EQ_BAND3		0x011C 
#define DAP_AUDIO_EQ_TREBLE_BAND4	0x011E 
#define DAP_MAIN_CHAN			0x0120
#define DAP_MIX_CHAN			0x0122
#define DAP_AVC_CTRL			0x0124
#define DAP_AVC_THRESHOLD		0x0126
#define DAP_AVC_ATTACK			0x0128
#define DAP_AVC_DECAY			0x012A
#define DAP_COEF_WR_B1_MSB		0x012C
#define DAP_COEF_WR_B1_LSB		0x012E
#define DAP_COEF_WR_B2_MSB		0x0130
#define DAP_COEF_WR_B2_LSB		0x0132
#define DAP_COEF_WR_A1_MSB		0x0134
#define DAP_COEF_WR_A1_LSB		0x0136
#define DAP_COEF_WR_A2_MSB		0x0138
#define DAP_COEF_WR_A2_LSB		0x013A
#define SGTL5000_I2C_ADDR_CS_LOW	0x0A  // CTRL_ADR0_CS pin low (normal configuration)
#define SGTL5000_I2C_ADDR_CS_HIGH	0x2A // CTRL_ADR0_CS  pin high

#define MAX_FIFO_SIZE  64

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

#include "sample.c"

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

typedef enum en_i2c_mode
{
    I2CRead = 1,
    I2CWrite = 2
} en_i2c_mode_t;

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

static volatile uint32_t u32Counter;  //ms counter
static uint32_t u32DataPos = 0;
static uint32_t u32MaxData = sizeof(au8Data);



/*****************************************************************************/
/* Local function prototypes ('static')                                      */
/*****************************************************************************/
//interrupt prototype SysTick_Handler defined in startup file
//prototype main defined in startup file
void delay(uint32_t delayMs);




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


/**
 *****************************************************************************
 ** 
 **\brief Systick interrupt handler defined by CMSIS
 **
 *****************************************************************************/
void SysTick_Handler(void)
{
	u32Counter++;
}


/**
*********************************************************************************
** \brief delay function used with SysTick IRQ
**  
** \param [in] delayMs Delay in ms
**  
** \details delay function used with SysTick IRQ
**  
*********************************************************************************/
void delay(uint32_t delayMs)
{
    uint32_t u32End = u32Counter;
    u32End += delayMs;
    while(u32End != u32Counter) __NOP();
}



/**
*********************************************************************************
** \brief Transfer data via IOM as I2C
**  
** \param Handle         IOM handle, for example IOM1
**
** \param enMode         Mode: I2CRead, I2CWrite
** 
** \param u16Address     Device Address
**
** \param pu8Offset      pointer to up to 3 bytes can be sent as offset, NULL if not used
**
** \param u8OffsetLen    length of offset 0..3
** 
** \param bNoStop        if TRUE, no stop condition is sent
**
** \param au32Data       32-bit alligned data to be send
**
** \param u32LenBytes    size in bytes to transfer
**  
** \param pu32DataTransferred  pointer to data transferred variable
**  
*********************************************************************************/
void I2CTransfer(IOM0_Type* Handle, en_i2c_mode_t enMode, uint16_t u16Address, uint8_t* pu8Offset, uint8_t u8OffsetLen, boolean_t bNoStop, uint32_t* au32Data, uint32_t u32LenBytes, uint32_t* pu32DataTransferred)
{
    uint32_t u32Cmd;
    uint32_t u32Irqbackup;
    volatile uint32_t u32Timeout;
    int i;

    //
    // make sure interrupts are disabled before issuing commands
    //
    u32Irqbackup = Handle->INTEN;
    Handle->INTEN = 0;

    //
    // Clear all interrupt flags
    //
    Handle->INTCLR = 0xFFFFFFFF;

    Handle->DEVCFG_b.DEVADDR = u16Address;

    u32Cmd = 0;

    //
    //  Check I2C RW mode and prepare command mode
    //
    switch(enMode)
    {
        case I2CWrite:
           u32Cmd |= _VAL2FLD(IOM0_CMD_CMD,1);
           Handle->MSPICFG_b.FULLDUP = 0;
           if (u32LenBytes > MAX_FIFO_SIZE) u32LenBytes = MAX_FIFO_SIZE;
           break;
        case I2CRead:
           u32Cmd |= _VAL2FLD(IOM0_CMD_CMD,2);
           Handle->MSPICFG_b.FULLDUP = 0;
           if (u32LenBytes > MAX_FIFO_SIZE) u32LenBytes = MAX_FIFO_SIZE;
           break;
    }

    //
    //  prepare length of bytes to be transferred
    //
    u32Cmd |= _VAL2FLD(IOM0_CMD_TSIZE,u32LenBytes);

    //
    //  if offset is 1 and more bytes, write OFFSETLO field with first byte
    //
    if (u8OffsetLen > 0)
    {
        u32Cmd |= _VAL2FLD(IOM0_CMD_OFFSETLO,pu8Offset[0]);
    }

    //
    //  if offset is 2 and more bytes, write lower OFFSETHI register with second byte
    //
    if (u8OffsetLen > 1)
    {
        Handle->OFFSETHI = pu8Offset[1];
    }

    //
    //  if offset is 3 bytes, write higher OFFSETHI register with third byte
    //
    if (u8OffsetLen > 2)
    {
        Handle->OFFSETHI |= pu8Offset[2] << 8;
    }

    //
    //  Check if CS shall keep low after transmission
    //
    if (TRUE == bNoStop)
    {
        u32Cmd |= _VAL2FLD(IOM0_CMD_CONT,1);
    }

    //
    // Check fifo has to be filled
    //
    if (enMode == I2CWrite)
    {
        for(i = 0;i < (u32LenBytes/4);i++)
        {
            Handle->FIFOPUSH = au32Data[i];
        }
    }

    //
    //  Issue command
    //
    Handle->CMD = u32Cmd;

    //
    // Restore enabled IRQs
    //
    Handle->INTEN = u32Irqbackup;
    
    //
    //  wait until transaction starts
    //
    while((Handle->STATUS_b.IDLEST == 1) || (Handle->STATUS_b.CMDACT == 0)) __NOP(); 

    //
    //  wait finished
    //
    u32Timeout = 100000;
    while((Handle->STATUS_b.IDLEST == 0) || (Handle->STATUS_b.CMDACT == 1))
    {
        u32Timeout--;
        if (u32Timeout == 0) break;
    }

    //
    // Check fifo has to be read
    //
    if (enMode == I2CRead)
    {
        i = 0;
        while(Handle->FIFOPTR_b.FIFO1SIZ > 0)
        {
            au32Data[i] = Handle->FIFOPOP;
            i++;
            if (i > (u32LenBytes/4)) break;
        }
    }

    if (pu32DataTransferred != NULL) *pu32DataTransferred = i*4; 
}


/**
*********************************************************************************
** \brief Configure IOM as I2C
**  
** \param Handle             IOM handle, for example IOM1
**
** \param u32Frequency       Frequency
**
** \param b10BitAddresses    TRUE to enable 10-bit addressing (else 7-bit)
** 
*********************************************************************************/
void I2CConfig(IOM0_Type* Handle, uint32_t u32Frequency, boolean_t b10BitAddresses)
{
    uint32_t u32Cfg, u32ClkCfg;

    //
    // Power Control
    //
    switch((int)Handle)
    {
        case (int)IOM0:
            PWRCTRL->DEVPWREN &= ~(1 << PWRCTRL_DEVPWREN_PWRIOM0_Pos);
            PWRCTRL->DEVPWREN |= (1 << PWRCTRL_DEVPWREN_PWRIOM0_Pos);
            //IOM modules 0,1 and 2 are contained in HCPB, while IOM modules 3,4 and 5 are contained in HCPC power domain
            //for IOM0, wait HCPB comes stable
            while(PWRCTRL->DEVPWRSTATUS_b.HCPB == 0) __NOP();
            break;
        case (int)IOM1:
            PWRCTRL->DEVPWREN &= ~(1 << PWRCTRL_DEVPWREN_PWRIOM1_Pos);
            PWRCTRL->DEVPWREN |= (1 << PWRCTRL_DEVPWREN_PWRIOM1_Pos);
            //IOM modules 0,1 and 2 are contained in HCPB, while IOM modules 3,4 and 5 are contained in HCPC power domain
            //for IOM1, wait HCPB comes stable
            while(PWRCTRL->DEVPWRSTATUS_b.HCPB == 0) __NOP();
            break;
        case (int)IOM2:
            PWRCTRL->DEVPWREN &= ~(1 << PWRCTRL_DEVPWREN_PWRIOM2_Pos);
            PWRCTRL->DEVPWREN |= (1 << PWRCTRL_DEVPWREN_PWRIOM2_Pos);
            //IOM modules 0,1 and 2 are contained in HCPB, while IOM modules 3,4 and 5 are contained in HCPC power domain
            //for IOM2, wait HCPB comes stable
            while(PWRCTRL->DEVPWRSTATUS_b.HCPB == 0) __NOP();
            break;
        case (int)IOM3:
            PWRCTRL->DEVPWREN &= ~(1 << PWRCTRL_DEVPWREN_PWRIOM3_Pos);
            PWRCTRL->DEVPWREN |= (1 << PWRCTRL_DEVPWREN_PWRIOM3_Pos);
            //IOM modules 0,1 and 2 are contained in HCPB, while IOM modules 3,4 and 5 are contained in HCPC power domain
            //for IOM3, wait HCPB comes stable
            while(PWRCTRL->DEVPWRSTATUS_b.HCPC == 0) __NOP();
            break;
        case (int)IOM4:
            PWRCTRL->DEVPWREN &= ~(1 << PWRCTRL_DEVPWREN_PWRIOM4_Pos);
            PWRCTRL->DEVPWREN |= (1 << PWRCTRL_DEVPWREN_PWRIOM4_Pos);
            //IOM modules 0,1 and 2 are contained in HCPB, while IOM modules 3,4 and 5 are contained in HCPC power domain
            //for IOM4, wait HCPB comes stable
            while(PWRCTRL->DEVPWRSTATUS_b.HCPC == 0) __NOP();
            break;
        case (int)IOM5:
            PWRCTRL->DEVPWREN &= ~(1 << PWRCTRL_DEVPWREN_PWRIOM5_Pos);
            PWRCTRL->DEVPWREN |= (1 << PWRCTRL_DEVPWREN_PWRIOM5_Pos);
            //IOM modules 0,1 and 2 are contained in HCPB, while IOM modules 3,4 and 5 are contained in HCPC power domain
            //for IOM4, wait HCPB comes stable
            while(PWRCTRL->DEVPWRSTATUS_b.HCPC == 0) __NOP();
            break;
    }
 
    //
    //make sure IOM is disabled
    //
    Handle->SUBMODCTRL &= ~(1 << IOM0_SUBMODCTRL_SMOD0EN_Pos);
    Handle->SUBMODCTRL &= ~(1 << IOM0_SUBMODCTRL_SMOD1EN_Pos);

    u32ClkCfg = 0;
    //
    // Clockseetings can be 100KHz, 400KHz or 1MHz
    //
    if (u32Frequency <= 100000UL)
    {
        u32ClkCfg = 2 << IOM0_CLKCFG_FSEL_Pos;        
        u32ClkCfg |= 1 << IOM0_CLKCFG_DIVEN_Pos;      
        u32ClkCfg |= 0x77 << IOM0_CLKCFG_TOTPER_Pos;   
        u32ClkCfg |= 0x3B << IOM0_CLKCFG_LOWPER_Pos;    
        Handle->CLKCFG = u32ClkCfg;          
        Handle->MI2CCFG = 0;
        Handle->MI2CCFG_b.SMPCNT = 3;             
        Handle->MI2CCFG_b.SDAENDLY = 15;          
        Handle->MI2CCFG_b.SCLENDLY = 0;          
        Handle->MI2CCFG_b.MI2CRST = 0;           
    } else if (u32Frequency <= 400000UL)
    {
        u32ClkCfg = 2 << IOM0_CLKCFG_FSEL_Pos;       
        u32ClkCfg |= 1 << IOM0_CLKCFG_DIVEN_Pos;      
        u32ClkCfg |= 0x1D << IOM0_CLKCFG_TOTPER_Pos;    
        u32ClkCfg |= 0x0E << IOM0_CLKCFG_LOWPER_Pos;   
        Handle->CLKCFG = u32ClkCfg;
        Handle->MI2CCFG = 0;
        Handle->MI2CCFG_b.SMPCNT = 15;           
        Handle->MI2CCFG_b.SDAENDLY = 15;          
        Handle->MI2CCFG_b.SCLENDLY = 2;        
        Handle->MI2CCFG_b.MI2CRST = 0;          
       
    } else
    {
        u32ClkCfg = 3 << IOM0_CLKCFG_FSEL_Pos; 
        u32ClkCfg |= 1 << IOM0_CLKCFG_DIVEN_Pos;
        u32ClkCfg |= 6 << IOM0_CLKCFG_TOTPER_Pos;
        u32ClkCfg |= 3 << IOM0_CLKCFG_LOWPER_Pos;
        u32ClkCfg |= (1 << IOM0_CLKCFG_IOCLKEN_Pos);
        Handle->CLKCFG = u32ClkCfg;
        Handle->MI2CCFG = 0;
        Handle->MI2CCFG_b.SMPCNT = 0x21;            
        Handle->MI2CCFG_b.SDAENDLY = 3;
        Handle->MI2CCFG_b.SCLENDLY = 0;
        Handle->MI2CCFG_b.MI2CRST = 0;           
    }
    u32ClkCfg |= (1 << IOM0_CLKCFG_IOCLKEN_Pos);
    Handle->CLKCFG = u32ClkCfg;

    Handle->MI2CCFG_b.ADDRSZ = b10BitAddresses;
    Handle->MSPICFG = 0;

    Handle->FIFOTHR = _VAL2FLD(IOM0_FIFOTHR_FIFOWTHR,8) | _VAL2FLD(IOM0_FIFOTHR_FIFORTHR,8);
    Handle->FIFOCTRL_b.FIFORSTN = 0;    
    Handle->FIFOCTRL_b.FIFORSTN = 1;

    //
    // Enable IOM
    //
    if (Handle->SUBMODCTRL_b.SMOD0TYPE == IOM0_SUBMODCTRL_SMOD0TYPE_I2C_MASTER)
    {
         Handle->SUBMODCTRL_b.SMOD1EN = 0;
         Handle->SUBMODCTRL_b.SMOD0EN = 1; 
    } else
    { 
         Handle->SUBMODCTRL_b.SMOD1EN = 1;
         Handle->SUBMODCTRL_b.SMOD0EN = 0; 
    }
}



/**
*********************************************************************************
** \brief CTIMER IRQ handle
**  
*********************************************************************************/
void CTIMER_IRQHandler(void)
{
    static volatile uint32_t u32InitCount = 0;
    uint32_t u32Status = CTIMER->INTSTAT;
    static uint32_t u32Tmp;
    

    if (u32Status & ((1 << CTIMER_INTSTAT_CTMRA0C0INT_Pos) | (1 << CTIMER_INTSTAT_CTMRA0C1INT_Pos)))
    {
        if (u32InitCount < 4)
        {
            if (u32InitCount == 1)
            {
                //
                // pattern generator was run one-time in dummy mode, activating WS clocked timer B0 
                // to trigger pattern generator A0 in single-mode in time
                //
                CTIMER->AUX0_b.TMRA0LMT = 61; // generating clock shift required by I2S spec.
                CTIMER->CTRL0_b.TMRB0EN = 1;  // enable pattern generator
            }
            if (u32InitCount == 2)
            {
                //
                // first clock interrupt happened, we switch the single pattern mode to repeated pattern
                //
                CTIMER->CTRL0_b.TMRA0FN = CTIMER_CTRL0_TMRA0FN_REPEATPATTERN;
            }
            if (u32InitCount == 3)
            {
                //
                //  switching number of bits back to 64
                //
                CTIMER->AUX0_b.TMRA0LMT = 63;
            }
            u32InitCount++;
        } else
        {
            memcpy((uint8_t*)&u32Tmp,&au8Data[u32DataPos],4);
            u32Tmp = __RBIT(u32Tmp);
            u32DataPos+= 4;
            if (u32DataPos >= sizeof(au8Data)) u32DataPos = 0;
            if (u32Status & (1 << CTIMER_INTSTAT_CTMRA0C0INT_Pos))
            {
                CTIMER->CMPRAUXA0 = u32Tmp; 
            } else
            {
                CTIMER->CMPRA0 = u32Tmp; 
            }
            
        }
    }
    CTIMER->INTCLR = u32Status;
}



/**
*********************************************************************************
** \brief Configure 12MHz MCLK generation
**  
*********************************************************************************/
void Generate12MHz_MCLK(void)
{
    CLKGEN->CLKKEY = 0x47;
    CLKGEN->HFADJ_b.HFADJCK = CLKGEN_HFADJ_HFADJCK_4SEC; 
    CLKGEN->HFADJ_b.HFADJEN = 1;
    CLKGEN->CLKKEY = 0;

    //select HFRC divided by 4
    CLKGEN->CLKOUT_b.CKSEL = CLKGEN_CLKOUT_CKSEL_HFRC_DIV4;
    //enable clock-out generation
    CLKGEN->CLKOUT_b.CKEN = 1;

    GPIO->PADKEY = 0x73; //unlock pad configuration
    //select PAD7 for clock output
    GPIO->PADREGB_b.PAD7FNCSEL = GPIO_PADREGB_PAD7FNCSEL_CLKOUT;
    GPIO->PADKEY = 0; //lock  pad configuration
}

/**
 *****************************************************************************
 ** 
 ** \brief Wrapper for writing I2C commands to the STGL5000 codec
 **
 ** \param reg      Register
 **
 ** \param data     Data
 **
 *****************************************************************************/
void Stgl5000_I2C_write(uint16_t reg, uint16_t data)
{
    uint32_t tmp;
    uint32_t u32BytesWritten;
    (((uint8_t*)&tmp))[0] = reg >> 8;
    (((uint8_t*)&tmp))[1] = reg & 0xFF;
    (((uint8_t*)&tmp))[2] = data >> 8;
    (((uint8_t*)&tmp))[3] = data & 0xFF;
    I2CTransfer(IOM1,I2CWrite,SGTL5000_I2C_ADDR_CS_LOW, NULL,0,FALSE,&tmp,4,&u32BytesWritten);
}


/**
 *****************************************************************************
 ** 
 **\brief Initialize STGL5000 Codec
 **
 *****************************************************************************/
void InitCodec(void)
{
    GPIO->PADKEY = 0x00000073;  //unlock pin selection
    GPIO->PADREGC_b.PAD8PULL = 1;
    GPIO->PADREGC_b.PAD8RSEL = GPIO_PADREGC_PAD8RSEL_PULL1_5K;
    GPIO->PADREGC_b.PAD9PULL = 1;
    GPIO->PADREGC_b.PAD9RSEL = GPIO_PADREGC_PAD9RSEL_PULL1_5K;
    GPIO->PADKEY = 0;

    //
    // Reset codec
    //
    Stgl5000_I2C_write(CHIP_CLK_CTRL, 0);       // writing reset value
    Stgl5000_I2C_write(CHIP_I2S_CTRL, 0x0008);  // writing reset value
    Stgl5000_I2C_write(CHIP_DIG_POWER, 0);      // writing reset value
    Stgl5000_I2C_write(CHIP_LINREG_CTRL,0);     // writing reset value
    Stgl5000_I2C_write(CHIP_ANA_POWER, 0x7060); // writing reset value
 
    delay(400);
    //
    //  Init codec
    //
    Stgl5000_I2C_write(CHIP_ANA_POWER, 0x4060);  // VDDD is externally driven with 1.8V
    Stgl5000_I2C_write(CHIP_LINREG_CTRL, 0x006C);  // VDDA & VDDIO both over 3.1V
    Stgl5000_I2C_write(CHIP_REF_CTRL, 0x01F2); // VAG=1.575, normal ramp, +12.5% bias current
    Stgl5000_I2C_write(CHIP_LINE_OUT_CTRL, 0x0F22); // LO_VAGCNTRL=1.65V, OUT_CURRENT=0.54mA
    Stgl5000_I2C_write(CHIP_SHORT_CTRL, 0x4446);  // allow up to 125mA
    Stgl5000_I2C_write(CHIP_ANA_CTRL, 0x0137);  // enable zero cross detectors
    Stgl5000_I2C_write(CHIP_ANA_POWER, 0x44FF); // power up: lineout, hp, adc, dac
    Stgl5000_I2C_write(CHIP_ANA_POWER, 0x45FF); // power up: lineout, hp, adc, dac
    Stgl5000_I2C_write(CHIP_PLL_CTRL,(15 << 11) | (108 << 0)); // writing PLL settings for 12MHz input
    Stgl5000_I2C_write(CHIP_DIG_POWER, 0x0073); // power up all digital stuff

    delay(400);

    Stgl5000_I2C_write(CHIP_LINE_OUT_VOL, 0x1D1D); // default approx 1.3 volts peak-to-peak
    Stgl5000_I2C_write(CHIP_CLK_CTRL, 0x0007);  // 32 kHz, PLL
    Stgl5000_I2C_write(CHIP_I2S_CTRL, 0x01B0); // SCLK=32*Fs, 16bit, I2S format, master mode
    Stgl5000_I2C_write(CHIP_SSS_CTRL, 0x0050); // ADC->I2S, I2S->DAC
    Stgl5000_I2C_write(CHIP_ADCDAC_CTRL, 0x0000); // disable dac mute
    Stgl5000_I2C_write(CHIP_DAC_VOL, 0x3C3C); // digital gain, 0dB
    Stgl5000_I2C_write(CHIP_ANA_HP_CTRL, 0x3C3C); // set volume to 0dB (0x7F7F = lowest level)
    Stgl5000_I2C_write(CHIP_ANA_CTRL, 0x0036);  // enable zero cross detectors
    Stgl5000_I2C_write(CHIP_ANA_CTRL, 0x0026);  // enable HP

}


/**
 *****************************************************************************
 ** 
 **\brief Setup GPIO for I2C
 **
 *****************************************************************************/
void GpioConfig_I2C(void)
{
    GPIO->PADKEY = 0x73; //unlock pad configuration

    //pin 8, M1SCL , FN1
    //pin 9, M1SDAWIR3, FN1
    GPIO->PADREGC_b.PAD8FNCSEL = GPIO_PADREGC_PAD8FNCSEL_M1SCL; //select function 1 (M0SCK) at PAD5 
    GPIO->PADREGC_b.PAD9FNCSEL = GPIO_PADREGC_PAD9FNCSEL_M1SDAWIR3; //select function 1 (M0MISO) at PAD6

    GPIO->CFGB_b.GPIO8OUTCFG = GPIO_CFGB_GPIO8OUTCFG_OD;   //out-config open-drain
    GPIO->CFGB_b.GPIO9OUTCFG = GPIO_CFGB_GPIO9OUTCFG_OD;   //out-config open-drain
    GPIO->PADREGC_b.PAD8INPEN = 1;  //input enable
    GPIO->PADREGC_b.PAD9INPEN = 1;  //input enable
    
    //
    // Enable 1.5k pull-ups
    //
    GPIO->PADREGC_b.PAD8RSEL = GPIO_PADREGC_PAD8RSEL_PULL1_5K; 
    GPIO->PADREGC_b.PAD8PULL = 1;
    GPIO->PADREGC_b.PAD9RSEL = GPIO_PADREGC_PAD9RSEL_PULL1_5K; 
    GPIO->PADREGC_b.PAD9PULL = 1;

    GPIO->PADKEY = 0; //lock pad configuration
}

/**
 *****************************************************************************
 ** 
 **\brief Setup GPIO for I2S
 **
 *****************************************************************************/
void GpioConfig_I2S(void)
{
    GPIO->PADKEY = 0x00000073;  //unlock pin selection

    //use pin 12 for timer output (data out signal)
    GPIO->PADREGD_b.PAD12FNCSEL = GPIO_PADREGD_PAD12FNCSEL_CT0;
    //pad 12 ouput is push-pull
    GPIO->CFGB_b.GPIO12OUTCFG = GPIO_CFGB_GPIO12OUTCFG_PUSHPULL; 


    //use pin 25 for timer A0 input (clock)
    GPIO->PADREGG_b.PAD25FNCSEL = GPIO_PADREGG_PAD25FNCSEL_CT1;
    //enable input at pad 25, pullup enable
    GPIO->PADREGG_b.PAD25INPEN = 1;
    GPIO->PADREGG_b.PAD25PULL = 1;


    //use pin 13 as sync timer input (B0)
    GPIO->PADREGD_b.PAD13INPEN = 1;
    GPIO->PADREGD_b.PAD13PULL = 1;
    GPIO->PADREGD_b.PAD13FNCSEL = GPIO_PADREGD_PAD13FNCSEL_CT2;
    //GPIO->INT0EN_b.GPIO13 = 1;

    GPIO->PADKEY = 0;  //lock pin selection
}

/**
 *****************************************************************************
 ** 
 **\brief Setup timers for I2S generation
 **
 *****************************************************************************/
void TimerConfig_I2S(void)
{
    CTIMER->INTCLR = 0xFFFFFFFF;
    CTIMER->CTRL0 = 0;

    //timer B0, WS input, B0OUT output
    CTIMER->INCFG_b.CFGB0 = CTIMER_INCFG_CFGB0_CT2;
    CTIMER->CTRL0_b.TMRB0CLR = 1;         //clear timer
    CTIMER->CTRL0_b.TMRB0FN = CTIMER_CTRL1_TMRA1FN_SINGLECOUNT;
    CTIMER->CTRL0_b.TMRB0CLK = CTIMER_CTRL0_TMRB0CLK_TMRPIN;
    CTIMER->INTEN_b.CTMRB0C0INT = 0;
    CTIMER->INTEN_b.CTMRB0C1INT = 1;
    CTIMER->CMPRB0_b.CMPR0B0 = 2;
    CTIMER->CMPRB0_b.CMPR1B0 = 4;
    CTIMER->AUX0_b.TMRB0NOSYNC;
    CTIMER->CTRL0_b.TMRB0CLR = 0;         //clear timer


    //timer A0, data generation
    CTIMER->OUTCFG0_b.CFG0 = CTIMER_OUTCFG0_CFG0_A0OUT; //Output configuration to ct0
    CTIMER->INCFG_b.CFGA0 = CTIMER_INCFG_CFGA0_CT1;     //use CT1 as in config
    GPIO->CTENCFG_b.EN0 = 0;             //Timer output enabled
    CTIMER->CTRL0_b.TMRA0EN = 0;
    CTIMER->CTRL0_b.TMRA0CLR = 1;         //clear timer
    CTIMER->CTRL0_b.TMRA0IE0 = 1;        
    CTIMER->CTRL0_b.TMRA0IE1 = 1;
    CTIMER->INTEN_b.CTMRA0C0INT = 1;
    CTIMER->INTEN_b.CTMRA0C1INT = 1;
    CTIMER->CTRL0_b.TMRA0FN = CTIMER_CTRL0_TMRA0FN_SINGLEPATTERN;
    CTIMER->CTRL0_b.TMRA0CLK = CTIMER_CTRL0_TMRA0CLK_TMRPIN;
    CTIMER->AUX0_b.TMRA0LMT = 63;              //set limit to 64
    CTIMER->AUX0_b.TMRA0TRIG = CTIMER_AUX0_TMRA0TRIG_B0OUT;
    CTIMER->AUX0_b.TMRA0NOSYNC;
    CTIMER->CTRL0_b.TMRA0CLR = 0;         //release clear timer
    CTIMER->CTRL0_b.TMRA0EN = 1;               

    NVIC_DisableIRQ(CTIMER_IRQn);         //disable IRQ in the NVIC
    NVIC_ClearPendingIRQ(CTIMER_IRQn);    //clear pending flag in the NVIC
    NVIC_SetPriority(CTIMER_IRQn,1);      //set the interrupts priority, smaller means higher priority
    NVIC_EnableIRQ(CTIMER_IRQn);          //enable the IRQ in the NVIC
}


/**
*********************************************************************************
** \brief Main
**  
*********************************************************************************/
int main(void)
{
    int i;
    SystemCoreClockUpdate();                //update clock variable SystemCoreClock (defined by CMSIS)
    SysTick_Config(SystemCoreClock / 1000); //setup 1ms SysTick (defined by CMSIS)

    GpioConfig_I2S();
    GpioConfig_I2C();

    Generate12MHz_MCLK();

    I2CConfig(IOM1,400000,FALSE);

    InitCodec();
   
    TimerConfig_I2S();

    //application initialization area
    while(1)
    {
       __WFI();
        //application code
    }
}


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

