GM30里面有一个线程函数,默认执行的时间为10s,充满后执行的时间为20s,时间也是可以设置的
charger_routine_thread 函数里面
while函数里面
info->do_algorithm(info); 调用了一个回调函数
这个回调函数是在 mtk_switch_charger.c 里面被设置的
mtk_switch_charging_init 函数
int mtk_switch_charging_init(struct charger_manager *info)
{
struct switch_charging_alg_data *swch_alg;
swch_alg = devm_kzalloc(&info->pdev->dev,
sizeof(*swch_alg), GFP_KERNEL);
if (!swch_alg)
return -ENOMEM;
info->chg1_dev = get_charger_by_name("primary_chg");
if (info->chg1_dev)
chr_err("Found primary charger [%s]\n",
info->chg1_dev->props.alias_name);
else
chr_err("*** Error : can't find primary charger ***\n");
mutex_init(&swch_alg->ichg_aicr_access_mutex);
info->algorithm_data = swch_alg;
info->do_algorithm = mtk_switch_charging_run; // 外部充电ic充电,设置了回调函数
info->plug_in = mtk_switch_charging_plug_in;
info->plug_out = mtk_switch_charging_plug_out;
info->do_charging = mtk_switch_charging_do_charging;
info->do_event = charger_dev_event;
info->change_current_setting = mtk_switch_charging_current; // 设置充电电流
return 0;
}
看下设置的回调函数 mtk_switch_charging_run,这个函数里面做了充电模式的切换,我们的主要是CC和BATFUL这两个,
同时会去检查充电时间,然后调用dump_register的回调函数,这里我们重点观察cc模式的这个函数
static int mtk_switch_charging_run(struct charger_manager *info)
{
struct switch_charging_alg_data *swchgalg = info->algorithm_data;
int ret = 0;
chr_err("%s [%d %d], timer=%d\n", __func__, swchgalg->state,
info->pd_type,
swchgalg->total_charging_time);
if (mtk_pdc_check_charger(info) == false &&
mtk_is_TA_support_pd_pps(info) == false) {
mtk_pe20_check_charger(info);
if (mtk_pe20_get_is_connect(info) == false)
mtk_pe_check_charger(info);
}
do {
switch (swchgalg->state) {
chr_err("%s_2 [%d] %d\n", __func__, swchgalg->state,
info->pd_type);
case CHR_CC:
ret = mtk_switch_chr_cc(info); // 恒流模式充电
break;
case CHR_PE40_INIT:
ret = mtk_switch_chr_pe40_init(info); // pe40初始化
break;
case CHR_PE40_CC:
ret = mtk_switch_chr_pe40_cc(info); // pe40恒流
break;
case CHR_BATFULL:
ret = mtk_switch_chr_full(info); // 电池充满
break;
case CHR_ERROR:
ret = mtk_switch_chr_err(info); // 充电错误
break;
}
} while (ret != 0);
mtk_switch_check_charging_time(info);
charger_dev_dump_registers(info->chg1_dev);
return 0;
}
mtk_switch_chr_cc 恒流充电模式函数,这个函数里面会去使能充电,同时会去检查充电是否完成
static int mtk_switch_chr_cc(struct charger_manager *info)
{
bool chg_done = false;
struct switch_charging_alg_data *swchgalg = info->algorithm_data;
struct timespec time_now, charging_time;
/* check bif */
if (IS_ENABLED(CONFIG_MTK_BIF_SUPPORT)) {
if (pmic_is_bif_exist() != 1) {
chr_err("CONFIG_MTK_BIF_SUPPORT but no bif , stop charging\n");
swchgalg->state = CHR_ERROR;
charger_manager_notifier(info, CHARGER_NOTIFY_ERROR);
}
}
get_monotonic_boottime(&time_now);
charging_time = timespec_sub(time_now, swchgalg->charging_begin_time);
swchgalg->total_charging_time = charging_time.tv_sec;
if (mtk_pe40_is_ready(info)) {
chr_err("enter PE4.0!\n");
swchgalg->state = CHR_PE40_INIT;
info->pe4.is_connect = true;
return 1;
}
swchg_turn_on_charging(info); // 使能开始充电
charger_dev_is_charging_done(info->chg1_dev, &chg_done); // 检查是否充电完成
if (chg_done) { // 充电完成
swchgalg->state = CHR_BATFULL; // 更新状态为充满
charger_dev_do_event(info->chg1_dev, EVENT_EOC, 0); // 发充满事件
chr_err("battery full!\n");
}
/* If it is not disabled by throttling,
* enable PE+/PE+20, if it is disabled
*/
if (info->chg1_data.thermal_input_current_limit != -1 &&
info->chg1_data.thermal_input_current_limit < 300)
return 0;
if (!mtk_pe20_get_is_enable(info)) {
mtk_pe20_set_is_enable(info, true);
mtk_pe20_set_to_check_chr_type(info, true);
}
if (!mtk_pe_get_is_enable(info)) {
mtk_pe_set_is_enable(info, true);
mtk_pe_set_to_check_chr_type(info, true);
}
return 0;
}
看下使能充电函数 swchg_turn_on_charging,这个函数里面会去选择充电电流,然后调用框架的函数来使能充电
static void swchg_turn_on_charging(struct charger_manager *info)
{
struct switch_charging_alg_data *swchgalg = info->algorithm_data;
bool charging_enable = true;
if (swchgalg->state == CHR_ERROR) {
charging_enable = false;
chr_err("[charger]Charger Error, turn OFF charging !\n");
} else if ((get_boot_mode() == META_BOOT) ||
((get_boot_mode() == ADVMETA_BOOT))) {
charging_enable = false;
info->chg1_data.input_current_limit = 200000; /* 200mA */
charger_dev_set_input_current(info->chg1_dev,
info->chg1_data.input_current_limit);
chr_err("In meta mode, disable charging and set input current limit to 200mA\n");
} else {
mtk_pe20_start_algorithm(info);
if (mtk_pe20_get_is_connect(info) == false)
mtk_pe_start_algorithm(info);
swchg_select_charging_current_limit(info); // 设置充电电流函数
if (info->chg1_data.input_current_limit == 0
|| info->chg1_data.charging_current_limit == 0) {
charging_enable = false;
chr_err("[charger]charging current is set 0mA, turn off charging !\n");
} else {
swchg_select_cv(info);
}
}
charger_dev_enable(info->chg1_dev, charging_enable); // 使能充电的框架函数
}
我们看下框架的函数 charger_dev_enable
charger_dev_xxx开头的函数很多都是框架函数,在charger_class.c文件里面,一般都是调用设置好的回调函数来干活的
int charger_dev_enable(struct charger_device *chg_dev, bool en) // 框架函数 用来使能充电
{
if (chg_dev != NULL && chg_dev->ops != NULL && chg_dev->ops->enable)
return chg_dev->ops->enable(chg_dev, en); // 调用使能的回调函数
return -ENOTSUPP;
}
EXPORT_SYMBOL(charger_dev_enable);
一般我们具体的充电IC驱动需要实现框架里面的一些函数,类似下面的这种,对于上面框架里面enable的调用实际上会调用到底层的bq25601_enable_charging函数
static struct charger_ops bq25601_chg_ops = {
#if 0
.enable_hz = bq25601_enable_hz,
#endif
/* Normal charging */
.dump_registers = bq25601_dump_register,
.enable = bq25601_enable_charging, // 使能函数其实就是调用了这个
.get_charging_current = bq25601_get_current,
.set_charging_current = bq25601_set_current,
.get_input_current = bq25601_get_input_current,
.set_input_current = bq25601_set_input_current,
/*.get_constant_voltage = bq25601_get_battery_voreg,*/
.set_constant_voltage = bq25601_set_cv_voltage,
.kick_wdt = bq25601_reset_watch_dog_timer,
.set_mivr = bq25601_set_vindpm_voltage,
.is_charging_done = bq25601_get_charging_status, // 这个函数是本节的主角,用来终止充电
/* Safety timer */
.enable_safety_timer = bq25601_enable_safetytimer,
.is_safety_timer_enabled = bq25601_get_is_safetytimer_enable,
/* Power path */
/*.enable_powerpath = bq25601_enable_power_path, */
/*.is_powerpath_enabled = bq25601_get_is_power_path_enable, */
/* OTG */
.enable_otg = bq25601_enable_otg,
.set_boost_current_limit = bq25601_set_boost_current_limit,
.event = bq25601_do_event,
};
顺便看下使能函数里面做了什么操作,其实就是控制寄存器咯
static int bq25601_enable_charging(struct charger_device *chg_dev,
bool en)
{
int status = 0;
pr_info("enable state : %d\n", en);
if (en) {
/* bq25601_config_interface(bq25601_CON3, 0x1, 0x1, 4); */
/* enable charging */
bq25601_set_en_hiz(0x0);
bq25601_set_chg_config(en);
} else {
/* bq25601_config_interface(bq25601_CON3, 0x0, 0x1, 4); */
/* enable charging */
bq25601_set_chg_config(en);
pr_info("[charging_enable] under test mode: disable charging\n");
/*bq25601_set_en_hiz(0x1);*/
}
return status;
}
我们继续回到 mtk_switch_chr_cc 恒流充电函数来,还有一个很重要的事就是检查充电状态是否完成
charger_dev_is_charging_done 函数,如果充电完成需要更新状态为BATFUL
charger_dev_is_charging_done(info->chg1_dev, &chg_done); // 检查是否充电完成
if (chg_done) { // 充电完成
swchgalg->state = CHR_BATFULL; // 更新状态为充满更新充电状态,更新这个状态
charger_dev_do_event(info->chg1_dev, EVENT_EOC, 0); // 发充满事件
chr_err("battery full!\n");
}
int charger_dev_is_charging_done(struct charger_device *chg_dev, bool *done)
{
if (chg_dev != NULL && chg_dev->ops != NULL &&
chg_dev->ops->is_charging_done)
return chg_dev->ops->is_charging_done(chg_dev, done); // 调用回调函数
return -ENOTSUPP;
}
EXPORT_SYMBOL(charger_dev_is_charging_done);
is_charging_done的回调函数为,这个函数里面根据寄存器的状态来判断当前是否充满,我们可以看到当寄存器的值返回是0x3的时候表示真正充满了,从而上报充满
static int bq25601_get_charging_status(struct charger_device *chg_dev,
bool *is_done)
{
unsigned int status = true;
unsigned int ret_val;
ret_val = bq25601_get_chrg_stat();
if (ret_val == 0x3)
*is_done = true;
else
*is_done = false;
return status;
}
我们继续看下这个0x3表示什么含义,需要分析bq25601_get_chrg_stat函数,调用了一个接口函数读取了CON8寄存器的bit3-bit4位的值
#define bq25601_CON8 0x08
#define CON8_CHRG_STAT_MASK 0x03
#define CON8_CHRG_STAT_SHIFT 3
unsigned int bq25601_get_chrg_stat(void)
{
unsigned int ret = 0;
unsigned char val = 0;
ret = bq25601_read_interface((unsigned char) (bq25601_CON8),
(&val),
(unsigned char) (CON8_CHRG_STAT_MASK),
(unsigned char) (CON8_CHRG_STAT_SHIFT)
);
return val;
}
我们看下这个值在手册里面的含义,从手册里面来看当值为11时表示的就是充电截至,因此就可以判断当前充电完成了
最后我们总结一下整个过程:
1、需要掌握充电函数的框架层charger_class.c文件里面的调用回调函数
2、charger_class.c文件负责将实例化的charger ic驱动和mtk_charger.c文件连接到了一起,mtk_charger.c不直接调用具体的charger ic驱动,而是通过框架charger_class.c来进行调用
3、充电的终止条件是根据charger ic的寄存器状态来判断的