/**************************************************************************//**
 * @file     gatedrv.c
 * @brief    This file provides GATEDRV firmware functions.
 * @version  VXX.XX.XX
 * @date     XX-XXX-XXXX
 *
 * @note
 * Copyright (C) 2022 Spintrol Electronic Technology (Shanghai) Co., Ltd.. All rights reserved.
 *
 * @attention
 * THIS SOFTWARE JUST PROVIDES CUSTOMERS WITH CODING INFORMATION REGARDING
 * THEIR PRODUCTS, WHICH AIMS AT SAVING TIME FOR THEM. SPINTROL SHALL NOT BE
 * LIABLE FOR THE USE OF THE SOFTWARE. SPINTROL DOES NOT GUARANTEE THE
 * CORRECTNESS OF THIS SOFTWARE AND RESERVES THE RIGHT TO MODIFY THE SOFTWARE
 * WITHOUT NOTIFICATION.
 *
 ******************************************************************************/

#include "gatedrv.h"



/**
 *  @brief  GATEDRV Register Default Value
 */
const uint8_t gau8GATEDRVRegDefaultVal[32] =
{
  0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x22, 0x03, 0xEF, 0x21, 0xEF, 0x21,
  0xC5, 0x87, 0x03, 0x3B, 0x0D, 0x07, 0x01, 0x07,
  0x01, 0x00, 0x00, 0x0A, 0xFF, 0x1A, 0x00, 0x00
};



/**
 *  @brief  GATEDRV Register Mask Value
 */
const uint8_t gau8GATEDRVRegMask[32] =
{
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
  0xFF, 0xFF, 0x3F, 0x03, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0x3F, 0x1F, 0x0F, 0x03, 0x0F,
  0x0F, 0xFF, 0xFF, 0x0F, 0xFF, 0x7F, 0xFF, 0xFF
};




/**
 *  @brief  GATEDRV Trim Data Variable
 */
OTPInfoStruct_GATEDRV OTPInfoData_GATEDRV;




/****************************************************************************//**
 * @brief      Initialize GATEDRV Pin interface
 *
 * @param[in]  none
 *
 * @return     none
 *
 *******************************************************************************/
void GATEDRV_PinInit(void)
{
  /* Set Pin As GPIO */
  GPIO_SetPinAsGPIO(GPIO_GATEDRV_EN);
  GPIO_SetPinAsGPIO(GPIO_GATEDRV_FAULTN);
  GPIO_SetPinAsGPIO(GPIO_GATEDRV_OC_OV);
  GPIO_SetPinAsGPIO(GPIO_GATEDRV_EN);

  /* Set Pin Direction */
  GPIO_SetPinDir(GPIO_GATEDRV_EN, GPIO_OUTPUT);
  GPIO_SetPinDir(GPIO_GATEDRV_FAULTN, GPIO_INPUT);
  GPIO_SetPinDir(GPIO_GATEDRV_OC_OV, GPIO_INPUT);
  GPIO_SetPinDir(GPIO_GATEDRV_EN, GPIO_OUTPUT);

  /* Gate Enabe Pin (GPIO17) Default Output Low */
  GPIO_WritePin(GPIO_GATEDRV_EN, GPIO_LEVEL_LOW);
}




/****************************************************************************//**
 * @brief      Initialize GATEDRV Communication Interface
 *
 * @param[in]  u32Baudrate:  Communication Speed (bps)
 *
 * @return     none
 *
 *******************************************************************************/
ErrorStatus GATEDRV_ComInit(uint32_t u32Baudrate)
{
  /* Set GATEDRV Communication Interface */
  GPIO_SetPinChannel(GPIO_GATEDRV_COM_DIO, GPIO18_SPI_MO );
  GPIO_SetPinChannel(GPIO_GATEDRV_COM_CLK, GPIO19_SPI_CLK);
  GPIO_SetPinChannel(GPIO_GATEDRV_COM_CS , GPIO20_SPI_FRM);

  /*  Enable Clock for SSP */
  CLOCK_EnableModule(SSP_MODULE);

  /* Init SSP - Master Mode, 32-bit frame size */
  SSP_Init(SSP, SSP_MASTER_MODE, 32, u32Baudrate, SSP_FRM_ACTIVE_LOW, SSP_CLK_IDLE_LOW, SSP_SEND_ON_FALLING_EDGE);

  /* Enable SSP */
  SSP_Enable(SSP);

  return SUCCESS;
}




