mtk 電池驅動流程詳解
mtk 電池驅動流程詳解
充電演算法,充9S停1S
電池溫度高於50,充電器電壓為>6.5V 停止充電,
充電電壓最大值是6500mV 最小值是4400mV 3.4V為開機電壓,電壓大於3.4V才能開機
// 獲得 BATSNS 引腳電壓 bat_vol = battery_meter_get_battery_voltage(KAL_TRUE); /* 獲得 PMIC 的 ISENSE 引腳電壓*/ Vsense = battery_meter_get_VSense(); if (upmu_is_chr_det() == KAL_TRUE) /* 獲得充電電流 */ ICharging = battery_meter_get_charging_current(); else ICharging = 0; //獲得充電資訊 /* 獲得充電器電壓 */ charger_vol = battery_meter_get_charger_voltage(); /* 通過獲得當前 NTC 電壓,查表並進行線性插值法,得到當前的溫度值 */ temperature = battery_meter_get_battery_temperature(); /* 這裡用來獲取電池 NTC 的電壓 */ temperatureV = battery_meter_get_tempV(); /* 獲得 下拉電阻與 NTC 並並聯的電壓 */ temperatureR = battery_meter_get_tempR(temperatureV); /* 獲得充電電流 */ BMT_status.ICharging = mt_battery_average_method(&batteryCurrentBuffer[0],ICharging, &icharging_sum, batteryIndex); // 獲得 BATSNS 引腳電壓 BMT_status.bat_vol = mt_battery_average_method(&batteryVoltageBuffer[0],bat_vol, &bat_sum, batteryIndex); /* 通過獲得當前 NTC 電壓,查表並進行線性插值法,得到當前的溫度值 */ BMT_status.temperature = mt_battery_average_method(&batteryTempBuffer[0],temperature, &temperature_sum, batteryIndex); BMT_status.Vsense = Vsense;/* 獲得 PMIC 的 ISENSE 引腳電壓*/ BMT_status.charger_vol = charger_vol; /* 獲得充電器電壓 */ BMT_status.temperatureV = temperatureV;/* 這裡用來獲取電池 NTC 的電壓 */ BMT_status.temperatureR = temperatureR;/* 獲得 下拉電阻與 NTC 並並聯的電壓 */ BMT_status.SOC = SOC; BMT_status.ZCV = ZCV;//開路電壓 BMT_status.CURRENT_NOW = BMT_status.IBattery;//當前充電電流 /* bat_thread_wakeup() 每 10s 喚醒一次,喚醒時設定 bat_meter_timeout = KAL_TRUE 這時候更新電池電量百分比 */ /* oam 演算法通過兩種方式更新電壓,去逼近真實的開路電壓,最終查表獲取近似真實的電量值百分比,方法 1,查表獲得電池百分比,方法 2,庫倫積分 以方法2獲得的引數補償方法 1 的值,具體方法見 oam_run()*/ // 6582 平臺用的計量方法【在 Battery_Charging_Introduction_for_customer_V1.0.pdf】 // SW FG演算法和HW FG演算法。事實上MTK平臺專案通常採用的是混合型演算法。 /* SW FG的核心 在於 通過兩種方式更新電壓,去逼近真實開路電壓 最終查表獲取近似真實的電量值。 ocv1 被假定為開路電壓 ocv2則是閉路電壓, D0 D1 D2 D3 D4 D5 代表不同的放電深度*/ /* 通過當前開路電壓 - 負載時電壓 = 當前電流 * 電池內阻 獲得當前電流值 */ oam_i_1 = (((oam_v_ocv_1 - vol_bat) * 1000) * 10) / oam_r_1; /* 0.1mA */ oam_i_2 = (((oam_v_ocv_2 - vol_bat) * 1000) * 10) / oam_r_2; /* 0.1mA */ /* 當前的變化電量值 = 當前電流 * 上次執行此函式到現在的時間 + 上次的電量值 */ oam_car_1 = (oam_i_1 * delta_time / 3600) + oam_car_1; /* 0.1mAh */ oam_car_2 = (oam_i_2 * delta_time / 3600) + oam_car_2; /* 0.1mAh */ /* 這裡使用的就是庫倫積分法: D1 = D0 + (-CAR)/Cmax 獲得當前的電池容量百分比 */ oam_d_1 = oam_d0 + (oam_car_1 * 100 / 10) / gFG_BATT_CAPACITY_aging; if (oam_d_1 < 0) oam_d_1 = 0; if (oam_d_1 > 100) oam_d_1 = 100; oam_d_2 = oam_d0 + (oam_car_2 * 100 / 10) / gFG_BATT_CAPACITY_aging; if (oam_d_2 < 0) oam_d_2 = 0; if (oam_d_2 > 100) oam_d_2 = 100;
//////////////////////////////////////////////////////////////////////////////////
// 整個程式的核心在這裡, 他使用了兩種方法更新電量:
1. 使用補償過的閉路電壓,查表獲得電量 【返回給使用者的】
2. 使用軟體庫倫積分,得到電量值 【用來校正的】
兩個方法相對獨立,但是在此處,方法 1 使用了 方法 2 的電流來進行較正!!!
//////////////////////////////////////////////////////////////////////////////////////
mtk_imp_tracking() 對閉合電壓補償後,當作開路電壓使用
通過對當前有負載的電池電壓進行補償,獲得當前開路電壓
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// BC1.1 充電協議,主要用來區分是插入的是 USB 還是充電器,如果是 USB 只能提供 500ma 充電,
// 如果是充電器,則可以大電流充電
/********* Step initial ***************/ hw_bc11_init(); static void hw_bc11_init(void) { msleep(300); Charger_Detect_Init(); //RG_BC11_BIAS_EN=1 upmu_set_rg_bc11_bias_en(0x1); //RG_BC11_VSRC_EN[1:0]=00 upmu_set_rg_bc11_vsrc_en(0x0); //RG_BC11_VREF_VTH = [1:0]=00 upmu_set_rg_bc11_vref_vth(0x0); //RG_BC11_CMP_EN[1.0] = 00 upmu_set_rg_bc11_cmp_en(0x0); //RG_BC11_IPU_EN[1.0] = 00 upmu_set_rg_bc11_ipu_en(0x0); //RG_BC11_IPD_EN[1.0] = 00 upmu_set_rg_bc11_ipd_en(0x0); //BC11_RST=1 upmu_set_rg_bc11_rst(0x1); //BC11_BB_CTRL=1 upmu_set_rg_bc11_bb_ctrl(0x1); //msleep(10); mdelay(50); /********* Step DCD ***************/ if(1 == hw_bc11_DCD()) { /********* Step A1 ***************/ if(1 == hw_bc11_stepA1()) { *(CHARGER_TYPE*)(data) = APPLE_2_1A_CHARGER; battery_xlog_printk(BAT_LOG_CRTI, "step A1 : Apple 2.1A CHARGER!\r\n"); } else { *(CHARGER_TYPE*)(data) = NONSTANDARD_CHARGER; battery_xlog_printk(BAT_LOG_CRTI, "step A1 : Non STANDARD CHARGER!\r\n"); } } else { /********* Step A2 ***************/ if(1 == hw_bc11_stepA2()) { /********* Step B2 ***************/ if(1 == hw_bc11_stepB2()) { *(CHARGER_TYPE*)(data) = STANDARD_CHARGER; battery_xlog_printk(BAT_LOG_CRTI, "step B2 : STANDARD CHARGER!\r\n"); } else { *(CHARGER_TYPE*)(data) = CHARGING_HOST; battery_xlog_printk(BAT_LOG_CRTI, "step B2 : Charging Host!\r\n"); } } else { *(CHARGER_TYPE*)(data) = STANDARD_HOST; battery_xlog_printk(BAT_LOG_CRTI, "step A2 : Standard USB Host!\r\n"); } } /********* Finally setting *******************************/ hw_bc11_done(); static void hw_bc11_done(void) { //RG_BC11_VSRC_EN[1:0]=00 upmu_set_rg_bc11_vsrc_en(0x0); //RG_BC11_VREF_VTH = [1:0]=0 upmu_set_rg_bc11_vref_vth(0x0); //RG_BC11_CMP_EN[1.0] = 00 upmu_set_rg_bc11_cmp_en(0x0); //RG_BC11_IPU_EN[1.0] = 00 upmu_set_rg_bc11_ipu_en(0x0); //RG_BC11_IPD_EN[1.0] = 00 upmu_set_rg_bc11_ipd_en(0x0); //RG_BC11_BIAS_EN=0 upmu_set_rg_bc11_bias_en(0x0); Charger_Detect_Release(); void Charger_Detect_Release(void) { /* RG_USB20_BC11_SW_EN = 1'b0 */ USBPHY_CLR8(0x1a, 0x80); udelay(1); //4 14. turn off internal 48Mhz PLL. usb_enable_clock(false); printk("Charger_Detect_Release\n"); } if(Enable_BATDRV_LOG == BAT_LOG_FULL) { battery_xlog_printk(BAT_LOG_FULL, "hw_bc11_done() \r\n"); hw_bc11_dump_register(); } } charging_type_det_done = KAL_TRUE; g_charger_type = *(CHARGER_TYPE*)(data); #endif return status; } BMT_status.charger_type = CHR_Type_num; } #endif mutex_unlock(&charger_type_mutex); return BMT_status.charger_type; }
/*
概念: ZCV:開路電壓 OCV: 開路電壓 VC:閉路電壓 CAR:庫倫計 DOD: 放電深度,100-DOD 即電容容量 Cmax/Qmax: 電池容量 初始化init------------pre_cc mode/CC Mode topoff mode(CV mode)切換模式 Battery Full Battery hold 1 初始化安全 1。做充電器的保護, 1。做充電器的保護 2>, 1電池百分比總是顯示100% 當充電器存在時,檢查呼叫狀態, 充電器 2。如果(1)失敗如果充電器電壓為>6.5V 2。如果(1)失敗如果充電器電壓為>6.5V 注意:當充電,電池百分比仍然是100%。 1。如果呼叫活動,Vbat>4.05V停止充電注意:避免熱的問題, 2 檢查V_bat電壓 如果電池溫度為>60c,則停止充電 如果電池溫度為>60C,則停止充電 是否大於3.4V決定 3.如果(2)通過,做充電演算法:充電9秒,3.如果(2)通過,做充電演算法。:充電10S 進入CC模式, 停止充電1秒。 檢查UI SOC是否等於100 決定進入電池滿電狀態
相關檔案關係:
Battery_common.c (s:\i841\mediatek\kernel\drivers\power) // 充電邏輯檔案
Charging_hw_pmic.c (s:\i841\mediatek\platform\mt6582\kernel\drivers\power) // 具體的充電晶片,相關電池引數檢測
Linear_charging.c (s:\i841\mediatek\kernel\drivers\power) // 充電狀態控制,內部 PMIC
Switch_charging.c (s:\i841\mediatek\kernel\drivers\power) // 充電狀態控制,外部 Charge IC
//////////////////////////////////////////////////////////////////////////////
// 【核心充電執行緒】
kthread_run(bat_thread_kthread, NULL, "bat_thread_kthread");
// 設定定時器超時時間
ktime_t ktime = ktime_set(3, 0); // 10s, 10* 1000 ms
while (1) {
// 這個是核心演算法
BAT_thread();
///////////////////////////////////////////////////////////////////////////////////////////
// 0. 第一次執行時執行,獲得開機顯示電量,初始化電池演算法 oam 引數
// 開機時就會執行,只會執行一次,對電池演算法 oam 方案進行初始化, 並獲得開機顯示電量百分比
if(battery_meter_initilized == KAL_FALSE)
{
// 進行的一系列的電池引數與溫度對應關係的表格的初始化,並根據電池當前電壓,hw ocv 取一個較合適值,
// 取合適值對應容量,再與 RTC 儲存容量比較,選擇一個合適量,為開機電池容量,最後初始化 oam 演算法引數
battery_meter_initial()
MTK_MULTI_BAT_PROFILE_SUPPORT
//電池曲線電池容量和在這裡呼叫
fgauge_get_profile_id();
//開adc通道取電壓值 時間單位是us
IMM_GetOneChannelValue_Cali(BATTERY_ID_CHANNEL_NUM, &id_volt)
//開adc通道讀取通過adc通道把模擬訊號轉換成數字訊號
return IMM_auxadc_GetOneChannelValue_Cali(Channel, voltage)
IMM_auxadc_GetOneChannelValue(Channel, data, &rawvalue);/* HAL API */
//使能一個時鐘訊號
clk_prepare_enable(clk_auxadc);
/* step1 check con2 if auxadc is busy step1如果auxadc忙,就檢查con2*/
while (AUXADC_DRV_ReadReg16((u16 *)AUXADC_CON2) & 0x01)
mdelay(1);
idle_count++;
if (idle_count > 30) {//當大於30us時
/* wait for idle time out/* wait for idle time out 等待空閒時間*/
pr_err("[adc_api]: wait for auxadc idle time out\n");
/* step2 clear bit 清除位*/
if (adc_auto_set == 0) {
/* clear bit */
AUXADC_DRV_ClearBits16((u16 *)AUXADC_CON1, (1 << dwChannel));
}
/* step3 read channel and make sure old ready bit ==0
/* step3讀取通道,確保老的就緒位==0*/
while (AUXADC_DRV_ReadReg16(AUXADC_DAT0 + dwChannel * 0x04) & (1 << 12)) {
pr_debug("[adc_api]: wait for channel[%d] ready bit clear\n", dwChannel);
mdelay(1);
data_ready_count++;
if (data_ready_count > 30) {
/* wait for idle time out等待空閒時間*/
pr_err("[adc_api]: wait for channel[%d] ready bit clear time out\n",
dwChannel);
/* step4 set bit to trigger sample
4 設定位觸發樣本 */
if (adc_auto_set == 0)
AUXADC_DRV_SetBits16((u16 *)AUXADC_CON1, (1 << dwChannel));
/* step5 read channel and make sure ready bit ==1
5 讀取通道並確保準備位==1*/
udelay(25); /* we must dealay here for hw sample cahnnel data 我們必須在此處理cahnnel樣本資料*/
while (0 == (AUXADC_DRV_ReadReg16(AUXADC_DAT0 + dwChannel * 0x04) & (1 << 12))) {
pr_debug("[adc_api]: wait for channel[%d] ready bit ==1\n", dwChannel);
mdelay(1);
data_ready_count++;
if (data_ready_count > 30) {
/* wait for idle time out 等待空閒時間*/
pr_err("[adc_api]: wait for channel[%d] data ready time out\n", dwChannel);
mutex_unlock(&mutex_get_cali_value);
return -3;
}
}
/* step6 read data 讀取資料*/
channel[dwChannel] = AUXADC_DRV_ReadReg16(AUXADC_DAT0 + dwChannel * 0x04) & 0x0FFF;
//得到通過的資料
mt_auxadc_get_cali_data(channel[dwChannel], data, true);
SOC_BY_AUXADC
//電池曲線的表的資料呼叫
table_init();
//合電池曲線兩個表的結構體,電池曲線 一個是百分比和電壓 一個是電阻和電壓
struct battery_profile_struct *profile_p;
struct r_profile_struct *profile_p_r_table;
//獲取當前溫度
int temperature = force_get_tbat(KAL_FALSE);
/* Re-constructure r-table profile according to current temperature */
//根據當前溫度重新構造r-table剖面
profile_p_r_table = fgauge_get_profile_r_table(batt_meter_cust_data.temperature_t);
struct r_profile_struct *fgauge_get_profile_r_table(unsigned int temperature)
switch (temperature) {
case batt_meter_cust_data.temperature_t0:
return &r_profile_t0[g_fg_battery_id][0];
/*break;*/
case batt_meter_cust_data.temperature_t1:
return &r_profile_t1[g_fg_battery_id][0];
/*break;*/
case batt_meter_cust_data.temperature_t2:
return &r_profile_t2[g_fg_battery_id][0];
/*break;*/
case batt_meter_cust_data.temperature_t3:
return &r_profile_t3[g_fg_battery_id][0];
/*break;*/
case batt_meter_cust_data.temperature_t:
return &r_profile_temperature[0];
/*break;*/
default:
return NULL;
/*break;*/
}
if (profile_p_r_table == NULL)
bm_print(BM_LOG_CRTI,
"[FGADC] fgauge_get_profile_r_table : create table fail !\r\n");
//根據當前溫度重新構造r-table剖面
fgauge_construct_r_table_profile(temperature, profile_p_r_table);
SOC_BY_HW_FG
//電池容量的初始化
fgauge_initialization();
/* 1. HW initialization HW初始化 */
ret = battery_meter_ctrl(BATTERY_METER_CMD_HW_FG_INIT, NULL);
/* 2. SW algorithm initialization SW演算法初始化 */
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_OCV, &gFG_voltage);//電池控制函式ocv開路電壓
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT, &gFG_current);//電流
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CAR, &gFG_columb);
gFG_temp = force_get_tbat(KAL_FALSE);//獲取溫度
gFG_capacity = fgauge_read_capacity(0);//讀取容量
gFG_capacity_by_c_init = gFG_capacity;//初始化容量
gFG_capacity_by_c = gFG_capacity;
gFG_capacity_by_v = gFG_capacity;
gFG_DOD0 = 100 - gFG_capacity;//放電深度的演算法
bm_print(BM_LOG_CRTI, "[fgauge_initialization] gFG_DOD0 =%d %d\n", gFG_DOD0, gFG_capacity);
gFG_BATT_CAPACITY = fgauge_get_Q_max(gFG_temp);//獲取最大容量
gFG_BATT_CAPACITY_init_high_current = fgauge_get_Q_max_high_current(gFG_temp);//初始化最大容量的高電流值
gFG_BATT_CAPACITY_aging = fgauge_get_Q_max(gFG_temp);//獲取最大容量
ret = battery_meter_ctrl(BATTERY_METER_CMD_DUMP_REGISTER, NULL);//控制函式控制
bm_print(BM_LOG_CRTI,
"[fgauge_initialization] Done HW_OCV:%d FG_Current:%d FG_CAR:%d tmp=%d capacity=%d Qmax=%d\n",
gFG_voltage, gFG_current, gFG_columb, gFG_temp, gFG_capacity, gFG_BATT_CAPACITY);
//電池容量演算法執行的初始化
fgauge_algo_run_init();
#ifdef INIT_SOC_BY_SW_SOC //如沒插充電器或者處於關機狀態 則停止為vbat測量充電
kal_bool charging_enable = KAL_FALSE; //沒插充電器
#if defined(CONFIG_MTK_KERNEL_POWER_OFF_CHARGING) && !defined(SWCHR_POWER_PATH)//處於關機
if (get_boot_mode() != LOW_POWER_OFF_CHARGING_BOOT)//
#endif
/*stop charging for vbat measurement 停止為vbat測量充電*/
battery_charging_control(CHARGING_CMD_ENABLE, &charging_enable);
msleep(50);
#endif
/* 1. Get Raw Data 得到原始資料*/
gFG_voltage = battery_meter_get_battery_voltage(KAL_TRUE);//獲取原始資料的電壓
gFG_voltage_init = gFG_voltage;//電壓賦值
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT, &gFG_current);//電流控制
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT_SIGN, &gFG_Is_Charging);//充電控制
//以下是電壓的一些演算法
gFG_voltage = gFG_voltage + fgauge_compensate_battery_voltage_recursion(gFG_voltage, 5); /* mV */
gFG_voltage = gFG_voltage + batt_meter_cust_data.ocv_board_compesate;
bm_print(BM_LOG_CRTI, "[FGADC] SWOCV : %d,%d,%d,%d,%d,%d\n",
gFG_voltage_init, gFG_voltage, gFG_current, gFG_Is_Charging, gFG_resistance_bat,
gFG_compensate_value);//初始化的電壓,電壓,充電電流 電阻 抵消值
#ifdef INIT_SOC_BY_SW_SOC
charging_enable = KAL_TRUE;
battery_charging_control(CHARGING_CMD_ENABLE, &charging_enable); //如果有插充電器,開始充電
#endif
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CAR, &gFG_columb);
/* 1.1 Average FG_voltage FG的平均電壓*/
for (i = 0; i < batt_meter_cust_data.fg_vbat_average_size; i++)
FGvbatVoltageBuffer[i] = gFG_voltage;
FGbatteryVoltageSum = gFG_voltage * batt_meter_cust_data.fg_vbat_average_size;
gFG_voltage_AVG = gFG_voltage;
#ifdef Q_MAX_BY_CURRENT
/* 1.2 Average FG_currentFG平均電流 */
for (i = 0; i < FG_CURRENT_AVERAGE_SIZE; i++)
FGCurrentBuffer[i] = gFG_current;
FGCurrentSum = gFG_current * FG_CURRENT_AVERAGE_SIZE;
gFG_current_AVG = gFG_current;
#endif
/* 2. Calculate battery capacity by VBAT 用VBAT計算電池容量*/
gFG_capacity_by_v = fgauge_read_capacity_by_v(gFG_voltage);
gFG_capacity_by_v_init = gFG_capacity_by_v;
/* 3. Calculate battery capacity by Coulomb Counter 用庫侖計數器計算電池容量 */
gFG_capacity_by_c = fgauge_read_capacity(1);
/* 4. update DOD0 更新DOD0 */
dod_init();
gFG_current_auto_detect_R_fg_count = 0;
for (i = 0; i < 10; i++) {
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT, &gFG_current);
gFG_current_auto_detect_R_fg_total += gFG_current;
gFG_current_auto_detect_R_fg_count++;
}
/* double check 再次確認*/
if (gFG_current_auto_detect_R_fg_total <= 0) {
bm_print(BM_LOG_CRTI, "gFG_current_auto_detect_R_fg_total=0, need double check\n");
gFG_current_auto_detect_R_fg_count = 0;
for (i = 0; i < 10; i++) {
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT, &gFG_current);
gFG_current_auto_detect_R_fg_total += gFG_current;
gFG_current_auto_detect_R_fg_count++;
}
}
//自動檢測電池曲線表中的電阻和電壓 結果值
gFG_current_auto_detect_R_fg_result =
gFG_current_auto_detect_R_fg_total / gFG_current_auto_detect_R_fg_count;
#if !defined(DISABLE_RFG_EXIST_CHECK)
if (gFG_current_auto_detect_R_fg_result <= batt_meter_cust_data.current_detect_r_fg) {
g_auxadc_solution = 1;
bm_print(BM_LOG_CRTI,
"[FGADC] Detect NO Rfg, use AUXADC report. (%d=%d/%d)(%d)\r\n",
gFG_current_auto_detect_R_fg_result, gFG_current_auto_detect_R_fg_total,
gFG_current_auto_detect_R_fg_count, g_auxadc_solution);
} else {
if (g_auxadc_solution == 0) {
g_auxadc_solution = 0;
bm_print(BM_LOG_CRTI,
"[FGADC] Detect Rfg, use FG report. (%d=%d/%d)(%d)\r\n",
gFG_current_auto_detect_R_fg_result,
gFG_current_auto_detect_R_fg_total,
gFG_current_auto_detect_R_fg_count, g_auxadc_solution);
} else {
bm_print(BM_LOG_CRTI,
"[FGADC] Detect Rfg, but use AUXADC report. due to g_auxadc_solution=%d \r\n",
g_auxadc_solution);
}
}
#endif
/* 5. Logging 記錄*/
bm_print(BM_LOG_CRTI,
"[FGADC] %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\r\n",
gFG_Is_Charging, gFG_current, gFG_columb, gFG_voltage, gFG_capacity_by_v,
gFG_capacity_by_c, gFG_capacity_by_c_init, gFG_BATT_CAPACITY,
gFG_BATT_CAPACITY_aging, gFG_compensate_value, gFG_ori_voltage,
batt_meter_cust_data.ocv_board_compesate, batt_meter_cust_data.r_fg_board_slope,
gFG_voltage_init, batt_meter_cust_data.minerroroffset, gFG_DOD0, gFG_DOD1,
batt_meter_cust_data.car_tune_value, batt_meter_cust_data.aging_tuning_value);
update_fg_dbg_tool_value();
g_fg_dbg_bat_volt = gFG_voltage_init;
if (gFG_Is_Charging == KAL_TRUE)
g_fg_dbg_bat_current = 1 - gFG_current - 1;
else
g_fg_dbg_bat_current = gFG_current;
g_fg_dbg_bat_zcv = gFG_voltage;
g_fg_dbg_bat_temp = gFG_temp;
g_fg_dbg_bat_r = gFG_resistance_bat;
g_fg_dbg_bat_car = gFG_columb;
g_fg_dbg_bat_qmax = gFG_BATT_CAPACITY_aging;
g_fg_dbg_d0 = gFG_DOD0;
g_fg_dbg_d1 = gFG_DOD1;
g_fg_dbg_percentage = bat_get_ui_percentage();
g_fg_dbg_percentage_fg = gFG_capacity_by_c;
g_fg_dbg_percentage_voltmode = gfg_percent_check_point;
SOC_BY_SW_FG
table_init();//電池曲線的表的資料呼叫
oam_init();//oam演算法的初始化
int ret = 0;
signed int vbat_capacity = 0;
kal_bool charging_enable = KAL_FALSE;
/*stop charging for vbat measurement 停止為vbat測量充電*/
battery_charging_control(CHARGING_CMD_ENABLE, &charging_enable);
msleep(50);
g_booting_vbat = 5; /* set avg times 設定avg時間*/
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_OCV, &gFG_voltage);
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_ADC_V_BAT_SENSE, &g_booting_vbat);
gFG_capacity_by_v = fgauge_read_capacity_by_v(gFG_voltage);
vbat_capacity = fgauge_read_capacity_by_v(g_booting_vbat);
if (bat_is_charger_exist() == KAL_TRUE) {
bm_print(BM_LOG_CRTI, "[oam_init_inf] gFG_capacity_by_v=%d, vbat_capacity=%d,\n",
gFG_capacity_by_v, vbat_capacity);
/* to avoid plug in cable without battery, then plug in battery to make hw soc = 100% */
//為了避免沒有電池的情況下插入電纜,然後插入電池使hw soc = 100%
/* if the difference bwtween ZCV and vbat is too large, using vbat instead ZCV */
//如果ZCV和vbat之間的差異太大,用vbat代替ZCV
if (((gFG_capacity_by_v == 100)
&& (vbat_capacity < batt_meter_cust_data.cust_poweron_max_vbat_tolrance))
|| (abs(gFG_capacity_by_v - vbat_capacity) >
batt_meter_cust_data.cust_poweron_delta_vbat_tolrance)) {
bm_print(BM_LOG_CRTI,
"[oam_init] fg_vbat=(%d), vbat=(%d), set fg_vat as vat\n",
gFG_voltage, g_booting_vbat);
gFG_voltage = g_booting_vbat;
gFG_capacity_by_v = vbat_capacity;
}
}
gFG_capacity_by_v_init = gFG_capacity_by_v;
dod_init();
gFG_BATT_CAPACITY_aging = fgauge_get_Q_max(force_get_tbat(KAL_FALSE));
/* oam_v_ocv_1 = gFG_voltage; */
/* oam_v_ocv_2 = gFG_voltage; */
oam_v_ocv_init = fgauge_read_v_by_d(gFG_DOD0);
oam_v_ocv_2 = oam_v_ocv_1 = oam_v_ocv_init;
g_vol_bat_hw_ocv = gFG_voltage;
/* vbat = 5; //set avg times */
/* ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_ADC_V_BAT_SENSE, &vbat); */
/* oam_r_1 = fgauge_read_r_bat_by_v(vbat); */
oam_r_1 = fgauge_read_r_bat_by_v(gFG_voltage);
oam_r_2 = oam_r_1;
oam_d0 = gFG_DOD0;
oam_d_5 = oam_d0;
oam_i_ori = gFG_current;
g_d_hw_ocv = oam_d0;
if (oam_init_i == 0) {
bm_print(BM_LOG_CRTI,
"[oam_init] oam_v_ocv_1,oam_v_ocv_2,oam_r_1,oam_r_2,oam_d0,oam_i_ori\n");
oam_init_i = 1;
}
bm_print(BM_LOG_CRTI, "[oam_init] %d,%d,%d,%d,%d,%d\n",
oam_v_ocv_1, oam_v_ocv_2, oam_r_1, oam_r_2, oam_d0, oam_i_ori);
bm_print(BM_LOG_CRTI, "[oam_init_inf] hw_OCV, hw_D0, RTC, D0, oam_OCV_init, tbat\n");
bm_print(BM_LOG_CRTI,
"[oam_run_inf] oam_OCV1, oam_OCV2, vbat, I1, I2, R1, R2, Car1, Car2,qmax, tbat\n");
bm_print(BM_LOG_CRTI, "[oam_result_inf] D1, D2, D3, D4, D5, UI_SOC\n");
bm_print(BM_LOG_CRTI, "[oam_init_inf] %d, %d, %d, %d, %d, %d\n",
gFG_voltage, (100 - fgauge_read_capacity_by_v(gFG_voltage)), g_rtc_fg_soc,
gFG_DOD0, oam_v_ocv_init, force_get_tbat(KAL_FALSE));
charging_enable = KAL_TRUE;
battery_charging_control(CHARGING_CMD_ENABLE, &charging_enable)
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// 1. 判斷是插入的是否充電器還是電腦 USB,看能不能進行充電
// 如果連線的 USB 線為 USB 充電線,或者電腦 USB 線,則開啟 USB,
// 這裡會通過 BC1.1 來判斷是電腦 USB 還是 USB 充電器,來決定充電電流
// 否則連線的不是充電線或者 USB 作為一個從裝置使用,要斷開 USB?
mt_battery_charger_detect_check();
// 1. 判斷是插入的是否充電器還是電腦 USB,看能不能進行充電
// 如果連線的 USB 線為 USB 充電線,或者電腦 USB 線,則開啟 USB,
// 這裡會通過 BC1.1 來判斷是電腦 USB 還是 USB 充電器,來決定充電電流
// 否則連線的不是充電線或者 USB 作為一個從裝置使用,要斷開 USB?
#ifdef CONFIG_MTK_BQ25896_SUPPORT
/*New low power feature of MT6531: disable charger CLK without CHARIN.
* MT6351 API abstracted in charging_hw_bw25896.c. Any charger with MT6351 needs to set this.
* Compile option is not limited to CONFIG_MTK_BQ25896_SUPPORT.
* PowerDown = 0
新的低功耗功能的MT6531:禁用充電器CLK沒有CHARIN。
* MT6351 API抽象在charging_hw_bw25896.c。任何MT6351的充電器都需要設定這個。
編譯選項不限於CONFIG_MTK_BQ25896_SUPPORT。
* PowerDown = 0
*/
unsigned int pwr;
#endif
if (upmu_is_chr_det() == KAL_TRUE) {
wake_lock(&battery_suspend_lock);
#if !defined(CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT)
//判斷充電器是否存在
BMT_status.charger_exist = KAL_TRUE;
#endif
#if defined(CONFIG_MTK_WIRELESS_CHARGER_SUPPORT)
//充電型別的檢測
mt_charger_type_detection();
if ((BMT_status.charger_type == STANDARD_HOST)
|| (BMT_status.charger_type == CHARGING_HOST)) {
//開啟 USB
mt_usb_connect();
}
#else
#if !defined(CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT)
if (BMT_status.charger_type == CHARGER_UNKNOWN) {
#else
if ((BMT_status.charger_type == CHARGER_UNKNOWN) &&
(DISO_data.diso_state.cur_vusb_state == DISO_ONLINE)) {
#endif
mt_charger_type_detection();
if ((BMT_status.charger_type == STANDARD_HOST)
|| (BMT_status.charger_type == CHARGING_HOST)) {
mt_usb_connect();
}
}
#endif
#ifdef CONFIG_MTK_BQ25896_SUPPORT
/*New low power feature of MT6531: disable charger CLK without CHARIN.
* MT6351 API abstracted in charging_hw_bw25896.c. Any charger with MT6351 needs to set this.
* Compile option is not limited to CONFIG_MTK_BQ25896_SUPPORT.
* PowerDown = 0
新的低功耗功能的MT6531:禁用充電器CLK沒有CHARIN。
* MT6351 API抽象在charging_hw_bw25896.c。任何MT6351的充電器都需要設定這個。
編譯選項不限於CONFIG_MTK_BQ25896_SUPPORT。
* PowerDown = 0
*/
pwr = 0;
battery_charging_control(CHARGING_CMD_SET_CHRIND_CK_PDN, &pwr);
#endif
battery_log(BAT_LOG_FULL, "[BAT_thread]Cable in, CHR_Type_num=%d\r\n",
BMT_status.charger_type);
} else {
wake_unlock(&battery_suspend_lock);
BMT_status.charger_exist = KAL_FALSE;
BMT_status.charger_type = CHARGER_UNKNOWN;
BMT_status.bat_full = KAL_FALSE;
BMT_status.bat_in_recharging_state = KAL_FALSE;
BMT_status.bat_charging_state = CHR_PRE;
BMT_status.total_charging_time = 0;
BMT_status.PRE_charging_time = 0;
BMT_status.CC_charging_time = 0;
BMT_status.TOPOFF_charging_time = 0;
BMT_status.POSTFULL_charging_time = 0;
battery_log(BAT_LOG_CRTI, "[BAT_thread]Cable out \r\n");
mt_usb_disconnect();
#ifdef CONFIG_MTK_BQ25896_SUPPORT
/*New low power feature of MT6531: disable charger CLK without CHARIN.
* MT6351 API abstracted in charging_hw_bw25896.c. Any charger with MT6351 needs to set this.
* Compile option is not limited to CONFIG_MTK_BQ25896_SUPPORT.
* PowerDown = 1
新的低功耗功能的MT6531:禁用充電器CLK沒有CHARIN。
* MT6351 API抽象在charging_hw_bw25896.c。任何MT6351的充電器都需要設定這個。
編譯選項不限於CONFIG_MTK_BQ25896_SUPPORT。
*關機= 1
*/
pwr = 1;
battery_charging_control(CHARGING_CMD_SET_CHRIND_CK_PDN, &pwr);
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////////
// 2. 通過具體的充電晶片來獲得電池資訊,充電資訊, 獲得電池電量百分比
// 通過 oam 演算法,獲得電量百分比
mt_battery_GetBatteryData();
//獲得電池資訊
bat_vol = battery_meter_get_battery_voltage(KAL_TRUE);
Vsense = battery_meter_get_VSense();//來限制輸出電流
if (upmu_is_chr_det() == KAL_TRUE)
ICharging = battery_meter_get_charging_current();//獲取當前的充電電流
else
ICharging = 0;
//獲得充電資訊
charger_vol = battery_meter_get_charger_voltage();//獲取充電電壓
temperature = battery_meter_get_battery_temperature();//獲取充電溫度
temperatureV = battery_meter_get_tempV();//獲取充電溫度V
temperatureR = battery_meter_get_tempR(temperatureV);//獲取充電溫度R
if (bat_meter_timeout == KAL_TRUE || bat_spm_timeout == TRUE || fg_wake_up_bat == KAL_TRUE) {
// 獲得電池電量百分比
SOC = battery_meter_get_battery_percentage();
/* if (bat_spm_timeout == true) */
/* BMT_status.UI_SOC = battery_meter_get_battery_percentage(); */
bat_meter_timeout = KAL_FALSE;
bat_spm_timeout = FALSE;
} else {
if (previous_SOC == -1)
SOC = battery_meter_get_battery_percentage();
else
SOC = previous_SOC;
}
ZCV = battery_meter_get_battery_zcv();//獲取開路電壓
BMT_status.ICharging =
mt_battery_average_method(BATTERY_AVG_CURRENT, &batteryCurrentBuffer[0], ICharging,
&icharging_sum, batteryIndex);//求電流的平均演算法
if (previous_SOC == -1 && bat_vol <= batt_cust_data.v_0percent_tracking) {
battery_log(BAT_LOG_CRTI,
"battery voltage too low, use ZCV to init average data.\n");
BMT_status.bat_vol =
mt_battery_average_method(BATTERY_AVG_VOLT, &batteryVoltageBuffer[0], ZCV,
&bat_sum, batteryIndex);//求電壓的平均演算法
} else {
BMT_status.bat_vol =
mt_battery_average_method(BATTERY_AVG_VOLT, &batteryVoltageBuffer[0], bat_vol,
&bat_sum, batteryIndex);
}
if (battery_cmd_thermal_test_mode == 1) {
battery_log(BAT_LOG_CRTI, "test mode , battery temperature is fixed.\n"); //測試模式,電池溫度是固定的。
} else {
BMT_status.temperature =
mt_battery_average_method(BATTERY_AVG_TEMP, &batteryTempBuffer[0], temperature,
&temperature_sum, batteryIndex);
}
//電池狀態的初始化
BMT_status.Vsense = Vsense;
BMT_status.charger_vol = charger_vol;
BMT_status.temperatureV = temperatureV;
BMT_status.temperatureR = temperatureR;
BMT_status.SOC = SOC;
BMT_status.ZCV = ZCV;
BMT_status.CURRENT_NOW = BMT_status.IBattery;
if (BMT_status.charger_exist == KAL_FALSE) {
signed int soc_tmp = BMT_status.SOC;
if (soc_tmp > previous_SOC && previous_SOC >= 0)
BMT_status.SOC = previous_SOC;
}
previous_SOC = BMT_status.SOC;
batteryIndex++;
if (batteryIndex >= BATTERY_AVERAGE_SIZE)
batteryIndex = 0;
if (g_battery_soc_ready == KAL_FALSE)
g_battery_soc_ready = KAL_TRUE;
battery_log(BAT_LOG_CRTI,
"AvgVbat=(%d,%d),AvgI=(%d,%d),VChr=%d,AvgT=(%d,%d),SOC=(%d,%d),UI_SOC=%d,ZCV=%d bcct:%d:%d I:%d\n",
BMT_status.bat_vol, bat_vol, BMT_status.ICharging, ICharging,
BMT_status.charger_vol, BMT_status.temperature, temperature,
previous_SOC, BMT_status.SOC, BMT_status.UI_SOC, BMT_status.ZCV,
g_bcct_flag, get_usb_current_unlimited(), get_bat_charging_current_level());
////////////////////////////////////////////////////////////////////////////////////////////////////////
// 3. 電池溫度保護
// 電池溫度檢查,如果溫度超過 60 度,關機重啟
mt_battery_thermal_check();
BMT_status.temperature = battery_cmd_thermal_test_mode_value;//獲取當前電池溫度
if (BMT_status.temperature >= 60) {// 電池溫度檢查,如果溫度超過 60 度,關機重啟
#if defined(CONFIG_MTK_JEITA_STANDARD_SUPPORT)
/* ignore default rule 忽略預設規則*/
#else
if (BMT_status.temperature >= 60) {// 電池溫度檢查,如果溫度超過 60 度,關機重啟
#if defined(CONFIG_POWER_EXT)
battery_log(BAT_LOG_CRTI,
"[BATTERY] CONFIG_POWER_EXT, no update battery update power down.\n");
#else
{
if ((g_platform_boot_mode == META_BOOT)
|| (g_platform_boot_mode == ADVMETA_BOOT)
|| (g_platform_boot_mode == ATE_FACTORY_BOOT)) {//繞過溫度檢查
battery_log(BAT_LOG_FULL,
"[BATTERY] boot mode = %d, bypass temperature check\n",
g_platform_boot_mode);
} else {
struct battery_data *bat_data = &battery_main;
struct power_supply *bat_psy = bat_data->psy;
battery_log(BAT_LOG_CRTI,
"[Battery] Tbat(%d)>=60, system need power down.\n",
BMT_status.temperature);
bat_data->BAT_CAPACITY = 0;
power_supply_changed(bat_psy);
if (BMT_status.charger_exist == KAL_TRUE) {
/* can not power down due to charger exist, so need reset system
忽略由於充電器的存在而導致的斷電,因此需要復位 */
orderly_reboot();
}
/* avoid SW no feedback 避免軟體無反饋*/
orderly_poweroff(true);
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// 4. 電池狀態檢查
// 對電池狀態進行檢查,如果有問題,則會呼叫 printk() 進行列印
mt_battery_notify_check();
g_BatteryNotifyCode = 0x0000;
if (g_BN_TestMode == 0x0000) { /* for normal case 對於正常情況*/
battery_log(BAT_LOG_FULL, "[BATTERY] mt_battery_notify_check\n");
mt_battery_notify_VCharger_check();
mt_battery_notify_VBatTemp_check();
mt_battery_notify_ICharging_check();
mt_battery_notify_VBat_check();
mt_battery_notify_TotalChargingTime_check();
} else { /* for UI test */
// 對電池狀態進行檢查,如果有問題,則會呼叫 printk() 進行列印
mt_battery_notify_UI_test();
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// 5. 呼叫具本的硬體相關函式進行充電,充電時會進行 CC/CV 之類的狀態機切換就是在這裡進行的
// 如果存在充電線,則呼叫具體充電晶片相關的函式進行充電
if( BMT_status.charger_exist == KAL_TRUE )
{
// 檢查電池狀態,設定到 BMT_status.bat_charging_state 中
mt_battery_CheckBatteryStatus();
// 檢查電池狀態,設定到 BMT_status.bat_charging_state 中
static void mt_battery_CheckBatteryStatus(void)
{
battery_log(BAT_LOG_FULL, "[mt_battery_CheckBatteryStatus] cmd_discharging=(%d)\n",
cmd_discharging);
if (cmd_discharging == 1) {//檢查到沒有插充電器
battery_log(BAT_LOG_CRTI,
"[mt_battery_CheckBatteryStatus] cmd_discharging=(%d)\n",
cmd_discharging);
BMT_status.bat_charging_state = CHR_ERROR;
battery_charging_control(CHARGING_CMD_SET_ERROR_STATE, &cmd_discharging);
return;
} else if (cmd_discharging == 0) {//檢查到有插充電器
BMT_status.bat_charging_state = CHR_PRE;
battery_charging_control(CHARGING_CMD_SET_ERROR_STATE, &cmd_discharging);
cmd_discharging = -1;
}
if (mt_battery_CheckBatteryTemp() != PMU_STATUS_OK) {//檢查電池溫度
BMT_status.bat_charging_state = CHR_ERROR;
return;
}
if (mt_battery_CheckChargerVoltage() != PMU_STATUS_OK) {//檢查電壓
BMT_status.bat_charging_state = CHR_ERROR;
return;
}
#if defined(STOP_CHARGING_IN_TAKLING)
if (mt_battery_CheckCallState() != PMU_STATUS_OK) {//檢查呼叫狀態
BMT_status.bat_charging_state = CHR_HOLD;
return;
}
#endif
if (mt_battery_CheckChargingTime() != PMU_STATUS_OK) {//檢查充電時間
BMT_status.bat_charging_state = CHR_ERROR;
return;
}
// 充電策略,這裡有兩個檔案: switch_charging.c 和 linear_charging.c
// 他們的關係是,如果定義了任一外部充電 IC,則選擇 switch_charging.c 的函式,否則就是 linear_charging.c 的函式
// 這裡就是呼叫具體的晶片的充電相關函式進行充電
mt_battery_charging_algorithm(); //如果定義了任一外部充電 IC,則選擇 switch_charging.c 的函式,否則就是 linear_charging.c 的函式