/*---------------------------------------------------------------------------
* Copyright (C) 2004-2007, Freescale Semiconductor, Inc. All Rights Reserved.
* THIS SOURCE CODE, AND ITS USE AND DISTRIBUTION, IS SUBJECT TO THE TERMS
* AND CONDITIONS OF THE APPLICABLE LICENSE AGREEMENT 
*--------------------------------------------------------------------------*/

//------------------------------------------------------------------------------
//
//  File:  bspsdhc.c
//
//  Implementation of SDHC Driver Platform Device Driver
//
//  This file implements platform specific functions for SDHC.
//------------------------------------------------------------------------------

#pragma warning(push)
#pragma warning(disable: 4115 4201 4204 4214)
#include <windows.h>
#include <nkintr.h>
#include <ceddk.h>
#include <Sdcard.h>
#pragma warning(pop)

#include "bsp.h"
#include "bspsdhc.h"

#include "pmic_lla.h"
//-----------------------------------------------------------------------------
// External Variables
//-----------------------------------------------------------------------------
// External Functions
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Defines

//------------------------------------------------------------------------------
// Types
typedef struct {
   DWORD dwIRQorGPIO;
   DWORD dwDDKGPIOPort;
   DWORD dwDDKGPIOPin;
   // These two data should be indexed in DDK library
   DWORD dwDDKIoMuxPin;
   DWORD dwDDKIoMuxPad;
} TDDK_GPIO_Info;

//------------------------------------------------------------------------------
// Global Variables

