问题点
发现低温箱关机状态下能充进去电。开机是正常的。
参考
kernel充电温度保护机制
-
drivers/power/supply/mediatek/charger/mtk_charger.c
充电保护线程:
dts:
/* Battery Temperature Protection */
#define MIN_CHARGE_TEMP 0
#define MIN_CHARGE_TEMP_PLUS_X_DEGREE 6
#define MAX_CHARGE_TEMP 50
#define MAX_CHARGE_TEMP_MINUS_X_DEGREE 47
static void charger_check_status(struct charger_manager *info)
{
bool charging = true;
int temperature;
struct battery_thermal_protection_data *thermal;
if (mt_get_charger_type() == CHARGER_UNKNOWN)
return;
temperature = info->battery_temp;
thermal = &info->thermal;
if (info->enable_sw_jeita == true) {
do_sw_jeita_state_machine(info);
if (info->sw_jeita.charging == false) {
charging = false;
goto stop_charging;
}
} else {
if (thermal->enable_min_charge_temp) { //温度过低,低于0度
if (temperature < thermal->min_charge_temp) {
chr_err("Battery Under Temperature or NTC fail %d %d\n",
temperature, thermal->min_charge_temp);
thermal->sm = BAT_TEMP_LOW;
charging = false;
goto stop_charging; //小于0°,停止充电
} else if (thermal->sm == BAT_TEMP_LOW) {//温度小于0度后,升上来了
if (temperature >=
thermal->min_charge_temp_plus_x_degree) {//温度大于6度了
chr_err("Battery Temperature raise from %d to %d(%d), allow charging!!\n",
thermal->min_charge_temp,
temperature,
thermal->min_charge_temp_plus_x_degree);
thermal->sm = BAT_TEMP_NORMAL;
} else {
charging = false;
goto stop_charging;
}
}
}
if (temperature >= thermal->max_charge_temp) { //温度太高,高于50度
chr_err("Battery over Temperature or NTC fail %d %d\n",
temperature, thermal->max_charge_temp);
thermal->sm = BAT_TEMP_HIGH;
charging = false;
goto stop_charging;
} else if (thermal->sm == BAT_TEMP_HIGH) {//温度大于50度后,降下来了
if (temperature
< thermal->max_charge_temp_minus_x_degree) { //现在温度小于47度了
chr_err("Battery Temperature raise from %d to %d(%d), allow charging!!\n",
thermal->max_charge_temp,
temperature,
thermal->max_charge_temp_minus_x_degree);
thermal->sm = BAT_TEMP_NORMAL;
} else {
charging = false;
goto stop_charging;
}
}
}
mtk_chg_get_tchg(info);
if (!mtk_chg_check_vbus(info)) {
charging = false;
goto stop_charging;
}
if (info->cmd_discharging)
charging = false;
if (info->safety_timeout)
charging = false;
if (info->vbusov_stat)
charging = false;
stop_charging:
mtk_battery_notify_check(info);
chr_err("tmp:%d (jeita:%d sm:%d cv:%d en:%d) (sm:%d) en:%d c:%d s:%d ov:%d %d %d\n",
temperature, info->enable_sw_jeita, info->sw_jeita.sm,
info->sw_jeita.cv, info->sw_jeita.charging, thermal->sm,
charging, info->cmd_discharging, info->safety_timeout,
info->vbusov_stat, info->can_charging, charging);
if (charging != info->can_charging)
_charger_manager_enable_charging(info->chg1_consumer,
0, charging);
info->can_charging = charging;
}
-
过压保护和温度保护通知,往底层节点
BatteryNotify
写异常标志,同时framework监听该节点并往上层app发送广播事件来显示充电危险。若是关机充电,重启后
kpoc_charger
程序将读取这个节点的异常值,显示危险断开充电图标。:
不正常状态如下:
/* charging abnormal status */
#define CHG_VBUS_OV_STATUS (1 << 0)
#define CHG_BAT_OT_STATUS (1 << 1)
#define CHG_OC_STATUS (1 << 2)
#define CHG_BAT_OV_STATUS (1 << 3)
#define CHG_ST_TMO_STATUS (1 << 4)
#define CHG_BAT_LT_STATUS (1 << 5)
#define CHG_TYPEC_WD_STATUS (1 << 6)
static void mtk_battery_notify_check(struct charger_manager *info)
{
if (info->notify_test_mode == 0x0000) {
mtk_battery_notify_VCharger_check(info);
mtk_battery_notify_VBatTemp_check(info);
} else {
mtk_battery_notify_UI_test(info);
}
}
static void mtk_battery_notify_VCharger_check(struct charger_manager *info)
{
#if defined(BATTERY_NOTIFY_CASE_0001_VCHARGER)
int vchr = 0;
vchr = battery_get_vbus() * 1000; /* uV */
if (vchr < info->data.max_charger_voltage)
info->notify_code &= ~CHG_VBUS_OV_STATUS;
else {
info->notify_code |= CHG_VBUS_OV_STATUS;
chr_err("[BATTERY] charger_vol(%d mV) > %d mV\n",
vchr / 1000, info->data.max_charger_voltage / 1000);
mtk_chgstat_notify(info);
}
#endif
}
温度过高过低保护:
static void mtk_battery_notify_VBatTemp_check(struct charger_manager *info)
{
#if defined(BATTERY_NOTIFY_CASE_0002_VBATTEMP)
if (info->battery_temp >= info->thermal.max_charge_temp) {
info->notify_code |= CHG_BAT_OT_STATUS;
chr_err("[BATTERY] bat_temp(%d) out of range(too high)\n",
info->battery_temp);
mtk_chgstat_notify(info);
} else {
info->notify_code &= ~CHG_BAT_OT_STATUS; //高温标志
}
if (info->enable_sw_jeita == true) {
if (info->battery_temp < info->data.temp_neg_10_thres) {
info->notify_code |= CHG_BAT_LT_STATUS;
chr_err("bat_temp(%d) out of range(too low)\n",
info->battery_temp);
mtk_chgstat_notify(info);
} else {
info->notify_code &= ~CHG_BAT_LT_STATUS;
}
} else {
#ifdef BAT_LOW_TEMP_PROTECT_ENABLE //这个宏默认没打开,需要打开
if (info->battery_temp < info->thermal.min_charge_temp) {
info->notify_code |= CHG_BAT_LT_STATUS;
chr_err("bat_temp(%d) out of range(too low)\n",
info->battery_temp);
mtk_chgstat_notify(info);
} else {
info->notify_code &= ~CHG_BAT_LT_STATUS;
}
#endif
}
#endif
}
下面这个就是通过uevent往上层发送异常事件,貌似不知道是在干嘛:
static int mtk_chgstat_notify(struct charger_manager *info)
{
int ret = 0;
char *env[2] = { "CHGSTAT=1", NULL };
chr_err("%s: 0x%x\n", __func__, info->notify_code);
ret = kobject_uevent_env(&info->pdev->dev.kobj, KOBJ_CHANGE, env);
if (ret)
chr_err("%s: kobject_uevent_fail, ret=%d", __func__, ret);
return ret;
}
-
改变
info->notify_code
值其实就是改变sys节点
/sys/devices/platform/charger/BatteryNotify
的值:
static ssize_t show_BatNotify(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct charger_manager *pinfo = dev->driver_data;
pr_debug("[Battery] show_BatteryNotify: 0x%x\n", pinfo->notify_code);
return sprintf(buf, "%u\n", pinfo->notify_code);
}
static ssize_t store_BatNotify(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct charger_manager *pinfo = dev->driver_data;
unsigned int reg = 0;
int ret;
pr_debug("[Battery] store_BatteryNotify\n");
if (buf != NULL && size != 0) {
pr_debug("[Battery] buf is %s and size is %zu\n", buf, size);
ret = kstrtouint(buf, 16, ®);
pinfo->notify_code = reg;
pr_debug("[Battery] store code: 0x%x\n", pinfo->notify_code);
mtk_chgstat_notify(pinfo);
}
return size;
}
static DEVICE_ATTR(BatteryNotify, 0664, show_BatNotify, store_BatNotify);
frameworks层发送广播
-
vendor/mediatek/proprietary/frameworks/opt/batterywarning/batterywarning.cpp
:
uevent事件轮询:
* batterywarn_init
* uevent_init()
* batterywarn_register_event(uevent_fd, uevent_event) //注册uevent_event
如下,如果 type>0,就发送广播sendBroadcastMessage(String16(ACTION), type);
上层会接受这个广播,根据type去提醒系统。
#define UEVENT_MSG_LEN 2048
static void uevent_event(uint32_t /*epevents*/) {
char msg[UEVENT_MSG_LEN + 2];
char *cp;
char *status;
int n;
char *buffer = (char*) malloc(MAX_CHAR * sizeof(char));
if (buffer == NULL) {
ALOGD("malloc memory failed");
return ;
}
n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
if (n <= 0) return;
if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
return;
msg[n] = '\0';
msg[n + 1] = '\0';
cp = msg;
while (*cp) {
if (!strncmp(cp, "CHGSTAT=", strlen("CHGSTAT="))) { // This CHGSTAT value will be provided by kernel driver
readType(buffer);
break;
}
/* advance to after the next \0 */
while (*cp++)
;
}
free(buffer);
}
void readType(char* buffer) {
FILE * pFile;
int file_index;
file_index=get_charger_file_path();
ALOGD("Inside file_index value : %d\n", file_index);
pFile = fopen(charger_file_path[file_index], "r");
if (pFile == NULL) {
ALOGE("error opening file");
return;
} else {
if (fgets(buffer, MAX_CHAR, pFile) == NULL) {
fclose(pFile);
ALOGE("can not get the string from the file");
return;
}
}
fclose(pFile);
int type = atoi(buffer);
if (type==0)
{
ALOGD("start activity by send intent to BatteryWarningReceiver to remove notification, type = %d\n", type);
sendBroadcastMessage(String16(NORMAL_ACTION), type);
}
if (type > 0) //如果 type>0,就发送广播
{
ALOGD("start activity by send intent to BatteryWarningReceiver, type = %d\n", type);
sendBroadcastMessage(String16(ACTION), type);
}
}
static int batterywarn_init() {
epollfd = epoll_create(MAX_EPOLL_EVENTS);
if (epollfd == -1) {
ALOGD("epoll_create failed; errno=%d\n", errno);
return -1;
}
uevent_init();
return 0;
}
int main()
{
char *buffer = (char*) malloc(MAX_CHAR * sizeof(char));
if (buffer == NULL) {
ALOGD("malloc memory failed");
return 0;
}
int ret;
/* Read the status to catch the event when batterywarning is not started */
readType(buffer);
ret= batterywarn_init();
if (ret) {
ALOGD("Initialization failed, exiting\n");
exit(1);
}
batterywarn_mainloop();
free(buffer);
return 0;
app接收广播
有人发送广播,就有人接收广播,因此继续跟踪谁接收了这个广播。
-
vendor/mediatek/proprietary/packages/apps/BatteryWarning/src/com/mediatek/batterywarning/BatteryWarningReceiver.java
:
分析这里面时,获取发送的广播,然后启动activity(BatteryWarningActivity),并且把type的值放在inten中传递过去。
type含义类型
private static final int CHARGER_OVER_VOLTAGE_TYPE = 0;
private static final int BATTERY_OVER_TEMPERATURE_TYPE = 1;
private static final int CURRENT_OVER_PROTECTION_TYPE = 2;
private static final int BATTERY_OVER_VOLTAGE_TYPE = 3;
private static final int SAFETY_OVER_TIMEOUT_TYPE = 4;
private static final int BATTERY_LOW_TEMPERATURE_TYPE = 5;
private static final int TYPEC_DETECTION_WATER_GAS_TYPE = 6;
CHARGER_OVER_VOLTAGE_TYPE = 0;//充电电压过高
BATTERY_OVER_TEMPERATURE_TYPE = 1;//电池温度过高
CURRENT_OVER_PROTECTION_TYPE = 2;//超过电流保护
BATTERY_OVER_VOLTAGE_TYPE = 3;//电池电压过高
SAFETY_OVER_TIMEOUT_TYPE = 4;//充电时间过长
BATTERY_LOW_TEMPERATURE_TYPE = 5;//电池温度过低
在onCreate()方法中,如果mType类型在0-5之间,就调用showWarningDialog()弹出提醒框。
分析到这里,整体的流程已经弄明白了,那么客制化的实现也很简单了。
版权声明:本文为u011784994原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。