/*******************************************************************************
 * @file     hv.c
 * @brief    High voltage module firmware functions.
 * @version  V4.0.1
 * @date     30-July-2026
 * @internal_changelog_begin
 * Version          : V4_0_0
 *   JIRA           : BSP-1098
 *     Author       : ruiqing.huang
 *       Description:
 *         In HV_ResetReg(), answer value should be HV_RESP_RESET.
 * @internal_changelog_end
 *
 * @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 "spc1158_hv.h"


#if defined(__CC_ARM)
    #pragma push
    #pragma O1
#endif




/********************************************************************************
 * @brief      Initialize High Voltage Module Communication Interface
 *
 * @param[in]  u32Baudrate:  Communication Speed (bps)
 *
 * @return     none
 *
 *******************************************************************************/
#if defined(__ICCARM__)
#pragma optimize=low
#endif
ErrorStatus HV_ComInit(uint32_t u32Baudrate)
{
  /*  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);

  /* Enable DC-DC Communication Interface */
  EPWR_WALLOW();
  EPWR_Enable();
  EPWR_EnableComInterface();
  EPWR_WDIS();

  return SUCCESS;
}




/********************************************************************************
 * @brief      Initialize High Voltage Module
 *
 * @param[in]  u32Baudrate:  Communication Speed (bps)
 * @param[in]  pu8ID      :  Pointer to the data stored High Voltage Module ID
 * @param[in]  u32Timeout :  Time-out
 *
 * @return     ERROR or SUCCESS
 *
 *******************************************************************************/
#if defined(__ICCARM__)
#pragma optimize=low
#endif
ErrorStatus HV_Init(uint32_t u32Baudrate, uint8_t *pu8ID, uint32_t u32Timeout)
{
  /* Init Communication */
  HV_ComInit(u32Baudrate);

  /* Handshake with High Voltage Module */
  if(HV_Handshake(pu8ID, u32Timeout) == ERROR)
  {
    return ERROR;
  }
  
  /* Init High Voltage Module registers */
  return HV_InitReg();
}




/********************************************************************************
 * @brief      Send command and receive its response
 *
 * @param[in]  u32Req  :  Request data
 * @param[in]  pu32Resp:  Pointer to the data received
 *
 * @return     ERROR or SUCCESS
 *
 *******************************************************************************/
#if defined(__ICCARM__)
#pragma optimize=low
#endif
ErrorStatus HV_Command(uint32_t u32Req, uint32_t *pu32Resp)
{
  /* Init the count number */
  volatile uint32_t u32Timeout;
    
  /* Set EPWR Communication Data Pin Direction - Transmit data */
  EPWR_WALLOW();
  EPWR_EnableTransmitData();
  EPWR_WDIS();

  /* Init the count number */
  u32Timeout = 0U;
  
  /* Wait until SSP TxFIFO is Not Full */
  while((SSP_IsTxNotFull(SSP) == 0U) && (u32Timeout < HV_TIMEOUT_MAX))
  {
    u32Timeout++;
  }
  /* Timeout */
  if(u32Timeout >= HV_TIMEOUT_MAX)
  {
    return ERROR;
  }

  /* Send Request data to High Voltage Module */
  SSP_SendData(SSP, u32Req);

  /* Init the count number */
  u32Timeout = 0U;
  
  /* Wait until SSP RxFIFO is Not Empty */
  while((SSP_IsRxNotEmpty(SSP) == 0U) && (u32Timeout < HV_TIMEOUT_MAX))
  {
    u32Timeout++;
  }
  /* Timeout */
  if(u32Timeout >= HV_TIMEOUT_MAX)
  {
    return ERROR;
  }

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

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

  /* Set EPWR Communication Data Pin Direction - Receive data */
  EPWR_WALLOW();
  EPWR_EnableReceiveData();
  EPWR_WDIS();

  /* Send dummy data for receive data from High Voltage Module */
  SSP_SendData(SSP, 0);

  /* Init the count number */
  u32Timeout = 0U;
  
  /* Wait until SSP RxFIFO is not empty */
  while((SSP_IsRxNotEmpty(SSP) == 0U) && (u32Timeout < HV_TIMEOUT_MAX))
  {
    u32Timeout++;
  }
  /* Timeout */
  if(u32Timeout >= HV_TIMEOUT_MAX)
  {
    return ERROR;
  }

  /* Get Response Data From High Voltage Module */
  *pu32Resp = SSP_ReceiveData(SSP);

  return SUCCESS;
}




