text: //--------------------------------------------------------
  //
  //
  //	Melfas MCS8000 Series Download base v1.0 2010.04.05
  //
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/interrupt.h>
  #include <linux/gpio.h>
  #include <linux/delay.h>
  #include <linux/irq.h>
  #include <asm/gpio.h>
  #include <asm/io.h>
  #include "mcs8000_download.h"
  
  
  //============================================================
  //
  //	Include MELFAS Binary code File ( ex> MELFAS_FIRM_bin.c)
  //
  //	Warning!!!!
  //		Please, don't add binary.c file into project
  //		Just #include here !!
  //
  //============================================================
  
  #include "MCS8000_bin.c"
  
  UINT8  ucVerifyBuffer[MELFAS_TRANSFER_LENGTH];		//	You may melloc *ucVerifyBuffer instead of this
  
  
  //---------------------------------
  //	Downloading functions
  //---------------------------------
  static int  mcsdl_download(const UINT8 *pData, const UINT16 nLength, INT8 IdxNum);
  static void mcsdl_set_ready(void);
  static void mcsdl_reboot_mcs(void);
  static int  mcsdl_erase_flash(INT8 IdxNum);
  static int  mcsdl_program_flash(UINT8 *pDataOriginal, UINT16 unLength, INT8 IdxNum);
  static void mcsdl_program_flash_part(UINT8 *pData);
  static int  mcsdl_verify_flash(UINT8 *pData, UINT16 nLength, INT8 IdxNum);
  static void mcsdl_read_flash(UINT8 *pBuffer);
  static int  mcsdl_read_flash_from(UINT8 *pBuffer, UINT16 unStart_addr, UINT16 unLength, INT8 IdxNum);
  static void mcsdl_select_isp_mode(UINT8 ucMode);
  static void mcsdl_unselect_isp_mode(void);
  static void mcsdl_read_32bits(UINT8 *pData);
  static void mcsdl_write_bits(UINT32 wordData, int nBits);
  static void mcsdl_scl_toggle_twice(void);
  //---------------------------------
  //	Delay functions
  //---------------------------------
  static void mcsdl_delay(UINT32 nCount);
  //---------------------------------
  //	For debugging display
  //---------------------------------
  #if MELFAS_ENABLE_DBG_PRINT
  static void mcsdl_print_result(int nRet);
  #endif
  //----------------------------------
  // Download enable command
  //----------------------------------
  #if MELFAS_USE_PROTOCOL_COMMAND_FOR_DOWNLOAD
  void melfas_send_download_enable_command(void)
  {
      // TO DO : Fill this up
  }
  #endif
  
  
  //============================================================
  //
  //	Main Download furnction
  //
  //   1. Run mcsdl_download( pBinary[IdxNum], nBinary_length[IdxNum], IdxNum);
  //       IdxNum : 0 (Master Chip Download)
  //       IdxNum : 1 (2Chip Download)
  //
  //
  //============================================================
  
  int mcsdl_download_binary_data(INT32 hw_ver)
  {
      int nRet;
  #if MELFAS_USE_PROTOCOL_COMMAND_FOR_DOWNLOAD
      melfas_send_download_enable_command();
      mcsdl_delay(MCSDL_DELAY_100US);
  #endif
  
      MELFAS_DISABLE_BASEBAND_ISR();					// Disable Baseband touch interrupt ISR.
      MELFAS_DISABLE_WATCHDOG_TIMER_RESET();			// Disable Baseband watchdog timer
  
      //------------------------
      // Run Download
      //------------------------
      nRet = mcsdl_download((const UINT8*) MELFAS_binary, (const UINT16)MELFAS_binary_nLength , 0);
  #if MELFAS_2CHIP_DOWNLOAD_ENABLE
      nRet = mcsdl_download((const UINT8*) MELFAS_binary_2, (const UINT16)MELFAS_binary_nLength_2, 1);  // Slave Binary data download
  #endif
      MELFAS_ROLLBACK_BASEBAND_ISR();					// Roll-back Baseband touch interrupt ISR.
      MELFAS_ROLLBACK_WATCHDOG_TIMER_RESET();			// Roll-back Baseband watchdog timer
  
      return (nRet == MCSDL_RET_SUCCESS);
  }
  
  
  
  int mcsdl_download_binary_file(void)
  {
      int nRet;
      int i;
  
      UINT8  *pBinary[2] = {NULL, NULL};
      UINT16 nBinary_length[2] = {0, 0};
      UINT8 IdxNum = MELFAS_2CHIP_DOWNLOAD_ENABLE;
      //==================================================
      //
      //	1. Read '.bin file'
      //   2. *pBinary[0]       : Binary data(Master)
      //       *pBinary[1]       : Binary data(Slave)
      //	   nBinary_length[0] : Firmware size(Master)
      //	   nBinary_length[1] : Firmware size(Slave)
      //	3. Run mcsdl_download( pBinary[IdxNum], nBinary_length[IdxNum], IdxNum);
      //       IdxNum : 0 (Master Chip Download)
      //       IdxNum : 1 (2Chip Download)
      //
      //==================================================
  
  #if 0
  
      // TO DO : File Process & Get file Size(== Binary size)
      //			This is just a simple sample
  
      FILE *fp;
      INT  nRead;
  
      //------------------------------
      // Open a file
      //------------------------------
  
      if (fopen(fp, "MELFAS_FIRMWARE.bin", "rb") == NULL)
      {
          return MCSDL_RET_FILE_ACCESS_FAILED;
      }
  
      //------------------------------
      // Get Binary Size
      //------------------------------
  
      fseek(fp, 0, SEEK_END);
  
      nBinary_length = (UINT16)ftell(fp);
  
      //------------------------------
      // Memory allocation
      //------------------------------
  
      pBinary = (UINT8*)malloc((INT)nBinary_length);
  
      if (pBinary == NULL)
      {
  
          return MCSDL_RET_FILE_ACCESS_FAILED;
      }
  
      //------------------------------
      // Read binary file
      //------------------------------
  
      fseek(fp, 0, SEEK_SET);
  
      nRead = fread(pBinary, 1, (INT)nBinary_length, fp);		// Read binary file
  
      if (nRead != (INT)nBinary_length)
      {
  
          fclose(fp);												// Close file
  
          if (pBinary != NULL)										// free memory alloced.
              free(pBinary);
  
          return MCSDL_RET_FILE_ACCESS_FAILED;
      }
  
      //------------------------------
      // Close file
      //------------------------------
  
      fclose(fp);
  
  #endif
  
  #if MELFAS_USE_PROTOCOL_COMMAND_FOR_DOWNLOAD
      melfas_send_download_enable_command();
      mcsdl_delay(MCSDL_DELAY_100US);
  #endif
  
      MELFAS_DISABLE_BASEBAND_ISR();                  // Disable Baseband touch interrupt ISR.
      MELFAS_DISABLE_WATCHDOG_TIMER_RESET();          // Disable Baseband watchdog timer
  
      for (i = 0;i <= IdxNum;i++)
      {
          if (pBinary[i] != NULL && nBinary_length[i] > 0 && nBinary_length[i] < 32*1024)
          {
              //------------------------
              // Run Download
              //------------------------
              nRet = mcsdl_download((const UINT8 *)pBinary[i], (const UINT16)nBinary_length[i], i);
          }
          else
          {
              nRet = MCSDL_RET_WRONG_BINARY;
          }
      }
  
      MELFAS_ROLLBACK_BASEBAND_ISR();                 // Roll-back Baseband touch interrupt ISR.
      MELFAS_ROLLBACK_WATCHDOG_TIMER_RESET();         // Roll-back Baseband watchdog timer
  
  #if MELFAS_ENABLE_DBG_PRINT
      mcsdl_print_result(nRet);
  #endif
  
      return (nRet == MCSDL_RET_SUCCESS);
  }
  
  //------------------------------------------------------------------
  //
  //	Download function
  //
  //------------------------------------------------------------------
  
  static int mcsdl_download(const UINT8 *pBianry, const UINT16 unLength, INT8 IdxNum)
  {
      int	i;
      int nRet;
  
      UINT8 Check_IC = 0xFF;  // d.model
      UINT8 readBuffer[32];
      UINT8 writeBuffer[4];
      UINT32 wordData;
  
      //---------------------------------
      // Check Binary Size
      //---------------------------------
      if (unLength >= MELFAS_FIRMWARE_MAX_SIZE)
      {
          nRet = MCSDL_RET_PROGRAM_SIZE_IS_WRONG;
          goto MCSDL_DOWNLOAD_FINISH;
      }
  
  
  #if MELFAS_ENABLE_DBG_PROGRESS_PRINT
      printk(" - Starting download...\n");
  #endif
  
      //---------------------------------
      // Make it ready
      //---------------------------------
  #if MELFAS_ENABLE_DBG_PROGRESS_PRINT
      printk(" > Ready\n");
  #endif
      mcsdl_set_ready();
  
      mcsdl_delay(MCSDL_DELAY_1MS);
      //--------------------------------------------------------------
      // IC Information read from Flash
      //--------------------------------------------------------------
  #if 1
      if (IdxNum == 0)
      {
          mcsdl_select_isp_mode(ISP_MODE_SERIAL_READ);
  
          wordData   = ((0x1F00 & 0x1FFF) << 1) | 0x0;
          wordData <<= 14;
          mcsdl_write_bits(wordData, 18);
  
          mcsdl_read_flash(readBuffer);
          MCSDL_GPIO_SDA_SET_LOW();
          MCSDL_GPIO_SDA_SET_OUTPUT(0);
  
          mcsdl_unselect_isp_mode();
  
          //if (readBuffer[3] != 0xFF)
          Check_IC = readBuffer[3];
  #if MELFAS_ENABLE_DBG_PROGRESS_PRINT
          printk("\IC Information :0x%02X,  0x%02X\n", readBuffer[3], Check_IC);
  #endif
          mcsdl_delay(MCSDL_DELAY_1MS);
      }
  #endif
  
      //---------------------------------
      // Erase Flash
      //---------------------------------
  #if MELFAS_ENABLE_DBG_PROGRESS_PRINT
      printk(" > Erase\n");
  #endif
      nRet = mcsdl_erase_flash(IdxNum);
      if (nRet != MCSDL_RET_SUCCESS)
          goto MCSDL_DOWNLOAD_FINISH;
  
  #if 1
      mcsdl_delay(MCSDL_DELAY_1MS);
      //--------------------------------------------------------------
      // IC Information write
      //--------------------------------------------------------------
      if (IdxNum == 0)
      {
          mcsdl_select_isp_mode(ISP_MODE_SERIAL_WRITE);
  
          wordData = ((0x1F00 & 0x1FFF) << 1) | 0x0 ;
          wordData = wordData << 14;
          mcsdl_write_bits(wordData, 18);
  
          writeBuffer[0] = Check_IC;
          writeBuffer[1] = 0xFF;
          writeBuffer[2] = 0xFF;
          writeBuffer[3] = 0xFF;
          mcsdl_program_flash_part(writeBuffer);
          //---------------------------------------------
          //	Tail
          //---------------------------------------------
          MCSDL_GPIO_SDA_SET_HIGH();
          mcsdl_delay(MCSDL_DELAY_40US);
  
          for (i = 0; i < 6; i++)
          {
              if (i == 2)
              {
                  mcsdl_delay(MCSDL_DELAY_20US);
              }
              else if (i == 3)
              {
                  mcsdl_delay(MCSDL_DELAY_40US);
              }
  
              MCSDL_GPIO_SCL_SET_HIGH();  mcsdl_delay(MCSDL_DELAY_10US);
              MCSDL_GPIO_SCL_SET_LOW();   mcsdl_delay(MCSDL_DELAY_10US);
          }
          MCSDL_GPIO_SDA_SET_LOW();
  
          mcsdl_unselect_isp_mode();
          mcsdl_delay(MCSDL_DELAY_1MS);
      }
  #endif
  
      //---------------------------------
      // Program Flash
      //---------------------------------
  #if MELFAS_ENABLE_DBG_PROGRESS_PRINT
      printk(" > Program   ");
  #endif
  
      nRet = mcsdl_program_flash((UINT8*)pBianry, (UINT16)unLength, IdxNum);
      if (nRet != MCSDL_RET_SUCCESS)
          goto MCSDL_DOWNLOAD_FINISH;
  
      mcsdl_delay(MCSDL_DELAY_1MS);
      //---------------------------------
      // Verify flash
      //---------------------------------
  #if MELFAS_ENABLE_DBG_PROGRESS_PRINT
      printk(" > Verify    ");
  #endif
      nRet = mcsdl_verify_flash((UINT8*)pBianry, (UINT16)unLength, IdxNum);
      if (nRet != MCSDL_RET_SUCCESS)
          goto MCSDL_DOWNLOAD_FINISH;
  
  
      mcsdl_delay(MCSDL_DELAY_1MS);
      nRet = MCSDL_RET_SUCCESS;
  
  
  MCSDL_DOWNLOAD_FINISH :
  
  #if MELFAS_ENABLE_DBG_PRINT
      mcsdl_print_result(nRet);								// Show result
  #endif
  #if MELFAS_ENABLE_DBG_PROGRESS_PRINT
      printk(" > Rebooting\n");
      printk(" - Fin.\n\n");
  #endif
      mcsdl_reboot_mcs();
  
      return nRet;
  }
  
  
  
  //------------------------------------------------------------------
  //
  //	Sub functions
  //
  //------------------------------------------------------------------
  static int mcsdl_erase_flash(INT8 IdxNum)
  {
      int	  i;
      UINT8 readBuffer[32];
      int eraseCompareValue = 0xFF;
      //----------------------------------------
      //	Do erase
      //----------------------------------------
      if (IdxNum > 0)
      {
          mcsdl_select_isp_mode(ISP_MODE_NEXT_CHIP_BYPASS);
          mcsdl_delay(MCSDL_DELAY_3US);
      }
      mcsdl_select_isp_mode(ISP_MODE_ERASE_FLASH);
      mcsdl_unselect_isp_mode();
  
  
      //----------------------------------------
      //	Check 'erased well'
      //----------------------------------------
  #if 0
      mcsdl_read_flash_from(readBuffer, 0x0000, 16, IdxNum);
      mcsdl_read_flash_from(&readBuffer[16], 0x7FF0, 16, IdxNum);
  
      // Compare with '0xFF'
      if (IdxNum > 0)
      {
          eraseCompareValue = 0x00;
      }
      for (i = 0; i < 32; i++)
      {
          if (readBuffer[i] != eraseCompareValue)
              return MCSDL_RET_ERASE_FLASH_VERIFY_FAILED;
      }
  #endif
  
      return MCSDL_RET_SUCCESS;
  }
  
  
  static int mcsdl_program_flash(UINT8 *pDataOriginal, UINT16 unLength, INT8 IdxNum)
  {
      int		i;
  
      UINT8	*pData;
      UINT8   ucLength;
  
      UINT16  addr;
      UINT32  header;
  
      addr   = 0;
      pData  = pDataOriginal;
      ucLength = MELFAS_TRANSFER_LENGTH;
  
      while ((addr*4) < (int)unLength)
      {
          if ((unLength - (addr*4)) < MELFAS_TRANSFER_LENGTH)
          {
              ucLength  = (UINT8)(unLength - (addr * 4));
          }
  
          //--------------------------------------
          //	Select ISP Mode
          //--------------------------------------
          mcsdl_delay(MCSDL_DELAY_40US);
          if (IdxNum > 0)
          {
              mcsdl_select_isp_mode(ISP_MODE_NEXT_CHIP_BYPASS);
              mcsdl_delay(MCSDL_DELAY_3US);
          }
          mcsdl_select_isp_mode(ISP_MODE_SERIAL_WRITE);
  
          //---------------------------------------------
          //	Header
          //	Address[13ibts] <<1
          //---------------------------------------------
          header = ((addr & 0x1FFF) << 1) | 0x0 ;
          header = header << 14;
          mcsdl_write_bits(header, 18); //Write 18bits
  
          //---------------------------------
          //	Writing
          //---------------------------------
          //addr += (UINT16)ucLength;
          addr += 1;
  
  #if MELFAS_ENABLE_DBG_PROGRESS_PRINT
          printk("#");
  #endif
          mcsdl_program_flash_part(pData);
          pData  += ucLength;
  
          //---------------------------------------------
          //	Tail
          //---------------------------------------------
          MCSDL_GPIO_SDA_SET_HIGH();
          mcsdl_delay(MCSDL_DELAY_40US);
  
          for (i = 0; i < 6; i++)
          {
              if (i == 2)
              {
                  mcsdl_delay(MCSDL_DELAY_20US);
              }
              else if (i == 3)
              {
                  mcsdl_delay(MCSDL_DELAY_40US);
              }
  
              MCSDL_GPIO_SCL_SET_HIGH();  mcsdl_delay(MCSDL_DELAY_10US);
              MCSDL_GPIO_SCL_SET_LOW();   mcsdl_delay(MCSDL_DELAY_10US);
          }
          MCSDL_GPIO_SDA_SET_LOW();
  
          mcsdl_unselect_isp_mode();
          mcsdl_delay(MCSDL_DELAY_300US);
      }
  
      return MCSDL_RET_SUCCESS;
  }
  
  static void mcsdl_program_flash_part(UINT8 *pData)
  {
      int     i;
      UINT32	data;
  
  
      //---------------------------------
      //	Body
      //---------------------------------
      data  = (UINT32)pData[0] <<  0;
      data |= (UINT32)pData[1] <<  8;
      data |= (UINT32)pData[2] << 16;
      data |= (UINT32)pData[3] << 24;
      mcsdl_write_bits(data, 32);
  }
  
  static int mcsdl_verify_flash(UINT8 *pDataOriginal, UINT16 unLength, INT8 IdxNum)
  {
      int	  i, j;
      int	  nRet;
  
      UINT8 *pData;
      UINT8 ucLength;
  
      UINT16 addr;
      UINT32 wordData;
  
      addr  = 0;
      pData = (UINT8 *) pDataOriginal;
      ucLength  = MELFAS_TRANSFER_LENGTH;
  
      while ((addr*4) < (int)unLength)
      {
          if ((unLength - (addr*4)) < MELFAS_TRANSFER_LENGTH)
          {
              ucLength = (UINT8)(unLength - (addr * 4));
          }
          // start ADD DELAY
          mcsdl_delay(MCSDL_DELAY_40US);
  
          //--------------------------------------
          //	Select ISP Mode
          //--------------------------------------
          if (IdxNum > 0)
          {
              mcsdl_select_isp_mode(ISP_MODE_NEXT_CHIP_BYPASS);
              mcsdl_delay(MCSDL_DELAY_3US);
          }
          mcsdl_select_isp_mode(ISP_MODE_SERIAL_READ);
  
  
          //---------------------------------------------
          //	Header
          //	Address[13ibts] <<1
          //---------------------------------------------
          wordData   = ((addr & 0x1FFF) << 1) | 0x0;
          wordData <<= 14;
          mcsdl_write_bits(wordData, 18);
          addr += 1;
  
  #if MELFAS_ENABLE_DBG_PROGRESS_PRINT
          printk("#");
  #endif
  
          //--------------------
          // Read flash
          //--------------------
          mcsdl_read_flash(ucVerifyBuffer);
  
          MCSDL_GPIO_SDA_SET_LOW();
          MCSDL_GPIO_SDA_SET_OUTPUT(0);
  
          //--------------------
          // Comparing
          //--------------------
          if (IdxNum == 0)
          {
              for (j = 0; j < (int)ucLength; j++)
              {
  #if MELFAS_ENABLE_DBG_PROGRESS_PRINT
                  printk(" %02X", ucVerifyBuffer[j]);
  #endif
                  if (ucVerifyBuffer[j] != pData[j])
                  {
  #if MELFAS_ENABLE_DBG_PROGRESS_PRINT
                      printk("\n [Error] Address : 0x%04X : 0x%02X - 0x%02X\n", addr, pData[j], ucVerifyBuffer[j]);
  #endif
                      nRet = MCSDL_RET_PROGRAM_VERIFY_FAILED;
                      goto MCSDL_VERIFY_FLASH_FINISH;
                  }
              }
          }
          else // slave
          {
              for (j = 0; j < (int)ucLength; j++)
              {
  #if MELFAS_ENABLE_DBG_PROGRESS_PRINT
                  printk(" %02X", ucVerifyBuffer[j]);
  #endif
                  if ((0xff - ucVerifyBuffer[j]) != pData[j])
                  {
  #if MELFAS_ENABLE_DBG_PROGRESS_PRINT
                      printk("\n [Error] Address : 0x%04X : 0x%02X - 0x%02X\n", addr, pData[j], ucVerifyBuffer[j]);
  #endif
                      nRet = MCSDL_RET_PROGRAM_VERIFY_FAILED;
                      goto MCSDL_VERIFY_FLASH_FINISH;
                  }
              }
          }
          pData += ucLength;
          mcsdl_unselect_isp_mode();
      }
  
      nRet = MCSDL_RET_SUCCESS;
  
  MCSDL_VERIFY_FLASH_FINISH:
  
  #if MELFAS_ENABLE_DBG_PROGRESS_PRINT
      printk("\n");
  #endif
  
      mcsdl_unselect_isp_mode();
      return nRet;
  }
  
  
  static void mcsdl_read_flash(UINT8 *pBuffer)
  {
      int i;
  
      MCSDL_GPIO_SCL_SET_LOW();
      MCSDL_GPIO_SDA_SET_LOW();
      mcsdl_delay(MCSDL_DELAY_40US);
  
      for (i = 0; i < 6; i++)
      {
          MCSDL_GPIO_SCL_SET_HIGH();  mcsdl_delay(MCSDL_DELAY_10US);
          MCSDL_GPIO_SCL_SET_LOW();  mcsdl_delay(MCSDL_DELAY_10US);
      }
  
      mcsdl_read_32bits(pBuffer);
  }
  
  static int mcsdl_read_flash_from(UINT8 *pBuffer, UINT16 unStart_addr, UINT16 unLength, INT8 IdxNum)
  {
      int	i;
      int j;
  
      UINT8  ucLength;
  
      UINT16 addr;
      UINT32 wordData;
  
      if (unLength >= MELFAS_FIRMWARE_MAX_SIZE)
      {
          return MCSDL_RET_PROGRAM_SIZE_IS_WRONG;
      }
  
      addr  = 0;
      ucLength  = MELFAS_TRANSFER_LENGTH;
  
  #if MELFAS_ENABLE_DBG_PROGRESS_PRINT
      printk(" %04X : ", unStart_addr);
  #endif
  
  
      for (i = 0; i < (int)unLength; i += (int)ucLength)
      {
  
          addr = (UINT16)i;
          if (IdxNum > 0)
          {
              mcsdl_select_isp_mode(ISP_MODE_NEXT_CHIP_BYPASS);
              mcsdl_delay(MCSDL_DELAY_3US);
          }
  
          mcsdl_select_isp_mode(ISP_MODE_SERIAL_READ);
          wordData   = (((unStart_addr + addr) & 0x1FFF) << 1) | 0x0;
          wordData <<= 14;
  
          mcsdl_write_bits(wordData, 18);
          if ((unLength - addr) < MELFAS_TRANSFER_LENGTH)
          {
              ucLength = (UINT8)(unLength - addr);
          }
  
          //--------------------
          // Read flash
          //--------------------
          mcsdl_read_flash(&pBuffer[addr]);
  
  #if MELFAS_ENABLE_DBG_PROGRESS_PRINT
          for (j = 0; j < (int)ucLength; j++)
          {
              printk("%02X ", pBuffer[j]);
          }
  #endif
  
          mcsdl_unselect_isp_mode();
      }
  
      return MCSDL_RET_SUCCESS;
  }
  
  
  static void mcsdl_set_ready(void)
  {
      //--------------------------------------------
      // Tkey module reset
      //--------------------------------------------
  
      MCSDL_VDD_SET_LOW(); // power
      //MCSDL_CE_SET_LOW();
      //MCSDL_CE_SET_OUTPUT();
  
      MCSDL_GPIO_SDA_SET_LOW();
      MCSDL_GPIO_SDA_SET_OUTPUT(0);
  
      MCSDL_GPIO_SCL_SET_LOW();
      MCSDL_GPIO_SCL_SET_OUTPUT(0);
  
      MCSDL_RESETB_SET_LOW();
      MCSDL_RESETB_SET_OUTPUT(0);
  
      mcsdl_delay(MCSDL_DELAY_25MS);						// Delay for Stable VDD
  
      MCSDL_VDD_SET_HIGH();
      //MCSDL_CE_SET_HIGH();
  
      MCSDL_GPIO_SCL_SET_LOW();
      MCSDL_GPIO_SDA_SET_HIGH();
      mcsdl_delay(MCSDL_DELAY_40MS); 						// Delay '30 msec'
  }
  
  
  static void mcsdl_reboot_mcs(void)
  {
      MCSDL_VDD_SET_LOW();
      //MCSDL_CE_SET_LOW();
      //MCSDL_CE_SET_OUTPUT();
  
      MCSDL_GPIO_SDA_SET_HIGH();
      MCSDL_GPIO_SDA_SET_OUTPUT(1);
  
      MCSDL_GPIO_SCL_SET_HIGH();
      MCSDL_GPIO_SCL_SET_OUTPUT(1);
  
      MCSDL_RESETB_SET_LOW();
      MCSDL_RESETB_SET_OUTPUT(0);
  
      mcsdl_delay(MCSDL_DELAY_25MS);						// Delay for Stable VDD
  
      MCSDL_VDD_SET_HIGH();
      //MCSDL_CE_SET_HIGH();
  
      MCSDL_RESETB_SET_HIGH();
      MCSDL_RESETB_SET_OUTPUT(0);
      MCSDL_RESETB_SET_INPUT();
  
      MCSDL_GPIO_SDA_SET_HIGH();
      MCSDL_GPIO_SDA_SET_OUTPUT(1);
      MCSDL_GPIO_SDA_SET_INPUT();
  
      MCSDL_GPIO_SCL_SET_HIGH();
      MCSDL_GPIO_SCL_SET_OUTPUT(1);
      MCSDL_GPIO_SCL_SET_INPUT();
      
      mcsdl_delay(MCSDL_DELAY_30MS); 						// Delay '25 msec'
  }
  
  
  //--------------------------------------------
  //
  //   Write ISP Mode entering signal
  //
  //--------------------------------------------
  static void mcsdl_select_isp_mode(UINT8 ucMode)
  {
      int    i;
  
      UINT8 enteringCodeMassErase[16]   = { 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1 };
      UINT8 enteringCodeSerialWrite[16] = { 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1 };
      UINT8 enteringCodeSerialRead[16]  = { 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1 };
      UINT8 enteringCodeNextChipBypass[16]  = { 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1 };
  
      UINT8 *pCode;
  
  
      //------------------------------------
      // Entering ISP mode : Part 1
      //------------------------------------
      if (ucMode == ISP_MODE_ERASE_FLASH) pCode = enteringCodeMassErase;
      else if (ucMode == ISP_MODE_SERIAL_WRITE) pCode = enteringCodeSerialWrite;
      else if (ucMode == ISP_MODE_SERIAL_READ) pCode = enteringCodeSerialRead;
      else if (ucMode == ISP_MODE_NEXT_CHIP_BYPASS) pCode = enteringCodeNextChipBypass;
  
      MCSDL_RESETB_SET_LOW();
      MCSDL_GPIO_SCL_SET_LOW();
      MCSDL_GPIO_SDA_SET_HIGH();
  
      for (i = 0; i < 16; i++)
      {
          if (pCode[i] == 1)
              MCSDL_RESETB_SET_HIGH();
          else
              MCSDL_RESETB_SET_LOW();
  
          mcsdl_delay(MCSDL_DELAY_3US);
          MCSDL_GPIO_SCL_SET_HIGH();	mcsdl_delay(MCSDL_DELAY_3US);
          MCSDL_GPIO_SCL_SET_LOW();	mcsdl_delay(MCSDL_DELAY_3US);
      }
  
      MCSDL_RESETB_SET_LOW();
  
      //---------------------------------------------------
      // Entering ISP mode : Part 2	- Only Mass Erase
      //---------------------------------------------------
      mcsdl_delay(MCSDL_DELAY_7US);
  
      MCSDL_GPIO_SCL_SET_LOW();
      MCSDL_GPIO_SDA_SET_HIGH();
      if (ucMode == ISP_MODE_ERASE_FLASH)
      {
          mcsdl_delay(MCSDL_DELAY_7US);
          for (i = 0; i < 4; i++)
          {
              if (i == 2) mcsdl_delay(MCSDL_DELAY_25MS);
              else if (i == 3) mcsdl_delay(MCSDL_DELAY_150US);
  
              MCSDL_GPIO_SCL_SET_HIGH();	mcsdl_delay(MCSDL_DELAY_3US);
              MCSDL_GPIO_SCL_SET_LOW();	mcsdl_delay(MCSDL_DELAY_7US);
          }
      }
      MCSDL_GPIO_SDA_SET_LOW();
  }
  
  
  static void mcsdl_unselect_isp_mode(void)
  {
      int i;
  
      MCSDL_RESETB_SET_LOW();
      mcsdl_delay(MCSDL_DELAY_3US);
  
      for (i = 0; i < 10; i++)
      {
          MCSDL_GPIO_SCL_SET_HIGH();	mcsdl_delay(MCSDL_DELAY_3US);
          MCSDL_GPIO_SCL_SET_LOW();	mcsdl_delay(MCSDL_DELAY_3US);
      }
  }
  
  
  
  static void mcsdl_read_32bits(UINT8 *pData)
  {
      int i, j;
  
      MCSDL_GPIO_SCL_SET_LOW();
      MCSDL_GPIO_SDA_SET_LOW();
  
      MCSDL_GPIO_SDA_SET_INPUT();
  
      for (i = 3; i >= 0; i--)
      {
          pData[i] = 0;
          for (j = 0; j < 8; j++)
          {
              pData[i] <<= 1;
  
              MCSDL_GPIO_SCL_SET_LOW();   mcsdl_delay(MCSDL_DELAY_1US);
              MCSDL_GPIO_SCL_SET_HIGH();  mcsdl_delay(MCSDL_DELAY_1US);
  
              if (MCSDL_GPIO_SDA_IS_HIGH())
                  pData[i] |= 0x01;
          }
      }
      
      MCSDL_GPIO_SDA_SET_LOW();
      MCSDL_GPIO_SDA_SET_OUTPUT(0);
  }
  
  
  
  static void mcsdl_write_bits(UINT32 wordData, int nBits)
  {
      int i;
  
      MCSDL_GPIO_SCL_SET_LOW();
      MCSDL_GPIO_SDA_SET_LOW();
  
      for (i = 0; i < nBits; i++)
      {
          if (wordData & 0x80000000) {MCSDL_GPIO_SDA_SET_HIGH();}
          else                       {MCSDL_GPIO_SDA_SET_LOW();}
  
          mcsdl_delay(MCSDL_DELAY_3US);
          MCSDL_GPIO_SCL_SET_HIGH();		mcsdl_delay(MCSDL_DELAY_3US);
          MCSDL_GPIO_SCL_SET_LOW();		mcsdl_delay(MCSDL_DELAY_3US);
  
          wordData <<= 1;
      }
  }
  
  
  static void mcsdl_scl_toggle_twice(void)
  {
      MCSDL_GPIO_SDA_SET_HIGH();
      MCSDL_GPIO_SDA_SET_OUTPUT(1);
  
      MCSDL_GPIO_SCL_SET_HIGH();	mcsdl_delay(MCSDL_DELAY_20US);
      MCSDL_GPIO_SCL_SET_LOW();	mcsdl_delay(MCSDL_DELAY_20US);
  
      MCSDL_GPIO_SCL_SET_HIGH();	mcsdl_delay(MCSDL_DELAY_20US);
      MCSDL_GPIO_SCL_SET_LOW();	mcsdl_delay(MCSDL_DELAY_20US);
  }
  
  
  //============================================================
  //
  //	Delay Function
  //
  //============================================================
  static void mcsdl_delay(UINT32 nCount)
  {
  
      switch (nCount)
      {
      case MCSDL_DELAY_1US   : {udelay(1);   break;}
      case MCSDL_DELAY_2US   : {udelay(2);   break;}
      case MCSDL_DELAY_3US   : {udelay(3);   break;}
      case MCSDL_DELAY_5US   : {udelay(5);   break;}
      case MCSDL_DELAY_7US   : {udelay(7);   break;}
      case MCSDL_DELAY_10US  : {udelay(10);  break;}
      case MCSDL_DELAY_15US  : {udelay(15);  break;}
      case MCSDL_DELAY_20US  : {udelay(20);  break;}
      case MCSDL_DELAY_40US  : {udelay(40);  break;}
      case MCSDL_DELAY_100US : {udelay(100); break;}
      case MCSDL_DELAY_150US : {udelay(150); break;}
      case MCSDL_DELAY_300US : {udelay(300); break;}
      case MCSDL_DELAY_500US : {udelay(500); break;}
      case MCSDL_DELAY_800US : {udelay(800); break;}
      case MCSDL_DELAY_1MS   : {msleep(1);   break;}
      case MCSDL_DELAY_5MS   : {msleep(5);   break;}
      case MCSDL_DELAY_10MS  : {msleep(10);  break;}
      case MCSDL_DELAY_25MS  : {msleep(25);  break;}
      case MCSDL_DELAY_30MS  : {msleep(30);  break;}
      case MCSDL_DELAY_40MS  : {msleep(40);  break;}
      case MCSDL_DELAY_45MS  : {msleep(45);  break;}
      case MCSDL_DELAY_60MS  : {msleep(60);  break;}
      default : {break;}
      }// Please, Use your delay function
  }
  
  
  
  //============================================================
  //
  //	Debugging print functions.
  //
  //============================================================
  
  #ifdef MELFAS_ENABLE_DBG_PRINT
  static void mcsdl_print_result(int nRet)
  {
      if (nRet == MCSDL_RET_SUCCESS)
      {
          printk(" > MELFAS Firmware downloading SUCCESS.\n");
      }
      else
      {
          printk(" > MELFAS Firmware downloading FAILED  :  ");
          switch (nRet)
          {
          case MCSDL_RET_SUCCESS                  		:   printk("MCSDL_RET_SUCCESS\n"); break;
          case MCSDL_RET_ERASE_FLASH_VERIFY_FAILED		:   printk("MCSDL_RET_ERASE_FLASH_VERIFY_FAILED\n"); break;
          case MCSDL_RET_PROGRAM_VERIFY_FAILED			:   printk("MCSDL_RET_PROGRAM_VERIFY_FAILED\n"); break;
  
          case MCSDL_RET_PROGRAM_SIZE_IS_WRONG			:   printk("MCSDL_RET_PROGRAM_SIZE_IS_WRONG\n"); break;
          case MCSDL_RET_VERIFY_SIZE_IS_WRONG				:   printk("MCSDL_RET_VERIFY_SIZE_IS_WRONG\n"); break;
          case MCSDL_RET_WRONG_BINARY						:   printk("MCSDL_RET_WRONG_BINARY\n"); break;
  
          case MCSDL_RET_READING_HEXFILE_FAILED       	:   printk("MCSDL_RET_READING_HEXFILE_FAILED\n"); break;
          case MCSDL_RET_FILE_ACCESS_FAILED       		:   printk("MCSDL_RET_FILE_ACCESS_FAILED\n"); break;
          case MCSDL_RET_MELLOC_FAILED     		  		:   printk("MCSDL_RET_MELLOC_FAILED\n"); break;
  
          case MCSDL_RET_WRONG_MODULE_REVISION     		:   printk("MCSDL_RET_WRONG_MODULE_REVISION\n"); break;
  
          default                             			:	printk("UNKNOWN ERROR. [0x%02X].\n", nRet); break;
          }
  
          printk("\n");
      }
  }
  
  #endif
  
  
  #if MELFAS_ENABLE_DELAY_TEST
  
  //============================================================
  //
  //	For initial testing of delay and gpio control
  //
  //	You can confirm GPIO control and delay time by calling this function.
  //
  //============================================================
  
  void mcsdl_delay_test(INT32 nCount)
  {
      INT16 i;
  
      MELFAS_DISABLE_BASEBAND_ISR();					// Disable Baseband touch interrupt ISR.
      MELFAS_DISABLE_WATCHDOG_TIMER_RESET();			// Disable Baseband watchdog timer
  
      //--------------------------------
      //	Repeating 'nCount' times
      //--------------------------------
  
      //MCSDL_SET_GPIO_I2C();
      MCSDL_GPIO_SCL_SET_OUTPUT(0);
      MCSDL_GPIO_SDA_SET_OUTPUT(0);
      MCSDL_RESETB_SET_OUTPUT(0);
  
      MCSDL_GPIO_SCL_SET_HIGH();
  
      for (i = 0; i < nCount; i++)
      {
  
  #if 1
  
          MCSDL_GPIO_SCL_SET_LOW();
  
          mcsdl_delay(MCSDL_DELAY_20US);
  
          MCSDL_GPIO_SCL_SET_HIGH();
  
          mcsdl_delay(MCSDL_DELAY_100US);
  #elif 0
  
          MCSDL_GPIO_SCL_SET_LOW();
  
          mcsdl_delay(MCSDL_DELAY_500US);
  
          MCSDL_GPIO_SCL_SET_HIGH();
  
          mcsdl_delay(MCSDL_DELAY_1MS);
  #else
  
          MCSDL_GPIO_SCL_SET_LOW();
  
          mcsdl_delay(MCSDL_DELAY_25MS);
  
          TKEY_INTR_SET_LOW();
  
          mcsdl_delay(MCSDL_DELAY_45MS);
  
          TKEY_INTR_SET_HIGH();
  #endif
      }
  
      MCSDL_GPIO_SCL_SET_HIGH();
  
      MELFAS_ROLLBACK_BASEBAND_ISR();					// Roll-back Baseband touch interrupt ISR.
      MELFAS_ROLLBACK_WATCHDOG_TIMER_RESET();			// Roll-back Baseband watchdog timer
  }
  #endif
  
  
  
  