/*
 * sja1102.c Ethernet switch driver.
 *
 *  created on: June 2020
 *  Originated from mcp3912.c, created on: 22 Aug 2018
 *  Original author: lx
 */

#include "sja1105.h"

#include <stdint.h>

#include "fsl_lpspi.h"
#include "fsl_gpio.h"
#include "MIMXRT1062.h"

//************************************************************************
//
// DEFINITIONS AND MACROS
//
//************************************************************************

#define SJA1105_LPSPI_MASTER_BASEADDR    (LPSPI1)
#define SJA1105_LPSPI_MASTER_IRQN        LPSPI1_IRQn
#define SJA1105_LPSPI_MASTER_IRQHandler  LPSPI1_IRQHandler

#define LPSPI_PRIORITY            (8U)   // interrupt priority
#define LPSPI_MASTER_PCS_FOR_INIT (kLPSPI_Pcs0)
#define LPSPI_MASTER_PCS_FOR_TRANSFER (kLPSPI_MasterPcs0)

#define LPSPI_CLOCK_SOURCE_SELECT (1U)  /* Select USB1 PLL PFD0 (720 MHz) as lpspi clock source */
#define LPSPI_CLOCK_SOURCE_DIVIDER (7U) /* Clock divider for master lpspi clock source */
#define LPSPI_MASTER_CLK_FREQ (CLOCK_GetFreq(kCLOCK_Usb1PllPfd0Clk) / (LPSPI_CLOCK_SOURCE_DIVIDER + 1U))
#define TRANSFER_BAUDRATE 16000000U       /* Transfer baudrate = 16M */

#define MAX_SAMPLE_DATA         4   // TODO - This is a setting for the ADS8688 ADC, review its use here.

#define PORT0_STATUS_MII_ADDR   0x100900          // Port0 Status Register addr

#define PLL_1_C_ADDR            0x10000A          // PLL_1 Control Register addr

#define CFG_PAD_MII3_RX_ADDR    0x100807          // PLL_1 Control Register addr
#define CFG_PAD_MII4_RX_ADDR    0x100809          // PLL_1 Control Register addr

#define IDIV_0_C_ADDR           0x10000B          // IDIV_0 Control Register addr
#define IDIV_1_C_ADDR           0x10000C          // IDIV_1 Control Register addr
#define IDIV_2_C_ADDR           0x10000D          // IDIV_2 Control Register addr
#define IDIV_3_C_ADDR           0x10000E          // IDIV_3 Control Register addr
#define IDIV_4_C_ADDR           0x10000F          // IDIV_4 Control Register addr

#define MII0_RMII_REF_CLK       0x100015          // MII0_RMII_REF_CLK Register addr
#define MII1_RMII_REF_CLK       0x10001C          // MII1_RMII_REF_CLK Register addr
#define MII2_RMII_REF_CLK       0x100023          // MII2_RMII_REF_CLK Register addr
#define MII3_RMII_REF_CLK       0x10002A          // MII3_RMII_REF_CLK Register addr
#define MII4_RMII_REF_CLK       0x100031          // MII4_RMII_REF_CLK Register addr

#define MII0_EXT_TX_CLK         0x100018          // MII0_EXT_TX_CLK Register addr
#define MII1_EXT_TX_CLK         0x10001F          // MII1_EXT_TX_CLK Register addr
#define MII2_EXT_TX_CLK         0x100026          // MII2_EXT_TX_CLK Register addr
#define MII3_EXT_TX_CLK         0x10002D          // MII3_EXT_TX_CLK Register addr

#define SJA1105_CS_GPIO GPIO3
#define SJA1105_CS_GPIO_PIN      (13U)

// Automotive Ethernet TJA1102 PHY definitions  TODO - Split PHY init to its own driver file?
#define TJA1102_RES_GPIO GPIO3
#define TJA1102_RES_GPIO_PIN      (17U)

#define TJA1102_EN_GPIO GPIO3
#define TJA1102_EN_GPIO_PIN       (25U)


//************************************************************************
//
// LOCAL VARIABLES AND CONSTS
//
//************************************************************************

uint32_t pll_1_c_reg_0;
uint32_t device_id_reg_0;
uint32_t config_status_info_0;
uint32_t port_status_mii_reg_0[5];
uint32_t cfg_pad_mii3_rx_reg0;
uint32_t cfg_pad_mii4_rx_reg0;

