/**
 * \file   plat_mcspi.c
 *
 * \brief  McPI Platform source file for AM335x
 *
 * 
*/

/*
 * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
 */
/* ========================================================================== */
/*                             Include Files                                  */
/* ========================================================================== */
#include "plat_mcspi.h"
#include "hw_mcspi.h"
#include "mcspi.h"
#include "hw_control_AM335x.h"
#include "hw_cm_per.h"
#include "soc_AM335x.h"
#include "plat_mux.h"
#include "plat_utils.h"
/* ========================================================================== */
/*                           Macros & Typedefs                                */
/* ========================================================================== */

/* ========================================================================== */
/*                         Structures and Enums                               */
/* ========================================================================== */

/* ========================================================================== */
/*                 Internal Function Declarations                             */
/* ========================================================================== */

/* ========================================================================== */
/*                            Global Variables                                */
/* ========================================================================== */


/* ========================================================================== */
/*                          Function Definitions                              */
/* ========================================================================== */

int McSPIPinMuxConfig(int spiId)
{
	short retVal;


	switch (spiId)
	{
	case 0:
	    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_SPI0_SCLK) =
				PINMUXMODE_1 |
			CONTROL_CONF_SPI0_SCLK_CONF_SPI0_SCLK_RXACTIVE;

		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_SPI0_D0 ) = 	PINMUXMODE_1 |
			CONTROL_CONF_SPI0_D0_CONF_SPI0_D0_RXACTIVE;

		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_SPI0_D1 ) = 	PINMUXMODE_1 |
			CONTROL_CONF_SPI0_D1_CONF_SPI0_D1_PUTYPESEL |
			CONTROL_CONF_SPI0_D1_CONF_SPI0_D1_RXACTIVE;

		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_SPI0_CS0) =	PINMUXMODE_1 |
				CONTROL_CONF_SPI0_D1_CONF_SPI0_D1_PUTYPESEL |
			CONTROL_CONF_SPI0_CS0_CONF_SPI0_CS0_RXACTIVE;

		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_SPI0_CS1) =  PINMUXMODE_1 |
			CONTROL_CONF_SPI0_CS1_CONF_SPI0_CS1_PUDEN |
			CONTROL_CONF_SPI0_CS1_CONF_SPI0_CS1_RXACTIVE;

		retVal = SUCCESS;
		break;

    case 1:
		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MCASP0_ACLKX) =
		    		PINMUXMODE_4 |
				CONTROL_CONF_MCASP0_ACLKX_CONF_MCASP0_ACLKX_RXACTIVE;

		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MCASP0_FSX ) = 	PINMUXMODE_4 |
				CONTROL_CONF_MCASP0_FSX_CONF_MCASP0_FSX_PUTYPESEL |
				CONTROL_CONF_MCASP0_FSX_CONF_MCASP0_FSX_RXACTIVE;


		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MCASP0_AXR0 ) = 	PINMUXMODE_4 |
				CONTROL_CONF_MCASP0_AXR0_CONF_MCASP0_AXR0_RXACTIVE;

		/*CS0 PIN*/
		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MCASP0_AHCLKR) =
			PINMUXMODE_4 |
			    CONTROL_CONF_MCASP0_AHCLKR_CONF_MCASP0_AHCLKR_PUTYPESEL
			        | CONTROL_CONF_MCASP0_AHCLKR_CONF_MCASP0_AHCLKR_RXACTIVE;

		retVal = SUCCESS;
		break;
    default:
		retVal = FAIL;
	}
	return retVal;
}

