777 lines
21 KiB
C
777 lines
21 KiB
C
/**
|
|
* @file sdrv_adc.c
|
|
* @brief Semidrive ADC driver source file.
|
|
*
|
|
* @copyright Copyright (c) 2021 Semidrive Semiconductor.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <debug.h>
|
|
#include <sdrv_adc.h>
|
|
#include <sdrv_adc_dev_data.h>
|
|
#include <clock_ip.h>
|
|
#include <udelay/udelay.h>
|
|
|
|
|
|
#if CONFIG_E3 || CONFIG_D3
|
|
static uint8_t adc_fifo_read_rcd[3];
|
|
#endif
|
|
|
|
__WEAK const sdrv_adc_dev_data_t sdrv_adc_dev_data_table[] = {
|
|
{APB_ADC1_BASE, CLK_NODE(g_ckgen_ip_adc1), HOST_ADC1_DFLT_OFFSET},
|
|
{APB_ADC2_BASE, CLK_NODE(g_ckgen_ip_adc2), HOST_ADC2_DFLT_OFFSET},
|
|
#ifdef APB_ADC3_BASE
|
|
{APB_ADC3_BASE, CLK_NODE(g_ckgen_ip_adc3), HOST_ADC3_DFLT_OFFSET},
|
|
#endif
|
|
{NULL, NULL}
|
|
};
|
|
|
|
|
|
void sdrv_adc_init(sdrv_adc_t *sdrv_adcX, unsigned int clk_div)
|
|
{
|
|
uint32_t temp;
|
|
uint32_t tmo;
|
|
uint32_t clk_freq;
|
|
unsigned int clk_div_min;
|
|
const sdrv_adc_dev_data_t *p_adc_data;
|
|
int i;
|
|
|
|
ASSERT(sdrv_adcX);
|
|
|
|
p_adc_data = NULL;
|
|
for (i = 0; sdrv_adc_dev_data_table[i].adc_base; i++) {
|
|
if (sdrv_adc_dev_data_table[i].adc_base == (uintptr_t)sdrv_adcX) {
|
|
p_adc_data = &sdrv_adc_dev_data_table[i];
|
|
break;
|
|
}
|
|
}
|
|
if (!p_adc_data) {
|
|
ssdk_printf(SSDK_WARNING, "Make sure ADC %p clock div%d <= 32MHz.\n", sdrv_adcX, clk_div);
|
|
clk_div_min = 1;
|
|
} else {
|
|
/* If p_adc_data->adc_ckgen is NULL, consider clk_div parameter as valid. */
|
|
clk_freq = sdrv_ckgen_get_rate(p_adc_data->adc_ckgen);
|
|
clk_div_min = clk_freq / CLK_MHZ(32);
|
|
if (clk_div_min) {
|
|
if (clk_freq / clk_div_min > CLK_MHZ(32))
|
|
clk_div_min++;
|
|
} else {
|
|
clk_div_min = 1;
|
|
}
|
|
}
|
|
|
|
#if CONFIG_E3 || CONFIG_D3
|
|
sdrv_adcX->ana_ref_cfg2 = 0xFFFFu;
|
|
sdrv_adc2->ana_ref_cfg2 = 0xFFFFu;
|
|
#endif
|
|
|
|
sdrv_adcX->soft_rst |= SADC_SOFT_RST_DIG | SADC_SOFT_RST_RC0TMR |
|
|
SADC_SOFT_RST_RC1TMR | SADC_SOFT_RST_RC2TMR |
|
|
SADC_SOFT_RST_RC3TMR;
|
|
udelay(50);
|
|
|
|
sdrv_adcX->htc = 0;
|
|
for (i = 0; i < SDRV_ADC_RC_CNT; i++) {
|
|
sdrv_adcX->rc[i] = 0;
|
|
}
|
|
for (i = 0; i < SDRV_ADC_MNT_SINGLE_CNT; i++) {
|
|
sdrv_adcX->mnt_thrd_single[i] = SADC_MNT_THRES_MODE_CLOSE;
|
|
}
|
|
sdrv_adcX->mnt_thrd_cont = SADC_MNT_THRES_MODE_CLOSE;
|
|
|
|
sdrv_adcX->sch_cfg = SADC_SCH_CFG_MODE_MASTER | SADC_SCH_CFG_ASYNC_STALL | 0xF;
|
|
|
|
temp = clk_div;
|
|
if (clk_div < clk_div_min)
|
|
clk_div = clk_div_min;
|
|
if (clk_div > SDRV_ADC_CLK_DIV_MAX)
|
|
clk_div = SDRV_ADC_CLK_DIV_MAX;
|
|
else if (clk_div == 3)
|
|
clk_div++;
|
|
|
|
if (clk_div != temp)
|
|
ssdk_printf(SSDK_WARNING, "Round ADC %p clock div %d to %d.\n", sdrv_adcX, temp, clk_div);
|
|
if (clk_div == 1) {
|
|
sdrv_adcX->clk_ctrl = SADC_CLK_CTRL_DIV_BYPASS;
|
|
} else {
|
|
temp = clk_div / 2;
|
|
/* duty cycle in [40%, 50%] */
|
|
sdrv_adcX->clk_ctrl = ((clk_div - temp - 1) << SADC_CLK_CTRL_REFL_POS) |
|
|
((temp - 1) << SADC_CLK_CTRL_REFH_POS);
|
|
}
|
|
|
|
sdrv_adcX->soft_rst = SADC_SOFT_RST_ANA;
|
|
|
|
tmo = SDRV_ADC_POLL_TMO;
|
|
sdrv_adcX->init |= SADC_INIT_START;
|
|
while (!(sdrv_adcX->init & SADC_INIT_DONE) && tmo--);
|
|
|
|
if (p_adc_data) {
|
|
sdrv_adc_set_dc_offset(sdrv_adcX, p_adc_data->dc_offset);
|
|
} else {
|
|
sdrv_adc_set_dc_offset(sdrv_adcX, 0);
|
|
}
|
|
|
|
for (i = 0; i < SDRV_ADC_SUB_FIFO_CNT; i++) {
|
|
sdrv_adcX->sub_fifo[i] &= ~(SADC_SUB_FIFO_SADDR_MSK | SADC_SUB_FIFO_RC_EN_MSK);
|
|
}
|
|
sdrv_adcX->sub_fifo[3] |= SADC_SUB_FIFO_RC_EN_MSK;
|
|
sdrv_adcX->fifo_cfg = SADC_FIFO_CFG_PACK_M_32 << SADC_FIFO_CFG_PACK_M_POS;
|
|
|
|
#if CONFIG_E3 || CONFIG_D3
|
|
if (IS_P1 || !tmo) {
|
|
return;
|
|
}
|
|
|
|
switch ((uintptr_t)sdrv_adcX) {
|
|
case APB_ADC1_BASE:
|
|
i = 0;
|
|
break;
|
|
|
|
case APB_ADC2_BASE:
|
|
i = 1;
|
|
break;
|
|
|
|
#ifdef APB_ADC3_BASE
|
|
case APB_ADC3_BASE:
|
|
i = 2;
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
/* Ignore ADC in slave chip. */
|
|
return;
|
|
}
|
|
|
|
if (!adc_fifo_read_rcd[i]) {
|
|
sdrv_adcX->rc[3] = SADC_RC_TRG_EN | SADC_RC_TRG_MODE_SW;
|
|
sdrv_adcX->sch_cfg &= ~SADC_SCH_CFG_ASYNC_STALL;
|
|
sdrv_adcX->rc_entry[3][0] = 0;
|
|
sdrv_adcX->ana_para[0] = 0;
|
|
|
|
sdrv_adcX->rc[3] |= SADC_RC_SOFT_TRG;
|
|
|
|
tmo = SDRV_ADC_POLL_TMO;
|
|
while ((sdrv_adcX->sub_fifo[3] & SADC_SUB_FIFO_EMPTY) && tmo--);
|
|
sdrv_adcX->fusa_cor_err_int_stat_en = 0;
|
|
sdrv_adcX->fusa_unc_err_int_stat_en = 0;
|
|
sdrv_adcX->fifo[3][0];
|
|
sdrv_adcX->fusa_cor_err_int_stat_en = 0xFFFFFFFFu;
|
|
sdrv_adcX->fusa_unc_err_int_stat_en = 0xFFFFFFFFu;
|
|
|
|
sdrv_adcX->rc[3] = 0;
|
|
sdrv_adcX->sch_cfg |= SADC_SCH_CFG_ASYNC_STALL;
|
|
|
|
adc_fifo_read_rcd[i] = 1;
|
|
}
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
void sdrv_adc_set_dc_offset(sdrv_adc_t *sdrv_adcX, int16_t offset)
|
|
{
|
|
uint32_t temp;
|
|
|
|
ASSERT(sdrv_adcX);
|
|
|
|
if (offset) {
|
|
temp = sdrv_adcX->dcoc;
|
|
temp &= ~(SADC_DCOC_EN | SADC_DCOC_VALUE_MSK | SADC_DCOC_VALUE_SIGN);
|
|
if (offset > 0) {
|
|
temp |= ((uint32_t)offset << SADC_DCOC_VALUE_POS) & SADC_DCOC_VALUE_MSK;
|
|
} else {
|
|
temp |= ((uint32_t)(-offset) << SADC_DCOC_VALUE_POS) & SADC_DCOC_VALUE_MSK;
|
|
temp |= SADC_DCOC_VALUE_SIGN;
|
|
}
|
|
temp |= SADC_DCOC_OVWR;
|
|
sdrv_adcX->dcoc = temp;
|
|
|
|
sdrv_adcX->dcoc |= SADC_DCOC_EN;
|
|
} else {
|
|
sdrv_adcX->dcoc &= ~SADC_DCOC_EN;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
int16_t sdrv_adc_get_dc_offset(sdrv_adc_t *sdrv_adcX)
|
|
{
|
|
uint32_t temp;
|
|
bool sign;
|
|
|
|
ASSERT(sdrv_adcX);
|
|
|
|
temp = sdrv_adcX->dcoc;
|
|
if (temp & SADC_DCOC_EN) {
|
|
sign = !!(temp & SADC_DCOC_VALUE_SIGN);
|
|
temp = (temp & SADC_DCOC_VALUE_MSK) >> SADC_DCOC_VALUE_POS;
|
|
if (sign) {
|
|
return -temp;
|
|
} else {
|
|
return temp;
|
|
}
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void sdrv_adc_set_slave_mode(sdrv_adc_t *sdrv_adcX)
|
|
{
|
|
ASSERT(sdrv_adcX);
|
|
ASSERT(sdrv_adcX != sdrv_adc1);
|
|
|
|
sdrv_adcX->sch_cfg &= ~SADC_SCH_CFG_MODE_MASTER;
|
|
return;
|
|
}
|
|
|
|
void sdrv_adc_clr_slave_mode(sdrv_adc_t *sdrv_adcX)
|
|
{
|
|
ASSERT(sdrv_adcX);
|
|
|
|
sdrv_adcX->sch_cfg |= SADC_SCH_CFG_MODE_MASTER;
|
|
return;
|
|
}
|
|
|
|
uint32_t sdrv_adc_read_int_status(sdrv_adc_t *sdrv_adcX)
|
|
{
|
|
ASSERT(sdrv_adcX);
|
|
|
|
return sdrv_adcX->int_stat;
|
|
}
|
|
|
|
void sdrv_adc_clear_int_status(sdrv_adc_t *sdrv_adcX, uint32_t int_bits)
|
|
{
|
|
ASSERT(sdrv_adcX);
|
|
|
|
sdrv_adcX->int_stat = int_bits;
|
|
return;
|
|
}
|
|
|
|
void sdrv_adc_int_status_en_cfg(sdrv_adc_t *sdrv_adcX, uint32_t int_bits, bool enable)
|
|
{
|
|
ASSERT(sdrv_adcX);
|
|
|
|
if (enable) {
|
|
sdrv_adcX->int_stat_en |= int_bits;
|
|
} else {
|
|
sdrv_adcX->int_stat_en &= ~int_bits;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void sdrv_adc_int_status_sig_en_cfg(sdrv_adc_t *sdrv_adcX, uint32_t int_bits, bool enable)
|
|
{
|
|
ASSERT(sdrv_adcX);
|
|
|
|
if (enable) {
|
|
sdrv_adcX->int_sig_en |= int_bits;
|
|
} else {
|
|
sdrv_adcX->int_sig_en &= ~int_bits;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void sdrv_adc_rc_cfg(sdrv_adc_t *sdrv_adcX, unsigned int rc_nbr, sdrv_adc_rc_cfg_t *rc_cfg)
|
|
{
|
|
uint32_t temp;
|
|
uint32_t terminal;
|
|
uint32_t compare;
|
|
|
|
ASSERT(sdrv_adcX);
|
|
ASSERT(rc_nbr < SDRV_ADC_RC_CNT);
|
|
ASSERT(rc_cfg);
|
|
ASSERT(rc_nbr || (rc_cfg->tmr_mode != SDRV_ADC_RC_TMR_MODE_SLAVE));
|
|
|
|
/* Avoid reg parity issue. */
|
|
terminal = (rc_cfg->terminal < SADC_RC_TIMER_TERMINAL_MIN) ?
|
|
SADC_RC_TIMER_TERMINAL_MIN : rc_cfg->terminal;
|
|
compare = rc_cfg->compare ? rc_cfg->compare : SADC_RC_TIMER_COMPARE_MIN;
|
|
sdrv_adcX->rc_timer[rc_nbr] = (terminal << SADC_RC_TIMER_TERMINAL_POS) |
|
|
(compare << SADC_RC_TIMER_COMPARE_POS);
|
|
|
|
temp = rc_cfg->q_cur << SADC_RC_Q_CUR_POS | SADC_RC_OVWR_CUR_EN;
|
|
temp |= rc_cfg->q_start << SADC_RC_Q_START_POS;
|
|
temp |= rc_cfg->q_end << SADC_RC_Q_END_POS;
|
|
if (rc_cfg->tmr_mode == SDRV_ADC_RC_TMR_MODE_SLAVE) {
|
|
temp |= SADC_RC_TMR_SLAVE;
|
|
}
|
|
if (rc_cfg->trg_mode == SDRV_ADC_RC_TRG_MODE_SW) {
|
|
temp |= SADC_RC_TRG_MODE_SW;
|
|
}
|
|
if (rc_cfg->trg_en) {
|
|
temp |= SADC_RC_TRG_EN;
|
|
}
|
|
sdrv_adcX->rc[rc_nbr] = temp;
|
|
|
|
return;
|
|
}
|
|
|
|
void sdrv_adc_rc_start_tmr(sdrv_adc_t *sdrv_adcX, unsigned int rc_nbr)
|
|
{
|
|
ASSERT(sdrv_adcX);
|
|
ASSERT(rc_nbr < SDRV_ADC_RC_CNT);
|
|
|
|
sdrv_adcX->rc[rc_nbr] |= SADC_RC_TRG_START;
|
|
return;
|
|
}
|
|
|
|
void sdrv_adc_rc_start_timers(sdrv_adc_t *sdrv_adcX, sdrv_adc_rc_start_flag_t rc_flags)
|
|
{
|
|
int i;
|
|
uint32_t reset_rc_tmr;
|
|
|
|
ASSERT(sdrv_adcX);
|
|
|
|
reset_rc_tmr = (rc_flags & SDRV_ADC_START_ALL) << SADC_SOFT_RST_RC_POS;
|
|
sdrv_adcX->soft_rst |= reset_rc_tmr;
|
|
|
|
for (i = 0; i < SDRV_ADC_RC_CNT; i++) {
|
|
if (rc_flags & (1u << i)) {
|
|
sdrv_adcX->rc[i] |= SADC_RC_TRG_START;
|
|
}
|
|
}
|
|
|
|
sdrv_adcX->soft_rst &= ~reset_rc_tmr;
|
|
|
|
return;
|
|
}
|
|
|
|
void sdrv_adc_rc_stop_tmr(sdrv_adc_t *sdrv_adcX, unsigned int rc_nbr)
|
|
{
|
|
uint32_t reset_rc_tmr;
|
|
|
|
ASSERT(sdrv_adcX);
|
|
ASSERT(rc_nbr < SDRV_ADC_RC_CNT);
|
|
|
|
switch (rc_nbr) {
|
|
case 0:
|
|
reset_rc_tmr = SADC_SOFT_RST_RC0TMR;
|
|
break;
|
|
|
|
case 1:
|
|
reset_rc_tmr = SADC_SOFT_RST_RC1TMR;
|
|
break;
|
|
|
|
case 2:
|
|
reset_rc_tmr = SADC_SOFT_RST_RC2TMR;
|
|
break;
|
|
|
|
case 3:
|
|
reset_rc_tmr = SADC_SOFT_RST_RC3TMR;
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
|
|
sdrv_adcX->soft_rst |= reset_rc_tmr;
|
|
|
|
sdrv_adcX->rc[rc_nbr] &= ~SADC_RC_TRG_START;
|
|
|
|
sdrv_adcX->soft_rst &= ~reset_rc_tmr;
|
|
|
|
return;
|
|
}
|
|
|
|
void sdrv_adc_rc_soft_trg(sdrv_adc_t *sdrv_adcX, unsigned int rc_nbr)
|
|
{
|
|
uint32_t tmo;
|
|
|
|
ASSERT(sdrv_adcX);
|
|
ASSERT(rc_nbr < SDRV_ADC_RC_CNT);
|
|
|
|
tmo = SDRV_ADC_POLL_TMO;
|
|
while ((sdrv_adcX->rc[rc_nbr] & SADC_RC_SOFT_TRG) && tmo--);
|
|
sdrv_adcX->rc[rc_nbr] |= SADC_RC_SOFT_TRG;
|
|
|
|
return;
|
|
}
|
|
|
|
void sdrv_adc_rcht_ready(sdrv_adc_t *sdrv_adcX, uint8_t ready_len)
|
|
{
|
|
ASSERT(sdrv_adcX);
|
|
|
|
sdrv_adcX->htc = (ready_len << SADC_HTC_READY_LEN_POS) |
|
|
SADC_HTC_READY;
|
|
return;
|
|
}
|
|
|
|
void sdrv_adc_rcht_clr_ready(sdrv_adc_t *sdrv_adcX)
|
|
{
|
|
ASSERT(sdrv_adcX);
|
|
|
|
sdrv_adcX->htc &= ~SADC_HTC_READY;
|
|
return;
|
|
}
|
|
|
|
void sdrv_adc_rcht_entry_cfg(sdrv_adc_t *sdrv_adcX,
|
|
unsigned int entry_nbr,
|
|
sdrv_adc_rcht_entry_cfg_t entry_cfg)
|
|
{
|
|
uint32_t temp;
|
|
|
|
ASSERT(sdrv_adcX);
|
|
ASSERT(entry_nbr < SDRV_ADC_RCHT_ENTRY_CNT);
|
|
|
|
temp = entry_cfg.channel |
|
|
(entry_cfg.cfg_sel << SADC_RCHT_ENTRY_CSEL_POS) |
|
|
(entry_cfg.repeat_cnt << SADC_RCHT_ENTRY_RPT_CNT_POS);
|
|
temp |= SADC_RCHT_ENTRY_RPT_MODE;
|
|
sdrv_adcX->rcht_entry[entry_nbr] = temp;
|
|
return;
|
|
}
|
|
|
|
void sdrv_adc_rc_entry_cfg( sdrv_adc_t *sdrv_adcX,
|
|
unsigned int rc_nbr,
|
|
unsigned int entry_nbr,
|
|
sdrv_adc_rc_entry_cfg_t entry_cfg)
|
|
{
|
|
uint32_t temp;
|
|
|
|
ASSERT(sdrv_adcX);
|
|
ASSERT(rc_nbr < SDRV_ADC_RC_CNT);
|
|
ASSERT(entry_nbr < SDRV_ADC_RC_ENTRY_CNT);
|
|
|
|
if (entry_cfg.repeat_cnt > 16) {
|
|
entry_cfg.repeat_cnt = 16;
|
|
} else if (entry_cfg.repeat_cnt == 0) {
|
|
entry_cfg.repeat_cnt = 1;
|
|
}
|
|
temp = entry_cfg.channel |
|
|
(entry_cfg.cfg_sel << SADC_RC_ENTRY_CSEL_POS) |
|
|
((entry_cfg.repeat_cnt - 1) << SADC_RC_ENTRY_RPT_CNT_POS);
|
|
if (entry_cfg.repeat_mode != SDRV_ADC_RC_REPM_HW_TRG) {
|
|
temp |= SADC_RC_ENTRY_RPT_MODE;
|
|
}
|
|
sdrv_adcX->rc_entry[rc_nbr][entry_nbr] = temp;
|
|
return;
|
|
}
|
|
|
|
void sdrv_adc_ana_param_cfg(sdrv_adc_t *sdrv_adcX,
|
|
unsigned int param_nbr,
|
|
sdrv_adc_ana_param_cfg_t aparam_cfg)
|
|
{
|
|
uint32_t temp;
|
|
|
|
ASSERT(sdrv_adcX);
|
|
ASSERT(param_nbr < SDRV_ADC_ANA_PARAM_CNT);
|
|
|
|
temp = sdrv_adcX->ana_para[param_nbr] &
|
|
~(SADC_ANA_PARAM_SAMCTRL_MSK | SADC_ANA_PARAM_REF_SEL | SADC_ANA_PARAM_DIFF_SEL);
|
|
temp |= aparam_cfg.sample_time << SADC_ANA_PARAM_SAMCTRL_POS;
|
|
if (aparam_cfg.ref_sel) {
|
|
temp |= SADC_ANA_PARAM_REF_SEL;
|
|
}
|
|
if (aparam_cfg.input_mode) {
|
|
temp |= SADC_ANA_PARAM_DIFF_SEL;
|
|
}
|
|
sdrv_adcX->ana_para[param_nbr] = temp;
|
|
return;
|
|
}
|
|
|
|
void sdrv_adc_fifo_cfg(sdrv_adc_t *sdrv_adcX, sdrv_adc_fifo_cfg_t *fifo_cfg)
|
|
{
|
|
uint32_t temp;
|
|
|
|
ASSERT(sdrv_adcX);
|
|
ASSERT(fifo_cfg);
|
|
|
|
if (fifo_cfg->bypass) {
|
|
sdrv_adcX->fifo_cfg |= SADC_FIFO_CFG_BYPASS;
|
|
return;
|
|
}
|
|
|
|
temp = fifo_cfg->pack_mode << SADC_FIFO_CFG_PACK_M_POS;
|
|
if (fifo_cfg->pack16_chnl) {
|
|
temp |= SADC_FIFO_CFG_PACK16_AMSEL;
|
|
}
|
|
sdrv_adcX->fifo_cfg = temp;
|
|
|
|
temp = sdrv_adcX->sub_fifo[3];
|
|
temp &= ~SADC_SUB_FIFO_THRES_MSK;
|
|
temp |= fifo_cfg->threshold << SADC_SUB_FIFO_THRES_POS;
|
|
sdrv_adcX->sub_fifo[3] = temp;
|
|
|
|
return;
|
|
}
|
|
|
|
void sdrv_adc_fifo_rc_cfg(sdrv_adc_t *sdrv_adcX, sdrv_adc_fifo_rc_cfg_t rc_cfg)
|
|
{
|
|
uint32_t temp;
|
|
|
|
ASSERT(sdrv_adcX);
|
|
|
|
temp = sdrv_adcX->sub_fifo[3];
|
|
temp &= ~SADC_SUB_FIFO_RC_EN_MSK;
|
|
temp |= rc_cfg << SADC_SUB_FIFO_RC_EN_POS;
|
|
sdrv_adcX->sub_fifo[3] = temp;
|
|
|
|
return;
|
|
}
|
|
|
|
uint32_t sdrv_adc_fifo_status(sdrv_adc_t *sdrv_adcX)
|
|
{
|
|
ASSERT(sdrv_adcX);
|
|
|
|
return (sdrv_adcX->sub_fifo[3] & (SADC_SUB_FIFO_EMPTY | SADC_SUB_FIFO_FULL));
|
|
}
|
|
|
|
uint32_t sdrv_adc_read_fifo(sdrv_adc_t *sdrv_adcX)
|
|
{
|
|
ASSERT(sdrv_adcX);
|
|
|
|
return sdrv_adcX->fifo[3][0];
|
|
}
|
|
|
|
uintptr_t sdrv_adc_fifo_addr(sdrv_adc_t *sdrv_adcX)
|
|
{
|
|
ASSERT(sdrv_adcX);
|
|
|
|
return (uintptr_t)&sdrv_adcX->fifo[3][0];
|
|
}
|
|
|
|
void sdrv_adc_dma_enable(sdrv_adc_t *sdrv_adcX, sdrv_adc_dma_src_cfg_t req_src)
|
|
{
|
|
ASSERT(sdrv_adcX);
|
|
ASSERT((unsigned int)req_src <= SDRV_ADC_DMA_SRC_RCHT);
|
|
|
|
switch (req_src) {
|
|
case SDRV_ADC_DMA_SRC_FIFO:
|
|
sdrv_adcX->dma_cfg = SADC_DMA_CH0EN_F3RC3 | SADC_DMA_MODE_FIFO3;
|
|
break;
|
|
|
|
case SDRV_ADC_DMA_SRC_RC0:
|
|
sdrv_adcX->dma_cfg = SADC_DMA_CH0EN_F0RC0;
|
|
break;
|
|
|
|
case SDRV_ADC_DMA_SRC_RC1:
|
|
sdrv_adcX->dma_cfg = SADC_DMA_CH0EN_F1RC1;
|
|
break;
|
|
|
|
case SDRV_ADC_DMA_SRC_RC2:
|
|
sdrv_adcX->dma_cfg = SADC_DMA_CH0EN_F2RC2;
|
|
break;
|
|
|
|
case SDRV_ADC_DMA_SRC_RC3:
|
|
sdrv_adcX->dma_cfg = SADC_DMA_CH0EN_F3RC3;
|
|
break;
|
|
|
|
case SDRV_ADC_DMA_SRC_RCHT:
|
|
sdrv_adcX->dma_cfg = SADC_DMA_CH0EN_RCHT;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void sdrv_adc_dma_disable(sdrv_adc_t *sdrv_adcX)
|
|
{
|
|
ASSERT(sdrv_adcX);
|
|
|
|
sdrv_adcX->dma_cfg = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
void sdrv_adc_sync_cfg( sdrv_adc_t *sdrv_adcX,
|
|
sdrv_adc_sync_cfg_t sync_cfg,
|
|
uint8_t *slot_cid,
|
|
unsigned int len)
|
|
{
|
|
uint8_t cid_buf[SADC_SCH_CID_CNT];
|
|
unsigned int cid_fill_cnt;
|
|
uint32_t temp, temp_ctrl;
|
|
uint32_t interval;
|
|
uint32_t clk_div;
|
|
int i, j;
|
|
|
|
ASSERT(sdrv_adcX);
|
|
ASSERT(slot_cid && len);
|
|
/* slot0 should not be 4, 5, 7. */
|
|
ASSERT((slot_cid[0] & SADC_SCH_CID_MSK) != SDRV_ADC_SYNC_CID_MERGE);
|
|
ASSERT(((slot_cid[0] & SADC_SCH_CID_MSK) != SDRV_ADC_SYNC_CID_RCHT) ||
|
|
/* slot_cid[0] won't be copied to slot0 under the following situation. */
|
|
(!sync_cfg.itvl_const && (len < SADC_SCH_CID_CNT)));
|
|
|
|
sdrv_adcX->sch_cfg &= ~SADC_SCH_CFG_ROT_EN;
|
|
sdrv_adcX->sch_cfg |= SADC_SCH_CFG_MODE_SYNC;
|
|
|
|
if (len > SADC_SCH_CID_CNT) {
|
|
len = SADC_SCH_CID_CNT;
|
|
}
|
|
|
|
for (i = 0; i < len; i++) {
|
|
cid_buf[i] = slot_cid[i] & SADC_SCH_CID_MSK;
|
|
}
|
|
|
|
if (len == SADC_SCH_CID_CNT) {
|
|
/* User set all slots manually. Nothing more to do. */
|
|
} else if (sync_cfg.itvl_const) {
|
|
cid_fill_cnt = SADC_SCH_CID_CNT % len;
|
|
if (cid_fill_cnt) {
|
|
/* check whether the input CID sequence consists of the same CID. */
|
|
for (i = 1; i < len; i++) {
|
|
if (cid_buf[i] != cid_buf[0])
|
|
break;
|
|
}
|
|
|
|
/* If so, copy the same CID to all 64 CID slots. */
|
|
if (i == len) {
|
|
len = 1;
|
|
cid_fill_cnt = 0;
|
|
}
|
|
}
|
|
|
|
/* Copy the input CID sequence to CID slots circularly.
|
|
The last cid_fill_cnt slots could be filled with CID 7.*/
|
|
for (i = len; i < SADC_SCH_CID_CNT - cid_fill_cnt; i++) {
|
|
cid_buf[i] = cid_buf[i - len];
|
|
}
|
|
|
|
if (cid_fill_cnt) {
|
|
/* Find the place where CID 7 could be inserted. */
|
|
cid_buf[SADC_SCH_CID_CNT - cid_fill_cnt] = cid_buf[0];
|
|
for (j = len - 1; j >= 0; j--) {
|
|
/* 7 is not allowed to be before 4 or 5. */
|
|
if ((cid_buf[j + 1] != SDRV_ADC_SYNC_CID_RCHT) &&
|
|
(cid_buf[j + 1] != SDRV_ADC_SYNC_CID_MERGE)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Fill the last cid_fill_cnt slots with CID 7. */
|
|
for (i = SADC_SCH_CID_CNT - cid_fill_cnt; i < SADC_SCH_CID_CNT; i++) {
|
|
cid_buf[i] = SADC_SCH_CID_MV_NEXT;
|
|
}
|
|
|
|
if (j < 0) {
|
|
/* If the place for CID 7 isnot found, change the last slot to CID 6. */
|
|
cid_buf[SADC_SCH_CID_CNT - 1] = SDRV_ADC_SYNC_CID_IDLE;
|
|
} else {
|
|
/* Move the CIDs after the place to the end of the 64 slots. */
|
|
for (i = len - 1; i > j; i--) {
|
|
cid_buf[SADC_SCH_CID_CNT - (len - i)] = cid_buf[i];
|
|
cid_buf[SADC_SCH_CID_CNT - cid_fill_cnt - (len - i)] = SADC_SCH_CID_MV_NEXT;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
/* slot0 must be 6 in non-const mode. */
|
|
cid_buf[0] = SDRV_ADC_SYNC_CID_IDLE;
|
|
cid_fill_cnt = (SADC_SCH_CID_CNT - 1) % len;
|
|
/* Copy the input CID sequence to CID slots circularly. */
|
|
for (i = 1; i < SADC_SCH_CID_CNT - cid_fill_cnt; i++) {
|
|
cid_buf[i] = slot_cid[(i - 1) % len];
|
|
}
|
|
/* Fill the last cid_fill_cnt slots with CID 7. */
|
|
for (; i < SADC_SCH_CID_CNT; i++) {
|
|
cid_buf[i] = SADC_SCH_CID_MV_NEXT;
|
|
}
|
|
}
|
|
|
|
/* Convert the slot sequence from 8-bit buffer to 8*4-bit register. */
|
|
for (i = 0; i < SDRV_ADC_CID_PART_CNT; i++) {
|
|
temp = 0;
|
|
for (j = SADC_SCH_CID_CNT_PER_REG - 1; j >= 0; j--) {
|
|
temp = (temp << SADC_SCH_CID_WIDTH_BIT) | cid_buf[i * SADC_SCH_CID_CNT_PER_REG + j];
|
|
}
|
|
sdrv_adcX->sch_cid_part[i] = temp;
|
|
}
|
|
|
|
interval = sync_cfg.slot_itvl ? sync_cfg.slot_itvl : 256;
|
|
temp = sdrv_adcX->sch_cfg;
|
|
temp &= ~SADC_SCH_CFG_SLOT_ITVL_MSK;
|
|
if (sync_cfg.itvl_const) {
|
|
temp |= SADC_SCH_CFG_SLOT_CONST;
|
|
temp |= (interval - 1) << SADC_SCH_CFG_SLOT_ITVL_POS;
|
|
} else {
|
|
temp &= ~SADC_SCH_CFG_SLOT_CONST;
|
|
temp |= 1u << SADC_SCH_CFG_SLOT_ITVL_POS; /* Let slot0 consume the least time. */
|
|
temp_ctrl = sdrv_adcX->clk_ctrl;
|
|
clk_div = 2;
|
|
clk_div += (temp_ctrl & SADC_CLK_CTRL_REFH_MSK) >> SADC_CLK_CTRL_REFH_POS;
|
|
clk_div += (temp_ctrl & SADC_CLK_CTRL_REFL_MSK) >> SADC_CLK_CTRL_REFL_POS;
|
|
sdrv_adcX->sch_tmo = interval * clk_div;
|
|
}
|
|
sdrv_adcX->sch_cfg = temp;
|
|
|
|
return;
|
|
}
|
|
|
|
void sdrv_adc_sync_start(sdrv_adc_t *sdrv_adcX)
|
|
{
|
|
ASSERT(sdrv_adcX);
|
|
|
|
sdrv_adcX->sch_cfg |= SADC_SCH_CFG_ROT_EN;
|
|
return;
|
|
}
|
|
|
|
void sdrv_adc_Async_start(sdrv_adc_t *sdrv_adcX)
|
|
{
|
|
ASSERT(sdrv_adcX);
|
|
|
|
sdrv_adcX->sch_cfg &= ~SADC_SCH_CFG_ASYNC_STALL;
|
|
return;
|
|
}
|
|
|
|
void sdrv_adc_sync_slot_reset(sdrv_adc_t *sdrv_adcX)
|
|
{
|
|
uint32_t tmo;
|
|
|
|
ASSERT(sdrv_adcX);
|
|
|
|
tmo = SDRV_ADC_POLL_TMO;
|
|
sdrv_adcX->sch_cfg |= SADC_SCH_CFG_SLOT_RST;
|
|
while (!(sdrv_adcX->sch_cfg & SADC_SCH_CFG_RST_DONE) && tmo--);
|
|
sdrv_adcX->sch_cfg &= ~SADC_SCH_CFG_SLOT_RST;
|
|
return;
|
|
}
|
|
|
|
void sdrv_adc_stop(sdrv_adc_t *sdrv_adcX, bool rc_tmr_stop)
|
|
{
|
|
uint32_t temp;
|
|
int i;
|
|
|
|
ASSERT(sdrv_adcX);
|
|
|
|
if (rc_tmr_stop) {
|
|
sdrv_adcX->soft_rst |= SADC_SOFT_RST_RC0TMR | SADC_SOFT_RST_RC1TMR |
|
|
SADC_SOFT_RST_RC2TMR | SADC_SOFT_RST_RC3TMR;
|
|
|
|
for (i = 0; i < SDRV_ADC_RC_CNT; i++) {
|
|
sdrv_adcX->rc[i] &= ~SADC_RC_TRG_START;
|
|
}
|
|
|
|
sdrv_adcX->soft_rst &= ~(SADC_SOFT_RST_RC0TMR | SADC_SOFT_RST_RC1TMR |
|
|
SADC_SOFT_RST_RC2TMR | SADC_SOFT_RST_RC3TMR);
|
|
}
|
|
|
|
temp = sdrv_adcX->sch_cfg;
|
|
if (temp & SADC_SCH_CFG_MODE_SYNC) {
|
|
temp &= ~SADC_SCH_CFG_ROT_EN;
|
|
} else {
|
|
temp |= SADC_SCH_CFG_ASYNC_STALL;
|
|
}
|
|
sdrv_adcX->sch_cfg = temp;
|
|
|
|
return;
|
|
}
|
|
|
|
void sdrv_adc_power_ctrl(sdrv_adc_t *sdrv_adcX, bool down)
|
|
{
|
|
ASSERT(sdrv_adcX);
|
|
|
|
if (down) {
|
|
sdrv_adcX->ana_ref_cfg1 |= (SADC_ANA_REF_PART1_PD | SADC_ANA_REF_PART1_PDBISA);
|
|
}
|
|
else {
|
|
sdrv_adcX->ana_ref_cfg1 &= ~SADC_ANA_REF_PART1_PD;
|
|
sdrv_adcX->ana_ref_cfg1 &= ~SADC_ANA_REF_PART1_PDBISA;
|
|
}
|
|
}
|