/********************************************************************************
 * @brief      Handshake with High Voltage Module
 *
 * @param[in]  pu8ID     :  Pointer to the data stored High Voltage Module ID
 * @param[in]  u32Timeout:  Time-out
 *
 * @return     ERROR or SUCCESS
 *
 *******************************************************************************/
#if defined(__ICCARM__)
#pragma optimize=low
#endif
ErrorStatus HV_Handshake(uint8_t *pu8ID, uint32_t u32Timeout)
{
  uint32_t u32RxData = 0;
  volatile uint32_t u32Count = 0;

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

    /* Try to Get High Voltage Module ID */
    if(HV_Command(HV_CMD_READ_ID, &u32RxData) == ERROR)
    {
      return ERROR;
    }

    /* Validate received data */
    if((u32RxData & 0xFFFFFF00U) == HV_RESP_READ_ID)
    {
      /* Valid ID data */
      if(pu8ID != NULL) *pu8ID = (uint8_t)(u32RxData & 0x000000FFU);

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




/********************************************************************************
 * @brief      Write data to High Voltage Module register
 *
 * @param[in]  u8Addr:  Register address
 * @param[in]  u8Data:  Data to be written to the specified register
 *
 * @return     ERROR or SUCCESS
 *
 *******************************************************************************/
#if defined(__ICCARM__)
#pragma optimize=low
#endif
ErrorStatus HV_WriteReg(uint8_t u8Addr, uint8_t u8Data)
{
  uint32_t u32Request = 0;
  uint32_t u32Response = 0;
  uint8_t  u8Data0 = u8Data;

  /* Check register address */
  if(!IS_HV_REG(u8Addr))
  {
    return ERROR;
  }
  
  /* Make sure BUCKCTL0[0] = 0 */
  if(u8Addr == HV_REG_BUCKCTL0)
  {
    u8Data0 = u8Data & 0xFE;
  }

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

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

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

  /* Excute request */
  u32Request = HV_CMD_EXECUTE;

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

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

  return SUCCESS;
}




/********************************************************************************
 * @brief      Read data from High Voltage Module register
 *
 * @param[in]  u8Addr :  Register address
 * @param[in]  pu8Data:  Pointer to the data readed from register
 *
 * @return     ERROR or SUCCESS
 *
 *******************************************************************************/
#if defined(__ICCARM__)
#pragma optimize=low
#endif
ErrorStatus HV_ReadReg(uint8_t u8Addr, uint8_t *pu8Data)
{
  ErrorStatus eStatus = ERROR;
  uint32_t u32Request = 0;
  uint32_t u32Response = 0;

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

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

  /* Send read request data */
  eStatus = HV_Command(u32Request, &u32Response);

  /* Get Register value */
  *pu8Data = (uint8_t)(u32Response & 0x000000FFU);
  
  if(ERROR == eStatus)
  {
    return ERROR;
  }

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

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

  return SUCCESS;
}




/********************************************************************************
 * @brief      Write High Voltage Module register bit-fieds
 *
 * @param[in]  u8Addr      :  Register address
 * @param[in]  u8Mask      :  Bit-field mask
 * @param[in]  u8FieldData :  Register bit-field value (shifted according to its position)
 *
 * @return     ERROR or SUCCESS
 *
 *******************************************************************************/
#if defined(__ICCARM__)
#pragma optimize=low
#endif
ErrorStatus HV_WriteRegField(uint8_t u8Addr, uint8_t u8Mask, uint8_t u8FieldData)
{
  uint8_t u8RxData = 0;

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

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

  /* Current register bit value == setting data */
  if((u8RxData & (u8Mask)) == (u8FieldData))
  {
    return SUCCESS;
  }

  u8RxData &= (~(u8Mask));
  u8RxData |= (u8FieldData);

  return HV_WriteReg(u8Addr, u8RxData);
}




/********************************************************************************
 * @brief      Init High Voltage Module registers (Trim)
 *
 * @param[in]  none
 *
 * @return     ERROR or SUCCESS
 *
 *******************************************************************************/
#if defined(__ICCARM__)
#pragma optimize=low
#endif
ErrorStatus HV_InitReg(void)
{
  uint32_t u32Temp;
  
  
  /* Get High Voltage Module Trim Flag */
  u32Temp = *(__IO uint32_t *)(0x11000200 + 0x30 * 4);
  
  /* Valid Trim Flag */
  if(u32Temp == 0x476F6F64)
  {
    /* Enable Write Access */
    if(HV_WriteReg(0x05, 0xAC) == ERROR)
    {
      return ERROR;
    }
    
    /* Write Trim value */
    u32Temp = *(__IO uint32_t *)(0x11000200 + 0x31 * 4);
    if(HV_WriteReg(0x06, u32Temp) == ERROR)
    {
      return ERROR;
    }
    
    /* Write Trim value */
    u32Temp = *(__IO uint32_t *)(0x11000200 + 0x32 * 4);
    if(HV_WriteReg(0x07, u32Temp) == ERROR)
    {
      return ERROR;
    }
    
    /* Disable Write Access */
    if(HV_WriteReg(0x05, 0x00) == ERROR)
    {
      return ERROR;
    }
  }
  else
  {
    return ERROR;
  }

  return SUCCESS;
}




/********************************************************************************
 * @brief      Reset High Voltage Module Register value
 *
 * @param[in]  none
 *
 * @return     ERROR or SUCCESS
 *
 *******************************************************************************/
#if defined(__ICCARM__)
#pragma optimize=low
#endif
ErrorStatus HV_ResetReg(void)
{
  uint32_t u32Request = 0;
  uint32_t u32Response = 0;

  /* Excute request */
  u32Request = HV_CMD_RESET;

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

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




/********************************************************************************
 * @brief      Connect VDDG/10 to Analog Test Pin (GPIO11)
 *
 * @param[in]  none
 *
 * @return     ERROR or SUCCESS
 *
 *******************************************************************************/
#if defined(__ICCARM__)
#pragma optimize=low
#endif
ErrorStatus HV_EnableVDDGAnalogTest(void)
{
  uint32_t u32Temp;
  __IO uint32_t *pREG = (uint32_t *)(0x40000F50);
  
  *pREG = 0x1ACCE551;
  
  pREG = (uint32_t *)(0x40000F00);
  u32Temp = *pREG;
  u32Temp |= 0x1000;
  *pREG = u32Temp;
  
  pREG = (uint32_t *)(0x40000F50);
  *pREG = 0;
  
  
  /* Enable Write Access */
  if(HV_WriteReg(0x05, 0xAC) == ERROR)
  {
    return ERROR;
  }
  
  /* Select VDDG/10 for Analog Test */
  if(HV_WriteReg(0x0A, 0x44) == ERROR)
  {
    return ERROR;
  }
  
  if(HV_WriteReg(0x0B, 0x09) == ERROR)
  {
    return ERROR;
  }
  
  /* Disable Write Access */
  if(HV_WriteReg(0x05, 0x00) == ERROR)
  {
    return ERROR;
  }
  
  return SUCCESS;
}


#if defined(__CC_ARM)
    #pragma pop
#endif


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