uint32_t pll_1_c_reg;
uint32_t device_id_reg;
uint32_t config_status_info;
uint32_t port_status_mii_reg[5];
uint32_t cfg_pad_mii3_rx_reg;
uint32_t cfg_pad_mii4_rx_reg;

uint32_t general_status_reg1;
uint32_t general_status_reg5;

// Modified config_Basic_L2_Switching_No_Priority_Queue_RMII_100, IGNORE2SF = 1, Port 3 not router to port4, port 0; Port 4 not router to port3, port 0.
static const uint8_t config_data_0[] = { 0x80, 0x20, 0x00, 0x00, 0x9E, 0x00, 0x03, 0x0E, 0x06, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x21, 0x6F, 0x25, 0x6B,
										 0xFE, 0xF7, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7,
										 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00,
										 0x03, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x03, 0xFF,
										 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF,
										 0xFE, 0xF7, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7,
										 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00,
										 0x03, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x07, 0xFF,
										 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF,
										 0xFE, 0xF7, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7,
										 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00,
										 0x07, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x07, 0xFF,
										 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF,
										 0xFE, 0xF7, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7,
										 0x00, 0x00, 0x0B, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00,
										 0x0B, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x0B, 0xFF,
										 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x0B, 0xFF, 0xFF, 0xFF,
										 0xFE, 0xF7, 0x00, 0x00, 0x0B, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7,
										 0x00, 0x00, 0x0B, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00,
										 0x0B, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x0B, 0xFF,
										 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF,
										 0xFE, 0xF7, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7,
										 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00,
										 0x0F, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x0F, 0xFF,
										 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF };

static const uint8_t config_data_1[] = { 0x80, 0x20, 0x04, 0x00, 0xFE, 0xF7, 0x00, 0x00, 0x0F, 0xFF,
										 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF,
										 0xFE, 0xF7, 0x00, 0x00, 0x13, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7,
										 0x00, 0x00, 0x13, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00,
										 0x13, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x13, 0xFF,
										 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x13, 0xFF, 0xFF, 0xFF,
										 0xFE, 0xF7, 0x00, 0x00, 0x13, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7,
										 0x00, 0x00, 0x13, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00,
										 0x13, 0xFF, 0xFF, 0xFF, 0xFA, 0x2E, 0x19, 0xF8, 0x07, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0xF2, 0x69, 0x5C, 0xA5,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x08, 0x00,
										 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x80, 0x48, 0x00, 0x00, 0x00,
										 0x00, 0x3F, 0xF0, 0x02, 0x52, 0x13, 0x87, 0x7B, 0x08, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x6A, 0xF6, 0x23, 0x53,
										 0x10, 0x00, 0x00, 0x00, 0xF7, 0xBD, 0xF5, 0x8D, 0x10, 0x00,
										 0x00, 0x00, 0xE7, 0x39, 0xF5, 0x8D, 0x10, 0x00, 0x00, 0x00,
										 0xD6, 0xB5, 0xF5, 0x8D, 0x10, 0x00, 0x00, 0x00, 0x31, 0x8D,
										 0xF5, 0x8D, 0x10, 0x00, 0x00, 0x00, 0x31, 0x8D, 0xF5, 0x8D,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0xA7, 0x5A, 0x43, 0x5A, 0x09, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0xDA, 0xB5, 0xBD, 0xC8 };

static const uint8_t config_data_2[] = { 0x80, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00,
										 0x00, 0x00, 0x07, 0xFC, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
										 0x07, 0xFC, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFC,
										 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFC, 0x01, 0x04,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
										 0x00, 0x00, 0x00, 0x00, 0x07, 0xFC, 0x01, 0x04, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0xE6, 0x79, 0x95, 0xD2, 0x0D, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x25, 0x0E, 0x7C, 0xBD,
										 0x00, 0x01, 0x25, 0xC0, 0x70, 0x94, 0x84, 0x50, 0x0E, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xC8, 0xA7, 0xCE, 0xE6,
										 0x00, 0x71, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0xC3, 0xF7, 0x04, 0xB9, 0x11, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x0A, 0x57, 0x1F, 0x81, 0x3F, 0x06, 0x44,
										 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00,
										 0xFF, 0x0D, 0x30, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
										 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x49, 0xA2,
										 0x6A, 0xBE, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };

