/*
 * @brief Secondary loader I2C host interface handler
 *
 * @note
 * Copyright(C) NXP Semiconductors, 2014
 * All rights reserved.
 *
 * @par
 * Software that is described herein is for illustrative purposes only
 * which provides customers with programming information regarding the
 * LPC products.  This software is supplied "AS IS" without any warranties of
 * any kind, and NXP Semiconductors and its licensor disclaim any and
 * all warranties, express or implied, including all implied warranties of
 * merchantability, fitness for a particular purpose and non-infringement of
 * intellectual property rights.  NXP Semiconductors assumes no responsibility
 * or liability for the use of the software, conveys no license or rights under any
 * patent, copyright, mask work right, or any other intellectual property rights in
 * or to any products. NXP Semiconductors reserves the right to make changes
 * in the software without notification. NXP Semiconductors also makes no
 * representation or warranty that such application will be suitable for the
 * specified use without further testing or modification.
 *
 * @par
 * Permission to use, copy, modify, and distribute this software and its
 * documentation is hereby granted, under NXP Semiconductors' and its
 * licensor's relevant copyrights in the software, without fee, provided that it
 * is used in conjunction with NXP Semiconductors microcontrollers.  This
 * copyright, permission, and disclaimer notice must appear in all copies of
 * this code.
 */

#include "chip.h"
#include "sl_common.h"
#include "i2c.h"
#include "i2cs_8xx.h"
#include "i2c_common_8xx.h"
#include "swm.h"


//--Adision
#define I2CNUM        0                          // Choose the instance number for the I2C (0 for I2C0, 1 for I2C1, etc.)
#define pI2CINST      __XCONCAT(LPC_I2C,I2CNUM,)
#define I2CINST       __XCONCAT(I2C,I2CNUM,)
#define I2CINSTSCL    __XCONCAT(I2C,I2CNUM,_SCL)
#define I2CINSTSDA    __XCONCAT(I2C,I2CNUM,_SDA)
#define I2CINSTRSTN   __XCONCAT(I2C,I2CNUM,_RST_N)
#define I2CINSTCLKSEL __XCONCAT(I2C,I2CNUM,CLKSEL)
#define I2CBAUD 100000

/*****************************************************************************
 * Private types/enumerations/variables
 ****************************************************************************/
static CHIP_SYSCON_CLOCK_CTRL_T I2C_GetClockID(LPC_I2C_T *pI2C)
{
	uint32_t base = (uint32_t) pI2C;
	switch (base) {
	case LPC_I2C1_BASE:
		return CLK_I2C1;

	default:
		return CLK_I2C0;
	}
}


static I2CS_XFER_T i2csCallBacks[3];

static LPC_I2C_T *pI2CArray[3] = {
	LPC_I2C0, LPC_I2C1, LPC_I2C0
};

static int buffSendIndex;
extern int buffXferPending;

/*****************************************************************************
 * Public types/enumerations/variables
 ****************************************************************************/

/*****************************************************************************
 * Private functions
 ****************************************************************************/

/* Handler for slave start callback */
static void processSlaveTransferStart(uint8_t addr)
{
	Hostif_DeAssertIRQ();

	/* Setup transfer at the start */
	buffSendIndex = 0;

	/* Receive buffer index always reset to 0 on asssert event */
	recvBuff.bytes = 0;
}

/* Handler for slave send callback */
static uint8_t processSlaveTransferSend(uint8_t *data)
{
	if (buffSendIndex < sendBuff.bytes) {
		*data = sendBuff.buffer[buffSendIndex];
		buffSendIndex++;
	}
	else {
		/* Can't NAK on a send with master controlling transfer,
		   but we'll return NAK for completion. It isn't used. */
		*data = CFG_BOOT_WHO_AM_I;	/* send WHOAMI identifier as marker for receiver to know no data is pending*/
		return I2C_SLVCTL_SLVNACK;
	}

	return 0;
}

/* Handler for slave receive callback */
static uint8_t processSlaveTransferRecv(uint8_t data)
{
	recvBuff.buffer[recvBuff.bytes] = data;
	recvBuff.bytes++;

	/* To be consistent with SPI new protocol doesn't require sending NAK on last byte received */
	return 0;
}

/* Handler for slave transfer complete callback */
static void processSlaveTransferDone(void)
{
	buffXferPending = 1;
}

static void processSlaveTransferDone_0(void)
{
	slIfConfig.ifSel = SL_I2C0;
	processSlaveTransferDone();
}

static void processSlaveTransferDone_1(void)
{
	slIfConfig.ifSel = SL_I2C1;
	processSlaveTransferDone();
}

static void processSlaveTransferDone_2(void)
{
	slIfConfig.ifSel = SL_I2C2;
	processSlaveTransferDone();
}

/*****************************************************************************
 * Public functions
 ****************************************************************************/