//------------------------------------------------------------------------------
// Local Variables
static const TDDK_GPIO_Info gc_pIRQTable[] = {
   {GET_GPIOPINNAME_IRQ(uP_nIRQA), GET_GPIOPINNAME_DDKPORT(uP_nIRQA), GET_GPIOPINNAME_DDKPIN(uP_nIRQA), GET_GPIOPINNAME_DDKIOMUX(uP_nIRQA, PIN), GET_GPIOPINNAME_DDKIOMUX(uP_nIRQA, PAD)},
   {GET_GPIOPINNAME_IRQ(uP_nIRQB), GET_GPIOPINNAME_DDKPORT(uP_nIRQB), GET_GPIOPINNAME_DDKPIN(uP_nIRQB), GET_GPIOPINNAME_DDKIOMUX(uP_nIRQB, PIN), GET_GPIOPINNAME_DDKIOMUX(uP_nIRQB, PAD)},
   {GET_GPIOPINNAME_IRQ(uP_nIRQC), GET_GPIOPINNAME_DDKPORT(uP_nIRQC), GET_GPIOPINNAME_DDKPIN(uP_nIRQC), GET_GPIOPINNAME_DDKIOMUX(uP_nIRQC, PIN), GET_GPIOPINNAME_DDKIOMUX(uP_nIRQC, PAD)},
   {GET_GPIOPINNAME_IRQ(uP_nIRQD), GET_GPIOPINNAME_DDKPORT(uP_nIRQD), GET_GPIOPINNAME_DDKPIN(uP_nIRQD), GET_GPIOPINNAME_DDKIOMUX(uP_nIRQD, PIN), GET_GPIOPINNAME_DDKIOMUX(uP_nIRQD, PAD)},
};
static const TDDK_GPIO_Info gc_pGPIOTable[] = {
   {GET_GPIOPINNAME_IRQ(uP_GPIO_0), GET_GPIOPINNAME_DDKPORT(uP_GPIO_0), GET_GPIOPINNAME_DDKPIN(uP_GPIO_0), GET_GPIOPINNAME_DDKIOMUX(uP_GPIO_0, PIN), GET_GPIOPINNAME_DDKIOMUX(uP_GPIO_0, PAD)},
   {GET_GPIOPINNAME_IRQ(uP_GPIO_1), GET_GPIOPINNAME_DDKPORT(uP_GPIO_1), GET_GPIOPINNAME_DDKPIN(uP_GPIO_1), GET_GPIOPINNAME_DDKIOMUX(uP_GPIO_1, PIN), GET_GPIOPINNAME_DDKIOMUX(uP_GPIO_1, PAD)},
   {GET_GPIOPINNAME_IRQ(uP_GPIO_2), GET_GPIOPINNAME_DDKPORT(uP_GPIO_2), GET_GPIOPINNAME_DDKPIN(uP_GPIO_2), GET_GPIOPINNAME_DDKIOMUX(uP_GPIO_2, PIN), GET_GPIOPINNAME_DDKIOMUX(uP_GPIO_2, PAD)},
   {GET_GPIOPINNAME_IRQ(uP_GPIO_3), GET_GPIOPINNAME_DDKPORT(uP_GPIO_3), GET_GPIOPINNAME_DDKPIN(uP_GPIO_3), GET_GPIOPINNAME_DDKIOMUX(uP_GPIO_3, PIN), GET_GPIOPINNAME_DDKIOMUX(uP_GPIO_3, PAD)},
   {GET_GPIOPINNAME_IRQ(uP_GPIO_4), GET_GPIOPINNAME_DDKPORT(uP_GPIO_4), GET_GPIOPINNAME_DDKPIN(uP_GPIO_4), GET_GPIOPINNAME_DDKIOMUX(uP_GPIO_4, PIN), GET_GPIOPINNAME_DDKIOMUX(uP_GPIO_4, PAD)},
   {GET_GPIOPINNAME_IRQ(uP_GPIO_5), GET_GPIOPINNAME_DDKPORT(uP_GPIO_5), GET_GPIOPINNAME_DDKPIN(uP_GPIO_5), GET_GPIOPINNAME_DDKIOMUX(uP_GPIO_5, PIN), GET_GPIOPINNAME_DDKIOMUX(uP_GPIO_5, PAD)},
   {GET_GPIOPINNAME_IRQ(uP_GPIO_6), GET_GPIOPINNAME_DDKPORT(uP_GPIO_6), GET_GPIOPINNAME_DDKPIN(uP_GPIO_6), GET_GPIOPINNAME_DDKIOMUX(uP_GPIO_6, PIN), GET_GPIOPINNAME_DDKIOMUX(uP_GPIO_6, PAD)},
   {GET_GPIOPINNAME_IRQ(uP_GPIO_7), GET_GPIOPINNAME_DDKPORT(uP_GPIO_7), GET_GPIOPINNAME_DDKPIN(uP_GPIO_7), GET_GPIOPINNAME_DDKIOMUX(uP_GPIO_7, PIN), GET_GPIOPINNAME_DDKIOMUX(uP_GPIO_7, PAD)},
};
/*******************************************************************************
 EXPORTED FUNCTIONS
*******************************************************************************/
//------------------------------------------------------------------------------
//
// Function: BSPSdhcLoadPlatformRegistrySettings
//
// This function is to get any platform-specific registry setting
//
// Parameters: 
//       hKeyDevice
//          [in] Registry key opened opened by CSP layer
//       pSpecificContext
//          [in] pointer to the structure
//
// Returns:
//      Return TRUE if successful
//             FALSE if unsuccessful
//------------------------------------------------------------------------------
BOOL BSPSdhcLoadPlatformRegistrySettings(HKEY hKeyDevice, PVOID pSpecificContext)
{
#if 0
   // Remove-W4: Warning C4100 workaround
   UNREFERENCED_PARAMETER(hKeyDevice);
#endif
   DWORD dwRegVal;
   DWORD dwDataSize;
   DWORD dwType;
   LONG  regError;
   PBSP_SDHC_CONTEXT pBspContext;
   int ii;
   
   pBspContext = (PBSP_SDHC_CONTEXT)pSpecificContext;
   
   // Get Card Detect IRQ
   dwDataSize = sizeof(DWORD);
   regError = RegQueryValueEx(hKeyDevice, CARD_DETECT_IRQ_TEXT, NULL, &dwType, (LPBYTE)&dwRegVal, &dwDataSize);
   if ((regError == ERROR_SUCCESS) && (dwType == REG_DWORD)) {
      pBspContext->dwCardDetectIRQ = dwRegVal;
   }
   else {
      return FALSE;
   }
   
   // Get Write Protect IRQ
   dwDataSize = sizeof(DWORD);
   regError = RegQueryValueEx(hKeyDevice, WRITE_PROTECT_IRQ_TEXT, NULL, &dwType, (LPBYTE)&dwRegVal, &dwDataSize);
   if ((regError == ERROR_SUCCESS) && (dwType == REG_DWORD)) {
      pBspContext->dwWriteProtectIRQ = dwRegVal;
   }
   else {
      pBspContext->dwWriteProtectIRQ = OAL_INTR_IRQ_UNDEFINED;
      dwDataSize = sizeof(DWORD);
      regError = RegQueryValueEx(hKeyDevice, WRITE_PROTECT_GPIO_TEXT, NULL, &dwType, (LPBYTE)&dwRegVal, &dwDataSize);
      if ((regError == ERROR_SUCCESS) && (dwType == REG_DWORD)) {
         pBspContext->dwWriteProtectGPIO = dwRegVal;
      }
      else {
         pBspContext->dwWriteProtectGPIO = (DWORD)(-1);
         return FALSE;
      }
   }
   
   // Get CardDetectIRQ GPIO port/pin
   for (ii=0; ii<ARRAYSIZE(gc_pIRQTable); ii++) {
      if (pBspContext->dwCardDetectIRQ == gc_pIRQTable[ii].dwIRQorGPIO) {
         pBspContext->dwCardDetectGPIOPort = gc_pIRQTable[ii].dwDDKGPIOPort;
         pBspContext->dwCardDetectGPIOPin  = gc_pIRQTable[ii].dwDDKGPIOPin;
         pBspContext->dwCardDetectIoMuxPin = gc_pIRQTable[ii].dwDDKIoMuxPin;
         pBspContext->dwCardDetectIoMuxPad = gc_pIRQTable[ii].dwDDKIoMuxPad;
         break;
      }
   }
   if (ii >= ARRAYSIZE(gc_pIRQTable)) {
      // Unknow CardDetectIRQ
      ERRORMSG(1, (__WFUNCTION__ TEXT(": Unknow \"") CARD_DETECT_IRQ_TEXT TEXT("\" = 0x%X.\r\n"), pBspContext->dwCardDetectIRQ));
      return FALSE;
   }
   
   // Get WriteProtect GPIO port/pin
   if (pBspContext->dwWriteProtectIRQ != OAL_INTR_IRQ_UNDEFINED) {
      // Use WriteProtectIRQ pin
      for (ii=0; ii<ARRAYSIZE(gc_pIRQTable); ii++) {
         if (pBspContext->dwWriteProtectIRQ == gc_pIRQTable[ii].dwIRQorGPIO) {
            pBspContext->dwWriteProtectGPIOPort = gc_pIRQTable[ii].dwDDKGPIOPort;
            pBspContext->dwWriteProtectGPIOPin  = gc_pIRQTable[ii].dwDDKGPIOPin;
            pBspContext->dwWriteProtectIoMuxPin = gc_pIRQTable[ii].dwDDKIoMuxPin;
            pBspContext->dwWriteProtectIoMuxPad = gc_pIRQTable[ii].dwDDKIoMuxPad;
            break;
         }
      }
      if (ii >= ARRAYSIZE(gc_pIRQTable)) {
         // Unknow WriteProtectIRQ
         ERRORMSG(1, (__WFUNCTION__ TEXT(": Unknow \"") WRITE_PROTECT_IRQ_TEXT TEXT("\" = 0x%X.\r\n"), pBspContext->dwWriteProtectIRQ));
         return FALSE;
      }
   }
   else {
      // Use WriteProtectGPIO pin
      for (ii=0; ii<ARRAYSIZE(gc_pGPIOTable); ii++) {
         if (pBspContext->dwWriteProtectGPIO == gc_pGPIOTable[ii].dwIRQorGPIO) {
            pBspContext->dwWriteProtectGPIOPort = gc_pGPIOTable[ii].dwDDKGPIOPort;
            pBspContext->dwWriteProtectGPIOPin  = gc_pGPIOTable[ii].dwDDKGPIOPin;
            pBspContext->dwWriteProtectIoMuxPin = gc_pGPIOTable[ii].dwDDKIoMuxPin;
            pBspContext->dwWriteProtectIoMuxPad = gc_pGPIOTable[ii].dwDDKIoMuxPad;
            break;
         }
      }
      if (ii >= ARRAYSIZE(gc_pGPIOTable)) {
         // Unknow WriteProtectIRQ
         ERRORMSG(1, (__WFUNCTION__ TEXT(": Unknow \"") WRITE_PROTECT_GPIO_TEXT TEXT("\" = 0x%X.\r\n"), pBspContext->dwWriteProtectGPIO));
         return FALSE;
      }
   }
   
   return TRUE;
}

