华为电池核心之battery_fault模块
一、模块概述
[battery_fault.c]是华为电源管理框架中的电池故障检测驱动,核心功能:
电池欠压保护(截止电压检测)
低温/休眠状态下的电压调整
故障事件通知与 DSM 上报
防误触发滤波机制
二、核心数据结构
struct bat_fault_device {
struct device *dev;
struct delayed_work fault_work;
struct notifier_block coul_event_nb;
struct bat_fault_config config;
struct bat_fault_data data;
struct wakeup_source *wake_lock;
const struct bat_fault_ops *ops;
};
struct bat_fault_config {
int vol_cutoff_normal;
int vol_cutoff_sleep;
int vol_cutoff_low_temp;
int vol_cutoff_filter_cnt;
};
struct bat_fault_data {
int vol_cutoff_sign;
int vol_cutoff_used;
};
struct bat_fault_ops {
void (*notify)(unsigned int event);
};
三、关键功能模块
3.1 截止电压动态更新
3.1.1 策略逻辑
bat_fault_update_cutoff_vol(bool sleep_mode) {
if (sleep_mode)
vol = vol_cutoff_sleep;
else
vol = vol_cutoff_normal;
temp = coul_interface_get_battery_temperature();
if (temp <= BAT_FAULT_LOW_TEMP_THLD)
vol = min(vol_cutoff_low_temp, vol);
di->data.vol_cutoff_used = vol;
}
3.1.2 温度单位说明
BAT_FAULT_LOW_TEMP_THLD = -50
应用场景:
| 状态 | 温度 | 使用电压 | 原因 |
|---|
| 正常使用 | 常温 | 3150mV | 最大化电量利用 |
| 休眠状态 | 常温 | 3350mV | 防止长时间放置过放 |
| 正常使用 | 低温 | 低温电压 | 低温内阻大,电压跌落快 |
3.2 欠压检测和滤波
bat_fault_cutoff_vol_event_handle() {
if (!bat_exist)
return;
count = di->config.vol_cutoff_filter_cnt;
while (count-- >= 0) {
voltage = coul_interface_get_battery_voltage();
if ((voltage - BAT_FAULT_CUTOFF_VOL_OFFSET) > cutoff_vol) {
hwlog_err("filter fail:vol=%d\n", voltage);
return;
}
if (count > 0)
msleep(BAT_FAULT_CUTOFF_VOL_PERIOD);
}
di->data.vol_cutoff_sign = 1;
bat_fault_notify(POWER_NE_COUL_LOW_VOL);
snprintf(buf, ...,
"[LOW VOL]cur_vol:%dmV,cut_vol=%dmV,cur_soc=%d,temp=%d,current=%d\n",
voltage, cutoff_vol, ui_soc, temp, cur);
power_dsm_report_dmd(POWER_DSM_BATTERY_DETECT,
POWER_DSM_ERROR_LOW_VOL_INT, buf);
}
时间轴:
t0 t1 t2 t3
↓ ↓ ↓ ↓
读取 -----> 读取 ----> 读取 ----> 确认欠压
(1s) (1s)
如果任意一次电压 > (cutoff + 10mV) → 退出,认为误触发
3.3 欠压判断入口
int bat_fault_is_cutoff_vol(void)
{
if (di->data.vol_cutoff_sign)
return di->data.vol_cutoff_sign;
bat_fault_update_cutoff_vol(false);
voltage = coul_interface_get_battery_voltage();
if (voltage < di->data.vol_cutoff_used) {
hwlog_err("battery voltage low %d, cutoff %d\n",
voltage, di->data.vol_cutoff_used);
power_event_bnc_notify(POWER_BNT_COUL, POWER_NE_COUL_LOW_VOL, NULL);
}
return di->data.vol_cutoff_sign;
}
调用链:
battery_core.c (健康度检测)
↓
bat_fault_is_cutoff_vol()
↓
voltage < cutoff_vol ?
↓ (是)
power_event_bnc_notify(POWER_NE_COUL_LOW_VOL)
↓
bat_fault_coul_event_notifier_call()
↓
queue_delayed_work(&fault_work)
↓
bat_fault_work()
↓
bat_fault_cutoff_vol_event_handle()
3.4 欠压事件通知
void bat_fault_send_under_voltage_event(void)
{
struct power_event_notify_data n_data;
n_data.event = "BATTERY_UNDER_VOLTAGE=1";
n_data.event_len = 23;
power_event_report_uevent(&n_data);
hwlog_info("battery under voltage, report uevent\n");
}
3.5 库仑计事件监听
static int bat_fault_coul_event_notifier_call(struct notifier_block *nb,
unsigned long event, void *data)
{
switch (event) {
case POWER_NE_COUL_LOW_VOL:
queue_delayed_work(system_power_efficient_wq,
&di->fault_work, msecs_to_jiffies(0));
break;
default:
break;
}
return NOTIFY_OK;
}
3.6 故障回调通知
static void bat_fault_notify(unsigned int event)
{
if (!di || !di->ops || !di->ops->notify)
return;
di->ops->notify(event);
}
int bat_fault_register_ops(const struct bat_fault_ops *ops)
{
di->ops = ops;
return 0;
}
3.7 DTS配置解析
支持硅基/石墨基差异化配置:
bat_fault_parse_dts() {
switch (bat_model_get_bat_cathode_type()) {
case BAT_MODEL_BAT_CATHODE_TYPE_SILICON:
power_dts_read_u32("vol_cutoff_normal_si", ...);
power_dts_read_u32("vol_cutoff_sleep_si", ...);
power_dts_read_u32("vol_cutoff_low_temp_si", ...);
power_dts_read_u32("vol_cutoff_filter_cnt_si", ...);
break;
case BAT_MODEL_BAT_CATHODE_TYPE_GRAPHITE:
default:
power_dts_read_u32("vol_cutoff_normal", ...);
power_dts_read_u32("vol_cutoff_sleep", ...);
power_dts_read_u32("vol_cutoff_low_temp", ...);
power_dts_read_u32("vol_cutoff_filter_cnt", ...);
}
}
DTS 示例:
battery_fault {
compatible = "huawei,battery_fault";
/* 石墨基电池配置 */
vol_cutoff_normal = <3150>; // 正常模式 3.15V
vol_cutoff_sleep = <3350>; // 休眠模式 3.35V
vol_cutoff_low_temp = <3000>; // 低温模式 3.00V
vol_cutoff_filter_cnt = <3>; // 滤波 3 次
/* 硅基电池配置 (电压特性不同) */
vol_cutoff_normal_si = <3000>; // 硅基电池截止电压更低
vol_cutoff_sleep_si = <3200>;
vol_cutoff_low_temp_si = <2850>;
vol_cutoff_filter_cnt_si = <5>; // 更严格的滤波
};
3.8 电源管理
休眠/唤醒处理:
static int bat_fault_prepare(struct device *dev)
{
bat_fault_update_cutoff_vol(true);
coul_interface_set_battery_low_voltage(
bat_core_get_coul_type(), di->data.vol_cutoff_used);
return 0;
}
static void bat_fault_complete(struct device *dev)
{
bat_fault_update_cutoff_vol(false);
coul_interface_set_battery_low_voltage(
bat_core_get_coul_type(), di->data.vol_cutoff_used);
}
休眠时提高阈值:防止长时间休眠导致电池过放损坏
唤醒后降低阈值:最大化电量利用,延长续航
3.9 debug调试接口
bat_fault_dbg_vol_cutoff_show() {
return scnprintf(buf, size, "vol_cutoff_used is %d\n",
di->data.vol_cutoff_used);
}
bat_fault_dbg_vol_cutoff_store(const char *buf, size_t size) {
kstrtoint(buf, 0, &val);
di->config.vol_cutoff_normal = val;
bat_fault_update_cutoff_vol(false);
return size;
}
使用方法:
# 查看当前截止电压
cat /sys/kernel/debug/power/bat_fault/vol_cutoff
# 设置新的截止电压 (调试)
echo 3100 > /sys/kernel/debug/power/bat_fault/vol_cutoff
四、初始化流程
bat_fault_probe()
├── 1. 分配设备结构体 (kzalloc)
├── 2. 解析 DTS 配置
│ └── 根据电池类型 (硅基/石墨基) 选择参数
├── 3. 注册 Debug 接口
├── 4. 初始化截止电压 (休眠模式)
│ └── bat_fault_update_cutoff_vol(true)
├── 5. 创建延迟工作队列
│ └── INIT_DELAYED_WORK(&fault_work, bat_fault_work)
├── 6. 注册库仑计事件监听
│ └── power_event_bnc_register(POWER_BNT_COUL, &coul_event_nb)
├── 7. 创建唤醒锁
│ └── power_wakeup_source_register()
└── 8. 设置全局指针 g_bat_fault_dev
五、关键宏定义
BAT_FAULT_NORMAL_CUTOFF_VOL 3150
BAT_FAULT_SLEEP_CUTOFF_VOL 3350
BAT_FAULT_CUTOFF_VOL_OFFSET 10
BAT_FAULT_CUTOFF_VOL_FILTERS 3
BAT_FAULT_CUTOFF_VOL_PERIOD 1000
BAT_FAULT_LOW_TEMP_THLD -50
BAT_FAULT_DSM_BUF_SIZE 256
六、典型应用场景
6.1 正常使用突然欠压
用户使用手机,电量显示 3%
电压读数 3140mV < 3150mV (截止电压)
bat_fault_is_cutoff_vol() 检测到欠压
触发 POWER_NE_COUL_LOW_VOL 事件
启动延迟工作队列,进行 3 次滤波验证
t=0s: voltage = 3140mV ✓
t=1s: voltage = 3135mV ✓
t=2s: voltage = 3130mV ✓
确认真实欠压
battery_core 设置健康度 = POWER_SUPPLY_HEALTH_UNDERVOLTAGE
发送 uevent 到 Android 层
Android 触发关机流程
6.2 充电时误触发(负载突降)
用户插入充电器瞬间
充电电流突增,电池内阻压降导致电压瞬降
瞬时读数 3140mV < 3150mV
触发第 1 次滤波检测: voltage = 3140mV ✓
等待 1s,充电稳定后
第 2 次滤波检测: voltage = 3600mV ✗ (超过阈值)
滤波失败,认为误触发,退出
vol_cutoff_sign 保持 0,不触发关机
6.3 低温环境欠压
环境温度 -10°C
电池温度读数 -100 (表示 -10.0°C) < -50
bat_fault_update_cutoff_vol() 选择低温截止电压
使用更低的阈值 3000mV 进行判断
避免低温下内阻大导致的误关机
6.4 休眠期间长时间放置
手机进入休眠 (suspend)
bat_fault_prepare() 被调用
切换到休眠截止电压 3350mV (更高)
通知库仑计芯片更新中断阈值
库仑计硬件监控电压
如果电压 < 3350mV,触发硬件中断唤醒系统
系统执行关机流程,防止过放
七、模块依赖
battery_fault.c
├── coul_interface (库仑计接口)
│ ├── get_battery_voltage()
│ ├── get_battery_temperature()
│ ├── get_battery_avg_current()
│ ├── is_battery_exist()
│ └── set_battery_low_voltage()
├── battery_core (电池核心)
│ └── bat_core_get_coul_type()
├── battery_ui_capacity (UI 电量)
│ └── bat_ui_capacity()
├── battery_model (电池型号)
│ └── bat_model_get_bat_cathode_type()
├── power_event (事件通知)
│ ├── power_event_bnc_notify()
│ └── power_event_report_uevent()
└── power_dsm (DSM 上报)
└── power_dsm_report_dmd()
八、电压阈值设计原理
为什么需要不同的截止电压?
| 场景 | 截止电压 | 原因 |
|---|
| 正常使用 | 3150mV | 最大化电量利用,避免过早关机 |
| 休眠状态 | 3350mV | 防止长时间静置导致过放损坏电池 |
| 低温环境 | 3000mV | 低温内阻大,电压跌落快,降低阈值避免误关机 |
滤波容差设计:
实际判断条件: voltage < (cutoff_vol + 10mV)
原因:
1. ADC 读数有 ±5mV 误差
2. 电池内阻导致瞬时压降
3. 10mV 容差可过滤大部分毛刺
九、调试建议
日志关键词
dmesg | grep battery_fault
dmesg | grep "LOW VOL"
dmesg | grep "cutoff"
关键日志示例:
battery_fault: v_cut=3150, v_sleep=3350, v_low_temp=3000, temp=250, vol=3150
battery_fault: filter fail:vol=3200,count=2,v_cut=3150
battery_fault: cutoff:vol=3130,v_cut=3150,cur_soc=3
battery_fault: battery under voltage, report uevent
Debug 节点:
cat /sys/kernel/debug/power/bat_fault/vol_cutoff
echo 3100 > /sys/kernel/debug/power/bat_fault/vol_cutoff
模拟欠压测试:
echo 3800 > /sys/kernel/debug/power/bat_fault/vol_cutoff
dmesg | tail -20
总结
battery_fault是电池安全的最后一道防线,通过多级滤波和动态阈值调整,准确识别真实欠压,防止电池过放损坏,同时避免误触发影响用户体验。