void McSPIModuleClkConfig(int spiInstance)
{
    if((spiInstance > 2) || ((spiInstance < 0)))
        return;

    HWREG(SOC_CM_PER_REGS + CM_PER_L3S_CLKSTCTRL) =
                             CM_PER_L3S_CLKSTCTRL_CLKTRCTRL_SW_WKUP;

    while((HWREG(SOC_CM_PER_REGS + CM_PER_L3S_CLKSTCTRL) &
     CM_PER_L3S_CLKSTCTRL_CLKTRCTRL) != CM_PER_L3S_CLKSTCTRL_CLKTRCTRL_SW_WKUP);

    HWREG(SOC_CM_PER_REGS + CM_PER_L3_CLKSTCTRL) =
                             CM_PER_L3_CLKSTCTRL_CLKTRCTRL_SW_WKUP;

    while((HWREG(SOC_CM_PER_REGS + CM_PER_L3_CLKSTCTRL) &
     CM_PER_L3_CLKSTCTRL_CLKTRCTRL) != CM_PER_L3_CLKSTCTRL_CLKTRCTRL_SW_WKUP);

    HWREG(SOC_CM_PER_REGS + CM_PER_L3_INSTR_CLKCTRL) =
                             CM_PER_L3_INSTR_CLKCTRL_MODULEMODE_ENABLE;

    while((HWREG(SOC_CM_PER_REGS + CM_PER_L3_INSTR_CLKCTRL) &
                               CM_PER_L3_INSTR_CLKCTRL_MODULEMODE) !=
                                   CM_PER_L3_INSTR_CLKCTRL_MODULEMODE_ENABLE);

    HWREG(SOC_CM_PER_REGS + CM_PER_L3_CLKCTRL) =
                             CM_PER_L3_CLKCTRL_MODULEMODE_ENABLE;

    while((HWREG(SOC_CM_PER_REGS + CM_PER_L3_CLKCTRL) &
        CM_PER_L3_CLKCTRL_MODULEMODE) != CM_PER_L3_CLKCTRL_MODULEMODE_ENABLE);

    HWREG(SOC_CM_PER_REGS + CM_PER_OCPWP_L3_CLKSTCTRL) =
                             CM_PER_OCPWP_L3_CLKSTCTRL_CLKTRCTRL_SW_WKUP;

    while((HWREG(SOC_CM_PER_REGS + CM_PER_OCPWP_L3_CLKSTCTRL) &
                              CM_PER_OCPWP_L3_CLKSTCTRL_CLKTRCTRL) !=
                                CM_PER_OCPWP_L3_CLKSTCTRL_CLKTRCTRL_SW_WKUP);

    HWREG(SOC_CM_PER_REGS + CM_PER_L4LS_CLKSTCTRL) =
                             CM_PER_L4LS_CLKSTCTRL_CLKTRCTRL_SW_WKUP;

    while((HWREG(SOC_CM_PER_REGS + CM_PER_L4LS_CLKSTCTRL) &
                             CM_PER_L4LS_CLKSTCTRL_CLKTRCTRL) !=
                               CM_PER_L4LS_CLKSTCTRL_CLKTRCTRL_SW_WKUP);

    HWREG(SOC_CM_PER_REGS + CM_PER_L4LS_CLKCTRL) =
                             CM_PER_L4LS_CLKCTRL_MODULEMODE_ENABLE;

    while((HWREG(SOC_CM_PER_REGS + CM_PER_L4LS_CLKCTRL) &
      CM_PER_L4LS_CLKCTRL_MODULEMODE) != CM_PER_L4LS_CLKCTRL_MODULEMODE_ENABLE);
      
    if(spiInstance == 0)
    {
        HWREG(SOC_CM_PER_REGS + CM_PER_SPI0_CLKCTRL) &= ~CM_PER_SPI0_CLKCTRL_MODULEMODE;

        HWREG(SOC_CM_PER_REGS + CM_PER_SPI0_CLKCTRL) |=
                                 CM_PER_SPI0_CLKCTRL_MODULEMODE_ENABLE;

        while((HWREG(SOC_CM_PER_REGS + CM_PER_SPI0_CLKCTRL) &
          CM_PER_SPI0_CLKCTRL_MODULEMODE) != CM_PER_SPI0_CLKCTRL_MODULEMODE_ENABLE);
    }
    else
    {
        HWREG(SOC_CM_PER_REGS + CM_PER_SPI1_CLKCTRL) &= ~CM_PER_SPI1_CLKCTRL_MODULEMODE;

        HWREG(SOC_CM_PER_REGS + CM_PER_SPI1_CLKCTRL) |=
                                 CM_PER_SPI1_CLKCTRL_MODULEMODE_ENABLE;

        while((HWREG(SOC_CM_PER_REGS + CM_PER_SPI1_CLKCTRL) &
          CM_PER_SPI1_CLKCTRL_MODULEMODE) != CM_PER_SPI1_CLKCTRL_MODULEMODE_ENABLE);
    
    }

    while(!(HWREG(SOC_CM_PER_REGS + CM_PER_L3S_CLKSTCTRL) &
            CM_PER_L3S_CLKSTCTRL_CLKACTIVITY_L3S_GCLK));

    while(!(HWREG(SOC_CM_PER_REGS + CM_PER_L3_CLKSTCTRL) &
            CM_PER_L3_CLKSTCTRL_CLKACTIVITY_L3_GCLK));

    while(!(HWREG(SOC_CM_PER_REGS + CM_PER_OCPWP_L3_CLKSTCTRL) &
           (CM_PER_OCPWP_L3_CLKSTCTRL_CLKACTIVITY_OCPWP_L3_GCLK |
            CM_PER_OCPWP_L3_CLKSTCTRL_CLKACTIVITY_OCPWP_L4_GCLK)));

    while(!(HWREG(SOC_CM_PER_REGS + CM_PER_L4LS_CLKSTCTRL) &
           (CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_L4LS_GCLK |
            CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_SPI_GCLK)));
}