//------------------------------------------------------------------------------
//
// Function: BSPSdhcSetClockGatingMode
//
// This function enable or disable CRM clock for SDHC.
//
// Parameters:
//      startClocks
//          [in] boolean variable to enable or disable CRM clock
//		Controller Index 
//			[in] SDHC controller index (1 or 2) 
//
// Returns:
//      Return TRUE.
//
//------------------------------------------------------------------------------
BOOL BSPSdhcSetClockGatingMode(BOOL startClocks, DWORD ControllerIndex)
{
   BOOL rc = FALSE;
   
   if (startClocks) {
      if (ControllerIndex == 1) {
         rc = DDKClockSetGatingMode(DDK_CLOCK_GATE_INDEX_SDHC1, DDK_CLOCK_GATE_MODE_ENABLED_ALL);
      }
      if (ControllerIndex == 2) {
         rc = DDKClockSetGatingMode(DDK_CLOCK_GATE_INDEX_SDHC2, DDK_CLOCK_GATE_MODE_ENABLED_ALL);
      }
   }
   else {
      if (ControllerIndex == 1) {
         rc = DDKClockSetGatingMode(DDK_CLOCK_GATE_INDEX_SDHC1, DDK_CLOCK_GATE_MODE_DISABLED);
      }
      if (ControllerIndex == 2) {
         rc = DDKClockSetGatingMode(DDK_CLOCK_GATE_INDEX_SDHC2, DDK_CLOCK_GATE_MODE_DISABLED);
      }
   }
   return rc;
}
//------------------------------------------------------------------------------
//
// Function: BSPGetSDHCCLK
//
// This function returns the BSP-specific clock
// source selection value for SDHC.
//
// Parameters:
//      None
//
// Returns:
//      The clock source for SDHC.
//
//------------------------------------------------------------------------------
UINT32 BSPGetSDHCCLK(void)
{
   UINT32 freq;
   
   // SDHC uses the PERCLK for generating the bit clock.
   DDKClockGetFreq(DDK_CLOCK_SIGNAL_PER, &freq);
   return freq;
}
//------------------------------------------------------------------------------
//
// Function: BSPSlotVoltageOn
//
// This function turns on the voltage to the specified slot
//
// Parameters:
//      dwIndex [in]    requested slot number
//
// Returns:
//------------------------------------------------------------------------------
void BSPSlotVoltageOn(DWORD dwIndex)
{
#if 0
   if (dwIndex == 1) {
      DDKGpioWriteDataPin(DDK_GPIO_PORT3, 0, 1);
   }
#endif
}
//------------------------------------------------------------------------------
//
// Function: BSPSetVoltageSlot
//
// This function sets voltage slot
//
// Parameters:
//      dwIndex [in]    requested slot number
//      mask [in]		requested voltage window mask 
//
// Returns:
//------------------------------------------------------------------------------
void BSPSetVoltageSlot(DWORD dwIndex, UINT32 mask)
{
#if 0
   if (dwIndex != 1)
      return;
   switch (mask) {
      case 0:
         DDKGpioWriteDataPin(DDK_GPIO_PORT3, 0, 0);
         break;
      default:
         DDKGpioWriteDataPin(DDK_GPIO_PORT3, 0, 1);
         break;
   }
#endif
}