/****************************************************************************//**
 * @brief      Initialize GATEDRV
 *
 * @param[in]  u32Baudrate:  Communication Speed (bps)
 * @param[in]  pu8ID      :  Pointer to the data stored GATEDRV ID
 * @param[in]  u32Timeout :  Time-out
 *
 * @return     ERROR or SUCCESS
 *
 *******************************************************************************/
ErrorStatus GATEDRV_Init(uint32_t u32Baudrate, uint8_t *pu8ID, uint32_t u32Timeout)
{
  /* Init Pin Interface */
  GATEDRV_PinInit();

  /* Init Communication */
  GATEDRV_ComInit(u32Baudrate);

  /* Handshake with GATEDRV */
  return GATEDRV_Handshake(pu8ID, u32Timeout);
}




/****************************************************************************//**
 * @brief      Send command and receive its response
 *
 * @param[in]  u32Req  :  Request data
 * @param[in]  pu32Resp:  Pointer to the data received
 *
 * @return     ERROR or SUCCESS
 *
 *******************************************************************************/
ErrorStatus GATEDRV_Command(uint32_t u32Req, uint32_t *pu32Resp)
{
  /* Set GATEDRV Communication Data Pin as Output */
  GPIO_SetPinChannel(GPIO_GATEDRV_COM_DIO, GPIO18_SPI_MO);

  /* Wait until SSP TxFIFO is Not Full */
  while(!SSP_IsTxFifoNotFull(SSP));

  /* Send Request data to GATEDRV */
  SSP_SendData(SSP, u32Req);

  /*** wait until SSP receive buffer is not empty, eg. SSP received data ***/
  while (!SSP_IsRxFifoNotEmpty(SSP));

  /*** Get SSP receive data from buffer, ignore these data ***/
  while (SSP_IsRxFifoNotEmpty(SSP))
  {
    SSP_ReceiveData(SSP);
  }

  /* This delay is important for correct data transfer */
  Delay_us(10);

  /* Set GATEDRV Communication Data Pin as Input */
  GPIO_SetPinChannel(GPIO_GATEDRV_COM_DIO, GPIO18_SPI_MI);

  /* Send dummy data for receive data from GATEDRV */
  SSP_SendData(SSP, 0);

  /* Wait until SSP Rx FIFO is not empty */
  while(!SSP_IsRxFifoNotEmpty(SSP));

  /* Get Response Data From GATEDRV */
  *pu32Resp = SSP_ReceiveData(SSP);

  return SUCCESS;
}




/****************************************************************************//**
 * @brief      Handshake with GATEDRV
 *
 * @param[in]  pu8ID     :  Pointer to the data stored GATEDRV ID
 * @param[in]  u32Timeout:  Time-out
 *
 * @return     ERROR or SUCCESS
 *
 *******************************************************************************/
ErrorStatus GATEDRV_Handshake(uint8_t *pu8ID, uint32_t u32Timeout)
{
  uint32_t u32RxData = 0;
  uint32_t u32Count = 0;

  /* Handshake Protocol */
  while(1)
  {
    Delay_us(100);

    /* Try to Get GATEDRV ID */
    if(GATEDRV_Command(GATEDRV_CMD_READ_ID, &u32RxData) == ERROR)
    {
      return ERROR;
    }

    /* Validate received data */
    if((u32RxData & 0xFFFF00FFU) == GATEDRV_RESP_READ_ID)
    {
      /* Valid ID data */
      *pu8ID = (uint8_t)((u32RxData & 0x0000FF00U) >> 8);

      return SUCCESS;
    }
    else if( u32Count++ > u32Timeout)
    {
      return ERROR;
    }
  }
}




/****************************************************************************//**
 * @brief      Write data to GATEDRV register
 *
 * @param[in]  u8Addr:  Register address
 * @param[in]  u8Data:  Data to be written to the specified register
 *
 * @return     ERROR or SUCCESS
 *
 *******************************************************************************/