/* Sets up pinmuxing for an I2C interface */
void setupMuxingI2C(int i2cNum)
{

	if(i2cNum == 0){
//--Adision's init		
  // SWM settings for I2C0 (slave):
	LPC_SWM->PINENABLE0 &= ~((1<<13)|(1<<12));  //--!!!Adision changed according UM_P143:P0.10 = I2C0_SCL;P0.11 = I2C0_SDA
		
  // Give I2C a reset
  LPC_SYSCON->PRESETCTRL0 &=  (I2C0_RST_N);
  LPC_SYSCON->PRESETCTRL0 |= ~(I2C0_RST_N);

  // Enable main_clk as function clock to I2C
  LPC_SYSCON->I2C0CLKSEL = FCLKSEL_MAIN_CLK;
  
//  // Get main_clk frequency
//  SystemCoreClockUpdate();  //??

	//--AZ get clock		SCL rate = I2C clock / (SCL_H+SCL_L) = 30000000 / 75 =400KHz .
	LPC_I2C0->MSTTIME &= 0XFFFFFF81;   //--L_0x1_3clock;H_0x0_2clock
	LPC_I2C0->CLKDIV = 5;						   //--SCL high time = (CLKDIV + 1) * (MSTSCLHIGH + 2) = 6*2 = 12 ; SCL_Low = 18 ;


		
		
		
//  // Configure the I2C CFG register:
//  // Slave enable = true
//  LPC_I2C0->CFG = CFG_SLVENA;

//  // Give the slave an address in one of its four address regs, and activate it;slave_board_address=0x18
//  LPC_I2C0->SLVADR3 = (0x18<<1) | 0;

//  // Enable the I2C slave pending interrupt
//  LPC_I2C0->INTENSET = STAT_SLVPEND;							//--8:This flag will cause an interrupt when set if enabled via INTENSET.
//	
		
		
//--Original code		
#if 0		
		// Provide main_clk as function clock to I2C0
		LPC_SYSCON->I2C0CLKSEL = FCLKSEL_MAIN_CLK;
  
		// Enable bus clocks to I2C0, SWM
		LPC_SYSCON->SYSAHBCLKCTRL0 |= (I2C0 | SWM);				
		ConfigSWM(I2C0_SCL, P0_14);               // Use for LPC804
		ConfigSWM(I2C0_SDA, P0_7); 
		// Give I2C0 a reset
		LPC_SYSCON->PRESETCTRL0 &= (I2C0_RST_N);
		LPC_SYSCON->PRESETCTRL0 |= ~(I2C0_RST_N);
		
		/*I2C FASH MODE*/
		LPC_I2C0->MSTTIME &= 0XFFFFFF81;
		LPC_I2C0->CLKDIV = 5;
#endif				
	}
	
	else if(i2cNum == 1){
//		ConfigSWM(I2C1_SCL, P0_10);               // Use for LPC804
//		ConfigSWM(I2C1_SDA, P0_11); 
	}
			
	return;
}

typedef void *I2C_HANDLE_T;

//--Set slave address & Interrupt enabled 
void setupInterfaceI2C(int i2cNum)
{
	/* Enable I2C clock and reset I2C peripheral */
		
	/* Set a single 7-bit I2C address, only 7-bit addressing is supported */
	Chip_I2CS_SetSlaveAddr(pI2CArray[i2cNum], 0, SL_I2C_SLAVE_ADDR_0);						//--< LPC_I2C0 SLVADR[0] = (0x18 << 1)>
	Chip_I2CS_SetSlaveAddr(pI2CArray[i2cNum], 1, SL_I2C_SLAVE_ADDR_LENOVO);
	Chip_I2CS_SetSlaveAddr(pI2CArray[i2cNum], 2, SL_I2C_SLAVE_ADDR_2);

	
	/* Clear interrupt status and enable slave interrupts */
	Chip_I2CS_ClearStatus(pI2CArray[i2cNum], STAT_SLVDESEL);											//--???_The Slave function has not become deselected.

	/* Interrupt enabled, but NVIC is not enabled in this app! */
	Chip_I2C_EnableInt(pI2CArray[i2cNum], STAT_SLVPEND | STAT_SLVDESEL);          //--Enable the I2C slave pending interrupt
}

void startHostIfI2C(int i2cNum)
{
	int i;

	/* I2C slavecallback function list */
	for (i = 0; i < 3; i++) {																											//--For what ??
		i2csCallBacks[i].slaveStart = &processSlaveTransferStart;
		i2csCallBacks[i].slaveSend  = &processSlaveTransferSend;
		i2csCallBacks[i].slaveRecv  = &processSlaveTransferRecv;
	}
	i2csCallBacks[0].slaveDone = &processSlaveTransferDone_0;
	i2csCallBacks[1].slaveDone = &processSlaveTransferDone_1;
	i2csCallBacks[2].slaveDone = &processSlaveTransferDone_2;

	/* Enable I2C slave interface */
	Chip_I2CS_Enable(pI2CArray[i2cNum]);																					//--Slave_Enable

	/* This I2C interface is now active */
}
#define LED_RED_ON  GPIOSetDir( 0, 12, 1 );\
					GPIOSetBitValue(0, 12, 0);
					
#define LED_RED_OFF GPIOSetDir( 0, 12, 1 );\
					GPIOSetBitValue(0, 12, 1);
/* I2C host interface processing loop */
void loopHostIfI2C(int i2cNum)
{
	uint32_t state = Chip_I2C_GetPendingInt(pI2CArray[i2cNum]);

	/* I2C slave related interrupt */
	while (state & (STAT_SLVPEND | STAT_SLVDESEL)) {                      //--((1 << 8))| (1 << 15)
		
LED_RED_ON;//--Adision		
		Chip_I2CS_XferHandler(pI2CArray[i2cNum], &i2csCallBacks[i2cNum]);
		/* Update state */
		state = Chip_I2C_GetPendingInt(pI2CArray[i2cNum]);
	}
}

/* Shut down a I2C slave interface */
void shutdownInterfaceI2C(int i2cNum)
{
	int i;

	for (i = 0; i <= 2; i++) {
		Chip_I2CS_DisableSlaveAddr(pI2CArray[i2cNum], (uint8_t) i);
	}
	Chip_I2CS_Disable(pI2CArray[i2cNum]);
	
	Disable_Periph_Clock(I2C_GetClockID(pI2CArray[i2cNum]));
}

/* I2C interrupts are only used in host interface detection */
void I2C0_IRQHandler(void)
{
	loopHostIfI2C(0);
}

void I2C1_IRQHandler(void)
{
	loopHostIfI2C(1);
}

