
/******************************************************************************
*@file  : hal_opa.c
*@brief : OPA HAL module driver.

*@ver   : 1.0.0
*@date  : 2022.10.20
******************************************************************************/

#include "hal.h"

/******************************************************************************
*@brief : OPA MSP Initialization.such as module clock, IO share, ... 
*           OPA1 VinP:  PA1, PA3, PA7, DAC1
*           OPA1 VinM:  PA3, PC5
*           OPA1 Vout:  PA2
*               
*           OPA2 VinP:  PA7, PB0, OPA1, DAC2
*           OPA2 VinM:  PA5, PC5
*           OPA2 Vout:  PA6
*               
*           OPA3 VinP:  PB0, PA1, PB11, DAC1
*           OPA3 VinM:  PB2, PB10
*           OPA3 Vout:  PB1
*@param : hopa: OPA handle
*@return: None
******************************************************************************/
__weak void HAL_OPA_MspInit(OPA_HandleTypeDef* hopa)
{  
    //Prevent unused argument(s) compilation warning
    UNUSED(hopa);

    //NOTE : This function should not be modified. 
    //when the callback is needed,the HAL_OPA_MspInit could be implemented in the user file
}

/******************************************************************************
*@brief : OPA MSP De-initiation, such as IO share ... 
*@param : hopa: pointer to OPA handle structure
*@return: None
******************************************************************************/
__weak void HAL_OPA_MspDeInit(OPA_HandleTypeDef* hopa)
{
    //Prevent unused argument(s) compilation warning
    UNUSED(hopa);

    //NOTE : This function should not be modified.
    //When the callback is needed,the HAL_OPA_MspDeInit could be implemented in the user file
}