//TODO: (currently not used)
//------------------------------------------------------------------------------
//
// Function: BSPGetVoltageSlot
//
// This function gets voltage window mask and optimal voltage
//
// Parameters:
//      mask [out]		supported voltage window mask 
//		voltage [out] 	optimum voltage mask
//
// Returns:
//      The clock source for SDHC.
//
//------------------------------------------------------------------------------
//void BSPGetVoltageSlot(UINT32 *mask, UINT32 *voltage, UINT32 *PowerUpDelay)
//{
//     *mask = SD_VDD_WINDOW_3_2_TO_3_3 | SD_VDD_WINDOW_3_3_TO_3_4 ; 
//	 *voltage = SD_VDD_WINDOW_3_2_TO_3_3 ;
//	 *PowerUpDelay = SDHC_MAX_POWER_SUPPLY_RAMP_UP ; 
//}

//------------------------------------------------------------------------------
//
// Function: BSPSdhcAlloc
//
// BSP specific allocation
//
// Parameters:
//      None
//
// Returns:
//      NULL if fail
//      Others if success
//
//------------------------------------------------------------------------------
PVOID BSPSdhcAlloc(void)
{
   PBSP_SDHC_CONTEXT pBspContext = NULL;
   
   pBspContext = (PBSP_SDHC_CONTEXT)malloc(sizeof(BSP_SDHC_CONTEXT));
   if (pBspContext == NULL) {
      ERRORMSG(1 , (__WFUNCTION__ TEXT(": Failed to allocate extension\r\n")));
      return NULL;
   }
   memset(pBspContext, 0, sizeof(BSP_SDHC_CONTEXT));
   
   return pBspContext;
}

//------------------------------------------------------------------------------
//
// Function: BSPSdhcInit
//
// BSP specific initialization
//
// Parameters:
//      ControllerIndex [in]     SDHC controller index
//
// Returns:
//      TRUE if success
//
//------------------------------------------------------------------------------
BOOL BSPSdhcInit(DWORD ControllerIndex)
{
   PBSP_SDHC_CONTEXT pBspContext = NULL;
   // Remove-W4: Warning C4100 workaround
   UNREFERENCED_PARAMETER(ControllerIndex);
   
#if 0
   PmicRegisterWrite(0x22, 0x00001540, 0x00ffffff);
#endif
   
   return TRUE;
}

//------------------------------------------------------------------------------
//
// Function: BSPSdhcDeinit
//
// BSP specific de-initialization
//
// Parameters:
//      pSpecificContext [in]    pointer to the structure 
//
// Returns:
//      None
//
//------------------------------------------------------------------------------
void BSPSdhcDeinit(PVOID pSpecificContext)
{
   PBSP_SDHC_CONTEXT pBspContext;
   
   pBspContext = (PBSP_SDHC_CONTEXT)pSpecificContext;
   
   if (pBspContext != NULL) {
      free(pBspContext);
      pBspContext = NULL;
   }
   
   return;
}

//------------------------------------------------------------------------------
//
// Function: BspSdhcIsCardPresent
//
// function to check card existence
//
// Parameters:
//      pSpecificContext [in]     BSP Context
//
// Returns:
//      TRUE if success 
//
//------------------------------------------------------------------------------
BOOL BspSdhcIsCardPresent(PVOID pSpecificContext)
{
   BOOL fCardExist = FALSE;
   DWORD dwPinData;
   PBSP_SDHC_CONTEXT pBspContext;
   
   pBspContext = (PBSP_SDHC_CONTEXT)pSpecificContext;
   
   fCardExist = DDKGpioReadDataPin(pBspContext->dwCardDetectGPIOPort, pBspContext->dwCardDetectGPIOPin, &dwPinData);
   
   if (fCardExist) {
      // Is associate pin low??
      fCardExist = (dwPinData == 0);
   }
   
   DEBUGMSG(1, (__WFUNCTION__ TEXT("(%c)-\r\n"), fCardExist?'T':'F'));
   
   return fCardExist;
}
//------------------------------------------------------------------------------
//
// Function: BspSdhcCardDetectDeinitialize
//
// function to clean up preiously configured iomux, gpio 
//
// Parameters:
//      pSpecificContext [in]     BSP Context
//
// Returns: None
//
//------------------------------------------------------------------------------
void BspSdhcCardDetectDeinitialize(PVOID pSpecificContext)
{
   PBSP_SDHC_CONTEXT pBspContext;
   
   pBspContext = (PBSP_SDHC_CONTEXT)pSpecificContext;
   
   DDKGpioClearIntrPin(pBspContext->dwCardDetectGPIOPort, pBspContext->dwCardDetectGPIOPin);
   DDKGpioUnbindIrq(pBspContext->dwCardDetectGPIOPort, pBspContext->dwCardDetectGPIOPin);
}

