/*
 * Copyright (c) 2012, Texas Instruments Incorporated
 * All rights reserved.
 *
 * 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.
 */

/*
 *  ======== TMDXDOCKH52C1.c ========
 */

#include <inc/hw_memmap.h>
#include <inc/hw_types.h>
#include <inc/hw_ints.h>
#include <inc/hw_gpio.h>
#include <inc/hw_sysctl.h>

#include <driverlib/gpio.h>
#include <driverlib/sysctl.h>
#include <driverlib/i2c.h>
#include <driverlib/ssi.h>

#include <xdc/std.h>
#include <xdc/runtime/System.h>

#include <ti/drivers/EMAC.h>
#include <ti/drivers/I2C.h>
#include <ti/drivers/GPIO.h>
#include <ti/drivers/UART.h>
#include <ti/drivers/SDSPI.h>
#include <ti/drivers/USBMSCHFatFs.h>

#include "TMDXDOCKH52C1.h"

static Void TMDXDOCKH52C1_setMaxSPIbitrate(SDSPI_Handle handle);
#define OSCCLKIN 10000000
#define UART1_BAUD 9600
/* GPIO configuration structure */
const GPIO_HWAttrs gpioHWAttrs[TMDXDOCKH52C1_GPIOCOUNT] = {
    {GPIO_PORTC_BASE, GPIO_PIN_6, GPIO_OUTPUT},  /* TMDXDOCKH52C1_LD2 */
    {GPIO_PORTC_BASE, GPIO_PIN_7, GPIO_OUTPUT},  /* TMDXDOCKH52C1_LD3 */
    {GPIO_PORTB_BASE, GPIO_PIN_4, GPIO_INPUT},   /* TMDXDOCKH52C1_BUTTON */
};

const GPIO_Config GPIO_config = 
    {TMDXDOCKH52C1_GPIOCOUNT, gpioHWAttrs};

/* UART objects */
UART_Object uartObjects[TMDXDOCKH52C1_UARTCOUNT];

/* UART configuration structure */
const UART_HWAttrs uartHWAttrs[TMDXDOCKH52C1_UARTCOUNT] = {
    {UART0_BASE, INT_UART0}, /* TMDXDOCKH52C1_UART0 */
};

const UART_Config UART_config =
    {TMDXDOCKH52C1_UARTCOUNT, uartObjects, uartHWAttrs};

/* EMAC objects */
EMAC_Object emacObjects[TMDXDOCKH52C1_EMACCOUNT];

/*
 *  EMAC configuration structure
 *  Set user/company specific MAC octates. The following sets the address
 *  to ff-ff-ff-ff-ff-ff. Users need to change this to make the label on
 *  their boards.
 */    
UInt8 macAddress[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};

const EMAC_HWAttrs emacHWAttrs[TMDXDOCKH52C1_EMACCOUNT] = {
    {INT_ETH, macAddress}
};

const EMAC_Config EMAC_config =
    {TMDXDOCKH52C1_EMACCOUNT, emacObjects, emacHWAttrs};

SDSPI_Object sdspiObjects[TMDXDOCKH52C1_SDSPICOUNT];

/* SDSPI configuration structure, describing which pins are to be used */
const SDSPI_HWAttrs sdspiHWAttrs[TMDXDOCKH52C1_SDSPICOUNT] = {
    {
        SSI0_BASE,          /* SPI base address */

        GPIO_PORTD_BASE,    /* The GPIO port used for the SPI pins */
        GPIO_PIN_2,         /* SCK */
        GPIO_PIN_1,         /* MISO */
        GPIO_PIN_0,         /* MOSI */

        GPIO_PORTD_BASE,    /* Chip select port */
        GPIO_PIN_3,         /* Chip select pin */

        GPIO_PORTA_BASE,    /* GPIO TX port */
        GPIO_PIN_5,         /* GPIO TX pin */
        
        TMDXDOCKH52C1_setMaxSPIbitrate /* Function that sets a new SPI bitrate */
    }
};

const SDSPI_Config SDSPI_config = 
    {TMDXDOCKH52C1_SDSPICOUNT, sdspiObjects, sdspiHWAttrs};

USBMSCHFatFs_Object USBMSCHFatFsObjects[TMDXDOCKH52C1_USBMSCHFatFsCOUNT];

/* USBMSCHFatFs configuration structure, describing which pins are to be used */
const USBMSCHFatFs_HWAttrs USBMSCHFatFsHWAttrs[TMDXDOCKH52C1_USBMSCHFatFsCOUNT] = {
    {INT_USB0}
};

const USBMSCHFatFs_Config USBMSCHFatFs_config = 
    {TMDXDOCKH52C1_USBMSCHFatFsCOUNT, USBMSCHFatFsObjects, USBMSCHFatFsHWAttrs};