/******************************************************************************
*@brief : Initialize the OPA. 
*@note  : If the selected OPA is locked, de-initialization can't be performed.
*         To unlock the configuration, perform a module reset.
*@param : hopa: OPA handle
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_OPA_Init(OPA_HandleTypeDef* hopa)
{            
    uint32_t trimValue, nvrTrimValue;
    uint32_t tempReg;
    __IO uint32_t *pCSRx;    
    
    if (hopa == NULL)
    {
        return HAL_ERROR;
    }
    
    //Check parameters
    
    assert_param(IS_OPA_INSTANCE(hopa->Instance));
    assert_param(IS_OPA_OPAx(hopa->Init.OPAx)); 
    assert_param(IS_OPA_MODE(hopa->Init.Mode));
    assert_param(IS_OPA_VINP(hopa->Init.VinPSel));
    assert_param(IS_OPA_VINM0(hopa->Init.VinM0En));
    assert_param(IS_OPA_OUT(hopa->Init.OutSel));    
    assert_param(IS_OPA_POL(hopa->Init.PolSel));
    assert_param(IS_OPA_HSM(hopa->Init.Hsm));
    assert_param(IS_OPA_TRIM(hopa->Init.TrimEn)); 

    if(hopa->Init.Mode == OPA_MODE_PGA)
    {
        assert_param(IS_OPA_GAIN(hopa->Init.Gain));           
    }    

    //get the CSR register of OPAx
    if(hopa->Init.OPAx == OPA1)
    {
        pCSRx = &hopa->Instance->CSR1;
        nvrTrimValue = HAL_EFLASH_READ_WORD(EFLASH_NVR_OPA1_CAL_OSPN_ADDR);
    }
    else if(hopa->Init.OPAx == OPA2)
    {
        pCSRx = &hopa->Instance->CSR2;
        nvrTrimValue = HAL_EFLASH_READ_WORD(EFLASH_NVR_OPA2_CAL_OSPN_ADDR);        
    }    
    else if(hopa->Init.OPAx == OPA3)
    {
        pCSRx = &hopa->Instance->CSR3;
        nvrTrimValue = HAL_EFLASH_READ_WORD(EFLASH_NVR_OPA3_CAL_OSPN_ADDR);          
    } 
    else
    {
        return HAL_ERROR;
    }
    
    //check lock status
    if(*pCSRx & OPA_CSR_LOCK)
    {
        return HAL_ERROR;
    }    

    /* Init the low level hardware : GPIO, CLOCK */
    HAL_OPA_MspInit(hopa);

    tempReg = 0;
    
    tempReg |= ((hopa->Init.Hsm & OPA_CSR_HSM_Msk) | \
                (hopa->Init.Gain & OPA_CSR_GAINSEL_Msk) | \
                (hopa->Init.PolSel & OPA_CSR_POLSEL_Msk) | \
                (hopa->Init.VinM0En & OPA_CSR_VINM0EN_Msk) | \
                (hopa->Init.Mode & OPA_CSR_MODESEL_Msk) | \
                (hopa->Init.VinPSel & OPA_CSR_VINPSEL_Msk) | \
                (hopa->Init.OutSel & OPA_CSR_OUTSEL_Msk));
    
    *pCSRx = tempReg;

    /* Enable the opa */
    SET_BIT(*pCSRx, OPA_CSR_EN); 
    
    if(hopa->Init.TrimEn == OPA_TRIM_ENABLE)
    {
        /* Trim the OPA_CSR_CAL_H N channel */    
        SET_BIT(*pCSRx, OPA_CSR_CALNEN);
        CLEAR_BIT(*pCSRx, OPA_CSR_CALPEN);
        
        for(trimValue=0;trimValue<31;trimValue++)
        {
            MODIFY_REG(*pCSRx,OPA_CSR_TRIMOSN_Msk,(trimValue)<<OPA_CSR_TRIMOSN_Pos);
            HAL_SimpleDelay(1000);
            if(READ_BIT(*pCSRx,OPA_CSR_CALOUT)) break;
        } 
        
        /* Trim the OPA_CSR_CAL_L P channel */    
        SET_BIT(*pCSRx, OPA_CSR_CALPEN);
        CLEAR_BIT(*pCSRx, OPA_CSR_CALNEN);
        
        for(trimValue=0;trimValue<31;trimValue++)
        {
            MODIFY_REG(*pCSRx,OPA_CSR_TRIMOSP_Msk,(trimValue)<<OPA_CSR_TRIMOSP_Pos);
            HAL_SimpleDelay(1000);
            if(READ_BIT(*pCSRx,OPA_CSR_CALOUT)) break;
        }
    }
    else
    {
        /* Use the nvr Trim value */    
        if(((~(nvrTrimValue>>16))&0xFFFF) != (nvrTrimValue&0xFFFF)) return HAL_ERROR;
        
        nvrTrimValue = nvrTrimValue & 0xFFFF;
            
        MODIFY_REG(*pCSRx,OPA_CSR_TRIMOSN_Msk,((nvrTrimValue&0x1F)<<OPA_CSR_TRIMOSN_Pos));
            
        MODIFY_REG(*pCSRx,OPA_CSR_TRIMOSP_Msk,(((nvrTrimValue>>5)&0x1F)<<OPA_CSR_TRIMOSP_Pos));    
    }
 
    /* enable the trim*/    
    SET_BIT(*pCSRx, OPA_CSR_CALPEN);
    SET_BIT(*pCSRx, OPA_CSR_CALNEN);

    return HAL_OK;
}

