/*
 * Copyright (c) 2021-2025 Yuntu Microelectronics Co., Ltd.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 *
 */

/*!
 * @file eadc_driver.c
 */

#include <stddef.h>
#include "eadc_driver.h"
#include "eadc_hw_access.h"
#include "clock_manager.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/

/*******************************************************************************
 * Variables
 ******************************************************************************/

/* Table of base addresses for eADC instances. */
static eADC_Type *const s_eadcBase[eADC_INSTANCE_COUNT] = eADC_BASE_PTRS;


/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_ConfigConverter
 * Description   : This function configures the eADC converter with the options
 * provided in the configuration structure.
 *
 * Implements : eADC_DRV_ConfigConverter_Activity
 *END**************************************************************************/
void eADC_DRV_ConfigConverter(const uint32_t instance,
                              const eadc_converter_config_t *const config)
{
    DEV_ASSERT(instance < eADC_INSTANCE_COUNT);
    DEV_ASSERT(config != NULL);

    eADC_Type *const base = s_eadcBase[instance];
    clock_names_t eadc_clocks[eADC_INSTANCE_COUNT] = EADC_CLOCKS;
    uint32_t eadc_freq = 0u;
    status_t clk_status = CLOCK_SYS_GetFreq(eadc_clocks[instance], &eadc_freq);
    DEV_ASSERT(clk_status == STATUS_SUCCESS);
    (void) clk_status;

    eadc_freq = eadc_freq / (uint32_t) (1UL + ((uint32_t) (config->clockDivider)));
    DEV_ASSERT((eadc_freq >= EADC_CLOCK_FREQ_MIN_RUNTIME) && (eadc_freq <= EADC_CLOCK_FREQ_MAX_RUNTIME));
    (void) eadc_freq;

    eADC_SetClkDivider(base, config->clockDivider);
    eADC_SetStartTime(base, config->startTime);
    eADC_SetSampleTime(base, config->sampleTime0, config->sampleTime1);
    eADC_SetSampleAverage(base, config->sampleAverage);
    eADC_SetSwitchChannelCnt(base, config->switchChannelCnt);

    eADC_SetLowPowerEnable(base, config->lowPowerEnable);
    eADC_SetAutoOffEnable(base, config->autoOffEnable);
    eADC_SetDMAGenOverride(base, config->overrideGenDMAReq);
    eADC_SetDataAlign(base, config->align);
    eADC_SetResolution(base, config->resolution);

    /* Config channels */
    eADC_DRV_ConfigSequence(instance, &config->seqConfig);

    /* Config interrupt */
    eADC_SetINTE(base, eADC_READY_INTERRUPT, config->readyIntEnable);
    eADC_SetINTE(base, eADC_END_OF_SAMPLING_INTERRUPT, config->sampIntEnable);
    eADC_SetINTE(base, eADC_END_OF_CONVERSION_INTERRUPT, config->convIntEnable);
    eADC_SetINTE(base, eADC_NORMAL_ERROR_INTERRUPT, config->normalErrorEnable);
    eADC_SetINTE(base, eADC_OVERRUN_INTERRUPT, config->ovrunIntEnable);
    eADC_SetINTE(base, eADC_LOW_PRIORITY_TRIGGER_ERROR_INTERRUPT, config->lowerTriggerErrorEnable);
    eADC_SetINTE(base, eADC_WATCHDOG_INTERRUPT, config->compIntEnable);

    eADC_DRV_ConfigHwCompareGroup(instance, config->compareConfig, config->eadcCompareCnt);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_ConfigHwCompareGroup
 * Description   : This functions sets the configuration for the Hardware
 * Compare feature using the configuration structure.
 *
 * Implements : eADC_DRV_ConfigHwCompareGroup_Activity
 *END**************************************************************************/
void eADC_DRV_ConfigHwCompareGroup(const uint32_t instance,
                                  eadc_compare_config_t *const config, 
                                  uint8_t count)
{
    DEV_ASSERT(instance < eADC_INSTANCE_COUNT);
    DEV_ASSERT(count <=  FEATURE_EADC_WDG_CHANNEL_COUNT);
    if (count == 0)
    {
        return;
    }
    DEV_ASSERT(config != NULL);

    eADC_Type *const base = s_eadcBase[instance];
    for(uint8_t i = 0; i < count; i ++)
    {
        eADC_SetHwCompareEnableFlag(base, config[i].compareEnable, config[i].comWdchIndex);
        eADC_SetHwCompareRangeEnableFlag(base, config[i].compChalSel, config[i].comWdchIndex);
        eADC_SetHwCompareCompHighValue(base, config[i].compHigh, config[i].comWdchIndex);
        eADC_SetHwCompareCompLowValue(base, config[i].compLow, config[i].comWdchIndex);
        eADC_SetAwdEffectiveMode(base, config[i].effectiveMode, config[i].comWdchIndex);
        /* Only WD0CH has this feature */
        if(config[i].comWdchIndex == 0)
        {
            eADC_SetHwCompareAllEnableFlag(base, config[i].compareAllChannelEnable);
        }
    }
}

/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_Start
 * Description   : This function start the eADC.
 * If software trigger is enabled, eADC will start sequence convert.
 * If hardware trigger is enabled, eADC will wait valid trigger then start 
 * sequence convert.
 *
 * Implements : eADC_DRV_Start_Activity
 *END**************************************************************************/
void eADC_DRV_Start(const uint32_t instance, bool swTrigEnable)
{
    DEV_ASSERT(instance < eADC_INSTANCE_COUNT);

    eADC_Type *const baseAddr = s_eadcBase[instance];

    eADC_Enable(baseAddr);

    if(swTrigEnable)
    {
        eADC_Start(baseAddr);
    }
}

/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_Stop
 * Description   : This function stop the eADC.
 *
 * Implements : eADC_DRV_Stop_Activity
 *END**************************************************************************/
void eADC_DRV_Stop(const uint32_t instance)
{
    DEV_ASSERT(instance < eADC_INSTANCE_COUNT);

    eADC_Type *const baseAddr = s_eadcBase[instance];

    eADC_Stop(baseAddr);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_ConfigSequence
 * Description   : This function sets a control sequence configuration.
 *
 * Configuring any control sequence while it is actively controlling a conversion
 * (sw or hw triggered) will implicitly abort the on-going conversion.
 *
 * Implements : eADC_DRV_ConfigSequence_Activity
 *END**************************************************************************/
void eADC_DRV_ConfigSequence(const uint32_t instance,
                             const eadc_sequence_config_t *const config)
{
    uint8_t i;
    uint8_t highSeqLen, lowSeqLen, tmp;
    DEV_ASSERT(instance < eADC_INSTANCE_COUNT);
    DEV_ASSERT(config != NULL);
    DEV_ASSERT(eADC_CHSEL_COUNT > config->highPrioSequence.totalChannels);
    DEV_ASSERT(eADC_CHSEL_COUNT > config->lowPrioSequence.totalChannels);

    eADC_Type *const base = s_eadcBase[instance];
    /* Stop eADC conversion before re-configuration */
    eADC_Stop(base);

    /* Config sequence max length */
    eADC_SetSeqCfg(base, config->seqLengthMax);
    /* Select which sequence as hardware sequence */
    eADC_SetHighSeqSelect(base, config->highSelect);
    /* Config sequence work mode */
    eADC_SetSeqMode(base, config->sequenceMode);
    /* Get max length for sequence */
    switch (config->seqLengthMax) {
        case eADC_SEQ0_15_SEQ1_1:
            highSeqLen = 15;
            lowSeqLen = 1;
            break;
        case eADC_SEQ0_2_SEQ1_14:
            highSeqLen = 2;
            lowSeqLen = 14;
            break;
        case eADC_SEQ0_4_SEQ1_12:
            highSeqLen = 4;
            lowSeqLen = 12;
            break;
        case eADC_SEQ0_8_SEQ1_8:
            highSeqLen = 8;
            lowSeqLen = 8;
            break;
        default:
            highSeqLen = 0;
            lowSeqLen = 0;
            break;
    }

    if(config->highSelect == eADC_SEQ1_AS_HIGH_PRIORITY_SEQ)
    {
        tmp = highSeqLen;
        highSeqLen = lowSeqLen;
        lowSeqLen = tmp;
    }

    /* Config hardware sequence */
    DEV_ASSERT(config->highPrioSequence.totalChannels <= highSeqLen);
    eADC_SetHighSeqLen(base, config->highPrioSequence.totalChannels);
    for(i = 0; i < highSeqLen; i++)
    {
        eADC_SetSequenceChannel(base, i, config->highPrioSequence.channels[i]);
    }
    eADC_SetINTE(base, eADC_HIGH_PRIORITY_END_OF_SEQUENCE_INTERRUPT, config->highPrioSequence.sequenceIntEnable);
    eADC_SetHighDmaEnable(base, config->highPrioSequence.dmaEnable);

    /* Config software sequence */
    DEV_ASSERT(config->lowPrioSequence.totalChannels <= lowSeqLen);
    eADC_SetSwEnable(base, config->swTriggerEnable);
    eADC_SetLowSeqLen(base, config->lowPrioSequence.totalChannels);
    for(i = highSeqLen; i < eADC_CHSEL_COUNT; i++)
    {
        eADC_SetSequenceChannel(base, i, config->lowPrioSequence.channels[i - highSeqLen]);
    }
    eADC_SetINTE(base, eADC_LOW_PRIORITY_END_OF_SEQUENCE_INTERRUPT, config->lowPrioSequence.sequenceIntEnable);
    eADC_SetLowDmaEnable(base, config->lowPrioSequence.dmaEnable);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_ReadFIFO
 * Description   : This function returns the conversion result from FIFO.
 *
 * Implements : eADC_DRV_ReadFIFO_Activity
 *END**************************************************************************/
uint16_t eADC_DRV_ReadFIFO(const uint32_t instance, uint8_t index)
{
    eADC_Type *const base = s_eadcBase[instance];

    return (eADC_ReadFIFO(base, index));
}

/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_GetEndOfHighSequenceFlag
 * Description   : This function returns the state of the High priority Sequence Conversion 
 * Complete flag for a control channel. This flag is at the end of conversion of a 
 * sequence or the condition generated by the Hardware Compare feature is evaluated to true.
 *
 * Implements : eADC_DRV_GetEndOfHighSequenceFlag_Activity
 *END**************************************************************************/
bool eADC_DRV_GetEndOfHighSequenceFlag(const uint32_t instance)
{
    DEV_ASSERT(instance < eADC_INSTANCE_COUNT);

    eADC_Type *const base = s_eadcBase[instance];

    return (eADC_GetStatus(base, eADC_HIGH_PRIORITY_END_OF_SEQUENCE_FLAG));
}

/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_ClearHighEoseqFlagCmd
 * Description   : This function is used to clear HEOSEQ flag.
 *
 * Implements    : eADC_DRV_ClearHighEoseqFlagCmd_Activity
 *END**************************************************************************/

void eADC_DRV_ClearHighEoseqFlagCmd(const uint32_t instance)
{
    DEV_ASSERT(instance < eADC_INSTANCE_COUNT);

    eADC_Type *const baseAddr = s_eadcBase[instance];

    eADC_ClearStatus(baseAddr, eADC_HIGH_PRIORITY_END_OF_SEQUENCE_FLAG);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_GetEndOfLowSequenceFlag
 * Description   : This function returns the state of the Low Priority Sequence Conversion 
 * Complete flag for a control channel. This flag is at the end of conversion of a 
 * sequence or the condition generated by the Hardware Compare feature is evaluated to true.
 *
 * Implements : eADC_DRV_GetEndOfLowSequenceFlag_Activity
 *END**************************************************************************/
bool eADC_DRV_GetEndOfLowSequenceFlag(const uint32_t instance)
{
    DEV_ASSERT(instance < eADC_INSTANCE_COUNT);

    eADC_Type *const base = s_eadcBase[instance];

    return (eADC_GetStatus(base, eADC_LOW_PRIORITY_END_OF_SEQUENCE_FLAG));
}

/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_ClearLowEoseqFlagCmd
 * Description   : This function is used to clear EOSEQ flag.
 *
 * Implements    : eADC_DRV_ClearLowEoseqFlagCmd_Activity
 *END**************************************************************************/
void eADC_DRV_ClearLowEoseqFlagCmd(const uint32_t instance)
{
    DEV_ASSERT(instance < eADC_INSTANCE_COUNT);

    eADC_Type *const baseAddr = s_eadcBase[instance];

    eADC_ClearStatus(baseAddr, eADC_LOW_PRIORITY_END_OF_SEQUENCE_FLAG);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_GetReadyFlag
 * Description   : This function is used to get ready flag.
 *
 * Implements    : eADC_DRV_GetReadyFlag_Activity
 *END**************************************************************************/
bool eADC_DRV_GetReadyFlag(const uint32_t instance)
{
    DEV_ASSERT(instance < eADC_INSTANCE_COUNT);

    eADC_Type *const base = s_eadcBase[instance];

    return (eADC_GetStatus(base, eADC_READY_FLAG));
}

/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_ClearReadyFlag
 * Description   : This function is used to clear ready flag.
 *
 * Implements    : eADC_DRV_ClearReadyFlag_Activity
 *END**************************************************************************/
void eADC_DRV_ClearReadyFlag(const uint32_t instance)
{
    DEV_ASSERT(instance < eADC_INSTANCE_COUNT);

    eADC_Type *const baseAddr = s_eadcBase[instance];

    eADC_ClearStatus(baseAddr, eADC_READY_FLAG); 
}

/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_GetEndOfSampleFlag
 * Description   : This function is used to get end of sample flag.
 *
 * Implements    : eADC_DRV_GetEndOfSampleFlag_Activity
 *END**************************************************************************/
bool eADC_DRV_GetEndOfSampleFlag(const uint32_t instance)
{
    DEV_ASSERT(instance < eADC_INSTANCE_COUNT);

    eADC_Type *const base = s_eadcBase[instance];

    return (eADC_GetStatus(base, eADC_END_OF_SAMPLING_FLAG));
}

/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_ClearEndOfSampleFlag
 * Description   : This function is used to clear end of sample flag.
 *
 * Implements    : eADC_DRV_ClearEndOfSampleFlag_Activity
 *END**************************************************************************/
void eADC_DRV_ClearEndOfSampleFlag(const uint32_t instance)
{
    DEV_ASSERT(instance < eADC_INSTANCE_COUNT);

    eADC_Type *const baseAddr = s_eadcBase[instance];

    eADC_ClearStatus(baseAddr, eADC_END_OF_SAMPLING_FLAG); 
}

/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_GetEndOfConvertFlag
 * Description   : This function is used to get end of convert flag.
 *
 * Implements    : eADC_DRV_GetEndOfConvertFlag_Activity
 *END**************************************************************************/
bool eADC_DRV_GetEndOfConvertFlag(const uint32_t instance)
{
    DEV_ASSERT(instance < eADC_INSTANCE_COUNT);

    eADC_Type *const base = s_eadcBase[instance];

    return (eADC_GetStatus(base, eADC_END_OF_CONVERSION_FLAG));
}

/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_ClearEndOfConvertFlag
 * Description   : This function is used to clear end of convert flag.
 *
 * Implements    : eADC_DRV_ClearEndOfConvertFlag_Activity
 *END**************************************************************************/
void eADC_DRV_ClearEndOfConvertFlag(const uint32_t instance)
{
    DEV_ASSERT(instance < eADC_INSTANCE_COUNT);

    eADC_Type *const baseAddr = s_eadcBase[instance];

    eADC_ClearStatus(baseAddr, eADC_END_OF_CONVERSION_FLAG); 
}

/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_GetNormalErrorFlag
 * Description   : This function is used to get normal flag.
 *
 * Implements    : eADC_DRV_GetNormalErrorFlag_Activity
 *END**************************************************************************/
bool eADC_DRV_GetNormalErrorFlag(const uint32_t instance)
{
    DEV_ASSERT(instance < eADC_INSTANCE_COUNT);

    eADC_Type *const base = s_eadcBase[instance];

    return (eADC_GetStatus(base, eADC_NORMAL_ERROR_FLAG));
}

/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_ClearNormalErrorFlag
 * Description   : This function is used to clear normal error flag.
 *
 * Implements    : eADC_DRV_ClearNormalErrorFlag_Activity
 *END**************************************************************************/
void eADC_DRV_ClearNormalErrorFlag(const uint32_t instance)
{
    DEV_ASSERT(instance < eADC_INSTANCE_COUNT);

    eADC_Type *const baseAddr = s_eadcBase[instance];

    eADC_ClearStatus(baseAddr, eADC_NORMAL_ERROR_FLAG); 
}

/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_GetLowPrioTriggerErrorFlag
 * Description   : This function is used to get low priority trigger missing flag.
 *
 * Implements    : eADC_DRV_GetLowPrioTriggerErrorFlag_Activity
 *END**************************************************************************/
bool eADC_DRV_GetLowPrioTriggerErrorFlag(const uint32_t instance)
{
    DEV_ASSERT(instance < eADC_INSTANCE_COUNT);

    eADC_Type *const base = s_eadcBase[instance];

    return (eADC_GetStatus(base, eADC_LOW_PRIORITY_TRIGGER_ERROR_FLAG));
}

/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_ClearLowPrioTriggerErrorFlag
 * Description   : This function is used to clear low priority trigger missing flag.
 *
 * Implements    : eADC_DRV_ClearLowPrioTriggerErrorFlag_Activity
 *END**************************************************************************/
void eADC_DRV_ClearLowPrioTriggerErrorFlag(const uint32_t instance)
{
    DEV_ASSERT(instance < eADC_INSTANCE_COUNT);

    eADC_Type *const baseAddr = s_eadcBase[instance];

    eADC_ClearStatus(baseAddr, eADC_LOW_PRIORITY_TRIGGER_ERROR_FLAG); 
}

/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_GetChannelOverrunFlag
 * Description   : This function is used to get overrun flag.
 *
 * Implements    : eADC_DRV_GetChannelOverrunFlag_Activity
 *END**************************************************************************/
bool eADC_DRV_GetChannelOverrunFlag(const uint32_t instance, uint8_t channelIndex)
{
    DEV_ASSERT(instance < eADC_INSTANCE_COUNT);

    eADC_Type *const base = s_eadcBase[instance];

    return (eADC_GetOverrun(base, channelIndex));
}

/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_ClearChannelOverrunFlag
 * Description   : This function is used to clear overrun flag.
 *
 * Implements    : eADC_DRV_ClearChannelOverrunFlag_Activity
 *END**************************************************************************/
void eADC_DRV_ClearChannelOverrunFlag(const uint32_t instance, uint8_t channelIndex)
{
    DEV_ASSERT(instance < eADC_INSTANCE_COUNT);

    eADC_Type *const baseAddr = s_eadcBase[instance];

    eADC_ClearOverrun(baseAddr, channelIndex); 
}

/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_GetWatchDogFlag
 * Description   : This function is used to get analogy watch dog flag.
 *
 * Implements    : eADC_DRV_GetWatchDogFlag_Activity
 *END**************************************************************************/
bool eADC_DRV_GetWatchDogFlag(const uint32_t instance, uint8_t wdgChannel)
{
    DEV_ASSERT(instance < eADC_INSTANCE_COUNT);
    DEV_ASSERT(wdgChannel < FEATURE_EADC_WDG_CHANNEL_COUNT);

    eADC_Type *const base = s_eadcBase[instance];
    uint32_t wdgFlag = (uint32_t)eADC_WATCHDOG0_FLAG + wdgChannel;

    return (eADC_GetStatus(base, (eadc_status_t)wdgFlag));
}

/*FUNCTION**********************************************************************
 *
 * Function Name : eADC_DRV_ClearWatchDogFlag
 * Description   : This function is used to clear analogy watch dog flag.
 *
 * Implements    : eADC_DRV_ClearWatchDogFlag_Activity
 *END**************************************************************************/
void eADC_DRV_ClearWatchDogFlag(const uint32_t instance, uint8_t wdgChannel)
{
    DEV_ASSERT(instance < eADC_INSTANCE_COUNT);
    DEV_ASSERT(wdgChannel < FEATURE_EADC_WDG_CHANNEL_COUNT);

    eADC_Type *const baseAddr = s_eadcBase[instance];
    uint32_t wdgFlag = (uint32_t)eADC_WATCHDOG0_FLAG + wdgChannel;

    eADC_ClearStatus(baseAddr, (eadc_status_t)wdgFlag); 

}




/******************************************************************************
 * EOF
 *****************************************************************************/