I2C_Object I2CObjects[TMDXDOCKH52C1_I2CCOUNT];

/* I2C configuration structure, describing which pins are to be used */
const I2C_HWAttrs I2CHWAttrs[TMDXDOCKH52C1_I2CCOUNT] = {
    {I2C0_MASTER_BASE, INT_I2C0},
    {I2C1_MASTER_BASE, INT_I2C1}
};

const I2C_Config I2C_config =
    {TMDXDOCKH52C1_I2CCOUNT, I2CObjects, I2CHWAttrs};

/*
 *  ======== TMDXDOCKH52C1_initEMAC ========
 */
Void TMDXDOCKH52C1_initEMAC(Void)
{   
    /*    
     *  Set up the pins that are used for Ethernet     
     *  MII_TXD3
     */
    GPIODirModeSet(GPIO_PORTC_BASE, GPIO_PIN_4, GPIO_DIR_MODE_HW);
    GPIOPadConfigSet(GPIO_PORTC_BASE, GPIO_PIN_4, GPIO_PIN_TYPE_STD);
    HWREG(GPIO_PORTC_BASE + GPIO_O_PCTL) &= 0xFFF0FFFF;
    HWREG(GPIO_PORTC_BASE + GPIO_O_PCTL) |= 0x00030000;

    /* MII_MDIO */
    GPIODirModeSet(GPIO_PORTE_BASE, GPIO_PIN_6, GPIO_DIR_MODE_HW);
    GPIOPadConfigSet(GPIO_PORTE_BASE, GPIO_PIN_6, GPIO_PIN_TYPE_STD);
    HWREG(GPIO_PORTE_BASE + GPIO_O_APSEL)|= 0x00000040;
    HWREG(GPIO_PORTE_BASE + GPIO_O_PCTL) &= 0xF0FFFFFF;
    HWREG(GPIO_PORTE_BASE + GPIO_O_PCTL) |= 0x0C000000;

    /* MII_RXD3 */
    GPIODirModeSet(GPIO_PORTF_BASE, GPIO_PIN_5, GPIO_DIR_MODE_HW);
    GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_5, GPIO_PIN_TYPE_STD);
    HWREG(GPIO_PORTF_BASE + GPIO_O_PCTL) &= 0xFF0FFFFF;
    HWREG(GPIO_PORTF_BASE + GPIO_O_PCTL) |= 0x00300000;

    /* MII_TXER , MII_RXDV , MII_RXD1 , MII_RXD2 */
    GPIODirModeSet(GPIO_PORTG_BASE, GPIO_PIN_7|GPIO_PIN_3|GPIO_PIN_1|GPIO_PIN_0,
                   GPIO_DIR_MODE_HW);
    GPIOPadConfigSet(GPIO_PORTG_BASE, GPIO_PIN_7|GPIO_PIN_3|GPIO_PIN_1|
                     GPIO_PIN_0,
                     GPIO_PIN_TYPE_STD);
    HWREG(GPIO_PORTG_BASE + GPIO_O_APSEL)|= 0x0000000B;
    HWREG(GPIO_PORTG_BASE + GPIO_O_PCTL) &= 0x0FFF0F00;
    HWREG(GPIO_PORTG_BASE + GPIO_O_PCTL) |= 0x3000C0CC;

    /* MII_TXCK , MII_TXEN , MII_TXD0 , MII_TXD1 , MII_TXD2 , MII_RXD0 */
    GPIODirModeSet(
        GPIO_PORTH_BASE, GPIO_PIN_7|GPIO_PIN_6|GPIO_PIN_5|GPIO_PIN_4|
        GPIO_PIN_3|
        GPIO_PIN_1, GPIO_DIR_MODE_HW);
    GPIOPadConfigSet(
        GPIO_PORTH_BASE, GPIO_PIN_7|GPIO_PIN_6|GPIO_PIN_5|GPIO_PIN_4|
        GPIO_PIN_3|
        GPIO_PIN_1, GPIO_PIN_TYPE_STD);
    HWREG(GPIO_PORTH_BASE + GPIO_O_APSEL)|= 0x000000C2;
    HWREG(GPIO_PORTH_BASE + GPIO_O_PCTL) &= 0x00000F0F;
    HWREG(GPIO_PORTH_BASE + GPIO_O_PCTL) |= 0xCC9990C0;

    /*
     *  MII_PHYRSTn , MII_PHYINTRn , MII_CRS , MII_COL , MII_MDC , MII_RXCK ,
     *  MII_RXER
     */
    GPIODirModeSet(
        GPIO_PORTJ_BASE, GPIO_PIN_7|GPIO_PIN_6|GPIO_PIN_5|GPIO_PIN_4|
        GPIO_PIN_3|
        GPIO_PIN_2|GPIO_PIN_0, GPIO_DIR_MODE_HW);
    GPIOPadConfigSet(
        GPIO_PORTJ_BASE, GPIO_PIN_7|GPIO_PIN_6|GPIO_PIN_5|GPIO_PIN_4|
        GPIO_PIN_3|
        GPIO_PIN_2|GPIO_PIN_0, GPIO_PIN_TYPE_STD);
    HWREG(GPIO_PORTJ_BASE + GPIO_O_APSEL)|= 0x000000FC;
    HWREG(GPIO_PORTJ_BASE + GPIO_O_PCTL) &= 0x000000F0;
    HWREG(GPIO_PORTJ_BASE + GPIO_O_PCTL) |= 0xCCCCCC03;
        
    /* Enable and Reset the Ethernet Controller. */
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ETH);
    SysCtlPeripheralReset(SYSCTL_PERIPH_ETH);
    
    if (macAddress[0] == 0xff && macAddress[1] == 0xff &&
        macAddress[2] == 0xff && macAddress[3] == 0xff &&
        macAddress[4] == 0xff && macAddress[5] == 0xff) {
        System_abort("Change the macAddress variable to match your board's MAC sticker");
    }

    /* Once EMAC_init is called, EMAC_config cannot be changed */
    EMAC_init();
}

