1、对于6739平台来说,识别用户插入充电器的过程是通过中断来实现的,下面我们来分析一下识别过程
2、识别的原理:通过PMIC上的VCDT引脚来进行识别,当我们插入充电器时VCDT上会检测到电压,从而会触发中断,我们使用的pmic型号:MT6357
3、在 pmic_chr_type_det_v2.c 文件里面
pmic_chrdet_init函数
static int __init pmic_chrdet_init(void)
{
mutex_init(&chrdet_lock);
chrdet_psy = power_supply_get_by_name("charger");
if (!chrdet_psy) {
pr_notice("%s: get power supply failed\n", __func__);
return -EINVAL;
}
#ifdef __SW_CHRDET_IN_PROBE_PHASE__
/* do charger detect here to prevent HW miss interrupt*/
INIT_WORK(&chr_work, do_charger_detection_work); 初始化了一个延时工作队列
schedule_work(&chr_work); 调度延时工作队列
#endif
#ifndef CONFIG_TCPC_CLASS
pmic_register_interrupt_callback(INT_CHRDET_EDGE, chrdet_int_handler); 使用pmic接口注册了一个中断,并且触发方式是边沿触发,插入充电器和拔出,首先会执行这个中断函数
pmic_enable_interrupt(INT_CHRDET_EDGE, 1, "PMIC"); 使能这个中断
#endif
return 0;
}
当我们有充电器插入时会触发 chrdet_int_handler 这个中断函数
/* PMIC Int Handler */
void chrdet_int_handler(void)
{
/*
* pr_notice("[chrdet_int_handler]CHRDET status = %d....\n",
* pmic_get_register_value(PMIC_RGS_CHRDET));
*/
if (!pmic_get_register_value(PMIC_RGS_CHRDET)) {
int boot_mode = 0;
hw_bc11_done();
boot_mode = get_boot_mode(); 获取启动模式
if (boot_mode == KERNEL_POWER_OFF_CHARGING_BOOT
|| boot_mode == LOW_POWER_OFF_CHARGING_BOOT) { 判断是否是关机充电或低电
pr_info("[%s] Unplug Charger/USB\n", __func__);
#ifndef CONFIG_TCPC_CLASS
pr_info("%s: system_state=%d\n", __func__,
system_state);
if (system_state != SYSTEM_POWER_OFF)
kernel_power_off(); 关闭系统
#else
return;
#endif
}
}
pmic_set_register_value(PMIC_RG_USBDL_RST, 1);
do_charger_detect(); 执行检测充电器干活函数
}
看下 do_charger_detect 这个函数做了什么事
/* Charger Detection */
void do_charger_detect(void)
{
if (pmic_get_register_value(PMIC_RGS_CHRDET)) 如果真的有充电器
mtk_pmic_enable_chr_type_det(true); 有充电器在
else
mtk_pmic_enable_chr_type_det(false);
}
继续看下 mtk_pmic_enable_chr_type_det 函数
void mtk_pmic_enable_chr_type_det(bool en)
{
#ifndef CONFIG_TCPC_CLASS
if (!mt_usb_is_device()) {
g_chr_type = CHARGER_UNKNOWN;
pr_info("charger type: UNKNOWN, Now is usb host mode. Skip detection\n");
return;
}
#endif
mutex_lock(&chrdet_lock);
if (en) { 如果有插充电器时en=true
if (is_meta_mode()) { 判断是否是meta模式,我们的显然不是
/* Skip charger type detection to speed up meta boot */
pr_notice("charger type: force Standard USB Host in meta\n");
g_chr_type = STANDARD_HOST;
chrdet_inform_psy_changed(g_chr_type, 1);
} else { 应该是这个才对
pr_info("charger type: charger IN\n"); 插入标志性打印
g_chr_type = hw_charging_get_charger_type(); 获取充电器类型
chrdet_inform_psy_changed(g_chr_type, 1); 上报充电器插入事件
if (!IS_ERR(pinctrl_cdis_low)) {
pinctrl_select_state(cdis_pinctrl, pinctrl_cdis_low);
printk("charger IN enable charger\n");
}
}
} else {
pr_info("charger type: charger OUT\n");
g_chr_type = CHARGER_UNKNOWN;
chrdet_inform_psy_changed(g_chr_type, 0);
if (!IS_ERR(pinctrl_cdis_high)) {
pinctrl_select_state(cdis_pinctrl, pinctrl_cdis_high);
printk("===charger OUT disable charger===\n");
}
}
mutex_unlock(&chrdet_lock);
}
一般插入充电器的打印日志:
charger type: charger IN
charger type: 4, Standard Charger
charger type: chrdet_inform_psy_changed: online = 1, type = 4
mt_charger_set_property
dump_charger_name: charger type: 4, Standard Charger
charger IN enable charger
mtk_charger_int_handler
看下充电器类型是怎么识别的,通过bc11硬件来识别的得到了充电器的类型
int hw_charging_get_charger_type(void)
{
enum charger_type CHR_Type_num = CHARGER_UNKNOWN;
#ifdef CONFIG_MTK_USB2JTAG_SUPPORT
if (usb2jtag_mode()) {
pr_info("[USB2JTAG] in usb2jtag mode, skip charger detection\n");
return STANDARD_HOST;
}
#endif
hw_bc11_init();
if (hw_bc11_DCD()) {
if (hw_bc11_stepA1())
CHR_Type_num = APPLE_2_1A_CHARGER;
else
CHR_Type_num = NONSTANDARD_CHARGER;
} else {
if (hw_bc11_stepA2()) {
if (hw_bc11_stepB2())
CHR_Type_num = STANDARD_CHARGER;
else
CHR_Type_num = CHARGING_HOST;
} else
CHR_Type_num = STANDARD_HOST;
}
if (CHR_Type_num != STANDARD_CHARGER)
hw_bc11_done();
else
pr_info("charger type: skip bc11 release for BC12 DCP SPEC\n");
dump_charger_name(CHR_Type_num);
#ifdef __FORCE_USB_TYPE__
CHR_Type_num = STANDARD_HOST;
pr_info("charger type: Froce to STANDARD_HOST\n");
#endif
return CHR_Type_num;
}
于此同时会去更新节点信息的,从而上层就知道了具体的充电器类型了
static int chrdet_inform_psy_changed(enum charger_type chg_type,
bool chg_online)
{
int ret = 0;
union power_supply_propval propval;
pr_info("charger type: %s: online = %d, type = %d\n", __func__,
chg_online, chg_type);
/* Inform chg det power supply */
if (chg_online) {
propval.intval = chg_online;
ret = power_supply_set_property(chrdet_psy,
POWER_SUPPLY_PROP_ONLINE, &propval);
if (ret < 0)
pr_notice("%s: psy online failed, ret = %d\n",
__func__, ret);
propval.intval = chg_type;
ret = power_supply_set_property(chrdet_psy,
POWER_SUPPLY_PROP_CHARGE_TYPE, &propval);
if (ret < 0)
pr_notice("%s: psy type failed, ret = %d\n",
__func__, ret);
return ret;
}
propval.intval = chg_type;
ret = power_supply_set_property(chrdet_psy,
POWER_SUPPLY_PROP_CHARGE_TYPE, &propval);
if (ret < 0)
pr_notice("%s: psy type failed, ret(%d)\n", __func__, ret);
propval.intval = chg_online;
ret = power_supply_set_property(chrdet_psy, POWER_SUPPLY_PROP_ONLINE,
&propval);
if (ret < 0)
pr_notice("%s: psy online failed, ret(%d)\n", __func__, ret);
return ret;
}
4、拔掉充电器执行的流程也是类似,可以自行分析,这里我们对整个识别过程做一个总结:
首先是注册了pmic VCDT引脚的中断,当有充电器插入时会触发这个中断函数,在这个中断函数里面会去获取系统的开机模式,检测充电器的类型,最后更新节点信息,告诉上层当前充电器的类型。