static const uint8_t config_data_3[] = { 0x80, 0x20, 0x0C, 0x00, 0x3A, 0x5D, 0x5E, 0x24, 0xB4, 0x00,
										 0x00, 0x00, 0xED, 0x48, 0xA8, 0x89, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x4F, 0x18, 0x7C, 0xE2 };


/*
// Modified config_Basic_L2_Switching_No_Priority_Queue_RMII_100, IGNORE2SF = 1
static const uint8_t config_data_0[] = { 0x80, 0x20, 0x00, 0x00, 0x9E, 0x00, 0x03, 0x0E, 0x06, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x21, 0x6F, 0x25, 0x6B,
										 0xFE, 0xF7, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7,
										 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00,
										 0x03, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x03, 0xFF,
										 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF,
										 0xFE, 0xF7, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7,
										 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00,
										 0x03, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x07, 0xFF,
										 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF,
										 0xFE, 0xF7, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7,
										 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00,
										 0x07, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x07, 0xFF,
										 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF,
										 0xFE, 0xF7, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7,
										 0x00, 0x00, 0x0B, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00,
										 0x0B, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x0B, 0xFF,
										 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x0B, 0xFF, 0xFF, 0xFF,
										 0xFE, 0xF7, 0x00, 0x00, 0x0B, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7,
										 0x00, 0x00, 0x0B, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00,
										 0x0B, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x0B, 0xFF,
										 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF,
										 0xFE, 0xF7, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7,
										 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00,
										 0x0F, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x0F, 0xFF,
										 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF };

static const uint8_t config_data_1[] = { 0x80, 0x20, 0x04, 0x00, 0xFE, 0xF7, 0x00, 0x00, 0x0F, 0xFF,
										 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF,
										 0xFE, 0xF7, 0x00, 0x00, 0x13, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7,
										 0x00, 0x00, 0x13, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00,
										 0x13, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x13, 0xFF,
										 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00, 0x13, 0xFF, 0xFF, 0xFF,
										 0xFE, 0xF7, 0x00, 0x00, 0x13, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7,
										 0x00, 0x00, 0x13, 0xFF, 0xFF, 0xFF, 0xFE, 0xF7, 0x00, 0x00,
										 0x13, 0xFF, 0xFF, 0xFF, 0xFA, 0x2E, 0x19, 0xF8, 0x07, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0xF2, 0x69, 0x5C, 0xA5,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x08, 0x00,
										 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x80, 0x48, 0x00, 0x00, 0x00,
										 0x00, 0x3F, 0xF0, 0x02, 0x52, 0x13, 0x87, 0x7B, 0x08, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x6A, 0xF6, 0x23, 0x53,
										 0x10, 0x00, 0x00, 0x00, 0xF7, 0xBD, 0xF5, 0x8D, 0x10, 0x00,
										 0x00, 0x00, 0xEF, 0x7B, 0xF5, 0x8D, 0x10, 0x00, 0x00, 0x00,
										 0xDE, 0xF7, 0xF5, 0x8D, 0x10, 0x00, 0x00, 0x00, 0xBD, 0xEF,
										 0xF5, 0x8D, 0x10, 0x00, 0x00, 0x00, 0x7B, 0xDF, 0xF5, 0x8D,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0xC0, 0x04, 0xA6, 0x06, 0x09, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0xDA, 0xB5, 0xBD, 0xC8 };

static const uint8_t config_data_2[] = { 0x80, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00,
										 0x00, 0x00, 0x07, 0xFC, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
										 0x07, 0xFC, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFC,
										 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFC, 0x01, 0x04,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
										 0x00, 0x00, 0x00, 0x00, 0x07, 0xFC, 0x01, 0x04, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0xE6, 0x79, 0x95, 0xD2, 0x0D, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x25, 0x0E, 0x7C, 0xBD,
										 0x00, 0x01, 0x25, 0xC0, 0x70, 0x94, 0x84, 0x50, 0x0E, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xC8, 0xA7, 0xCE, 0xE6,
										 0x00, 0x71, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0xC3, 0xF7, 0x04, 0xB9, 0x11, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x0A, 0x57, 0x1F, 0x81, 0x3F, 0x06, 0x44,
										 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00,
										 0xFF, 0x0D, 0x30, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
										 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x49, 0xA2,
										 0x6A, 0xBE, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };

static const uint8_t config_data_3[] = { 0x80, 0x20, 0x0C, 0x00, 0x3A, 0x5D, 0x5E, 0x24, 0xB4, 0x00,
										 0x00, 0x00, 0xED, 0x48, 0xA8, 0x89, 0x00, 0x00, 0x00, 0x00,
										 0x00, 0x00, 0x00, 0x00, 0x4F, 0x18, 0x7C, 0xE2 };
*/

