/*================================================================ Copyright (c) 2022, Quectel Wireless Solutions Co., Ltd. All rights reserved. Quectel Wireless Solutions Proprietary and Confidential. =================================================================*/ #include "quec_cust_startup_feature.h" #ifdef QUECTEL_OPEN_CPU #include "ql_boot_power.h" #include "ningbo.h" #include "guilin.h" #include "pmic.h" //#include "dm_charge.h" //#include "dm_ningbo.h" #ifndef true #define false 0 #define true 1 #endif #ifdef QUEC_POWER_LOG_ENABLE #define power_dbg_log(fmt, args...) #else #define power_dbg_log(fmt, args...) uart_printf("[%s][%d]"fmt, __FUNCTION__, __LINE__, ##args) #endif //somer.zhang-2020/05/12-add pwrkey check #ifdef QUEC_BOOT_PWRKEY_CHECK void Quec_pwrkey_check(void) { unsigned int i, j=0; char reg = 0; unsigned char power_up_flag = 0xff; //uart_printf("[Quec][PWK]OnkeyPowerOnCheck\r\n"); /* Set 15s for power-down-by-long-ONKEY-pressing period, this register is restricted to change only one bit each time. */ PMIC_WRITE_REG_BASE(0xE3, 0xC0); PMIC_WRITE_REG_BASE(0xE3, 0xE0); PMIC_WRITE_REG_BASE(0xE3, 0xF0); *(volatile unsigned long*)APBTIMER0_EN_REG = 0x1; //enable Timer0_0 (in free run) reg = PMIC_READ_REG_BASE(0xEB); if( 0 == (reg & 0x80)) { power_up_flag = 0x00; // cold power on uart_printf("Cold power on\n"); } else { power_up_flag = 0x01; // hot power on uart_printf("Hot power on\n"); } if(power_up_flag == 0x00){ //cold power on for(i=0;i<2;i++) // 500ms for powerkey check { if (!Quec_PMIC_GET_PWEKY_STATUS()) { uart_printf("short press, do poweroff!!\r\n"); DelayInMilliSecond(100); PMIC_PowerDown(); //Power down if ONKEY is not pressed long enough. } DelayInMilliSecond(100); } reg |= 0x80; PMIC_WRITE_REG_BASE(0xEB, reg); *(volatile unsigned long*)APBTIMER0_EN_REG = 0x0; //stop Timer0_0 } } #endif //for CHARER bind on USB_VBUS BOOL PM812_VBUS_IS_AVAILABLE(void) { if (PMIC_IS_PM812()) { //check whether VBUS is availabe (VCHG_LOW_TH < vbus.vol < VCHG_UPP_TH) return ((PMIC_READ_REG_BASE(PM812_STATUS_1_REG) & PM812_VBUS_STATUS_BIT) ? TRUE : FALSE); } #ifdef CRANE_MCU_DONGLE else if (PMIC_IS_PM802()||PMIC_IS_PM803()||PMIC_IS_PM803L()||PMIC_IS_PM807()) { #if(0) uart_printf("ERR . PM802 means no charge function!\r\n"); return FALSE; #else /*PMIC802/PMIC803 do not support charger(so VBUS detectio is impossible), we check PMUap offset0x7C ,bit15 to detect VBUS state */ uart_printf("DBG====PMIC is PM802/PM803/PM803L\n"); return (((*(volatile unsigned long*)0xd428287c >>15)&0x1) ? TRUE : FALSE); #endif } #endif else { if (PMIC_IS_PM813_A3()) return ((PMIC_READ_REG_BASE(NINGBO_READONLY_DATA_2_REG) & (NINGBO_RONLY_DATA_CHG_OK)) ? TRUE : FALSE); else return ((PMIC_READ_REG_BASE(NINGBO_STATUS_REG1) & (NINGBO_VBUS_STATUS_BIT | NINGBO_VBUS_OVP_BIT | NINGBO_VBUS_UVLO_BIT)) ? TRUE : FALSE); } } #ifdef CRANE_MCU_DONGLE #define GUILIN_PWRUP_LOG_REG 0x10 #endif #define GUILIN_POWERDOWN_LOG_REG 0xE5 #define GUILIN_POWERDOWN_LOG_REG2 0xE6 #define PM812_POWERDOWN_LOG_REG2 0xe6 #define PM812_POWERUP_LOG_REG 0x10 static UINT8 PM812_GET_POWER_DOWN_LOG() { if (PMIC_IS_PM812()) return PMIC_READ_REG_BASE(PM812_POWERDOWN_LOG_REG); #ifdef CRANE_MCU_DONGLE else if (PMIC_IS_PM802()) return PMIC_READ_REG_BASE(GUILIN_POWERDOWN_LOG_REG); #endif else return PMIC_READ_REG_BASE(NINGBO_POWERDOWN_LOG_REG); } static UINT8 PM812_GET_POWER_DOWN_LOG2() { if (PMIC_IS_PM812()) return PMIC_READ_REG_BASE(PM812_POWERDOWN_LOG_REG2); #ifdef CRANE_MCU_DONGLE else if (PMIC_IS_PM802()) return PMIC_READ_REG_BASE(GUILIN_POWERDOWN_LOG_REG2); #endif else return PMIC_READ_REG_BASE(NINGBO_POWERDOWN_LOG_REG2); } static void PM812_CLR_POWER_UP_LOG(UINT8 tmp) { if (PMIC_IS_PM812()) PMIC_WRITE_REG_BASE(PM812_POWERUP_LOG_REG,tmp); #ifdef CRANE_MCU_DONGLE else if (PMIC_IS_PM802()) PMIC_WRITE_REG_BASE(GUILIN_PWRUP_LOG_REG,tmp); #endif else PMIC_WRITE_REG_BASE(NINGBO_PWRUP_LOG_REG,tmp); } static void PM812_CLR_POWER_DOWN_LOG(UINT8 tmp) { if (PMIC_IS_PM812()) PMIC_WRITE_REG_BASE(PM812_POWERDOWN_LOG_REG,tmp); #ifdef CRANE_MCU_DONGLE else if (PMIC_IS_PM802()) PMIC_WRITE_REG_BASE(GUILIN_POWERDOWN_LOG_REG,tmp); #endif else PMIC_WRITE_REG_BASE(NINGBO_POWERDOWN_LOG_REG,tmp); } static void PM812_CLR_POWER_DOWN_LOG2(UINT8 tmp) { if (PMIC_IS_PM812()) PMIC_WRITE_REG_BASE(PM812_POWERDOWN_LOG_REG2,tmp); #ifdef CRANE_MCU_DONGLE else if (PMIC_IS_PM802()) PMIC_WRITE_REG_BASE(GUILIN_POWERDOWN_LOG_REG2,tmp); #endif else PMIC_WRITE_REG_BASE(NINGBO_POWERDOWN_LOG_REG2,tmp); } UINT8 power_up_reason; UINT8 power_down_reason; UINT8 power_down_reason2; int ql_get_powerup_reason(void) { unsigned char hldreg0xE9 = 0x0; //power up log & power down log power_up_reason = PMIC_GET_POWER_UP_LOG(); PM812_CLR_POWER_UP_LOG(power_up_reason); //forrest.liu@20210304 add for PM803 0xe5/0xe6 registers are clear after read if(PMIC_IS_PM803()||PMIC_IS_PM803L()||PMIC_IS_PM807()) { unsigned char *reg; reg = asr_property_get("power_down_reg"); power_down_reason = reg[2]; power_down_reason2 = reg[3]; #if(1) // ref@preboot pmic.c pmic_setup() if(power_down_reason == 0xFF) { power_down_reason = 0x0; } if(power_down_reason2 == 0xFF) { power_down_reason2 = 0x0; } #endif if(PMIC_IS_PM803L() || PMIC_IS_PM807()){ PM812_CLR_POWER_DOWN_LOG(power_down_reason); PM812_CLR_POWER_DOWN_LOG2(power_down_reason2); } } else { power_down_reason = PM812_GET_POWER_DOWN_LOG(); PM812_CLR_POWER_DOWN_LOG(power_down_reason); power_down_reason2 = PM812_GET_POWER_DOWN_LOG2(); PM812_CLR_POWER_DOWN_LOG2(power_down_reason2); } /* uart_printf("power_up_reason:0x%02X\r\n",power_up_reason); uart_printf("power_down_reason:0x%02X\r\n",power_down_reason); uart_printf("power_down_reason2:0x%02X\r\n",power_down_reason2); */ if (power_up_reason & (1<<1)) //0x02 { if ((0x00==power_down_reason) && (0x00==power_down_reason2)) { return QL_POWERUP_RESET; } else { return QL_POWERUP_PWRKEY; } } //forrest.liu@20210304 add for PM803 0xe5/0xe6 registers are clear after read if(PMIC_IS_PM803()) { if (power_up_reason & (1<<4))//forrest.liu@20210128 add for power_up_reason is not correct when run ql_power_reset() { if((0x04==power_down_reason) && (0x00==power_down_reason2)) { return QL_POWERUP_RESET;//ql_power_reset } else if((0x00==power_down_reason) && (0x00==power_down_reason2)) { return QL_POWERUP_RESET;//reset by hand } } if (power_up_reason & (1<<2)) //0x04 { return QL_POWERUP_RTC; } if (power_up_reason & (1<<3)) //0x8 { return QL_POWERUP_VBAT; } } else if(PMIC_IS_PM807())//pmic807 { if (power_up_reason & (1<<6)) { if((0x04==power_down_reason) && (0x00==power_down_reason2)) { return QL_POWERUP_RESET;//ql_power_reset } else if((0x00==power_down_reason) && (0x00==power_down_reason2)) { return QL_POWERUP_RESET;//reset by hand } } if (power_up_reason & (1<<5)) //0x20 { return QL_POWERUP_VBAT; } if (power_up_reason & (1<<4)) //0x10 { return QL_POWERUP_RTC; } } else if(PMIC_IS_PM803L())//pmic803L { if (power_up_reason & (1<<5))//forrest.liu@20210128 add for power_up_reason is not correct when run ql_power_reset() { if((0x06==power_down_reason) && (0x00==power_down_reason2)) { return QL_POWERUP_RESET;//ql_power_reset } else if((0x00==power_down_reason) && (0x00==power_down_reason2)) { return QL_POWERUP_RESET;//reset by hand } } if (power_up_reason & (1<<3)) //0x08 { return QL_POWERUP_VBAT; } if (power_up_reason & (1<<4)) //0x10 { return QL_POWERUP_RTC; } if (power_up_reason & (1<<5)) //0x20 { return QL_POWERUP_FAULT; } } return QL_POWERUP_NO_REASON; } void delay_s(int s) { int i; for(i=0;i= vbat_base) { vol_cali = (unsigned short)(3700 + (vol_GPADC-vbat_base)); } else { vol_cali = (unsigned short)(3700 - (vbat_base-vol_GPADC)); } *vbat = vol_cali; } unsigned short ql_get_battery_vol(void) { if(PMIC_IS_PM813())//EC100Y { return (unsigned short)pm813_get_battery_voltage_withoutCharger(); } else if(PMIC_IS_PM802())//EC600S { unsigned short vat_val=0; quec_adc_read_bat(&vat_val); return vat_val; } else if(PMIC_IS_PM803()||PMIC_IS_PM803L()||PMIC_IS_PM807())//EC600N,not support use in boot٬Support Use in logo { return get_cranel_vbat(); } } /* somer-2020/05/29-add charger terminate current poll */ /* somer-2020/05/29-add recharger poll */ QL_RECHARGE_JUDGE_E ql_recharger_poll(unsigned int recharge_vol_mV) { unsigned int bat_vol=0; static unsigned char cnt=0; bat_vol = ql_get_battery_vol(); if( bat_vol <= recharge_vol_mV ) { if(++cnt>3) { cnt = 0; pm813_charger_switch(1); return QL_RECHARGE_ENABLE; } }else{cnt=0;} return QL_RECHARGE_DISABLE; } //forrest.liu@20201201 add from R01_b04 newest change #define BATTERY_LOW_VOL 3050 #define BATTERY_FULL_VOL 4200 #define LIMIT_CURR 1000 //1A #define USB_UVLO 4200 /*=====================================================================*/ //description: //ntc demo //ntc name:NCP15XH103F03RC //10K ==> 25 degree #define LN_EN 0 static float ntc_to_Temp_v2(float ntc) { float Y_temp; uart_printf("ntc = %.02f K\r\n", ntc); if(ntc>97) { #if LN_EN Y_temp = -18.59*log(ntc) + 57.967; #else Y_temp = 0.0006*ntc*ntc - 0.2914*ntc - 3.9682; #endif } else if(ntc>53.65) { #if LN_EN Y_temp = -20.27*log(ntc) + 65.648; #else Y_temp = 0.0021*ntc*ntc - 0.593*ntc + 10.726; #endif } else if(ntc>31) { #if LN_EN Y_temp = -21.9*log(ntc) + 72.165; #else Y_temp = 0.0071*ntc*ntc - 1.128*ntc + 25.157; #endif } else if(ntc>18.67) { #if LN_EN Y_temp = -23.64*log(ntc) + 78.124; #else Y_temp = 0.0225*ntc*ntc - 2.087*ntc + 40.106; #endif } else if(ntc>11.63) { #if LN_EN Y_temp = -25.34*log(ntc) + 83.12; #else Y_temp = 0.0645*ntc*ntc - 3.6551*ntc + 54.762; #endif } else if(ntc>7.46) { #if LN_EN Y_temp = -27.04*log(ntc) + 87.292; #else Y_temp = 0.1713*ntc*ntc - 6.1452*ntc + 69.296; #endif } else if(ntc>4.92) { #if LN_EN Y_temp = -28.78*log(ntc) + 90.793; #else Y_temp = 0.4336*ntc*ntc - 10.078*ntc + 84.058; #endif } else if(ntc>3.32) { #if LN_EN Y_temp = -30.44*log(ntc) + 93.447; #else Y_temp = 1.041*ntc*ntc - 16.054*ntc + 98.768; #endif } else if(ntc>2.29) { #if LN_EN Y_temp = -32.61*log(ntc) + 96.028; #else Y_temp = 2.5397*ntc*ntc - 25.994*ntc + 115.26; #endif } else if(ntc>1.62) { #if LN_EN Y_temp = -34.62*log(ntc) + 97.711; #else Y_temp = 5.309*ntc*ntc - 38.634*ntc + 129.7; #endif } else if(ntc>1.17) { #if LN_EN Y_temp = -36.72*log(ntc) + 98.73; #else Y_temp = 10.952*ntc*ntc - 57.094*ntc + 144.8; #endif } else if(ntc>0.86) { #if LN_EN Y_temp = -38.68*log(ntc) + 99.026; #else Y_temp = 22.925*ntc*ntc - 84.916*ntc + 160.97; #endif } else if(ntc>0.64) { #if LN_EN Y_temp = -40.98*log(ntc) + 98.686; #else Y_temp = 43.412*ntc*ntc - 120.1*ntc + 176.09; #endif } else { #if LN_EN Y_temp = -42.74*log(ntc) + 97.929; #else Y_temp = 72.692*ntc*ntc - 158.46*ntc + 188.65; #endif } return Y_temp; } static float volt_to_temp_v2(unsigned int volt) { float Y_temp; float X_ntc; float ss=0.0f; ss = volt*139/39; X_ntc = 10*ss / ((1800-ss)-(volt/39));//10k pull up uart_printf("current ntc = %.02f K\r\n", X_ntc); Y_temp = ntc_to_Temp_v2(X_ntc); return Y_temp; } //description: //usb plug in ==> enter charging //usb plug out ==> stop charging and power down /** * LDO13, 1.8V output * on_off: 0---off, 1---on **/ void ql_set_cam_iovdd_output(unsigned char on_off) { Ningbo_Ldo_13_set_1_8(); Ningbo_Ldo_13_set(on_off); } //test code void ql_boot_get_battery_vol_test(void) { unsigned short bat_vol = 0; int ii = 0; int jj = 0; int kk = 0; while(1) { bat_vol = ql_get_battery_vol(); uart_printf("bat_vol:%d\r\n",bat_vol); for(ii=0;ii<2000;ii++) { for(jj=0;jj<10000;jj++); } if(kk++>20) { break; } } } #endif #endif