AC63_BT_SDK/cpu/br25/adc_api.c
2025-02-18 15:40:42 +08:00

772 lines
18 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "typedef.h"
#include "asm/clock.h"
#include "asm/adc_api.h"
#include "timer.h"
#include "init.h"
#include "asm/efuse.h"
#include "irq.h"
#include "asm/power/p33.h"
#include "asm/power_interface.h"
#include "jiffies.h"
static volatile u16 _adc_res;
static volatile u16 cur_ch_value;
static u8 cur_ch = 0;
struct adc_info_t {
u32 ch;
u16 value;
u32 jiffies;
u32 sample_period;
};
void set_change_vbg_value_flag(void);
#define ENABLE_OCCUPY_MODE 1
static struct adc_info_t adc_queue[ADC_MAX_CH + ENABLE_OCCUPY_MODE];
static u16 vbg_adc_value;
static u16 vbat_adc_value;
static u8 vbat_vddio_tieup = 0;
#define ADC_SRC_CLK clk_get("adc")
/*config adc clk according to sys_clk*/
static const u32 sys2adc_clk_info[] = {
128000000L,
96000000L,
72000000L,
48000000L,
24000000L,
12000000L,
6000000L,
1000000L,
};
extern const int config_bt_temperature_pll_trim;
static void temperature_pll_trim_init(void);
static void temperature_pll_trim_exit(void);
u32 adc_add_sample_ch(u32 ch)
{
u32 i = 0;
for (i = 0; i < ADC_MAX_CH; i++) {
/* printf("%s() %d %x %x\n", __func__, i, ch, adc_queue[i].ch); */
if (adc_queue[i].ch == ch) {
break;
} else if (adc_queue[i].ch == -1) {
adc_queue[i].ch = ch;
adc_queue[i].value = 1;
adc_queue[i].jiffies = 0;
adc_queue[i].sample_period = msecs_to_jiffies(0);
printf("add sample ch %x\n", ch);
break;
}
}
return i;
}
u32 adc_set_sample_freq(u32 ch, u32 ms)
{
u32 i;
for (i = 0; i < ADC_MAX_CH; i++) {
if (adc_queue[i].ch == ch) {
adc_queue[i].sample_period = msecs_to_jiffies(ms);
adc_queue[i].jiffies = msecs_to_jiffies(ms) + jiffies;
break;
}
}
return i;
}
u32 adc_remove_sample_ch(u32 ch)
{
u32 i = 0;
for (i = 0; i < ADC_MAX_CH; i++) {
if (adc_queue[i].ch == ch) {
adc_queue[i].ch = -1;
break;
}
}
return i;
}
static u32 adc_get_next_ch(u32 cur_ch)
{
for (int i = cur_ch + 1; i < ADC_MAX_CH; i++) {
if (adc_queue[i].ch != -1) {
return i;
}
}
return 0;
}
void adc_set_vbat_vddio_tieup(u8 en)
{
vbat_vddio_tieup = !!en;
}
u32 adc_get_value(u32 ch)
{
if (vbat_vddio_tieup) {
if (ch == AD_CH_VBAT) {
return vbat_adc_value;
}
} else {
if (ch == AD_CH_LDOREF) {
return vbg_adc_value;
}
}
for (int i = 0; i < ADC_MAX_CH; i++) {
if (adc_queue[i].ch == ch) {
return adc_queue[i].value;
}
}
return 0;
}
u32 adc_value_to_voltage(u32 adc_vbg, u32 adc_ch_val)
{
#define CENTER 1168
u32 adc_res = adc_ch_val;
u32 adc_trim = get_vbg_trim();
u32 tmp, tmp1;
tmp1 = adc_trim & 0x1f;
tmp = (adc_trim & BIT(5)) ? CENTER - tmp1 * 3.2 : CENTER + tmp1 * 3.2;
adc_res = adc_res * tmp / adc_vbg;
return adc_res;
}
u32 adc_get_voltage(u32 ch)
{
#ifdef CONFIG_FPGA_ENABLE
return 1000;
#endif
u32 adc_vbg = adc_get_value(AD_CH_LDOREF);
u32 adc_res = adc_get_value(ch);
return adc_value_to_voltage(adc_vbg, adc_res);
}
static u8 check_vbat_cnt = 0;
static u8 check_vbat_flag = 0;
u32 adc_check_vbat_lowpower()
{
if (!vbat_vddio_tieup) {
u32 vbat = adc_get_value(AD_CH_VBAT);
//printf("vbat_adc = %d vbg = %d\n", vbat, vbg_adc_value);
if ((!check_vbat_flag) && (__builtin_abs(vbat - 255) < 15)) {
//printf("&1\n");
set_change_vbg_value_flag();
check_vbat_flag = 1;
}
if (check_vbat_flag) {
check_vbat_cnt ++;
if (check_vbat_cnt > 18) {
//printf("&2\n");
check_vbat_flag = 0;
check_vbat_cnt = 0;
}
}
}
return 0;
}
void adc_audio_ch_select(u32 ch)
{
SFR(JL_ANA->DAA_CON0, 0, 5, ch);
}
void adc_pll_detect_en(u32 ch)
{
JL_CLOCK->PLL_CON1 |= BIT(18);//pll
SFR(JL_CLOCK->PLL_CON1, 16, 2, ch);
}
void adc_fm_detect_en(u32 ch)
{
JL_ANA->WLA_CON25 |= (BIT(19));//fm
SFR(JL_ANA->WLA_CON25, 21, 3, ch);
}
void adc_bt_detect_en(u32 ch)
{
JL_ANA->WLA_CON4 |= (BIT(6));//bt
}
void adc_close()
{
JL_ADC->CON = 0;
JL_ADC->CON = 0;
}
void adc_suspend()
{
JL_ADC->CON &= ~BIT(4);
}
void adc_resume()
{
JL_ADC->CON |= BIT(4);
}
void adc_enter_occupy_mode(u32 ch)
{
if (JL_ADC->CON & BIT(4)) {
return;
}
adc_queue[ADC_MAX_CH].ch = ch;
cur_ch_value = adc_sample(ch);
}
void adc_exit_occupy_mode()
{
adc_queue[ADC_MAX_CH].ch = -1;
}
u32 adc_occupy_run()
{
if (adc_queue[ADC_MAX_CH].ch != -1) {
while (1) {
asm volatile("nop");
if (_adc_res != (u16) - 1) {
break;
}
}
if (_adc_res == 0) {
_adc_res ++;
}
adc_queue[ADC_MAX_CH].value = _adc_res;
_adc_res = cur_ch_value;
return adc_queue[ADC_MAX_CH].value;
}
return 0;
}
u32 adc_get_occupy_value()
{
if (adc_queue[ADC_MAX_CH].ch != -1) {
return adc_queue[ADC_MAX_CH].value;
}
return 0;
}
u32 get_adc_div(u32 src_clk)
{
u32 adc_clk;
u32 adc_clk_idx;
u32 cnt;
adc_clk = src_clk;
cnt = ARRAY_SIZE(sys2adc_clk_info);
for (adc_clk_idx = 0; adc_clk_idx < cnt; adc_clk_idx ++) {
if (adc_clk > sys2adc_clk_info[adc_clk_idx]) {
break;
}
}
if (adc_clk_idx < cnt) {
adc_clk_idx = cnt - adc_clk_idx;
} else {
adc_clk_idx = cnt - 1;
}
return adc_clk_idx;
}
static void adc_ch_mux_select(u32 mux_ch)
{
#if 1
//先把所有复用通道都关了
P33_CON_SET(P3_ANA_CON4, 0, 1, 0);//pmu
SFR(JL_ANA->DAA_CON0, 0, 5, 0);//audio
JL_CLOCK->PLL_CON1 &= ~BIT(18);//pll
/* JL_ANA->WLA_CON25 &= ~(BIT(19));//fm */
/* JL_ANA->WLA_CON4 &= ~(BIT(6));//bt */
#endif
if ((mux_ch & 0xfffff) == AD_OF_PMU) {
adc_pmu_detect_en(mux_ch >> 20);
} else if ((mux_ch & 0xfffff) == AD_OF_AUDIO) {
adc_audio_ch_select(mux_ch >> 20);
} else if ((mux_ch & 0xfffff) == AD_OF_PLL) {
adc_pll_detect_en(mux_ch >> 20);
} else if ((mux_ch & 0xfffff) == AD_OF_FM) {
adc_fm_detect_en(mux_ch >> 20);
} else if ((mux_ch & 0xfffff) == AD_OF_BT) {
adc_bt_detect_en(mux_ch >> 20);
}
}
u8 __attribute__((weak)) adc_io_reuse_enter(u32 ch)
{
return 0;
}
u8 __attribute__((weak)) adc_io_reuse_exit(u32 ch)
{
return 0;
}
___interrupt
static void adc_isr()
{
u32 ch;
ch = (JL_ADC->CON & 0xf00) >> 8;
adc_io_reuse_exit(ch);
_adc_res = JL_ADC->RES;
adc_pmu_detect_en(AD_CH_WVDD >> 20);
local_irq_disable();
JL_ADC->CON = BIT(6);
JL_ADC->CON = 0;
local_irq_enable();
}
u32 adc_sample(u32 ch)
{
const u32 tmp_adc_res = _adc_res;
_adc_res = (u16) - 1;
if (adc_io_reuse_enter(ch)) {
_adc_res = adc_get_value(ch);
return tmp_adc_res;
}
u32 adc_con = 0;
SFR(adc_con, 0, 3, 0b110);//div 96
adc_con |= (0xf << 12); //启动延时控制,实际启动延时为此数值*8个ADC时钟
adc_con |= (adc_queue[0].ch & 0xf) << 8;
adc_con |= BIT(3);
adc_con |= BIT(6);
adc_con |= BIT(5);//ie
SFR(adc_con, 8, 4, ch & 0xf);
if ((ch & 0xffff) == AD_CH_MUX) {
adc_ch_mux_select(ch);
}
JL_ADC->CON = adc_con;
JL_ADC->CON |= BIT(4);//en
JL_ADC->CON |= BIT(6);//kistart
return tmp_adc_res;
}
static u8 change_vbg_flag = 0;
void set_change_vbg_value_flag(void)
{
change_vbg_flag = 1;
}
void adc_scan(void *priv)
{
static u16 adc_sample_flag = 0;
if (adc_queue[ADC_MAX_CH].ch != -1) {//occupy mode
return;
}
if (JL_ADC->CON & BIT(4)) {
return ;
}
if (adc_sample_flag) {
if (adc_sample_flag == 2) {
vbg_adc_value = _adc_res;
} else {
adc_queue[cur_ch].value = _adc_res;
if (adc_queue[cur_ch].ch == AD_CH_LDOREF) {
vbg_adc_value = _adc_res;
}
}
adc_sample_flag = 0;
}
if (change_vbg_flag) {
change_vbg_flag = 0;
adc_sample(AD_CH_LDOREF);
adc_sample_flag = 2;
return;
}
u8 next_ch = adc_get_next_ch(cur_ch);
if (adc_queue[next_ch].sample_period) {
if (time_before(adc_queue[next_ch].jiffies, jiffies)) {
adc_sample(adc_queue[next_ch].ch);
adc_sample_flag = 1;
adc_queue[next_ch].jiffies += adc_queue[next_ch].sample_period;
}
} else {
adc_sample(adc_queue[next_ch].ch);
adc_sample_flag = 1;
}
cur_ch = next_ch;
}
//获取当前采集ad的通道总数
u8 get_cur_total_ad_ch(void)
{
u8 total_ch = 0;
u8 i = 0;
while (i < ADC_MAX_CH) {
if (adc_queue[i].ch != -1) {
total_ch++;
}
i++;
}
return total_ch;
}
void _adc_init(u32 sys_lvd_en)
{
memset(adc_queue, 0xff, sizeof(adc_queue));
JL_ADC->CON = 0;
JL_ADC->CON = 0;
adc_pmu_detect_en(1);
u32 i;
vbat_adc_value = 0;
adc_sample(AD_CH_VBAT);
for (i = 0; i < 10; i++) {
while (!(JL_ADC->CON & BIT(7)));
vbat_adc_value += JL_ADC->RES;
JL_ADC->CON |= BIT(6);
}
vbat_adc_value /= 10;
printf("vbat_adc_value = %d\n", vbat_adc_value);
vbg_adc_value = 0;
adc_sample(AD_CH_LDOREF);
for (i = 0; i < 10; i++) {
while (!(JL_ADC->CON & BIT(7)));
vbg_adc_value += JL_ADC->RES;
JL_ADC->CON |= BIT(6);
}
vbg_adc_value /= 10;
printf("vbg_adc_value = %d\n", vbg_adc_value);
u32 vbat_queue_ch = 0;
u32 vbg_queue_ch = 0;
if (vbat_vddio_tieup) {
vbg_queue_ch = adc_add_sample_ch(AD_CH_LDOREF);
adc_set_sample_freq(AD_CH_LDOREF, 30000);
adc_queue[vbg_queue_ch].value = vbg_adc_value;
} else {
vbat_queue_ch = adc_add_sample_ch(AD_CH_VBAT);
adc_set_sample_freq(AD_CH_VBAT, 30000);
adc_queue[vbat_queue_ch].value = vbat_adc_value;
}
if (config_bt_temperature_pll_trim) {
u32 dtemp_ch = adc_add_sample_ch(AD_CH_DTEMP);
adc_set_sample_freq(AD_CH_DTEMP, 1500);
adc_sample(AD_CH_DTEMP);
while (!(JL_ADC->CON & BIT(7)));
adc_queue[dtemp_ch].value = JL_ADC->RES;
JL_ADC->CON |= BIT(6);
temperature_pll_trim_init();
}
request_irq(IRQ_SARADC_IDX, 0, adc_isr, 0);
sys_s_hi_timer_add(NULL, adc_scan, 2); //2ms
/* void adc_test(); */
/* sys_s_hi_timer_add(NULL, adc_test, 1000); //2ms */
/* */
/* extern void wdt_close(); */
/* wdt_close(); */
/* */
/* while(1); */
}
static u8 wvdd_lev = 0;
static u32 get_wvdd_voltage()
{
u32 vbg_value = 0;
u32 wvdd_value = 0;
adc_pmu_detect_en(1);
adc_sample(AD_CH_LDOREF);
for (int i = 0; i < 10; i++) {
while (!(JL_ADC->CON & BIT(7))) { //wait pending
}
vbg_value += JL_ADC->RES;
JL_ADC->CON |= BIT(6);
}
adc_sample(AD_CH_WVDD);
for (int i = 0; i < 10; i++) {
while (!(JL_ADC->CON & BIT(7))) { //wait pending
}
wvdd_value += JL_ADC->RES;
JL_ADC->CON |= BIT(6);
}
u32 adc_vbg = vbg_value / 10;
u32 adc_res = wvdd_value / 10;
return adc_value_to_voltage(adc_vbg, adc_res);
}
static void wvdd_trim()
{
wvdd_lev = 0;
P33_CON_SET(P3_WLDO06_AUTO, 0, 3, wvdd_lev);
WLDO06_EN(1);
delay(2000);//1ms
do {
P33_CON_SET(P3_WLDO06_AUTO, 0, 3, wvdd_lev);
delay(2000);//1ms * n
if (get_wvdd_voltage() > 700) {
break;
}
wvdd_lev ++;
} while (wvdd_lev < 8);
WLDO06_EN(0);
printf("wvdd_lev: %d\n", wvdd_lev);
power_set_wvdd(wvdd_lev);
}
//*********************************************************************************
//蓝牙温度跟随trim
//*********************************************************************************
#define CHECK_TEMPERATURE_CYCLE (2000) //检测周期
#define BTOSC_TEMPERATURE_THRESHOLD (10 * 3) //偏差阈值
#define AD_SAMPLE_COUNTS 1
#define WIPE_EXTREMUM_EN 1
#define ABS(x) (x > 0 ? x : (-x))
#if WIPE_EXTREMUM_EN && (AD_SAMPLE_COUNTS == 2)
#error "AD_SAMPLE_COUNTS must >= 3 while WIPE_EXTREMUM_EN=1"
#endif
#if (AD_SAMPLE_COUNTS < 1)
#error "AD_SAMPLE_COUNTS must > 0"
#endif
static u32 pll_trim_timer = 0;
static u32 prev_mV = 0;
extern void bta_pll_config_init(s32 offset);
static u32 get_cur_temperature(void)
{
if (!config_bt_temperature_pll_trim) {
return 0;
}
u32 cur_mV;
u32 sum_mV = 0;
#if WIPE_EXTREMUM_EN
u32 max = 0;
u32 min = (u32) - 1;
#endif /* WIPE_EXTREMUM_EN */
for (int i = 0; i < AD_SAMPLE_COUNTS; i++) {
#if 0
/* adc_enter_occupy_mode(AD_CH_DTEMP); */
/* cur_mV = adc_occupy_run(); */
/* adc_exit_occupy_mode(); */
#else
cur_mV = adc_get_voltage(AD_CH_DTEMP);
#endif
printf("cur_mV=%d\r\n", cur_mV);
sum_mV += cur_mV;
#if WIPE_EXTREMUM_EN
max = (cur_mV > max) ? cur_mV : max;
min = (cur_mV < min) ? cur_mV : min;
#endif /* WIPE_EXTREMUM_EN */
}
#if WIPE_EXTREMUM_EN
printf("sum_mV=%d, max=%d, min=%d", sum_mV, max, min);
return ((sum_mV - max - min) / (AD_SAMPLE_COUNTS - 2));
#else
return sum_mV / AD_SAMPLE_COUNTS;
#endif /* WIPE_EXTREMUM_EN */
}
u8 get_bt_rf_state(void);
void get_bta_pll_midbank_temp(void);
static void pll_trim_timer_handler(void)
{
if (!config_bt_temperature_pll_trim) {
return;
}
/* printf("\n--func=%s", __FUNCTION__); */
u32 cur_mV;
s32 minus;
static s32 pll_bank_offset = 0;
cur_mV = adc_get_voltage(AD_CH_DTEMP);
minus = (s32)(cur_mV - prev_mV);
printf("cur_mV =%d, prev_mV =%d,minus =%d\n", cur_mV, prev_mV, minus);
if (ABS(minus) >= BTOSC_TEMPERATURE_THRESHOLD) {
prev_mV = cur_mV;
(minus > 0) ? pll_bank_offset ++ : pll_bank_offset --;
printf("pll_bank_offset =%d\n\n", pll_bank_offset);
/* bta_pll_config_init(pll_bank_offset); */
get_bta_pll_midbank_temp();
}
}
static void temperature_pll_trim_init(void)
{
prev_mV = adc_get_voltage(AD_CH_DTEMP);
printf("init prev_mV:%d\n", prev_mV);
pll_trim_timer = sys_timer_add(NULL, pll_trim_timer_handler, CHECK_TEMPERATURE_CYCLE);
}
static void temperature_pll_trim_exit(void)
{
if (pll_trim_timer) {
sys_timeout_del(pll_trim_timer);
pll_trim_timer = 0;
}
}
//*********************************************************************************
u8 vddiom_trim_level;
void vddiom_trim()
{
u32 vbg_value = 0;
adc_pmu_detect_en(1);
adc_sample(AD_CH_LDOREF);
for (int i = 0; i < 10; i++) {
while (!(JL_ADC->CON & BIT(7))) { //wait pending
}
vbg_value += JL_ADC->RES;
JL_ADC->CON |= BIT(6);
}
vbg_value /= 10;
u32 vddio_vol = adc_value_to_voltage(vbg_value, 1023);
// printf("vddio_vol %d (mv), vbg_value %d\n", vddio_vol, vbg_value);
u32 vddiom_lev = GET_VDDIOM_VOL();
u32 vddiom_ref = (vddiom_lev - VDDIOM_VOL_22V) * 200 + 2200;
int vddiom_diff = (vddio_vol - vddiom_ref);
if (__builtin_abs(vddiom_diff) > 100) {
if (vddio_vol > vddiom_ref) {
vddiom_trim_level = vddiom_lev - 1;
} else {
vddiom_trim_level = vddiom_lev + 1;
}
VDDIOM_VOL_SEL(vddiom_trim_level);
delay(5000);
} else {
vddiom_trim_level = vddiom_lev;
}
printf("trim: vddio_vol %d (mv), vddiom_lev %d, vddiom_diff %d, vbg_value %d\n", vddio_vol, vddiom_trim_level, vddiom_diff, vbg_value);
u32 temp = (vddiom_trim_level - VDDIOM_VOL_22V) * 200 + 2200;
u32 vddiow_lev_bak = GET_VDDIOW_VOL();
u32 vddiow_ref = 0;
VDDIOW_VOL_SEL(VDDIOW_VOL_21V);
switch (vddiow_lev_bak) {
case VDDIOW_VOL_21V:
vddiow_ref = 2100;
break;
case VDDIOW_VOL_24V:
vddiow_ref = 2400;
break;
case VDDIOW_VOL_28V:
vddiow_ref = 2800;
break;
case VDDIOW_VOL_32V:
vddiow_ref = 3200;
break;
}
if (temp < vddiow_ref + 200) { //vddiom需要比vddiow高200mV
if (temp >= 3200 + 200) {
VDDIOW_VOL_SEL(VDDIOW_VOL_32V);
} else if (temp >= 2800 + 200) {
VDDIOW_VOL_SEL(VDDIOW_VOL_28V);
} else if (temp >= 2400 + 200) {
VDDIOW_VOL_SEL(VDDIOW_VOL_24V);
} else {
VDDIOW_VOL_SEL(VDDIOW_VOL_21V);
}
// printf("trim: vddiow lev %d to %d\n", vddiow_lev_bak, GET_VDDIOW_VOL());
} else {
VDDIOW_VOL_SEL(vddiow_lev_bak);
}
}
void adc_init()
{
JL_ANA->WLA_CON25 &= ~(BIT(19)); //fm
JL_ANA->WLA_CON4 &= ~(BIT(6));//bt
//audio
JL_ANA->DAA_CON0 &= ~BIT(4);//DACVDD_TEST_EN_11v
JL_ANA->DAA_CON0 &= ~BIT(3);//CTADCREF_TEST_EN_11v
JL_ANA->DAA_CON0 &= ~BIT(2);//MICLDO_TEST_EN_11v
JL_ANA->DAA_CON0 &= ~BIT(1);//VOUTR_TEST_EN_11v
JL_ANA->DAA_CON0 &= ~BIT(0);//VOUTL_TEST_EN_11v
JL_CLOCK->PLL_CON1 &= ~BIT(18); //pll
//每次开机消耗5~8ms
vddiom_trim();
//trim wvdd
wvdd_trim();
/* check_pmu_voltage(vbat_vddio_tieup); */
_adc_init(1);
}
//late_initcall(adc_init);
void adc_test()
{
/* printf("\n\n%s() chip_id :%x\n", __func__, get_chip_id()); */
/* printf("%s() vbg trim:%x\n", __func__, get_vbg_trim()); */
/* printf("%s() vbat trim:%x\n", __func__, get_vbat_trim()); */
/* printf("\n\nWLA_CON0 %x\n", JL_ANA->WLA_CON0); */
/* printf("WLA_CON9 %x\n", JL_ANA->WLA_CON9); */
/* printf("WLA_CON10 %x\n", JL_ANA->WLA_CON10); */
/* printf("WLA_CON21 %x\n", JL_ANA->WLA_CON21); */
/* */
/* printf("ADA_CON %x\n", JL_ANA->ADA_CON3); */
/* printf("PLL_CON1 %x\n", JL_CLOCK->PLL_CON1); */
printf("\n%s() VBAT:%d %d mv\n\n", __func__,
adc_get_value(AD_CH_VBAT), adc_get_voltage(AD_CH_VBAT) * 4);
printf("\n%s() DTEMP:%d %d mv\n\n", __func__,
adc_get_value(AD_CH_DTEMP), adc_get_voltage(AD_CH_DTEMP));
}
void adc_vbg_init()
{
return ;
}
//__initcall(adc_vbg_init);