void McSPICycle(int spiId, unsigned char *buf,
                unsigned short len, unsigned int chNum)
{
    unsigned int i;
    volatile int loop;

    int baseAdd;

	switch(spiId)
	{
	    case MCSPI_INSTANCE_0:
            baseAdd = SOC_SPI_0_REGS;
            break;
	    case MCSPI_INSTANCE_1:
            baseAdd = SOC_SPI_1_REGS;
            break;
        default:
            return ;
	}

    /* Enable Channel */
    if (chNum > 0)
    	chNum = 1;   /*In SUBARTIC only two channels are used*/

    McSPIChannelEnable(baseAdd,chNum);

    for(loop = 0; loop < 1000; loop++);

    McSPICSAssert(baseAdd,chNum);
    /* SPI System Register Configuration*/
    HWREG(baseAdd + MCSPI_SYST) = (HWREG(baseAdd + MCSPI_SYST) &
                                    ~MCSPI_SYST_SPIEN_0);

    for ( i = 0 ; i < len ; i++ )
    {
        loop = 1000;
        /* Wait for transmit empty */
        while(((McSPIChannelStatusGet(baseAdd,chNum) & MCSPI_CH_STAT_TXS_EMPTY) == 0) && (loop--));
        if(loop == 0)
            return;
        McSPITransmitData(baseAdd,buf[i],chNum);
        
        loop = 1000;
        while(((McSPIChannelStatusGet(baseAdd,chNum) & MCSPI_CH_STAT_RXS_FULL) == 0) && (loop--));
        if(loop == 0)
            return;        
        buf[i] = (unsigned char)McSPIReceiveData(baseAdd,chNum);
    }

    McSPICSDeAssert(baseAdd,chNum);

    HWREG(baseAdd + MCSPI_SYST) |= (1 << MCSPI_SYST_SPIEN_0_SHIFT);

    McSPIChannelDisable(baseAdd,chNum);

    for(loop = 0; loop < 1000; loop++);
}



unsigned int McSPIGetBaseAddress(int spiId)
{
	unsigned int baseAdd;
	switch(spiId)
	{
	    case MCSPI_INSTANCE_0:
            baseAdd = SOC_SPI_0_REGS;
            break;
	    case MCSPI_INSTANCE_1:
            baseAdd = SOC_SPI_1_REGS;
            break;
        default:
        	baseAdd = 0;
        	break;
	}
	return baseAdd;

}
/* -------------------------------------------------------------------------- */
/*                 Internal Function Definitions                              */
/* -------------------------------------------------------------------------- */