__attribute__((unused))
static const uint8_t config_pll_1_0[] = { 0x81, 0x00, 0x00, 0xA0, 0x0A, 0x00, 0x00, 0x01};
static const uint8_t config_pll_1_1[] = { 0x81, 0x00, 0x00, 0xA0, 0x0A, 0x00, 0x00, 0x00};

// static const uint8_t config_IDIV_0[] = { 0x81, 0x00, 0x00, 0xB0, 0x0A, 0x00, 0x00, 0x01};
static const uint8_t config_IDIV_1[] = { 0x81, 0x00, 0x00, 0xC0, 0x0A, 0x00, 0x00, 0x01};
static const uint8_t config_IDIV_2[] = { 0x81, 0x00, 0x00, 0xD0, 0x0A, 0x00, 0x00, 0x01};
static const uint8_t config_IDIV_3[] = { 0x81, 0x00, 0x00, 0xE0, 0x0A, 0x00, 0x00, 0x01};
static const uint8_t config_IDIV_4[] = { 0x81, 0x00, 0x00, 0xF0, 0x0A, 0x00, 0x00, 0x01};

// static const uint8_t config_MII0_RMII_REF_CLK[] = { 0x81, 0x00, 0x01, 0x50, 0x00, 0x00, 0x08, 0x00};
// static const uint8_t config_MII1_RMII_REF_CLK[] = { 0x81, 0x00, 0x01, 0xC0, 0x02, 0x00, 0x08, 0x00};
// static const uint8_t config_MII2_RMII_REF_CLK[] = { 0x81, 0x00, 0x02, 0x30, 0x04, 0x00, 0x08, 0x00};
static const uint8_t config_MII3_RMII_REF_CLK[] = { 0x81, 0x00, 0x02, 0xA0, 0x06, 0x00, 0x08, 0x00};
static const uint8_t config_MII4_RMII_REF_CLK[] = { 0x81, 0x00, 0x03, 0x10, 0x08, 0x00, 0x08, 0x00};

// static const uint8_t config_MII0_EXT_TX_CLK[] = { 0x81, 0x00, 0x01, 0x80, 0x0E, 0x00, 0x08, 0x00};
// static const uint8_t config_MII1_EXT_TX_CLK[] = { 0x81, 0x00, 0x01, 0xF0, 0x0E, 0x00, 0x08, 0x00};
static const uint8_t config_MII1_MII_RX_CLK[] = { 0x81, 0x00, 0x01, 0xB0, 0x03, 0x00, 0x08, 0x00};
static const uint8_t config_MII2_MII_RX_CLK[] = { 0x81, 0x00, 0x02, 0x20, 0x05, 0x00, 0x08, 0x00};

static const uint8_t config_MII1_MII_TX_CLK[] = { 0x81, 0x00, 0x01, 0xA0, 0x02, 0x00, 0x08, 0x00};
static const uint8_t config_MII2_MII_TX_CLK[] = { 0x81, 0x00, 0x02, 0x10, 0x04, 0x00, 0x08, 0x00};

static const uint8_t config_PAD_MII3_RX[] = { 0x81, 0x00, 0x80, 0x70, 0x02, 0x03, 0x03, 0x12};
static const uint8_t config_PAD_MII4_RX[] = { 0x81, 0x00, 0x80, 0x90, 0x02, 0x03, 0x03, 0x12};


//************************************************************************
//
// LOCAL PROTOTYPES
//
//************************************************************************

static void delay(void);
static void initGPIO_SAJ1105_CS(void);
static void InitSJA1105_SPI(void);
static void Write_SJA1105_config(LPSPI_Type *base, const uint8_t *config_data, uint16_t length);
static uint32_t ReadSJA1105(LPSPI_Type *base, uint32_t address);
static void Read_SJA1105_Internal_Registers(LPSPI_Type *base);
static void Write_SJA1105_config(LPSPI_Type *base, const uint8_t *config_data, uint16_t length);

