以mt6357 pmic为例,充电器插拔检测和类型检测在mt6357-charger-type.c下完成:
一、首先从pmic的probe开始分析:
static int mt6357_charger_type_probe(struct platform_device *pdev)
{
struct mtk_charger_type *info;
struct iio_channel *chan_vbus;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
int ret = 0;
pr_notice("%s: starts\n", __func__);
chan_vbus = devm_iio_channel_get(
&pdev->dev, "pmic_vbus"); //dts中pmic_vbus设备节点读取,通过adc读取vcdt引脚上的分压电压(充电器电压)来识别并触发中断,
if (IS_ERR(chan_vbus)) {
pr_notice("mt6357 charger type requests probe deferral ret:%d\n",
chan_vbus);
return -EPROBE_DEFER;
}
info = devm_kzalloc(&pdev->dev, sizeof(*info),
GFP_KERNEL);
if (!info)
return -ENOMEM;
info->chip = (struct mt6397_chip *)dev_get_drvdata( //pmic私有数据获取
pdev->dev.parent);
info->regmap = info->chip->regmap;
dev_set_drvdata(&pdev->dev, info);
info->pdev = pdev;
mutex_init(&info->ops_lock);
check_boot_mode(info, &pdev->dev);
info->psy_desc.name = "mtk_charger_type"; //一些私有数据赋值
info->psy_desc.type = POWER_SUPPLY_TYPE_UNKNOWN;
info->psy_desc.properties = chr_type_properties;
info->psy_desc.num_properties = ARRAY_SIZE(chr_type_properties);
info->psy_desc.get_property = psy_chr_type_get_property;
info->psy_desc.set_property = psy_chr_type_set_property;
info->psy_desc.property_is_writeable =
psy_charger_type_property_is_writeable;
info->psy_desc.usb_types = mt6357_charger_usb_types,
info->psy_desc.num_usb_types = ARRAY_SIZE(mt6357_charger_usb_types),
info->psy_cfg.drv_data = info;
info->psy_cfg.of_node = np;
info->psy_cfg.supplied_to = mt6357_charger_supplied_to;
info->psy_cfg.num_supplicants = ARRAY_SIZE(mt6357_charger_supplied_to);
info->ac_desc.name = "ac";
info->ac_desc.type = POWER_SUPPLY_TYPE_MAINS;
info->ac_desc.properties = mt_ac_properties;
info->ac_desc.num_properties = ARRAY_SIZE(mt_ac_properties);
info->ac_desc.get_property = mt_ac_get_property;
info->ac_cfg.drv_data = info;
info->usb_desc.name = "usb";
info->usb_desc.type = POWER_SUPPLY_TYPE_USB;
info->usb_desc.properties = mt_usb_properties;
info->usb_desc.num_properties = ARRAY_SIZE(mt_usb_properties);
info->usb_desc.get_property = mt_usb_get_property;
info->usb_cfg.drv_data = info;
info->psy = power_supply_register(&pdev->dev, &info->psy_desc, //注册此pmic设备为psy设备
&info->psy_cfg);
if (IS_ERR(info->psy)) {
pr_notice("%s Failed to register power supply: %ld\n",
__func__, PTR_ERR(info->psy));
return PTR_ERR(info->psy);
}
pr_notice("%s register psy success\n", __func__);
info->chan_vbus = devm_iio_channel_get( //再次读取该psy设备信息
&pdev->dev, "pmic_vbus");
if (IS_ERR_OR_NULL(info->chan_vbus)) {
pr_notice("chan_vbus auxadc get fail, ret=%d\n",
PTR_ERR(info->chan_vbus));
}
if (of_property_read_u32(np, "bc12_active", &info->bc12_active) < 0) //bc1.2使能,bc检测使能
pr_notice("%s: no bc12_active\n", __func__);
pr_notice("%s: bc12_active:%d\n", __func__, info->bc12_active);
if (info->bc12_active) {
info->ac_psy = power_supply_register(&pdev->dev, //注册ac psy设备
&info->ac_desc, &info->ac_cfg);
if (IS_ERR(info->ac_psy)) {
pr_notice("%s Failed to register power supply: %ld\n",
__func__, PTR_ERR(info->ac_psy));
return PTR_ERR(info->ac_psy);
}
info->usb_psy = power_supply_register(&pdev->dev, //注册usb psy设备
&info->usb_desc, &info->usb_cfg);
if (IS_ERR(info->usb_psy)) {
pr_notice("%s Failed to register power supply: %ld\n",
__func__, PTR_ERR(info->usb_psy));
return PTR_ERR(info->usb_psy);
}
INIT_WORK(&info->chr_work, do_charger_detection_work); //这里初始化了一个do_charger_detection_work任务,做插拔检测
schedule_work(&info->chr_work);
ret = devm_request_threaded_irq(&pdev->dev, //这里注册了一个chrdet_int_handler中断,触发方式是边沿触发,插入充电器和拔出,首先会执行这个中断函数
platform_get_irq_byname(pdev, "chrdet"), NULL,
chrdet_int_handler, IRQF_TRIGGER_HIGH, "chrdet", info);
if (ret < 0)
pr_notice("%s request chrdet irq fail\n", __func__);
}
info->first_connect = true;
pr_notice("%s: done\n", __func__);
return 0;
}
下面分解看它的中断函数和检测函数:
二、chrdet_int_handler函数:
irqreturn_t chrdet_int_handler(int irq, void *data)
{
struct mtk_charger_type *info = data;
unsigned int chrdet = 0;
chrdet = bc11_get_register_value(info->regmap, //bc1.2读取pmic CHRDET寄存器值,来判断是否使能检测充电器
PMIC_RGS_CHRDET_ADDR,
PMIC_RGS_CHRDET_MASK,
PMIC_RGS_CHRDET_SHIFT);
if (!chrdet) {
hw_bc11_done(info); //pmic寄存器操作
/* 8 = KERNEL_POWER_OFF_CHARGING_BOOT */
/* 9 = LOW_POWER_OFF_CHARGING_BOOT */
if (info->bootmode == 8 || info->bootmode == 9) { //boot mode判断,关机充电或者低压充电
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(); //系统下点
#endif
}
}
pr_notice("%s: chrdet:%d\n", __func__, chrdet);
do_charger_detect(info, chrdet); //这里会去做充电器是否在位和类型判断
return IRQ_HANDLED;
}
三、do_charger_detection_work:
static void do_charger_detection_work(struct work_struct *data)
{
//container_of: 通过已知的一个数据结构成员指针data,数据结构类型mtk_charger_type,以及这个成员指针在这个数据结构中的成员名chr_work,来获取指向这个数据结构的指针mtk_charger_type *
struct mtk_charger_type *info = (struct mtk_charger_type *)container_of(
data, struct mtk_charger_type, chr_work);
unsigned int chrdet = 0;
chrdet = bc11_get_register_value(info->regmap, //bc1.2读取pmic CHRDET寄存器值,来判断是否使能检测充电器
PMIC_RGS_CHRDET_ADDR,
PMIC_RGS_CHRDET_MASK,
PMIC_RGS_CHRDET_SHIFT);
pr_notice("%s: chrdet:%d\n", __func__, chrdet);
if (chrdet)
do_charger_detect(info, chrdet); //这里会去做充电器是否在位和类型判断
else {
hw_bc11_done(info);
/* 8 = KERNEL_POWER_OFF_CHARGING_BOOT */
/* 9 = LOW_POWER_OFF_CHARGING_BOOT */
if (info->bootmode == 8 || info->bootmode == 9) {
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();
#endif
}
}
}
四、do_charger_detect:
这个函数会在do_charger_detection_work和chrdet_int_handler都去调用,主要是做psy设备状态改变之后的通知动作
;
void do_charger_detect(struct mtk_charger_type *info, bool en)
{
union power_supply_propval prop, prop2, prop3;
int ret = 0;
#ifndef CONFIG_TCPC_CLASS
if (!mt_usb_is_device()) { //通过usb phy识别和确认是usb设备
pr_info("charger type: UNKNOWN, Now is usb host mode. Skip detection\n");
return;
}
#endif
prop.intval = en;
if (en) {
ret = power_supply_set_property(info->psy, //spy设备online属性设置
POWER_SUPPLY_PROP_ONLINE, &prop);
ret = power_supply_get_property(info->psy, //psy类型获取
POWER_SUPPLY_PROP_TYPE, &prop2);
ret = power_supply_get_property(info->psy, //usb类型获取
POWER_SUPPLY_PROP_USB_TYPE, &prop3);
} else {
prop2.intval = POWER_SUPPLY_TYPE_UNKNOWN;
prop3.intval = POWER_SUPPLY_USB_TYPE_UNKNOWN;
info->psy_desc.type = POWER_SUPPLY_TYPE_UNKNOWN;
info->type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
}
pr_notice("%s type:%d usb_type:%d\n", __func__, prop2.intval, prop3.intval);
if(en &&(prop3.intval ==1 || prop3.intval ==3)) { //usb类型
mt_usb_connect();
} else {
mt_usb_disconnect();
}
power_supply_changed(info->psy); //这里做psy设备状态更新
}