/* spi.c */

#include "spi.h"
#include "interrupt.h"
#include "event.h"
#include "uart.h"

#define SSPBASE 0xE0068000

#define SSPCR0   0x00
#define SSPCR1   0x04
#define SSPDR    0x08
#define SSPSR    0x0c
#define SSPCPSR  0x10
#define SSPIMSC  0x14
#define SSPRIS   0x18
#define SSPMIS   0x1c
#define SSPICR   0x20

#define REG(x) (((volatile unsigned char *)SSPBASE)[x])
#define WREG(x) (((volatile unsigned int *)SSPBASE)[(x)/sizeof(unsigned int)])

#define TNF (REG(SSPSR) & (1<<1))
#define RNE (REG(SSPSR) & (1<<2))

#define FP0XVAL (*((volatile unsigned int *) 0x3FFFC014))
#define FP0XSET (*((volatile unsigned int *) 0x3FFFC018))
#define FP0XCLR (*((volatile unsigned int *) 0x3FFFC01C))

void init_spi(void)
{
	WREG(SSPCR0) = 0x1f07; /* SPI clock = PCLK/64, mode 0, 8 bits */
//	WREG(SSPCR0) = 0xff07;
	/* Set to 0x0007 later */
	REG(SSPCPSR) = 2; /* Divide PCLK by 2 */
	REG(SSPCR1) = 0x0002; /* Enable SSP, Master mode */
}

void spi_speedup(void)
{
#if 1
	WREG(SSPCR0) = 0x0107; /* SPI clock = PCLK/4, mode 0, 8 bits */
#endif
}

void spi_write_byte(char byte)
{
	unsigned int dummy;

	while (!TNF) ;
	WREG(SSPDR) = byte;

	while (!RNE) ;
	dummy = REG(SSPDR);

#ifdef SPIDEBUG
	putstr(">");
	puthex(byte);
	putstr("(");
	puthex(dummy);
	putstr(") ");
#endif
}

char spi_read_byte(void)
{
	char byte;

	while (!TNF) ;
	WREG(SSPDR) = 0xff;

	while (!RNE) ;
	byte = (char) REG(SSPDR);

#ifdef SPIDEBUG
	putstr("<");
	puthex(byte);
	putstr(" ");
#endif

	return byte;
}

void spi_write_bytes(char *data, int len)
{
	while (len--)
		spi_write_byte(*data++);
}

void spi_read_bytes(char *data, int len)
{
	while (len--)
		*data++ = spi_read_byte();
}

void spi_transaction_start(void)
{
	FP0XCLR = 0x00200000;
}

void spi_transaction_stop(void)
{
	FP0XSET = 0x00200000;
}

void spi_drain(void)
{
	char byte;
	putstr("Draining:");
	while (RNE) {
		byte = (char) REG(SSPDR);
		putstr(" ");
		puthex(byte);
	}
	putstr("\r\n");
}