ErrorStatus GATEDRV_WriteREG(uint8_t u8Addr, uint8_t u8Data)
{
  uint32_t u32Request = 0;
  uint32_t u32Response = 0;

  /* Check register address */
  if(!IS_GATEDRV_REG_ADDR(u8Addr))
  {
    return ERROR;
  }

  /* Write request */
  u32Request = GATEDRV_CMD_WRITE | ((u8Addr & 0x0000001FU) << 16) | ((u8Data & 0x000000FFU) <<  8) ;

  /* Send write request data */
  if(GATEDRV_Command(u32Request, &u32Response) == ERROR)
  {
    return ERROR;
  }

  /* Validate response data */
  if(u32Response != (GATEDRV_RESP_WRITE | ((u8Addr & 0x0000001FU) << 16) | ((u8Data & 0x000000FFU) <<  8)) )
  {
    return ERROR;
  }

  /* Excute request */
  u32Request = GATEDRV_CMD_EXECUTE;

  /* Send excute request data */
  if(GATEDRV_Command(u32Request, &u32Response) == ERROR)
  {
    return ERROR;
  }

  /* Validate response data */
  if(u32Response != GATEDRV_RESP_EXECUTE)
  {
    return ERROR;
  }

  return SUCCESS;
}




/****************************************************************************//**
 * @brief      Read data from GATEDRV register
 *
 * @param[in]  u8Addr :  Register address
 * @param[in]  pu8Data:  Pointer to the  data read from register
 *
 * @return     ERROR or SUCCESS
 *
 *******************************************************************************/
ErrorStatus GATEDRV_ReadREG(uint8_t u8Addr, uint8_t *pu8Data)
{
  uint32_t u32Request = 0;
  uint32_t u32Response = 0;

  /* Check register address */
  if(!IS_GATEDRV_REG_ADDR(u8Addr))
  {
    return ERROR;
  }

  /* Read request */
  u32Request = GATEDRV_CMD_READ | (((u8Addr) & 0x0000001FU) << 16);

  /* Send read request data */
  if(GATEDRV_Command(u32Request, &u32Response) == ERROR)
  {
    return ERROR;
  }

  /* Validate response data */
  if((u32Response & 0xFFFF0000U) != (GATEDRV_RESP_READ | (((u8Addr) & 0x0000001FU) << 16)))
  {
    return ERROR;
  }

  /* Validate register data */
  if((u32Response & 0x000000FFU) != ((u32Response & 0x0000FF00U) >> 8))
  {
    return ERROR;
  }

  /* Get Register value */
  *pu8Data = (uint8_t)(u32Response & 0x000000FFU);

  return SUCCESS;
}




/****************************************************************************//**
 * @brief      Write GATEDRV register Bit Fields
 *
 * @param[in]  u8Addr :  Register address
 * @param[in]  u8Data :  Data to be written to the specified register bits
 * @param[in]  u8Start:  The start bit
 * @param[in]  u8Len  :  Bit length
 *
 * @return     ERROR or SUCCESS
 *
 *******************************************************************************/
ErrorStatus GATEDRV_WriteREGBits(uint8_t u8Addr, uint8_t u8Data, uint8_t u8Start, uint8_t u8Len)
{
  uint8_t i = 0;
  uint8_t u8Msk = 0;
  uint8_t u8RxData = 0;

  /* Check register address */
  if(!IS_GATEDRV_REG_ADDR(u8Addr))
  {
    return ERROR;
  }

  /* Check register bit */
  if((u8Start >= 8) || ((u8Start + u8Len) > 8))
  {
    return ERROR;
  }

  /* Check register bit data */
  for(i = 0; i < u8Len; i++)
  {
    u8Msk = (u8Msk << 1) + 1;
  }

  if(u8Data > u8Msk)
  {
    return ERROR;
  }

  /* Read register data */
  if(GATEDRV_ReadREG(u8Addr, &u8RxData) == ERROR)
  {
    return ERROR;
  }

  /* Current register bit value == setting data */
  if(((u8RxData >> u8Start) & u8Msk) == u8Data)
  {
    return SUCCESS;
  }

  u8Data <<= u8Start;
  u8Msk <<= u8Start;

  return GATEDRV_WriteREG(u8Addr, (u8RxData & (~u8Msk)) | u8Data);
}




