/*****************************************************************************/
#include "type.h"
#include "usbdebug.h"

#include "spi.h"
/*****************************************************************************/

/* SSP Controller */
#define SSP_BASE_ADDR		0xE0068000
#define SSPCR0         (*(volatile unsigned long * )(SSP_BASE_ADDR + 0x00))
#define SSPCR1         (*(volatile unsigned long * )(SSP_BASE_ADDR + 0x04))
#define SSPDR          (*(volatile unsigned long * )(SSP_BASE_ADDR + 0x08))
#define SSPSR          (*(volatile unsigned long * )(SSP_BASE_ADDR + 0x0C))
#define SSPCPSR        (*(volatile unsigned long * )(SSP_BASE_ADDR + 0x10))
#define SSPIMSC        (*(volatile unsigned long * )(SSP_BASE_ADDR + 0x14))
#define SSPRIS         (*(volatile unsigned long * )(SSP_BASE_ADDR + 0x18))
#define SSPMIS         (*(volatile unsigned long * )(SSP_BASE_ADDR + 0x1C))
#define SSPICR         (*(volatile unsigned long * )(SSP_BASE_ADDR + 0x20))

/* General Purpose Input/Output (GPIO) */
#define IOPIN0         (*((volatile unsigned long *) 0xE0028000))
#define IOSET0         (*((volatile unsigned long *) 0xE0028004))
#define IODIR0         (*((volatile unsigned long *) 0xE0028008))
#define IOCLR0         (*((volatile unsigned long *) 0xE002800C))
#define IOPIN1         (*((volatile unsigned long *) 0xE0028010))
#define IOSET1         (*((volatile unsigned long *) 0xE0028014))
#define IODIR1         (*((volatile unsigned long *) 0xE0028018))
#define IOCLR1         (*((volatile unsigned long *) 0xE002801C))

/* Pin Connect Block */
#define PINSEL0        (*((volatile unsigned long *) 0xE002C000))
#define PINSEL1        (*((volatile unsigned long *) 0xE002C004))
#define PINSEL2        (*((volatile unsigned long *) 0xE002C014))

/* SSPSR - bit definitions. */
#define TFE     0x01
#define TNF     0x02
#define RNE     0x04
#define RFF     0x08
#define BSY     0x10

/* Port Controls  (Platform dependent) */
#define SELECT_CARD()	IOCLR0   = IOCLR0 | (1<<20)		/* MMC CS = L */
#define UNSELECT_CARD()	IOSET0   = IOSET0 | (1<<20);	/* MMC CS = H */
#define rcvr_spi() spi_send(0xff)

/*----------------------------------------------------------------------------
 *      SPI Driver Functions
 *----------------------------------------------------------------------------
 *  Required functions for SPI driver module:
 *   - void spi_init ()
 *   - U8   spi_send (U8 outb)
 *   - void spi_hi_speed (BOOL on)
 *---------------------------------------------------------------------------*/

/*--------------------------- spi_init --------------------------------------*/

void spi_init (void) {
   /* Initialize and enable the SSP Interface module. */

   /* SSEL is GPIO, output set to high. */
   IODIR0  |= 1<<20;
   IOSET0   = 1<<20;
   /* SCK1, MISO1, MOSI1 are SSP pins. */
   PINSEL1  = (PINSEL1 & ~0x000003FC) | 0x000000A8;

   /* Enable SPI in Master Mode, CPOL=1, CPHA=1 (Clock low-active). */
   SSPCR0 = 0x00C7;
   SSPCR1 = 0x0002;
   SSPCPSR = 0xFE;

   /* Enable SSP auto select. */
//   PINSEL1 |= 0x00000200;
}


inline U8 spi_send (U8 outb) {
   /* Write and Read a byte on SPI interface. */
   U8 inb;

   /* Wait if TNF cleared, Tx FIFO is full. */
   while ((SSPSR & TNF) == 0);
   SSPDR = outb;
   /* Wait if RNE cleared, Rx FIFO is empty. */
   while ((SSPSR & RNE) == 0);
   inb = SSPDR;
   return (inb);
}



inline void SPISetSpeed(U8 speed)
{
	speed &= 0xFE;
	if (speed < SPI_PRESCALE_MIN) {
		speed = SPI_PRESCALE_MIN;
	}
	SSPCPSR = speed;
}

void SPIInit(void)
{
	U8 n;

	DBG("spiInit for SPI(1)\n");

	spi_init();
	// low speed during init
	SPISetSpeed(254);

	/* Send 20 spi commands with card not selected */
	for (n = 10; n; n--) rcvr_spi();	/* 80 dummy clocks */
}

U8 SPISend(U8 outgoing)
{
	U8 incoming;

	SELECT_CARD();
	incoming = spi_send(outgoing);
	UNSELECT_CARD();

	return incoming;
}

void SPISendN(U8 * pbBuf, int iLen)
{
	int i;

	SELECT_CARD();
	for (i = 0; i < iLen; i++) {
		spi_send(*pbBuf ++);
	}
	UNSELECT_CARD();
}

void SPIRecvN(U8 * pbBuf, int iLen)
{
	int i;

	SELECT_CARD();
	for (i = 0; i < iLen; i++) {
		*pbBuf ++ = rcvr_spi();
	}
	UNSELECT_CARD();
}

/*----------------------------------------------------------------------------
 * end of file
 *---------------------------------------------------------------------------*/
