初版
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user