#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>

#include <bsp.h>
#include <Library.h>
#include <max8698.h>
#include <oal_i2cemul.h>

static PGPIO_REG pGPIOReg;
static PUART_REG pUARTReg;

VOID OEMInitLib(VOID)
{
    pGPIOReg = (PGPIO_REG)BASE_REG_PA_GPIO;
    OEMInitDebugSerial();
    EdbgOutputDebugString("OEMInitLIb is Success\r\n");
}

VOID OEMInitDebugSerial(VOID) 
{
    volatile PCMU_CLK_REG pCMUCLKReg = (PCMU_CLK_REG)BASE_REG_PA_CMU_CLK;
    float Div;
    DWORD DivSlot;
    const DWORD aSlotTable[16] = 
    {
        0x0000, 0x0080, 0x0808, 0x0888, 
        0x2222, 0x4924, 0x4a52, 0x54aa, 
        0x5555, 0xd555, 0xd5d5, 0xddd5, 
        0xdddd, 0xdfdd, 0xdfdf, 0xffdf
    };
    DWORD nSlot=0;

    pUARTReg = NULL;
#if   (ILDR_DEBUG_PORT == DEBUG_UART0)
    // UART0
    pUARTReg = (PUART_REG)BASE_REG_PA_UART0;
#elif (ILDR_DEBUG_PORT == DEBUG_UART1)
    // UART1
    pUARTReg = (PUART_REG)BASE_REG_PA_UART1;
#elif (ILDR_DEBUG_PORT == DEBUG_UART2)
    // UART2
    pUARTReg = (PUART_REG)BASE_REG_PA_UART2;
#elif (ILDR_DEBUG_PORT == DEBUG_UART3)
    // UART3
    pUARTReg = (PUART_REG)BASE_REG_PA_UART3;
#else
    INVALID_DEBUG_PORT        // Error
#endif
    
    // UART I/O port initialize
#if   (ILDR_DEBUG_PORT == DEBUG_UART0)
    SETREG32(&pCMUCLKReg->CLK_GATE.CLK_GATE_IP3, (CLK_ON<<BP_CLK_IP_UART0));
    Set_PinFunction(pGPIOReg, UART0_RXD);
    Set_PinFunction(pGPIOReg, UART0_TXD);
    Set_PinPullUD(pGPIOReg, UART0_RXD, sgip_PULL_DOWN);
    Set_PinPullUD(pGPIOReg, UART0_TXD, sgip_PULL_DISABLE);

#elif (ILDR_DEBUG_PORT == DEBUG_UART1)
    SETREG32(&pCMUCLKReg->CLK_GATE.CLK_GATE_IP3, (CLK_ON<<BP_CLK_IP_UART1));
    Set_PinFunction(pGPIOReg, UART1_RXD);
    Set_PinFunction(pGPIOReg, UART1_TXD);
    Set_PinPullUD(pGPIOReg, UART1_RXD, sgip_PULL_DOWN);
    Set_PinPullUD(pGPIOReg, UART1_TXD, sgip_PULL_DISABLE);

#elif (ILDR_DEBUG_PORT == DEBUG_UART2)
    SETREG32(&pCMUCLKReg->CLK_GATE.CLK_GATE_IP3, (CLK_ON<<BP_CLK_IP_UART2));
    Set_PinFunction(pGPIOReg, UART2_RXD);
    Set_PinFunction(pGPIOReg, UART2_TXD);
    Set_PinPullUD(pGPIOReg, UART2_RXD, sgip_PULL_DOWN);
    Set_PinPullUD(pGPIOReg, UART2_TXD, sgip_PULL_DISABLE);

#elif (ILDR_DEBUG_PORT == DEBUG_UART3)
    SETREG32(&pCMUCLKReg->CLK_GATE.CLK_GATE_IP3, (CLK_ON<<BP_CLK_IP_UART3));
    Set_PinFunction(pGPIOReg, UART3_RXD);
    Set_PinFunction(pGPIOReg, UART3_TXD);
    Set_PinPullUD(pGPIOReg, UART3_RXD, sgip_PULL_DOWN);
    Set_PinPullUD(pGPIOReg, UART3_TXD, sgip_PULL_DISABLE);
#endif


    // UART Configuration
    Div = (float)((float)PCLKPSYS/(16.0*(float)DEFAULT_DEBUG_BAUDRATE)) - 1;
    OUTREG32(&pUARTReg->UFCON,  DEBUG_UART_UFCON);
    OUTREG32(&pUARTReg->ULCON,  DEBUG_UART_ULCON);
    OUTREG32(&pUARTReg->UCON,   DEBUG_UART_UCON);
    OUTREG32(&pUARTReg->UBRDIV, (DWORD)Div);

    DivSlot = (DWORD)(((Div-(int)Div)*16)+0.5);
    OUTREG32(&pUARTReg->UDIVSLOT, aSlotTable[DivSlot]);
}


