714 lines
22 KiB
C
714 lines
22 KiB
C
#include "timer.h"
|
||
#include "asm/charge.h"
|
||
#include "gpadc.h"
|
||
#include "uart.h"
|
||
#include "device/device.h"
|
||
#include "asm/power_interface.h"
|
||
#include "system/event.h"
|
||
#include "asm/efuse.h"
|
||
#include "gpio.h"
|
||
#include "clock.h"
|
||
#include "app_config.h"
|
||
#include "syscfg_id.h"
|
||
|
||
#define LOG_TAG_CONST CHARGE
|
||
#define LOG_TAG "[CHARGE]"
|
||
#define LOG_INFO_ENABLE
|
||
#define LOG_DUMP_ENABLE
|
||
#define LOG_ERROR_ENABLE
|
||
#define LOG_DEBUG_ENABLE
|
||
#include "debug.h"
|
||
|
||
typedef struct _CHARGE_VAR {
|
||
const struct charge_platform_data *data;
|
||
u8 charge_flag;
|
||
u8 charge_poweron_en;
|
||
u8 cc_flag;
|
||
u8 cc_counter;
|
||
volatile u8 charge_online_flag;
|
||
volatile u8 charge_event_flag;
|
||
volatile u8 init_ok;
|
||
volatile u8 detect_stop;
|
||
volatile u16 full_voltage;
|
||
volatile u16 ldo5v_timer; //检测LDOIN状态变化的usr timer
|
||
volatile u16 charge_timer; //检测充电是否充满的usr timer
|
||
volatile u16 cc_timer; //涓流切恒流的sys timer
|
||
volatile u16 progi_timer; //获取恒流的progi的电压sys_timer
|
||
} CHARGE_VAR;
|
||
|
||
#define __this (&charge_var)
|
||
static CHARGE_VAR charge_var;
|
||
|
||
// PMU结构简述:(NVDC架构)
|
||
// VPWR为充电输入引脚,VBAT为电池接口
|
||
// 充电模块的输入为VIN
|
||
// 正常情况下,(VPWR>VBAT时,VIN=VPWR) (VPWR<VBAT时,VIN=VBAT)
|
||
// >>/<<为电流可能走向
|
||
// VPWR----->>-----VIN--->><<-----CHARGE-->><<----VBAT
|
||
// |
|
||
// |
|
||
// IOVDD
|
||
|
||
/*
|
||
* 充电线性环路1说明,开启后对跟随充更友好,将会限制 VIN>VBAT+100mV(@SLT=0)
|
||
* 例如:
|
||
* VPWR外部供电5V限流50mA,充电模块设置100mA充电,充电开启后VIN电压将被拉低
|
||
* 但是由于线性环路开启,VIN恒定处于VBAT+100mV的电压,此时充电电流为50mA
|
||
*/
|
||
|
||
/*
|
||
* 充电线性环路2说明,开启后将不支持跟随充功能,充电模块输入端VIN电压将限制在不低于4V.
|
||
* 例如:
|
||
* 1、VPWR外部供电5V限流50mA,充电模块设置100mA充电,充电开启后,VIN将被拉低,
|
||
* 当VIN被拉低至4V时,线性环路2将起作用,主动限制充电电流,VIN电压会恒定处于4V;
|
||
*
|
||
* 2、VPWR外部供电5V限流50mA,充电模块设置20mA充电,系统推屏需要从IOVDD耗电40mA,充电推屏开启后,VIN将被拉低
|
||
* 当VIN被拉低至4V时,线性环路2将起作用,将优先满足系统供电需求,主动限制充电电流,VIN电压会恒定处于4V;
|
||
*
|
||
* 3、VPWR外部供电5V限流50mA,电池为3.7V,充电模块设置20mA充电,系统推屏需要从IOVDD耗电80mA;
|
||
* 充电推屏开启后,VIN将被拉低,系统会把VIN的电压扯到低于4V,充电电流会降低至0mA,VIN会继续下降,
|
||
* 一旦下降到低于VBAT电压,电池就会给系统供电,这种模式称为补电模式,在改模式下,VPWR和VBAT同时为系统供电
|
||
*/
|
||
|
||
#define CHARGE_VILOOP1_ENABLE 1//默认开启
|
||
#define CHARGE_VILOOP2_ENABLE TCFG_CHARGE_NVDC_EN//默认关闭
|
||
|
||
//判满时,VBAT的最小电压值
|
||
#define CHARGE_FULL_VBAT_MIN_VOLTAGE (__this->full_voltage - 100)
|
||
//滤波8s进行判满
|
||
#define CHARGE_FULL_FILTER_TIMES 8
|
||
|
||
//涓流切恒流滤波/s
|
||
#define CHARGE_TC2CC_FILTER_TIMES 4
|
||
|
||
#define BIT_LDO5V_IN BIT(0)
|
||
#define BIT_LDO5V_OFF BIT(1)
|
||
#define BIT_LDO5V_KEEP BIT(2)
|
||
|
||
#define GET_PINR_EN() ((P33_CON_GET(P3_PINR_CON1) & BIT(0)) ? 1: 0)
|
||
#define GET_PINR_LEVEL() ((P33_CON_GET(P3_PINR_CON1) & BIT(2)) ? 1: 0)
|
||
#define GET_PINR_PIN() ((P33_CON_GET(P3_PINR_CON1) & BIT(3)) ? 1: 0)
|
||
|
||
static u16 constant_current_progi_volt;
|
||
static u8 bat_type;
|
||
static void charge_full_detect(void *priv);
|
||
extern void charge_event_to_user(u8 event);
|
||
|
||
u8 check_pinr_shutdown_enable(void)
|
||
{
|
||
log_info("pinr lvl %d, ldo5v det %d", GET_PINR_LEVEL(), LDO5V_DET_GET());
|
||
if (GET_PINR_EN() && (GET_PINR_LEVEL() == LDO5V_DET_GET()) && !GET_PINR_PIN()) {
|
||
return 0;
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
u8 get_charge_poweron_en(void)
|
||
{
|
||
return __this->charge_poweron_en;
|
||
}
|
||
|
||
void set_charge_poweron_en(u32 onOff)
|
||
{
|
||
__this->charge_poweron_en = onOff;
|
||
}
|
||
|
||
void charge_check_and_set_pinr(u8 level)
|
||
{
|
||
u8 reg;
|
||
reg = P33_CON_GET(P3_PINR_CON1);
|
||
//开启LDO5V_DET长按复位
|
||
if ((reg & BIT(0)) && ((reg & BIT(3)) == 0)) {
|
||
if (level == 0) {
|
||
P33_CON_SET(P3_PINR_CON1, 2, 1, 0);
|
||
} else {
|
||
P33_CON_SET(P3_PINR_CON1, 2, 1, 1);
|
||
}
|
||
}
|
||
}
|
||
|
||
extern void udelay(u32 usec);
|
||
static u8 check_charge_state(void)
|
||
{
|
||
u16 i;
|
||
__this->charge_online_flag = 0;
|
||
|
||
for (i = 0; i < 20; i++) {
|
||
if (LVCMP_DET_GET() || LDO5V_DET_GET()) {
|
||
__this->charge_online_flag = 1;
|
||
break;
|
||
}
|
||
udelay(1000);
|
||
}
|
||
return __this->charge_online_flag;
|
||
}
|
||
|
||
void set_charge_online_flag(u8 flag)
|
||
{
|
||
__this->charge_online_flag = flag;
|
||
}
|
||
|
||
u8 get_charge_online_flag(void)
|
||
{
|
||
return __this->charge_online_flag;
|
||
}
|
||
|
||
void set_charge_event_flag(u8 flag)
|
||
{
|
||
__this->charge_event_flag = flag;
|
||
}
|
||
|
||
u8 get_ldo5v_online_hw(void)
|
||
{
|
||
return LDO5V_DET_GET();
|
||
}
|
||
|
||
u8 get_lvcmp_det(void)
|
||
{
|
||
return LVCMP_DET_GET();
|
||
}
|
||
|
||
u8 get_ldo5v_pulldown_en(void)
|
||
{
|
||
if (!__this->data) {
|
||
return 0;
|
||
}
|
||
if (get_ldo5v_online_hw()) {
|
||
if (__this->data->ldo5v_pulldown_keep == 0) {
|
||
return 0;
|
||
}
|
||
}
|
||
return __this->data->ldo5v_pulldown_en;
|
||
}
|
||
|
||
u8 get_ldo5v_pulldown_res(void)
|
||
{
|
||
if (__this->data) {
|
||
return __this->data->ldo5v_pulldown_lvl;
|
||
}
|
||
return CHARGE_PULLDOWN_200K;
|
||
}
|
||
static const u16 volt_difference[16] = {
|
||
224, 261, 288, 320,
|
||
360, 383, 437, 496,
|
||
543, 587, 603, 643,
|
||
702, 755, 819, 898,
|
||
};
|
||
|
||
//更新progi口的电压用来判断满电电流
|
||
static void constant_current_progi_volt_config(void *priv)
|
||
{
|
||
u16 cur_vbat, cur_vpwr;
|
||
static u32 progi_volt = 0;
|
||
static u8 get_progi_volt_cnt = 0;
|
||
static u8 unit_cnt = 0;
|
||
|
||
if (syscfg_read(VM_CHARGE_PROGI_VOLT, &constant_current_progi_volt, 2) != 2) {
|
||
constant_current_progi_volt = 1200;
|
||
} else {
|
||
if (__this->progi_timer) {
|
||
sys_timer_del(__this->progi_timer);
|
||
log_info("constant_current_progi_volt 1:%d\n", constant_current_progi_volt);
|
||
__this->progi_timer = 0;
|
||
}
|
||
return;
|
||
}
|
||
|
||
cur_vbat = adc_get_voltage(AD_CH_PMU_VBAT) * AD_CH_PMU_VBAT_DIV;
|
||
cur_vpwr = adc_get_voltage(ADC_CH_PMU_VPWR_4) * 4;
|
||
|
||
//判断VPWR-VBAT的电压大于恒流的压差 && vbat的电压小于4.2,4.4,4.5V类型电池3.8V,4.0v,4.1v获取恒流progi口的电压。
|
||
if ((cur_vpwr - cur_vbat > (volt_difference[__this->data->charge_mA] + 50))) {
|
||
if (((cur_vbat < 3800) && (bat_type == BAT_4P2)) || ((cur_vbat < 4000) && (bat_type == BAT_4P4)) || ((cur_vbat < 4100) && (bat_type == BAT_4P5))) {
|
||
//更新最大的电压值
|
||
progi_volt += adc_get_voltage(AD_CH_PMU_PROGI);
|
||
get_progi_volt_cnt++;
|
||
}
|
||
}
|
||
unit_cnt++;
|
||
if (unit_cnt < 6) {
|
||
return;
|
||
}
|
||
//更新constant_current_progi_volt
|
||
if (get_progi_volt_cnt > 3) {
|
||
progi_volt = progi_volt / get_progi_volt_cnt;
|
||
if ((progi_volt >= 950) && (progi_volt <= 1450)) {
|
||
constant_current_progi_volt = progi_volt;
|
||
syscfg_write(VM_CHARGE_PROGI_VOLT, &constant_current_progi_volt, 2);
|
||
}
|
||
}
|
||
get_progi_volt_cnt = 0;
|
||
unit_cnt = 0;
|
||
progi_volt = 0;
|
||
if (__this->progi_timer) {
|
||
sys_timer_del(__this->progi_timer);
|
||
__this->progi_timer = 0;
|
||
log_info("constant_current_progi_volt 2:%d\n", constant_current_progi_volt);
|
||
}
|
||
}
|
||
|
||
static void charge_cc_check(void *priv)
|
||
{
|
||
u8 first_entry = (u8)priv;
|
||
if ((adc_get_voltage_blocking(AD_CH_PMU_VBAT) * AD_CH_PMU_VBAT_DIV / 10) > CHARGE_CCVOL_V) {
|
||
if (__this->cc_flag == 0) {
|
||
__this->cc_counter++;
|
||
}
|
||
if (first_entry || ((__this->cc_flag == 0) && (__this->cc_counter > CHARGE_TC2CC_FILTER_TIMES))) {
|
||
__this->cc_flag = 1;
|
||
set_charge_mA(__this->data->charge_mA);
|
||
if (__this->charge_timer == 0) {
|
||
__this->charge_timer = sys_timer_add(NULL, charge_full_detect, 1000);
|
||
}
|
||
if (__this->progi_timer == 0) {
|
||
__this->progi_timer = sys_timer_add(NULL, constant_current_progi_volt_config, 100);
|
||
}
|
||
}
|
||
} else {
|
||
__this->cc_counter = 0;
|
||
if (first_entry || (__this->cc_flag == 1)) {
|
||
__this->cc_flag = 0;
|
||
set_charge_mA(__this->data->charge_trickle_mA);
|
||
if (__this->charge_timer) {
|
||
sys_timer_del(__this->charge_timer);
|
||
__this->charge_timer = 0;
|
||
}
|
||
if (__this->progi_timer) {
|
||
sys_timer_del(__this->progi_timer);
|
||
__this->progi_timer = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
//TC2CC or CC2TC check
|
||
if (first_entry && (__this->cc_timer == 0)) {
|
||
__this->cc_counter = 0;
|
||
__this->cc_timer = usr_timer_add(0, charge_cc_check, 1000, 1);
|
||
}
|
||
}
|
||
|
||
void charge_start(void)
|
||
{
|
||
log_info("%s\n", __func__);
|
||
|
||
if (__this->charge_timer) {
|
||
sys_timer_del(__this->charge_timer);
|
||
__this->charge_timer = 0;
|
||
}
|
||
|
||
charge_cc_check((void *)1);
|
||
|
||
PMU_NVDC_EN(CHARGE_VILOOP2_ENABLE);
|
||
CHG_VILOOP_EN(CHARGE_VILOOP1_ENABLE);
|
||
CHG_VILOOP2_EN(CHARGE_VILOOP2_ENABLE);
|
||
CHARGE_EN(1);
|
||
CHGGO_EN(1);
|
||
|
||
charge_event_to_user(CHARGE_EVENT_CHARGE_START);
|
||
}
|
||
|
||
void charge_close(void)
|
||
{
|
||
log_info("%s\n", __func__);
|
||
|
||
CHARGE_EN(0);
|
||
CHGGO_EN(0);
|
||
CHG_VILOOP_EN(0);
|
||
CHG_VILOOP2_EN(0);
|
||
PMU_NVDC_EN(1);
|
||
charge_event_to_user(CHARGE_EVENT_CHARGE_CLOSE);
|
||
|
||
if (__this->charge_timer) {
|
||
sys_timer_del(__this->charge_timer);
|
||
__this->charge_timer = 0;
|
||
}
|
||
if (__this->cc_timer) {
|
||
usr_timer_del(__this->cc_timer);
|
||
__this->cc_timer = 0;
|
||
}
|
||
if (__this->progi_timer) {
|
||
sys_timer_del(__this->progi_timer);
|
||
__this->progi_timer = 0;
|
||
}
|
||
}
|
||
static const u16 constant_current[16] = {
|
||
40, 50, 60, 70,
|
||
80, 100, 120, 140,
|
||
160, 180, 200, 220,
|
||
240, 260, 280, 300,
|
||
};
|
||
|
||
static void charge_full_detect(void *priv)
|
||
{
|
||
static u16 charge_full_cnt = 0;
|
||
u16 vbat_vol, cur_charge_current;
|
||
|
||
//没有初始化成功或者5v不在线
|
||
if ((!__this->init_ok) || (!LVCMP_DET_GET())) {
|
||
charge_full_cnt = 0;
|
||
log_debug("no init or vpwr not 5v online : %d %d\n", __this->init_ok, LVCMP_DET_GET());
|
||
return;
|
||
}
|
||
|
||
vbat_vol = adc_get_voltage(AD_CH_PMU_VBAT) * AD_CH_PMU_VBAT_DIV;
|
||
if (vbat_vol < CHARGE_FULL_VBAT_MIN_VOLTAGE) {
|
||
charge_full_cnt = 0;
|
||
log_debug("vbat voltage not enough: %d < %d\n", vbat_vol, CHARGE_FULL_VBAT_MIN_VOLTAGE);
|
||
return;
|
||
}
|
||
//获取充电电流
|
||
cur_charge_current = (adc_get_voltage(AD_CH_PMU_PROGI) * constant_current[__this->data->charge_mA]) / constant_current_progi_volt;
|
||
log_debug("cur_charge_current:%d\n", cur_charge_current);
|
||
//获取的电流小于满电电流进行判满操作
|
||
if (cur_charge_current < __this->data->charge_full_mA) {
|
||
charge_full_cnt++;
|
||
if (charge_full_cnt > CHARGE_FULL_FILTER_TIMES) {
|
||
charge_full_cnt = 0;
|
||
charge_event_to_user(CHARGE_EVENT_CHARGE_FULL);
|
||
if (__this->charge_timer) {
|
||
sys_timer_del(__this->charge_timer);
|
||
__this->charge_timer = 0;
|
||
}
|
||
}
|
||
} else {
|
||
charge_full_cnt = 0;
|
||
}
|
||
}
|
||
|
||
static void ldo5v_detect(void *priv)
|
||
{
|
||
static u16 ldo5v_on_cnt = 0;
|
||
static u16 ldo5v_keep_cnt = 0;
|
||
static u16 ldo5v_off_cnt = 0;
|
||
|
||
if (__this->detect_stop) {
|
||
return;
|
||
}
|
||
|
||
if (LVCMP_DET_GET()) { //ldoin > vbat
|
||
log_char('X');
|
||
if (ldo5v_on_cnt < __this->data->ldo5v_on_filter) {
|
||
ldo5v_on_cnt++;
|
||
if (ldo5v_off_cnt >= (__this->data->ldo5v_off_filter + 4)) {
|
||
ldo5v_off_cnt = __this->data->ldo5v_off_filter + 4;
|
||
}
|
||
if (__this->data->ldo5v_keep_filter <= 16) {
|
||
ldo5v_keep_cnt = 0;
|
||
} else if (ldo5v_keep_cnt >= (__this->data->ldo5v_keep_filter - 16)) {
|
||
ldo5v_keep_cnt = __this->data->ldo5v_keep_filter - 16;
|
||
}
|
||
} else {
|
||
log_debug("ldo5V_IN\n");
|
||
set_charge_online_flag(1);
|
||
ldo5v_off_cnt = 0;
|
||
ldo5v_keep_cnt = 0;
|
||
//消息线程未准备好接收消息,继续扫描
|
||
if (__this->charge_event_flag == 0) {
|
||
return;
|
||
}
|
||
ldo5v_on_cnt = 0;
|
||
usr_timer_del(__this->ldo5v_timer);
|
||
__this->ldo5v_timer = 0;
|
||
if ((__this->charge_flag & BIT_LDO5V_IN) == 0) {
|
||
__this->charge_flag = BIT_LDO5V_IN;
|
||
charge_event_to_user(CHARGE_EVENT_LDO5V_IN);
|
||
}
|
||
}
|
||
} else if (LDO5V_DET_GET() == 0) { //ldoin<拔出电压(0.6)
|
||
log_char('Q');
|
||
if (ldo5v_off_cnt < (__this->data->ldo5v_off_filter + 20)) {
|
||
ldo5v_off_cnt++;
|
||
if (__this->data->ldo5v_on_filter <= 16) {
|
||
ldo5v_on_cnt = 0;
|
||
} else if (ldo5v_on_cnt >= (__this->data->ldo5v_on_filter - 16)) {
|
||
ldo5v_on_cnt = __this->data->ldo5v_on_filter - 16;
|
||
}
|
||
if (__this->data->ldo5v_keep_filter <= 16) {
|
||
ldo5v_keep_cnt = 0;
|
||
} else if (ldo5v_keep_cnt >= (__this->data->ldo5v_keep_filter - 16)) {
|
||
ldo5v_keep_cnt = __this->data->ldo5v_keep_filter - 16;
|
||
}
|
||
} else {
|
||
log_debug("ldo5V_OFF\n");
|
||
set_charge_online_flag(0);
|
||
ldo5v_on_cnt = 0;
|
||
ldo5v_keep_cnt = 0;
|
||
//消息线程未准备好接收消息,继续扫描
|
||
if (__this->charge_event_flag == 0) {
|
||
return;
|
||
}
|
||
ldo5v_off_cnt = 0;
|
||
usr_timer_del(__this->ldo5v_timer);
|
||
__this->ldo5v_timer = 0;
|
||
if ((__this->charge_flag & BIT_LDO5V_OFF) == 0) {
|
||
__this->charge_flag = BIT_LDO5V_OFF;
|
||
charge_event_to_user(CHARGE_EVENT_LDO5V_OFF);
|
||
}
|
||
}
|
||
} else { //拔出电压(0.6左右)< ldoin < vbat
|
||
log_char('E');
|
||
if (ldo5v_keep_cnt < __this->data->ldo5v_keep_filter) {
|
||
ldo5v_keep_cnt++;
|
||
if (ldo5v_off_cnt >= (__this->data->ldo5v_off_filter + 4)) {
|
||
ldo5v_off_cnt = __this->data->ldo5v_off_filter + 4;
|
||
}
|
||
if (__this->data->ldo5v_on_filter <= 16) {
|
||
ldo5v_on_cnt = 0;
|
||
} else if (ldo5v_on_cnt >= (__this->data->ldo5v_on_filter - 16)) {
|
||
ldo5v_on_cnt = __this->data->ldo5v_on_filter - 16;
|
||
}
|
||
} else {
|
||
log_debug("ldo5V_ERR\n");
|
||
set_charge_online_flag(1);
|
||
ldo5v_off_cnt = 0;
|
||
ldo5v_on_cnt = 0;
|
||
//消息线程未准备好接收消息,继续扫描
|
||
if (__this->charge_event_flag == 0) {
|
||
return;
|
||
}
|
||
ldo5v_keep_cnt = 0;
|
||
usr_timer_del(__this->ldo5v_timer);
|
||
__this->ldo5v_timer = 0;
|
||
if ((__this->charge_flag & BIT_LDO5V_KEEP) == 0) {
|
||
__this->charge_flag = BIT_LDO5V_KEEP;
|
||
if (__this->data->ldo5v_off_filter) {
|
||
charge_event_to_user(CHARGE_EVENT_LDO5V_KEEP);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void ldoin_wakeup_isr(void)
|
||
{
|
||
if (!__this->init_ok) {
|
||
return;
|
||
}
|
||
if (__this->ldo5v_timer == 0) {
|
||
__this->ldo5v_timer = usr_timer_add(0, ldo5v_detect, 2, 1);
|
||
}
|
||
}
|
||
|
||
void charge_set_ldo5v_detect_stop(u8 stop)
|
||
{
|
||
__this->detect_stop = stop;
|
||
}
|
||
|
||
u8 get_charge_mA_config(void)
|
||
{
|
||
return __this->data->charge_mA;
|
||
}
|
||
|
||
void set_charge_mA(u8 charge_mA)
|
||
{
|
||
static u8 charge_mA_old = 0xff;
|
||
if (charge_mA_old != charge_mA) {
|
||
charge_mA_old = charge_mA;
|
||
if (charge_mA & BIT(4)) {
|
||
CHG_TRICKLE_EN(1);
|
||
} else {
|
||
CHG_TRICKLE_EN(0);
|
||
}
|
||
CHARGE_mA_SEL(charge_mA & 0x0f);
|
||
}
|
||
}
|
||
|
||
u16 get_charge_full_value(void)
|
||
{
|
||
ASSERT(__this->init_ok, "charge not init ok!\n");
|
||
ASSERT(__this->data->charge_full_V < CHARGE_FULL_V_MAX);
|
||
return __this->full_voltage;
|
||
}
|
||
|
||
static void charge_config(void)
|
||
{
|
||
u8 charge_trim_val;
|
||
u8 offset = 0;
|
||
u8 charge_full_v_val = 0;
|
||
u8 charge_curr_trim;
|
||
//判断是用4.2V 4.4V 4.5V的电池
|
||
if (__this->data->charge_full_V < CHARGE_FULL_V_4240_4P4V) {
|
||
CHG_HV_MODE(0);
|
||
PMU_MFIXI_SET_1(0);
|
||
bat_type = BAT_4P2;
|
||
charge_trim_val = efuse_get_vbat_trim_4p2();//4.20V对应的trim出来的实际档位
|
||
log_info("vbat 4p2v charge_trim_val = %d\n", charge_trim_val);
|
||
if (__this->data->charge_full_V >= CHARGE_FULL_V_4200_4P2V) {
|
||
offset = __this->data->charge_full_V - CHARGE_FULL_V_4200_4P2V;
|
||
charge_full_v_val = charge_trim_val + offset;
|
||
if (charge_full_v_val > 0xf) {
|
||
charge_full_v_val = 0xf;
|
||
}
|
||
__this->full_voltage = 4200 + (charge_full_v_val - charge_trim_val) * 20;
|
||
} else {
|
||
offset = CHARGE_FULL_V_4200_4P2V - __this->data->charge_full_V;
|
||
if (charge_trim_val >= offset) {
|
||
charge_full_v_val = charge_trim_val - offset;
|
||
} else {
|
||
charge_full_v_val = 0;
|
||
}
|
||
__this->full_voltage = 4200 - (charge_trim_val - charge_full_v_val) * 20;
|
||
}
|
||
} else if (__this->data->charge_full_V < CHARGE_FULL_V_4340_4P5V) {
|
||
CHG_HV_MODE(1);
|
||
PMU_MFIXI_SET_1(0);
|
||
bat_type = BAT_4P4;
|
||
charge_trim_val = efuse_get_vbat_trim_4p4();//4.35V对应的trim出来的实际档位
|
||
log_info("4p4v charge_trim_val = %d\n", charge_trim_val);
|
||
if (__this->data->charge_full_V >= CHARGE_FULL_V_4400_4P4V) {
|
||
offset = __this->data->charge_full_V - CHARGE_FULL_V_4400_4P4V;
|
||
charge_full_v_val = charge_trim_val + offset;
|
||
if (charge_full_v_val > 0xf) {
|
||
charge_full_v_val = 0xf;
|
||
}
|
||
__this->full_voltage = 4400 + (charge_full_v_val - charge_trim_val) * 20;
|
||
} else {
|
||
offset = CHARGE_FULL_V_4400_4P4V - __this->data->charge_full_V;
|
||
if (charge_trim_val >= offset) {
|
||
charge_full_v_val = charge_trim_val - offset;
|
||
} else {
|
||
charge_full_v_val = 0;
|
||
}
|
||
__this->full_voltage = 4400 - (charge_trim_val - charge_full_v_val) * 20;
|
||
}
|
||
} else {
|
||
CHG_HV_MODE(1);
|
||
PMU_MFIXI_SET_1(1);
|
||
bat_type = BAT_4P5;
|
||
charge_trim_val = efuse_get_vbat_trim_4p5();//4.35V对应的trim出来的实际档位
|
||
log_info("4p5v charge_trim_val = %d\n", charge_trim_val);
|
||
if (__this->data->charge_full_V >= CHARGE_FULL_V_4500_4P5V) {
|
||
offset = __this->data->charge_full_V - CHARGE_FULL_V_4500_4P5V;
|
||
charge_full_v_val = charge_trim_val + offset;
|
||
if (charge_full_v_val > 0xf) {
|
||
charge_full_v_val = 0xf;
|
||
}
|
||
__this->full_voltage = 4500 + (charge_full_v_val - charge_trim_val) * 20;
|
||
} else {
|
||
offset = CHARGE_FULL_V_4500_4P5V - __this->data->charge_full_V;
|
||
if (charge_trim_val >= offset) {
|
||
charge_full_v_val = charge_trim_val - offset;
|
||
} else {
|
||
charge_full_v_val = 0;
|
||
}
|
||
__this->full_voltage = 4500 - (charge_trim_val - charge_full_v_val) * 20;
|
||
}
|
||
}
|
||
log_info("charge_full_v_val = %d\n", charge_full_v_val);
|
||
log_info("charge_full_voltage = %d mV\n", __this->full_voltage);
|
||
|
||
//电流校准
|
||
charge_curr_trim = efuse_get_charge_cur_trim();
|
||
log_info("charge curr set value = %d\n", charge_curr_trim);
|
||
|
||
CHGI_TRIM_SEL(charge_curr_trim);
|
||
CHARGE_FULL_V_SEL(charge_full_v_val);
|
||
set_charge_mA(__this->data->charge_trickle_mA);
|
||
}
|
||
|
||
int charge_init(const struct charge_platform_data *data)
|
||
{
|
||
log_info("%s\n", __func__);
|
||
|
||
__this->data = data;
|
||
|
||
ASSERT(__this->data);
|
||
|
||
__this->init_ok = 0;
|
||
__this->charge_online_flag = 0;
|
||
__this->charge_poweron_en = data->charge_poweron_en;
|
||
|
||
CHARGE_EN(0);
|
||
CHGGO_EN(0);
|
||
CHG_CCLOOP_EN(1);
|
||
CHG_VILOOP_EN(0);
|
||
CHG_VILOOP2_EN(0);
|
||
PMU_NVDC_EN(1);
|
||
L5V_IO_MODE(0);
|
||
//消除vbat到vpwr的漏电再判断ldo5v状态
|
||
u8 temp = 10;
|
||
if (is_reset_source(P33_VDDIO_POR_RST)) {
|
||
gpio_set_mode(IO_PORT_SPILT(IO_PORTP_00), PORT_INPUT_PULLDOWN_10K);
|
||
while (temp) {
|
||
udelay(1000);
|
||
if (LDO5V_DET_GET() == 0) {
|
||
temp = 0;
|
||
} else {
|
||
temp--;
|
||
}
|
||
}
|
||
gpio_set_mode(IO_PORT_SPILT(IO_PORTP_00), PORT_INPUT_FLOATING);
|
||
}
|
||
/*LDO5V的100K下拉电阻使能*/
|
||
L5V_RES_DET_S_SEL(__this->data->ldo5v_pulldown_lvl);
|
||
L5V_LOAD_EN(__this->data->ldo5v_pulldown_en);
|
||
|
||
charge_config();
|
||
|
||
adc_add_sample_ch(AD_CH_PMU_VPWR_4);
|
||
adc_add_sample_ch(AD_CH_PMU_PROGI);
|
||
|
||
if (check_charge_state()) {
|
||
if (__this->ldo5v_timer == 0) {
|
||
__this->ldo5v_timer = usr_timer_add(0, ldo5v_detect, 2, 1);
|
||
}
|
||
} else {
|
||
__this->charge_flag = BIT_LDO5V_OFF;
|
||
}
|
||
|
||
__this->init_ok = 1;
|
||
return 0;
|
||
}
|
||
|
||
void charge_module_stop(void)
|
||
{
|
||
if (!__this->init_ok) {
|
||
return;
|
||
}
|
||
charge_close();
|
||
p33_io_wakeup_enable(IO_LDOIN_DET, 0);
|
||
p33_io_wakeup_enable(IO_VBTCH_DET, 0);
|
||
if (__this->ldo5v_timer) {
|
||
usr_timer_del(__this->ldo5v_timer);
|
||
__this->ldo5v_timer = 0;
|
||
}
|
||
}
|
||
|
||
void charge_module_restart(void)
|
||
{
|
||
if (!__this->init_ok) {
|
||
return;
|
||
}
|
||
if (!__this->ldo5v_timer) {
|
||
__this->ldo5v_timer = usr_timer_add(NULL, ldo5v_detect, 2, 1);
|
||
}
|
||
p33_io_wakeup_enable(IO_LDOIN_DET, 1);
|
||
p33_io_wakeup_enable(IO_VBTCH_DET, 1);
|
||
}
|
||
|
||
//系统进入低功耗时会调用
|
||
void charge_enter_lowpower(enum LOW_POWER_LEVEL lp_mode)
|
||
{
|
||
if (lp_mode == LOW_POWER_MODE_SOFF) {
|
||
CHARGE_EN(0);
|
||
CHGGO_EN(0);
|
||
PMU_NVDC_EN(0);
|
||
CHG_CCLOOP_EN(0);
|
||
CHG_VILOOP_EN(0);
|
||
CHG_VILOOP2_EN(0);
|
||
L5V_LOAD_EN(get_ldo5v_pulldown_en());
|
||
L5V_RES_DET_S_SEL(get_ldo5v_pulldown_res());
|
||
}
|
||
}
|
||
#if defined TCFG_CHANEG_DONT_ENTER_LOW_POWER &&TCFG_CHANEG_DONT_ENTER_LOW_POWER
|
||
static u8 charge_idle_query(void)
|
||
{
|
||
return !__this->charge_online_flag;
|
||
}
|
||
REGISTER_LP_TARGET(charge_lp_target) = {
|
||
.name = "charge",
|
||
.is_idle = charge_idle_query,
|
||
};
|
||
#endif//TCFG_CHANEG_DONT_ENTER_LOW_POWER
|
||
|