//************************************************************************
//
// FUNCTIONS
//
//************************************************************************

// Blocking delay.
// jem TODO - This was in the main() of Lees ac_analogue project. Replace with tick based solution?
static void delay(void)
{
    volatile uint32_t i = 0;
    for (i = 0; i < 1000000; ++i)
    {
        __asm("NOP"); /* delay */
    }
}

static void initGPIO_SAJ1105_CS(void)
{
    /* Define the init structure for the input switch pin */
    gpio_pin_config_t ps_config_out = {kGPIO_DigitalOutput, 1, kGPIO_NoIntmode};

    /* Init output SJA1105 CS GPIO. */
    GPIO_PinInit(SJA1105_CS_GPIO, SJA1105_CS_GPIO_PIN, &ps_config_out);

}



void initGPIO_TAJ1102(void)
{
    /* Define the init structure for the input switch pin */
    gpio_pin_config_t ps_config_out = {kGPIO_DigitalOutput, 1, kGPIO_NoIntmode};

    /* Init output TJA1102 RES GPIO. */
    GPIO_PinInit(TJA1102_RES_GPIO, TJA1102_RES_GPIO_PIN, &ps_config_out);

    /* Init output TJA1102 EN GPIO. */
    GPIO_PinInit(TJA1102_EN_GPIO, TJA1102_EN_GPIO_PIN, &ps_config_out);

    /* Reset TJA1102 */
    GPIO_WritePinOutput(TJA1102_RES_GPIO, TJA1102_RES_GPIO_PIN, 0);
    delay();
    GPIO_WritePinOutput(TJA1102_RES_GPIO, TJA1102_RES_GPIO_PIN, 1);
//    delay();

    /* Enable TJA1102 */
    GPIO_WritePinOutput(TJA1102_EN_GPIO, TJA1102_EN_GPIO_PIN, 1);
    delay();

}



//>>>>>>> Read the registers from SJA1105
static uint32_t ReadSJA1105(LPSPI_Type *base, uint32_t address)
{
	uint32_t read_command;
	uint32_t register_value;
	__attribute__((unused)) volatile uint8_t receive_data;

	uint8_t data0, data1, data2, data3;

	read_command = (uint32_t)(0x01<<25) | (uint32_t)(address<<4);

	// Reset Receive & Transmit FIFO
    base->CR |= (LPSPI_CR_RRF_MASK | LPSPI_CR_RTF_MASK);

	// Drop the CS signal
    GPIO_PinWrite(SJA1105_CS_GPIO, SJA1105_CS_GPIO_PIN, 0U);

	// Transmit the SJA1105 read control double word
	base->TDR = (uint32_t)(read_command >> 24);
    while (LPSPI_GetRxFifoCount(base) == 0);
    receive_data = (uint8_t)(base->RDR & 0xFF);

	base->TDR = (uint32_t)(read_command >> 16);
    while (LPSPI_GetRxFifoCount(base) == 0);
    receive_data = (uint8_t)(base->RDR & 0xFF);

	base->TDR = (uint32_t)(read_command >> 8);
    while (LPSPI_GetRxFifoCount(base) == 0);
    receive_data = (uint8_t)(base->RDR & 0xFF);

	base->TDR = (uint32_t)(read_command);
    while (LPSPI_GetRxFifoCount(base) == 0);
    receive_data = (uint8_t)(base->RDR & 0xFF);

    // Read out the register value
    base->TDR = 0;
    while (LPSPI_GetRxFifoCount(base) == 0);
    data0 = (uint8_t)(base->RDR & 0xFF);

    base->TDR = 0;
    while (LPSPI_GetRxFifoCount(base) == 0);
    data1 = (uint8_t)(base->RDR & 0xFF);

    base->TDR = 0;
    while (LPSPI_GetRxFifoCount(base) == 0);
    data2 = (uint8_t)(base->RDR & 0xFF);

    base->TDR = 0;
    while (LPSPI_GetRxFifoCount(base) == 0);
    data3 = (uint8_t)(base->RDR & 0xFF);

	// Raise the CS signal
	GPIO_PinWrite(SJA1105_CS_GPIO, SJA1105_CS_GPIO_PIN, 1U);

	register_value = (uint32_t)((data0<<24) | (data1<<16) | (data2<<8) | data3);

	return(register_value);
}

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//  Reads the registers from SJA1105
static void Read_SJA1105_Internal_Registers(LPSPI_Type *base)
{

	// Read the Device ID register (address: 00h)
	device_id_reg = ReadSJA1105(base, 0x00);

	// Read the Configuration status information (address: 01h)
	config_status_info = ReadSJA1105(base, 0x01);

	// Read the general status register	1 (address: 03h)
	general_status_reg1 = ReadSJA1105(base, 0x03);

	// Read the general status register	5 (address: 07h)
	general_status_reg5 = ReadSJA1105(base, 0x07);

	cfg_pad_mii3_rx_reg = ReadSJA1105(base, CFG_PAD_MII3_RX_ADDR);

	cfg_pad_mii4_rx_reg = ReadSJA1105(base, CFG_PAD_MII4_RX_ADDR);


}