//------------------------------------------------------------------------------
//
//  Function: OEMWriteDebugByte
//
//  Transmits a character out the debug serial port.
//
VOID OEMWriteDebugByte(CHAR ch) 
{
    // Wait for transmit buffer to be empty
    while((INREG32(&pUARTReg->UTRSTAT) & 0x02) == 0);

	OUTREG32(&pUARTReg->UTXH, ch);
}

VOID OEMWriteDebugString(CHAR *string)
{
    while (*string != '\0') OEMWriteDebugByte(*string++);
}

VOID OEMInitPMIC(VOID)
{	
    DWORD dwRegVal;
    
    EdbgOutputDebugString("+++OEMPMICInit\r\n");

	//Init I2C emul
    I2C_EMUL_Init(PMIC_GROUP, BASE_REG_PA_GPIO, NULL, PMIC_SLAVE_ADDR, 200);

	//Init LDO on/off
    I2C_EMUL_Write(PMIC_GROUP, ONOFF1, ONOFF1_REG_VALUE_INIT);
    I2C_EMUL_Write(PMIC_GROUP, ONOFF2, ONOFF2_REG_VALUE_INIT);

    //For debugging
    dwRegVal = 0;
    I2C_EMUL_Read(PMIC_GROUP, ONOFF1, &dwRegVal);
    //OALMSG(TRUE, (TEXT("PMIC: ONOFF1 0x%x\r\n"), dwRegVal));
    //DebugString("PMIC: ONOFF1 0x%X, 0x%X\r\n", ONOFF1_REG_VALUE_INIT, dwRegVal);
    EdbgOutputDebugString("[PMIC] ONOFF1 0x%X, 0x%X\r\n", ONOFF1_REG_VALUE_INIT, dwRegVal);

    dwRegVal = 0;
    I2C_EMUL_Read(PMIC_GROUP, ONOFF2, &dwRegVal);
    //OALMSG(TRUE, (TEXT("PMIC: ONOFF2 0x%x\r\n"), dwRegVal));
    //DebugString("PMIC: ONOFF1 0x%X, 0x%X\r\n", ONOFF1_REG_VALUE_INIT, dwRegVal);
    EdbgOutputDebugString("[PMIC] ONOFF2 0x%X, 0x%X\r\n", ONOFF2_REG_VALUE_INIT, dwRegVal);
    
    
	//Init BUCKs
	I2C_EMUL_Write(PMIC_GROUP, DVSARM1_2, (DVS_L0_ARM|(DVS_L1_ARM<<DVSARM2_START)));
    I2C_EMUL_Write(PMIC_GROUP, DVSARM3_4, (DVS_L2_ARM|(DVS_L3_ARM<<DVSARM4_START)));
    
    I2C_EMUL_Write(PMIC_GROUP, DVSINT1_2, (DVS_L0_INT|(DVS_L1_INT<<DVSINT2_START)));

    /*
    I2C_EMUL_Read(PMIC_GROUP, DVSARM1_2, &regVal);
    OALMSG(TRUE, (TEXT("PMIC: DVSARM1_2 0x%x\r\n"), regVal));
    I2C_EMUL_Read(PMIC_GROUP, DVSINT1_2, &regVal);
    OALMSG(TRUE, (TEXT("PMIC: DVSINT1_2 0x%x\r\n"), regVal));
    */
    
    //Select DVS_L0_ARM (BUCK1_DVSARM1)
    //Refer to Table2. in PMIC manual
    //SET1(BUCK1_EN_A)  SET2(BUCK1_EN_B)    BUCK1
    //      0                   0          DVSARM1
    //      1                   0          DVSARM2
    //      0                   1          DVSARM3
    //      1                   1          DVSARM4    
    Set_PinFunction(pGPIOReg, PMIC_SET1);
    Set_PinData(pGPIOReg, PMIC_SET1, FALSE);
    Set_PinFunction(pGPIOReg, PMIC_SET2);
    Set_PinData(pGPIOReg, PMIC_SET2, FALSE);

    //Select DVS_L0_INT (BUCK2_DVSINT1)
    //Refer to Table3. in PMIC manual
    //SET3(BUCK_2_EN )    BUCK2
    //        0          DVSINT1
    //        1          DVSINT2
    Set_PinFunction(pGPIOReg, PMIC_SET3);
    Set_PinData(pGPIOReg, PMIC_SET3, FALSE);
    
	EdbgOutputDebugString("---OEMPMICInit\r\n");
}