//-----------------------------------------------------------------------------
//
// Function: BspSdhcSetIOMux
//
// This function configures IOMUX for successful operation of the SDHC.
//
// Parameters:
//      ControllerIndex [in]    SDHC controller index.
//
// Returns: None
//-----------------------------------------------------------------------------
void BspSdhcSetIOMux(DWORD ControllerIndex)
{
   if (ControllerIndex == 1) {
      // Configure IOMUX to request SDHC1 bus signals
      DDKIomuxSetPinMux(DDK_IOMUX_PIN_SD1_CMD,   DDK_IOMUX_OUT_FUNC, DDK_IOMUX_IN_FUNC);
      DDKIomuxSetPinMux(DDK_IOMUX_PIN_SD1_CLK,   DDK_IOMUX_OUT_FUNC, DDK_IOMUX_IN_FUNC);
      DDKIomuxSetPinMux(DDK_IOMUX_PIN_SD1_DATA0, DDK_IOMUX_OUT_FUNC, DDK_IOMUX_IN_FUNC | DDK_IOMUX_IN_GPIO);
      DDKIomuxSetPinMux(DDK_IOMUX_PIN_SD1_DATA1, DDK_IOMUX_OUT_FUNC, DDK_IOMUX_IN_FUNC);
      DDKIomuxSetPinMux(DDK_IOMUX_PIN_SD1_DATA2, DDK_IOMUX_OUT_FUNC, DDK_IOMUX_IN_FUNC);
      DDKIomuxSetPinMux(DDK_IOMUX_PIN_SD1_DATA3, DDK_IOMUX_OUT_FUNC, DDK_IOMUX_IN_FUNC);
      DDKGpioSetConfig(DDK_GPIO_PORT2, 28, DDK_GPIO_DIR_IN, DDK_GPIO_INTR_NONE);
      DDKIomuxSetPadConfig(DDK_IOMUX_PAD_SD1_CMD, DDK_IOMUX_PAD_SLEW_FAST,
                           DDK_IOMUX_PAD_DRIVE_MAX, DDK_IOMUX_PAD_MODE_CMOS,
                           DDK_IOMUX_PAD_TRIG_SCHMITT,
                           DDK_IOMUX_PAD_PULL_UP_22K);
      
      DDKIomuxSetPadConfig(DDK_IOMUX_PAD_SD1_CLK, DDK_IOMUX_PAD_SLEW_FAST,
                           DDK_IOMUX_PAD_DRIVE_MAX, DDK_IOMUX_PAD_MODE_CMOS,
                           DDK_IOMUX_PAD_TRIG_SCHMITT,
                           DDK_IOMUX_PAD_PULL_UP_22K);
      
      DDKIomuxSetPadConfig(DDK_IOMUX_PAD_SD1_DATA0, DDK_IOMUX_PAD_SLEW_FAST,
                           DDK_IOMUX_PAD_DRIVE_MAX, DDK_IOMUX_PAD_MODE_CMOS,
                           DDK_IOMUX_PAD_TRIG_SCHMITT,
                           DDK_IOMUX_PAD_PULL_UP_22K);
      
      DDKIomuxSetPadConfig(DDK_IOMUX_PAD_SD1_DATA1, DDK_IOMUX_PAD_SLEW_FAST,
                           DDK_IOMUX_PAD_DRIVE_MAX, DDK_IOMUX_PAD_MODE_CMOS,
                           DDK_IOMUX_PAD_TRIG_SCHMITT,
                           DDK_IOMUX_PAD_PULL_UP_22K);
      
      DDKIomuxSetPadConfig(DDK_IOMUX_PAD_SD1_DATA2, DDK_IOMUX_PAD_SLEW_FAST,
                           DDK_IOMUX_PAD_DRIVE_MAX, DDK_IOMUX_PAD_MODE_CMOS,
                           DDK_IOMUX_PAD_TRIG_SCHMITT,
                           DDK_IOMUX_PAD_PULL_UP_22K);
      
      DDKIomuxSetPadConfig(DDK_IOMUX_PAD_SD1_DATA3, DDK_IOMUX_PAD_SLEW_FAST,
                           DDK_IOMUX_PAD_DRIVE_MAX, DDK_IOMUX_PAD_MODE_CMOS,
                           DDK_IOMUX_PAD_TRIG_SCHMITT,
                           DDK_IOMUX_PAD_PULL_UP_22K);
#if 0
      // Configure GPIO3_0 FOR SD1 EN
      DDKIomuxSetPinMux(DDK_IOMUX_PIN_GPIO3_0, DDK_IOMUX_OUT_GPIO, DDK_IOMUX_IN_GPIO);
      DDKIomuxSetPadConfig(DDK_IOMUX_PIN_GPIO3_0, DDK_IOMUX_PAD_SLEW_SLOW,
                           DDK_IOMUX_PAD_DRIVE_NORMAL, DDK_IOMUX_PAD_MODE_CMOS,
                           DDK_IOMUX_PAD_TRIG_SCHMITT, DDK_IOMUX_PAD_PULL_UP_100K);
      DDKGpioSetConfig(DDK_GPIO_PORT3, 0, DDK_GPIO_DIR_OUT, DDK_GPIO_INTR_NONE);
      DDKGpioWriteDataPin(DDK_GPIO_PORT3,0, 1);
#endif
   }
   else if (ControllerIndex == 2) {
      // Configure IOMUX to request SDHC2 bus signals
      // SD2_CMD, nPC_CD1 (L7)
      DDKIomuxSetPinMux(DDK_IOMUX_PIN_PC_CD1_B,  DDK_IOMUX_OUT_ALT1, DDK_IOMUX_IN_ALT1);
      // SD2_CLK, nPC_CD2 (K1)
      DDKIomuxSetPinMux(DDK_IOMUX_PIN_PC_CD2_B,  DDK_IOMUX_OUT_ALT1, DDK_IOMUX_IN_ALT1);
      // SD2_DATA0, nPC_WAIT (L6)
      DDKIomuxSetPinMux(DDK_IOMUX_PIN_PC_WAIT_B, DDK_IOMUX_OUT_ALT1, DDK_IOMUX_IN_ALT1);
      // SD2_DATA1, PC_READY (J2)
      DDKIomuxSetPinMux(DDK_IOMUX_PIN_PC_READY,  DDK_IOMUX_OUT_ALT1, DDK_IOMUX_IN_ALT1);
      // SD2_DATA2, PC_PWRON (K3)
      DDKIomuxSetPinMux(DDK_IOMUX_PIN_PC_PWRON,  DDK_IOMUX_OUT_ALT1, DDK_IOMUX_IN_ALT1);
      // SD2_DATA3, PC_VS1 (J1)
      DDKIomuxSetPinMux(DDK_IOMUX_PIN_PC_VS1,    DDK_IOMUX_OUT_ALT1, DDK_IOMUX_IN_ALT1);
      
      // SD2_CMD, nPC_CD1 (L7)
      DDKIomuxSetPadConfig(DDK_IOMUX_PIN_PC_CD1_B, DDK_IOMUX_PAD_SLEW_FAST,
                           DDK_IOMUX_PAD_DRIVE_MAX, DDK_IOMUX_PAD_MODE_CMOS,
                           DDK_IOMUX_PAD_TRIG_SCHMITT,
                           DDK_IOMUX_PAD_PULL_UP_22K);
      // SD2_CLK, nPC_CD2 (K1)
      DDKIomuxSetPadConfig(DDK_IOMUX_PIN_PC_CD2_B, DDK_IOMUX_PAD_SLEW_FAST,
                           DDK_IOMUX_PAD_DRIVE_MAX, DDK_IOMUX_PAD_MODE_CMOS,
                           DDK_IOMUX_PAD_TRIG_SCHMITT,
                           DDK_IOMUX_PAD_PULL_UP_22K);
      // SD2_DATA0, nPC_WAIT (L6)
      DDKIomuxSetPadConfig(DDK_IOMUX_PIN_PC_WAIT_B, DDK_IOMUX_PAD_SLEW_FAST,
                           DDK_IOMUX_PAD_DRIVE_MAX, DDK_IOMUX_PAD_MODE_CMOS,
                           DDK_IOMUX_PAD_TRIG_SCHMITT,
                           DDK_IOMUX_PAD_PULL_UP_22K);
      // SD2_DATA1, PC_READY (J2)
      DDKIomuxSetPadConfig(DDK_IOMUX_PIN_PC_READY, DDK_IOMUX_PAD_SLEW_FAST,
                           DDK_IOMUX_PAD_DRIVE_MAX, DDK_IOMUX_PAD_MODE_CMOS,
                           DDK_IOMUX_PAD_TRIG_SCHMITT,
                           DDK_IOMUX_PAD_PULL_UP_22K);
      // SD2_DATA2, PC_PWRON (K3)
      DDKIomuxSetPadConfig(DDK_IOMUX_PIN_PC_PWRON, DDK_IOMUX_PAD_SLEW_FAST,
                           DDK_IOMUX_PAD_DRIVE_MAX, DDK_IOMUX_PAD_MODE_CMOS,
                           DDK_IOMUX_PAD_TRIG_SCHMITT,
                           DDK_IOMUX_PAD_PULL_UP_22K);
      // SD2_DATA3, PC_VS1 (J1)
      DDKIomuxSetPadConfig(DDK_IOMUX_PIN_PC_VS1, DDK_IOMUX_PAD_SLEW_FAST,
                           DDK_IOMUX_PAD_DRIVE_MAX, DDK_IOMUX_PAD_MODE_CMOS,
                           DDK_IOMUX_PAD_TRIG_SCHMITT,
                           DDK_IOMUX_PAD_PULL_UP_22K);
   }
}
//------------------------------------------------------------------------------
//
// Function: BspSdhcGetIrq
//
// This function is to get the interrupt line
//
// Parameters:
//		 None 
//
// Returns:
//      Interrupt line
//
//------------------------------------------------------------------------------
UINT BspSdhcGetIrq(DWORD ControllerIndex)
{
   if (ControllerIndex == 1) {
      return IRQ_SDHC1;
   }
   else {
      return IRQ_SDHC2;
   }
}
//------------------------------------------------------------------------------
//
// Function: BspSdhcCardDetectInitialize
//
// setup GPIO pins for cadr detection 
//
// Parameters:
//      ControllerIndex  [in]     SDHC controller index
//      pSpecificContext [in]     BSP Context
//
// Returns: TRUE if successful
//          FALSE if not successful
//
//------------------------------------------------------------------------------
BOOL BspSdhcCardDetectInitialize(DWORD ControllerIndex, PVOID pSpecificContext)
{
   PBSP_SDHC_CONTEXT pBspContext;
   
   pBspContext = (PBSP_SDHC_CONTEXT)pSpecificContext;
   if (pBspContext == NULL) {
      ERRORMSG(1 , (__WFUNCTION__ TEXT(": Failed to allocate extension\n")));
      return FALSE;
   }
   
   DDKIomuxSetPinMux(pBspContext->dwCardDetectIoMuxPin, DDK_IOMUX_OUT_GPIO, DDK_IOMUX_IN_GPIO);
   DDKIomuxSetPadConfig(pBspContext->dwCardDetectIoMuxPad, DDK_IOMUX_PAD_SLEW_SLOW, 
                        DDK_IOMUX_PAD_DRIVE_NORMAL, DDK_IOMUX_PAD_MODE_CMOS, 
                        DDK_IOMUX_PAD_TRIG_SCHMITT, DDK_IOMUX_PAD_PULL_UP_100K);
   DDKGpioSetConfig(pBspContext->dwCardDetectGPIOPort, pBspContext->dwCardDetectGPIOPin, DDK_GPIO_DIR_IN, DDK_GPIO_INTR_LOW_LEV);
   DDKGpioClearIntrPin(pBspContext->dwCardDetectGPIOPort, pBspContext->dwCardDetectGPIOPin);
   DDKGpioBindIrq(pBspContext->dwCardDetectGPIOPort, pBspContext->dwCardDetectGPIOPin, BspSdhcGetIrq(ControllerIndex));
   
   //Copy Controller Index number from hardware context to card detect context
   pBspContext->dwControllerIndex = ControllerIndex;
   
   return TRUE;
}

