123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631 |
- #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/p11.h"
- #include "asm/power_interface.h"
- #include "jiffies.h"
- #include "app_config.h"
- u32 adc_sample(u32 ch);
- 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;
- };
- #define ENABLE_OCCUPY_MODE 1
- static struct adc_info_t adc_queue[ADC_MAX_CH + ENABLE_OCCUPY_MODE];
- static u8 adc_sample_flag = 0;
- static u16 dtemp_voltage = 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,
- };
- 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;
- }
- #define PMU_CH_SAMPLE_FREQ 500 //ms
- #define PMU_CH_VALUE_ARRAY_SIZE (16 + 1)
- static u16 vbat_value_array[PMU_CH_VALUE_ARRAY_SIZE];
- static u16 vbg_value_array[PMU_CH_VALUE_ARRAY_SIZE];
- static void adc_value_push(u16 *array, u16 adc_value)
- {
- u16 pos = array[0];
- pos++;
- if (pos >= PMU_CH_VALUE_ARRAY_SIZE) {
- pos = 1;
- }
- array[pos] = adc_value;
- array[0] = pos;
- }
- static u16 adc_value_avg(u16 *array)
- {
- u32 i, j, sum = 0;
- for (i = 1, j = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i++) {
- if (array[i]) {
- sum += array[i];
- j += 1;
- }
- }
- if (sum) {
- return (sum / j);
- }
- return 1;
- }
- static void adc_value_array_reset(u16 *array)
- {
- for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i++) {
- array[i] = 0;
- }
- }
- u32 adc_get_value(u32 ch)
- {
- if (ch == AD_CH_VBAT) {
- return adc_value_avg(vbat_value_array);
- } else if (ch == AD_CH_LDOREF) {
- return adc_value_avg(vbg_value_array);
- }
- for (int i = 0; i < ADC_MAX_CH; i++) {
- if (adc_queue[i].ch == ch) {
- return adc_queue[i].value;
- }
- }
- return 1;
- }
- #define VBG_CENTER 801
- #define VBG_RES 3
- u32 adc_value_to_voltage(u32 adc_vbg, u32 adc_ch_val)
- {
- u32 adc_res = adc_ch_val;
- u32 adc_trim = get_vbg_trim();
- u32 tmp, tmp1;
- tmp1 = adc_trim & 0x0f;
- tmp = (adc_trim & BIT(4)) ? VBG_CENTER - tmp1 * VBG_RES : VBG_CENTER + tmp1 * VBG_RES;
- adc_res = adc_res * tmp / adc_vbg;
- //printf("adc_res %d mv vbg:%d adc:%d adc_trim:%x\n", adc_res, adc_vbg, adc_ch_val, adc_trim);
- return adc_res;
- }
- u32 adc_get_voltage(u32 ch)
- {
- #ifdef CONFIG_FPGA_ENABLE
- return 1000;
- #endif
- if (ch == AD_CH_DTEMP) {
- return dtemp_voltage;
- }
- 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);
- }
- /*
- 1、第一次上电: 电压小于2.4v,不允许切dcdc模式
- 2、运行中,当检测到电压小于2.4v,切换为ldo模式
- 2、运行中,当检测到电压大于2.4v,切换相应的电源模式
- */
- void power_set_ldo_for_lowpower(u8 en);
- u8 power_set_ldo_for_lowpower_check(u8 init)
- {
- static u8 ldo_lowpower = 0;
- /*
- 电池电压小于2.4v时,切换成ldo模式
- */
- u32 vbat = adc_get_voltage(AD_CH_VBAT) * 4;
- if (vbat < 2400) {
- if (ldo_lowpower == 0) {
- local_irq_disable();
- power_set_ldo_for_lowpower(1);
- power_set_mode(PWR_LDO15);
- ldo_lowpower = 1;
- local_irq_enable();
- }
- } else {
- if (ldo_lowpower) {
- local_irq_disable();
- power_set_ldo_for_lowpower(0);
- if (TCFG_LOWPOWER_POWER_SEL == PWR_DCDC15) {
- if (get_charge_online_flag()) {
- power_set_mode(PWR_DCDC15_FOR_CHARGE);
- } else {
- power_set_mode(PWR_DCDC15);
- }
- }
- ldo_lowpower = 0;
- local_irq_enable();
- }
- }
- }
- u32 adc_check_vbat_lowpower()
- {
- power_set_ldo_for_lowpower_check(0);
- return 0;
- }
- void adc_audio_ch_select(u32 ch)
- {
- /* SFR(JL_ANA->DAA_CON0, 12, 4, ch); */
- }
- 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("idle");//wait isr
- 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;
- }
- ___interrupt
- static void adc_isr()
- {
- _adc_res = JL_ADC->RES;
- /* P33_CON_SET(P3_ANA_CON4, 5, 1, 0); */
- local_irq_disable();
- JL_ADC->CON = BIT(6);
- local_irq_enable();
- #if 1
- if (adc_sample_flag > 1) {
- extern void adc_scan(void *priv);
- adc_scan(NULL);
- }
- #endif
- }
- u32 adc_sample(u32 ch)
- {
- const u32 tmp_adc_res = _adc_res;
- _adc_res = (u16) - 1;
- u32 adc_con = 0;
- SFR(adc_con, 0, 3, 0b110);//div 96
- adc_con |= (0xf << 12); //启动延时控制,实际启动延时为此数值*8个ADC时钟
- adc_con |= BIT(3); //ana en
- adc_con |= BIT(6); //en
- adc_con |= BIT(5);//ie
- SFR(adc_con, 8, 4, ch & 0xf);
- if ((ch & 0xffff) == AD_CH_PMU) {
- if (adc_sample_flag > 1) {
- SFR(adc_con, 0, 3, 0b011);//div 24
- adc_con &= ~(0xf << 12);
- }
- adc_pmu_ch_select(ch >> 16);
- }
- JL_ADC->CON = adc_con;
- JL_ADC->CON |= BIT(4);//en
- JL_ADC->CON |= BIT(6);//kistart
- return tmp_adc_res;
- }
- void adc_scan(void *priv)
- {
- static u16 vbg_adc_res = 0;
- static u16 dtemp_adc_res = 0;
- if (adc_queue[ADC_MAX_CH].ch != -1) { //occupy mode
- return;
- }
- if (JL_ADC->CON & BIT(4)) {
- adc_sample_flag = 0;
- return ;
- }
- if (adc_sample_flag) {
- if (adc_sample_flag == 2) {
- dtemp_adc_res = _adc_res;
- adc_sample_flag = 3;
- adc_sample(AD_CH_LDOREF);
- return;
- } else if (adc_sample_flag == 3) {
- vbg_adc_res = _adc_res;
- dtemp_voltage = adc_value_to_voltage(vbg_adc_res, dtemp_adc_res);
- /* printf("vbg:%d dtemp:%d vol:%dmv\n", vbg_adc_res, dtemp_adc_res, dtemp_voltage); */
- } else {
- adc_queue[cur_ch].value = _adc_res;
- if (adc_queue[cur_ch].ch == AD_CH_VBAT) {
- adc_value_push(vbat_value_array, _adc_res);
- /* printf("vbat %d",_adc_res); */
- } else if (adc_queue[cur_ch].ch == AD_CH_LDOREF) {
- adc_value_push(vbg_value_array, _adc_res);
- /* printf("vbg %d",_adc_res); */
- }
- }
- adc_sample_flag = 0;
- }
- 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)) {
- if (adc_queue[next_ch].ch == AD_CH_DTEMP) {
- adc_sample_flag = 2;
- } else {
- adc_sample_flag = 1;
- }
- adc_sample(adc_queue[next_ch].ch);
- 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;
- }
- static u16 adc_wait_pnd()
- {
- while (!(JL_ADC->CON & BIT(7)));
- u32 adc_res = JL_ADC->RES;
- asm("nop");
- JL_ADC->CON |= BIT(6);
- return adc_res;
- }
- void _adc_init(u32 sys_lvd_en)
- {
- memset(adc_queue, 0xff, sizeof(adc_queue));
- memset(vbg_value_array, 0x0, sizeof(vbg_value_array));
- memset(vbat_value_array, 0x0, sizeof(vbat_value_array));
- JL_ADC->CON = 0;
- adc_add_sample_ch(AD_CH_LDOREF);
- adc_set_sample_freq(AD_CH_LDOREF, PMU_CH_SAMPLE_FREQ);
- adc_add_sample_ch(AD_CH_VBAT);
- adc_set_sample_freq(AD_CH_VBAT, PMU_CH_SAMPLE_FREQ);
- adc_add_sample_ch(AD_CH_DTEMP);
- adc_set_sample_freq(AD_CH_DTEMP, PMU_CH_SAMPLE_FREQ);
- u32 sum_ad = 0;
- adc_sample(AD_CH_LDOREF);
- for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i ++) {
- sum_ad += adc_wait_pnd();
- }
- sum_ad /= PMU_CH_VALUE_ARRAY_SIZE;
- adc_value_push(vbg_value_array, sum_ad);
- printf("vbg_adc_value = %d\n", adc_value_avg(vbg_value_array));
- sum_ad = 0;
- adc_sample(AD_CH_VBAT);
- for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i ++) {
- sum_ad += adc_wait_pnd();
- }
- sum_ad /= PMU_CH_VALUE_ARRAY_SIZE;
- adc_value_push(vbat_value_array, sum_ad);
- printf("vbat_adc_value = %d\n", adc_value_avg(vbat_value_array));
- printf("vbat = %d mv\n", adc_get_voltage(AD_CH_VBAT) * 4);
- sum_ad = 0;
- adc_sample(AD_CH_DTEMP);
- for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i ++) {
- sum_ad += adc_wait_pnd();
- }
- sum_ad /= PMU_CH_VALUE_ARRAY_SIZE;
- dtemp_voltage = adc_value_to_voltage(adc_value_avg(vbg_value_array), sum_ad);
- printf("dtemp_adc_value = %d\n", sum_ad);
- printf("dtemp = %d mv\n", dtemp_voltage);
- request_irq(IRQ_SARADC_IDX, 0, adc_isr, 0);
- usr_timer_add(NULL, adc_scan, 5, 0); //2ms
- /* sys_timer_add(NULL, adc_scan, 10); //2ms */
- /* void adc_test(); */
- /* usr_timer_add(NULL, adc_test, 1000, 0); //2ms */
- /* extern void wdt_close(); */
- /* wdt_close(); */
- /* */
- /* while(1); */
- }
- static u32 get_vdd_voltage(u32 ch)
- {
- u32 vbg_value = 0;
- u32 wvdd_value = 0;
- adc_sample(AD_CH_LDOREF);
- for (int i = 0; i < 10; i++) {
- vbg_value += adc_wait_pnd();
- }
- adc_sample(ch);
- for (int i = 0; i < 10; i++) {
- wvdd_value += adc_wait_pnd();
- }
- u32 adc_vbg = vbg_value / 10;
- u32 adc_res = wvdd_value / 10;
- return adc_value_to_voltage(adc_vbg, adc_res);
- }
- u8 wvdd_efuse_level[4] = {WVDD_VOL_SEL_065V, WVDD_VOL_SEL_070V, WVDD_VOL_SEL_075V, WVDD_VOL_SEL_080V};
- static u8 wvdd_trim(u8 trim)
- {
- u8 wvdd_lev = 0;
- u8 wvdd_efuse_lev = ((p33_rd_page(1) >> 24) & 0x3);
- if (trim) {
- wvdd_lev = wvdd_efuse_level[wvdd_efuse_lev];
- } else {
- wvdd_lev = get_wvdd_trim_level();
- }
- if (wvdd_lev < WVDD_VOL_SEL_065V) {
- wvdd_lev = WVDD_VOL_SEL_080V;
- }
- printf("trim: %d, wvdd_lev: %d\n", trim, wvdd_lev);
- M2P_WDVDD = wvdd_lev;
- return wvdd_lev;
- }
- static u8 pvdd_trim(u8 trim)
- {
- u32 v = 0;
- u32 lev = 0xf;
- u8 err = 0;
- if (trim) {
- for (; lev; lev--) {
- P33_CON_SET(P3_PVDD1_AUTO, 0, 8, (lev | lev << 4));
- delay(2000);//1ms
- v = get_vdd_voltage(AD_CH_PVDD);
- if (v < (PVDD_VOL_TRIM + PVDD_VOL_STEP)) {
- break;
- }
- }
- if (v < PVDD_VOL_TRIM) {
- if (lev < PVDD_LEVEL_MAX) {
- lev++;
- }
- }
- //update_pvdd_trim_level(lev);
- } else {
- lev = get_pvdd_trim_level();
- }
- #if 0
- printf("pvdd min: %d, max: %d, def_lev: %d\n", (PVDD_VOL_TRIM - PVDD_VOL_MIN) / PVDD_VOL_STEP - 2, \
- (PVDD_VOL_TRIM - PVDD_VOL_MIN) / PVDD_VOL_STEP + 2, \
- PVDD_LEVEL_DEFAULT);
- #endif
- printf("trim: %d, pvdd_lev: %d, pvdd_lev_l: %d\n", trim, lev, lev - PVDD_LEVEL_TRIM_LOW);
- if (trim) {
- u8 min = (PVDD_VOL_TRIM - PVDD_VOL_MIN) / PVDD_VOL_STEP - 2;
- u8 max = (PVDD_VOL_TRIM - PVDD_VOL_MIN) / PVDD_VOL_STEP + 2;
- if (!(lev >= min && lev <= max)) {
- lev = PVDD_LEVEL_DEFAULT;
- err = 1;
- }
- }
- P33_CON_SET(P3_PVDD1_AUTO, 0, 8, (lev | lev << 4));
- delay(2000);
- P33_CON_SET(P3_PVDD0_AUTO, 0, 8, (7 << 4) | (lev - PVDD_LEVEL_TRIM_LOW));
- if (err) {
- return PVDD_LEVEL_ERR;
- }
- return lev;
- }
- void adc_init()
- {
- adc_pmu_detect_en(1);
- //trim wvdd
- u8 trim = check_wvdd_pvdd_trim(0);
- u8 wvdd_lev = wvdd_trim(trim);
- u8 pvdd_lev = pvdd_trim(trim);
- if (trim) {
- if ((wvdd_lev != WVDD_LEVEL_ERR) && (pvdd_lev != PVDD_LEVEL_ERR)) {
- update_wvdd_pvdd_trim_level(wvdd_lev, pvdd_lev);
- }
- }
- _adc_init(1);
- //这个函数之后才能切电源模式
- power_set_ldo_for_lowpower_check(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() pa3:%d %d mv\n\n", __func__, */
- /* adc_get_value(AD_CH_PA3), adc_get_voltage(AD_CH_PA3)); */
- }
- void adc_vbg_init()
- {
- return ;
- }
- //__initcall(adc_vbg_init);
|