/// \file main.c Driver needed to get VS1005 Amp Board work with SD card.
/// \author Henrik Herranen, VLSI Solution Oy
#include <vo_stdio.h>
#include <volink.h>     // Linker directives like DLLENTRY
#include <apploader.h>  // RunLibraryFunction etc
#include <kernel.h>
#include <vo_gpio.h>
#include <timers.h>
#include <power.h>
#include <imem.h>
#include <string.h>
#include <stdlib.h>
#include <iochannel.h>
#include <extSymbols.h>

__mem_y u_int16 origSetPower = 0;
__mem_y u_int16 origResetSdCard = 0;
struct ExtSymbol __mem_y  *symResetSdCard = NULL;

/* GPIO 0.7 is the default pin for the VS1005 AmpBoard.
   For VS1005 Breakout Board 2.1 the correct pin is 0x23. */
__mem_y u_int16 usePin = 0x07;

void AmpResetSdCard(void) {
  //Pull all pins low
  GpioSetPin(0x26, 0); //miso gpio2.6
  GpioSetPin(0x2a, 0); //mosi gpio2.10
  GpioSetPin(0x25, 0); //sclk gpio2.5
  GpioSetPin(0x29, 0); //xcs gpio2.9
  GpioSetPin(0x27, 0); //dataX gpio2.7
  GpioSetPin(0x28, 0); //dataX gpio2.8
  // Switch power off
  SetPowerOff(PCL_SDCARD);
  Delay(500);
  // Switch power on
  SetPowerOn(PCL_SDCARD);
  Delay(50);
}


void AmpBoardSetPower(register u_int16 mask, register u_int16 onoff) {
  if (mask == PCL_SDCARD) {
#if 0
    printf("PCL_SDCARD %d\n", onoff);
#endif
    GpioSetPin(usePin, onoff);
  }
}


/*

  VS1005 AmpBoard pins:

  GPIO0_7 = 3V3 regulator 1:on (spdif+sdcard)
  GPIO1_5 = Amp mute off 1:off
  GPIO0_8 = Amp gain 20dB=1
  GPIO1_6 = Amp standby off:1
  GPIO2_0:1 = RCA input range select 10:1.5Vrms, 00:3Vrms
  GPIO2_2:3 = XLR input range select 10:4Vrms, 00:12Vrms

*/

DLLENTRY(init)
ioresult init(char *paramStr) {
  char *endP=NULL;
  int t;
  origSetPower = (u_int16)(ReadIMem((u_int16)SetPower) >> 6);

  SetHandler(SetPower, AmpBoardSetPower);

  symResetSdCard = SymbolFind("_ResetSdCard");
  origResetSdCard = symResetSdCard->addr;
  symResetSdCard->addr = (u_int16)AmpResetSdCard;

  t = strtol(paramStr, &endP, 0);
  if (endP != paramStr && !(*endP)) {
    usePin = t;
  }
  printf("SD power pin 0x%02x\n", usePin);

  ResetSdCard();
  return S_OK;
}


DLLENTRY(fini)
void fini(void) {
  SetHandler(SetPower, (void *)origSetPower);
  symResetSdCard->addr = origResetSdCard;
}
