This commit is contained in:
huxi
2025-12-03 11:12:34 +08:00
parent c23ae4f24c
commit bc195654bf
8163 changed files with 3799544 additions and 92 deletions
+713
View File
@@ -0,0 +1,713 @@
#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
+95
View File
@@ -0,0 +1,95 @@
#include "app_config.h"
#include "cpu/includes.h"
#include "asm/charge.h"
#include "system/init.h"
#include "asm/power_interface.h"
#include "gpio.h"
#if TCFG_CHARGE_ENABLE
static void vpwr_wakeup_callback(P33_IO_WKUP_EDGE edge)
{
ldoin_wakeup_isr();
}
static const struct _p33_io_wakeup_config vbat_port = {
.edge = BOTH_EDGE, //唤醒方式选择,可选:上升沿\下降沿\双边沿
.filter = PORT_FLT_16ms,
.gpio = IO_VBTCH_DET, //唤醒口选择
.callback = vpwr_wakeup_callback,
};
static const struct _p33_io_wakeup_config ldoin_port = {
.edge = BOTH_EDGE, //唤醒方式选择,可选:上升沿\下降沿\双边沿
.filter = PORT_FLT_16ms,
.gpio = IO_LDOIN_DET, //唤醒口选择
.callback = vpwr_wakeup_callback,
};
void charge_wakeup_init()
{
p33_io_wakeup_port_init(&vbat_port);
p33_io_wakeup_enable(IO_VBTCH_DET, 1);
p33_io_wakeup_port_init(&ldoin_port);
p33_io_wakeup_enable(IO_LDOIN_DET, 1);
}
static const struct charge_platform_data charge_data = {
.charge_en = TCFG_CHARGE_ENABLE, //内置充电使能
.charge_poweron_en = TCFG_CHARGE_POWERON_ENABLE, //是否支持充电开机
.charge_full_V = TCFG_CHARGE_FULL_V, //充电截止电压
.charge_full_mA = TCFG_CHARGE_FULL_MA, //充电截止电流
.charge_mA = TCFG_CHARGE_MA, //充电电流
.charge_trickle_mA = TCFG_CHARGE_TRICKLE_MA, //涓流电流
/* ldo5v拔出过滤值,过滤时间 = (filter*2 + 20)ms,
* ldoin < 0.6V且时间大于过滤时间才认为拔出
* 对于充满直接从5V掉到0V的充电仓,该值必须设置成0
* 对于充满由5V先掉到0V之后再升压到xV的 充电仓,需要根据实际情况设置该值大小
* */
.ldo5v_off_filter = TCFG_LDOIN_OFF_FILTER_TIME / 2,
.ldo5v_on_filter = TCFG_LDOIN_ON_FILTER_TIME / 2,
.ldo5v_keep_filter = TCFG_LDOIN_KEEP_FILTER_TIME / 2,
.ldo5v_pulldown_lvl = TCFG_LDOIN_PULLDOWN_LEV,
.ldo5v_pulldown_keep = TCFG_LDOIN_PULLDOWN_KEEP,
/*
* 1. 对于自动升压充电舱,若充电舱需要更大的负载才能检测到插入时,请将该变量置1
并且根据需求配置下拉电阻档位
* 2. 对于按键升压,并且是通过上拉电阻去提供维持电压的舱,请将该变量设置1,
并且根据舱的上拉配置下拉需要的电阻挡位
* 3. 对于常5V的舱,可将改变量设为0,省功耗
*/
.ldo5v_pulldown_en = TCFG_LDOIN_PULLDOWN_EN,
};
int board_charge_init()
{
charge_wakeup_init();
charge_init(&charge_data);
if (get_charge_online_flag()) {
power_set_mode(PWR_LDO15);
} else {
power_set_mode(TCFG_LOWPOWER_POWER_SEL);
}
return 0;
}
platform_initcall(board_charge_init);
#else
//没开启充电时,关闭漏电寄存器(约2uA)
int board_charge_init()
{
CHG_VILOOP_EN(0);
CHG_VILOOP2_EN(0);
return 0;
}
platform_initcall(board_charge_init);
#endif
+168
View File
@@ -0,0 +1,168 @@
#include "board_config.h"
#include "includes.h"
#include "app_config.h"
#include "chargebox.h"
#include "clock.h"
#include "uart.h"
#include "asm/gpio_hw.h"
#if (TCFG_CHARGE_BOX_ENABLE)
#define BUF_LEN (64)
struct chargebox_handle {
const struct chargebox_platform_data *data;
s32 udev;
volatile u8 lr_flag;
volatile u8 rx_index;
};
static u8 chg_uart_buf[BUF_LEN] __attribute__((aligned(4)));
static u8 chg_uart_dma_buf[BUF_LEN] __attribute__((aligned(4)));
#define __this (&hdl)
static struct chargebox_handle hdl;
extern void chargebox_data_deal(u8 cmd, u8 l_r, u8 *data, u8 length);
void __attribute__((weak)) chargebox_data_deal(u8 cmd, u8 l_r, u8 *data, u8 len)
{
}
static void chargebox_uart_isr_cb(uart_dev uart_num, enum uart_event event)
{
if (event == UART_EVENT_TX_DONE) {
chargebox_data_deal(CMD_COMPLETE, __this->lr_flag, NULL, 0);
} else if (event == UART_EVENT_RX_DATA) {
uart_recv_bytes(__this->udev, &chg_uart_buf[__this->rx_index], 1);
chargebox_data_deal(CMD_RECVBYTE, __this->lr_flag, NULL, 0);
if (chg_uart_buf[0] == 0x55) {
__this->rx_index++;
} else {
return;
}
//耳机发来数据长度为head 2byte + (data len +1) + 校验码 1byte
if ((__this->rx_index > 3) && (__this->rx_index == (chg_uart_buf[2] + 4))) {
chargebox_data_deal(CMD_RECVDATA, __this->lr_flag, chg_uart_buf, __this->rx_index);
__this->rx_index = 0;
}
}
}
u8 chargebox_write(u8 l_r, u8 *data, u8 len)
{
if ((len == 0) || (len > BUF_LEN) || (__this->udev < 0)) {
return 0;
}
__this->lr_flag = l_r;
if (((u32)data) % 4) {//4byte对齐
ASSERT(0, "%s: unaligned accesses!", __func__);
}
memcpy(chg_uart_buf, data, len);
uart_send_bytes(__this->udev, chg_uart_buf, (u32)len);
return len;
}
void chargebox_open(u8 l_r, u8 mode)
{
u32 uart_timeout;
u32 io_port;
s32 ret;
struct uart_config config = {0};
struct uart_dma_config dma = {0};
if (mode == MODE_RECVDATA) {
__this->rx_index = 0;
}
if (__this->udev >= 0) {
return;
}
if (l_r == EAR_L) {
io_port = __this->data->L_port;
} else {
io_port = __this->data->R_port;
}
__this->lr_flag = l_r;
config.baud_rate = __this->data->baudrate;
config.tx_pin = io_port;
config.rx_pin = io_port;
config.parity = UART_PARITY_DISABLE;
config.tx_wait_mutex = 0;
__this->udev = uart_init(-1, &config);
if (__this->udev < 0) {
goto __err_exit;
}
//确保2byte的时间
uart_timeout = 25 * 1000000 / __this->data->baudrate;//us
dma.rx_timeout_thresh = uart_timeout;
dma.frame_size = 1;
dma.event_mask = UART_EVENT_RX_DATA | UART_EVENT_RX_TIMEOUT | UART_EVENT_TX_DONE;
dma.irq_priority = 2;
dma.irq_callback = chargebox_uart_isr_cb;
dma.rx_cbuffer = chg_uart_dma_buf;
dma.rx_cbuffer_size = BUF_LEN;
ret = uart_dma_init(__this->udev, &dma);
if (ret < 0) {
goto __err_exit;
}
return;
__err_exit:
ASSERT(0, "chargebox open err!\n");
if (__this->udev >= 0) {
uart_deinit(__this->udev);
}
__this->udev = -1;
}
void chargebox_close(u8 l_r)
{
if (__this->udev < 0) {
return;
}
uart_deinit(__this->udev);
__this->udev = -1;
if (l_r == EAR_L) {
gpio_hw_set_pull_up(IO_PORT_SPILT(__this->data->L_port), GPIO_PULLUP_DISABLE);
gpio_hw_set_pull_down(IO_PORT_SPILT(__this->data->L_port), GPIO_PULLDOWN_DISABLE);
gpio_hw_set_die(IO_PORT_SPILT(__this->data->L_port), 1);
gpio_hw_set_dieh(IO_PORT_SPILT(__this->data->L_port), 1);
gpio_set_mode(IO_PORT_SPILT(__this->data->L_port), PORT_OUTPUT_HIGH);
} else {
gpio_hw_set_pull_up(IO_PORT_SPILT(__this->data->R_port), GPIO_PULLUP_DISABLE);
gpio_hw_set_pull_down(IO_PORT_SPILT(__this->data->R_port), GPIO_PULLDOWN_DISABLE);
gpio_hw_set_die(IO_PORT_SPILT(__this->data->R_port), 1);
gpio_hw_set_dieh(IO_PORT_SPILT(__this->data->R_port), 1);
gpio_set_mode(IO_PORT_SPILT(__this->data->R_port), PORT_OUTPUT_HIGH);
}
}
void chargebox_set_baud(u32 baudrate)
{
u32 uart_timeout;
if (__this->udev < 0) {
return;
}
//确保2byte的时间
uart_timeout = 25 * 1000000 / baudrate;
uart_set_baudrate(__this->udev, baudrate);
uart_set_rx_timeout_thresh(__this->udev, uart_timeout);
//重新初始化DMA,防止高波特率时候出现分包行为
uart_dma_rx_reset(__this->udev);
}
void chargebox_init(const struct chargebox_platform_data *data)
{
__this->data = (struct chargebox_platform_data *)data;
ASSERT(data);
__this->udev = -1;
}
#endif
+204
View File
@@ -0,0 +1,204 @@
#include "generic/typedef.h"
#include "gpio.h"
#include "asm/power_interface.h"
#include "asm/hwi.h"
#include "asm/gpio_hw.h"
#include "asm/charge.h"
#include "asm/chargestore.h"
#include "update.h"
#include "app_config.h"
#include "clock.h"
#include "uart.h"
#include "asm/power/p33/charge_hw.h"
#if (TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE)
struct chargestore_handle {
const struct chargestore_platform_data *data;
s32 udev;
};
#define DMA_BUF_LEN 544
#define __this (&hdl)
static struct chargestore_handle hdl;
u8 uart_rx_buf[DMA_BUF_LEN] __attribute__((aligned(4)));
u8 uart_dma_buf[DMA_BUF_LEN] __attribute__((aligned(4)));
enum {
UPGRADE_NULL = 0,
UPGRADE_USB_HARD_KEY,
UPGRADE_USB_SOFTKEY,
UPGRADE_UART_SOFT_KEY,
UPGRADE_UART_ONE_WIRE_HARD_KEY,
};
extern void nvram_set_boot_state(u32 state);
void chargestore_set_update_ram(void)
{
//需要补充设置ram
int tmp;
__asm__ volatile("%0 =icfg" : "=r"(tmp));
tmp &= ~(3 << 8);
__asm__ volatile("icfg = %0" :: "r"(tmp));//GIE1
local_irq_disable();
nvram_set_boot_state(UPGRADE_UART_SOFT_KEY);
}
void __attribute__((weak)) chargestore_data_deal(u8 cmd, u8 *data, u32 len)
{
}
void __attribute__((weak)) chargestore_uart_data_deal(u8 *data, u8 len)
{
}
static u8 chargestore_get_f95_det_res(u32 equ_res)
{
u8 det_res = (equ_res + 50) / 100;
if (det_res > 0) {
det_res -= 1;
}
if (det_res > 0x0f) {
det_res = 0x0f;
}
return det_res;
}
u8 chargestore_get_det_level(u8 chip_type)
{
u32 res = 1600;
switch (chip_type) {
case TYPE_F95:
if (IS_L5V_LOAD_EN()) {
res = (GET_L5V_RES_DET_S_SEL() + 1) * 50;
}
return chargestore_get_f95_det_res(res);
case TYPE_NORMAL:
default:
return 0x0f;
}
}
static void chargestore_uart_isr_cb(uart_dev uart_num, enum uart_event event)
{
s32 rx_len;
if (event == UART_EVENT_RX_DATA) {
} else if (event == UART_EVENT_TX_DONE) {
if (__this->data->io_port == IO_PORT_LDOIN) {
gpio_set_mode(IO_PORT_SPILT(__this->data->io_port), PORT_INPUT_FLOATING);
}
chargestore_data_deal(CMD_COMPLETE, NULL, 0);
} else if (event == UART_EVENT_RX_TIMEOUT) {
rx_len = uart_recv_bytes(__this->udev, uart_rx_buf, DMA_BUF_LEN);
if (rx_len > 0) {
chargestore_data_deal(CMD_RECVDATA, uart_rx_buf, rx_len);
chargestore_uart_data_deal(uart_rx_buf, rx_len);
}
}
}
void chargestore_write(u8 *data, u8 len)
{
if (__this->udev < 0) {
return;
}
if (((u32)data) % 4) {//4byte对齐
ASSERT(0, "%s: unaligned accesses!", __func__);
}
uart_send_bytes(__this->udev, (const void *)data, (u32)len);
}
void chargestore_open(u8 mode)
{
s32 ret;
u32 uart_timeout;
struct uart_config config = {0};
struct uart_dma_config dma = {0};
#if (TCFG_CHARGE_ENABLE && (TCFG_CHARGESTORE_PORT == IO_PORT_LDOIN))
if (mode == MODE_RECVDATA) {
charge_set_ldo5v_detect_stop(0);
} else {
charge_set_ldo5v_detect_stop(1);
}
#endif
if (__this->udev >= 0) {
return;
}
config.baud_rate = __this->data->baudrate;
config.tx_pin = __this->data->io_port;
config.rx_pin = __this->data->io_port;
config.parity = UART_PARITY_DISABLE;
config.tx_wait_mutex = 0;
__this->udev = uart_init(-1, &config);
if (__this->udev < 0) {
goto __err_exit;
}
//如果为VPWR引脚,则关闭驱动开启的上拉
if (__this->data->io_port == IO_PORT_LDOIN) {
gpio_set_mode(IO_PORT_SPILT(__this->data->io_port), PORT_INPUT_FLOATING);
}
//确保2byte的时间
uart_timeout = 25 * 1000000 / __this->data->baudrate;//us
dma.rx_timeout_thresh = uart_timeout;
dma.frame_size = DMA_BUF_LEN;
dma.event_mask = UART_EVENT_RX_DATA | UART_EVENT_RX_TIMEOUT | UART_EVENT_TX_DONE;
dma.irq_priority = 2;
dma.irq_callback = chargestore_uart_isr_cb;
dma.rx_cbuffer = uart_dma_buf;
dma.rx_cbuffer_size = DMA_BUF_LEN;
ret = uart_dma_init(__this->udev, &dma);
if (ret < 0) {
goto __err_exit;
}
return;
__err_exit:
ASSERT(0, "chargebox open err!\n");
if (__this->udev >= 0) {
uart_deinit(__this->udev);
}
__this->udev = -1;
}
void chargestore_close(void)
{
if (__this->udev < 0) {
return;
}
uart_deinit(__this->udev);
__this->udev = -1;
#if (TCFG_CHARGE_ENABLE && (TCFG_CHARGESTORE_PORT == IO_PORT_LDOIN))
charge_set_ldo5v_detect_stop(0);
#endif
}
void chargestore_set_baudrate(u32 baudrate)
{
u32 uart_timeout;
if (__this->udev < 0) {
return;
}
//确保2byte的时间
uart_timeout = 25 * 1000000 / baudrate;
uart_set_baudrate(__this->udev, baudrate);
uart_set_rx_timeout_thresh(__this->udev, uart_timeout);
//重新初始化DMA,防止高波特率时候出现分包行为
uart_dma_rx_reset(__this->udev);
}
void chargestore_init(const struct chargestore_platform_data *data)
{
__this->data = (struct chargestore_platform_data *)data;
ASSERT(data);
__this->udev = -1;
}
#endif
+50
View File
@@ -0,0 +1,50 @@
#include "app_config.h"
#include "asm/chargestore.h"
#include "asm/charge.h"
#include "gpio_config.h"
#include "system/init.h"
#include "asm/power_interface.h"
#include "gpio.h"
#if TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE
static void chargestore_wakeup_callback(P33_IO_WKUP_EDGE edge)
{
extern void chargestore_ldo5v_fall_deal(void);
chargestore_ldo5v_fall_deal();
}
static const struct _p33_io_wakeup_config port1 = {
.pullup_down_mode = PORT_KEEP_STATE, //配置I/O 保持之前IO状态
.edge = FALLING_EDGE, //唤醒方式选择,可选:上升沿\下降沿
.filter = PORT_FLT_1ms,
.gpio = TCFG_CHARGESTORE_PORT, //唤醒口选择
.callback = chargestore_wakeup_callback,
};
static const struct chargestore_platform_data chargestore_data = {
.io_port = TCFG_CHARGESTORE_PORT,
.baudrate = 9600,
.init = chargestore_init,
.open = chargestore_open,
.close = chargestore_close,
.write = chargestore_write,
};
int board_chargestore_config()
{
p33_io_wakeup_port_init(&port1);
p33_io_wakeup_enable(TCFG_CHARGESTORE_PORT, 1);
chargestore_api_init(&chargestore_data);
return 0;
}
static void board_chargestore_not_config()
{
p33_io_wakeup_enable(TCFG_CHARGESTORE_PORT, 0);
}
platform_initcall(board_chargestore_config);
platform_uninitcall(board_chargestore_not_config);
#endif
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More