/*
 *  ======== TMDXDOCKH52C1_initGeneral ========
 */
Void TMDXDOCKH52C1_initGeneral(Void)
{
    /* Disable Protection */
    HWREG(SYSCTL_MWRALLOW) =  0xA5A5A5A5;
    // 100MHz - M3 and 100MHz - C28x
    SysCtlClockConfigSet(SYSCTL_SYSDIV_1 | SYSCTL_M3SSDIV_1 | SYSCTL_USE_PLL |
                         (SYSCTL_SPLLIMULT_M & 0x14));
    /* Enable clock supply for the following peripherals */
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOG);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOH);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOJ);

    /* Disable clock supply for the watchdog modules */
    SysCtlPeripheralDisable(SYSCTL_PERIPH_WDOG1);
    SysCtlPeripheralDisable(SYSCTL_PERIPH_WDOG0);
}

/*
 *  ======== TMDXDOCKH52C1_initI2C ========
 */
Void TMDXDOCKH52C1_initI2C(Void)
{
    /* I2C0 Init */
    /* Enable the peripheral */
    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);

    /* Initialize the I2C master. 400KHz */
    I2CMasterInitExpClk(I2C0_MASTER_BASE, SysCtlClockGet(SYSTEM_CLOCK_SPEED), TRUE);

    /* Configure the appropriate pins to be I2C instead of GPIO. */
    GPIOPinUnlock(GPIO_PORTB_BASE, GPIO_PIN_7);
    GPIOPinConfigure(GPIO_PB7_I2C0SCL); /* GPIO15 on Concerto base board */
    GPIOPinConfigure(GPIO_PB6_I2C0SDA); /* GPIO14 on Concerto base board */
    GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_6 | GPIO_PIN_7);
    
    /* I2C1 Init */
    /* Enable the peripheral */
    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C1);

    /* Initialize the I2C master. 400KHz */
    I2CMasterInitExpClk(I2C1_MASTER_BASE, SysCtlClockGet(SYSTEM_CLOCK_SPEED), TRUE);

    /* Configure the appropriate pins to be I2C instead of GPIO. */
    GPIOPinConfigure(GPIO_PA0_I2C1SCL);
    GPIOPinConfigure(GPIO_PA1_I2C1SDA);
    GPIOPinTypeI2C(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    
    I2C_init();
}

/*
 *  ======== TMDXDOCKH52C1_initGPIO ========
 */
Void TMDXDOCKH52C1_initGPIO(Void)
{
    /* Setup the LED GPIO pins used */ 
    GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE,GPIO_PIN_1);  /* TMDXDOCKH52C1_LD2 */
    GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE,GPIO_PIN_2);  /* T_RW */
    
    /* Setup the button GPIO pins used */
    GPIOPinTypeGPIOInput(GPIO_PORTD_BASE,GPIO_PIN_1);   /* TMDXDOCKH52C1_BUTTON */
//    GPIOPadConfigSet(GPIO_PORTB_BASE, GPIO_PIN_2, GPIO_PIN_TYPE_STD_WPU);
    
    /* Once GPIO_init is called, GPIO_config cannot be changed */
    GPIO_init();
    
    GPIO_write(TMDXDOCKH52C1_LD2, TMDXDOCKH52C1_LED_OFF);
