#include "iolpc2368.h"
#include "ucos_ii.h"
#include <stdlib.h>
#include "cpu.h"
#include "spi1.h"

#ifdef CONFIG_SPI1_ENABLE

static OS_EVENT *Spi1Lock = NULL;

void spi1_setSpeed(unsigned int speed_hz)
{
    if (speed_hz <= 100000)
    {
        SSP1CPSR_bit.CPSDVSR = 255;   // 100 kHz
    }
    else if (speed_hz <= 400000)
    {
        SSP1CPSR_bit.CPSDVSR = 96;   // 375 kHz
    }
    else
    {
        SSP1CPSR_bit.CPSDVSR = 6;   // ~10 MHz
    }
}

unsigned char spi1_exchange(unsigned char c)
{
  while(!SSP1SR_bit.TFE);
  SSP1DR = c;
  while(SSP1SR_bit.BSY);
  while(!SSP1SR_bit.RNE);
  return SSP1DR;
}

void spi1_init(void)
{
  // on spi power
  PCONP_bit.PCSSP1 = 1;

  // clk = cclk
  PCLKSEL0_bit.PCLK_SSP1 = 1;

  // SD CARD CS
  PINSEL0_bit.P0_6 = 0x0;
  PINMODE0_bit.P0_6 = 0;
  FIO0DIR_bit.P0_6 = 1;
  FIO0MASK_bit.P0_6 = 0;
  FIO0SET_bit.P0_6 = 1;
  
  // MUSIC SHIELD CS
  PINSEL4_bit.P2_12 = 0x0;
  PINMODE4_bit.P2_12 = 0;
  FIO2DIR_bit.P2_12 = 1;
  FIO2MASK_bit.P2_12 = 0;
  FIO2SET_bit.P2_12 = 1;
  
  // pin select
  PINSEL0_bit.P0_7 = 0x2;   // SCK1
  PINMODE0_bit.P0_7 = 2;
  FIO0MASK_bit.P0_7 = 1;

  PINSEL0_bit.P0_8 = 0x2;   // MISO1
  PINMODE0_bit.P0_8 = 2;
  FIO0MASK_bit.P0_8 = 1;

  PINSEL0_bit.P0_9 = 0x2;   // MOSI1
  PINMODE0_bit.P0_9 = 2;
  FIO0MASK_bit.P0_9 = 1;
  
  SSP1CR0_bit.DSS = 7; // 8-bit
  SSP1CR0_bit.FRF = 0; // spi
  SSP1CR0_bit.SPO = 0;
  SSP1CR0_bit.SPH = 0;
  SSP1CR0_bit.SCR = 1;
  
  SSP1CR1_bit.LBM = 0;
  SSP1CR1_bit.SSE = 1;
  SSP1CR1_bit.MS = 0; // master
  SSP1CR1_bit.SOD = 0;
  
  SSP1CPSR_bit.CPSDVSR = 4;  
  
  SSP1IMSC = 0;
  SSP1DMACR = 0;
 
  if (!Spi1Lock) Spi1Lock = OSSemCreate(1); 
}


void spi1_selectChip(unsigned char spi)
{
    if (spi == SPI1_CS_SD_CARD)
    {
        FIO0CLR_bit.P0_6 = 1;
    }
    else if (spi == SPI1_CS_MUSIC_SHIELD)
    {
        FIO2CLR_bit.P2_12 = 1;
    }
}

void spi1_unselectChip(unsigned char spi)
{
    if (spi == SPI1_CS_SD_CARD)
    {
        FIO0SET_bit.P0_6 = 1;
    }
    else if (spi == SPI1_CS_MUSIC_SHIELD)
    {
        FIO2SET_bit.P2_12 = 1;
    }
}

void spi1_getSem()
{
    CPU_INT08U err;  
    do{
        OSSemPend(Spi1Lock, 1, &err);
        if (!err) break;
        OSTimeDly(1);
    }while (err);
}

void spi1_freeSem()
{
    OSSemPost(Spi1Lock);
}

#endif // CONFIG_SPI1_ENABLE