/*
 * Copyright 2020-2024 Yuntu Microelectronics co.,ltd
 * All rights reserved.
 *
 * YUNTU Confidential. This software is owned or controlled by YUNTU and may
 * only be used strictly in accordance with the applicable license terms. By expressly
 * accepting such terms or by downloading, installing, activating and/or otherwise
 * using the software, you are agreeing that you have read, and that you agree to
 * comply with and are bound by, such license terms. If you do not agree to be
 * bound by the applicable license terms, then you may not retain, install,
 * activate or otherwise use the software. The production use license in
 * Section 2.3 is expressly granted for this software.
 */
/*!
 * @file hw_adc.c
 */

 #include <stdint.h>
 #include <stddef.h>
 #include "hw_adc.h"
 #include "device_registers.h"
 #include "status.h"
 #include "interrupt_manager.h"
 
 /*******************************************************************************
  * Definitions
  ******************************************************************************/

void HW_SetupAdcSeqMode(const uint8_t *channels, uint8_t channel_cnt, const isr_t adcISR)
{
    ADC_Type *base = ADC0;
    /* Reset adc module */
    IPC->CTRL[IPC_ADC0_INDEX] |= IPC_CTRL_SWREN(1);
    IPC->CTRL[IPC_ADC0_INDEX] &= ~IPC_CTRL_SWREN_MASK;

    /* Setup adc configuration */
    base->CFG0 = ((channel_cnt - 1) & 0xFU) << ADC_CFG0_SEQLEN_SHIFT |   /* Sequence length */
                 ADC_CFG0_CONVMD(0U) |                                     /* Enable single mode */
                 ADC_CFG0_TRIGMD(1U);                                    /* Hardware trigger mode */

    base->CFG1 = ADC_CFG1_STCNT(32U) | ADC_CFG1_PRS(1);                  /* Start time count */
    base->SMP = ADC_SMP_SMP(4U);                                         /* Sample time */
    for (int i = 0; i < channel_cnt; i++)
    {
        base->CHSEL[i] = ADC_CHSEL_CHSEL(channels[i]);                   /* Setup channel */
    }
    base->INTE = ADC_INTE_EOSEQIE(1U);                                   /* Enable end of sequence interrupt */
    INT_SYS_InstallHandler(ADC0_IRQn, adcISR, NULL);
    INT_SYS_EnableIRQ(ADC0_IRQn);
    base->CTRL = ADC_CTRL_TSEN(1U) |                                     /* Enable temperature sensor */
                 ADC_CTRL_ADEN(1U);                                      /* Enable ADC */
    base->CTRL |= ADC_CTRL_ADSTART(1U);                                  /* Start ADC */
    while(!(base->STS & ADC_STS_ADRDY_MASK));                           /* Wait for ADC ready */
}

void HW_SetupAdcSeq1Mode(const uint8_t *channels, uint8_t channel_cnt, const isr_t adcISR)
{    
    ADC_Type *base = ADC0;

    /* Setup adc configuration */
    base->CFG0 = ((channel_cnt - 1) & 0xFU) << ADC_CFG0_SEQLEN_SHIFT |   /* Sequence length */
                 ADC_CFG0_CONVMD(2U) |                                     /* Enable single mode */
                 ADC_CFG0_TRIGMD(1U);                                    /* Hardware trigger mode */

    base->CFG1 = ADC_CFG1_STCNT(32U) | ADC_CFG1_PRS(0);                   /* Start time count */
    base->SMP = ADC_SMP_SMP(1U);                                         /* Sample time */

        /* Configure sequence 0 channels for current sensing */
    ADC0->CHSEL[0] = ADC_CHSEL_CHSEL(ADC_V_PHASE_CHANNEL);
    ADC0->CHSEL[1] = ADC_CHSEL_CHSEL(ADC_V_PHASE_CHANNEL);

    base->INTE = ADC_INTE_EOSEQIE(1U);                                     /* Enable end of sequence interrupt */
    INT_SYS_InstallHandler(ADC0_IRQn, adcISR, NULL);
    INT_SYS_EnableIRQ(ADC0_IRQn);
    base->CTRL = ADC_CTRL_ADEN(1U);                                      /* Enable ADC */
    base->CTRL |= ADC_CTRL_ADSTART(1U);                                  /* Start ADC */
    while(!(base->STS & ADC_STS_ADRDY_MASK));                            /* Wait for ADC ready */
}

void HW_SetupAdcSeq2Mode(const uint8_t *channels, uint8_t channel_cnt, const isr_t adcISR)
{    
    ADC_Type *base = ADC0;

    /* Setup adc configuration */
    base->CFG0 = ((channel_cnt - 1) & 0xFU) << ADC_CFG0_SEQLEN_SHIFT |   /* Sequence length */
                 ADC_CFG0_CONVMD(0U) |                                     /* Enable single mode */
                 ADC_CFG0_TRIGMD(0U);                                    /* Hardware trigger mode */

    base->CFG1 = ADC_CFG1_STCNT(32U) | ADC_CFG1_PRS(0);                 /* Start time count */
    base->SMP = ADC_SMP_SMP(16U);                                         /* Sample time */
    for (int i = 0; i < channel_cnt; i++)
    {
        base->CHSEL[i] = ADC_CHSEL_CHSEL(channels[i]);                   /* Setup channel */
    }
    base->INTE = ADC_INTE_EOSEQIE(1U);                                   /* Enable end of sequence interrupt */
    INT_SYS_InstallHandler(ADC0_IRQn, adcISR, NULL);
    INT_SYS_EnableIRQ(ADC0_IRQn);
    base->CTRL = ADC_CTRL_TSEN(1U) |                                     /* Enable temperature sensor */
                 ADC_CTRL_ADEN(1U);                                      /* Enable ADC */
    base->CTRL |= ADC_CTRL_ADSTART(1U);                                  /* Start ADC */
    while(!(base->STS & ADC_STS_ADRDY_MASK));                           /* Wait for ADC ready */
}

void HW_DeinitADC(void)
{
    /* Stop ADC */
    ADC0->CTRL = ADC_CTRL_ADSTOP_MASK;
    /* Disable ADC interrupt */
    ADC0->INTE = 0U;
    INT_SYS_DisableIRQ(ADC0_IRQn);
    /* Reset ADC register */
    IPC->CTRL[IPC_ADC0_INDEX] |= IPC_CTRL_SWREN(1);
    IPC->CTRL[IPC_ADC0_INDEX] &= ~IPC_CTRL_SWREN_MASK;
}