//    GPIO_write(TMDXDOCKH52C1_LD3, TMDXDOCKH52C1_LED_OFF);
}

/*
 *  ======== TMDXDOCKH52C1_initSDSPI ========
 */
Void TMDXDOCKH52C1_initSDSPI(Void)
{
    SDSPI_HWAttrs const *attrs;
    
    /* Enable the peripherals used by the SD Card */
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);

    /* Configure SSI Peripheral pin muxing */
    GPIOPinConfigure(GPIO_PD2_SSI0CLK);
    GPIOPinConfigure(GPIO_PD0_SSI0TX);
    GPIOPinConfigure(GPIO_PD1_SSI0RX);

    attrs = SDSPI_config.hwAttrs;
    
    /* Configure pad settings */
    GPIOPadConfigSet(attrs->portSPI,
            attrs->pinSCK | attrs->pinMISO | attrs->pinMOSI,
            GPIO_PIN_TYPE_STD_WPU);

    GPIOPadConfigSet(attrs->portCS, attrs->pinCS, GPIO_PIN_TYPE_STD_WPU);

    /* Set to a 400 kHz SPI bit rate */
    SSIConfigSetExpClk(attrs->baseAddr,
            SysCtlClockGet(SYSTEM_CLOCK_SPEED),
            SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 400000, 8);

    /* Configure the SPI and GPIO ports based on the config structure */
    SDSPI_init();

}

/*
 *  ======== TMDXDOCKH52C1_initUART ========
 */
Void TMDXDOCKH52C1_initUART()
{    
    /* Enable and configure the peripherals used by the uart. */
//    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
//    GPIOPinTypeUART(GPIO_PORTE_BASE, GPIO_PIN_4 | GPIO_PIN_5);
//    GPIOPinConfigure(GPIO_PE4_U0RX);
//    GPIOPinConfigure(GPIO_PE5_U0TX);
//    GPIOPadConfigSet(GPIO_PORTE_BASE, GPIO_PIN_4 | GPIO_PIN_5, GPIO_PIN_TYPE_STD_WPU);
//
    /* Enable and configure the peripherals used by the uart. */
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1);
    GPIOPinTypeUART(GPIO_PORTB_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    GPIOPinConfigure(GPIO_PB0_U1RX);
    GPIOPinConfigure(GPIO_PB1_U1TX);
    UARTConfigSetExpClk(UART1_BASE, SysCtlClockGet(OSCCLKIN), UART1_BAUD,(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));

    /* Initialize the UART driver */
    UART_init();
}

/*
 *  ======== TMDXDOCKH52C1_initUSB ========
 *  This function just turns on the USB
 */
Void TMDXDOCKH52C1_initUSB(TMDXDOCKH52C1_USBMode usbMode)
{
    /* 
     * Setup USB clock tree for 60MHz
     * 20MHz * 12 / 4 = 60
     */
    SysCtlUSBPLLConfigSet(
            (SYSCTL_UPLLIMULT_M & 12) | SYSCTL_UPLLCLKSRC_X1 | SYSCTL_UPLLEN);

    /* Setup pins for USB operation */
    GPIOPinTypeUSBAnalog(GPIO_PORTF_BASE, GPIO_PIN_6);
    GPIOPinTypeUSBAnalog(
            GPIO_PORTG_BASE, GPIO_PIN_2 | GPIO_PIN_5 | GPIO_PIN_6);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);

    /* Additional configurations for Host mode */
    if (usbMode == TMDXDOCKH52C1_USBHOST) {
        /* Configure the pins needed */
        GPIOPinConfigure(GPIO_PC5_USB0EPEN);
        GPIOPinConfigure(GPIO_PJ1_USB0PFLT);
        GPIOPinTypeUSBDigital(GPIO_PORTC_BASE, GPIO_PIN_5);
        GPIOPinTypeUSBDigital(GPIO_PORTJ_BASE, GPIO_PIN_1);
    }
}

/*
 *  ======== TMDXDOCKH52C1_initUSBMSCHFatFs ========
 */
Void TMDXDOCKH52C1_initUSBMSCHFatFs(Void)
{
    /* Call the USB initialization function for the USB Reference modules */
    TMDXDOCKH52C1_initUSB(TMDXDOCKH52C1_USBHOST);
    USBMSCHFatFs_init();
}

/*
 *  ======== TMDXDOCKH52C1_setMaxSPIbitrate ========
 */
static Void TMDXDOCKH52C1_setMaxSPIbitrate(SDSPI_Handle handle)
{
    /* Set to a 12.5 MHz SPI bit rate */
    SSIConfigSetExpClk(handle->hwAttrs->baseAddr,
            SysCtlClockGet(SYSTEM_CLOCK_SPEED),
            SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 12500000, 8);
}

