Files
banban/ql-bootloader/common/src/ql_boot_power.c
T

575 lines
13 KiB
C

/*================================================================
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<s*20;i++)
{
mdelay(1000);
}
}
#ifdef ASR_PLATFORM_CRANEL
/**************** USB charge API ********************/
extern struct chargeManagerT chargeManager[8];
unsigned char ql_get_vbus_state(void)
{
return PM812_VBUS_IS_AVAILABLE();
}
static void quec_adc_read_bat(unsigned short * vbat)
{
unsigned short meas_val;
unsigned short vol_GPADC, vol_cali;
unsigned short vbat_base;
meas_val = guilin_read_volt_meas_val(GUILIN_VINLDO_AVE_REG); // Read the VSYS(Vbat)
vol_GPADC = (unsigned short) ((meas_val * 6450) / 4096);
vbat_base = 3700;
if (vol_GPADC >= 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