//------------------------------------------------------------------------------
//
// Function: BspSdhcSetcardDetectType
//
// setup card detection type (removal or insertion)
//
// Parameters:
//      pSpecificContext [in]     BSP Context
//      type             [in]     detection type (insertion or removal)
//
// Returns: None
//
//------------------------------------------------------------------------------
void BspSdhcSetcardDetectType(PVOID pSpecificContext, UINT8 type)
{
   PBSP_SDHC_CONTEXT pBspContext;
   
   pBspContext = (PBSP_SDHC_CONTEXT)pSpecificContext;
   
   if (type == CARD_DETECT_INSERTION) {
      //Set GPIO pin to sense card insertion 
      DDKGpioSetConfig(pBspContext->dwCardDetectGPIOPort, pBspContext->dwCardDetectGPIOPin, DDK_GPIO_DIR_IN, DDK_GPIO_INTR_LOW_LEV);
   }
   else if (type == CARD_DETECT_REMOVAL) {
      //Set GPIO pin to sense card removal
      DDKGpioSetConfig(pBspContext->dwCardDetectGPIOPort, pBspContext->dwCardDetectGPIOPin, DDK_GPIO_DIR_IN, DDK_GPIO_INTR_HIGH_LEV);
   }
   
}

//------------------------------------------------------------------------------
//
// Function: BSPSdhcIsCardWriteProtected
//
// This function is to check whether card is write protected. 
//
// Parameters:
//      pSpecificContext [in]     BSP Context
//
// Returns:
//      Return TRUE if card is write protected 
//			   FALSE if card is not write protected 
//
//------------------------------------------------------------------------------
BOOL BSPSdhcIsCardWriteProtected(PVOID pSpecificContext)
{
   BOOL fCardWriteProtected = FALSE;
   DWORD dwPinData;
   PBSP_SDHC_CONTEXT pBspContext;
   
   pBspContext = (PBSP_SDHC_CONTEXT)pSpecificContext;
   
   fCardWriteProtected = DDKGpioReadDataPin(pBspContext->dwWriteProtectGPIOPort, pBspContext->dwWriteProtectGPIOPin, &dwPinData);
   
   if (fCardWriteProtected) {
      // Is associate pin high??
      fCardWriteProtected = (dwPinData != 0);
   }
   
   DEBUGMSG(1, (__WFUNCTION__ TEXT("(%c)-\r\n"), fCardWriteProtected?'T':'F'));
   
   return fCardWriteProtected;
}