//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//   Write the SJA1105 configuration memory
static void Write_SJA1105_config(LPSPI_Type *base, const uint8_t *config_data, uint16_t length)
{
	int i;
    __attribute__((unused)) volatile uint8_t receive_data;

	// Reset Receive FIFO
    base->CR |= (LPSPI_CR_RRF_MASK | LPSPI_CR_RTF_MASK);

	// Drop the CS signal
	GPIO_PinWrite(SJA1105_CS_GPIO, SJA1105_CS_GPIO_PIN, 0U);

	for(i=0; i<length; i++)
	{
		base->TDR = config_data[4*i];
		while (LPSPI_GetRxFifoCount(base) == 0);
		receive_data = (uint8_t)(base->RDR & 0xFF);

		base->TDR = config_data[4*i + 1];
		while (LPSPI_GetRxFifoCount(base) == 0);
		receive_data = (uint8_t)(base->RDR & 0xFF);

		base->TDR = config_data[4*i + 2];
		while (LPSPI_GetRxFifoCount(base) == 0);
		receive_data = (uint8_t)(base->RDR & 0xFF);

		base->TDR = config_data[4*i + 3];
		while (LPSPI_GetRxFifoCount(base) == 0);
		receive_data = (uint8_t)(base->RDR & 0xFF);
	}

	// Raise the CS signal
	GPIO_PinWrite(SJA1105_CS_GPIO, SJA1105_CS_GPIO_PIN, 1U);
}

