mtk充电器插拔检测

以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设备状态更新
}
  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值