//------------------------------------------------------------------------------
//
// Function: BspSdhcGetSdmaChannelPriority
//
// This function is to get sdma channel priority 
//
// Parameters:
//		 None 
//
// Returns:
//      Return channel priority
//
//------------------------------------------------------------------------------
UINT8 BspSdhcGetSdmaChannelPriority(DWORD ControllerIndex)
{
   if (ControllerIndex == 1) {
      return BSP_SDMA_CHNPRI_SDHC1;
   }
   else {
      return BSP_SDMA_CHNPRI_SDHC2;
   }
}
//------------------------------------------------------------------------------
//
// Function: BspSdhcGetSdmaChannelTx
//
// This function is to get Tx channel number 
//
// Parameters:
//		 None 
//
// Returns:
//      Tx Channel Number
//
//------------------------------------------------------------------------------
UINT BspSdhcGetSdmaChannelTx(DWORD ControllerIndex)
{
   if (ControllerIndex == 1) {
      return DDK_DMA_REQ_SDHC1_TX;
   }
   else {
      return DDK_DMA_REQ_SDHC2_TX;
   }
}
//------------------------------------------------------------------------------
//
// Function: BspSdhcGetSdmaChannelRx
//
// This function is to get Rx channel number 
//
// Parameters:
//		 None 
//
// Returns:
//      Rx Channel Number
//
//------------------------------------------------------------------------------
UINT BspSdhcGetSdmaChannelRx(DWORD ControllerIndex)
{
   if (ControllerIndex == 1) {
      return DDK_DMA_REQ_SDHC1_RX;
   }
   else {
      return DDK_DMA_REQ_SDHC2_RX;
   }
}
//------------------------------------------------------------------------------
//
// Function: BspSdhcIsSdmaSupported
//
// This function is to know whether DMA support is enabled for the controller
//
// Parameters:
//		 None 
//
// Returns:
//      TRUE - DMA supported
//      FALSE - DMA not supported
//
//------------------------------------------------------------------------------
BOOL BspSdhcIsSdmaSupported(DWORD ControllerIndex)
{
   if (ControllerIndex == 1) {
#if BSP_SDMA_SUPPORT_SDHC1
      return TRUE;
#else
      return FALSE;
#endif // BSP_SDMA_SUPPORT_SDHC1
   }
   else {
#if BSP_SDMA_SUPPORT_SDHC2
      return TRUE;
#else
      return FALSE;
#endif // BSP_SDMA_SUPPORT_SDHC2
   }
}
//------------------------------------------------------------------------------
//
// Function: BspSdhcIsClockGatingBetweenCmdsSupported
//
// This function is to know whether controller can be clock gated between commands
//
// Parameters:
//		 None 
//
// Returns:
//      TRUE - if supported
//      FALSE - if not supported
//
//------------------------------------------------------------------------------
BOOL BspSdhcIsClockGatingBetweenCmdsSupported(DWORD ControllerIndex)
{
   if (ControllerIndex == 1) {
#if BSP_CLK_GATING_BETWEEN_CMDS_SDHC1
      return TRUE;
#else
      return FALSE;
#endif // BSP_CLK_GATING_BETWEEN_CMDS_SDHC1
   }
   else {
#if BSP_CLK_GATING_BETWEEN_CMDS_SDHC2
      return TRUE;
#else
      return FALSE;
#endif // BSP_CLK_GATING_BETWEEN_CMDS_SDHC2
   }
}