static void InitSJA1105_SPI(void)
{
    uint32_t whichPcs;
    uint8_t txWatermark;
    uint8_t rxWatermark;
    lpspi_master_config_t masterConfig;
    LPSPI_Type *base = SJA1105_LPSPI_MASTER_BASEADDR;
    uint32_t srcClock_Hz;
    __attribute__((unused)) uint32_t usbClock;

    // Set clock source for LPSPI
    CLOCK_SetMux(kCLOCK_LpspiMux, LPSPI_CLOCK_SOURCE_SELECT);
    CLOCK_SetDiv(kCLOCK_LpspiDiv, LPSPI_CLOCK_SOURCE_DIVIDER);

    // Master config
    masterConfig.baudRate = TRANSFER_BAUDRATE;
    masterConfig.bitsPerFrame = 8;                        // 8 bits format
    masterConfig.cpol = kLPSPI_ClockPolarityActiveHigh;   // CPOL = 0
    masterConfig.cpha = kLPSPI_ClockPhaseSecondEdge;      // CPHA = 1
    masterConfig.direction = kLPSPI_MsbFirst;

    masterConfig.pcsToSckDelayInNanoSec = 500000000 / masterConfig.baudRate;
    masterConfig.lastSckToPcsDelayInNanoSec = 500000000 / masterConfig.baudRate;
    masterConfig.betweenTransferDelayInNanoSec = 500000000 / masterConfig.baudRate;

    masterConfig.whichPcs = LPSPI_MASTER_PCS_FOR_INIT;
    masterConfig.pcsActiveHighOrLow = kLPSPI_PcsActiveLow;

#ifdef REVISION_A_BOARD
    masterConfig.pinCfg = kLPSPI_SdoInSdiOut;
#else
    masterConfig.pinCfg = kLPSPI_SdiInSdoOut;
#endif
    masterConfig.dataOutConfig = kLpspiDataOutRetained;

    usbClock = CLOCK_GetFreq(kCLOCK_Usb1PllPfd0Clk);
    srcClock_Hz = LPSPI_MASTER_CLK_FREQ;
//    srcClock_Hz = 4500000;

    whichPcs = LPSPI_MASTER_PCS_FOR_INIT;

    // The TX and RX FIFO sizes are always the same
//    g_masterFifoSize = LPSPI_GetRxFifoSize(base);

    // Set the RX and TX watermarks to reduce the ISR times.
	txWatermark = 0;
	rxWatermark = 0;

    LPSPI_MasterInit(base, &masterConfig, srcClock_Hz);

    LPSPI_SetFifoWatermarks(base, txWatermark, rxWatermark);

    LPSPI_Enable(base, false);
    base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK);
    LPSPI_Enable(base, true);

    // Flush FIFO , clear status , disable all the inerrupts.
    LPSPI_FlushFifo(base, true, true);
    LPSPI_ClearStatusFlags(base, kLPSPI_AllStatusFlag);
    LPSPI_DisableInterrupts(base, kLPSPI_AllInterruptEnable);

    // Set the Transmit Command Register (TCR)

    base->TCR =
            (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_RXMSK_MASK | LPSPI_TCR_PCS_MASK)) |
            LPSPI_TCR_CONT(0) | LPSPI_TCR_CONTC(0) | LPSPI_TCR_RXMSK(0) | LPSPI_TCR_TXMSK(0) | LPSPI_TCR_PCS(whichPcs);

    // TCR is also shared the FIFO , so wait for TCR written.
    while (LPSPI_GetTxFifoCount(base) != 0)
    {
    }

    NVIC_SetPriority(SJA1105_LPSPI_MASTER_IRQN, LPSPI_PRIORITY);
}

