kernel_samsung_a34x-permissive/drivers/power/supply/mediatek/switch_charging.c
2024-04-28 15:51:13 +02:00

1313 lines
34 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2021 MediaTek Inc.
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <mach/mt_charging.h>
#include <mt-plat/battery_common.h>
#include <mt-plat/battery_meter.h>
#include <mt-plat/battery_meter_hal.h>
#include <mt-plat/charging.h>
#include <mt-plat/mtk_boot.h>
#include "mtk_pep20_intf.h"
#include "mtk_pep_intf.h"
#ifdef CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT
#include <mach/mt_diso.h>
#include <mt-plat/diso.h>
#endif
/* ============================================================ // */
/* define */
/* ============================================================ // */
/* cut off to full */
#define POST_CHARGING_TIME (30 * 60) /* 30mins */
#define FULL_CHECK_TIMES 6
#define STATUS_OK 0
#define STATUS_UNSUPPORTED -1
#define STATUS_FAIL -2
/* ============================================================ // */
/* global variable */
/* ============================================================ // */
unsigned int g_bcct_flag;
unsigned int g_bcct_value;
/*input-output curent distinction*/
unsigned int g_bcct_input_flag;
unsigned int g_bcct_input_value;
unsigned int g_full_check_count;
enum CHR_CURRENT_ENUM g_temp_CC_value = CHARGE_CURRENT_0_00_MA;
enum CHR_CURRENT_ENUM g_temp_input_CC_value = CHARGE_CURRENT_0_00_MA;
unsigned int g_usb_state = USB_UNCONFIGURED;
static bool usb_unlimited;
#if (CONFIG_MTK_GAUGE_VERSION == 20)
#ifdef HIGH_BATTERY_VOLTAGE_SUPPORT
enum BATTERY_VOLTAGE_ENUM g_cv_voltage = BATTERY_VOLT_04_340000_V;
#else
enum BATTERY_VOLTAGE_ENUM g_cv_voltage = BATTERY_VOLT_04_200000_V;
#endif
unsigned int get_cv_voltage(void)
{
return g_cv_voltage;
}
#endif
DEFINE_MUTEX(g_ichg_aicr_access_mutex);
DEFINE_MUTEX(g_aicr_access_mutex);
DEFINE_MUTEX(g_ichg_access_mutex);
DEFINE_MUTEX(g_hv_charging_mutex);
unsigned int g_aicr_upper_bound;
static enum kal_bool g_pd_enable_power_path = KAL_TRUE;
static enum kal_bool g_enable_dynamic_cv = KAL_TRUE;
static enum kal_bool g_enable_hv_charging = KAL_TRUE;
static atomic_t g_en_kpoc_shdn = ATOMIC_INIT(1);
/* /////////////////////////////////////////////////////////////////////// */
/* // JEITA */
/* /////////////////////////////////////////////////////////////////////// */
#if defined(CONFIG_MTK_JEITA_STANDARD_SUPPORT)
int g_temp_status = TEMP_POS_10_TO_POS_45;
enum kal_bool temp_error_recovery_chr_flag = KAL_TRUE;
#endif
/* ============================================================ // */
/* function prototype */
/* ============================================================ // */
void BATTERY_SetUSBState(int usb_state_value)
{
#if defined(CONFIG_POWER_EXT)
battery_log(BAT_LOG_CRTI,
"[%s] in FPGA/EVB, no service\r\n",
__func__);
#else
if ((usb_state_value < USB_SUSPEND) ||
((usb_state_value > USB_CONFIGURED))) {
battery_log(
BAT_LOG_CRTI,
"[BATTERY] BAT_SetUSBState Fail! Restore to default value\r\n");
usb_state_value = USB_UNCONFIGURED;
} else {
battery_log(BAT_LOG_CRTI,
"[BATTERY] BAT_SetUSBState Success! Set %d\r\n",
usb_state_value);
g_usb_state = usb_state_value;
}
#endif
}
unsigned int get_charging_setting_current(void)
{
return g_temp_CC_value;
}
int mtk_get_dynamic_cv(unsigned int *cv)
{
int ret = 0;
#ifdef CONFIG_MTK_BIF_SUPPORT
u32 _cv;
u32 vbat_bif = 0, vbat_auxadc = 0, vbat = 0;
u32 retry_cnt = 0;
u32 ircmp_volt_clamp = 0, ircmp_resistor = 0;
if (!g_enable_dynamic_cv) {
if (batt_cust_data.high_battery_voltage_support)
_cv = BATTERY_VOLT_04_340000_V / 1000;
else
_cv = BATTERY_VOLT_04_200000_V / 1000;
goto _out;
}
do {
ret = battery_charging_control(CHARGING_CMD_GET_BIF_VBAT,
&vbat_bif);
vbat_auxadc = battery_meter_get_battery_voltage(KAL_TRUE);
if (ret >= 0 && vbat_bif != 0 && vbat_bif < vbat_auxadc) {
vbat = vbat_bif;
battery_log(
BAT_LOG_CRTI,
"%s: use BIF vbat = %dmV, dV to auxadc = %dmV\n",
__func__, vbat, vbat_auxadc - vbat_bif);
break;
}
retry_cnt++;
} while (retry_cnt < 5);
if (retry_cnt == 5) {
ret = 0;
vbat = vbat_auxadc;
battery_log(BAT_LOG_CRTI,
"%s: use AUXADC vbat = %dmV, since BIF vbat = %d\n",
__func__, vbat_auxadc, vbat_bif);
}
/* Adjust CV according to the obtained vbat */
if (vbat >= 3400 && vbat < 4300) {
_cv = 4550;
battery_charging_control(CHARGING_CMD_SET_IRCMP_VOLT_CLAMP,
&ircmp_volt_clamp);
battery_charging_control(CHARGING_CMD_SET_IRCMP_RESISTOR,
&ircmp_resistor);
} else {
if (batt_cust_data.high_battery_voltage_support)
_cv = BATTERY_VOLT_04_340000_V / 1000;
else
_cv = BATTERY_VOLT_04_200000_V / 1000;
/* Turn on IR compensation */
ircmp_volt_clamp = 200;
ircmp_resistor = 80;
battery_charging_control(CHARGING_CMD_SET_IRCMP_VOLT_CLAMP,
&ircmp_volt_clamp);
battery_charging_control(CHARGING_CMD_SET_IRCMP_RESISTOR,
&ircmp_resistor);
/* Disable dynamic CV */
g_enable_dynamic_cv = KAL_FALSE;
}
_out:
*cv = _cv;
battery_log(BAT_LOG_CRTI, "%s: CV = %dmV, enable dynamic cv = %d\n",
__func__, _cv, g_enable_dynamic_cv);
#else
ret = -ENOTSUPP;
#endif
return ret;
}
#if defined(CONFIG_MTK_JEITA_STANDARD_SUPPORT)
static enum BATTERY_VOLTAGE_ENUM select_jeita_cv(void)
{
enum BATTERY_VOLTAGE_ENUM cv_voltage;
if (g_temp_status == TEMP_ABOVE_POS_60) {
cv_voltage = JEITA_TEMP_ABOVE_POS_60_CV_VOLTAGE;
} else if (g_temp_status == TEMP_POS_45_TO_POS_60) {
cv_voltage = JEITA_TEMP_POS_45_TO_POS_60_CV_VOLTAGE;
} else if (g_temp_status == TEMP_POS_10_TO_POS_45) {
if (batt_cust_data.high_battery_voltage_support)
cv_voltage = BATTERY_VOLT_04_340000_V;
else
cv_voltage = JEITA_TEMP_POS_10_TO_POS_45_CV_VOLTAGE;
} else if (g_temp_status == TEMP_POS_0_TO_POS_10) {
cv_voltage = JEITA_TEMP_POS_0_TO_POS_10_CV_VOLTAGE;
} else if (g_temp_status == TEMP_NEG_10_TO_POS_0) {
cv_voltage = JEITA_TEMP_NEG_10_TO_POS_0_CV_VOLTAGE;
} else if (g_temp_status == TEMP_BELOW_NEG_10) {
cv_voltage = JEITA_TEMP_BELOW_NEG_10_CV_VOLTAGE;
} else {
cv_voltage = BATTERY_VOLT_04_200000_V;
}
return cv_voltage;
}
unsigned int do_jeita_state_machine(void)
{
enum BATTERY_VOLTAGE_ENUM cv_voltage;
unsigned int jeita_status = PMU_STATUS_OK;
/* JEITA battery temp Standard */
if (BMT_status.temperature >= TEMP_POS_60_THRESHOLD) {
battery_log(
BAT_LOG_CRTI,
"[BATTERY] Battery Over high Temperature(%d) !!\n\r",
TEMP_POS_60_THRESHOLD);
g_temp_status = TEMP_ABOVE_POS_60;
return PMU_STATUS_FAIL;
} else if (BMT_status.temperature >
TEMP_POS_45_THRESHOLD) { /* control 45c to normal behavior */
if ((g_temp_status == TEMP_ABOVE_POS_60) &&
(BMT_status.temperature >=
TEMP_POS_60_THRES_MINUS_X_DEGREE)) {
battery_log(
BAT_LOG_CRTI,
"[BATTERY] Battery Temperature between %d and %d,not allow charging yet!!\n\r",
TEMP_POS_60_THRES_MINUS_X_DEGREE,
TEMP_POS_60_THRESHOLD);
jeita_status = PMU_STATUS_FAIL;
} else {
battery_log(
BAT_LOG_CRTI,
"[BATTERY] Battery Temperature between %d and %d !!\n\r",
TEMP_POS_45_THRESHOLD, TEMP_POS_60_THRESHOLD);
g_temp_status = TEMP_POS_45_TO_POS_60;
}
} else if (BMT_status.temperature >= TEMP_POS_10_THRESHOLD) {
if (((g_temp_status == TEMP_POS_45_TO_POS_60) &&
(BMT_status.temperature >=
TEMP_POS_45_THRES_MINUS_X_DEGREE)) ||
((g_temp_status == TEMP_POS_0_TO_POS_10) &&
(BMT_status.temperature <=
TEMP_POS_10_THRES_PLUS_X_DEGREE))) {
battery_log(
BAT_LOG_CRTI,
"[BATTERY] Battery Temperature not recovery to normal temperature charging mode yet!!\n\r");
} else {
battery_log(
BAT_LOG_CRTI,
"[BATTERY] Battery Normal Temperature between %d and %d !!\n\r",
TEMP_POS_10_THRESHOLD, TEMP_POS_45_THRESHOLD);
g_temp_status = TEMP_POS_10_TO_POS_45;
}
} else if (BMT_status.temperature >= TEMP_POS_0_THRESHOLD) {
if ((g_temp_status == TEMP_NEG_10_TO_POS_0 ||
g_temp_status == TEMP_BELOW_NEG_10) &&
(BMT_status.temperature <=
TEMP_POS_0_THRES_PLUS_X_DEGREE)) {
if (g_temp_status == TEMP_NEG_10_TO_POS_0) {
battery_log(
BAT_LOG_CRTI,
"[BATTERY] Battery Temperature between %d and %d !!\n\r",
TEMP_POS_0_THRES_PLUS_X_DEGREE,
TEMP_POS_10_THRESHOLD);
}
if (g_temp_status == TEMP_BELOW_NEG_10) {
battery_log(
BAT_LOG_CRTI,
"[BATTERY] Battery Temperature between %d and %d,not allow charging yet!!\n\r",
TEMP_POS_0_THRESHOLD,
TEMP_POS_0_THRES_PLUS_X_DEGREE);
return PMU_STATUS_FAIL;
}
} else {
battery_log(
BAT_LOG_CRTI,
"[BATTERY] Battery Temperature between %d and %d !!\n\r",
TEMP_POS_0_THRESHOLD, TEMP_POS_10_THRESHOLD);
g_temp_status = TEMP_POS_0_TO_POS_10;
}
} else if (BMT_status.temperature >= TEMP_NEG_10_THRESHOLD) {
if ((g_temp_status == TEMP_BELOW_NEG_10) &&
(BMT_status.temperature <=
TEMP_NEG_10_THRES_PLUS_X_DEGREE)) {
battery_log(
BAT_LOG_CRTI,
"[BATTERY] Battery Temperature between %d and %d,not allow charging yet!!\n\r",
TEMP_NEG_10_THRESHOLD,
TEMP_NEG_10_THRES_PLUS_X_DEGREE);
jeita_status = PMU_STATUS_FAIL;
} else {
battery_log(
BAT_LOG_CRTI,
"[BATTERY] Battery Temperature between %d and %d !!\n\r",
TEMP_NEG_10_THRESHOLD, TEMP_POS_0_THRESHOLD);
g_temp_status = TEMP_NEG_10_TO_POS_0;
}
} else {
battery_log(
BAT_LOG_CRTI,
"[BATTERY] Battery below low Temperature(%d) !!\n\r",
TEMP_NEG_10_THRESHOLD);
g_temp_status = TEMP_BELOW_NEG_10;
jeita_status = PMU_STATUS_FAIL;
}
/* set CV after temperature changed */
/* In normal range, we adjust CV dynamically */
if (g_temp_status != TEMP_POS_10_TO_POS_45) {
cv_voltage = select_jeita_cv();
battery_charging_control(CHARGING_CMD_SET_CV_VOLTAGE,
&cv_voltage);
#if (CONFIG_MTK_GAUGE_VERSION == 20)
g_cv_voltage = cv_voltage;
#endif
}
return jeita_status;
}
static void set_jeita_charging_current(void)
{
#ifdef CONFIG_USB_IF
if (BMT_status.charger_type == STANDARD_HOST)
return;
#endif
if (g_temp_status == TEMP_NEG_10_TO_POS_0) {
g_temp_CC_value = CHARGE_CURRENT_350_00_MA;
g_temp_input_CC_value = CHARGE_CURRENT_500_00_MA;
battery_log(BAT_LOG_CRTI,
"[BATTERY] JEITA set charging current : %d\r\n",
g_temp_CC_value);
}
}
#endif /* CONFIG_MTK_JEITA_STANDARD_SUPPORT */
bool get_usb_current_unlimited(void)
{
if (BMT_status.charger_type == STANDARD_HOST ||
BMT_status.charger_type == CHARGING_HOST)
return usb_unlimited;
return false;
}
void set_usb_current_unlimited(bool enable)
{
usb_unlimited = enable;
}
/*BQ25896 is the first switch chrager separating input and charge current */
unsigned int set_chr_input_current_limit(int current_limit)
{
#ifdef CONFIG_MTK_SWITCH_INPUT_OUTPUT_CURRENT_SUPPORT
u32 power_path_enable = 1;
CHR_CURRENT_ENUM chr_type_aicr = 0; /* 10uA */
CHR_CURRENT_ENUM chr_type_ichg = 0;
mutex_lock(&g_aicr_access_mutex);
if (current_limit != -1) {
g_bcct_input_flag = 1;
if (current_limit < 100) {
/* limit < 100, turn off power path */
current_limit = 0;
power_path_enable = 0;
battery_charging_control(CHARGING_CMD_ENABLE_POWER_PATH,
&power_path_enable);
} else {
/* Enable power path if it is disabled previously */
if (g_bcct_input_value == 0) {
power_path_enable = 1;
battery_charging_control(
CHARGING_CMD_ENABLE_POWER_PATH,
&power_path_enable);
}
switch (BMT_status.charger_type) {
case STANDARD_HOST:
chr_type_aicr =
batt_cust_data.usb_charger_current;
break;
case NONSTANDARD_CHARGER:
chr_type_aicr =
batt_cust_data
.non_std_ac_charger_current;
break;
case STANDARD_CHARGER:
chr_type_aicr =
batt_cust_data.ac_charger_input_current;
mtk_pep20_set_charging_current(&chr_type_ichg,
&chr_type_aicr);
mtk_pep_set_charging_current(&chr_type_ichg,
&chr_type_aicr);
break;
case CHARGING_HOST:
chr_type_aicr =
batt_cust_data
.charging_host_charger_current;
break;
case APPLE_2_1A_CHARGER:
chr_type_aicr =
batt_cust_data
.apple_2_1a_charger_current;
break;
case APPLE_1_0A_CHARGER:
chr_type_aicr =
batt_cust_data
.apple_1_0a_charger_current;
break;
case APPLE_0_5A_CHARGER:
chr_type_aicr =
batt_cust_data
.apple_0_5a_charger_current;
break;
default:
chr_type_aicr = CHARGE_CURRENT_500_00_MA;
break;
}
chr_type_aicr /= 100;
if (current_limit > chr_type_aicr)
current_limit = chr_type_aicr;
}
g_bcct_input_value = current_limit;
} else {
/* Enable power path if it is disabled previously */
if (g_bcct_input_value == 0) {
power_path_enable = 1;
battery_charging_control(CHARGING_CMD_ENABLE_POWER_PATH,
&power_path_enable);
}
/* Change to default current setting */
g_bcct_input_flag = 0;
}
battery_log(BAT_LOG_CRTI,
"[BATTERY] %s (%d)\n", __func__
current_limit);
mutex_unlock(&g_aicr_access_mutex);
return g_bcct_input_flag;
#else
battery_log(BAT_LOG_CRTI,
"[BATTERY] %s _NOT_ supported\n", __func__);
return 0;
#endif
}
static void mtk_select_ichg_aicr(void);
unsigned int set_bat_charging_current_limit(int current_limit)
{
enum CHR_CURRENT_ENUM chr_type_ichg = 0;
enum CHR_CURRENT_ENUM chr_type_aicr = 0;
mutex_lock(&g_ichg_access_mutex);
if (current_limit != -1) {
g_bcct_flag = 1;
switch (BMT_status.charger_type) {
case STANDARD_HOST:
chr_type_ichg = batt_cust_data.usb_charger_current;
break;
case NONSTANDARD_CHARGER:
chr_type_ichg =
batt_cust_data.non_std_ac_charger_current;
break;
case STANDARD_CHARGER:
chr_type_ichg = batt_cust_data.ac_charger_current;
mtk_pep20_set_charging_current(&chr_type_ichg,
&chr_type_aicr);
mtk_pep_set_charging_current(&chr_type_ichg,
&chr_type_aicr);
break;
case CHARGING_HOST:
chr_type_ichg =
batt_cust_data.charging_host_charger_current;
break;
case APPLE_2_1A_CHARGER:
chr_type_ichg =
batt_cust_data.apple_2_1a_charger_current;
break;
case APPLE_1_0A_CHARGER:
chr_type_ichg =
batt_cust_data.apple_1_0a_charger_current;
break;
case APPLE_0_5A_CHARGER:
chr_type_ichg =
batt_cust_data.apple_0_5a_charger_current;
break;
default:
chr_type_ichg = CHARGE_CURRENT_500_00_MA;
break;
}
chr_type_ichg /= 100;
if (current_limit > chr_type_ichg)
current_limit = chr_type_ichg;
g_bcct_value = current_limit;
} else /* change to default current setting */
g_bcct_flag = 0;
mtk_select_ichg_aicr();
battery_log(BAT_LOG_CRTI,
"[BATTERY] %s (%d)\r\n",
__func__, current_limit);
mutex_unlock(&g_ichg_access_mutex);
return g_bcct_flag;
}
int mtk_chr_reset_aicr_upper_bound(void)
{
g_aicr_upper_bound = 0;
return 0;
}
int mtk_chr_pd_enable_power_path(unsigned char enable)
{
int ret = 0;
g_pd_enable_power_path = enable;
if (enable && g_bcct_input_flag && (g_bcct_input_value == 0)) {
battery_log(BAT_LOG_CRTI,
"%s: thermal set power path off, so keep it off\n",
__func__);
return -EINVAL;
}
ret = battery_charging_control(CHARGING_CMD_ENABLE_POWER_PATH, &enable);
return ret;
}
int mtk_chr_enable_chr_type_det(unsigned char en)
{
battery_log(BAT_LOG_CRTI, "%s: enable = %d\n", __func__, en);
battery_charging_control(CHARGING_CMD_ENABLE_CHR_TYPE_DET, &en);
return 0;
}
int mtk_chr_enable_discharge(enum kal_bool enable)
{
return battery_charging_control(CHARGING_CMD_ENABLE_DISCHARGE, &enable);
}
int mtk_chr_enable_hv_charging(enum kal_bool en)
{
battery_log(BAT_LOG_CRTI, "%s: en = %d\n", __func__, en);
mutex_lock(&g_hv_charging_mutex);
g_enable_hv_charging = en;
mutex_unlock(&g_hv_charging_mutex);
return 0;
}
enum kal_bool mtk_chr_is_hv_charging_enable(void)
{
return g_enable_hv_charging;
}
int mtk_chr_enable_kpoc_shutdown(enum kal_bool en)
{
if (en)
atomic_set(&g_en_kpoc_shdn, 1);
else
atomic_set(&g_en_kpoc_shdn, 0);
return 0;
}
enum kal_bool mtk_chr_is_kpoc_shutdown_enable(void)
{
int en = 0;
en = atomic_read(&g_en_kpoc_shdn);
return en > 0 ? KAL_TRUE : KAL_FALSE;
}
int set_chr_boost_current_limit(unsigned int current_limit)
{
int ret = 0;
ret = battery_charging_control(CHARGING_CMD_SET_BOOST_CURRENT_LIMIT,
&current_limit);
return ret;
}
int set_chr_enable_otg(unsigned int enable)
{
int ret = 0;
ret = battery_charging_control(CHARGING_CMD_ENABLE_OTG, &enable);
return ret;
}
int mtk_chr_get_tchr(int *min_temp, int *max_temp)
{
int ret = 0;
int temp[2] = {0, 0};
ret = battery_charging_control(CHARGING_CMD_GET_CHARGER_TEMPERATURE,
temp);
if (ret < 0)
return ret;
*min_temp = temp[0];
*max_temp = temp[1];
return ret;
}
int mtk_chr_get_soc(unsigned int *soc)
{
if (BMT_status.SOC < 0) {
*soc = 0;
return -ENOTSUPP;
}
*soc = BMT_status.SOC;
return 0;
}
int mtk_chr_get_ui_soc(unsigned int *ui_soc)
{
/* UI_SOC2 is the one that shows on UI */
if (BMT_status.UI_SOC2 < 0) {
*ui_soc = 0;
return -ENOTSUPP;
}
*ui_soc = BMT_status.UI_SOC2;
return 0;
}
int mtk_chr_get_vbat(unsigned int *vbat)
{
if (BMT_status.bat_vol < 0) {
*vbat = 0;
return -ENOTSUPP;
}
*vbat = BMT_status.bat_vol;
return 0;
}
int mtk_chr_get_ibat(unsigned int *ibat)
{
*ibat = BMT_status.IBattery / 10;
return 0;
}
int mtk_chr_get_vbus(unsigned int *vbus)
{
if (BMT_status.charger_vol < 0) {
*vbus = 0;
return -ENOTSUPP;
}
*vbus = BMT_status.charger_vol;
return 0;
}
int mtk_chr_get_aicr(unsigned int *aicr)
{
int ret = 0;
u32 _aicr = 0; /* 10uA */
ret = battery_charging_control(CHARGING_CMD_GET_INPUT_CURRENT, &_aicr);
*aicr = _aicr / 100;
return ret;
}
int mtk_chr_is_charger_exist(unsigned char *exist)
{
*exist = (BMT_status.charger_exist ? 1 : 0);
return 0;
}
static unsigned int charging_full_check(void)
{
unsigned int status;
battery_charging_control(CHARGING_CMD_GET_CHARGING_STATUS, &status);
if (status == KAL_TRUE) {
g_full_check_count++;
if (g_full_check_count >= FULL_CHECK_TIMES)
return KAL_TRUE;
else
return KAL_FALSE;
}
g_full_check_count = 0;
return status;
}
static bool mtk_is_pep_series_connect(void)
{
if (mtk_pep20_get_is_connect() || mtk_pep_get_is_connect())
return true;
return false;
}
static int mtk_check_aicr_upper_bound(void)
{
u32 aicr_upper_bound = 0; /* 10uA */
if (mtk_is_pep_series_connect())
return -EPERM;
/* Check AICR upper bound gererated by AICL */
aicr_upper_bound = g_aicr_upper_bound * 100;
if (g_temp_input_CC_value > aicr_upper_bound && aicr_upper_bound > 0)
g_temp_input_CC_value = aicr_upper_bound;
return 0;
}
void select_charging_current(void)
{
if (g_ftm_battery_flag) {
battery_log(BAT_LOG_CRTI, "[BATTERY] FTM charging : %d\r\n",
charging_level_data[0]);
g_temp_CC_value = charging_level_data[0];
if (g_temp_CC_value == CHARGE_CURRENT_450_00_MA) {
g_temp_input_CC_value = CHARGE_CURRENT_500_00_MA;
} else {
g_temp_input_CC_value = CHARGE_CURRENT_MAX;
g_temp_CC_value = batt_cust_data.ac_charger_current;
battery_log(BAT_LOG_CRTI,
"[BATTERY] set_ac_current \r\n");
}
} else {
if (BMT_status.charger_type == STANDARD_HOST) {
#ifdef CONFIG_USB_IF
{
g_temp_input_CC_value = CHARGE_CURRENT_MAX;
if (g_usb_state == USB_SUSPEND)
g_temp_CC_value =
USB_CHARGER_CURRENT_SUSPEND;
else if (g_usb_state == USB_UNCONFIGURED)
g_temp_CC_value =
batt_cust_data
.usb_charger_current_unconfigured;
else if (g_usb_state == USB_CONFIGURED)
g_temp_CC_value =
batt_cust_data
.usb_charger_current_configured;
else
g_temp_CC_value =
batt_cust_data
.usb_charger_current_unconfigured;
g_temp_input_CC_value = g_temp_CC_value;
battery_log(
BAT_LOG_CRTI,
"[BATTERY] STANDARD_HOST CC mode charging : %d on %d state\r\n",
g_temp_CC_value, g_usb_state);
}
#else
{
g_temp_input_CC_value =
batt_cust_data.usb_charger_current;
g_temp_CC_value =
batt_cust_data.usb_charger_current;
}
#endif
} else if (BMT_status.charger_type == NONSTANDARD_CHARGER) {
g_temp_input_CC_value =
batt_cust_data.non_std_ac_charger_current;
g_temp_CC_value =
batt_cust_data.non_std_ac_charger_current;
} else if (BMT_status.charger_type == STANDARD_CHARGER) {
if (batt_cust_data.ac_charger_input_current != 0)
g_temp_input_CC_value =
batt_cust_data.ac_charger_input_current;
else
g_temp_input_CC_value =
batt_cust_data.ac_charger_current;
g_temp_CC_value = batt_cust_data.ac_charger_current;
mtk_pep_set_charging_current(&g_temp_CC_value,
&g_temp_input_CC_value);
mtk_pep20_set_charging_current(&g_temp_CC_value,
&g_temp_input_CC_value);
} else if (BMT_status.charger_type == CHARGING_HOST) {
g_temp_input_CC_value =
batt_cust_data.charging_host_charger_current;
g_temp_CC_value =
batt_cust_data.charging_host_charger_current;
} else if (BMT_status.charger_type == APPLE_2_1A_CHARGER) {
g_temp_input_CC_value =
batt_cust_data.apple_2_1a_charger_current;
g_temp_CC_value =
batt_cust_data.apple_2_1a_charger_current;
} else if (BMT_status.charger_type == APPLE_1_0A_CHARGER) {
g_temp_input_CC_value =
batt_cust_data.apple_1_0a_charger_current;
g_temp_CC_value =
batt_cust_data.apple_1_0a_charger_current;
} else if (BMT_status.charger_type == APPLE_0_5A_CHARGER) {
g_temp_input_CC_value =
batt_cust_data.apple_0_5a_charger_current;
g_temp_CC_value =
batt_cust_data.apple_0_5a_charger_current;
} else {
g_temp_input_CC_value = CHARGE_CURRENT_500_00_MA;
g_temp_CC_value = CHARGE_CURRENT_500_00_MA;
}
#if defined(CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT)
if (DISO_data.diso_state.cur_vdc_state == DISO_ONLINE) {
g_temp_input_CC_value =
batt_cust_data.ac_charger_current;
g_temp_CC_value = batt_cust_data.ac_charger_current;
}
#endif
#if defined(CONFIG_MTK_JEITA_STANDARD_SUPPORT)
set_jeita_charging_current();
#endif
}
mtk_check_aicr_upper_bound();
}
void select_charging_current_bcct(void)
{
/*BQ25896 is the first switch chrager separating input and charge current
* any switch charger can use this compile option which may be generalized
* to be CONFIG_SWITCH_INPUT_OUTPUT_CURRENT_SUPPORT
*/
#ifndef CONFIG_MTK_SWITCH_INPUT_OUTPUT_CURRENT_SUPPORT
if ((BMT_status.charger_type == STANDARD_HOST) ||
(BMT_status.charger_type == NONSTANDARD_CHARGER)) {
if (g_bcct_value < 100)
g_temp_input_CC_value = CHARGE_CURRENT_0_00_MA;
else if (g_bcct_value < 500)
g_temp_input_CC_value = CHARGE_CURRENT_100_00_MA;
else if (g_bcct_value < 800)
g_temp_input_CC_value = CHARGE_CURRENT_500_00_MA;
else if (g_bcct_value == 800)
g_temp_input_CC_value = CHARGE_CURRENT_800_00_MA;
else
g_temp_input_CC_value = CHARGE_CURRENT_500_00_MA;
} else if ((BMT_status.charger_type == STANDARD_CHARGER) ||
(BMT_status.charger_type == CHARGING_HOST)) {
g_temp_input_CC_value = CHARGE_CURRENT_MAX;
/* --------------------------------------------------- */
/* set IOCHARGE */
if (g_bcct_value < 550)
g_temp_CC_value = CHARGE_CURRENT_0_00_MA;
else if (g_bcct_value < 650)
g_temp_CC_value = CHARGE_CURRENT_550_00_MA;
else if (g_bcct_value < 750)
g_temp_CC_value = CHARGE_CURRENT_650_00_MA;
else if (g_bcct_value < 850)
g_temp_CC_value = CHARGE_CURRENT_750_00_MA;
else if (g_bcct_value < 950)
g_temp_CC_value = CHARGE_CURRENT_850_00_MA;
else if (g_bcct_value < 1050)
g_temp_CC_value = CHARGE_CURRENT_950_00_MA;
else if (g_bcct_value < 1150)
g_temp_CC_value = CHARGE_CURRENT_1050_00_MA;
else if (g_bcct_value < 1250)
g_temp_CC_value = CHARGE_CURRENT_1150_00_MA;
else if (g_bcct_value == 1250)
g_temp_CC_value = CHARGE_CURRENT_1250_00_MA;
else
g_temp_CC_value = CHARGE_CURRENT_650_00_MA;
/* --------------------------------------------------- */
} else {
g_temp_input_CC_value = CHARGE_CURRENT_500_00_MA;
}
#else
if (g_bcct_flag == 1)
g_temp_CC_value = g_bcct_value * 100;
if (g_bcct_input_flag == 1)
g_temp_input_CC_value = g_bcct_input_value * 100;
#endif
mtk_check_aicr_upper_bound();
}
static void mtk_select_ichg_aicr(void)
{
unsigned int enable_charger = KAL_TRUE;
mutex_lock(&g_ichg_aicr_access_mutex);
/* Set Ichg, AICR */
if (get_usb_current_unlimited()) {
if (batt_cust_data.ac_charger_input_current != 0)
g_temp_input_CC_value =
batt_cust_data.ac_charger_input_current;
else
g_temp_input_CC_value =
batt_cust_data.ac_charger_current;
g_temp_CC_value = batt_cust_data.ac_charger_current;
battery_log(
BAT_LOG_FULL,
"USB_CURRENT_UNLIMITED, use batt_cust_data.ac_charger_current\n");
}
#ifndef CONFIG_MTK_SWITCH_INPUT_OUTPUT_CURRENT_SUPPORT
else if (g_bcct_flag == 1) {
select_charging_current_bcct();
battery_log(BAT_LOG_FULL,
"[BATTERY] select_charging_current_bcct !\n");
} else {
select_charging_current();
battery_log(BAT_LOG_FULL,
"[BATTERY] select_charging_current !\n");
}
#else
else if (g_bcct_flag == 1 || g_bcct_input_flag == 1) {
select_charging_current();
select_charging_current_bcct();
battery_log(BAT_LOG_FULL,
"[BATTERY] select_charging_curret_bcct !\n");
} else {
select_charging_current();
battery_log(BAT_LOG_FULL,
"[BATTERY] select_charging_curret !\n");
}
#endif
battery_log(
BAT_LOG_CRTI,
"[BATTERY] Default CC mode charging : %d, input current = %d\n",
g_temp_CC_value, g_temp_input_CC_value);
battery_charging_control(CHARGING_CMD_SET_INPUT_CURRENT,
&g_temp_input_CC_value);
battery_charging_control(CHARGING_CMD_SET_CURRENT, &g_temp_CC_value);
/* For thermal, they need to enable charger immediately */
if (g_temp_CC_value > 0 && g_temp_input_CC_value > 0)
battery_charging_control(CHARGING_CMD_ENABLE, &enable_charger);
/* If AICR < 300mA, stop PE+/PE+20 */
if (g_temp_input_CC_value < CHARGE_CURRENT_300_00_MA) {
if (mtk_pep20_get_is_enable()) {
mtk_pep20_set_is_enable(true);
if (mtk_pep20_get_is_connect())
mtk_pep20_reset_ta_vchr();
}
if (mtk_pep_get_is_enable()) {
mtk_pep_set_is_enable(false);
if (mtk_pep_get_is_connect())
mtk_pep_reset_ta_vchr();
}
} else if (g_bcct_input_flag == 0 && g_bcct_flag == 0) {
if (!mtk_pep20_get_is_enable()) {
mtk_pep20_set_is_enable(true);
mtk_pep20_set_to_check_chr_type(true);
}
if (!mtk_pep_get_is_enable()) {
mtk_pep_set_is_enable(true);
mtk_pep_set_to_check_chr_type(true);
}
}
mutex_unlock(&g_ichg_aicr_access_mutex);
}
static void mtk_select_cv(void)
{
int ret = 0;
u32 dynamic_cv = 0;
enum BATTERY_VOLTAGE_ENUM cv_voltage;
#ifdef CONFIG_MTK_JEITA_STANDARD_SUPPORT
/* If temperautre is abnormal, return not permitted */
if (g_temp_status != TEMP_POS_10_TO_POS_45)
return;
#endif
if (batt_cust_data.high_battery_voltage_support)
cv_voltage = BATTERY_VOLT_04_340000_V;
else
cv_voltage = BATTERY_VOLT_04_200000_V;
ret = mtk_get_dynamic_cv(&dynamic_cv);
if (ret == 0) {
cv_voltage = dynamic_cv * 1000;
battery_log(BAT_LOG_FULL, "%s: set dynamic cv = %dmV\n",
__func__, dynamic_cv);
}
battery_charging_control(CHARGING_CMD_SET_CV_VOLTAGE, &cv_voltage);
#if (CONFIG_MTK_GAUGE_VERSION == 20)
g_cv_voltage = cv_voltage;
#endif
}
static void pchr_turn_on_charging(void)
{
u32 charging_enable = KAL_TRUE;
#ifdef CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT
if (BMT_status.charger_exist)
charging_enable = KAL_TRUE;
else
charging_enable = KAL_FALSE;
#endif
if (BMT_status.bat_charging_state == CHR_ERROR) {
battery_log(BAT_LOG_CRTI,
"[BATTERY] Charger Error, turn OFF charging !\n");
charging_enable = KAL_FALSE;
} else if ((g_platform_boot_mode == META_BOOT) ||
(g_platform_boot_mode == ADVMETA_BOOT)) {
battery_log(
BAT_LOG_CRTI,
"[BATTERY] In meta or advanced meta mode, disable charging.\n");
charging_enable = KAL_FALSE;
} else {
/* HW initialization */
battery_charging_control(CHARGING_CMD_INIT, NULL);
battery_log(BAT_LOG_FULL, "charging_hw_init\n");
/* PE+/PE+20 algorithm */
mtk_pep20_start_algorithm();
mtk_pep_start_algorithm();
/* Select ICHG/AICR */
mtk_select_ichg_aicr();
if (g_temp_CC_value == CHARGE_CURRENT_0_00_MA ||
g_temp_input_CC_value == CHARGE_CURRENT_0_00_MA) {
charging_enable = KAL_FALSE;
battery_log(
BAT_LOG_CRTI,
"[BATTERY] charging current is set 0mA, turn off charging !\r\n");
} else /* Set CV Voltage */
mtk_select_cv();
}
/* enable/disable charging */
battery_charging_control(CHARGING_CMD_ENABLE, &charging_enable);
battery_log(BAT_LOG_FULL,
"[BATTERY] %s(), enable =%d !\r\n",
__func__, charging_enable);
}
unsigned int BAT_PreChargeModeAction(void)
{
#ifdef CONFIG_MTK_BIF_SUPPORT
int ret = 0;
unsigned int bif_exist = false;
#endif
unsigned int led_en = true;
battery_log(BAT_LOG_CRTI,
"[BATTERY] Pre-CC mode charge, timer=%d on %d !!\n\r",
BMT_status.PRE_charging_time,
BMT_status.total_charging_time);
BMT_status.PRE_charging_time += BAT_TASK_PERIOD;
BMT_status.CC_charging_time = 0;
BMT_status.TOPOFF_charging_time = 0;
BMT_status.total_charging_time += BAT_TASK_PERIOD;
#ifdef CONFIG_MTK_BIF_SUPPORT
/* If defined BIF but not BIF's battery, stop charging */
ret = battery_charging_control(CHARGING_CMD_GET_BIF_IS_EXIST,
&bif_exist);
if (!bif_exist) {
battery_log(
BAT_LOG_CRTI,
"%s: define BIF but no BIF battery, disable charging\n",
__func__);
BMT_status.bat_charging_state = CHR_ERROR;
return PMU_STATUS_OK;
}
#endif
battery_charging_control(CHARGING_CMD_SET_PWRSTAT_LED_EN, &led_en);
/* Enable charger */
pchr_turn_on_charging();
#if (CONFIG_MTK_GAUGE_VERSION == 20)
if (BMT_status.UI_SOC2 == 100 && charging_full_check()) {
#else
if (BMT_status.UI_SOC == 100) {
#endif
BMT_status.bat_charging_state = CHR_BATFULL;
BMT_status.bat_full = KAL_TRUE;
g_charging_full_reset_bat_meter = KAL_TRUE;
} else if (BMT_status.bat_vol > V_PRE2CC_THRES) {
BMT_status.bat_charging_state = CHR_CC;
}
/* If it is not disabled by throttling,
* enable PE+/PE+20, if it is disabled
*/
if (g_bcct_input_flag && g_bcct_input_value < 300)
return PMU_STATUS_OK;
if (!mtk_pep20_get_is_enable()) {
mtk_pep20_set_is_enable(true);
mtk_pep20_set_to_check_chr_type(true);
}
if (!mtk_pep_get_is_enable()) {
mtk_pep_set_is_enable(true);
mtk_pep_set_to_check_chr_type(true);
}
return PMU_STATUS_OK;
}
unsigned int BAT_ConstantCurrentModeAction(void)
{
unsigned int led_en = true;
battery_log(
BAT_LOG_CRTI, "[BATTERY] CC mode charge, timer=%d on %d!!\n",
BMT_status.CC_charging_time, BMT_status.total_charging_time);
BMT_status.PRE_charging_time = 0;
BMT_status.CC_charging_time += BAT_TASK_PERIOD;
BMT_status.TOPOFF_charging_time = 0;
BMT_status.total_charging_time += BAT_TASK_PERIOD;
battery_charging_control(CHARGING_CMD_SET_PWRSTAT_LED_EN, &led_en);
/* Enable charger */
pchr_turn_on_charging();
if (charging_full_check() == KAL_TRUE) {
BMT_status.bat_charging_state = CHR_BATFULL;
BMT_status.bat_full = KAL_TRUE;
g_charging_full_reset_bat_meter = KAL_TRUE;
}
return PMU_STATUS_OK;
}
unsigned int BAT_BatteryFullAction(void)
{
unsigned int led_en = false;
battery_log(BAT_LOG_CRTI, "[BATTERY] Battery full !!\n\r");
BMT_status.bat_full = KAL_TRUE;
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;
BMT_status.bat_in_recharging_state = KAL_FALSE;
battery_log(BAT_LOG_FULL, "Turn off PWRSTAT LED\n");
battery_charging_control(CHARGING_CMD_SET_PWRSTAT_LED_EN, &led_en);
/*
* If CV is set to lower value by JEITA,
* Reset CV to normal value if temperture is in normal zone
*/
mtk_select_cv();
if (charging_full_check() == KAL_FALSE) {
battery_log(BAT_LOG_CRTI, "[BATTERY] Battery Re-charging!\n\r");
BMT_status.bat_in_recharging_state = KAL_TRUE;
BMT_status.bat_charging_state = CHR_CC;
#if (CONFIG_MTK_GAUGE_VERSION == 20)
battery_meter_reset();
#endif
mtk_pep20_set_to_check_chr_type(true);
mtk_pep_set_to_check_chr_type(true);
g_enable_dynamic_cv = KAL_TRUE;
}
return PMU_STATUS_OK;
}
unsigned int BAT_BatteryHoldAction(void)
{
unsigned int charging_enable;
battery_log(BAT_LOG_CRTI, "[BATTERY] Hold mode !!\n\r");
if (BMT_status.bat_vol < TALKING_RECHARGE_VOLTAGE ||
g_call_state == CALL_IDLE) {
BMT_status.bat_charging_state = CHR_CC;
battery_log(
BAT_LOG_CRTI,
"[BATTERY] Exit Hold mode and Enter CC mode !!\n\r");
}
/* Disable charger */
charging_enable = KAL_FALSE;
battery_charging_control(CHARGING_CMD_ENABLE, &charging_enable);
return PMU_STATUS_OK;
}
unsigned int BAT_BatteryStatusFailAction(void)
{
unsigned int charging_enable;
battery_log(BAT_LOG_CRTI,
"[BATTERY] BAD Battery status... Charging Stop !!\n\r");
#if defined(CONFIG_MTK_JEITA_STANDARD_SUPPORT)
if ((g_temp_status == TEMP_ABOVE_POS_60) ||
(g_temp_status == TEMP_BELOW_NEG_10))
temp_error_recovery_chr_flag = KAL_FALSE;
if ((temp_error_recovery_chr_flag == KAL_FALSE) &&
(g_temp_status != TEMP_ABOVE_POS_60) &&
(g_temp_status != TEMP_BELOW_NEG_10)) {
temp_error_recovery_chr_flag = KAL_TRUE;
BMT_status.bat_charging_state = CHR_PRE;
}
#endif
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;
/* Disable charger */
charging_enable = KAL_FALSE;
battery_charging_control(CHARGING_CMD_ENABLE, &charging_enable);
/* Disable PE+/PE+20 */
if (mtk_pep20_get_is_enable()) {
mtk_pep20_set_is_enable(false);
if (mtk_pep20_get_is_connect())
mtk_pep20_reset_ta_vchr();
}
if (mtk_pep_get_is_enable()) {
mtk_pep_set_is_enable(false);
if (mtk_pep_get_is_connect())
mtk_pep_reset_ta_vchr();
}
return PMU_STATUS_OK;
}
void mt_battery_charging_algorithm(void)
{
battery_charging_control(CHARGING_CMD_RESET_WATCH_DOG_TIMER, NULL);
/* Generate AICR upper bound by AICL */
if (!mtk_is_pep_series_connect()) {
battery_charging_control(CHARGING_CMD_RUN_AICL,
&g_aicr_upper_bound);
}
mtk_pep20_check_charger();
mtk_pep_check_charger();
switch (BMT_status.bat_charging_state) {
case CHR_PRE:
BAT_PreChargeModeAction();
break;
case CHR_CC:
BAT_ConstantCurrentModeAction();
break;
case CHR_BATFULL:
BAT_BatteryFullAction();
break;
case CHR_HOLD:
BAT_BatteryHoldAction();
break;
case CHR_ERROR:
BAT_BatteryStatusFailAction();
break;
}
battery_charging_control(CHARGING_CMD_DUMP_REGISTER, NULL);
}