//------------------------------------------------------------------------------
//
//  Function: BspSdhcGetSdmaMinTransfer
//
//  Specifies the minimum transfer size for which DMA should be used.  Small 
//  transfers may not benefit from DMA usage due to the overhead associated with 
//  setting up the DMA transfer.
//
//  Parameters:
//      None 
//
//  Returns:
//      Minimum transfer size for DMA in bytes.
//
//------------------------------------------------------------------------------
UINT32 BspSdhcGetSdmaMinTransfer(VOID)
{
   return BSP_SDHC_SDMA_MIN_TRANSFER;
}

//------------------------------------------------------------------------------
//
//  Function: BSPGetMaxCardCLK
//
//  Specifies the maximum card clock frequency supported by the platform.
//  Note that this is a limitation.
//
//  Parameters:
//      None 
//
//  Returns:
//      card clock frequency
//
//------------------------------------------------------------------------------
UINT32 BSPGetMaxCardCLK(void)
{
   return BSP_SDHC_MAX_SDBUS_CLK_SUPPORTED;
}
//------------------------------------------------------------------------------
//
//  Function: BSPPollDataLength
//
//  Specifies the polling duration of data transfer in terms of data bytes.
//  
//  Parameters:
//      None 
//
//  Returns:
//      number of bytes to poll for
//
//------------------------------------------------------------------------------
UINT32 BSPPollDataLength(void)
{
   return BSP_SDHC_POLL_DATA_LENGTH;
}

//------------------------------------------------------------------------------
//
// Function: BSPSdhcIsCardBusy
//
// This function is to check card busy or not.
//
// Parameters:
//		None.
//
// Returns:
//		TRUE indicates card is busy; otherwise return FALSE.
//
//-------------------------------------------------------------------------------
BOOL BSPSdhcIsCardBusy(void)
{
   UINT32 card_busy = 0 ;
   
   if (DDKGpioReadDataPin(DDK_GPIO_PORT2, 28, &card_busy) == FALSE) {
      card_busy = 0 ; //GPIO read failed
   }
   return (card_busy ? FALSE : TRUE); 
}