// Function to initialise SJA Automotive Ethernet Switch
void initSJA1105(void)
{
	int i;
	uint32_t read_address;

	initGPIO_SAJ1105_CS();

	initGPIO_TAJ1102();  // TODO - This should be part of the PHY driver (if we ever need it)

    InitSJA1105_SPI();

	// Read the PLL_1 Control register (address: 10000Ah)
	pll_1_c_reg_0 = ReadSJA1105(SJA1105_LPSPI_MASTER_BASEADDR, PLL_1_C_ADDR);

	// Read the Device ID register (address: 00h)
	device_id_reg_0 = ReadSJA1105(SJA1105_LPSPI_MASTER_BASEADDR, 0x00);

	// Read the Configuration status information (address: 01h)
	config_status_info_0 = ReadSJA1105(SJA1105_LPSPI_MASTER_BASEADDR, 0x01);

	cfg_pad_mii3_rx_reg0 = ReadSJA1105(SJA1105_LPSPI_MASTER_BASEADDR, CFG_PAD_MII3_RX_ADDR);

	cfg_pad_mii4_rx_reg0 = ReadSJA1105(SJA1105_LPSPI_MASTER_BASEADDR, CFG_PAD_MII4_RX_ADDR);

	// Read the port status register (address: 100900h + i)
	for(i=0; i<5; i++)
	{
		read_address = PORT0_STATUS_MII_ADDR + i;
		port_status_mii_reg_0[i] = ReadSJA1105(SJA1105_LPSPI_MASTER_BASEADDR, read_address);
	}

	// Write config_data_0
	Write_SJA1105_config(SJA1105_LPSPI_MASTER_BASEADDR, config_data_0, 65);

	// Write config_data_1
	Write_SJA1105_config(SJA1105_LPSPI_MASTER_BASEADDR, config_data_1, 65);

	// Write config_data_2
	Write_SJA1105_config(SJA1105_LPSPI_MASTER_BASEADDR, config_data_2, 65);

	// Write config_data_3
	Write_SJA1105_config(SJA1105_LPSPI_MASTER_BASEADDR, config_data_3, 7);

	// Write PLL_1 control register 1st time
//	Write_SJA1105_config(EXAMPLE_LPSPI_MASTER_BASEADDR, config_pll_1_0, 2);
	// Write PLL_1 control register 2nd time
	Write_SJA1105_config(SJA1105_LPSPI_MASTER_BASEADDR, config_pll_1_1, 2);

	/* Port0 not used for digital I/O
	// Write IDIV_0_C control register
	Write_SJA1105_config(EXAMPLE_LPSPI_MASTER_BASEADDR, config_IDIV_0, 2);

	// Write MII0_RMII_REF_CLK register
	Write_SJA1105_config(EXAMPLE_LPSPI_MASTER_BASEADDR, config_MII0_RMII_REF_CLK, 2);

	// Write MII0_EXT_TX_CLK register
	Write_SJA1105_config(EXAMPLE_LPSPI_MASTER_BASEADDR, config_MII0_EXT_TX_CLK, 2);
    */
	// Write IDIV_1_C control register
	Write_SJA1105_config(SJA1105_LPSPI_MASTER_BASEADDR, config_IDIV_1, 2);

	// Write MII1_RMII_REF_CLK register
	// Write_SJA1105_config(EXAMPLE_LPSPI_MASTER_BASEADDR, config_MII1_RMII_REF_CLK, 2);

	// Write MII1_EXT_TX_CLK register
	//Write_SJA1105_config(EXAMPLE_LPSPI_MASTER_BASEADDR, config_MII1_EXT_TX_CLK, 2);

	// Write MII1_MII_RX_CLK register
	Write_SJA1105_config(SJA1105_LPSPI_MASTER_BASEADDR, config_MII1_MII_RX_CLK, 2);

	// Write MII1_MII_TX_CLK register
	Write_SJA1105_config(SJA1105_LPSPI_MASTER_BASEADDR, config_MII1_MII_TX_CLK, 2);


	// Write IDIV_2_C control register
	Write_SJA1105_config(SJA1105_LPSPI_MASTER_BASEADDR, config_IDIV_2, 2);

	// Write MII2_RMII_REF_CLK register
	// Write_SJA1105_config(EXAMPLE_LPSPI_MASTER_BASEADDR, config_MII2_RMII_REF_CLK, 2);

	// Write MII2_EXT_TX_CLK register
	// Write_SJA1105_config(EXAMPLE_LPSPI_MASTER_BASEADDR, config_MII2_EXT_TX_CLK, 2);

	// Write MII2_MII_RX_CLK register
	Write_SJA1105_config(SJA1105_LPSPI_MASTER_BASEADDR, config_MII2_MII_RX_CLK, 2);

	// Write MII2_MII_RX_CLK register
	Write_SJA1105_config(SJA1105_LPSPI_MASTER_BASEADDR, config_MII2_MII_TX_CLK, 2);

	// Write IDIV_3_C control register
	Write_SJA1105_config(SJA1105_LPSPI_MASTER_BASEADDR, config_IDIV_3, 2);

	// Write MII3_RMII_REF_CLK register
	Write_SJA1105_config(SJA1105_LPSPI_MASTER_BASEADDR, config_MII3_RMII_REF_CLK, 2);

	// Write IDIV_4_C control register
	Write_SJA1105_config(SJA1105_LPSPI_MASTER_BASEADDR, config_IDIV_4, 2);

	// Write MII4_RMII_REF_CLK register
	Write_SJA1105_config(SJA1105_LPSPI_MASTER_BASEADDR, config_MII4_RMII_REF_CLK, 2);

	// Write CFG_PAD_MII3_RX register
	Write_SJA1105_config(SJA1105_LPSPI_MASTER_BASEADDR, config_PAD_MII3_RX, 2);

	// Write CFG_PAD_MII4_RX register
	Write_SJA1105_config(SJA1105_LPSPI_MASTER_BASEADDR, config_PAD_MII4_RX, 2);

	// Read all the R/W registers of SJA1105
	Read_SJA1105_Internal_Registers(SJA1105_LPSPI_MASTER_BASEADDR);

	// Read the PLL_1 Control register (address: 10000Ah)
	pll_1_c_reg = ReadSJA1105(SJA1105_LPSPI_MASTER_BASEADDR, PLL_1_C_ADDR);

	// Read the port status register (address: 100900h + i)
	for(i=0; i<5; i++)
	{
		read_address = PORT0_STATUS_MII_ADDR + i;
		port_status_mii_reg[i] = ReadSJA1105(SJA1105_LPSPI_MASTER_BASEADDR, read_address);
	}

}
