blob: b39df2db4550618eb5c83d36035e2dd19969c59c [file] [log] [blame]
#include <linux/power_supply.h>
#include <linux/mutex.h>
#include <linux/power_supply.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/jiffies.h>
#include <linux/workqueue.h>
#include <linux/rtc.h>
#include <linux/ktime.h>
#include <linux/fs.h>
#ifdef CONFIG_OPLUS_KEVENT_UPLOAD
#include <linux/oplus_kevent.h>
#endif
#include "oplus_vooc.h"
#include "oplus_charger.h"
#include "oplus_debug_info.h"
//#define OPLUS_CHG_DEBUG_TEST
#ifdef OPLUS_CHG_DEBUG_TEST
static int fake_soc = -1;
static int fake_ui_soc = -1;
static int aging_cap_test = -1;
#endif
#ifdef CONFIG_OPLUS_KEVENT_UPLOAD
#define OPLUS_CHG_DEBUG_LOG_TAG "OplusCharger"
#define OPLUS_CHG_DEBUG_EVENT_ID "charge_monitor"
#endif
struct oplus_chg_debug_info oplus_chg_debug_info;
struct vooc_charger_type {
int chg_type;
int vol;
int cur;
int output_power_type;
};
struct vooc_fw_type {
int fw_type;
int vol;
int cur;
};
struct capacity_range {
int low;
int high;
};
struct temp_range {
int low;
int high;
};
struct input_current_setting {
int cur;
int vol;
int time;
};
#define OPLUS_CHG_VOOC_INPUT_CURRENT_MAX_CNT 10
struct vooc_charge_strategy {
struct capacity_range capacity_range;
struct temp_range temp_range;
struct input_current_setting input_current[OPLUS_CHG_VOOC_INPUT_CURRENT_MAX_CNT];
};
enum {
OPLUS_FASTCHG_OUTPUT_POWER_20W,
OPLUS_FASTCHG_OUTPUT_POWER_30W,
OPLUS_FASTCHG_OUTPUT_POWER_50W,
OPLUS_FASTCHG_OUTPUT_POWER_65W,
OPLUS_FASTCHG_OUTPUT_POWER_MAX,
};
#define OPLUS_CHG_START_STABLE_TIME (30) //单位s
#define OPLUS_CHG_DEBUG_FASTCHG_STOP_CNT 6
#define OPLUS_CHG_DEBUG_MAX_SOC 85
#define OPLUS_CHG_DEBUG_VOOC_MAX_VOLT 4400
//TODO 部分项目ibus不对
#define LED_ON_HIGH_POWER_CONSUPTION (4000 * 500) /*单位mW*/
#define LED_OFF_HIGH_POWER_CONSUPTION (4000 * 300) /*单位mW*/
#define LED_OFF_STABLE_TIME (30) //单位s
#define INPUT_POWER_RATIO 60 //百分比
#define INPUT_CURRENT_DECREASE (300000) //单位微安
#define INPUT_POWER_DECREASE (4000 * 500) //单位w
#define OPLUS_CHARGERID_VOLT_LOW_THLD 650
#define OPLUS_CHARGERID_VOLT_HIGH_THLD 1250
#define HIGH_POWER_FASTCHG_BATT_VOLT 4224
#define HIGH_POWER_CHG_LOW_TEMP 160
#define HIGH_POWER_CHG_HIGH_TEMP 400
#define OPLUS_CHG_BATT_AGING_CAP_DECREASE 300
#define OPLUS_CHG_BATT_INVALID_CAPACITY -0x1010101
#define OPLUS_CHG_BATT_S0C_CAPACITY_LOAD_JUMP_NUM 5
#define OPLUS_CHG_BATT_UI_S0C_CAPACITY_LOAD_JUMP_NUM 5
#define OPLUS_CHG_BATT_S0C_CAPACITY_JUMP_NUM 3
#define OPLUS_CHG_BATT_UI_S0C_CAPACITY_JUMP_NUM 5
#define OPLUS_CHG_BATT_UI_TO_S0C_CAPACITY_JUMP_NUM 3
#define OPLUS_CHG_MONITOR_FILE "/data/oplus_charge/oplus_chg_debug_monitor.txt"
#if 1
#define OPLUS_CHG_BATT_AGING_CHECK_CNT 360
#define OPLUS_CHG_BATT_AGING_CHECK_TIME (7 * 24 * 60 * 60)
#else
//for test
#define OPLUS_CHG_BATT_AGING_CHECK_CNT 1
#define OPLUS_CHG_BATT_AGING_CHECK_TIME (1)
#endif
#define OPLUS_CHG_DEBUG_MSG_LEN 2048
char oplus_chg_debug_msg[OPLUS_CHG_DEBUG_MSG_LEN] = "";
enum oplus_chg_debug_info_notify_type {
OPLUS_CHG_DEBUG_NOTIFY_TYPE_SOC_JUMP,
OPLUS_CHG_DEBUG_NOTIFY_TYPE_CHG_FULL,
OPLUS_CHG_DEBUG_NOTIFY_TYPE_BATT_FCC,
OPLUS_CHG_DEBUG_NOTIFY_TYPE_CHG_SLOW,
OPLUS_CHG_DEBUG_NOTIFY_TYPE_MAX,
};
enum oplus_chg_debug_info_notify_flag {
/*电量跳变标志*/
OPLUS_NOTIFY_BATT_SOC_CAPCITY_LOAD_JUMP,
OPLUS_NOTIFY_BATT_UI_SOC_CAPCITY_LOAD_JUMP,
OPLUS_NOTIFY_BATT_SOC_CAPCITY_JUMP,
OPLUS_NOTIFY_BATT_UI_SOC_CAPCITY_JUMP,
OPLUS_NOTIFY_BATT_UI_TO_SOC_CAPCITY_JUMP,
OPLUS_NOTIFY_BATT_SOC_JUMP, //5
/*充电慢标志*/
OPLUS_NOTIFY_CHG_SLOW_BATT_NON_AUTH,
OPLUS_NOTIFY_CHG_SLOW_NON_OPLUS_CHARGER,
OPLUS_NOTIFY_CHG_SLOW_OVERTIME,
OPLUS_NOTIFY_CHG_SLOW_ADAPTER_INPUT_LOW_POWER, //线损大
OPLUS_NOTIFY_CHG_SLOW_VOOC_NON_START, //10
OPLUS_NOTIFY_CHG_SLOW_VOOC_ADAPTER_NON_MAX_POWER, //非匹配的最大功率快充充电器
OPLUS_NOTIFY_CHG_SLOW_CHARGER_OV,
OPLUS_NOTIFY_CHG_SLOW_CHARGER_UV,
OPLUS_NOTIFY_CHG_SLOW_BATT_COLD_TEMP,
OPLUS_NOTIFY_CHG_SLOW_BATT_WARM_TEMP, //15
OPLUS_NOTIFY_CHG_SLOW_FASTCHG_TO_WARM,
OPLUS_NOTIFY_CHG_SLOW_CHG_TYPE_SDP,
OPLUS_NOTIFY_CHG_SLOW_SYS_POWER_CONSUME_HIGH,
OPLUS_NOTIFY_CHG_SLOW_CHG_POWER_LOW,
OPLUS_NOTIFY_CHG_SLOW_LOW_CHARGE_CURRENT_LONG_TIME, //20
OPLUS_NOTIFY_CHG_SLOW_LED_ON_LONG_TIME,
OPLUS_NOTIFY_CHG_SLOW_CAM_ON_LONG_TIME,
OPLUS_NOTIFY_CHG_SLOW_CALLING_LONG_TIME,
OPLUS_NOTIFY_CHG_SLOW_COOLDOWN_LONG_TIME,
OPLUS_NOTIFY_CHG_SLOW_CHECK_TIME, //25
//充电报满
OPLUS_NOTIFY_CHG_BATT_FULL_NON_100_CAP,
OPLUS_NOTIFY_CHG_BATT_FULL_AND_100_CAP,
OPLUS_NOTIFY_CHG_FULL,
//电池老化
OPLUS_NOTIFY_BATT_AGING_CAP,
OPLUS_NOTIFY_BATT_AGING,
OPLUS_NOTIFY_CHG_MAX_CNT,
};
enum {
OPLUS_CHG_NOTIFY_UNKNOW,
OPLUS_CHG_NOTIFY_ONCE,
OPLUS_CHG_NOTIFY_REPEAT,
OPLUS_CHG_NOTIFY_TOTAL,
};
struct oplus_chg_debug_info {
int initialized;
//电量跳变
int pre_soc;
int cur_soc;
int pre_ui_soc;
int cur_ui_soc;
int soc_load_flag;
unsigned long sleep_tm_sec;
int soc_notified_flag;
#define SOC_LOAD_DELAY (60 * 1000)
struct delayed_work soc_load_dwork;
//充电慢
int fast_chg_type;
int pre_prop_status;
int chg_start_soc;
int chg_start_temp;
int chg_start_time;
int chg_total_time;
int total_time;
int pre_led_state;
int led_off_start_time;
int chg_cnt[OPLUS_NOTIFY_CHG_MAX_CNT];
int notify_type;
unsigned long long notify_flag;
struct mutex nflag_lock;
struct power_supply *usb_psy;
struct power_supply *batt_psy;
int fastchg_stop_cnt;
int cool_down_by_user;
int chg_current_by_tbatt;
int chg_current_by_cooldown;
int fastchg_input_current;
struct vooc_charge_strategy *vooc_charge_strategy;
int vooc_charge_input_current_index;
int vooc_charge_cur_state_chg_time;
int vooc_max_input_volt;
int vooc_max_input_current;
//电池容量
int fcc_design;
//充电报满
int chg_full_notified_flag;
struct workqueue_struct *oplus_chg_debug_wq;
#ifdef CONFIG_OPLUS_KEVENT_UPLOAD
struct kernel_packet_info *dcs_info;
struct mutex dcs_info_lock;
#define SEND_INFO_DELAY 3000
struct delayed_work send_info_dwork;
#define SEND_INFO_MAX_CNT 5
int retry_cnt;
#endif
};
struct oplus_chg_debug_notify_policy {
int policy;
int fast_chg_time; //单位5s
int normal_chg_time; //单位5s
int percent; //百分比
};
#if 0
//TODO 需要移植到dtsi中
struct vooc_charge_strategy vooc_charge_strategy_30w[] = {
{
.capacity_range = {0, 75},
.temp_range = {120, 160},
.input_current = {
{4000, 4450, 0},
{3000, 4470, 0},
{2000, 4480, 0}
}
},
{
.capacity_range = {0, 75},
.temp_range = {160, 410},
.input_current = {
{6000, 4200, 900},
{5000, 4200, 0},
{4500, 4450, 0},
{4000, 4450, 0},
{3000, 4470, 0},
{2000, 4480, 0}
}
},
{
.capacity_range = {0, 75},
.temp_range = {410, 420},
.input_current = {
{4000, 4470, 0},
{2000, 4480, 0}
}
},
{
.capacity_range = {0, 75},
.temp_range = {420, 425},
.input_current = {
{4000, 4480, 0}
}
},
{
.capacity_range = {0, 75},
.temp_range = {425, 435},
.input_current = {
{3000, 4480, 0}
}
},
{
.capacity_range = {-1, -1},
}
};
struct vooc_charge_strategy vooc_charge_strategy_65w[] = {
{
.capacity_range = {0, 50},
.temp_range = {120, 160},
.input_current = {
{6000, 4200, 0},
{4000, 4454, 0},
{2000, 4494, 0},
{1500, 4500, 0}
}
},
{
.capacity_range = {0, 50},
.temp_range = {160, 370},
.input_current = {
{6500, 4200, 0},
{6000, 4250, 300},
{5500, 4300, 400},
{4500, 4454, 780},
{3500, 4454, 0},
{2000, 4494, 0},
{1500, 4500, 0}
}
},
{
.capacity_range = {0, 50},
.temp_range = {370, 430},
.input_current = {
{6500, 4200, 0},
{6000, 4250, 300},
{5500, 4300, 400},
{4500, 4454, 780},
{3500, 4454, 0},
{2000, 4494, 0},
{1600, 4500, 0}
}
},
{
.capacity_range = {-1, -1},
}
};
struct vooc_charge_strategy *g_vooc_charge_strategy_p[] = {
NULL,
vooc_charge_strategy_30w,
NULL,
vooc_charge_strategy_65w,
};
#else
struct vooc_charge_strategy *g_vooc_charge_strategy_p[OPLUS_FASTCHG_OUTPUT_POWER_MAX] = {
NULL,
NULL,
NULL,
NULL
};
#endif
static struct oplus_chg_debug_notify_policy oplus_chg_debug_notify_policy[] = {
[OPLUS_NOTIFY_BATT_SOC_CAPCITY_LOAD_JUMP] = {OPLUS_CHG_NOTIFY_ONCE, 1, 1, -1},
[OPLUS_NOTIFY_BATT_UI_SOC_CAPCITY_LOAD_JUMP] = {OPLUS_CHG_NOTIFY_ONCE, 1, 1, -1},
[OPLUS_NOTIFY_BATT_SOC_CAPCITY_JUMP] = {OPLUS_CHG_NOTIFY_REPEAT, 1, 1, -1},
[OPLUS_NOTIFY_BATT_UI_SOC_CAPCITY_JUMP] = {OPLUS_CHG_NOTIFY_REPEAT, 1, 1, -1},
[OPLUS_NOTIFY_BATT_UI_TO_SOC_CAPCITY_JUMP] = {OPLUS_CHG_NOTIFY_REPEAT, 1, 1, -1},
[OPLUS_NOTIFY_CHG_SLOW_BATT_NON_AUTH] = {OPLUS_CHG_NOTIFY_ONCE, 6, 6, -1},
[OPLUS_NOTIFY_CHG_SLOW_NON_OPLUS_CHARGER] = {OPLUS_CHG_NOTIFY_ONCE, 6, 6, -1},
[OPLUS_NOTIFY_CHG_SLOW_OVERTIME] = {OPLUS_CHG_NOTIFY_ONCE, 1, 1, -1},
[OPLUS_NOTIFY_CHG_SLOW_ADAPTER_INPUT_LOW_POWER] = {OPLUS_CHG_NOTIFY_TOTAL, 720, 1440, 50},
[OPLUS_NOTIFY_CHG_SLOW_VOOC_NON_START] = {OPLUS_CHG_NOTIFY_TOTAL, 720, 1440, 30},
[OPLUS_NOTIFY_CHG_SLOW_VOOC_ADAPTER_NON_MAX_POWER] = {OPLUS_CHG_NOTIFY_TOTAL, 720, 1440, 50},
[OPLUS_NOTIFY_CHG_SLOW_CHARGER_OV] = {OPLUS_CHG_NOTIFY_TOTAL, 720, 1440, 30},
[OPLUS_NOTIFY_CHG_SLOW_CHARGER_UV] = {OPLUS_CHG_NOTIFY_TOTAL, 720, 1440, 30},
[OPLUS_NOTIFY_CHG_SLOW_BATT_COLD_TEMP] = {OPLUS_CHG_NOTIFY_TOTAL, 720, 1440, 30},
[OPLUS_NOTIFY_CHG_SLOW_BATT_WARM_TEMP] = {OPLUS_CHG_NOTIFY_TOTAL, 720, 1440, 30},
[OPLUS_NOTIFY_CHG_SLOW_FASTCHG_TO_WARM] = {OPLUS_CHG_NOTIFY_REPEAT, 1, 1, -1},
[OPLUS_NOTIFY_CHG_SLOW_CHG_TYPE_SDP] = {OPLUS_CHG_NOTIFY_TOTAL, 720, 1440, 80},
[OPLUS_NOTIFY_CHG_SLOW_SYS_POWER_CONSUME_HIGH] = {OPLUS_CHG_NOTIFY_TOTAL, 720, 1440, 40},
[OPLUS_NOTIFY_CHG_SLOW_CHG_POWER_LOW] = {OPLUS_CHG_NOTIFY_TOTAL, 720, 1440, 40},
[OPLUS_NOTIFY_CHG_SLOW_LOW_CHARGE_CURRENT_LONG_TIME] = {OPLUS_CHG_NOTIFY_TOTAL, 720, 1440, 70},
[OPLUS_NOTIFY_CHG_SLOW_LED_ON_LONG_TIME] = {OPLUS_CHG_NOTIFY_TOTAL, 720, 1440, 70},
[OPLUS_NOTIFY_CHG_SLOW_CAM_ON_LONG_TIME] = {OPLUS_CHG_NOTIFY_TOTAL, 720, 1440, 50},
[OPLUS_NOTIFY_CHG_SLOW_CALLING_LONG_TIME] = {OPLUS_CHG_NOTIFY_TOTAL, 720, 1440, 70},
[OPLUS_NOTIFY_CHG_SLOW_COOLDOWN_LONG_TIME] = {OPLUS_CHG_NOTIFY_TOTAL, 720, 1440, 70},
[OPLUS_NOTIFY_CHG_SLOW_CHECK_TIME] = {OPLUS_CHG_NOTIFY_REPEAT, 720, 1440, -1},
[OPLUS_NOTIFY_CHG_BATT_FULL_NON_100_CAP] = {OPLUS_CHG_NOTIFY_ONCE, 3, 3, -1},
[OPLUS_NOTIFY_CHG_BATT_FULL_AND_100_CAP] = {OPLUS_CHG_NOTIFY_ONCE, 3, 3, -1},
[OPLUS_NOTIFY_BATT_AGING_CAP] = {OPLUS_CHG_NOTIFY_REPEAT, 1, 1, -1},
};
struct vooc_charger_type vooc_charger_type_list[] = {
{0x01, 5000, 4000, OPLUS_FASTCHG_OUTPUT_POWER_20W},
{0x11, 10000, 5000, OPLUS_FASTCHG_OUTPUT_POWER_50W},
{0x12, 10000, 5000, OPLUS_FASTCHG_OUTPUT_POWER_50W},
{0x13, 5000, 4000, OPLUS_FASTCHG_OUTPUT_POWER_20W},
{0x14, 10000, 6500, OPLUS_FASTCHG_OUTPUT_POWER_65W},
{0x19, 5000, 6000, OPLUS_FASTCHG_OUTPUT_POWER_30W},
{0x21, 10000, 5000, OPLUS_FASTCHG_OUTPUT_POWER_50W},
{0x29, 5000, 6000, OPLUS_FASTCHG_OUTPUT_POWER_30W},
{0x31, 10000, 5000, OPLUS_FASTCHG_OUTPUT_POWER_50W},
{0x33, 10000, 5000, OPLUS_FASTCHG_OUTPUT_POWER_50W},
{0x34, 5000, 4000, OPLUS_FASTCHG_OUTPUT_POWER_20W},
};
static int oplus_chg_debug_info_reset(void);
static int oplus_chg_chg_is_normal_path(struct oplus_chg_chip *chip);
//static unsigned long long oplus_chg_debug_get_notify_flag(bool reset);
static int oplus_chg_debug_notify_flag_is_set(int flag);
//static int oplus_chg_debug_mask_notify_flag(int low, int high);
static int oplus_chg_debug_reset_notify_flag(void);
static int oplus_chg_reset_chg_notify_type(void);
static int oplus_chg_chg_batt_capacity_jump_check(struct oplus_chg_chip *chip);
#ifdef CONFIG_OPLUS_KEVENT_UPLOAD
static int oplus_chg_pack_debug_info(struct oplus_chg_chip *chip)
{
char log_tag[] = OPLUS_CHG_DEBUG_LOG_TAG;
char event_id[] = OPLUS_CHG_DEBUG_EVENT_ID;
int len;
len = strlen(&oplus_chg_debug_msg[sizeof(struct kernel_packet_info)]);
if (len) {
mutex_lock(&oplus_chg_debug_info.dcs_info_lock);
memset(oplus_chg_debug_info.dcs_info, 0x0, sizeof(struct kernel_packet_info));
oplus_chg_debug_info.dcs_info->type = 1;
memcpy(oplus_chg_debug_info.dcs_info->log_tag, log_tag, strlen(log_tag));
memcpy(oplus_chg_debug_info.dcs_info->event_id, event_id, strlen(event_id));
oplus_chg_debug_info.dcs_info->payload_length = len + 1;
#ifdef OPLUS_CHG_DEBUG_TEST
chg_err("%s\n", oplus_chg_debug_info.dcs_info->payload);
#endif
mutex_unlock(&oplus_chg_debug_info.dcs_info_lock);
return 0;
}
return -1;
}
static int oplus_chg_debug_mask_notify_flag(int low, int high)
{
unsigned long long mask = -1;
int bits = sizeof(mask) * 8 - 1;
mask = (mask >> low) << low;
mask = (mask << (bits - high)) >> (bits - high);
mutex_lock(&oplus_chg_debug_info.nflag_lock);
oplus_chg_debug_info.notify_flag &= ~mask;
mutex_unlock(&oplus_chg_debug_info.nflag_lock);
return 0;
}
static void oplus_chg_send_info_dwork(struct work_struct *work)
{
int ret;
mutex_lock(&oplus_chg_debug_info.dcs_info_lock);
ret = kevent_send_to_user(oplus_chg_debug_info.dcs_info);
mutex_unlock(&oplus_chg_debug_info.dcs_info_lock);
if ((ret > 0) && (oplus_chg_debug_info.retry_cnt > 0)) {
queue_delayed_work(oplus_chg_debug_info.oplus_chg_debug_wq,
&oplus_chg_debug_info.send_info_dwork, msecs_to_jiffies(SEND_INFO_DELAY));
}
else {
//soc jump
oplus_chg_debug_mask_notify_flag(0, OPLUS_NOTIFY_BATT_SOC_JUMP);
//slow check
oplus_chg_debug_mask_notify_flag(OPLUS_NOTIFY_CHG_SLOW_CHECK_TIME, OPLUS_NOTIFY_CHG_SLOW_CHECK_TIME);
//batt full
oplus_chg_debug_mask_notify_flag(OPLUS_NOTIFY_CHG_SLOW_CHECK_TIME + 1, OPLUS_NOTIFY_CHG_FULL);
//batt aging
oplus_chg_debug_mask_notify_flag(OPLUS_NOTIFY_CHG_FULL + 1, OPLUS_NOTIFY_BATT_AGING);
oplus_chg_reset_chg_notify_type();
}
chg_err("retry_cnt: %d\n", oplus_chg_debug_info.retry_cnt);
oplus_chg_debug_info.retry_cnt--;
}
#endif
static int oplus_chg_read_filedata(struct timespec *ts)
{
struct file *filp = NULL;
mm_segment_t old_fs;
ssize_t size;
loff_t offsize = 0;
char buf[32] = {0};
filp = filp_open(OPLUS_CHG_MONITOR_FILE, O_RDONLY, 0644);
if (IS_ERR(filp)) {
/*chg_err("open file %s failed[%d].\n", OPLUS_CHG_MONITOR_FILE, PTR_ERR(filp));*/
return -1;
}
old_fs = get_fs();
set_fs(KERNEL_DS);
memset(buf, 0x0, sizeof(buf));
size = vfs_read(filp, buf, sizeof(buf), &offsize);
set_fs(old_fs);
filp_close(filp, NULL);
if (size <= 0) {
chg_err("read file size is zero.\n");
return -1;
}
sscanf(buf, "%ld", &ts->tv_sec);
return 0;
}
static int oplus_chg_write_filedata(struct timespec *ts)
{
struct file *filp = NULL;
mm_segment_t old_fs;
ssize_t size;
loff_t offsize = 0;
char buf[32] = {0};
filp = filp_open(OPLUS_CHG_MONITOR_FILE, O_RDWR | O_CREAT, 0644);
if (IS_ERR(filp)) {
chg_err("open file %s failed[%d].\n", OPLUS_CHG_MONITOR_FILE, PTR_ERR(filp));
return -1;
}
old_fs = get_fs();
set_fs(KERNEL_DS);
snprintf(buf, sizeof(buf), "%lu", ts->tv_sec);
size = vfs_write(filp, buf, sizeof(buf), &offsize);
set_fs(old_fs);
filp_close(filp, NULL);
if (size <= 0) {
chg_err("read file size is zero.\n");
return -1;
}
return 0;
}
#if 0
static void oplus_chg_print_debug_info(struct oplus_chg_chip *chip)
{
int ret = 0;
int i;
if (oplus_chg_debug_info.notify_type)
{
#ifdef CONFIG_OPLUS_KEVENT_UPLOAD
if (delayed_work_pending(&oplus_chg_debug_info.send_info_dwork))
cancel_delayed_work_sync(&oplus_chg_debug_info.send_info_dwork);
mutex_lock(&oplus_chg_debug_info.dcs_info_lock);
#endif
memset(oplus_chg_debug_msg, 0x0, sizeof(oplus_chg_debug_msg));
#ifdef CONFIG_OPLUS_KEVENT_UPLOAD
ret += sizeof(struct kernel_packet_info);
#endif
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"Notify Type: 0x%-4x, ", oplus_chg_debug_info.notify_type);
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"Notify Flag: 0x%-4x, CHG_CNT[ ", oplus_chg_debug_info.notify_flag);
for(i = 0; i < OPLUS_NOTIFY_CHG_MAX_CNT; i++)
{
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"%4d ", oplus_chg_debug_info.chg_cnt[i]);
}
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret, "], ");
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"DBG INFO[%3d %3d %3d %3d %3d %4d %4d], ",
oplus_chg_debug_info.pre_soc,
oplus_chg_debug_info.cur_soc,
oplus_chg_debug_info.pre_ui_soc,
oplus_chg_debug_info.cur_ui_soc,
oplus_chg_debug_info.chg_start_soc,
oplus_chg_debug_info.chg_start_time,
oplus_chg_debug_info.chg_total_time);
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"CHGR[ %d %d %d %d %d ], "
"BAT[ %d %d %d %d %d %4d ], "
"GAUGE[ %3d %d %d %4d %7d %3d %3d %3d %3d %4d], "
"STATUS[ %d %4d %d %d %d 0x%-4x ], "
"OTHER[ %d %d %d %d %d %d ]",
chip->charger_exist, chip->charger_type, chip->charger_volt, chip->prop_status, chip->boot_mode,
chip->batt_exist, chip->batt_full, chip->chging_on, chip->in_rechging, chip->charging_state, oplus_chg_debug_info.total_time,
chip->temperature, chip->batt_volt, chip->batt_volt_min, chip->icharging, chip->ibus, chip->soc, chip->ui_soc, chip->soc_load, chip->batt_rm, chip->batt_fcc,
chip->vbatt_over, chip->chging_over_time, chip->vchg_status, chip->tbatt_status, chip->stop_voter, chip->notify_code,
chip->otg_switch, chip->mmi_chg, chip->boot_reason, chip->boot_mode, chip->chargerid_volt, chip->chargerid_volt_got);
#ifdef CONFIG_OPLUS_KEVENT_UPLOAD
mutex_unlock(&oplus_chg_debug_info.dcs_info_lock);
ret = oplus_chg_pack_debug_info(chip);
if (!ret)
{
oplus_chg_debug_info.retry_cnt = SEND_INFO_MAX_CNT;
queue_delayed_work(oplus_chg_debug_info.oplus_chg_debug_wq, &oplus_chg_debug_info.send_info_dwork, 0);
}
#else
chg_err("%s\n", oplus_chg_debug_msg);
#endif
}
}
#else
static void oplus_chg_print_debug_info(struct oplus_chg_chip *chip)
{
int ret = 0;
struct oplus_vooc_chip *vooc_chip = NULL;
struct timespec ts;
struct rtc_time tm;
#ifndef OPLUS_CHG_DEBUG_TEST
if (oplus_chg_debug_info.notify_type)
#endif
{
#ifdef CONFIG_OPLUS_KEVENT_UPLOAD
if (delayed_work_pending(&oplus_chg_debug_info.send_info_dwork))
cancel_delayed_work_sync(&oplus_chg_debug_info.send_info_dwork);
mutex_lock(&oplus_chg_debug_info.dcs_info_lock);
#endif
memset(oplus_chg_debug_msg, 0x0, sizeof(oplus_chg_debug_msg));
getnstimeofday(&ts);
rtc_time_to_tm(ts.tv_sec, &tm);
#ifdef CONFIG_OPLUS_KEVENT_UPLOAD
ret += sizeof(struct kernel_packet_info);
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
OPLUS_CHG_DEBUG_EVENT_ID"$$");
#endif
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"type@@0x%x", oplus_chg_debug_info.notify_type);
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"$$flag@@0x%x", oplus_chg_debug_info.notify_flag);
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"$$pre_soc@@%d", oplus_chg_debug_info.pre_soc);
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"$$cur_soc@@%d", oplus_chg_debug_info.cur_soc);
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"$$pre_ui_soc@@%d", oplus_chg_debug_info.pre_ui_soc);
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"$$cur_ui_soc@@%d", oplus_chg_debug_info.cur_ui_soc);
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"$$sleep_time@@%lu", oplus_chg_debug_info.sleep_tm_sec);
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"$$soc_load@@%d", chip->soc_load);
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"$$batt_fcc@@%d", chip->batt_fcc);
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"$$charge_status@@%d", chip->prop_status);
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"$$boot_mode@@%d", chip->boot_mode);
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"$$chg_total_time@@%d", oplus_chg_debug_info.chg_total_time);
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"$$chg_start_temp@@%d", oplus_chg_debug_info.chg_start_temp);
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"$$chg_cur_temp@@%d", chip->temperature);
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"$$chg_start_soc@@%d", oplus_chg_debug_info.chg_start_soc);
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"$$adapter_type@@0x%x", (oplus_chg_debug_info.fast_chg_type << 8) | chip->real_charger_type);
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"$$icharging@@%d", chip->icharging);
if (oplus_chg_chg_is_normal_path(chip))
{
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"$$ibus@@%d", chip->ibus);
}
else
{
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"$$ibus@@%d", oplus_chg_debug_info.fastchg_input_current);
}
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"$$vbat@@%d", chip->batt_volt);
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"$$cool_down@@%d", chip->cool_down);
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"$$other@@time[%d-%d-%d %d:%d:%d], "
"CHGR[ %d %d %d %d %d %d %d], "
"BAT[ %d %d %d %d %d %4d ], "
"GAUGE[ %3d %d %d %4d %7d %3d %3d %3d %3d %4d], "
"STATUS[ %d %4d %d %d %d 0x%-4x %d %d %d], "
"OTHER[ %d %d %d %d %d %d ], ",
tm.tm_year + 1900, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
chip->charger_exist, chip->charger_type, chip->charger_volt, chip->prop_status, chip->boot_mode,oplus_chg_debug_info.chg_current_by_tbatt, oplus_chg_debug_info.chg_current_by_cooldown,
chip->batt_exist, chip->batt_full, chip->chging_on, chip->in_rechging, chip->charging_state, oplus_chg_debug_info.total_time,
chip->temperature, chip->batt_volt, chip->batt_volt_min, chip->icharging, chip->ibus, chip->soc, chip->ui_soc, chip->soc_load, chip->batt_rm, chip->batt_fcc,
chip->vbatt_over, chip->chging_over_time, chip->vchg_status, chip->tbatt_status, chip->stop_voter, chip->notify_code, chip->sw_full, chip->hw_full_by_sw, chip->hw_full,
chip->otg_switch, chip->mmi_chg, chip->boot_reason, chip->boot_mode, chip->chargerid_volt, chip->chargerid_volt_got);
oplus_vooc_get_vooc_chip_handle(&vooc_chip);
if (vooc_chip) {
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"VOOC[ %d / %d / %d / %d / %d / %d]",
vooc_chip->fastchg_allow, vooc_chip->fastchg_started, vooc_chip->fastchg_dummy_started,
vooc_chip->fastchg_to_normal, vooc_chip->fastchg_to_warm, vooc_chip->btb_temp_over);
}
#ifdef OPLUS_CHG_DEBUG_TEST
{
int i;
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
", CHG_CNT[");
for(i = 0; i < OPLUS_NOTIFY_CHG_MAX_CNT; i++)
{
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"%4d ", oplus_chg_debug_info.chg_cnt[i]);
}
ret += snprintf(&oplus_chg_debug_msg[ret], OPLUS_CHG_DEBUG_MSG_LEN - ret,
"]");
}
#endif
#ifdef CONFIG_OPLUS_KEVENT_UPLOAD
mutex_unlock(&oplus_chg_debug_info.dcs_info_lock);
chg_err("%s\n", &oplus_chg_debug_msg[sizeof(struct kernel_packet_info)]);
if (oplus_chg_debug_info.notify_type) {
ret = oplus_chg_pack_debug_info(chip);
if (!ret) {
oplus_chg_debug_info.retry_cnt = SEND_INFO_MAX_CNT;
queue_delayed_work(oplus_chg_debug_info.oplus_chg_debug_wq, &oplus_chg_debug_info.send_info_dwork, 0);
}
}
#else
#ifdef OPLUS_CHG_DEBUG_TEST
chg_err("%s\n", oplus_chg_debug_msg);
#endif
#endif
}
}
#endif
#if 0
static int oplus_chg_get_vooc_max_input_power()
{
int i;
int max_input_power = 0;
int arr_size = sizeof(vooc_charger_type_list) / sizeof(vooc_charger_type_list[0]);
int vol,cur;
struct oplus_vooc_chip *vooc_chip = NULL;
oplus_vooc_get_vooc_chip_handle(&vooc_chip);
if (vooc_chip == NULL)
max_input_power = 0;
for(i = 0; i < arr_size; i++)
{
if (oplus_vooc_get_fast_chg_type() == vooc_charger_type_list[i].chg_type)
{
vol = oplus_chg_debug_info.vooc_max_input_volt < vooc_charger_type_list[i].vol ?
oplus_chg_debug_info.vooc_max_input_volt : vooc_charger_type_list[i].vol;
cur = oplus_chg_debug_info.vooc_max_input_current < vooc_charger_type_list[i].cur ?
oplus_chg_debug_info.vooc_max_input_current : vooc_charger_type_list[i].cur;
max_input_power = vol * cur * 8 / 10;
break;
}
}
return max_input_power;
}
#endif
static int oplus_chg_get_input_power(struct oplus_chg_chip *chip)
{
int input_power;
input_power = chip->ibus / 1000 * chip->charger_volt * 8 / 10;
#ifdef OPLUS_CHG_DEBUG_TEST
chg_err("input_power: %d\n", input_power);
#endif
return input_power;
}
static int oplus_chg_get_vooc_adapter_type_index(struct oplus_chg_chip *chip)
{
int i;
int arr_size = sizeof(vooc_charger_type_list) / sizeof(vooc_charger_type_list[0]);
for(i = 0; i < arr_size; i++) {
if (oplus_vooc_get_fast_chg_type() == vooc_charger_type_list[i].chg_type) {
break;
}
}
if (i == arr_size)
return 0;
return i;
}
static int oplus_chg_get_vooc_adapter_is_low_input_power(struct oplus_chg_chip *chip)
{
int adapter_input_power = 0;
int vooc_adapter_type_index = -1;
vooc_adapter_type_index = oplus_chg_get_vooc_adapter_type_index(chip);
adapter_input_power = vooc_charger_type_list[vooc_adapter_type_index].vol * vooc_charger_type_list[vooc_adapter_type_index].cur;
if (adapter_input_power < (oplus_chg_debug_info.vooc_max_input_volt * oplus_chg_debug_info.vooc_max_input_current))
return 1;
return 0;
}
static int oplus_chg_get_vooc_chg_max_input_power(struct oplus_chg_chip *chip)
{
int vooc_adapter_type_index = -1;
int adapter_input_power = 0;
vooc_adapter_type_index = oplus_chg_get_vooc_adapter_type_index(chip);
adapter_input_power = vooc_charger_type_list[vooc_adapter_type_index].vol * vooc_charger_type_list[vooc_adapter_type_index].cur;
if (adapter_input_power < (oplus_chg_debug_info.vooc_max_input_volt * oplus_chg_debug_info.vooc_max_input_current))
return adapter_input_power * 8 / 10;
return (oplus_chg_debug_info.vooc_max_input_volt * oplus_chg_debug_info.vooc_max_input_current * 8 / 10);
}
static int oplus_chg_get_vooc_input_power(struct oplus_chg_chip *chip)
{
int i;
int input_power = 0;
int vol,cur;
struct oplus_vooc_chip *vooc_chip = NULL;
int mcu_chg_current = 0;
oplus_vooc_get_vooc_chip_handle(&vooc_chip);
if (vooc_chip == NULL)
return 0;
i = oplus_chg_get_vooc_adapter_type_index(chip);
vol = oplus_chg_debug_info.vooc_max_input_volt < vooc_charger_type_list[i].vol ?
oplus_chg_debug_info.vooc_max_input_volt : vooc_charger_type_list[i].vol;
cur = oplus_chg_debug_info.vooc_max_input_current < vooc_charger_type_list[i].cur ?
oplus_chg_debug_info.vooc_max_input_current : vooc_charger_type_list[i].cur;
if (vooc_chip->vooc_chg_current_now > 0)
cur = cur < vooc_chip->vooc_chg_current_now ? cur : vooc_chip->vooc_chg_current_now;
if (oplus_chg_debug_info.vooc_charge_strategy) {
chg_err("vooc strategy input_current_index: %d\n", oplus_chg_debug_info.vooc_charge_input_current_index);
mcu_chg_current = oplus_chg_debug_info.vooc_charge_strategy->input_current[oplus_chg_debug_info.vooc_charge_input_current_index].cur;
cur = cur < mcu_chg_current ? cur : mcu_chg_current;
}
oplus_chg_debug_info.fastchg_input_current = cur;
input_power = vol * cur * 8 / 10;
#ifdef OPLUS_CHG_DEBUG_TEST
chg_err("input_power: %d\n", input_power);
#endif
return input_power;
}
static int oplus_chg_get_charge_power(struct oplus_chg_chip *chip)
{
int charge_power;
charge_power = chip->icharging * chip->batt_volt * chip->vbatt_num;
#ifdef OPLUS_CHG_DEBUG_TEST
chg_err("charge_pwoer: %d\n", charge_power);
#endif
return charge_power;
}
static int oplus_chg_reset_chg_cnt(int index)
{
if ((index < 0) && (index >= OPLUS_NOTIFY_CHG_MAX_CNT))
return -1;
mutex_lock(&oplus_chg_debug_info.nflag_lock);
oplus_chg_debug_info.chg_cnt[index] = 0;
mutex_unlock(&oplus_chg_debug_info.nflag_lock);
return 0;
}
static int oplus_chg_set_notify_type(int index)
{
if ((index < 0) || (index >= OPLUS_CHG_DEBUG_NOTIFY_TYPE_MAX))
return -1;
mutex_lock(&oplus_chg_debug_info.nflag_lock);
oplus_chg_debug_info.notify_type |= (1 << index);
mutex_unlock(&oplus_chg_debug_info.nflag_lock);
return 0;
}
static int oplus_chg_debug_notify_type_is_set(int type)
{
int ret = 0;
mutex_lock(&oplus_chg_debug_info.nflag_lock);
if (oplus_chg_debug_info.notify_type & (1 << type)) {
ret = 1;
}
mutex_unlock(&oplus_chg_debug_info.nflag_lock);
return ret;
}
static int oplus_chg_reset_chg_notify_type(void)
{
mutex_lock(&oplus_chg_debug_info.nflag_lock);
oplus_chg_debug_info.notify_type = 0;
mutex_unlock(&oplus_chg_debug_info.nflag_lock);
return 0;
}
static int oplus_chg_set_chg_flag(int index)
{
int rc = 0;
int policy_time = 1;
if ((index < 0) || (index >= OPLUS_NOTIFY_CHG_MAX_CNT))
return -1;
mutex_lock(&oplus_chg_debug_info.nflag_lock);
oplus_chg_debug_info.chg_cnt[index]++;
if ((oplus_chg_debug_info.fast_chg_type == FASTCHG_CHARGER_TYPE_UNKOWN)
|| (oplus_chg_debug_info.fast_chg_type == CHARGER_SUBTYPE_FASTCHG_VOOC)) {
policy_time = oplus_chg_debug_notify_policy[index].normal_chg_time;
}
else {
policy_time = oplus_chg_debug_notify_policy[index].fast_chg_time;
}
switch(oplus_chg_debug_notify_policy[index].policy)
{
case OPLUS_CHG_NOTIFY_ONCE:
if (oplus_chg_debug_info.chg_cnt[index] == policy_time)
{
oplus_chg_debug_info.notify_flag |= (1 << index);
}
rc = 0;
break;
case OPLUS_CHG_NOTIFY_REPEAT:
if ((oplus_chg_debug_info.chg_cnt[index] % policy_time) == 0)
{
oplus_chg_debug_info.notify_flag |= (1 << index);
}
if ((index == OPLUS_NOTIFY_CHG_SLOW_CHECK_TIME)
&& (oplus_chg_debug_info.chg_cnt[index] > policy_time)
&& ((oplus_chg_debug_info.chg_cnt[index] - policy_time) % (policy_time / 3) == 0))
{
oplus_chg_debug_info.notify_flag |= (1 << index);
}
rc = 0;
break;
case OPLUS_CHG_NOTIFY_TOTAL:
if (((oplus_chg_debug_info.chg_cnt[index] % (policy_time * oplus_chg_debug_notify_policy[index].percent / 100)) == 0))
{
oplus_chg_debug_info.notify_flag |= (1 << index);
}
rc = 0;
break;
default:
rc = -1;
}
#ifdef OPLUS_CHG_DEBUG_TEST
chg_err("cnt: %d, index: %d, flag: 0x%x\n",
oplus_chg_debug_info.chg_cnt[index], index, oplus_chg_debug_info.notify_flag);
#endif
mutex_unlock(&oplus_chg_debug_info.nflag_lock);
return rc;
}
static int oplus_chg_vooc_charge_strategy_init(struct oplus_chg_chip *chip)
{
int i;
int index;
int output_power_type = -1;
int start_soc, start_temp;
struct vooc_charge_strategy *vooc_charge_strategy_p;
if (oplus_chg_debug_info.vooc_charge_strategy != NULL)
{
for(i = oplus_chg_debug_info.vooc_charge_input_current_index; i < OPLUS_CHG_VOOC_INPUT_CURRENT_MAX_CNT; i++) {
if (chip->batt_volt <= oplus_chg_debug_info.vooc_charge_strategy->input_current[i].vol) {
if (i == oplus_chg_debug_info.vooc_charge_input_current_index)
oplus_chg_debug_info.vooc_charge_cur_state_chg_time +=5;
if (oplus_chg_debug_info.vooc_charge_strategy->input_current[i].time > 0) {
if (oplus_chg_debug_info.vooc_charge_cur_state_chg_time >= oplus_chg_debug_info.vooc_charge_strategy->input_current[i].time) {
if (i < (OPLUS_CHG_VOOC_INPUT_CURRENT_MAX_CNT - 1)) {
i++;
}
}
}
if (i != oplus_chg_debug_info.vooc_charge_input_current_index) {
oplus_chg_debug_info.vooc_charge_cur_state_chg_time = 0;
oplus_chg_debug_info.vooc_charge_input_current_index = i;
}
break;
}
}
return 0;
}
if (!oplus_chg_chg_is_normal_path(chip)) {
if (oplus_vooc_get_fastchg_started()) {
index = oplus_chg_get_vooc_adapter_type_index(chip);
output_power_type = vooc_charger_type_list[index].output_power_type;
}
}
if (output_power_type >= 0) {
start_soc = chip->soc;
start_temp = chip->temperature;
vooc_charge_strategy_p = g_vooc_charge_strategy_p[output_power_type];
if (vooc_charge_strategy_p) {
for(i = 0; vooc_charge_strategy_p[i].capacity_range.low != -1; i++) {
if ((vooc_charge_strategy_p[i].capacity_range.low < start_soc)
&& (vooc_charge_strategy_p[i].capacity_range.high >= start_soc)
&& (vooc_charge_strategy_p[i].temp_range.low < start_temp)
&& (vooc_charge_strategy_p[i].temp_range.high >= start_temp)) {
oplus_chg_debug_info.vooc_charge_strategy = &vooc_charge_strategy_p[i];
chg_err("output_power_type: %d, capacity_range [%d, %d], temp_range [%d, %d]\n",
output_power_type,
vooc_charge_strategy_p[i].capacity_range.low,
vooc_charge_strategy_p[i].capacity_range.high,
vooc_charge_strategy_p[i].temp_range.low,
vooc_charge_strategy_p[i].temp_range.high);
break;
}
}
}
}
if (oplus_chg_debug_info.vooc_charge_strategy) {
for(i = oplus_chg_debug_info.vooc_charge_input_current_index; i < OPLUS_CHG_VOOC_INPUT_CURRENT_MAX_CNT; i++) {
if (chip->batt_volt <= oplus_chg_debug_info.vooc_charge_strategy->input_current[i].vol) {
oplus_chg_debug_info.vooc_charge_input_current_index = i;
oplus_chg_debug_info.vooc_charge_cur_state_chg_time = 5;
break;
}
}
}
return 0;
}
#if 0
static int oplus_chg_vooc_charge_strategy_post(struct oplus_chg_chip *chip)
{
if (oplus_chg_debug_info.vooc_charge_strategy != NULL)
return 0;
if (oplus_chg_chg_is_normal_path(chip))
return 0;
if (oplus_vooc_get_fastchg_started())
{
oplus_chg_debug_info.vooc_charge_cur_state_chg_time += 5;
}
else
{
oplus_chg_debug_info.vooc_charge_strategy = NULL;
oplus_chg_debug_info.vooc_charge_input_current_index = 0;
oplus_chg_debug_info.vooc_charge_cur_state_chg_time = 0;
}
return 0;
}
#endif
int oplus_chg_debug_set_cool_down_by_user(int is_cool_down)
{
oplus_chg_debug_info.cool_down_by_user = is_cool_down;
return 0;
}
int oplus_chg_debug_get_cooldown_current(int chg_current_by_tbatt, int chg_current_by_cooldown)
{
oplus_chg_debug_info.chg_current_by_tbatt = chg_current_by_tbatt;
oplus_chg_debug_info.chg_current_by_cooldown = chg_current_by_cooldown;
return 0;
}
static int oplus_chg_debug_fastchg_monitor_condition(struct oplus_chg_chip *chip)
{
if (oplus_chg_debug_info.fastchg_stop_cnt < OPLUS_CHG_DEBUG_FASTCHG_STOP_CNT) {
oplus_chg_debug_info.fastchg_stop_cnt++;
return 0;
}
return 1;
}
static int oplus_chg_chg_is_normal_path(struct oplus_chg_chip *chip)
{
struct oplus_vooc_chip *vooc_chip = NULL;
if (!oplus_vooc_get_fastchg_started())
return 1;
oplus_vooc_get_vooc_chip_handle(&vooc_chip);
if (vooc_chip == NULL)
return 1;
if (vooc_chip->support_vooc_by_normal_charger_path
&& (oplus_vooc_get_fast_chg_type() == CHARGER_SUBTYPE_FASTCHG_VOOC))
return 1;
return 0;
}
static int oplus_chg_fastchg_is_allowed(struct oplus_chg_chip *chip)
{
struct oplus_vooc_chip *vooc_chip = NULL;
if (chip->charger_type != POWER_SUPPLY_TYPE_USB_DCP)
return 0;
oplus_vooc_get_vooc_chip_handle(&vooc_chip);
if (vooc_chip) {
if (chip->temperature < vooc_chip->vooc_low_temp)
return 0;
if (chip->temperature > vooc_chip->vooc_high_temp)
return 0;
if (chip->soc < vooc_chip->vooc_low_soc)
return 0;
if (chip->soc > vooc_chip->vooc_high_soc)
return 0;
return 1;
}
else {
return 0;
}
return 1;
}
static int oplus_chg_normal_chg_input_power_check(struct oplus_chg_chip *chip)
{
#ifdef CONFIG_OPLUS_SHORT_USERSPACE
int input_current_settled;
int input_voltage_settled;
union power_supply_propval pval = {0, };
int float_voltage;
power_supply_get_property(oplus_chg_debug_info.usb_psy,
POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, &pval);
input_current_settled = pval.intval;
pval.intval = 0;
power_supply_get_property(oplus_chg_debug_info.usb_psy,
POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval);
input_voltage_settled = pval.intval;
pval.intval = 0;
power_supply_get_property(oplus_chg_debug_info.batt_psy,
POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval);
float_voltage = pval.intval;
if ((chip->batt_volt * 1000) < float_voltage) {
if (((input_current_settled * input_voltage_settled / 1000) - (chip->ibus * chip->charger_volt))
> INPUT_POWER_DECREASE) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_ADAPTER_INPUT_LOW_POWER);
}
}
else {
oplus_chg_reset_chg_cnt(OPLUS_NOTIFY_CHG_SLOW_ADAPTER_INPUT_LOW_POWER);
}
#endif
return 0;
}
static int oplus_chg_normal_chg_consume_power_check(struct oplus_chg_chip *chip)
{
int input_power;
int charge_power;
input_power = oplus_chg_get_input_power(chip);
charge_power = oplus_chg_get_charge_power(chip);
//系统功耗
if (!chip->led_on) {
//黑屏
if ((oplus_chg_debug_info.total_time - oplus_chg_debug_info.led_off_start_time) > LED_OFF_STABLE_TIME) {
if ((input_power + charge_power) > LED_OFF_HIGH_POWER_CONSUPTION) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_SYS_POWER_CONSUME_HIGH);
}
}
}
else {
//亮屏
if ((input_power + charge_power) > LED_ON_HIGH_POWER_CONSUPTION) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_SYS_POWER_CONSUME_HIGH);
}
}
return 0;
}
static int oplus_chg_fastchg_chg_input_power_check(struct oplus_chg_chip *chip)
{
int input_power;
int charge_power;
if (chip->led_on)
return 0;
if (oplus_chg_debug_info.cool_down_by_user)
return 0;
input_power = oplus_chg_get_vooc_input_power(chip);
charge_power = oplus_chg_get_charge_power(chip);
if (((input_power + charge_power) > INPUT_POWER_DECREASE) && (!chip->led_on)
&& (chip->batt_volt < HIGH_POWER_FASTCHG_BATT_VOLT)) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_ADAPTER_INPUT_LOW_POWER);
}
else {
oplus_chg_reset_chg_cnt(OPLUS_NOTIFY_CHG_SLOW_ADAPTER_INPUT_LOW_POWER);
}
return 0;
}
static int oplus_chg_fastchg_consume_power_check(struct oplus_chg_chip *chip)
{
int input_power;
int charge_power;
//系统功耗
//if (chip->batt_volt < HIGH_POWER_FASTCHG_BATT_VOLT)
{
input_power = oplus_chg_get_vooc_input_power(chip);
charge_power = oplus_chg_get_charge_power(chip);
if (!chip->led_on) {
//黑屏
if ((oplus_chg_debug_info.total_time - oplus_chg_debug_info.led_off_start_time) > LED_OFF_STABLE_TIME) {
if ((input_power + charge_power) > LED_OFF_HIGH_POWER_CONSUPTION) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_SYS_POWER_CONSUME_HIGH);
}
}
}
else {
if ((input_power + charge_power) > LED_ON_HIGH_POWER_CONSUPTION) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_SYS_POWER_CONSUME_HIGH);
}
}
}
return 0;
}
static int oplus_chg_fastchg_power_limit_check(struct oplus_chg_chip *chip)
{
int vooc_chg_max_input_power;
int charge_power;
vooc_chg_max_input_power = oplus_chg_get_vooc_chg_max_input_power(chip);
charge_power = oplus_chg_get_charge_power(chip);
#ifdef OPLUS_CHG_DEBUG_TEST
chg_err("vooc_chg_max_input_power = %d, charge_power = %d\n",
vooc_chg_max_input_power, charge_power);
#endif
if ((-1 * charge_power * 10) < (vooc_chg_max_input_power * 5)) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_LOW_CHARGE_CURRENT_LONG_TIME);
}
return 0;
}
static int oplus_chg_input_power_limit_check(struct oplus_chg_chip *chip)
{
int float_voltage;
union power_supply_propval pval = {0, };
int default_input_current = -1;
int max_charger_voltage = -1;
int charge_power = oplus_chg_get_charge_power(chip);
struct oplus_vooc_chip *vooc_chip = NULL;
oplus_vooc_get_vooc_chip_handle(&vooc_chip);
if (vooc_chip) {
if (chip->charger_type == POWER_SUPPLY_TYPE_USB_DCP) {
if (vooc_chip->fastchg_to_warm) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_FASTCHG_TO_WARM);
}
else {
if ((chip->soc < vooc_chip->vooc_high_soc) && (chip->soc > vooc_chip->vooc_low_soc)) {
if (chip->temperature >= vooc_chip->vooc_high_temp) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_BATT_WARM_TEMP);
}
if (chip->temperature <= vooc_chip->vooc_low_temp) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_BATT_COLD_TEMP);
}
}
}
}
}
if (oplus_chg_chg_is_normal_path(chip)) {
power_supply_get_property(oplus_chg_debug_info.batt_psy,
POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval);
float_voltage = pval.intval;
pval.intval = 0;
power_supply_get_property(oplus_chg_debug_info.usb_psy,
POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval);
max_charger_voltage = pval.intval;
if (chip->batt_volt < float_voltage) {
switch(chip->real_charger_type)
{
case POWER_SUPPLY_TYPE_USB_DCP:
if (oplus_vooc_get_fast_chg_type() == CHARGER_SUBTYPE_FASTCHG_VOOC) {
default_input_current = chip->limits.default_input_current_vooc_ma_normal;
}
else {
default_input_current = chip->limits.default_input_current_charger_ma;
}
break;
case POWER_SUPPLY_TYPE_USB_CDP:
default_input_current = chip->limits.input_current_cdp_ma;
break;
case POWER_SUPPLY_TYPE_USB_PD:
default_input_current = chip->limits.pd_input_current_charger_ma;
break;
#ifndef CONFIG_OPLUS_CHARGER_MTK
case POWER_SUPPLY_TYPE_USB_HVDCP:
case POWER_SUPPLY_TYPE_USB_HVDCP_3:
//case POWER_SUPPLY_TYPE_USB_HVDCP_3P5:
default_input_current = chip->limits.qc_input_current_charger_ma;
break;
#endif
default:
default_input_current = -1;
max_charger_voltage = -1;
break;
}
if ((default_input_current > 0) && (max_charger_voltage > 0)) {
if ((-1 * charge_power * 10) < (default_input_current * max_charger_voltage * 6)) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_LOW_CHARGE_CURRENT_LONG_TIME);
}
}
}
}
else {
if (oplus_vooc_get_fastchg_started() == true)
oplus_chg_fastchg_power_limit_check(chip);
}
return 0;
}
static int oplus_chg_chg_slow_check(struct oplus_chg_chip *chip)
{
struct timespec ts = {0, 0};
static struct timespec charge_start_ts = {0, 0};
if ((oplus_chg_debug_info.pre_prop_status != chip->prop_status)
&& (chip->prop_status != POWER_SUPPLY_STATUS_CHARGING)) {
if (!chip->charger_exist) {
oplus_chg_debug_info_reset();
}
oplus_chg_debug_info.pre_prop_status = chip->prop_status;
}
if (chip->charger_exist) {
if (!oplus_chg_debug_info.total_time) {
oplus_chg_debug_info.total_time = 5;
getnstimeofday(&charge_start_ts);
}
else {
getnstimeofday(&ts);
oplus_chg_debug_info.total_time = 5 + ts.tv_sec - charge_start_ts.tv_sec;
}
}
else {
oplus_chg_debug_info.total_time = 0;
}
if (chip->charger_exist && (chip->prop_status != POWER_SUPPLY_STATUS_FULL)) {
//高温限流
if ((chip->tbatt_status == BATTERY_STATUS__WARM_TEMP)
|| (chip->tbatt_status == BATTERY_STATUS__HIGH_TEMP)) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_BATT_WARM_TEMP);
if (chip->prop_status != POWER_SUPPLY_STATUS_CHARGING) {
goto oplus_chg_slow_check_end;
}
}
//低温限流
if ((chip->tbatt_status == BATTERY_STATUS__COLD_TEMP)
|| (chip->tbatt_status == BATTERY_STATUS__LOW_TEMP)
|| (chip->tbatt_status == BATTERY_STATUS__REMOVED)) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_BATT_COLD_TEMP);
if (chip->prop_status != POWER_SUPPLY_STATUS_CHARGING) {
goto oplus_chg_slow_check_end;
}
}
if (chip->notify_code & (1 << NOTIFY_CHARGER_OVER_VOL)) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_CHARGER_OV);
if (chip->prop_status != POWER_SUPPLY_STATUS_CHARGING) {
goto oplus_chg_slow_check_end;
}
}
if (chip->notify_code & (1 << NOTIFY_CHARGER_LOW_VOL)) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_CHARGER_UV);
if (chip->prop_status != POWER_SUPPLY_STATUS_CHARGING) {
goto oplus_chg_slow_check_end;
}
}
}
if (!(chip->prop_status == POWER_SUPPLY_STATUS_CHARGING)) {
return 0;
}
//detect the charger is fast-charger or not
//if it's fast-charger, there is not need set unknown when it back to normal charge mode
if (oplus_vooc_get_fastchg_started()) {
if (oplus_chg_debug_info.fast_chg_type == FASTCHG_CHARGER_TYPE_UNKOWN) {
oplus_chg_debug_info.fast_chg_type = oplus_vooc_get_fast_chg_type();
chg_err("fast_chg_type = %d\n", oplus_chg_debug_info.fast_chg_type);
}
}
if ((oplus_chg_debug_info.pre_prop_status != chip->prop_status)
&& (oplus_chg_debug_info.pre_prop_status != POWER_SUPPLY_STATUS_CHARGING)) {
oplus_chg_debug_info.chg_start_soc = chip->soc;
oplus_chg_debug_info.chg_start_temp = chip->temperature;
oplus_chg_debug_info.chg_start_time = oplus_chg_debug_info.total_time;
}
oplus_chg_debug_info.pre_prop_status = chip->prop_status;
oplus_chg_debug_info.chg_total_time = oplus_chg_debug_info.total_time - oplus_chg_debug_info.chg_start_time;
if ((oplus_chg_debug_info.total_time - oplus_chg_debug_info.chg_start_time) < OPLUS_CHG_START_STABLE_TIME) {
goto oplus_chg_slow_check_end;
}
//电池认证
if (!chip->authenticate) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_BATT_NON_AUTH);
goto oplus_chg_slow_check_end;
}
if (!oplus_chg_chg_is_normal_path(chip)) {
if (!oplus_chg_debug_fastchg_monitor_condition(chip)) {
goto oplus_chg_slow_check_end;
}
}
else {
if (oplus_chg_debug_info.batt_psy) {
union power_supply_propval pval = {0, };
power_supply_get_property(oplus_chg_debug_info.batt_psy,
POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval);
if (chip->batt_volt > pval.intval) {
goto oplus_chg_slow_check_end;
}
}
}
//SDP充电
if (chip->charger_type == POWER_SUPPLY_TYPE_USB) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_CHG_TYPE_SDP);
goto oplus_chg_slow_check_end;
}
if (chip->notify_code & (1 << NOTIFY_CHGING_OVERTIME))
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_OVERTIME);
if ((oplus_chg_debug_info.pre_led_state != chip->led_on)
&& (!chip->led_on)) {
oplus_chg_debug_info.led_off_start_time = oplus_chg_debug_info.total_time;
}
oplus_chg_debug_info.pre_led_state = chip->led_on;
//vooc charge strategy init
oplus_chg_vooc_charge_strategy_init(chip);
//线损检测
if (oplus_chg_chg_is_normal_path(chip)) {
oplus_chg_normal_chg_input_power_check(chip);
}
else {
oplus_chg_fastchg_chg_input_power_check(chip);
}
//充电器及充电类型检测
if (chip->vooc_project) {
#if 0
if (!((chip->chargerid_volt <= OPLUS_CHARGERID_VOLT_HIGH_THLD)
&& (chip->chargerid_volt >= OPLUS_CHARGERID_VOLT_LOW_THLD)))
{
//非oplus充电器
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_NON_OPLUS_CHARGER);
}
else
#endif
{
if ((oplus_chg_fastchg_is_allowed(chip) == 1)
&& (oplus_vooc_get_fastchg_started() == false)) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_VOOC_NON_START);
}
else if ((oplus_vooc_get_fastchg_started() == true)) {
if (oplus_chg_get_vooc_adapter_is_low_input_power(chip)) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_VOOC_ADAPTER_NON_MAX_POWER);
}
}
}
}
//系统功耗检测
if (oplus_chg_chg_is_normal_path(chip)) {
oplus_chg_normal_chg_consume_power_check(chip);
}
else {
oplus_chg_fastchg_consume_power_check(chip);
}
//cool down检测
if (!oplus_chg_chg_is_normal_path(chip)) {
if (oplus_chg_debug_info.cool_down_by_user) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_COOLDOWN_LONG_TIME);
}
}
//长时间处于限流阶段
#if 0
if ((chip->tbatt_status == BATTERY_STATUS__WARM_TEMP) || (chip->tbatt_status == BATTERY_STATUS__COLD_TEMP))
{
if (chip->tbatt_status == BATTERY_STATUS__WARM_TEMP)
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_BATT_WARM_TEMP);
if (chip->tbatt_status == BATTERY_STATUS__COLD_TEMP)
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_BATT_COLD_TEMP);
}
else if (oplus_vooc_get_fastchg_started())
{
//TODO
}
#else
oplus_chg_input_power_limit_check(chip);
#endif
//长时间亮屏
if (chip->led_on) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_LED_ON_LONG_TIME);
}
//长时间camera打开
if (chip->camera_on) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_CAM_ON_LONG_TIME);
}
//长时间calling
if (chip->calling_on) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_CALLING_LONG_TIME);
}
oplus_chg_slow_check_end:
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_SLOW_CHECK_TIME);
if (oplus_chg_debug_notify_flag_is_set(OPLUS_NOTIFY_CHG_SLOW_CHECK_TIME)) {
oplus_chg_set_notify_type(OPLUS_CHG_DEBUG_NOTIFY_TYPE_CHG_SLOW);
}
return 0;
}
static int oplus_chg_chg_full_check(struct oplus_chg_chip *chip)
{
union power_supply_propval pval = {0, };
int status, capacity;
power_supply_get_property(oplus_chg_debug_info.batt_psy,
POWER_SUPPLY_PROP_STATUS, &pval);
status = pval.intval;
#if 0
power_supply_get_property(oplus_chg_debug_info.batt_psy,
POWER_SUPPLY_PROP_CAPACITY, &pval);
capacity = pval.intval;
#endif
capacity = oplus_chg_debug_info.cur_soc;
if ((status == POWER_SUPPLY_STATUS_FULL) && (capacity != 100)
&& (!(oplus_chg_debug_info.chg_full_notified_flag & (1 << 0)))) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_BATT_FULL_NON_100_CAP);
if (oplus_chg_debug_notify_flag_is_set(OPLUS_NOTIFY_CHG_BATT_FULL_NON_100_CAP)) {
oplus_chg_debug_info.chg_full_notified_flag |= (1 << 0);
oplus_chg_set_notify_type(OPLUS_CHG_DEBUG_NOTIFY_TYPE_CHG_FULL);
}
}
else if ((status == POWER_SUPPLY_STATUS_FULL) && (capacity == 100)) {
oplus_chg_debug_info.chg_full_notified_flag &= ~(1 << 0);
if (!(oplus_chg_debug_info.chg_full_notified_flag & (1 << 1))) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_CHG_BATT_FULL_AND_100_CAP);
if (oplus_chg_debug_notify_flag_is_set(OPLUS_NOTIFY_CHG_BATT_FULL_AND_100_CAP)) {
oplus_chg_debug_info.chg_full_notified_flag |= (1 << 1);
oplus_chg_set_notify_type(OPLUS_CHG_DEBUG_NOTIFY_TYPE_CHG_FULL);
}
}
}
else {
oplus_chg_debug_info.chg_full_notified_flag = 0;
}
return 0;
}
//TODO
static int oplus_chg_chg_batt_aging_check(struct oplus_chg_chip *chip)
{
union power_supply_propval pval = {0, };
int ret;
struct timespec ts;
static struct timespec last_ts = {0, 0};
struct rtc_time tm;
static int count = 0;
#ifdef OPLUS_CHG_DEBUG_TEST
if ((aging_cap_test > 0) || (count++ > OPLUS_CHG_BATT_AGING_CHECK_CNT))
#else
if (count++ > OPLUS_CHG_BATT_AGING_CHECK_CNT)
#endif
{
getnstimeofday(&ts);
if (last_ts.tv_sec == 0) {
ret = oplus_chg_read_filedata(&last_ts);
if (ret < 0) {
ret = oplus_chg_write_filedata(&ts);
if (!ret) {
last_ts.tv_sec = ts.tv_sec;
count = 0;
}
}
return 0;
}
rtc_time_to_tm(last_ts.tv_sec, &tm);
chg_err("last date: %d-%d-%d %d:%d:%d\n",
tm.tm_year + 1900,
tm.tm_mon,
tm.tm_mday,
tm.tm_hour,
tm.tm_min,
tm.tm_sec
);
rtc_time_to_tm(ts.tv_sec, &tm);
chg_err("current date: %d-%d-%d %d:%d:%d\n",
tm.tm_year + 1900,
tm.tm_mon,
tm.tm_mday,
tm.tm_hour,
tm.tm_min,
tm.tm_sec
);
#ifdef OPLUS_CHG_DEBUG_TEST
if ((aging_cap_test > 0) || (ts.tv_sec - last_ts.tv_sec > OPLUS_CHG_BATT_AGING_CHECK_TIME))
#else
if (ts.tv_sec - last_ts.tv_sec > OPLUS_CHG_BATT_AGING_CHECK_TIME)
#endif
{
#if 0
ret = power_supply_get_property(oplus_chg_debug_info.batt_psy,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, &pval);
if (ret < 0)
return -1;
oplus_chg_debug_info.fcc_design = pval.intval;
#endif
ret = power_supply_get_property(oplus_chg_debug_info.batt_psy,
POWER_SUPPLY_PROP_BATTERY_FCC, &pval);
if (ret < 0)
return -1;
ret = oplus_chg_write_filedata(&ts);
if (!ret) {
last_ts.tv_sec = ts.tv_sec;
count = 0;
oplus_chg_set_chg_flag(OPLUS_NOTIFY_BATT_AGING_CAP);
if (oplus_chg_debug_notify_flag_is_set(OPLUS_NOTIFY_BATT_AGING_CAP)) {
oplus_chg_set_notify_type(OPLUS_CHG_DEBUG_NOTIFY_TYPE_BATT_FCC);
#ifdef OPLUS_CHG_DEBUG_TEST
aging_cap_test = -1;
#endif
}
}
}
else {
count = 0;
}
}
return 0;
}
int oplus_chg_debug_set_soc_info(struct oplus_chg_chip *chip)
{
if (chip->sleep_tm_sec > 0) {
//suspend
oplus_chg_debug_info.sleep_tm_sec = chip->sleep_tm_sec;
oplus_chg_debug_info.cur_soc = chip->soc;
oplus_chg_debug_info.cur_ui_soc = chip->ui_soc;
}
else {
//resume
oplus_chg_chg_batt_capacity_jump_check(chip);
}
return 0;
}
static void oplus_chg_soc_load_dwork(struct work_struct *work)
{
if (oplus_chg_debug_info.soc_load_flag & (1 << OPLUS_NOTIFY_BATT_SOC_CAPCITY_LOAD_JUMP)) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_BATT_SOC_CAPCITY_LOAD_JUMP);
if (oplus_chg_debug_notify_flag_is_set(OPLUS_NOTIFY_BATT_SOC_CAPCITY_LOAD_JUMP)) {
oplus_chg_set_notify_type(OPLUS_CHG_DEBUG_NOTIFY_TYPE_SOC_JUMP);
}
}
if (oplus_chg_debug_info.soc_load_flag & (1 << OPLUS_NOTIFY_BATT_UI_SOC_CAPCITY_LOAD_JUMP)) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_BATT_UI_SOC_CAPCITY_LOAD_JUMP);
if (oplus_chg_debug_notify_flag_is_set(OPLUS_NOTIFY_BATT_UI_SOC_CAPCITY_LOAD_JUMP)) {
oplus_chg_set_notify_type(OPLUS_CHG_DEBUG_NOTIFY_TYPE_SOC_JUMP);
}
}
oplus_chg_debug_info.soc_load_flag = 0;
}
static int oplus_chg_set_soc_notified_flag(int flag)
{
oplus_chg_debug_info.soc_notified_flag |= (1 << flag);
return 0;
}
static int oplus_chg_unset_soc_notified_flag(int flag)
{
oplus_chg_debug_info.soc_notified_flag &= ~(1 << flag);
return 0;
}
static int oplus_chg_soc_notified_flag_is_set(int flag)
{
if (oplus_chg_debug_info.soc_notified_flag & (1 << flag))
return 1;
return 0;
}
static int oplus_chg_chg_batt_capacity_jump_check(struct oplus_chg_chip *chip)
{
if (oplus_chg_debug_info.cur_soc == OPLUS_CHG_BATT_INVALID_CAPACITY) {
oplus_chg_debug_info.pre_soc = chip->soc;
oplus_chg_debug_info.cur_soc = chip->soc;
oplus_chg_debug_info.cur_ui_soc = chip->ui_soc;
oplus_chg_debug_info.pre_ui_soc = chip->ui_soc;
if (abs(oplus_chg_debug_info.cur_soc - chip->soc_load) > OPLUS_CHG_BATT_S0C_CAPACITY_LOAD_JUMP_NUM) {
oplus_chg_debug_info.soc_load_flag |= 1 << OPLUS_NOTIFY_BATT_SOC_CAPCITY_LOAD_JUMP;
}
if (abs(oplus_chg_debug_info.cur_ui_soc - chip->soc_load) > OPLUS_CHG_BATT_UI_S0C_CAPACITY_LOAD_JUMP_NUM) {
oplus_chg_debug_info.soc_load_flag |= 1 << OPLUS_NOTIFY_BATT_UI_SOC_CAPCITY_LOAD_JUMP;
}
if (oplus_chg_debug_info.soc_load_flag) {
//delay upload soc_load jump to wait for oplus_kevent deamon
queue_delayed_work(oplus_chg_debug_info.oplus_chg_debug_wq,
&oplus_chg_debug_info.soc_load_dwork, msecs_to_jiffies(SOC_LOAD_DELAY));
}
}
else {
oplus_chg_debug_info.pre_soc = oplus_chg_debug_info.cur_soc;
oplus_chg_debug_info.pre_ui_soc = oplus_chg_debug_info.cur_ui_soc;
#ifdef OPLUS_CHG_DEBUG_TEST
if (fake_soc >= 0) {
oplus_chg_debug_info.cur_soc = fake_soc;
}
else {
oplus_chg_debug_info.cur_soc = chip->soc;
}
if (fake_ui_soc >= 0) {
oplus_chg_debug_info.cur_ui_soc = fake_ui_soc;
}
else {
oplus_chg_debug_info.cur_ui_soc = chip->ui_soc;
}
#else
oplus_chg_debug_info.cur_soc = chip->soc;
oplus_chg_debug_info.cur_ui_soc = chip->ui_soc;
#endif
if ((abs(oplus_chg_debug_info.cur_soc - oplus_chg_debug_info.pre_soc) > OPLUS_CHG_BATT_S0C_CAPACITY_JUMP_NUM)
&& (!oplus_chg_soc_notified_flag_is_set(OPLUS_NOTIFY_BATT_SOC_CAPCITY_JUMP))) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_BATT_SOC_CAPCITY_JUMP);
if (oplus_chg_debug_notify_flag_is_set(OPLUS_NOTIFY_BATT_SOC_CAPCITY_JUMP)) {
oplus_chg_set_notify_type(OPLUS_CHG_DEBUG_NOTIFY_TYPE_SOC_JUMP);
oplus_chg_set_soc_notified_flag(OPLUS_NOTIFY_BATT_SOC_CAPCITY_JUMP);
}
}
else if (oplus_chg_debug_info.cur_soc == oplus_chg_debug_info.pre_soc) {
oplus_chg_unset_soc_notified_flag(OPLUS_NOTIFY_BATT_SOC_CAPCITY_JUMP);
}
if ((abs(oplus_chg_debug_info.cur_ui_soc - oplus_chg_debug_info.pre_ui_soc) > OPLUS_CHG_BATT_UI_S0C_CAPACITY_JUMP_NUM)
&& (!oplus_chg_soc_notified_flag_is_set(OPLUS_NOTIFY_BATT_UI_SOC_CAPCITY_JUMP))) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_BATT_UI_SOC_CAPCITY_JUMP);
if (oplus_chg_debug_notify_flag_is_set(OPLUS_NOTIFY_BATT_UI_SOC_CAPCITY_JUMP)) {
oplus_chg_set_notify_type(OPLUS_CHG_DEBUG_NOTIFY_TYPE_SOC_JUMP);
oplus_chg_set_soc_notified_flag(OPLUS_NOTIFY_BATT_UI_SOC_CAPCITY_JUMP);
}
}
else if (oplus_chg_debug_info.cur_ui_soc == oplus_chg_debug_info.pre_ui_soc) {
oplus_chg_unset_soc_notified_flag(OPLUS_NOTIFY_BATT_UI_SOC_CAPCITY_JUMP);
}
if ((abs(oplus_chg_debug_info.cur_ui_soc - oplus_chg_debug_info.cur_soc) > OPLUS_CHG_BATT_UI_TO_S0C_CAPACITY_JUMP_NUM)
&& (!oplus_chg_soc_notified_flag_is_set(OPLUS_NOTIFY_BATT_UI_TO_SOC_CAPCITY_JUMP))) {
oplus_chg_set_chg_flag(OPLUS_NOTIFY_BATT_UI_TO_SOC_CAPCITY_JUMP);
if (oplus_chg_debug_notify_flag_is_set(OPLUS_NOTIFY_BATT_UI_TO_SOC_CAPCITY_JUMP)) {
oplus_chg_set_notify_type(OPLUS_CHG_DEBUG_NOTIFY_TYPE_SOC_JUMP);
oplus_chg_set_soc_notified_flag(OPLUS_NOTIFY_BATT_UI_TO_SOC_CAPCITY_JUMP);
}
}
else if (oplus_chg_debug_info.cur_ui_soc == oplus_chg_debug_info.cur_soc) {
oplus_chg_unset_soc_notified_flag(OPLUS_NOTIFY_BATT_UI_TO_SOC_CAPCITY_JUMP);
}
if (!oplus_chg_debug_notify_type_is_set(OPLUS_CHG_DEBUG_NOTIFY_TYPE_SOC_JUMP)) {
oplus_chg_debug_info.sleep_tm_sec = 0;
}
}
return 0;
}
int oplus_chg_debug_chg_monitor(struct oplus_chg_chip *chip)
{
int rc = 0;
if (!oplus_chg_debug_info.initialized)
return -1;
if (chip->authenticate) {
oplus_chg_chg_batt_aging_check(chip);
oplus_chg_chg_batt_capacity_jump_check(chip);
oplus_chg_chg_full_check(chip);
}
oplus_chg_chg_slow_check(chip);
oplus_chg_print_debug_info(chip);
return rc;
}
#if 0
static unsigned long long oplus_chg_debug_get_notify_flag(bool reset)
{
unsigned long long flag = 0;
mutex_lock(&oplus_chg_debug_info.nflag_lock);
flag = oplus_chg_debug_info.notify_flag;
if (reset)
{
oplus_chg_debug_info.notify_flag = 0;
}
mutex_unlock(&oplus_chg_debug_info.nflag_lock);
return flag;
}
#endif
static int oplus_chg_debug_notify_flag_is_set(int flag)
{
int ret = 0;
mutex_lock(&oplus_chg_debug_info.nflag_lock);
if (oplus_chg_debug_info.notify_flag & (1 << flag)) {
ret = 1;
}
mutex_unlock(&oplus_chg_debug_info.nflag_lock);
return ret;
}
static int oplus_chg_debug_reset_notify_flag(void)
{
mutex_lock(&oplus_chg_debug_info.nflag_lock);
oplus_chg_debug_info.notify_flag = 0;
mutex_unlock(&oplus_chg_debug_info.nflag_lock);
return 0;
}
static int oplus_chg_debug_info_parse_dt(void)
{
struct oplus_vooc_chip *vooc_chip = NULL;
struct device_node *vooc_node = NULL;
struct device_node *node, *child;
int ret;
int i, j, k;
int count;
int size;
u32 val[2];
char *vooc_adpater_name[] = {
"vooc_charge_strategy_20w",
"vooc_charge_strategy_30w",
"vooc_charge_strategy_50w",
"vooc_charge_strategy_65w"
};
oplus_vooc_get_vooc_chip_handle(&vooc_chip);
if (vooc_chip == NULL)
return 0;
vooc_node = vooc_chip->dev->of_node;
if (!vooc_node)
return 0;
ret = of_property_read_u32(vooc_node, "qcom,vooc-max-input-volt-support", &oplus_chg_debug_info.vooc_max_input_volt);
if (ret) {
oplus_chg_debug_info.vooc_max_input_volt = 5000;
}
ret = of_property_read_u32(vooc_node, "qcom,vooc-max-input-current-support", &oplus_chg_debug_info.vooc_max_input_current);
if (ret) {
oplus_chg_debug_info.vooc_max_input_current = 4000;
}
for(i = 0; i < OPLUS_FASTCHG_OUTPUT_POWER_MAX; i++) {
node = of_find_node_by_name(vooc_node, vooc_adpater_name[i]);
if (!node)
continue;
count = 0;
for_each_child_of_node(node, child)
count++;
if (!count)
continue;
g_vooc_charge_strategy_p[i] = kzalloc((count + 1) * sizeof(struct vooc_charge_strategy), GFP_KERNEL);
j = 0;
for_each_child_of_node(node, child)
{
ret = of_property_read_u32_array(child, "capacity_range", val, 2);
if (!ret) {
g_vooc_charge_strategy_p[i][j].capacity_range.low = val[0];
g_vooc_charge_strategy_p[i][j].capacity_range.high = val[1];
}
ret = of_property_read_u32_array(child, "temp_range", val, 2);
if (!ret) {
g_vooc_charge_strategy_p[i][j].temp_range.low = val[0];
g_vooc_charge_strategy_p[i][j].temp_range.high = val[1];
}
size = of_property_count_elems_of_size(child, "input_current", sizeof(u32));
if (size >= 0) {
for(k = 0; (k < (size / 3)) && (k < OPLUS_CHG_VOOC_INPUT_CURRENT_MAX_CNT); k++)
{
ret = of_property_read_u32_index(child, "input_current", 3 * k, &val[0]);
if (!ret) {
g_vooc_charge_strategy_p[i][j].input_current[k].cur = val[0];
}
ret = of_property_read_u32_index(child, "input_current", 3 * k + 1, &val[0]);
if (!ret) {
g_vooc_charge_strategy_p[i][j].input_current[k].vol = val[0];
}
ret = of_property_read_u32_index(child, "input_current", 3 * k + 2, &val[0]);
if (!ret) {
g_vooc_charge_strategy_p[i][j].input_current[k].time = val[0];
}
}
}
j++;
}
g_vooc_charge_strategy_p[i][count].capacity_range.low = -1;
g_vooc_charge_strategy_p[i][count].capacity_range.high = -1;
}
return 0;
}
#ifdef OPLUS_CHG_DEBUG_TEST
static ssize_t charge_monitor_test_write(struct file *filp,
const char __user *buf, size_t len, loff_t *data)
{
char tmp_buf[32] = {0};
int str_len;
str_len = len;
if (str_len >= sizeof(tmp_buf))
str_len = sizeof(tmp_buf) - 1;
if (copy_from_user(tmp_buf, buf, str_len))
{
chg_err("copy_from_user failed.\n");
return -EFAULT;
}
chg_err("%s\n", tmp_buf);
if (!strncmp(tmp_buf, "soc:", strlen("soc:"))) {
sscanf(tmp_buf, "soc:%d", &fake_soc);
}
else if (!strncmp(tmp_buf, "ui_soc:", strlen("ui_soc:"))) {
sscanf(tmp_buf, "ui_soc:%d", &fake_ui_soc);
}
else if (!strncmp(tmp_buf, "aging_cap:", strlen("aging_cap:"))) {
sscanf(tmp_buf, "aging_cap:%d", &aging_cap_test);
}
return len;
}
static ssize_t charge_monitor_test_read(struct file *filp,
char __user *buff, size_t count, loff_t *off)
{
int len = 0;
char buf[512] = {0};
sprintf(buf, "fake_soc:%d, fake_ui_soc:%d, aging_cap_test:%d\n",
fake_soc, fake_ui_soc, aging_cap_test);
len = strlen(buf);
if (len > *off)
len -= *off;
else
len = 0;
if (copy_to_user(buff, buf, (len < count ? len : count))) {
return -EFAULT;
}
*off += len < count ? len : count;
return (len < count ? len : count);
}
static const struct file_operations charge_monitor_test_fops = {
.write = charge_monitor_test_write,
.read = charge_monitor_test_read,
};
static int charge_monitor_test_init(void)
{
struct proc_dir_entry *proc_dentry = NULL;
proc_dentry = proc_create("charge_monitor_test", 0664, NULL,
&charge_monitor_test_fops);
if (!proc_dentry) {
pr_err("proc_create charge_monitor_test fops fail!\n");
return -1;
}
return 0;
}
#endif
static int oplus_chg_debug_info_reset(void)
{
int i;
chg_err("enter\n");
#if 1
for(i = OPLUS_NOTIFY_CHG_SLOW_NON_OPLUS_CHARGER; i <= OPLUS_NOTIFY_CHG_SLOW_CHECK_TIME; i++)
{
oplus_chg_debug_info.chg_cnt[i] = 0;
}
#else
memset(oplus_chg_debug_info.chg_cnt, 0x0, sizeof(oplus_chg_debug_info.chg_cnt));
#endif
oplus_chg_debug_info.fast_chg_type = FASTCHG_CHARGER_TYPE_UNKOWN;
oplus_chg_debug_info.fastchg_stop_cnt = 0;
oplus_chg_debug_info.cool_down_by_user = 0;
oplus_chg_debug_info.chg_current_by_cooldown = 0;
oplus_chg_debug_info.chg_current_by_tbatt = 0;
oplus_chg_debug_info.fastchg_input_current = -1;
oplus_chg_debug_info.vooc_charge_strategy = NULL;
oplus_chg_debug_info.vooc_charge_input_current_index = 0;
oplus_chg_debug_info.vooc_charge_cur_state_chg_time = 0;
oplus_chg_debug_info.chg_full_notified_flag = 0;
oplus_chg_debug_reset_notify_flag();
oplus_chg_reset_chg_notify_type();
return 0;
}
int oplus_chg_debug_info_init(void)
{
memset(&oplus_chg_debug_info, 0x0, sizeof(oplus_chg_debug_info));
memset(&oplus_chg_debug_msg[0], 0x0, sizeof(oplus_chg_debug_msg));
mutex_init(&oplus_chg_debug_info.nflag_lock);
oplus_chg_debug_info_reset();
oplus_chg_debug_info.pre_led_state = 1;
oplus_chg_debug_info.pre_soc = OPLUS_CHG_BATT_INVALID_CAPACITY;
oplus_chg_debug_info.cur_soc = OPLUS_CHG_BATT_INVALID_CAPACITY;
oplus_chg_debug_info.pre_ui_soc = OPLUS_CHG_BATT_INVALID_CAPACITY;
oplus_chg_debug_info.cur_ui_soc = OPLUS_CHG_BATT_INVALID_CAPACITY;
oplus_chg_debug_info.usb_psy = power_supply_get_by_name("usb");
oplus_chg_debug_info.batt_psy = power_supply_get_by_name("battery");
oplus_chg_debug_info.oplus_chg_debug_wq = create_workqueue("oplus_chg_debug_wq");
#ifdef CONFIG_OPLUS_KEVENT_UPLOAD
oplus_chg_debug_info.dcs_info = (struct kernel_packet_info *)&oplus_chg_debug_msg[0];
INIT_DELAYED_WORK(&oplus_chg_debug_info.send_info_dwork, oplus_chg_send_info_dwork);
mutex_init(&oplus_chg_debug_info.dcs_info_lock);
#endif
INIT_DELAYED_WORK(&oplus_chg_debug_info.soc_load_dwork, oplus_chg_soc_load_dwork);
oplus_chg_debug_info_parse_dt();
#ifdef OPLUS_CHG_DEBUG_TEST
{
int ret;
ret = charge_monitor_test_init();
if (ret < 0)
return ret;
}
#endif
oplus_chg_debug_info.initialized = 1;
return 0;
}