/****************************************************************************//**
 * @brief      Reset GATEDRV register to default value
 *
 * @param[in]  none
 *
 * @return     ERROR or SUCCESS
 *
 *******************************************************************************/
ErrorStatus GATEDRV_ResetREG(void)
{
  uint8_t u8Addr;

  /* Write default register value */
  for(u8Addr = 4; u8Addr <= 0x1F; u8Addr++)
  {
    if(GATEDRV_WriteREG(u8Addr, gau8GATEDRVRegDefaultVal[u8Addr]) == ERROR)
    {
      return ERROR;
    }
  }

  return SUCCESS;
}




/****************************************************************************//**
 * @brief      Trim GATEDRV register
 *
 * @param[in]  none
 *
 * @return     ERROR or SUCCESS
 *
 *******************************************************************************/
ErrorStatus GATEDRV_Trim(void)
{
  ErrorStatus status = SUCCESS;

  /* Read GATEDRV trim data from OTP Flash */
  FLASH_ReadOTP((uint8_t *)(&OTPInfoData_GATEDRV), 0x1038, sizeof(OTPInfoStruct_GATEDRV));

  /* Check trim value - If GATEDRV not trimmed, set trim value to default */
  if(OTPInfoData_GATEDRV.BUCK_REF_SEL == 0xFF)
  {
    OTPInfoData_GATEDRV.BUCK_REF_SEL = 7;
  }

  if(OTPInfoData_GATEDRV.LDO5_TRIM == 0xFF)
  {
    OTPInfoData_GATEDRV.LDO5_TRIM = 7;
  }

  if(OTPInfoData_GATEDRV.BUCK_TRIM_TON == 0xFF)
  {
    OTPInfoData_GATEDRV.BUCK_TRIM_TON = 1;
  }

  if(OTPInfoData_GATEDRV.BUCK_TRIM_ILIMIT == 0xFF)
  {
    OTPInfoData_GATEDRV.BUCK_TRIM_ILIMIT = 3;
  }

  if(OTPInfoData_GATEDRV.GATEDRV_OSC_TRIM == 0xFF)
  {
    OTPInfoData_GATEDRV.GATEDRV_OSC_TRIM = 3;
  }

  /* LDO5 trim */
  status = GATEDRV_WriteREG(0x17, OTPInfoData_GATEDRV.LDO5_TRIM);
  if(status == ERROR) return ERROR;

  /* Buck reference voltage trim */
  status = GATEDRV_WriteREG(0x11, 0x80 | OTPInfoData_GATEDRV.BUCK_REF_SEL);
  if(status == ERROR) return ERROR;

  /* Current limit and PWM turn-on time trim */
  status = GATEDRV_WriteREG(0x14, (OTPInfoData_GATEDRV.BUCK_TRIM_ILIMIT << 2) | OTPInfoData_GATEDRV.BUCK_TRIM_TON);
  if(status == ERROR) return ERROR;

  /* OSC trim */
  status = GATEDRV_WriteREG(0x13, (0x07 << 3) | OTPInfoData_GATEDRV.GATEDRV_OSC_TRIM);

  return status;
}




/********************************************************************************
 * @brief      Enable the PREDRIVER Low Voltage Operation
 *
 * @param[in]  none
 *
 * @return     ERROR or SUCCESS
 *
 *
 *******************************************************************************/
ErrorStatus GATEDRV_EnableLowVoltageOperation(void)
{
  uint8_t u8PREDRIDATA;
    
  /* Read the original data */
  if(GATEDRV_ReadREG(0x18, &u8PREDRIDATA) == ERROR)
  {
    return ERROR;
  }
  
  /* Enable the PREDRIVER Low Voltage Operation */
  if(GATEDRV_WriteREG(0x18, (u8PREDRIDATA | 0x8)) == ERROR)
  {
    return ERROR;
  }
  
  return SUCCESS;
}


/******************* Copyright (C) 2022 Spintrol Electronic Technology (Shanghai) Co., Ltd. ***** END OF FILE ****/
