6db4831e98
Android 14
1966 lines
75 KiB
C
1966 lines
75 KiB
C
/*
|
|
* sec_battery_thermal.c
|
|
* Samsung Mobile Battery Driver
|
|
*
|
|
* Copyright (C) 2021 Samsung Electronics
|
|
*
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
#include "sec_battery.h"
|
|
#include "battery_logger.h"
|
|
|
|
#if IS_ENABLED(CONFIG_MUIC_NOTIFIER) && !defined(CONFIG_SEC_FACTORY)
|
|
extern int muic_set_hiccup_mode(int on_off);
|
|
#endif
|
|
#if defined(CONFIG_SEC_KUNIT)
|
|
#include <kunit/mock.h>
|
|
#else
|
|
#define __visible_for_testing static
|
|
#endif
|
|
|
|
char *sec_bat_thermal_zone[] = {
|
|
"COLD",
|
|
"COOL3",
|
|
"COOL2",
|
|
"COOL1",
|
|
"NORMAL",
|
|
"WARM",
|
|
"OVERHEAT",
|
|
"OVERHEATLIMIT",
|
|
};
|
|
|
|
#define THERMAL_HYSTERESIS_2 19
|
|
|
|
const char *sec_usb_conn_str(int usb_conn_sts)
|
|
{
|
|
switch (usb_conn_sts) {
|
|
case USB_CONN_NORMAL:
|
|
return "NORMAL";
|
|
case USB_CONN_SLOPE_OVER:
|
|
return "SLOPE_OVER";
|
|
case USB_CONN_GAP_OVER1:
|
|
return "GAP_OVER1";
|
|
case USB_CONN_GAP_OVER2:
|
|
return "GAP_OVER2";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
#if IS_ENABLED(CONFIG_DUAL_BATTERY)
|
|
int sec_bat_get_high_priority_temp(struct sec_battery_info *battery)
|
|
{
|
|
int priority_temp = battery->temperature;
|
|
int standard_temp = 250;
|
|
|
|
if (battery->pdata->sub_bat_thm_info.check_type == SEC_BATTERY_TEMP_CHECK_NONE)
|
|
return battery->temperature;
|
|
|
|
if ((battery->temperature > standard_temp) && (battery->sub_bat_temp > standard_temp)) {
|
|
if (battery->temperature < battery->sub_bat_temp)
|
|
priority_temp = battery->sub_bat_temp;
|
|
} else {
|
|
if (battery->temperature > battery->sub_bat_temp)
|
|
priority_temp = battery->sub_bat_temp;
|
|
}
|
|
|
|
pr_info("%s priority_temp = %d\n", __func__, priority_temp);
|
|
return priority_temp;
|
|
}
|
|
#endif
|
|
|
|
/* trigger mix limit */
|
|
void sec_bat_check_mix_temp_v2_trigger(struct sec_battery_info *battery)
|
|
{
|
|
sec_battery_platform_data_t *p = battery->pdata;
|
|
|
|
int max_icl = p->full_check_current_1st + 50;
|
|
int mix_icl = ((p->chg_float_voltage / p->chg_float_voltage_conv) * max_icl) /
|
|
((battery->input_voltage * 9) / 10);
|
|
/* input current = float voltage * (topoff_current_1st + 50mA(margin)) / (vbus_level * 0.9) */
|
|
|
|
if (mix_icl > max_icl)
|
|
mix_icl = max_icl;
|
|
|
|
/* skip other heating control */
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_SKIP_HEATING_CONTROL,
|
|
SEC_BAT_CURRENT_EVENT_SKIP_HEATING_CONTROL);
|
|
|
|
sec_vote(battery->input_vote, VOTER_MIX_LIMIT, true, mix_icl);
|
|
|
|
#if IS_ENABLED(CONFIG_WIRELESS_TX_MODE)
|
|
if (battery->wc_tx_enable) {
|
|
pr_info("%s @Tx_Mode enter mix_temp_limit, TX mode should turn off\n", __func__);
|
|
sec_bat_set_tx_event(battery, BATT_TX_EVENT_WIRELESS_TX_HIGH_TEMP,
|
|
BATT_TX_EVENT_WIRELESS_TX_HIGH_TEMP);
|
|
battery->tx_retry_case |= SEC_BAT_TX_RETRY_MIX_TEMP;
|
|
sec_wireless_set_tx_enable(battery, false);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* recovery mix limit */
|
|
void sec_bat_check_mix_temp_v2_recovery(struct sec_battery_info *battery)
|
|
{
|
|
battery->mix_limit = false;
|
|
/* for checking charging source (SC -> DC) */
|
|
sec_vote_refresh(battery->fcc_vote);
|
|
sec_vote(battery->input_vote, VOTER_MIX_LIMIT, false, 0);
|
|
|
|
if (battery->tx_retry_case & SEC_BAT_TX_RETRY_MIX_TEMP) {
|
|
pr_info("%s @Tx_Mode recovery mix_temp_limit, TX mode should be retried\n", __func__);
|
|
if ((battery->tx_retry_case & ~SEC_BAT_TX_RETRY_MIX_TEMP) == 0)
|
|
sec_bat_set_tx_event(battery, BATT_TX_EVENT_WIRELESS_TX_RETRY,
|
|
BATT_TX_EVENT_WIRELESS_TX_RETRY);
|
|
battery->tx_retry_case &= ~SEC_BAT_TX_RETRY_MIX_TEMP;
|
|
}
|
|
}
|
|
|
|
void sec_bat_check_mix_temp_v2(struct sec_battery_info *battery)
|
|
{
|
|
sec_battery_platform_data_t *p = battery->pdata;
|
|
|
|
int ct = battery->cable_type;
|
|
|
|
int lrpst = battery->lrp;
|
|
int bat_temp = battery->temperature;
|
|
int chg_temp = battery->chg_temp;
|
|
#if IS_ENABLED(CONFIG_DIRECT_CHARGING)
|
|
int dchg_temp = battery->dchg_temp;
|
|
#else
|
|
int dchg_temp = 0;
|
|
#endif
|
|
|
|
if (battery->pdata->lrp_temp_check_type == SEC_BATTERY_TEMP_CHECK_NONE)
|
|
return;
|
|
|
|
if (battery->lcd_status || !is_wired_type(ct)) {
|
|
pr_info("%s: clear mix temp(%d), lcd(%d), ct(%d)\n", __func__,
|
|
battery->mix_limit, battery->lcd_status, ct);
|
|
|
|
if (battery->mix_limit) /* recovery mix limit */
|
|
sec_bat_check_mix_temp_v2_recovery(battery);
|
|
|
|
return;
|
|
}
|
|
|
|
if (battery->mix_limit) { /* mix limit enabled status */
|
|
pr_info("%s: lrpst(%d), lrp mix temp recovery condition(%d)\n", __func__, lrpst, p->mix_v2_lrp_recov);
|
|
if (lrpst > p->mix_v2_lrp_recov) { /* maintain mix limit */
|
|
sec_bat_check_mix_temp_v2_trigger(battery);
|
|
|
|
store_battery_log(
|
|
"Mix:%d%%,%dmV,mix_lim(%d),lrpst(%d),tbat(%d), tchg(%d), tdchg(%d), icurr(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now, true,
|
|
lrpst, bat_temp, chg_temp, dchg_temp,
|
|
get_sec_vote_result(battery->input_vote), sb_get_ct_str(battery->cable_type));
|
|
} else { /* recovery mix limit */
|
|
sec_bat_check_mix_temp_v2_recovery(battery);
|
|
|
|
store_battery_log(
|
|
"Mix:%d%%,%dmV,mix_lim(%d),lrpst(%d),tbat(%d), tchg(%d), tdchg(%d), icurr(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now, false,
|
|
lrpst, bat_temp, chg_temp, dchg_temp,
|
|
get_sec_vote_result(battery->input_vote), sb_get_ct_str(battery->cable_type));
|
|
}
|
|
} else { /* mix limit disabled status, check mix limit */
|
|
pr_info("%s: lrp:%d/%d, bat:%d/%d, chg:%d/%d, dchg:%d/%d\n", __func__,
|
|
lrpst, p->mix_v2_lrp_cond, bat_temp, p->mix_v2_bat_cond,
|
|
chg_temp, p->mix_v2_chg_cond, dchg_temp, p->mix_v2_dchg_cond);
|
|
|
|
if ((lrpst >= p->mix_v2_lrp_cond) && (bat_temp >= p->mix_v2_bat_cond) &&
|
|
(chg_temp >= p->mix_v2_chg_cond) && dchg_temp >= p->mix_v2_dchg_cond) {
|
|
/* for checking charging source (DC -> SC) */
|
|
if (is_pd_apdo_wire_type(ct) && battery->pd_list.now_isApdo) {
|
|
battery->mix_limit = true;
|
|
sec_vote_refresh(battery->fcc_vote);
|
|
return;
|
|
}
|
|
|
|
sec_bat_check_mix_temp_v2_trigger(battery);
|
|
|
|
store_battery_log(
|
|
"Mix:%d%%,%dmV,mix_lim(%d),lrpst(%d),tbat(%d), tchg(%d), tdchg(%d), icurr(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now, true,
|
|
lrpst, bat_temp, chg_temp, dchg_temp,
|
|
get_sec_vote_result(battery->input_vote), sb_get_ct_str(battery->cable_type));
|
|
|
|
battery->mix_limit = true;
|
|
|
|
}
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_KUNIT(sec_bat_check_mix_temp_v2);
|
|
|
|
void sec_bat_check_mix_temp(struct sec_battery_info *battery, int ct, int siop_level, bool is_apdo)
|
|
{
|
|
int temperature = battery->temperature;
|
|
int chg_temp;
|
|
int input_current = 0;
|
|
|
|
if (battery->pdata->bat_thm_info.check_type == SEC_BATTERY_TEMP_CHECK_NONE ||
|
|
battery->pdata->chg_thm_info.check_type == SEC_BATTERY_TEMP_CHECK_NONE)
|
|
return;
|
|
|
|
if (battery->pdata->blk_thm_info.check_type)
|
|
temperature = battery->blkt_temp;
|
|
|
|
#if IS_ENABLED(CONFIG_DIRECT_CHARGING)
|
|
if (is_apdo)
|
|
chg_temp = battery->dchg_temp;
|
|
else
|
|
chg_temp = battery->chg_temp;
|
|
#else
|
|
chg_temp = battery->chg_temp;
|
|
#endif
|
|
|
|
if (siop_level >= 100 && !battery->lcd_status && !is_wireless_fake_type(ct)) {
|
|
if ((!battery->mix_limit && (temperature >= battery->pdata->mix_high_temp) &&
|
|
(chg_temp >= battery->pdata->mix_high_chg_temp)) ||
|
|
(battery->mix_limit && (temperature > battery->pdata->mix_high_temp_recovery))) {
|
|
int max_input_current = battery->pdata->full_check_current_1st + 50;
|
|
|
|
if (!battery->mix_limit)
|
|
store_battery_log(
|
|
"Mix:%d%%,%dmV,mix_lim(%d),tbat(%d),tchg(%d),icurr(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now, true,
|
|
temperature, chg_temp, input_current, sb_get_ct_str(battery->cable_type));
|
|
|
|
/* for checking charging source (DC -> SC) */
|
|
if (is_apdo) {
|
|
battery->mix_limit = true;
|
|
sec_vote_refresh(battery->fcc_vote);
|
|
return;
|
|
}
|
|
/* input current = float voltage * (topoff_current_1st + 50mA(margin)) / (vbus_level * 0.9) */
|
|
input_current = ((battery->pdata->chg_float_voltage / battery->pdata->chg_float_voltage_conv) *
|
|
max_input_current) / ((battery->input_voltage * 9) / 10);
|
|
|
|
if (input_current > max_input_current)
|
|
input_current = max_input_current;
|
|
|
|
/* skip other heating control */
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_SKIP_HEATING_CONTROL,
|
|
SEC_BAT_CURRENT_EVENT_SKIP_HEATING_CONTROL);
|
|
sec_vote(battery->input_vote, VOTER_MIX_LIMIT, true, input_current);
|
|
|
|
#if IS_ENABLED(CONFIG_WIRELESS_TX_MODE)
|
|
if (battery->wc_tx_enable) {
|
|
pr_info("%s @Tx_Mode enter mix_temp_limit, TX mode should turn off\n", __func__);
|
|
sec_bat_set_tx_event(battery, BATT_TX_EVENT_WIRELESS_TX_HIGH_TEMP,
|
|
BATT_TX_EVENT_WIRELESS_TX_HIGH_TEMP);
|
|
battery->tx_retry_case |= SEC_BAT_TX_RETRY_MIX_TEMP;
|
|
sec_wireless_set_tx_enable(battery, false);
|
|
}
|
|
#endif
|
|
battery->mix_limit = true;
|
|
} else if (battery->mix_limit) {
|
|
battery->mix_limit = false;
|
|
/* for checking charging source (SC -> DC) */
|
|
sec_vote_refresh(battery->fcc_vote);
|
|
sec_vote(battery->input_vote, VOTER_MIX_LIMIT, false, 0);
|
|
|
|
if (battery->tx_retry_case & SEC_BAT_TX_RETRY_MIX_TEMP) {
|
|
pr_info("%s @Tx_Mode recovery mix_temp_limit, TX mode should be retried\n", __func__);
|
|
if ((battery->tx_retry_case & ~SEC_BAT_TX_RETRY_MIX_TEMP) == 0)
|
|
sec_bat_set_tx_event(battery, BATT_TX_EVENT_WIRELESS_TX_RETRY,
|
|
BATT_TX_EVENT_WIRELESS_TX_RETRY);
|
|
battery->tx_retry_case &= ~SEC_BAT_TX_RETRY_MIX_TEMP;
|
|
}
|
|
store_battery_log(
|
|
"Mix:%d%%,%dmV,mix_lim(%d),tbat(%d),tchg(%d),icurr(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now, battery->mix_limit,
|
|
temperature, chg_temp, get_sec_vote_result(battery->input_vote),
|
|
sb_get_ct_str(battery->cable_type));
|
|
}
|
|
|
|
pr_info("%s: mix_limit(%d), temp(%d), chg_temp(%d), input_current(%d)\n",
|
|
__func__, battery->mix_limit, temperature, chg_temp, get_sec_vote_result(battery->input_vote));
|
|
} else {
|
|
if (battery->mix_limit) {
|
|
battery->mix_limit = false;
|
|
/* for checking charging source (SC -> DC) */
|
|
sec_vote_refresh(battery->fcc_vote);
|
|
sec_vote(battery->input_vote, VOTER_MIX_LIMIT, false, 0);
|
|
}
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_KUNIT(sec_bat_check_mix_temp);
|
|
|
|
int sec_bat_get_temp_by_temp_control_source(struct sec_battery_info *battery, int tcs)
|
|
{
|
|
switch (tcs) {
|
|
case TEMP_CONTROL_SOURCE_CHG_THM:
|
|
return battery->chg_temp;
|
|
case TEMP_CONTROL_SOURCE_USB_THM:
|
|
return battery->usb_temp;
|
|
case TEMP_CONTROL_SOURCE_WPC_THM:
|
|
return battery->wpc_temp;
|
|
case TEMP_CONTROL_SOURCE_NONE:
|
|
case TEMP_CONTROL_SOURCE_BAT_THM:
|
|
default:
|
|
return battery->temperature;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_KUNIT(sec_bat_get_temp_by_temp_control_source);
|
|
|
|
#if IS_ENABLED(CONFIG_WIRELESS_CHARGING)
|
|
__visible_for_testing int sec_bat_check_wpc_vout(struct sec_battery_info *battery, int ct, unsigned int chg_limit,
|
|
int pre_vout, unsigned int evt)
|
|
{
|
|
union power_supply_propval value = {0, };
|
|
int vout = 0;
|
|
bool check_flicker_wa = false;
|
|
|
|
if (!is_hv_wireless_type(ct) || (ct == SEC_BATTERY_CABLE_WIRELESS_MPP))
|
|
return 0;
|
|
|
|
if ((ct == SEC_BATTERY_CABLE_HV_WIRELESS_20) || (ct == SEC_BATTERY_CABLE_WIRELESS_EPP))
|
|
vout = battery->wpc_max_vout_level;
|
|
else
|
|
vout = WIRELESS_VOUT_10V;
|
|
|
|
mutex_lock(&battery->voutlock);
|
|
if (battery->pdata->wpc_vout_ctrl_lcd_on) {
|
|
psy_do_property(battery->pdata->wireless_charger_name, get,
|
|
POWER_SUPPLY_EXT_PROP_WIRELESS_TX_ID, value);
|
|
if ((value.intval != WC_PAD_ID_UNKNOWN) &&
|
|
(value.intval != WC_PAD_ID_SNGL_DREAM) &&
|
|
(value.intval != WC_PAD_ID_STAND_DREAM)) {
|
|
if (battery->wpc_vout_ctrl_mode && battery->lcd_status) {
|
|
pr_info("%s: trigger flicker wa\n", __func__);
|
|
check_flicker_wa = true;
|
|
} else {
|
|
value.intval = 0;
|
|
psy_do_property(battery->pdata->wireless_charger_name, get,
|
|
POWER_SUPPLY_EXT_PROP_PAD_VOLT_CTRL, value);
|
|
if (!value.intval) {
|
|
pr_info("%s: recover flicker wa\n", __func__);
|
|
value.intval = battery->lcd_status;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_EXT_PROP_PAD_VOLT_CTRL, value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* get vout level */
|
|
psy_do_property(battery->pdata->wireless_charger_name, get,
|
|
POWER_SUPPLY_EXT_PROP_WIRELESS_RX_VOUT, value);
|
|
|
|
if (value.intval == WIRELESS_VOUT_5_5V_STEP)
|
|
pre_vout = WIRELESS_VOUT_5_5V_STEP;
|
|
|
|
if ((evt & (SEC_BAT_CURRENT_EVENT_HIGH_TEMP_SWELLING | SEC_BAT_CURRENT_EVENT_ISDB)) ||
|
|
battery->sleep_mode || chg_limit || check_flicker_wa)
|
|
vout = WIRELESS_VOUT_5_5V_STEP;
|
|
|
|
if (vout != pre_vout) {
|
|
if (evt & SEC_BAT_CURRENT_EVENT_WPC_VOUT_LOCK) {
|
|
vout = pre_vout;
|
|
pr_info("%s: block to set wpc vout level(%d) because otg on\n",
|
|
__func__, vout);
|
|
} else {
|
|
value.intval = vout;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_EXT_PROP_INPUT_VOLTAGE_REGULATION, value);
|
|
pr_info("%s: change vout level(%d)", __func__, vout);
|
|
sec_vote(battery->input_vote, VOTER_AICL, false, 0);
|
|
}
|
|
} else if ((vout == WIRELESS_VOUT_10V ||
|
|
vout == battery->wpc_max_vout_level)) {
|
|
/* reset aicl current to recover current for unexpected aicl during */
|
|
/* before vout boosting completion */
|
|
sec_vote(battery->input_vote, VOTER_AICL, false, 0);
|
|
}
|
|
mutex_unlock(&battery->voutlock);
|
|
return vout;
|
|
}
|
|
EXPORT_SYMBOL_KUNIT(sec_bat_check_wpc_vout);
|
|
|
|
__visible_for_testing int sec_bat_check_wpc_step_limit(struct sec_battery_info *battery, unsigned int step_sz,
|
|
unsigned int *step_limit_temp, unsigned int rx_power, int temp)
|
|
{
|
|
int i;
|
|
int fcc = 0;
|
|
|
|
for (i = 0; i < step_sz; ++i) {
|
|
if (temp > step_limit_temp[i]) {
|
|
if (rx_power == SEC_WIRELESS_RX_POWER_12W)
|
|
fcc = battery->pdata->wpc_step_limit_fcc_12w[i];
|
|
else if (rx_power >= SEC_WIRELESS_RX_POWER_15W)
|
|
fcc = battery->pdata->wpc_step_limit_fcc_15w[i];
|
|
else
|
|
fcc = battery->pdata->wpc_step_limit_fcc[i];
|
|
pr_info("%s: wc20_rx_power(%d), wpc_step_limit[%d] temp:%d, fcc:%d\n",
|
|
__func__, rx_power, i, temp, fcc);
|
|
break;
|
|
}
|
|
}
|
|
return fcc;
|
|
}
|
|
EXPORT_SYMBOL_KUNIT(sec_bat_check_wpc_step_limit);
|
|
|
|
__visible_for_testing void sec_bat_check_wpc_condition(struct sec_battery_info *battery, bool lcd_off, int ct,
|
|
unsigned int rx_power, int *wpc_high_temp, int *wpc_high_temp_recovery)
|
|
{
|
|
if (lcd_off) {
|
|
if ((ct == SEC_BATTERY_CABLE_HV_WIRELESS_20) || (ct == SEC_BATTERY_CABLE_WIRELESS_EPP)) {
|
|
if (rx_power == SEC_WIRELESS_RX_POWER_12W) {
|
|
*wpc_high_temp = battery->pdata->wpc_high_temp_12w;
|
|
*wpc_high_temp_recovery = battery->pdata->wpc_high_temp_recovery_12w;
|
|
} else {
|
|
*wpc_high_temp = battery->pdata->wpc_high_temp_15w;
|
|
*wpc_high_temp_recovery = battery->pdata->wpc_high_temp_recovery_15w;
|
|
}
|
|
} else {
|
|
*wpc_high_temp = battery->pdata->wpc_high_temp;
|
|
*wpc_high_temp_recovery = battery->pdata->wpc_high_temp_recovery;
|
|
}
|
|
} else {
|
|
if ((ct == SEC_BATTERY_CABLE_HV_WIRELESS_20) || (ct == SEC_BATTERY_CABLE_WIRELESS_EPP)) {
|
|
if (rx_power == SEC_WIRELESS_RX_POWER_12W) {
|
|
*wpc_high_temp = battery->pdata->wpc_lcd_on_high_temp_12w;
|
|
*wpc_high_temp_recovery = battery->pdata->wpc_lcd_on_high_temp_rec_12w;
|
|
} else {
|
|
*wpc_high_temp = battery->pdata->wpc_lcd_on_high_temp_15w;
|
|
*wpc_high_temp_recovery = battery->pdata->wpc_lcd_on_high_temp_rec_15w;
|
|
}
|
|
} else {
|
|
*wpc_high_temp = battery->pdata->wpc_lcd_on_high_temp;
|
|
*wpc_high_temp_recovery = battery->pdata->wpc_lcd_on_high_temp_rec;
|
|
}
|
|
}
|
|
}
|
|
|
|
__visible_for_testing int sec_bat_check_wpc_chg_limit(struct sec_battery_info *battery, bool lcd_off, int ct,
|
|
int chg_limit, int *step_limit_fcc)
|
|
{
|
|
int wpc_high_temp = battery->pdata->wpc_high_temp;
|
|
int wpc_high_temp_recovery = battery->pdata->wpc_high_temp_recovery;
|
|
int thermal_source = battery->pdata->wpc_temp_control_source;
|
|
int temp;
|
|
|
|
if (!lcd_off)
|
|
thermal_source = battery->pdata->wpc_temp_lcd_on_control_source;
|
|
|
|
temp = sec_bat_get_temp_by_temp_control_source(battery, thermal_source);
|
|
sec_bat_check_wpc_condition(battery,
|
|
lcd_off, ct, battery->wc20_rx_power, &wpc_high_temp, &wpc_high_temp_recovery);
|
|
|
|
if (temp >= wpc_high_temp)
|
|
chg_limit = true;
|
|
else if (temp <= wpc_high_temp_recovery)
|
|
chg_limit = false;
|
|
|
|
if (!chg_limit && (temp >= wpc_high_temp_recovery)) {
|
|
*step_limit_fcc = sec_bat_check_wpc_step_limit(battery, battery->pdata->wpc_step_limit_size,
|
|
battery->pdata->wpc_step_limit_temp, battery->wc20_rx_power, temp);
|
|
}
|
|
return chg_limit;
|
|
}
|
|
|
|
void sec_bat_check_wpc_temp(struct sec_battery_info *battery, int ct, int siop_level)
|
|
{
|
|
int step_limit_fcc = 0;
|
|
int chg_limit = battery->chg_limit;
|
|
bool lcd_off = !battery->lcd_status;
|
|
int icl = battery->pdata->wpc_input_limit_current;
|
|
int fcc = battery->pdata->wpc_charging_limit_current;
|
|
|
|
/* nv wc temp control is not necessary when nv wc icl has same value with hv limited icl.
|
|
That is why nv_wc_temp_ctrl_skip has true when nv wc icl has same value with hv limited icl.
|
|
Otherwise wc temp control is necessary with all kinds of wireless charger types when when nv wc icl is bigger than hv limited icl.
|
|
For example, 5.5V/800mA(NV) and 5.5V/800mA(HV) same power so that nv wc type can skip nv wc temp control,
|
|
but in case of 5.5V/800mA(NV) and 5.5V/700mA(HV) need wc temp control with nv wc type. */
|
|
if (battery->pdata->wpc_thm_info.check_type == SEC_BATTERY_TEMP_CHECK_NONE || (ct == SEC_BATTERY_CABLE_WIRELESS_MPP) ||
|
|
(battery->nv_wc_temp_ctrl_skip && !is_hv_wireless_type(ct) && (ct != SEC_BATTERY_CABLE_WIRELESS_TX)) ||
|
|
(!battery->nv_wc_temp_ctrl_skip && !is_wireless_type(ct)))
|
|
return;
|
|
|
|
chg_limit = sec_bat_check_wpc_chg_limit(battery, lcd_off, ct, chg_limit, &step_limit_fcc);
|
|
battery->wpc_vout_level = sec_bat_check_wpc_vout(battery, ct, chg_limit,
|
|
battery->wpc_vout_level, battery->current_event);
|
|
|
|
pr_info("%s: vout_level: %d, chg_limit: %d, step_limit: %d\n",
|
|
__func__, battery->wpc_vout_level, chg_limit, step_limit_fcc);
|
|
battery->chg_limit = chg_limit;
|
|
if (chg_limit) {
|
|
if (!lcd_off)
|
|
icl = battery->pdata->wpc_lcd_on_input_limit_current;
|
|
if (ct == SEC_BATTERY_CABLE_WIRELESS_TX &&
|
|
battery->pdata->wpc_input_limit_by_tx_check)
|
|
icl = battery->pdata->wpc_input_limit_current_by_tx;
|
|
sec_vote(battery->input_vote, VOTER_CHG_TEMP, true, icl);
|
|
sec_vote(battery->input_vote, VOTER_CABLE, false, 0); /* 10(V)/ICL(mA) -> 5.5(V)/wpc_input_limit_current(mA) */
|
|
sec_vote(battery->fcc_vote, VOTER_CHG_TEMP, true, fcc);
|
|
} else {
|
|
if (step_limit_fcc)
|
|
sec_vote(battery->fcc_vote, VOTER_CHG_TEMP, true, step_limit_fcc);
|
|
else
|
|
sec_vote(battery->fcc_vote, VOTER_CHG_TEMP, false, fcc);
|
|
sec_vote(battery->input_vote, VOTER_CABLE, true,
|
|
battery->pdata->charging_current[ct].input_current_limit); /* 5.5(V)/wpc_input_limit_current(mA) -> 10(V)/ICL(mA) */
|
|
sec_vote(battery->input_vote, VOTER_CHG_TEMP, false, icl);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_KUNIT(sec_bat_check_wpc_temp);
|
|
|
|
/* concept: nv_wireless_type does not control */
|
|
/* concept: no need check LCD ON */
|
|
/* concept: no need step fcc control */
|
|
void sec_bat_check_wpc_temp_v2(struct sec_battery_info *battery)
|
|
{
|
|
int ct = battery->cable_type;
|
|
int wpc_temp = battery->wpc_temp;
|
|
int temp_trigger = battery->pdata->wpc_high_temp;
|
|
int temp_recovery = battery->pdata->wpc_high_temp_recovery;
|
|
int temp_reset_condition = battery->pdata->wpc_temp_v2_cond;
|
|
int chg_limit = battery->chg_limit;
|
|
bool using_lrp = false;
|
|
union power_supply_propval value = {0, };
|
|
|
|
/* exception handling */
|
|
if (!is_hv_wireless_type(ct) ||
|
|
battery->pdata->wpc_thm_info.check_type == SEC_BATTERY_TEMP_CHECK_NONE) {
|
|
battery->wpc_temp_v2_offset = 0;
|
|
return;
|
|
}
|
|
|
|
if (battery->pdata->wpc_high_check_using_lrp && !sec_bat_get_lpmode() && battery->lcd_status) {
|
|
if (battery->pdata->lrp_temp_check_type == SEC_BATTERY_TEMP_CHECK_NONE) {
|
|
battery->wpc_temp_v2_offset = 0;
|
|
return;
|
|
}
|
|
using_lrp = true;
|
|
wpc_temp = battery->lrp;
|
|
|
|
/* operating temperature standard settings */
|
|
if ((ct == SEC_BATTERY_CABLE_HV_WIRELESS_20) || (ct == SEC_BATTERY_CABLE_WIRELESS_EPP)) {
|
|
if (battery->wc20_rx_power == SEC_WIRELESS_RX_POWER_12W) {
|
|
temp_trigger = battery->pdata->wpc_lrp_high_temp_12w;
|
|
temp_recovery = battery->pdata->wpc_lrp_high_temp_recovery_12w;
|
|
temp_reset_condition = battery->pdata->wpc_lrp_temp_v2_cond_12w;
|
|
} else {
|
|
temp_trigger = battery->pdata->wpc_lrp_high_temp_15w;
|
|
temp_recovery = battery->pdata->wpc_lrp_high_temp_recovery_15w;
|
|
temp_reset_condition = battery->pdata->wpc_lrp_temp_v2_cond_15w;
|
|
}
|
|
} else {
|
|
temp_trigger = battery->pdata->wpc_lrp_high_temp;
|
|
temp_recovery = battery->pdata->wpc_lrp_high_temp_recovery;
|
|
temp_reset_condition = battery->pdata->wpc_lrp_temp_v2_cond;
|
|
}
|
|
} else {
|
|
/* operating temperature standard settings */
|
|
if ((ct == SEC_BATTERY_CABLE_HV_WIRELESS_20) || (ct == SEC_BATTERY_CABLE_WIRELESS_EPP)) {
|
|
if (battery->wc20_rx_power == SEC_WIRELESS_RX_POWER_12W) {
|
|
temp_trigger = battery->pdata->wpc_high_temp_12w;
|
|
temp_recovery = battery->pdata->wpc_high_temp_recovery_12w;
|
|
temp_reset_condition = battery->pdata->wpc_temp_v2_cond_12w;
|
|
} else {
|
|
temp_trigger = battery->pdata->wpc_high_temp_15w;
|
|
temp_recovery = battery->pdata->wpc_high_temp_recovery_15w;
|
|
temp_reset_condition = battery->pdata->wpc_temp_v2_cond_15w;
|
|
}
|
|
} /* else initial value */
|
|
}
|
|
|
|
/* check chg_limit condition */
|
|
if (wpc_temp >= temp_trigger)
|
|
chg_limit = true;
|
|
else if (wpc_temp <= temp_recovery)
|
|
chg_limit = false;
|
|
/* else initial value, remain prev chg_limit data */
|
|
|
|
/* check vout_level condition */
|
|
battery->wpc_vout_level = sec_bat_check_wpc_vout(battery, ct, chg_limit,
|
|
battery->wpc_vout_level, battery->current_event);
|
|
|
|
pr_info("%s: vout_level: %d, chg_limit: %d, %s_temp(%d), trc(%d/%d/%d)\n", __func__,
|
|
battery->wpc_vout_level, chg_limit, using_lrp ? "lrp" : "wpc", wpc_temp,
|
|
temp_trigger, temp_recovery, temp_reset_condition);
|
|
|
|
if (chg_limit) {
|
|
/* icl min limit = 500mA */
|
|
int offset_limit = battery->pdata->charging_current[ct].input_current_limit - 500;
|
|
|
|
if (ct == SEC_BATTERY_CABLE_WIRELESS_MPP) {
|
|
if (battery->chg_limit != chg_limit) {
|
|
value.intval = 1;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_EXT_PROP_MPP_ICL_CTRL, value);
|
|
}
|
|
} else {
|
|
/* 10(V)/ICL(mA) -> 5.5(V)/wpc_input_limit_current(mA) */
|
|
sec_vote(battery->input_vote, VOTER_CHG_TEMP, true, battery->pdata->wpc_input_limit_current);
|
|
sec_vote(battery->input_vote, VOTER_CABLE, false, 0);
|
|
sec_vote(battery->fcc_vote, VOTER_CHG_TEMP, true, battery->pdata->wpc_charging_limit_current);
|
|
}
|
|
|
|
/* work only once for offset change */
|
|
if (battery->chg_limit != chg_limit) {
|
|
battery->wpc_temp_v2_offset += 50;
|
|
if (battery->wpc_temp_v2_offset > offset_limit)
|
|
battery->wpc_temp_v2_offset = offset_limit;
|
|
pr_info("%s: offset++, wpc_temp_v2_offset: (%d), limit(%d)\n", __func__,
|
|
battery->wpc_temp_v2_offset, offset_limit);
|
|
}
|
|
} else {
|
|
int icl_max = battery->pdata->charging_current[ct].input_current_limit;
|
|
|
|
if (wpc_temp <= temp_reset_condition) {
|
|
battery->wpc_temp_v2_offset -= 50;
|
|
if (battery->wpc_temp_v2_offset < 0)
|
|
battery->wpc_temp_v2_offset = 0;
|
|
pr_info("%s: offset--, wpc_temp_v2_offset: (%d)\n", __func__, battery->wpc_temp_v2_offset);
|
|
}
|
|
|
|
if (ct == SEC_BATTERY_CABLE_WIRELESS_MPP) {
|
|
if (battery->chg_limit != chg_limit) {
|
|
value.intval = 1;
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_EXT_PROP_MPP_INC_INT_CTRL, value);
|
|
}
|
|
} else {
|
|
sec_vote(battery->fcc_vote, VOTER_CHG_TEMP, false, 0);
|
|
/* 5.5(V)/wpc_input_limit_current(mA) -> 10(V)/ICL(mA) */
|
|
sec_vote(battery->input_vote, VOTER_CABLE, true, icl_max - battery->wpc_temp_v2_offset);
|
|
sec_vote(battery->input_vote, VOTER_CHG_TEMP, false, 0);
|
|
}
|
|
}
|
|
battery->chg_limit = chg_limit;
|
|
}
|
|
EXPORT_SYMBOL_KUNIT(sec_bat_check_wpc_temp_v2);
|
|
|
|
void sec_bat_thermal_warm_wc_fod(struct sec_battery_info *battery, bool is_charging)
|
|
{
|
|
union power_supply_propval value = {0, };
|
|
|
|
if (!battery->pdata->wpc_warm_fod)
|
|
return;
|
|
|
|
if (!is_wireless_fake_type(battery->cable_type))
|
|
return;
|
|
|
|
value.intval = is_charging;
|
|
if (!is_charging)
|
|
sec_vote(battery->input_vote, VOTER_SWELLING, true, battery->pdata->wpc_warm_fod_icc);
|
|
|
|
psy_do_property(battery->pdata->wireless_charger_name, set,
|
|
POWER_SUPPLY_EXT_PROP_WARM_FOD, value);
|
|
}
|
|
#else
|
|
void sec_bat_check_wpc_temp(struct sec_battery_info *battery, int ct, int siop_level) {}
|
|
void sec_bat_check_wpc_temp_v2(struct sec_battery_info *battery) {}
|
|
void sec_bat_thermal_warm_wc_fod(struct sec_battery_info *battery, bool is_charging) {}
|
|
#endif
|
|
|
|
#if defined(CONFIG_WIRELESS_TX_MODE)
|
|
void sec_bat_check_tx_temperature(struct sec_battery_info *battery)
|
|
{
|
|
int bat_temp = battery->temperature;
|
|
|
|
#if IS_ENABLED(CONFIG_DUAL_BATTERY)
|
|
bat_temp = sec_bat_get_high_priority_temp(battery);
|
|
#endif
|
|
if (battery->wc_tx_enable) {
|
|
if (bat_temp >= battery->pdata->tx_high_threshold) {
|
|
pr_info("@Tx_Mode : %s: Battery temperature is too high. Tx mode should turn off\n", __func__);
|
|
/* set tx event */
|
|
sec_bat_set_tx_event(battery, BATT_TX_EVENT_WIRELESS_TX_HIGH_TEMP, BATT_TX_EVENT_WIRELESS_TX_HIGH_TEMP);
|
|
battery->tx_retry_case |= SEC_BAT_TX_RETRY_HIGH_TEMP;
|
|
sec_wireless_set_tx_enable(battery, false);
|
|
} else if (bat_temp <= battery->pdata->tx_low_threshold) {
|
|
pr_info("@Tx_Mode : %s: Battery temperature is too low. Tx mode should turn off\n", __func__);
|
|
/* set tx event */
|
|
sec_bat_set_tx_event(battery, BATT_TX_EVENT_WIRELESS_TX_LOW_TEMP, BATT_TX_EVENT_WIRELESS_TX_LOW_TEMP);
|
|
battery->tx_retry_case |= SEC_BAT_TX_RETRY_LOW_TEMP;
|
|
sec_wireless_set_tx_enable(battery, false);
|
|
}
|
|
} else if (battery->tx_retry_case & SEC_BAT_TX_RETRY_HIGH_TEMP) {
|
|
if (bat_temp <= battery->pdata->tx_high_recovery) {
|
|
pr_info("@Tx_Mode : %s: Battery temperature goes to normal(High). Retry TX mode\n", __func__);
|
|
battery->tx_retry_case &= ~SEC_BAT_TX_RETRY_HIGH_TEMP;
|
|
if (!battery->tx_retry_case)
|
|
sec_bat_set_tx_event(battery, BATT_TX_EVENT_WIRELESS_TX_RETRY, BATT_TX_EVENT_WIRELESS_TX_RETRY);
|
|
}
|
|
} else if (battery->tx_retry_case & SEC_BAT_TX_RETRY_LOW_TEMP) {
|
|
if (bat_temp >= battery->pdata->tx_low_recovery) {
|
|
pr_info("@Tx_Mode : %s: Battery temperature goes to normal(Low). Retry TX mode\n", __func__);
|
|
battery->tx_retry_case &= ~SEC_BAT_TX_RETRY_LOW_TEMP;
|
|
if (!battery->tx_retry_case)
|
|
sec_bat_set_tx_event(battery, BATT_TX_EVENT_WIRELESS_TX_RETRY, BATT_TX_EVENT_WIRELESS_TX_RETRY);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
int sec_bat_check_power_type(
|
|
int max_chg_pwr, int pd_max_chg_pwr, int ct, int ws, int is_apdo)
|
|
{
|
|
if (is_pd_wire_type(ct) && is_apdo) {
|
|
if (get_chg_power_type(ct, ws, pd_max_chg_pwr, max_chg_pwr) == SFC_45W)
|
|
return SFC_45W;
|
|
else
|
|
return SFC_25W;
|
|
} else {
|
|
return NORMAL_TA;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_KUNIT(sec_bat_check_power_type);
|
|
|
|
int sec_bat_check_lrp_temp_cond(int prev_step,
|
|
int temp, int trig, int recov)
|
|
{
|
|
if (trig <= temp)
|
|
prev_step++;
|
|
else if (recov >= temp)
|
|
prev_step--;
|
|
|
|
if (prev_step < LRP_NONE)
|
|
prev_step = LRP_NONE;
|
|
else if (prev_step > LRP_STEP2)
|
|
prev_step = LRP_STEP2;
|
|
|
|
return prev_step;
|
|
}
|
|
|
|
int sec_bat_check_lrp_step(
|
|
struct sec_battery_info *battery, int temp, int pt, bool lcd_sts)
|
|
{
|
|
int step = LRP_NONE;
|
|
int lcd_st = LCD_OFF;
|
|
int lrp_pt = LRP_NORMAL;
|
|
int lrp_high_temp_st1 = battery->pdata->lrp_temp[LRP_NORMAL].trig[ST1][LCD_OFF];
|
|
int lrp_high_temp_st2 = battery->pdata->lrp_temp[LRP_NORMAL].trig[ST2][LCD_OFF];
|
|
int lrp_high_temp_recov_st1 = battery->pdata->lrp_temp[LRP_NORMAL].recov[ST1][LCD_OFF];
|
|
int lrp_high_temp_recov_st2 = battery->pdata->lrp_temp[LRP_NORMAL].recov[ST2][LCD_OFF];
|
|
|
|
if (lcd_sts)
|
|
lcd_st = LCD_ON;
|
|
|
|
if (pt == SFC_45W)
|
|
lrp_pt = LRP_45W;
|
|
else if (pt == SFC_25W)
|
|
lrp_pt = LRP_25W;
|
|
|
|
lrp_high_temp_st1 = battery->pdata->lrp_temp[lrp_pt].trig[ST1][lcd_st];
|
|
lrp_high_temp_st2 = battery->pdata->lrp_temp[lrp_pt].trig[ST2][lcd_st];
|
|
lrp_high_temp_recov_st1 = battery->pdata->lrp_temp[lrp_pt].recov[ST1][lcd_st];
|
|
lrp_high_temp_recov_st2 = battery->pdata->lrp_temp[lrp_pt].recov[ST2][lcd_st];
|
|
|
|
pr_info("%s: st1(%d), st2(%d), recv_st1(%d), recv_st2(%d), lrp(%d)\n", __func__,
|
|
lrp_high_temp_st1, lrp_high_temp_st2,
|
|
lrp_high_temp_recov_st1, lrp_high_temp_recov_st2, temp);
|
|
|
|
switch (battery->lrp_step) {
|
|
case LRP_STEP2:
|
|
step = sec_bat_check_lrp_temp_cond(battery->lrp_step,
|
|
temp, 900, lrp_high_temp_recov_st2);
|
|
break;
|
|
case LRP_STEP1:
|
|
step = sec_bat_check_lrp_temp_cond(battery->lrp_step,
|
|
temp, lrp_high_temp_st2, lrp_high_temp_recov_st1);
|
|
break;
|
|
case LRP_NONE:
|
|
step = sec_bat_check_lrp_temp_cond(battery->lrp_step,
|
|
temp, lrp_high_temp_st1, -200);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if ((battery->lrp_step != LRP_STEP1) && (step == LRP_STEP1))
|
|
step = sec_bat_check_lrp_temp_cond(step,
|
|
temp, lrp_high_temp_st2, lrp_high_temp_recov_st1);
|
|
|
|
return step;
|
|
}
|
|
|
|
#if defined(CONFIG_SUPPORT_HV_CTRL) && !defined(CONFIG_SEC_FACTORY)
|
|
bool sec_bat_temp_vbus_condition(int ct, unsigned int evt)
|
|
{
|
|
if (!(is_hv_wire_type(ct) || is_pd_wire_type(ct)) ||
|
|
(ct == SEC_BATTERY_CABLE_QC30))
|
|
return false;
|
|
|
|
if ((evt & SEC_BAT_CURRENT_EVENT_AFC) ||
|
|
(evt & SEC_BAT_CURRENT_EVENT_SELECT_PDO))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool sec_bat_change_temp_vbus(struct sec_battery_info *battery,
|
|
int ct, unsigned int evt, int lrp_step, int vote_evt)
|
|
{
|
|
if (battery->pdata->chg_thm_info.check_type == SEC_BATTERY_TEMP_CHECK_NONE ||
|
|
battery->store_mode)
|
|
return false;
|
|
if (!sec_bat_temp_vbus_condition(ct, evt))
|
|
return false;
|
|
|
|
if (lrp_step <= LRP_STEP1)
|
|
sec_vote(battery->iv_vote, vote_evt, false, 0);
|
|
else {
|
|
sec_vote(battery->iv_vote, vote_evt, true, SEC_INPUT_VOLTAGE_5V);
|
|
pr_info("%s: vbus set 5V by lrp, Cable(%d, %d, %d)\n",
|
|
__func__, ct, battery->muic_cable_type, battery->pd_usb_attached);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
void sec_bat_check_lrp_temp(
|
|
struct sec_battery_info *battery, int ct, int ws, int siop_level, bool lcd_sts)
|
|
{
|
|
int input_current = 0, charging_current = 0;
|
|
int lrp_step = LRP_NONE;
|
|
bool is_apdo = false;
|
|
int power_type = NORMAL_TA;
|
|
bool hv_ctrl = false;
|
|
#if IS_ENABLED(CONFIG_DIRECT_CHARGING)
|
|
unsigned int cur_lrp_chg_src = battery->lrp_chg_src;
|
|
#endif
|
|
if (battery->pdata->lrp_temp_check_type == SEC_BATTERY_TEMP_CHECK_NONE)
|
|
return;
|
|
|
|
#if IS_ENABLED(CONFIG_DIRECT_CHARGING)
|
|
is_apdo = (is_pd_apdo_wire_type(ct) && battery->pd_list.now_isApdo) ? 1 : 0;
|
|
#endif
|
|
power_type = sec_bat_check_power_type(battery->max_charge_power,
|
|
battery->pd_max_charge_power, ct, ws, is_apdo);
|
|
|
|
lrp_step = sec_bat_check_lrp_step(battery, battery->lrp, power_type, lcd_sts);
|
|
|
|
#if IS_ENABLED(CONFIG_DIRECT_CHARGING)
|
|
/* trigger from DC to SC for lcd on at LRP_STEP2 */
|
|
if (battery->pdata->sc_LRP_25W) {
|
|
if (power_type == SFC_25W || battery->lrp_chg_src == SEC_CHARGING_SOURCE_SWITCHING) {
|
|
if (lcd_sts && lrp_step >= LRP_STEP2)
|
|
cur_lrp_chg_src = SEC_CHARGING_SOURCE_SWITCHING;
|
|
else
|
|
cur_lrp_chg_src = SEC_CHARGING_SOURCE_DIRECT;
|
|
}
|
|
}
|
|
|
|
/* FPDO DC concept */
|
|
if (battery->cable_type == SEC_BATTERY_CABLE_FPDO_DC && lrp_step != LRP_NONE) {
|
|
union power_supply_propval value = {0, };
|
|
|
|
battery->lrp_limit = true;
|
|
cur_lrp_chg_src = SEC_CHARGING_SOURCE_SWITCHING;
|
|
|
|
value.intval = 0;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_EXT_PROP_REFRESH_CHARGING_SOURCE, value);
|
|
|
|
}
|
|
#endif
|
|
|
|
if ((lrp_step == LRP_STEP2) || (lrp_step == LRP_STEP1)) {
|
|
if (is_pd_wire_type(ct) || is_hv_wire_type(ct)) {
|
|
if (power_type == SFC_45W) {
|
|
input_current = battery->pdata->lrp_curr[LRP_45W].st_icl[lrp_step - 1];
|
|
charging_current = battery->pdata->lrp_curr[LRP_45W].st_fcc[lrp_step - 1];
|
|
} else if (power_type == SFC_25W) {
|
|
input_current = battery->pdata->lrp_curr[LRP_25W].st_icl[lrp_step - 1];
|
|
charging_current = battery->pdata->lrp_curr[LRP_25W].st_fcc[lrp_step - 1];
|
|
} else {
|
|
#if defined(CONFIG_SUPPORT_HV_CTRL) && !defined(CONFIG_SEC_FACTORY)
|
|
if (battery->misc_event & BATT_MISC_EVENT_HV_BY_AICL)
|
|
hv_ctrl = false;
|
|
else
|
|
hv_ctrl = sec_bat_change_temp_vbus(battery, ct,
|
|
battery->current_event, lrp_step, VOTER_LRP_TEMP);
|
|
#endif
|
|
if (lrp_step == LRP_STEP1) { /* 9W */
|
|
input_current =
|
|
battery->pdata->lrp_curr[LRP_NORMAL].st_icl[lrp_step - 1];
|
|
} else { /* 6W */
|
|
input_current = hv_ctrl ?
|
|
battery->pdata->lrp_curr[LRP_NORMAL].st_icl[lrp_step - 1] :
|
|
mA_by_mWmV(battery->pdata->power_value, battery->input_voltage);
|
|
}
|
|
charging_current = battery->pdata->lrp_curr[LRP_NORMAL].st_fcc[lrp_step - 1];
|
|
}
|
|
#if defined(CONFIG_USE_POGO)
|
|
} else if (ct == SEC_BATTERY_CABLE_POGO_9V) {
|
|
if (lcd_sts) {
|
|
input_current = battery->pdata->siop_hv_icl;
|
|
charging_current = battery->pdata->siop_hv_fcc;
|
|
} else {
|
|
input_current = battery->pdata->chg_input_limit_current;
|
|
charging_current = battery->pdata->chg_charging_limit_current;
|
|
}
|
|
#endif
|
|
} else {
|
|
if (lcd_sts) {
|
|
input_current = battery->pdata->siop_icl;
|
|
charging_current = battery->pdata->siop_fcc;
|
|
} else {
|
|
input_current = battery->pdata->default_input_current;
|
|
charging_current = battery->pdata->default_charging_current;
|
|
}
|
|
}
|
|
sec_vote(battery->fcc_vote, VOTER_LRP_TEMP, true, charging_current);
|
|
sec_vote(battery->input_vote, VOTER_LRP_TEMP, true, input_current);
|
|
#if IS_ENABLED(CONFIG_DIRECT_CHARGING)
|
|
if (battery->lrp_chg_src != cur_lrp_chg_src) {
|
|
battery->lrp_chg_src = cur_lrp_chg_src;
|
|
sec_vote_refresh(battery->fcc_vote);
|
|
}
|
|
#endif
|
|
if (battery->lrp_step != lrp_step)
|
|
store_battery_log(
|
|
"LRP:SOC(%d),Vnow(%d),lrp_step(%d),lcd(%d),tlrp(%d),icl(%d),fcc(%d),ct(%d),is_apdo(%d),mcp(%d,%d)",
|
|
battery->capacity, battery->voltage_now, lrp_step, lcd_sts,
|
|
battery->lrp, input_current, charging_current, battery->cable_type,
|
|
is_apdo, battery->pd_max_charge_power, battery->max_charge_power);
|
|
battery->lrp_limit = true;
|
|
} else if ((battery->lrp_limit == true) && (lrp_step == LRP_NONE)) {
|
|
sec_vote(battery->iv_vote, VOTER_LRP_TEMP, false, 0);
|
|
sec_vote(battery->fcc_vote, VOTER_LRP_TEMP, false, 0);
|
|
sec_vote(battery->input_vote, VOTER_LRP_TEMP, false, 0);
|
|
battery->lrp_limit = false;
|
|
#if IS_ENABLED(CONFIG_DIRECT_CHARGING)
|
|
battery->lrp_chg_src = SEC_CHARGING_SOURCE_DIRECT;
|
|
#endif
|
|
store_battery_log(
|
|
"LRP:%d%%,%dmV,lrp_lim(%d),tlrp(%d),icurr(%d),ocurr(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now, battery->lrp_limit,
|
|
battery->lrp, get_sec_vote_result(battery->input_vote),
|
|
get_sec_vote_result(battery->fcc_vote), sb_get_ct_str(battery->cable_type));
|
|
}
|
|
battery->lrp_step = lrp_step;
|
|
|
|
pr_info("%s: cable_type(%d), lrp_step(%d), lrp(%d)\n", __func__,
|
|
ct, battery->lrp_step, battery->lrp);
|
|
}
|
|
EXPORT_SYMBOL_KUNIT(sec_bat_check_lrp_temp);
|
|
|
|
#if IS_ENABLED(CONFIG_DIRECT_CHARGING)
|
|
static int sec_bat_check_lpm_power(int lpm, int pt)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (pt == SFC_25W)
|
|
ret |= 0x02;
|
|
|
|
if (lpm)
|
|
ret |= 0x01;
|
|
|
|
return ret;
|
|
}
|
|
|
|
int sec_bat_set_dchg_current(struct sec_battery_info *battery, int power_type, int pt)
|
|
{
|
|
int input_current = 0, charging_current = 0;
|
|
|
|
/* skip power_type check for non-use lrp_temp_check models */
|
|
if (battery->pdata->lrp_temp_check_type == SEC_BATTERY_TEMP_CHECK_NONE)
|
|
power_type = NORMAL_TA;
|
|
|
|
if (power_type == SFC_45W) {
|
|
if (pt & 0x01) {
|
|
input_current = battery->pdata->lrp_curr[LRP_45W].st_icl[ST1];
|
|
charging_current = battery->pdata->lrp_curr[LRP_45W].st_fcc[ST1];
|
|
} else {
|
|
input_current = battery->pdata->lrp_curr[LRP_45W].st_icl[ST2];
|
|
charging_current = battery->pdata->lrp_curr[LRP_45W].st_fcc[ST2];
|
|
}
|
|
} else if (power_type == SFC_25W) {
|
|
if (pt & 0x01) {
|
|
input_current = battery->pdata->lrp_curr[LRP_25W].st_icl[ST1];
|
|
charging_current = battery->pdata->lrp_curr[LRP_25W].st_fcc[ST1];
|
|
} else {
|
|
input_current = battery->pdata->lrp_curr[LRP_25W].st_icl[ST2];
|
|
charging_current = battery->pdata->lrp_curr[LRP_25W].st_fcc[ST2];
|
|
}
|
|
} else {
|
|
input_current = battery->pdata->dchg_input_limit_current;
|
|
charging_current = battery->pdata->dchg_charging_limit_current;
|
|
}
|
|
|
|
sec_vote(battery->fcc_vote, VOTER_CHG_TEMP, true, charging_current);
|
|
sec_vote(battery->input_vote, VOTER_CHG_TEMP, true, input_current);
|
|
|
|
return charging_current;
|
|
}
|
|
|
|
void sec_bat_check_direct_chg_temp(struct sec_battery_info *battery, int siop_level)
|
|
{
|
|
int input_current = 0, charging_current = 0, pt = 0;
|
|
int ct = battery->cable_type, ws = battery->wire_status;
|
|
bool is_apdo = false;
|
|
int power_type = NORMAL_TA;
|
|
|
|
if (battery->pdata->dchg_thm_info.check_type == SEC_BATTERY_TEMP_CHECK_NONE) {
|
|
return;
|
|
} else if (battery->pdata->dctp_bootmode_en) {
|
|
battery->chg_limit = false;
|
|
sec_vote(battery->fcc_vote, VOTER_CHG_TEMP, false, 0);
|
|
sec_vote(battery->input_vote, VOTER_CHG_TEMP, false, 0);
|
|
|
|
return;
|
|
}
|
|
|
|
is_apdo = (is_pd_apdo_wire_type(ct) && battery->pd_list.now_isApdo) ? 1 : 0;
|
|
power_type = sec_bat_check_power_type(battery->max_charge_power,
|
|
battery->pd_max_charge_power, ct, ws, is_apdo);
|
|
pt = sec_bat_check_lpm_power(sec_bat_get_lpmode(), power_type);
|
|
|
|
if (siop_level >= 100) {
|
|
if (!battery->chg_limit &&
|
|
((battery->dchg_temp >= battery->pdata->dchg_high_temp[pt]) ||
|
|
(battery->temperature >= battery->pdata->dchg_high_batt_temp[pt]))) {
|
|
battery->chg_limit = true;
|
|
charging_current = sec_bat_set_dchg_current(battery, power_type, pt);
|
|
input_current = charging_current / 2;
|
|
store_battery_log(
|
|
"Dchg:%d%%,%dmV,chg_lim(%d),tbat(%d),tdchg(%d),icurr(%d),ocurr(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now, battery->chg_limit,
|
|
battery->temperature, battery->dchg_temp, input_current, charging_current,
|
|
sb_get_ct_str(battery->cable_type));
|
|
} else if (battery->chg_limit) {
|
|
if ((battery->dchg_temp <= battery->pdata->dchg_high_temp_recovery[pt]) &&
|
|
(battery->temperature <= battery->pdata->dchg_high_batt_temp_recovery[pt])) {
|
|
battery->chg_limit = false;
|
|
sec_vote(battery->fcc_vote, VOTER_CHG_TEMP, false, 0);
|
|
sec_vote(battery->input_vote, VOTER_CHG_TEMP, false, 0);
|
|
store_battery_log(
|
|
"Dchg:%d%%,%dmV,chg_lim(%d),tbat(%d),tdchg(%d),icurr(%d),ocurr(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now, battery->chg_limit,
|
|
battery->temperature, battery->dchg_temp,
|
|
get_sec_vote_result(battery->input_vote),
|
|
get_sec_vote_result(battery->fcc_vote), sb_get_ct_str(battery->cable_type));
|
|
} else {
|
|
battery->chg_limit = true;
|
|
sec_bat_set_dchg_current(battery, power_type, pt);
|
|
}
|
|
}
|
|
pr_info("%s: chg_limit(%d)\n", __func__, battery->chg_limit);
|
|
} else if (battery->chg_limit) {
|
|
battery->chg_limit = false;
|
|
sec_vote(battery->fcc_vote, VOTER_CHG_TEMP, false, 0);
|
|
sec_vote(battery->input_vote, VOTER_CHG_TEMP, false, 0);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_KUNIT(sec_bat_check_direct_chg_temp);
|
|
#else
|
|
void sec_bat_check_direct_chg_temp(struct sec_battery_info *battery, int siop_level) {}
|
|
#endif
|
|
|
|
void sec_bat_check_pdic_temp(struct sec_battery_info *battery, int siop_level)
|
|
{
|
|
int input_current = 0, charging_current = 0;
|
|
bool pre_chg_limit = battery->chg_limit;
|
|
|
|
if (battery->pdata->chg_thm_info.check_type == SEC_BATTERY_TEMP_CHECK_NONE)
|
|
return;
|
|
|
|
if (battery->pdic_ps_rdy && siop_level >= 100) {
|
|
if ((!battery->chg_limit && (battery->chg_temp >= battery->pdata->chg_high_temp)) ||
|
|
(battery->chg_limit && (battery->chg_temp >= battery->pdata->chg_high_temp_recovery))) {
|
|
input_current =
|
|
(battery->pdata->chg_input_limit_current * SEC_INPUT_VOLTAGE_9V) / battery->input_voltage;
|
|
charging_current = battery->pdata->chg_charging_limit_current;
|
|
sec_vote(battery->fcc_vote, VOTER_CHG_TEMP, true, charging_current);
|
|
sec_vote(battery->input_vote, VOTER_CHG_TEMP, true, input_current);
|
|
if (!battery->chg_limit)
|
|
store_battery_log(
|
|
"Pdic:%d%%,%dmV,chg_lim(%d),tchg(%d),icurr(%d),ocurr(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now, true,
|
|
battery->chg_temp, input_current, charging_current,
|
|
sb_get_ct_str(battery->cable_type));
|
|
battery->chg_limit = true;
|
|
} else if (battery->chg_limit && battery->chg_temp <= battery->pdata->chg_high_temp_recovery) {
|
|
battery->chg_limit = false;
|
|
sec_vote(battery->fcc_vote, VOTER_CHG_TEMP, false, 0);
|
|
sec_vote(battery->input_vote, VOTER_CHG_TEMP, false, 0);
|
|
store_battery_log(
|
|
"Pdic:%d%%,%dmV,chg_lim(%d),tchg(%d),icurr(%d),ocurr(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now, battery->chg_limit,
|
|
battery->chg_temp, get_sec_vote_result(battery->input_vote),
|
|
get_sec_vote_result(battery->fcc_vote), sb_get_ct_str(battery->cable_type));
|
|
}
|
|
pr_info("%s: chg_limit(%d)\n", __func__, battery->chg_limit);
|
|
} else if (battery->chg_limit) {
|
|
battery->chg_limit = false;
|
|
sec_vote(battery->fcc_vote, VOTER_CHG_TEMP, false, 0);
|
|
sec_vote(battery->input_vote, VOTER_CHG_TEMP, false, 0);
|
|
}
|
|
|
|
/* FPDO DC concept */
|
|
if (battery->cable_type == SEC_BATTERY_CABLE_FPDO_DC && battery->chg_limit != pre_chg_limit) {
|
|
union power_supply_propval value = {0, };
|
|
|
|
value.intval = 0;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_EXT_PROP_REFRESH_CHARGING_SOURCE, value);
|
|
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_KUNIT(sec_bat_check_pdic_temp);
|
|
|
|
void sec_bat_check_afc_temp(struct sec_battery_info *battery, int siop_level)
|
|
{
|
|
int input_current = 0, charging_current = 0;
|
|
int ct = battery->cable_type;
|
|
|
|
if (battery->pdata->chg_thm_info.check_type == SEC_BATTERY_TEMP_CHECK_NONE)
|
|
return;
|
|
|
|
if (siop_level >= 100) {
|
|
#if defined(CONFIG_SUPPORT_HV_CTRL)
|
|
if (!battery->chg_limit && is_hv_wire_type(ct) &&
|
|
(battery->chg_temp >= battery->pdata->chg_high_temp)) {
|
|
input_current = battery->pdata->chg_input_limit_current;
|
|
charging_current = battery->pdata->chg_charging_limit_current;
|
|
battery->chg_limit = true;
|
|
sec_vote(battery->fcc_vote, VOTER_CHG_TEMP, true, charging_current);
|
|
sec_vote(battery->input_vote, VOTER_CHG_TEMP, true, input_current);
|
|
store_battery_log(
|
|
"Afc:%d%%,%dmV,chg_lim(%d),tchg(%d),icurr(%d),ocurr(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now, battery->chg_limit,
|
|
battery->chg_temp, input_current, charging_current,
|
|
sb_get_ct_str(ct));
|
|
} else if (!battery->chg_limit && battery->max_charge_power >=
|
|
(battery->pdata->pd_charging_charge_power - 500) &&
|
|
(battery->chg_temp >= battery->pdata->chg_high_temp)) {
|
|
input_current = battery->pdata->default_input_current;
|
|
charging_current = battery->pdata->default_charging_current;
|
|
battery->chg_limit = true;
|
|
sec_vote(battery->fcc_vote, VOTER_CHG_TEMP, true, charging_current);
|
|
sec_vote(battery->input_vote, VOTER_CHG_TEMP, true, input_current);
|
|
store_battery_log(
|
|
"Afc:%d%%,%dmV,chg_lim(%d),tchg(%d),icurr(%d),ocurr(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now, battery->chg_limit,
|
|
battery->chg_temp, input_current, charging_current,
|
|
sb_get_ct_str(battery->cable_type));
|
|
} else if (battery->chg_limit && is_hv_wire_type(ct)) {
|
|
if (battery->chg_temp <= battery->pdata->chg_high_temp_recovery) {
|
|
battery->chg_limit = false;
|
|
sec_vote(battery->fcc_vote, VOTER_CHG_TEMP, false, 0);
|
|
sec_vote(battery->input_vote, VOTER_CHG_TEMP, false, 0);
|
|
store_battery_log(
|
|
"Afc:%d%%,%dmV,chg_lim(%d),tchg(%d),icurr(%d),ocurr(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now, battery->chg_limit,
|
|
battery->chg_temp, get_sec_vote_result(battery->input_vote),
|
|
get_sec_vote_result(battery->fcc_vote), sb_get_ct_str(ct));
|
|
}
|
|
} else if (battery->chg_limit && battery->max_charge_power >=
|
|
(battery->pdata->pd_charging_charge_power - 500)) {
|
|
if (battery->chg_temp <= battery->pdata->chg_high_temp_recovery) {
|
|
battery->chg_limit = false;
|
|
sec_vote(battery->fcc_vote, VOTER_CHG_TEMP, false, 0);
|
|
sec_vote(battery->input_vote, VOTER_CHG_TEMP, false, 0);
|
|
store_battery_log(
|
|
"Afc:%d%%,%dmV,chg_lim(%d),tchg(%d),icurr(%d),ocurr(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now, battery->chg_limit,
|
|
battery->chg_temp, get_sec_vote_result(battery->input_vote),
|
|
get_sec_vote_result(battery->fcc_vote), sb_get_ct_str(ct));
|
|
}
|
|
}
|
|
pr_info("%s: cable_type(%d), chg_limit(%d)\n", __func__,
|
|
ct, battery->chg_limit);
|
|
#else
|
|
if ((!battery->chg_limit && is_hv_wire_type(ct) &&
|
|
(battery->chg_temp >= battery->pdata->chg_high_temp)) ||
|
|
(battery->chg_limit && is_hv_wire_type(ct) &&
|
|
(battery->chg_temp > battery->pdata->chg_high_temp_recovery))) {
|
|
if (!battery->chg_limit) {
|
|
input_current = battery->pdata->chg_input_limit_current;
|
|
charging_current = battery->pdata->chg_charging_limit_current;
|
|
battery->chg_limit = true;
|
|
sec_vote(battery->fcc_vote, VOTER_CHG_TEMP, true, charging_current);
|
|
sec_vote(battery->input_vote, VOTER_CHG_TEMP, true, input_current);
|
|
store_battery_log(
|
|
"Afc:%d%%,%dmV,chg_lim(%d),tchg(%d),icurr(%d),ocurr(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now, battery->chg_limit,
|
|
battery->chg_temp, input_current, charging_current,
|
|
sb_get_ct_str(ct));
|
|
}
|
|
} else if (battery->chg_limit && is_hv_wire_type(ct) &&
|
|
(battery->chg_temp <= battery->pdata->chg_high_temp_recovery)) {
|
|
battery->chg_limit = false;
|
|
sec_vote(battery->fcc_vote, VOTER_CHG_TEMP, false, 0);
|
|
sec_vote(battery->input_vote, VOTER_CHG_TEMP, false, 0);
|
|
store_battery_log(
|
|
"Afc:%d%%,%dmV,chg_lim(%d),tchg(%d),icurr(%d),ocurr(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now, battery->chg_limit,
|
|
battery->chg_temp, get_sec_vote_result(battery->input_vote),
|
|
get_sec_vote_result(battery->fcc_vote), sb_get_ct_str(ct));
|
|
}
|
|
#endif
|
|
} else if (battery->chg_limit) {
|
|
battery->chg_limit = false;
|
|
sec_vote(battery->fcc_vote, VOTER_CHG_TEMP, false, 0);
|
|
sec_vote(battery->input_vote, VOTER_CHG_TEMP, false, 0);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_KUNIT(sec_bat_check_afc_temp);
|
|
|
|
void sec_bat_set_threshold(struct sec_battery_info *battery, int cable_type)
|
|
{
|
|
if (is_wireless_fake_type(cable_type)) {
|
|
battery->cold_cool3_thresh = battery->pdata->wireless_cold_cool3_thresh;
|
|
battery->cool3_cool2_thresh = battery->pdata->wireless_cool3_cool2_thresh;
|
|
battery->cool2_cool1_thresh = battery->pdata->wireless_cool2_cool1_thresh;
|
|
battery->cool1_normal_thresh = battery->pdata->wireless_cool1_normal_thresh;
|
|
battery->normal_warm_thresh = battery->pdata->wireless_normal_warm_thresh;
|
|
battery->warm_overheat_thresh = battery->pdata->wireless_warm_overheat_thresh;
|
|
} else {
|
|
battery->cold_cool3_thresh = battery->pdata->wire_cold_cool3_thresh;
|
|
battery->cool3_cool2_thresh = battery->pdata->wire_cool3_cool2_thresh;
|
|
battery->cool2_cool1_thresh = battery->pdata->wire_cool2_cool1_thresh;
|
|
battery->cool1_normal_thresh = battery->pdata->wire_cool1_normal_thresh;
|
|
battery->normal_warm_thresh = battery->pdata->wire_normal_warm_thresh;
|
|
battery->warm_overheat_thresh = battery->pdata->wire_warm_overheat_thresh;
|
|
|
|
}
|
|
|
|
switch (battery->thermal_zone) {
|
|
case BAT_THERMAL_OVERHEATLIMIT:
|
|
battery->warm_overheat_thresh -= THERMAL_HYSTERESIS_2;
|
|
battery->normal_warm_thresh -= THERMAL_HYSTERESIS_2;
|
|
break;
|
|
case BAT_THERMAL_OVERHEAT:
|
|
battery->warm_overheat_thresh -= THERMAL_HYSTERESIS_2;
|
|
battery->normal_warm_thresh -= THERMAL_HYSTERESIS_2;
|
|
break;
|
|
case BAT_THERMAL_WARM:
|
|
battery->normal_warm_thresh -= THERMAL_HYSTERESIS_2;
|
|
break;
|
|
case BAT_THERMAL_COOL1:
|
|
battery->cool1_normal_thresh += THERMAL_HYSTERESIS_2;
|
|
break;
|
|
case BAT_THERMAL_COOL2:
|
|
battery->cool2_cool1_thresh += THERMAL_HYSTERESIS_2;
|
|
battery->cool1_normal_thresh += THERMAL_HYSTERESIS_2;
|
|
break;
|
|
case BAT_THERMAL_COOL3:
|
|
battery->cool3_cool2_thresh += THERMAL_HYSTERESIS_2;
|
|
battery->cool2_cool1_thresh += THERMAL_HYSTERESIS_2;
|
|
battery->cool1_normal_thresh += THERMAL_HYSTERESIS_2;
|
|
break;
|
|
case BAT_THERMAL_COLD:
|
|
battery->cold_cool3_thresh += THERMAL_HYSTERESIS_2;
|
|
battery->cool3_cool2_thresh += THERMAL_HYSTERESIS_2;
|
|
battery->cool2_cool1_thresh += THERMAL_HYSTERESIS_2;
|
|
battery->cool1_normal_thresh += THERMAL_HYSTERESIS_2;
|
|
break;
|
|
case BAT_THERMAL_NORMAL:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
int sec_usb_conn_gap_check(struct sec_battery_info *battery, int thm1_temp, int thm2_temp)
|
|
{
|
|
int gap = 0;
|
|
|
|
if (thm1_temp > thm2_temp)
|
|
gap = thm1_temp - thm2_temp;
|
|
|
|
pr_info("%s: thm1_temp(%d), thm2_temp(%d), gap(%d)\n",
|
|
__func__, thm1_temp, thm2_temp, gap);
|
|
|
|
if ((thm1_temp >= battery->usb_protection_temp) &&
|
|
(gap >= battery->temp_gap_bat_usb)) {
|
|
pr_info("%s: USB_CONN_GAP_OVER1 detected\n", __func__);
|
|
if (battery->run_usb_conn_check && battery->usb_conn_check_cnt > 0) {
|
|
battery->cisd.data[CISD_DATA_USB_OVERHEAT_RAPID_CHANGE]++;
|
|
battery->cisd.data[CISD_DATA_USB_OVERHEAT_RAPID_CHANGE_PER_DAY]++;
|
|
} else {
|
|
battery->cisd.data[CISD_DATA_USB_OVERHEAT_ALONE]++;
|
|
battery->cisd.data[CISD_DATA_USB_OVERHEAT_ALONE_PER_DAY]++;
|
|
}
|
|
return USB_CONN_GAP_OVER1;
|
|
}
|
|
|
|
return USB_CONN_NORMAL;
|
|
}
|
|
|
|
int sec_usb_conn_slope_check(struct sec_battery_info *battery, int cur_usb_temp, int prev_usb_temp)
|
|
{
|
|
int usb_temp_gap = 0, usb_temp_gap_avg = 0;
|
|
static int usb_temp_sum;
|
|
static unsigned int valid_temp_cnt;
|
|
|
|
if (battery->usb_conn_check_cnt == 1) {
|
|
usb_temp_sum = 0;
|
|
valid_temp_cnt = 0;
|
|
}
|
|
|
|
usb_temp_gap = cur_usb_temp - prev_usb_temp;
|
|
pr_info("%s: prev_usb_temp(%d) -> cur_usb_temp(%d), usb_temp_gap(%d)\n",
|
|
__func__, prev_usb_temp, cur_usb_temp, usb_temp_gap);
|
|
|
|
if (cur_usb_temp >= 100 && usb_temp_gap < 50) {
|
|
usb_temp_sum += usb_temp_gap;
|
|
valid_temp_cnt++;
|
|
pr_info("%s: usb_temp_sum(%d), valid_temp_cnt(%d)\n", __func__,
|
|
usb_temp_sum, valid_temp_cnt);
|
|
if (usb_temp_sum > 0 && battery->usb_conn_check_cnt == MAX_USB_CONN_CHECK_CNT) {
|
|
usb_temp_gap_avg = usb_temp_sum / valid_temp_cnt;
|
|
pr_info("%s: usb_temp_gap_avg(%d)\n", __func__, usb_temp_gap_avg);
|
|
if (usb_temp_gap_avg >= battery->pdata->usb_conn_slope_avg) {
|
|
pr_info("%s: USB_CONN_SLOPE_OVER detected\n", __func__);
|
|
battery->cisd.data[CISD_DATA_USB_OVERHEAT_RAPID_CHANGE]++;
|
|
battery->cisd.data[CISD_DATA_USB_OVERHEAT_RAPID_CHANGE_PER_DAY]++;
|
|
return USB_CONN_SLOPE_OVER;
|
|
}
|
|
}
|
|
}
|
|
|
|
return USB_CONN_NORMAL;
|
|
}
|
|
|
|
void sec_usb_conn_protection(struct sec_battery_info *battery)
|
|
{
|
|
int thm1_temp = battery->usb_temp; // default for flagship models, THM1 = USB_THM
|
|
int thm2_temp = battery->temperature; // default for flagship models, THM2 = BAT_THM
|
|
|
|
if (battery->pdata->usb_thm_info.check_type == SEC_BATTERY_TEMP_CHECK_NONE) {
|
|
// there is no USB_THM, mass models, THM1 = BAT_THM, THM2 = CHG_THM
|
|
battery->usb_temp = battery->temperature;
|
|
thm1_temp = battery->temperature;
|
|
thm2_temp = battery->chg_temp;
|
|
} else if (battery->pdata->mass_with_usb_thm) {
|
|
// there is USB_THM, mass models, THM1 = USB_THM, THM2 = CHG_THM
|
|
thm1_temp = battery->usb_temp;
|
|
thm2_temp = battery->chg_temp;
|
|
}
|
|
|
|
battery->usb_conn_status = sec_usb_conn_gap_check(battery, thm1_temp, thm2_temp);
|
|
if (battery->usb_conn_status != USB_CONN_NORMAL) {
|
|
battery->run_usb_conn_check = false;
|
|
battery->usb_conn_check_cnt = 0;
|
|
__pm_relax(battery->usb_conn_check_ws);
|
|
cancel_delayed_work(&battery->usb_conn_check_work);
|
|
}
|
|
}
|
|
|
|
int sec_usb_conn_check(struct sec_battery_info *battery)
|
|
{
|
|
int cur_bat_temp = 0;
|
|
int cur_sub_bat_temp = 0;
|
|
int cur_usb_temp = 0;
|
|
int cur_chg_temp = 0;
|
|
int prev_usb_temp = battery->usb_temp;
|
|
int thm1_temp = 0, thm2_temp = 0;
|
|
battery->usb_conn_status = USB_CONN_NORMAL;
|
|
|
|
if (battery->pdata->usb_thm_info.check_type != SEC_BATTERY_TEMP_CHECK_NONE) {
|
|
cur_usb_temp = sec_bat_get_temperature(battery->dev, &battery->pdata->usb_thm_info, cur_usb_temp,
|
|
battery->pdata->charger_name, battery->pdata->fuelgauge_name, battery->pdata->adc_read_type);
|
|
thm1_temp = cur_usb_temp;
|
|
if (battery->pdata->mass_with_usb_thm) {
|
|
// there is USB_THM, mass models, THM1 = USB_THM, THM2 = CHG_THM
|
|
cur_chg_temp = sec_bat_get_temperature(battery->dev, &battery->pdata->chg_thm_info, cur_chg_temp,
|
|
battery->pdata->charger_name, battery->pdata->fuelgauge_name,
|
|
battery->pdata->adc_read_type);
|
|
thm2_temp = cur_chg_temp;
|
|
} else {
|
|
// there is USB_THM, flagship models, THM1 = USB_THM, THM2 = SUB_THM
|
|
if (battery->pdata->lr_enable) {
|
|
cur_sub_bat_temp = sec_bat_get_temperature(battery->dev, &battery->pdata->sub_bat_thm_info, cur_sub_bat_temp,
|
|
battery->pdata->charger_name, battery->pdata->fuelgauge_name,
|
|
battery->pdata->adc_read_type);
|
|
thm2_temp = cur_sub_bat_temp;
|
|
} else {
|
|
// there is USB_THM, flagship models, THM1 = USB_THM, THM2 = BAT_THM
|
|
cur_bat_temp = sec_bat_get_temperature(battery->dev, &battery->pdata->bat_thm_info, cur_bat_temp,
|
|
battery->pdata->charger_name, battery->pdata->fuelgauge_name,
|
|
battery->pdata->adc_read_type);
|
|
thm2_temp = cur_bat_temp;
|
|
}
|
|
}
|
|
} else {
|
|
pr_err("%s: USB_THM, Invalid Temp Check Type, usb_thm <- bat_thm\n", __func__);
|
|
// there is no USB_THM, mass models, THM1 = BAT_THM, THM2 = CHG_THM
|
|
cur_bat_temp = sec_bat_get_temperature(battery->dev, &battery->pdata->bat_thm_info, cur_bat_temp,
|
|
battery->pdata->charger_name, battery->pdata->fuelgauge_name, battery->pdata->adc_read_type);
|
|
cur_chg_temp = sec_bat_get_temperature(battery->dev, &battery->pdata->chg_thm_info, cur_chg_temp,
|
|
battery->pdata->charger_name, battery->pdata->fuelgauge_name, battery->pdata->adc_read_type);
|
|
cur_usb_temp = cur_bat_temp;
|
|
thm1_temp = cur_bat_temp;
|
|
thm2_temp = cur_chg_temp;
|
|
}
|
|
|
|
battery->usb_conn_status = sec_usb_conn_slope_check(battery, cur_usb_temp, prev_usb_temp);
|
|
if (battery->usb_conn_status == USB_CONN_NORMAL)
|
|
battery->usb_conn_status = sec_usb_conn_gap_check(battery, thm1_temp, thm2_temp);
|
|
|
|
battery->usb_temp = cur_usb_temp;
|
|
|
|
return battery->usb_conn_status;
|
|
}
|
|
|
|
void sec_bat_thermal_charging_status(struct sec_battery_info *battery)
|
|
{
|
|
#if defined(CONFIG_ENABLE_FULL_BY_SOC)
|
|
if ((battery->capacity >= 100) || (battery->status == POWER_SUPPLY_STATUS_FULL))
|
|
sec_bat_set_charging_status(battery, POWER_SUPPLY_STATUS_FULL);
|
|
else
|
|
sec_bat_set_charging_status(battery, POWER_SUPPLY_STATUS_CHARGING);
|
|
#else
|
|
if (battery->status != POWER_SUPPLY_STATUS_FULL)
|
|
sec_bat_set_charging_status(battery, POWER_SUPPLY_STATUS_CHARGING);
|
|
#endif
|
|
}
|
|
|
|
int sec_usb_temp_gap_check(struct sec_battery_info *battery,
|
|
bool tmp_chk, int usb_temp)
|
|
{
|
|
int gap = 0;
|
|
int bat_thm = battery->temperature;
|
|
|
|
#if IS_ENABLED(CONFIG_DUAL_BATTERY)
|
|
/* select low temp thermistor */
|
|
if (battery->temperature > battery->sub_bat_temp)
|
|
bat_thm = battery->sub_bat_temp;
|
|
#endif
|
|
if (usb_temp > bat_thm)
|
|
gap = usb_temp - bat_thm;
|
|
|
|
if (tmp_chk) { /* check usb temp gap */
|
|
if ((usb_temp >= battery->usb_protection_temp) &&
|
|
(gap >= battery->temp_gap_bat_usb)) {
|
|
pr_info("%s: Temp gap between Usb temp and Bat temp : %d\n", __func__, gap);
|
|
return USB_CONN_GAP_OVER1;
|
|
} else if ((usb_temp >= battery->overheatlimit_threshold) &&
|
|
(gap >= (battery->temp_gap_bat_usb - 100))) {
|
|
pr_info("%s: Usb Temp (%d) over and gap between Usb temp and Bat temp : %d\n",
|
|
__func__, usb_temp, gap);
|
|
return USB_CONN_GAP_OVER2;
|
|
}
|
|
} else { /* recover check */
|
|
if ((battery->usb_conn_status == USB_CONN_GAP_OVER1) &&
|
|
(usb_temp >= battery->usb_protection_temp)) {
|
|
return USB_CONN_GAP_OVER1;
|
|
|
|
} else if ((battery->usb_conn_status == USB_CONN_GAP_OVER2) &&
|
|
(usb_temp >= battery->overheatlimit_threshold)) {
|
|
return USB_CONN_GAP_OVER2;
|
|
}
|
|
}
|
|
pr_info("%s: %s -> NORMAL\n", __func__, sec_usb_conn_str(battery->usb_conn_status));
|
|
|
|
return USB_CONN_NORMAL;
|
|
}
|
|
|
|
void sec_usb_thm_overheatlimit(struct sec_battery_info *battery)
|
|
{
|
|
bool use_usb_temp = (battery->pdata->usb_thm_info.check_type != SEC_BATTERY_TEMP_CHECK_NONE);
|
|
int usb_temp = battery->usb_temp;
|
|
|
|
if (!use_usb_temp) {
|
|
pr_err("%s: USB_THM, Invalid Temp Check Type, usb_thm <- bat_thm\n", __func__);
|
|
battery->usb_temp = battery->temperature;
|
|
usb_temp = battery->temperature;
|
|
}
|
|
#if defined(CONFIG_SEC_FACTORY)
|
|
use_usb_temp = false;
|
|
#endif
|
|
|
|
switch (battery->usb_conn_status) {
|
|
case USB_CONN_NORMAL:
|
|
if ((usb_temp >= battery->overheatlimit_threshold) &&
|
|
!use_usb_temp) {
|
|
pr_info("%s: Usb Temp over than %d (usb_thm : %d)\n", __func__,
|
|
battery->overheatlimit_threshold, usb_temp);
|
|
battery->usb_conn_status = USB_CONN_OVERHEATLIMIT;
|
|
} else {
|
|
if (use_usb_temp)
|
|
battery->usb_conn_status = sec_usb_temp_gap_check(battery, true, usb_temp);
|
|
}
|
|
break;
|
|
case USB_CONN_OVERHEATLIMIT:
|
|
if (usb_temp <= battery->overheatlimit_recovery)
|
|
battery->usb_conn_status = USB_CONN_NORMAL;
|
|
break;
|
|
case USB_CONN_GAP_OVER1:
|
|
case USB_CONN_GAP_OVER2:
|
|
battery->usb_conn_status = sec_usb_temp_gap_check(battery, false, usb_temp);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
int sec_usb_protection_gap_check(struct sec_battery_info *battery, bool tmp_chk, int thm1_temp, int thm2_temp)
|
|
{
|
|
int gap = 0;
|
|
|
|
if (thm1_temp > thm2_temp)
|
|
gap = thm1_temp - thm2_temp;
|
|
|
|
if (tmp_chk) { /* check usb temp gap */
|
|
if ((thm1_temp >= battery->usb_protection_temp) &&
|
|
(gap >= battery->temp_gap_bat_usb)) {
|
|
pr_info("%s: Temp gap between THM1 temp and THM2 temp : %d\n", __func__, gap);
|
|
return USB_CONN_GAP_OVER1;
|
|
} else if ((thm1_temp >= battery->overheatlimit_threshold) &&
|
|
(gap >= (battery->temp_gap_bat_usb - 100))) {
|
|
pr_info("%s: THM1 Temp (%d) over and gap between THM1 temp and THM2 temp : %d\n",
|
|
__func__, thm1_temp, gap);
|
|
return USB_CONN_GAP_OVER2;
|
|
}
|
|
} else { /* recover check */
|
|
if ((battery->usb_conn_status == USB_CONN_GAP_OVER1) &&
|
|
(thm1_temp >= battery->usb_protection_temp)) {
|
|
return USB_CONN_GAP_OVER1;
|
|
|
|
} else if ((battery->usb_conn_status == USB_CONN_GAP_OVER2) &&
|
|
(thm1_temp >= battery->overheatlimit_threshold)) {
|
|
return USB_CONN_GAP_OVER2;
|
|
}
|
|
}
|
|
pr_info("%s: %s -> NORMAL\n", __func__, sec_usb_conn_str(battery->usb_conn_status));
|
|
|
|
return USB_CONN_NORMAL;
|
|
}
|
|
|
|
void sec_usb_protection(struct sec_battery_info *battery)
|
|
{
|
|
// gap = THM1_temperature - THM2_temperature
|
|
int thm1_temp = battery->usb_temp; // default for flagship models, THM1 = USB_THM
|
|
int thm2_temp = battery->temperature; // default for flagship models, THM2 = BAT_THM
|
|
|
|
if (battery->pdata->usb_thm_info.check_type == SEC_BATTERY_TEMP_CHECK_NONE) {
|
|
// there is no USB_THM, mass models, THM1 = BAT_THM, THM2 = CHG_THM
|
|
battery->usb_temp = battery->temperature;
|
|
thm1_temp = battery->temperature;
|
|
thm2_temp = battery->chg_temp;
|
|
} else if (battery->pdata->mass_with_usb_thm) {
|
|
// there is USB_THM, mass models, THM1 = USB_THM, THM2 = CHG_THM
|
|
thm1_temp = battery->usb_temp;
|
|
thm2_temp = battery->chg_temp;
|
|
}
|
|
#if IS_ENABLED(CONFIG_DUAL_BATTERY)
|
|
/* select low temp thermistor */
|
|
if (thm2_temp > battery->sub_bat_temp)
|
|
thm2_temp = battery->sub_bat_temp;
|
|
#endif
|
|
|
|
switch (battery->usb_conn_status) {
|
|
case USB_CONN_NORMAL:
|
|
battery->usb_conn_status = sec_usb_protection_gap_check(battery, true, thm1_temp, thm2_temp);
|
|
break;
|
|
case USB_CONN_GAP_OVER1:
|
|
case USB_CONN_GAP_OVER2:
|
|
battery->usb_conn_status = sec_usb_protection_gap_check(battery, false, thm1_temp, thm2_temp);
|
|
break;
|
|
default:
|
|
pr_info("%s: Unknown usb_conn_status(%d), forced set to NORMAL\n", __func__, battery->usb_conn_status);
|
|
battery->usb_conn_status = USB_CONN_NORMAL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void sec_bat_thermal_check(struct sec_battery_info *battery)
|
|
{
|
|
int bat_thm = battery->temperature;
|
|
int pre_thermal_zone = battery->thermal_zone;
|
|
int voter_status = SEC_BAT_CHG_MODE_CHARGING;
|
|
|
|
#if IS_ENABLED(CONFIG_DUAL_BATTERY)
|
|
union power_supply_propval val = {0, };
|
|
|
|
bat_thm = sec_bat_get_high_priority_temp(battery);
|
|
#endif
|
|
|
|
pr_err("%s: co_c3: %d, c3_c2: %d, c2_c1: %d, c1_no: %d, no_wa: %d, wa_ov: %d, tz(%s)\n", __func__,
|
|
battery->cold_cool3_thresh, battery->cool3_cool2_thresh, battery->cool2_cool1_thresh,
|
|
battery->cool1_normal_thresh, battery->normal_warm_thresh, battery->warm_overheat_thresh,
|
|
sec_bat_thermal_zone[battery->thermal_zone]);
|
|
|
|
if ((battery->status == POWER_SUPPLY_STATUS_DISCHARGING && battery->usb_conn_status == USB_CONN_NORMAL) ||
|
|
#if defined(CONFIG_BC12_DEVICE) && defined(CONFIG_SEC_FACTORY)
|
|
battery->vbat_adc_open ||
|
|
#endif
|
|
battery->skip_swelling) {
|
|
battery->health_change = false;
|
|
pr_debug("%s: DISCHARGING or 15 test mode. stop thermal check\n", __func__);
|
|
battery->thermal_zone = BAT_THERMAL_NORMAL;
|
|
battery->usb_conn_status = USB_CONN_NORMAL;
|
|
sec_vote(battery->topoff_vote, VOTER_SWELLING, false, 0);
|
|
sec_vote(battery->fcc_vote, VOTER_SWELLING, false, 0);
|
|
sec_vote(battery->fv_vote, VOTER_SWELLING, false, 0);
|
|
sec_vote(battery->input_vote, VOTER_SWELLING, false, 0);
|
|
if (battery->dchg_dc_in_swelling)
|
|
sec_vote(battery->dc_fv_vote, VOTER_SWELLING, false, 0);
|
|
sec_vote(battery->chgen_vote, VOTER_SWELLING, false, 0);
|
|
sec_vote(battery->chgen_vote, VOTER_CHANGE_CHGMODE, false, 0);
|
|
sec_vote(battery->iv_vote, VOTER_CHANGE_CHGMODE, false, 0);
|
|
sec_bat_set_current_event(battery, 0, SEC_BAT_CURRENT_EVENT_SWELLING_MODE);
|
|
sec_bat_set_threshold(battery, battery->cable_type);
|
|
return;
|
|
}
|
|
|
|
if (battery->pdata->bat_thm_info.check_type == SEC_BATTERY_TEMP_CHECK_NONE) {
|
|
pr_err("%s: BAT_THM, Invalid Temp Check Type\n", __func__);
|
|
return;
|
|
} else {
|
|
/* COLD - COOL3 - COOL2 - COOL1 - NORMAL - WARM - OVERHEAT - OVERHEATLIMIT*/
|
|
if (battery->pdata->support_usb_conn_check) {
|
|
if (battery->usb_conn_status == USB_CONN_NORMAL) /* 2023.03.20 new concept */
|
|
sec_usb_conn_protection(battery);
|
|
} else if (battery->pdata->usb_protection) /* 2022.03.03 new concept */
|
|
sec_usb_protection(battery);
|
|
else /* original usb protection concept */
|
|
sec_usb_thm_overheatlimit(battery);
|
|
|
|
/* Fix usb_conn_status at the request of Reliability Group Test */
|
|
if (battery->current_event & SEC_BAT_CURRENT_EVENT_TEMP_CTRL_TEST)
|
|
battery->usb_conn_status = USB_CONN_NORMAL;
|
|
|
|
if (battery->usb_conn_status != USB_CONN_NORMAL) {
|
|
battery->thermal_zone = BAT_THERMAL_OVERHEATLIMIT;
|
|
} else if (bat_thm >= battery->normal_warm_thresh) {
|
|
if (bat_thm >= battery->warm_overheat_thresh) {
|
|
battery->thermal_zone = BAT_THERMAL_OVERHEAT;
|
|
} else {
|
|
battery->thermal_zone = BAT_THERMAL_WARM;
|
|
}
|
|
} else if (bat_thm <= battery->cool1_normal_thresh) {
|
|
if (bat_thm <= battery->cold_cool3_thresh) {
|
|
battery->thermal_zone = BAT_THERMAL_COLD;
|
|
} else if (bat_thm <= battery->cool3_cool2_thresh) {
|
|
battery->thermal_zone = BAT_THERMAL_COOL3;
|
|
} else if (bat_thm <= battery->cool2_cool1_thresh) {
|
|
battery->thermal_zone = BAT_THERMAL_COOL2;
|
|
} else {
|
|
battery->thermal_zone = BAT_THERMAL_COOL1;
|
|
}
|
|
} else {
|
|
battery->thermal_zone = BAT_THERMAL_NORMAL;
|
|
}
|
|
}
|
|
|
|
if (pre_thermal_zone != battery->thermal_zone) {
|
|
battery->bat_thm_count++;
|
|
|
|
if (battery->bat_thm_count < battery->pdata->temp_check_count) {
|
|
pr_info("%s : bat_thm_count %d/%d\n", __func__,
|
|
battery->bat_thm_count, battery->pdata->temp_check_count);
|
|
battery->thermal_zone = pre_thermal_zone;
|
|
return;
|
|
}
|
|
|
|
/* FPDO DC concept */
|
|
if (battery->cable_type == SEC_BATTERY_CABLE_FPDO_DC && battery->thermal_zone != BAT_THERMAL_NORMAL) {
|
|
union power_supply_propval value = {0, };
|
|
|
|
value.intval = 0;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_EXT_PROP_REFRESH_CHARGING_SOURCE, value);
|
|
|
|
}
|
|
|
|
pr_info("%s: thermal zone update (%s -> %s), bat_thm(%d), usb_thm(%d)\n", __func__,
|
|
sec_bat_thermal_zone[pre_thermal_zone],
|
|
sec_bat_thermal_zone[battery->thermal_zone], bat_thm, battery->usb_temp);
|
|
battery->health_change = true;
|
|
battery->bat_thm_count = 0;
|
|
|
|
pr_info("%s : SAFETY TIME RESET!\n", __func__);
|
|
battery->expired_time = battery->pdata->expired_time;
|
|
battery->prev_safety_time = 0;
|
|
|
|
sec_bat_set_threshold(battery, battery->cable_type);
|
|
sec_bat_set_current_event(battery, 0, SEC_BAT_CURRENT_EVENT_SWELLING_MODE);
|
|
|
|
switch (battery->thermal_zone) {
|
|
case BAT_THERMAL_OVERHEATLIMIT:
|
|
if (battery->status != POWER_SUPPLY_STATUS_DISCHARGING) {
|
|
sec_bat_set_health(battery, POWER_SUPPLY_EXT_HEALTH_OVERHEATLIMIT);
|
|
sec_bat_set_charging_status(battery, POWER_SUPPLY_STATUS_NOT_CHARGING);
|
|
sec_vote(battery->chgen_vote, VOTER_SWELLING, true, SEC_BAT_CHG_MODE_BUCK_OFF);
|
|
battery->cisd.data[CISD_DATA_UNSAFETY_TEMPERATURE]++;
|
|
battery->cisd.data[CISD_DATA_UNSAFE_TEMPERATURE_PER_DAY]++;
|
|
sec_vote(battery->iv_vote, VOTER_MUIC_ABNORMAL, true, SEC_INPUT_VOLTAGE_5V);
|
|
#if !defined(CONFIG_SEC_FACTORY)
|
|
if (!sec_bat_get_lpmode()) {
|
|
#if IS_ENABLED(CONFIG_MUIC_NOTIFIER)
|
|
muic_set_hiccup_mode(1);
|
|
#endif
|
|
if (is_pd_wire_type(battery->cable_type) || battery->pdata->mass_with_usb_thm)
|
|
sec_pd_manual_ccopen_req(1);
|
|
}
|
|
} else { // if already in discharging, just set misc_event
|
|
pr_info("%s: Set BATT_MISC_EVENT_TEMP_HICCUP_TYPE for discharging\n", __func__);
|
|
sec_bat_set_misc_event(battery,
|
|
BATT_MISC_EVENT_TEMP_HICCUP_TYPE, BATT_MISC_EVENT_TEMP_HICCUP_TYPE);
|
|
battery->usb_conn_status = USB_CONN_NORMAL;
|
|
#endif
|
|
}
|
|
store_battery_log(
|
|
"OHL:%d%%,%dmV,usb_conn_st(%d),tbat(%d),tusb(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now,
|
|
battery->usb_conn_status, bat_thm,
|
|
battery->usb_temp, sb_get_ct_str(battery->cable_type));
|
|
break;
|
|
case BAT_THERMAL_OVERHEAT:
|
|
battery->usb_conn_status = USB_CONN_NORMAL;
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_HIGH_TEMP_SWELLING,
|
|
SEC_BAT_CURRENT_EVENT_SWELLING_MODE);
|
|
if (battery->voltage_now > battery->pdata->high_temp_float) {
|
|
#if defined(CONFIG_WIRELESS_TX_MODE)
|
|
if (get_sec_vote_result(battery->iv_vote) > SEC_INPUT_VOLTAGE_5V) {
|
|
sec_vote(battery->iv_vote, VOTER_CHANGE_CHGMODE, true, SEC_INPUT_VOLTAGE_5V);
|
|
sec_vote(battery->chgen_vote, VOTER_CHANGE_CHGMODE, true, SEC_BAT_CHG_MODE_NOT_SET);
|
|
}
|
|
#endif
|
|
sec_vote(battery->chgen_vote, VOTER_SWELLING, true, SEC_BAT_CHG_MODE_BUCK_OFF);
|
|
} else {
|
|
sec_vote(battery->chgen_vote, VOTER_SWELLING, true, SEC_BAT_CHG_MODE_CHARGING_OFF);
|
|
sec_vote(battery->iv_vote, VOTER_CHANGE_CHGMODE, false, 0);
|
|
}
|
|
sec_bat_set_health(battery, POWER_SUPPLY_HEALTH_OVERHEAT);
|
|
sec_bat_set_charging_status(battery, POWER_SUPPLY_STATUS_NOT_CHARGING);
|
|
battery->cisd.data[CISD_DATA_UNSAFETY_TEMPERATURE]++;
|
|
battery->cisd.data[CISD_DATA_UNSAFE_TEMPERATURE_PER_DAY]++;
|
|
store_battery_log(
|
|
"OH:%d%%,%dmV,tbat(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now,
|
|
bat_thm, sb_get_ct_str(battery->cable_type));
|
|
break;
|
|
case BAT_THERMAL_WARM:
|
|
battery->usb_conn_status = USB_CONN_NORMAL;
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_HIGH_TEMP_SWELLING,
|
|
SEC_BAT_CURRENT_EVENT_SWELLING_MODE);
|
|
sec_bat_thermal_charging_status(battery);
|
|
if (battery->voltage_now > battery->pdata->high_temp_float) {
|
|
if ((battery->wc_tx_enable || battery->uno_en) &&
|
|
(is_hv_wire_type(battery->cable_type) ||
|
|
is_pd_wire_type(battery->cable_type))) {
|
|
sec_vote(battery->chgen_vote, VOTER_SWELLING, true,
|
|
SEC_BAT_CHG_MODE_CHARGING_OFF);
|
|
} else {
|
|
sec_vote(battery->chgen_vote, VOTER_SWELLING,
|
|
true, SEC_BAT_CHG_MODE_BUCK_OFF);
|
|
}
|
|
sec_bat_thermal_warm_wc_fod(battery, false);
|
|
} else if ((battery->voltage_now > battery->pdata->swelling_high_rechg_voltage) &&
|
|
!battery->pdata->chgen_over_swell_rechg_vol) {
|
|
sec_vote(battery->chgen_vote, VOTER_SWELLING, true, SEC_BAT_CHG_MODE_CHARGING_OFF);
|
|
sec_bat_thermal_warm_wc_fod(battery, false);
|
|
} else {
|
|
sec_vote(battery->chgen_vote, VOTER_SWELLING, true, SEC_BAT_CHG_MODE_CHARGING);
|
|
sec_vote(battery->input_vote, VOTER_SWELLING, false, 0);
|
|
sec_bat_thermal_warm_wc_fod(battery, true);
|
|
}
|
|
|
|
if (is_wireless_fake_type(battery->cable_type)) {
|
|
sec_vote(battery->fcc_vote, VOTER_SWELLING, true, battery->pdata->wireless_warm_current);
|
|
battery->cisd.data[CISD_DATA_WC_HIGH_TEMP_SWELLING]++;
|
|
battery->cisd.data[CISD_DATA_WC_HIGH_TEMP_SWELLING_PER_DAY]++;
|
|
} else {
|
|
sec_vote(battery->fcc_vote, VOTER_SWELLING, true, battery->pdata->wire_warm_current);
|
|
battery->cisd.data[CISD_DATA_HIGH_TEMP_SWELLING]++;
|
|
battery->cisd.data[CISD_DATA_HIGH_TEMP_SWELLING_PER_DAY]++;
|
|
}
|
|
sec_vote(battery->fv_vote, VOTER_SWELLING, true, battery->pdata->high_temp_float);
|
|
if (battery->dchg_dc_in_swelling)
|
|
sec_vote(battery->dc_fv_vote, VOTER_SWELLING, true, battery->pdata->high_temp_float);
|
|
sec_vote(battery->topoff_vote, VOTER_SWELLING, true, battery->pdata->full_check_current_2nd);
|
|
sec_vote(battery->iv_vote, VOTER_CHANGE_CHGMODE, false, 0);
|
|
|
|
sec_bat_set_health(battery, POWER_SUPPLY_HEALTH_GOOD);
|
|
store_battery_log(
|
|
"THM_W:%d%%,%dmV,tbat(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now,
|
|
bat_thm, sb_get_ct_str(battery->cable_type));
|
|
break;
|
|
case BAT_THERMAL_COOL1:
|
|
battery->usb_conn_status = USB_CONN_NORMAL;
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_LOW_TEMP_SWELLING_COOL1,
|
|
SEC_BAT_CURRENT_EVENT_SWELLING_MODE);
|
|
sec_bat_thermal_charging_status(battery);
|
|
if (is_wireless_fake_type(battery->cable_type)) {
|
|
sec_vote(battery->fcc_vote, VOTER_SWELLING, true, battery->pdata->wireless_cool1_current);
|
|
} else {
|
|
sec_vote(battery->fcc_vote, VOTER_SWELLING, true, battery->pdata->wire_cool1_current);
|
|
}
|
|
sec_vote(battery->fv_vote, VOTER_SWELLING, true, battery->pdata->low_temp_float);
|
|
if (battery->dchg_dc_in_swelling)
|
|
sec_vote(battery->dc_fv_vote, VOTER_SWELLING, true, battery->pdata->low_temp_float);
|
|
sec_vote(battery->input_vote, VOTER_SWELLING, false, 0);
|
|
sec_vote(battery->topoff_vote, VOTER_SWELLING, false, 0);
|
|
sec_vote(battery->chgen_vote, VOTER_SWELLING, true, SEC_BAT_CHG_MODE_CHARGING);
|
|
sec_vote(battery->iv_vote, VOTER_CHANGE_CHGMODE, false, 0);
|
|
sec_bat_set_health(battery, POWER_SUPPLY_HEALTH_GOOD);
|
|
store_battery_log(
|
|
"THM_C1:%d%%,%dmV,tbat(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now,
|
|
bat_thm, sb_get_ct_str(battery->cable_type));
|
|
break;
|
|
case BAT_THERMAL_COOL2:
|
|
battery->usb_conn_status = USB_CONN_NORMAL;
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_LOW_TEMP_SWELLING_COOL2,
|
|
SEC_BAT_CURRENT_EVENT_SWELLING_MODE);
|
|
sec_bat_thermal_charging_status(battery);
|
|
if (is_wireless_fake_type(battery->cable_type)) {
|
|
sec_vote(battery->fcc_vote, VOTER_SWELLING, true, battery->pdata->wireless_cool2_current);
|
|
} else {
|
|
sec_vote(battery->fcc_vote, VOTER_SWELLING, true, battery->pdata->wire_cool2_current);
|
|
}
|
|
sec_vote(battery->fv_vote, VOTER_SWELLING, true, battery->pdata->low_temp_float);
|
|
if (battery->dchg_dc_in_swelling)
|
|
sec_vote(battery->dc_fv_vote, VOTER_SWELLING, true, battery->pdata->low_temp_float);
|
|
sec_vote(battery->input_vote, VOTER_SWELLING, false, 0);
|
|
sec_vote(battery->topoff_vote, VOTER_SWELLING, false, 0);
|
|
sec_vote(battery->chgen_vote, VOTER_SWELLING, true, SEC_BAT_CHG_MODE_CHARGING);
|
|
sec_vote(battery->iv_vote, VOTER_CHANGE_CHGMODE, false, 0);
|
|
sec_bat_set_health(battery, POWER_SUPPLY_HEALTH_GOOD);
|
|
store_battery_log(
|
|
"THM_C2:%d%%,%dmV,tbat(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now,
|
|
bat_thm, sb_get_ct_str(battery->cable_type));
|
|
break;
|
|
case BAT_THERMAL_COOL3:
|
|
battery->usb_conn_status = USB_CONN_NORMAL;
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_LOW_TEMP_SWELLING_COOL3,
|
|
SEC_BAT_CURRENT_EVENT_SWELLING_MODE);
|
|
sec_bat_thermal_charging_status(battery);
|
|
if (is_wireless_fake_type(battery->cable_type)) {
|
|
sec_vote(battery->fcc_vote, VOTER_SWELLING, true, battery->pdata->wireless_cool3_current);
|
|
} else {
|
|
sec_vote(battery->fcc_vote, VOTER_SWELLING, true, battery->pdata->wire_cool3_current);
|
|
}
|
|
sec_vote(battery->fv_vote, VOTER_SWELLING, true, battery->pdata->low_temp_cool3_float);
|
|
if (battery->dchg_dc_in_swelling)
|
|
sec_vote(battery->dc_fv_vote, VOTER_SWELLING, true,
|
|
battery->pdata->low_temp_cool3_float);
|
|
sec_vote(battery->input_vote, VOTER_SWELLING, false, 0);
|
|
sec_vote(battery->topoff_vote, VOTER_SWELLING, true, battery->pdata->full_check_current_2nd);
|
|
sec_vote(battery->chgen_vote, VOTER_SWELLING, true, SEC_BAT_CHG_MODE_CHARGING);
|
|
sec_vote(battery->iv_vote, VOTER_CHANGE_CHGMODE, false, 0);
|
|
sec_bat_set_health(battery, POWER_SUPPLY_HEALTH_GOOD);
|
|
store_battery_log(
|
|
"THM_C3:%d%%,%dmV,tbat(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now,
|
|
bat_thm, sb_get_ct_str(battery->cable_type));
|
|
break;
|
|
case BAT_THERMAL_COLD:
|
|
battery->usb_conn_status = USB_CONN_NORMAL;
|
|
sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_LOW_TEMP_SWELLING_COOL3,
|
|
SEC_BAT_CURRENT_EVENT_SWELLING_MODE);
|
|
sec_vote(battery->input_vote, VOTER_SWELLING, false, 0);
|
|
sec_vote(battery->chgen_vote, VOTER_SWELLING, true, SEC_BAT_CHG_MODE_CHARGING_OFF);
|
|
sec_vote(battery->iv_vote, VOTER_CHANGE_CHGMODE, false, 0);
|
|
sec_bat_set_health(battery, POWER_SUPPLY_HEALTH_COLD);
|
|
sec_bat_set_charging_status(battery, POWER_SUPPLY_STATUS_NOT_CHARGING);
|
|
battery->cisd.data[CISD_DATA_UNSAFETY_TEMPERATURE]++;
|
|
battery->cisd.data[CISD_DATA_UNSAFE_TEMPERATURE_PER_DAY]++;
|
|
store_battery_log(
|
|
"THM_C:%d%%,%dmV,tbat(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now,
|
|
bat_thm, sb_get_ct_str(battery->cable_type));
|
|
break;
|
|
case BAT_THERMAL_NORMAL:
|
|
default:
|
|
battery->usb_conn_status = USB_CONN_NORMAL;
|
|
sec_bat_thermal_charging_status(battery);
|
|
sec_vote(battery->fcc_vote, VOTER_SWELLING, false, 0);
|
|
sec_vote(battery->fv_vote, VOTER_SWELLING, false, 0);
|
|
if (battery->dchg_dc_in_swelling)
|
|
sec_vote(battery->dc_fv_vote, VOTER_SWELLING, false, 0);
|
|
sec_vote(battery->topoff_vote, VOTER_SWELLING, false, 0);
|
|
sec_vote(battery->chgen_vote, VOTER_SWELLING, false, 0);
|
|
sec_vote(battery->input_vote, VOTER_SWELLING, false, 0);
|
|
sec_vote(battery->iv_vote, VOTER_CHANGE_CHGMODE, false, 0);
|
|
sec_bat_set_health(battery, POWER_SUPPLY_HEALTH_GOOD);
|
|
store_battery_log(
|
|
"THM_N:%d%%,%dmV,tbat(%d),ct(%s)",
|
|
battery->capacity, battery->voltage_now,
|
|
bat_thm, sb_get_ct_str(battery->cable_type));
|
|
break;
|
|
}
|
|
} else { /* pre_thermal_zone == battery->thermal_zone */
|
|
battery->health_change = false;
|
|
|
|
switch (battery->thermal_zone) {
|
|
case BAT_THERMAL_OVERHEAT:
|
|
/* does not need buck control at low temperatures */
|
|
if (battery->health == POWER_SUPPLY_HEALTH_OVERHEAT) {
|
|
int v_ref = battery->pdata->high_temp_float - battery->pdata->buck_recovery_margin;
|
|
|
|
if (get_sec_voter_status(battery->chgen_vote, VOTER_SWELLING, &voter_status) < 0)
|
|
pr_err("%s: INVALID VOTER ID\n", __func__);
|
|
pr_info("%s: voter_status: %d\n", __func__, voter_status);
|
|
if ((voter_status == SEC_BAT_CHG_MODE_BUCK_OFF) &&
|
|
(battery->voltage_now < v_ref)) {
|
|
pr_info("%s: Vnow(%dmV) < %dmV, buck on\n", __func__,
|
|
battery->voltage_now, v_ref);
|
|
sec_vote(battery->chgen_vote, VOTER_SWELLING, true,
|
|
SEC_BAT_CHG_MODE_CHARGING_OFF);
|
|
}
|
|
sec_bat_thermal_warm_wc_fod(battery, false);
|
|
}
|
|
break;
|
|
case BAT_THERMAL_WARM:
|
|
if (battery->health == POWER_SUPPLY_HEALTH_GOOD) {
|
|
int v_ref = battery->pdata->high_temp_float - battery->pdata->buck_recovery_margin;
|
|
int voltage = battery->voltage_now;
|
|
#if IS_ENABLED(CONFIG_DUAL_BATTERY)
|
|
voltage = max(battery->voltage_pack_main, battery->voltage_pack_sub);
|
|
#endif
|
|
|
|
if (get_sec_voter_status(battery->chgen_vote, VOTER_SWELLING, &voter_status) < 0)
|
|
pr_err("%s: INVALID VOTER ID\n", __func__);
|
|
pr_info("%s: voter_status: %d\n", __func__, voter_status);
|
|
if (voter_status == SEC_BAT_CHG_MODE_CHARGING) {
|
|
if (sec_bat_check_fullcharged(battery)) {
|
|
pr_info("%s: battery thermal zone WARM. Full charged.\n", __func__);
|
|
sec_bat_thermal_warm_wc_fod(battery, false);
|
|
sec_vote(battery->chgen_vote, VOTER_SWELLING, true,
|
|
SEC_BAT_CHG_MODE_CHARGING_OFF);
|
|
#if IS_ENABLED(CONFIG_DUAL_BATTERY)
|
|
/* Enable supplement mode for swelling full charging done, should cut off charger then limiter sequence */
|
|
val.intval = 1;
|
|
psy_do_property(battery->pdata->dual_battery_name, set,
|
|
POWER_SUPPLY_EXT_PROP_CHARGING_ENABLED, val);
|
|
#endif
|
|
}
|
|
} else if ((voter_status == SEC_BAT_CHG_MODE_CHARGING_OFF ||
|
|
voter_status == SEC_BAT_CHG_MODE_BUCK_OFF) &&
|
|
(voltage <= battery->pdata->swelling_high_rechg_voltage)) {
|
|
pr_info("%s: thermal zone WARM. charging recovery. Voltage: %d\n",
|
|
__func__, voltage);
|
|
battery->expired_time = battery->pdata->expired_time;
|
|
battery->prev_safety_time = 0;
|
|
sec_vote(battery->input_vote, VOTER_SWELLING, false, 0);
|
|
sec_bat_thermal_warm_wc_fod(battery, true);
|
|
sec_vote(battery->fv_vote, VOTER_SWELLING, true,
|
|
battery->pdata->high_temp_float);
|
|
if (battery->dchg_dc_in_swelling)
|
|
sec_vote(battery->dc_fv_vote, VOTER_SWELLING, true,
|
|
battery->pdata->high_temp_float);
|
|
sec_vote(battery->chgen_vote, VOTER_FULL_CHARGE, false, 0);
|
|
sec_vote(battery->chgen_vote, VOTER_SWELLING, true,
|
|
SEC_BAT_CHG_MODE_CHARGING);
|
|
} else if (voter_status == SEC_BAT_CHG_MODE_BUCK_OFF && voltage < v_ref) {
|
|
pr_info("%s: Voltage(%dmV) < %dmV, buck on\n", __func__,
|
|
voltage, v_ref);
|
|
sec_bat_thermal_warm_wc_fod(battery, false);
|
|
sec_vote(battery->chgen_vote, VOTER_SWELLING, true,
|
|
SEC_BAT_CHG_MODE_CHARGING_OFF);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|