/******************************************************************************
*@brief : de-Initialize the OPA. 
*@note  : If the selected OPA is locked, de-initialization can't be performed.
*         To unlock the configuration, perform a module reset.
*@param : hopa: OPA handle
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_OPA_DeInit(OPA_HandleTypeDef* hopa)
{ 
    __IO uint32_t *pCSRx;      

    if (hopa == NULL)
    {
        return HAL_ERROR;
    }
    
    assert_param(IS_OPA_INSTANCE(hopa->Instance));
    assert_param(IS_OPA_OPAx(hopa->Init.OPAx)); 
    
    //get the CSR register of OPAx
    if(hopa->Init.OPAx == OPA1)
    {
        pCSRx = &hopa->Instance->CSR1;
    }
    else if(hopa->Init.OPAx == OPA2)
    {
        pCSRx = &hopa->Instance->CSR2;
    }    
    else if(hopa->Init.OPAx == OPA3)
    {
        pCSRx = &hopa->Instance->CSR3;
    } 
    else
    {
        return HAL_ERROR;
    }
    
    //check lock status
    if(*pCSRx & OPA_CSR_LOCK)
    {
        return HAL_ERROR;
    } 
    
    //disable opa
    CLEAR_BIT(*pCSRx, OPA_CSR_EN);
    
    HAL_OPA_MspDeInit(hopa);
    
    return HAL_OK;
}

/******************************************************************************
*@brief : enable OPA.
*@param : hopa: OPA handle
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_OPA_Enable(OPA_HandleTypeDef* hopa)
{    
    __IO uint32_t *pCSRx;
    
    if (hopa == NULL)
    {
        return HAL_ERROR;
    }
    
    assert_param(IS_OPA_INSTANCE(hopa->Instance));
    assert_param(IS_OPA_OPAx(hopa->Init.OPAx)); 
    
    //get the CSR register of OPAx
    if(hopa->Init.OPAx == OPA1)
    {
        pCSRx = &hopa->Instance->CSR1;
    }
    else if(hopa->Init.OPAx == OPA2)
    {
        pCSRx = &hopa->Instance->CSR2;
    }    
    else if(hopa->Init.OPAx == OPA3)
    {
        pCSRx = &hopa->Instance->CSR3;
    } 
    else
    {
        return HAL_ERROR;
    }
    
    //check lock status
    if(*pCSRx & OPA_CSR_LOCK)
    {
        return HAL_ERROR;
    } 
        
    // Enable the opa
    SET_BIT(*pCSRx, OPA_CSR_EN); 
    
    return HAL_OK;
}


/******************************************************************************
*@brief : disable OPA.
*@param : hopa: OPA handle
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_OPA_Disable(OPA_HandleTypeDef* hopa)
{        
    __IO uint32_t *pCSRx;
    
    if (hopa == NULL)
    {
        return HAL_ERROR;
    }
    
    assert_param(IS_OPA_INSTANCE(hopa->Instance));
    assert_param(IS_OPA_OPAx(hopa->Init.OPAx)); 
    
    //get the CSR register of OPAx
    if(hopa->Init.OPAx == OPA1)
    {
        pCSRx = &hopa->Instance->CSR1;
    }
    else if(hopa->Init.OPAx == OPA2)
    {
        pCSRx = &hopa->Instance->CSR2;
    }    
    else if(hopa->Init.OPAx == OPA3)
    {
        pCSRx = &hopa->Instance->CSR3;
    } 
    else
    {
        return HAL_ERROR;
    }
    
    //check lock status
    if(*pCSRx & OPA_CSR_LOCK)
    {
        return HAL_ERROR;
    } 
        
    // Enable the opa
    CLEAR_BIT(*pCSRx, OPA_CSR_EN); 
    
    return HAL_OK;
}

/******************************************************************************
*@brief : lock OPA.
*@param : hopa: OPA handle
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_OPA_Lock(OPA_HandleTypeDef* hopa)
{        
    __IO uint32_t *pCSRx;
    
    if (hopa == NULL)
    {
        return HAL_ERROR;
    }
    
    assert_param(IS_OPA_INSTANCE(hopa->Instance));
    assert_param(IS_OPA_OPAx(hopa->Init.OPAx)); 
    
    //get the CSR register of OPAx
    if(hopa->Init.OPAx == OPA1)
    {
        pCSRx = &hopa->Instance->CSR1;
    }
    else if(hopa->Init.OPAx == OPA2)
    {
        pCSRx = &hopa->Instance->CSR2;
    }    
    else if(hopa->Init.OPAx == OPA3)
    {
        pCSRx = &hopa->Instance->CSR3;
    } 
    else
    {
        return HAL_ERROR;
    }
    
    //check lock status
    if(*pCSRx & OPA_CSR_LOCK)
    {
        return HAL_OK;
    } 
        
    // lock the opa
    SET_BIT(*pCSRx, OPA_CSR_LOCK); 
    
    return HAL_OK;
}


