#define __SPIN_LOCK_UNLOCKED(lockname) \ (spinlock_t ) __SPIN_LOCK_INITIALIZER(lockname)
#define ATOMIC_NOTIFIER_INIT(name) { \
.lock = __SPIN_LOCK_UNLOCKED(name.lock), \
.head = NULL }
#define ATOMIC_NOTIFIER_HEAD(name) \
struct atomic_notifier_head name = \
ATOMIC_NOTIFIER_INIT(name)
ATOMIC_NOTIFIER_HEAD(power_supply_notifier); 展开为:
struct atomic_notifier_head power_supply_notifier = {
.lock = (spinlock_t ) __SPIN_LOCK_INITIALIZER(power_supply_notifier.lock)
.head = NULL }
};
struct atomic_notifier_head {
spinlock_t lock;
struct notifier_block __rcu *head;
};
ATOMIC_NOTIFIER_HEAD(power_supply_notifier); //struct atomic_notifier_head
EXPORT_SYMBOL_GPL(power_supply_notifier);
int atomic_notifier_chain_register(struct atomic_notifier_head *nh, struct notifier_block *n)
int srcu_notifier_chain_register(struct srcu_notifier_head *nh, struct notifier_block *n)
static int notifier_chain_register(struct notifier_block **nl, struct notifier_block *n) //static函数,外部不能使用
================================================================
int register_charger_manager_notifier(struct charger_consumer *consumer, struct notifier_block *nb)
->struct charger_manager *info = consumer->cm;
->srcu_notifier_chain_register(&info->evt_nh, nb);
->notifier_chain_register(&nh->head, n);
int power_supply_reg_notifier(struct notifier_block *nb)
->atomic_notifier_chain_register(&power_supply_notifier, nb);
->notifier_chain_register(&nh->head, n);
power_supply_changed_work
atomic_notifier_call_chain(&power_supply_notifier, PSY_EVENT_PROP_CHANGED, psy);
int atomic_notifier_call_chain(struct atomic_notifier_head *nh,unsigned long val, void *v)
================================================================
struct charger_manager {
... ...
struct charger_device *chg1_dev;
struct notifier_block chg1_nb;
struct charger_data chg1_data;
struct charger_consumer *chg1_consumer;
enum charger_type chr_type;
... ...
struct srcu_notifier_head evt_nh;
... ...
}
struct mt_charger
->struct chg_type_info *cti;
->struct charger_consumer *chg_consumer;
struct charger_consumer
->void *cm; //pinfo
static struct charger_manager *pinfo;
static struct list_head consumer_head = LIST_HEAD_INIT(consumer_head);
mtk_charger_probe //mtk_charger.c
->struct charger_manager *info = NULL;
->info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
->pinfo = info;
->kthread_run(charger_routine_thread, info, "charger_thread");
->if (of_property_read_string(np, "algorithm_name", &info->algorithm_name) < 0) {
info->algorithm_name = "SwitchCharging"; //如果没找到相应的节点,那么直接赋值
->mtk_charger_parse_dt(info, &pdev->dev);
->info->algorithm_name = "SwitchCharging";
->mtk_switch_charging_init(info);
->info->chg1_dev = get_charger_by_name("primary_chg");
->info->algorithm_data = swch_alg;
->info->do_algorithm = mtk_switch_charging_run;
->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; //mtk_switch_charging.c
->info->change_current_setting = mtk_switch_charging_current;
->mtk_charger_init_timer(info);
->kthread_run(charger_routine_thread, info, "charger_thread");
->info->chg1_nb.notifier_call = info->do_event;
->register_charger_device_notifier(info->chg1_dev, &info->chg1_nb);
->srcu_notifier_chain_register(&chg_dev->evt_nh, nb);
->notifier_chain_register(&nh->head, n);
->charger_dev_set_drvdata(info->chg1_dev, info);
->info->psy_nb.notifier_call = charger_psy_event; //mtk_charger.c
->power_supply_reg_notifier(&info->psy_nb);
->atomic_notifier_chain_register(&power_supply_notifier, nb);
->notifier_chain_register(&nh->head, n);
->srcu_init_notifier_head(&info->evt_nh);
->info->chg1_consumer = charger_manager_get_by_name(&pdev->dev, "charger_port1");
->struct charger_consumer *puser;
->puser->cm = pinfo;
->info->init_done = true;
->_wake_up_charger(info);
//通过power_supply_reg_notifier注册的内核通知链,在power_supply_changed的时候都会被回调
battery_probe //mtk_battery.c
->mtk_battery_init(pdev);
->mtk_power_misc_init(pdev);
->kthread_run(power_misc_routine_thread, &sdc, "power_misc_thread");
->sdc.psy_nb.notifier_call = mtk_power_misc_psy_event; //主要功能为获取"battery"的power_supply POWER_SUPPLY_PROP_TEMP //mtk_power_misc.c
->power_supply_reg_notifier(&sdc.psy_nb);
->gm.pbat_consumer = charger_manager_get_by_name(&(pdev->dev), "charger");
->if (gm.pbat_consumer != NULL) {
->gm.bat_nb.notifier_call = battery_callback; //只有中断时由mtk_charger_int_handler()调用,主要功能为battery_update(&battery_main); //mtk_battery.c
->register_charger_manager_notifier(gm.pbat_consumer, &gm.bat_nb);
->srcu_notifier_chain_register(&info->evt_nh, nb);
->notifier_chain_register(&nh->head, n);
mt_charger_probe //mtk_chg_type_det.c
->struct chg_type_info *cti = NULL;
->struct mt_charger *mt_chg = NULL;
->mt_chg = devm_kzalloc(&pdev->dev, sizeof(*mt_chg), GFP_KERNEL);
->cti = devm_kzalloc(&pdev->dev, sizeof(*cti), GFP_KERNEL);
->cti->chg_consumer = charger_manager_get_by_name(cti->dev,"charger_port1");
->mt_chg->cti = cti;
struct hl7019d_info
->struct charger_device *chg_dev
static int hl7019d_driver_probe(struct i2c_client *client, const struct i2c_device_id *id)
->struct hl7019d_info *info = NULL;
->info = devm_kzalloc(&client->dev, sizeof(struct hl7019d_info), GFP_KERNEL);
->info->chg_dev = charger_device_register(info->chg_dev_name, &client->dev, info, &hl7019d_chg_ops, &info->chg_props);
->struct charger_device *chg_dev = NULL;
->struct srcu_notifier_head *head = NULL;
->chg_dev = kzalloc(sizeof(*chg_dev), GFP_KERNEL);
->head = &chg_dev->evt_nh;
->srcu_init_notifier_head(head);
===========================================
static struct charger_manager *pinfo;
charger_manager_notifier(pinfo, CHARGER_NOTIFY_STOP_CHARGING)
charger_manager_notifier(pinfo, CHARGER_NOTIFY_START_CHARGING);
中断调用流程:
/kernel-4.14/drivers/misc/mediatek/pmic/mt6390/v1/pmic_chr_type_det_v2.c
pmic_chr_type_det_v2.c pmic_chrdet_init
->chrdet_int_handler
->pmic_set_register_value(PMIC_RG_USBDL_RST, 1);
->do_charger_detect()
->mtk_pmic_enable_chr_type_det(pmic_get_register_value(PMIC_RGS_CHRDET))
->if (!mt_usb_is_device()) { return;}
->g_chr_type = hw_charging_get_charger_type(); //获取充电类型
->chrdet_inform_psy_changed(g_chr_type, 1);
power_supply_core.c ->static struct power_supply *chrdet_psy = power_supply_get_by_name("charger"); //pmic_chrdet_init(void)
->power_supply_set_property(chrdet_psy, POWER_SUPPLY_PROP_ONLINE, &propval)
->power_supply_set_property(chrdet_psy, POWER_SUPPLY_PROP_CHARGE_TYPE, &propval)
->psy->desc->set_property //psy->desc = &mt_chg->chg_desc
mtk_chg_type_det.c ->mt_charger_set_property //mt_chg->chg_desc.set_property = mt_charger_set_property
->switch (psp) {
->case POWER_SUPPLY_PROP_ONLINE:
->mt_charger_online(mtk_chg);
->if (!mtk_chg->chg_online) { //如果充电器不存在
->boot_mode = get_boot_mode();
->if (boot_mode == KERNEL_POWER_OFF_CHARGING_BOOT || boot_mode == LOW_POWER_OFF_CHARGING_BOOT) {
->kernel_power_off() //如果是关机充电模式,则关机
->orderly_poweroff(true) //使用这个,上面的没作用
->case POWER_SUPPLY_PROP_CHARGE_TYPE:
->mtk_chg->chg_type = val->intval; //将g_chr_type保存在struct mt_charger *mtk_chg,以供mt_get_charger_type()使用
->queue_work(cti->chg_in_wq, &cti->chg_in_work); //INIT_WORK(&cti->chg_in_work, charger_in_work_handler);
->charger_in_work_handler
mtk_charger.c ->mtk_charger_int_handler
->charger_manager_notifier(pinfo, CHARGER_NOTIFY_STOP_CHARGING); //if (mt_get_charger_type() == CHARGER_UNKNOWN) {
->charger_manager_notifier(pinfo, CHARGER_NOTIFY_START_CHARGING); //else
notifier.c ->srcu_notifier_call_chain(&info->evt_nh, event, NULL); //int srcu_notifier_call_chain(struct srcu_notifier_head*nh, unsigned long val, void *v)
->battery_callback
->_wake_up_charger(pinfo)
->wake_up(&info->wait_que)
->charger_routine_thread
->chr_err("Vbat=%d,Ibat=%d,I=%d,VChr=%d,T=%d,Soc=%d:%d,CT:%d:%d hv:%d pd:%d:%d\n",
->is_charger_on = mtk_is_charger_on(info)
->chr_type = mt_get_charger_type(); //去拿充电类型
->return mtk_chg->chg_type;
->if (chr_type == CHARGER_UNKNOWN && info->chr_type != CHARGER_UNKNOWN) {
->mtk_charger_plug_out(info);
->info->plug_out(info);
mtk_switch_charging.c ->int mtk_switch_charging_plug_out(struct charger_manager *info)
->info->chg1_dev = get_charger_by_name("primary_chg"); //int mtk_switch_charging_init(struct charger_manager *info)
charger_class.c ->charger_dev_set_input_current(info->chg1_dev, 100000);
->charger_dev_plug_out(info->chg1_dev);
->chg_dev->ops->plug_out(chg_dev)
->else if (info->chr_type == CHARGER_UNKNOWN)
->mtk_charger_plug_in(info, chr_type);
->info->plug_in(info)
mtk_switch_charging.c ->int mtk_switch_charging_plug_in(struct charger_manager *info)
->info->chg1_dev = get_charger_by_name("primary_chg") //int mtk_switch_charging_init(struct charger_manager *info)
charger_class.c ->charger_dev_set_input_current(info->chg1_dev, info->chg1_data.input_current_limit);
->charger_dev_plug_in(info->chg1_dev);
->chg_dev->ops->plug_in(chg_dev)
->charger_update_data(info) //检查电池温度
->check_battery_exist(info)
->check_dynamic_mivr(info)
->charger_check_status(info)
->kpoc_power_off_check(info)
->if (is_charger_on == true) {
->info->do_algorithm(info);
->mtk_switch_charging_run(struct charger_manager *info)
->struct switch_charging_alg_data *swchgalg = info->algorithm_data
->switch (swchgalg->state) {
->case CHR_CC:
->mtk_switch_chr_cc(info)
->swchg_turn_on_charging(info)
->swchg_select_charging_current_limit(info) //如果不是META_BOOT
->struct charger_data *pdata = &info->chg1_data;
->charger_dev_set_input_current(info->chg1_dev, pdata->input_current_limit)
->chg_dev->ops->set_input_current(chg_dev, uA)
->charger_dev_set_charging_current(info->chg1_dev, pdata->charging_current_limit)
->chg_dev->ops->set_charging_current(chg_dev, uA)
->/*If thermal current limit is larger than charging IC's minimum current setting, enable the charger immediately*/
->charger_dev_enable(info->chg1_dev, true);
->charger_dev_enable(info->chg1_dev, charging_enable)
->chg_dev->ops->enable(chg_dev, en)
->charger_dev_dump_registers(info->chg1_dev);
->chg_dev->ops->dump_registers(chg_dev)
->wakeup_sc_algo_cmd(&pinfo->sc.data, SC_EVENT_CHARGING, 0);
->if (is_charger_on == false) {
->wakeup_sc_algo_cmd(&pinfo->sc.data, SC_EVENT_STOP_CHARGING, 0);
mtk_battery_core.c ->fg_charger_in_handler
mtk_chg_type_det.c ->mt_get_charger_type
mtk_battery.c ->wakeup_fg_algo_atomic(FG_INTR_CHARGER_IN)
power_supply_core.c ->power_supply_changed(mtk_chg->ac_psy);
->schedule_work(&psy->changed_work)
->power_supply_changed(mtk_chg->usb_psy);
->schedule_work(&psy->changed_work) //INIT_WORK(&psy->changed_work, power_supply_changed_work);
->power_supply_changed_work(struct work_struct *work)
notifier.c ->atomic_notifier_call_chain(&power_supply_notifier, PSY_EVENT_PROP_CHANGED, psy);
->__atomic_notifier_call_chain(nh, val, v, -1, NULL)
->notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
mtk_power_misc.c ->mtk_power_misc_psy_event(struct notifier_block *nb, unsigned long event, void *v)
->if (strcmp(psy->desc->name, "battery") == 0) {
->psy->desc->get_property(psy, POWER_SUPPLY_PROP_TEMP, &val);
mtk_battery.c ->int battery_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val)
dts Code \kernel-4.14\arch\arm64\boot\dts\mediatek\mt8168.dtsi
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | | /* /kernel-4.14/drivers/power/supply/mediatek/battery/mtk_battery.c */ bat_gm30: battery { compatible = "mediatek,bat_gm30"; }; mt6357_gauge { compatible = "mediatek,mt6357_gauge"; gauge_name = "gauge"; alias_name = "MT6357"; }; /* kernel-4.14/drivers/power/supply/mediatek/charger/mtk_chg_type_det.c */ mt_charger: mt_charger { compatible = "mediatek,mt-charger"; };
lk_charger: lk_charger { compatible = "mediatek,lk_charger"; enable_anime; enable_pe_plus; power_path_support; max_charger_voltage = <6500000>; fast_charge_voltage = <3000000>;
/* charging current */ usb_charger_current = <500000>; ac_charger_current = <2050000>; ac_charger_input_current = <3200000>; non_std_ac_charger_current = <500000>; charging_host_charger_current = <1500000>; ta_ac_charger_current = <3000000>; pd_charger_current = <500000>;
/* battery temperature protection */ temp_t4_threshold = <50>; temp_t3_threshold = <45>; temp_t1_threshold = <0>; }; /* kernel-4.14\drivers\misc\mediatek\pmic\mt6390\v1\mt6390_charger.c */ mt6390_charger { compatible = "mediatek,mt6390_charger"; charger_name = "primary_chg"; //mtk_linear_charging.c mtk_linear_charging_init 保存到struct charger_manager *info->struct charger_device *chg1_dev alias_name = "mt6390"; ichg = <500000>; /* uA */ cv = <4200000>; /* uV */ vcdt_hv_thres = <7000000>; /* uV */ vbat_ov_thres = <4450000>; /* uV */ }; /* kernel-4.14/drivers/power/supply/mediatek/charger/mtk_charger.c */ charger: charger { compatible = "mediatek,charger"; algorithm_name = "LinearCharging"; //mtk_charger.c mtk_charger_parse_dt->mtk_linear_charging_init /* enable_sw_jeita; */ enable_pe_plus; enable_type_c; power_path_support; |
C Code /kernel-4.14/drivers/power/supply/mediatek/charger/mtk_charger.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | | static int mtk_charger_probe(struct platform_device *pdev) { struct charger_manager *info = NULL; struct list_head *pos; struct list_head *phead = &consumer_head; struct charger_consumer *ptr; int ret;
chr_err("%s: starts\n", __func__);
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM;
pinfo = info;
platform_set_drvdata(pdev, info); //(&pdev->dev)->driver_data = info; info->pdev = pdev; mtk_charger_parse_dt(info, &pdev->dev); //从dts获取客制化充电电流、电压、并调用mtk_linear_charging_init初始化
mutex_init(&info->charger_lock); mutex_init(&info->charger_pd_lock); mutex_init(&info->cable_out_lock); atomic_set(&info->enable_kpoc_shdn, 1); wakeup_source_init(&info->charger_wakelock, "charger suspend wakelock"); spin_lock_init(&info->slock);
/* init thread */ init_waitqueue_head(&info->wait_que); //初始化等待队列 info->polling_interval = CHARGING_INTERVAL; info->enable_dynamic_cv = true;
info->chg1_data.thermal_charging_current_limit = -1; info->chg1_data.thermal_input_current_limit = -1; info->chg1_data.input_current_limit_by_aicl = -1; info->chg2_data.thermal_charging_current_limit = -1; info->chg2_data.thermal_input_current_limit = -1;
info->sw_jeita.error_recovery_flag = true;
mtk_charger_init_timer(info); //初始化定时器
kthread_run(charger_routine_thread, info, "charger_thread"); //开启充电线程
if (info->chg1_dev != NULL && info->do_event != NULL) { info->chg1_nb.notifier_call = info->do_event; register_charger_device_notifier(info->chg1_dev, &info->chg1_nb); charger_dev_set_drvdata(info->chg1_dev, info); }
info->psy_nb.notifier_call = charger_psy_event; power_supply_reg_notifier(&info->psy_nb);
srcu_init_notifier_head(&info->evt_nh); ret = mtk_charger_setup_files(pdev); if (ret) chr_err("Error creating sysfs interface\n");
info->pd_adapter = get_adapter_by_name("pd_adapter"); if (info->pd_adapter) chr_err("Found PD adapter [%s]\n", info->pd_adapter->props.alias_name); else chr_err("*** Error : can't find PD adapter ***\n");
if (mtk_pe_init(info) < 0) info->enable_pe_plus = false;
if (mtk_pe20_init(info) < 0) info->enable_pe_2 = false;
if (mtk_pe40_init(info) == false) info->enable_pe_4 = false;
mtk_pdc_init(info); charger_ftm_init(); mtk_charger_get_atm_mode(info);
#ifdef CONFIG_MTK_CHARGER_UNLIMITED info->usb_unlimited = true; info->enable_sw_safety_timer = false; charger_dev_enable_safety_timer(info->chg1_dev, false); #endif
charger_debug_init();
mutex_lock(&consumer_mutex); list_for_each(pos, phead) { ptr = container_of(pos, struct charger_consumer, list); ptr->cm = info; if (ptr->pnb != NULL) { srcu_notifier_chain_register(&info->evt_nh, ptr->pnb); ptr->pnb = NULL; } } mutex_unlock(&consumer_mutex); info->chg1_consumer = charger_manager_get_by_name(&pdev->dev, "charger_port1"); info->init_done = true; _wake_up_charger(info);
return 0; }
static const struct of_device_id mtk_charger_of_match[] = { {.compatible = "mediatek,charger",}, {}, }; MODULE_DEVICE_TABLE(of, mtk_charger_of_match);
static struct platform_driver charger_driver = { .probe = mtk_charger_probe, .remove = mtk_charger_remove, .shutdown = mtk_charger_shutdown, .driver = { .name = "charger", .of_match_table = mtk_charger_of_match, }, };
static int __init mtk_charger_init(void) { return platform_driver_register(&charger_driver); } late_initcall(mtk_charger_init);
static void __exit mtk_charger_exit(void) { platform_driver_unregister(&charger_driver); } module_exit(mtk_charger_exit);
MODULE_AUTHOR("wy.chuang <wy.chuang@mediatek.com>"); MODULE_DESCRIPTION("MTK Charger Driver"); MODULE_LICENSE("GPL"); |
C Code /kernel-4.14/drivers/power/supply/mediatek/charger/mtk_charger.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | | static int mtk_charger_parse_dt(struct charger_manager *info, struct device *dev) { struct device_node *np = dev->of_node; u32 val;
chr_err("%s: starts\n", __func__);
if (!np) { chr_err("%s: no device node\n", __func__); return -EINVAL; }
if (of_property_read_string(np, "algorithm_name", //读取"mediatek,charger"节点内,algorithm_name子节点的名字 &info->algorithm_name) < 0) { chr_err("%s: no algorithm_name name\n", __func__); info->algorithm_name = "SwitchCharging"; //如果没有读取到,则默认为"SwitchCharging" }
if (strcmp(info->algorithm_name, "SwitchCharging") == 0) { chr_err("found SwitchCharging\n"); mtk_switch_charging_init(info); } #ifdef CONFIG_MTK_DUAL_CHARGER_SUPPORT if (strcmp(info->algorithm_name, "DualSwitchCharging") == 0) { pr_debug("found DualSwitchCharging\n"); mtk_dual_switch_charging_init(info); } #endif if (strcmp(info->algorithm_name, "LinearCharging") == 0) { pr_info("%s: LinearCharging\n", __func__); mtk_linear_charging_init(info); } ... } |
C Code /kernel-4.14/drivers/power/supply/mediatek/charger/mtk_linear_charging.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | | int mtk_linear_charging_init(struct charger_manager *info) { struct linear_charging_alg_data *algo_data;
algo_data = devm_kzalloc(&info->pdev->dev, sizeof(*algo_data), GFP_KERNEL); if (!algo_data) return -ENOMEM;
info->chg1_dev = get_charger_by_name("primary_chg"); //struct charger_device *chg1_dev; 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");
info->algorithm_data = algo_data; mtk_linear_charger_parse_dt(info);
mutex_init(&algo_data->ichg_access_mutex);
info->do_algorithm = mtk_linear_charging_run; info->plug_in = mtk_linear_charging_plug_in; info->plug_out = mtk_linear_charging_plug_out; info->do_charging = mtk_linear_charging_do_charging; info->do_event = linear_charger_dev_event; info->change_current_setting = mtk_linear_charging_current;
return 0; } |
C Code /kernel-4.14/drivers/power/supply/mediatek/charger/charger_class.c
1 2 3 4 5 6 7 8 9 10 11 12 13 | | struct charger_device *get_charger_by_name(const char *name) { struct device *dev;
if (!name) return (struct charger_device *)NULL; dev = class_find_device(charger_class, NULL, name, charger_match_device_by_name);
return dev ? to_charger_device(dev) : NULL;
} EXPORT_SYMBOL(get_charger_by_name); |
触发中断函数chrdet_int_handler
C Code /kernel-4.14/drivers/misc/mediatek/include/mt-plat/mt8168/include/mach/upmu_sw.h
1 2 3 4 5 6 7 8 9 10 | | /*============================================================================= * PMIC IRQ ENUM define *============================================================================= */ enum PMIC_IRQ_ENUM { ... INT_CHRDET, //53 INT_CHRDET_EDGE, //54 ... } |
C Code /kernel-4.14/drivers/misc/mediatek/pmic/mt6390/v1/pmic_chr_type_det_v2.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | | static struct power_supply *chrdet_psy; 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 //CONFIG_TCPC_CLASS is not set pmic_register_interrupt_callback(INT_CHRDET_EDGE, chrdet_int_handler); pmic_enable_interrupt(INT_CHRDET_EDGE, 1, "PMIC"); #endif
return 0; }
late_initcall(pmic_chrdet_init); |
C Code /kernel-4.14/drivers/misc/mediatek/pmic/mt6390/v1/pmic_chr_type_det_v2.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | | /* 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) orderly_poweroff(true); #else return; #endif } } pmic_set_register_value(PMIC_RG_USBDL_RST, 1);
do_charger_detect(); } |
/kernel-4.14/drivers/misc/mediatek/pmic/mt6390/v1/pmic_chr_type_det_v2.c
1 2 3 4 5 6 7 8 | /* 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); } |
/kernel-4.14/drivers/misc/mediatek/pmic/mt6390/v1/pmic_chr_type_det_v2.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | void mtk_pmic_enable_chr_type_det(bool en) { #ifndef CONFIG_TCPC_CLASS //CONFIG_TCPC_CLASS is not set if (!mt_usb_is_device()) { //判断是否为OTG模式 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) { if (is_meta_mode()) { /* 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); } } else { pr_info("charger type: charger OUT\n"); //充电器拔出 g_chr_type = CHARGER_UNKNOWN; chrdet_inform_psy_changed(g_chr_type, 0); }
mutex_unlock(&chrdet_lock); } |
/kernel-4.14/drivers/usb/mtu3/mtu3_dr.c
1 2 3 4 5 6 7 8 9 10 | bool mt_usb_is_device(void) { int host_state = extcon_get_state(g_extcon_edev, EXTCON_USB_HOST);
if (host_state == 1) return false;
return true; } EXPORT_SYMBOL_GPL(mt_usb_is_device); |
/kernel-4.14/drivers/misc/mediatek/pmic/mt6390/v1/pmic_chr_type_det_v2.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 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; } |
/kernel-4.14/drivers/power/supply/power_supply_core.c
1 2 3 4 5 6 7 8 9 10 | int power_supply_set_property(struct power_supply *psy, enum power_supply_property psp, const union power_supply_propval *val) { if (atomic_read(&psy->use_cnt) <= 0 || !psy->desc->set_property) return -ENODEV;
return psy->desc->set_property(psy, psp, val); } EXPORT_SYMBOL_GPL(power_supply_set_property); |
那么chrdet_psy是什么呢?
/kernel-4.14/drivers/misc/mediatek/pmic/mt6390/v1/pmic_chr_type_det_v2.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | static struct power_supply *chrdet_psy; //全局变量 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 //CONFIG_TCPC_CLASS is not set pmic_register_interrupt_callback(INT_CHRDET_EDGE, chrdet_int_handler); pmic_enable_interrupt(INT_CHRDET_EDGE, 1, "PMIC"); #endif
return 0; }
late_initcall(pmic_chrdet_init); |
/kernel-4.14/drivers/power/supply/power_supply_core.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | /* exported for the APM Power driver, APM emulation */ struct class *power_supply_class; EXPORT_SYMBOL_GPL(power_supply_class);
static int power_supply_match_device_by_name(struct device *dev, const void *data) { const char *name = data; struct power_supply *psy = dev_get_drvdata(dev);
return strcmp(psy->desc->name, name) == 0; }
struct power_supply *power_supply_get_by_name(const char *name) { struct power_supply *psy = NULL; struct device *dev = class_find_device(power_supply_class, NULL, name, power_supply_match_device_by_name);
if (dev) { psy = dev_get_drvdata(dev); atomic_inc(&psy->use_cnt); }
return psy; } EXPORT_SYMBOL_GPL(power_supply_get_by_name);
static int __init power_supply_class_init(void) { power_supply_class = class_create(THIS_MODULE, "power_supply");
if (IS_ERR(power_supply_class)) return PTR_ERR(power_supply_class);
power_supply_class->dev_uevent = power_supply_uevent; power_supply_init_attrs(&power_supply_dev_type);
return 0; } subsys_initcall(power_supply_class_init); |
其实chrdet_psy是mt_charger_probe中注册的struct power_supply *chg_psy,其中struct power_supply_desc chg_desc.name = "charger";
在注册mt_charger_det_init平台驱动时,在mt_charger_probe会调用power_supply_register,然后赋值psy->desc = desc (实际上就是chrdet_psy->desc = &mt_chg->chg_desc)
而mt_chg->chg_desc.set_property = mt_charger_set_property
所以chrdet_psy->desc->set_property就能找到了
C Code /kernel-4.14/drivers/power/supply/mediatek/charger/mtk_chg_type_det.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | | static const struct of_device_id mt_charger_match[] = { { .compatible = "mediatek,mt-charger", }, { }, }; static struct platform_driver mt_charger_driver = { .probe = mt_charger_probe, .remove = mt_charger_remove, .driver = { .name = "mt-charger-det", .owner = THIS_MODULE, .pm = &mt_charger_pm_ops, .of_match_table = mt_charger_match, }, }; static s32 __init mt_charger_det_init(void) { return platform_driver_register(&mt_charger_driver); }
static void __exit mt_charger_det_exit(void) { platform_driver_unregister(&mt_charger_driver); }
subsys_initcall(mt_charger_det_init); module_exit(mt_charger_det_exit); |
C Code /kernel-4.14/drivers/power/supply/mediatek/charger/mtk_chg_type_det.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | | struct mt_charger { struct device *dev; struct power_supply_desc chg_desc; struct power_supply_config chg_cfg; struct power_supply *chg_psy; struct power_supply_desc ac_desc; struct power_supply_config ac_cfg; struct power_supply *ac_psy; struct power_supply_desc usb_desc; struct power_supply_config usb_cfg; struct power_supply *usb_psy; struct chg_type_info *cti; #ifdef CONFIG_EXTCON_USB_CHG struct usb_extcon_info *extcon_info; struct delayed_work extcon_work; #endif bool chg_online; /* Has charger in or not */ enum charger_type chg_type; }; |
C Code /kernel-4.14/drivers/power/supply/mediatek/charger/mtk_chg_type_det.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | | static int mt_charger_probe(struct platform_device *pdev) { int ret = 0; struct chg_type_info *cti = NULL; struct mt_charger *mt_chg = NULL; #ifdef CONFIG_EXTCON_USB_CHG struct usb_extcon_info *info; #endif
pr_info("%s\n", __func__);
mt_chg = devm_kzalloc(&pdev->dev, sizeof(*mt_chg), GFP_KERNEL); if (!mt_chg) return -ENOMEM;
mt_chg->dev = &pdev->dev; mt_chg->chg_online = false; mt_chg->chg_type = CHARGER_UNKNOWN;
mt_chg->chg_desc.name = "charger"; //这是GM3.0新增的 mt_chg->chg_desc.type = POWER_SUPPLY_TYPE_UNKNOWN; mt_chg->chg_desc.properties = mt_charger_properties; mt_chg->chg_desc.num_properties = ARRAY_SIZE(mt_charger_properties); mt_chg->chg_desc.set_property = mt_charger_set_property; mt_chg->chg_desc.get_property = mt_charger_get_property; mt_chg->chg_cfg.drv_data = mt_chg;
mt_chg->ac_desc.name = "ac"; //相当于以前battery_common.c的static struct ac_data ac_main mt_chg->ac_desc.type = POWER_SUPPLY_TYPE_MAINS; mt_chg->ac_desc.properties = mt_ac_properties; mt_chg->ac_desc.num_properties = ARRAY_SIZE(mt_ac_properties); mt_chg->ac_desc.get_property = mt_ac_get_property; mt_chg->ac_cfg.drv_data = mt_chg;
mt_chg->usb_desc.name = "usb"; //相当于以前battery_common.c的static struct usb_data usb_main mt_chg->usb_desc.type = POWER_SUPPLY_TYPE_USB; mt_chg->usb_desc.properties = mt_usb_properties; mt_chg->usb_desc.num_properties = ARRAY_SIZE(mt_usb_properties); mt_chg->usb_desc.get_property = mt_usb_get_property; mt_chg->usb_cfg.drv_data = mt_chg;
mt_chg->chg_psy = power_supply_register(&pdev->dev, &mt_chg->chg_desc, &mt_chg->chg_cfg); mt_chg->ac_psy = power_supply_register(&pdev->dev, &mt_chg->ac_desc, &mt_chg->ac_cfg); mt_chg->usb_psy = power_supply_register(&pdev->dev, &mt_chg->usb_desc, &mt_chg->usb_cfg); ... /* Init power off work */ cti->pwr_off_wq = create_singlethread_workqueue("tcpc_power_off"); INIT_WORK(&cti->pwr_off_work, tcpc_power_off_work_handler);
cti->chg_in_wq = create_singlethread_workqueue("charger_in"); INIT_WORK(&cti->chg_in_work, charger_in_work_handler); ... } |
C Code /kernel-4.14/drivers/power/supply/power_supply_core.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | | static struct power_supply *__must_check __power_supply_register(struct device *parent, const struct power_supply_desc *desc, const struct power_supply_config *cfg, bool ws) struct power_supply *psy; psy = kzalloc(sizeof(*psy), GFP_KERNEL); if (!psy) return ERR_PTR(-ENOMEM); ... psy->desc = desc; ... return psy; } |
C Code /kernel-4.14/drivers/power/supply/mediatek/charger/mtk_chg_type_det.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | | static int mt_charger_set_property(struct power_supply *psy, enum power_supply_property psp, const union power_supply_propval *val) { struct mt_charger *mtk_chg = power_supply_get_drvdata(psy); struct chg_type_info *cti; #ifdef CONFIG_EXTCON_USB_CHG struct usb_extcon_info *info; #endif
pr_info("%s\n", __func__);
if (!mtk_chg) { pr_notice("%s: no mtk chg data\n", __func__); return -EINVAL; }
#ifdef CONFIG_EXTCON_USB_CHG info = mtk_chg->extcon_info; #endif
switch (psp) { case POWER_SUPPLY_PROP_ONLINE: mtk_chg->chg_online = val->intval; mt_charger_online(mtk_chg); return 0; case POWER_SUPPLY_PROP_CHARGE_TYPE: mtk_chg->chg_type = val->intval; break; default: return -EINVAL; }
dump_charger_name(mtk_chg->chg_type);
cti = mtk_chg->cti; if (!cti->ignore_usb) { /* usb */ if ((mtk_chg->chg_type == STANDARD_HOST) || (mtk_chg->chg_type == CHARGING_HOST) || (mtk_chg->chg_type == NONSTANDARD_CHARGER)) { mt_usb_connect(); #ifdef CONFIG_EXTCON_USB_CHG info->vbus_state = 1; #endif } else { mt_usb_disconnect(); #ifdef CONFIG_EXTCON_USB_CHG info->vbus_state = 0; #endif } }
queue_work(cti->chg_in_wq, &cti->chg_in_work); #ifdef CONFIG_EXTCON_USB_CHG if (!IS_ERR(info->edev)) queue_delayed_work(system_power_efficient_wq, &info->wq_detcable, info->debounce_jiffies); #endif
power_supply_changed(mtk_chg->ac_psy); power_supply_changed(mtk_chg->usb_psy);
return 0; } |
C Code /kernel-4.14/drivers/power/supply/mediatek/charger/mtk_chg_type_det.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | | static int mt_charger_online(struct mt_charger *mtk_chg) { int ret = 0; int boot_mode = 0;
if (!mtk_chg->chg_online) { boot_mode = get_boot_mode(); if (boot_mode == KERNEL_POWER_OFF_CHARGING_BOOT || boot_mode == LOW_POWER_OFF_CHARGING_BOOT) { pr_notice("%s: Unplug Charger/USB\n", __func__); pr_notice("%s: system_state=%d\n", __func__, system_state); if (system_state != SYSTEM_POWER_OFF) kernel_power_off(); } }
return ret; } |
C Code /kernel-4.14/drivers/power/supply/mediatek/charger/mtk_chg_type_det.c
1 2 3 4 5 | | static void charger_in_work_handler(struct work_struct *work) { mtk_charger_int_handler(); //唤醒线程 fg_charger_in_handler(); //唤醒电量计 } |
C Code /kernel-4.14/drivers/power/supply/mediatek/charger/mtk_charger.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | | void mtk_charger_int_handler(void) { chr_err("%s\n", __func__);
if (pinfo == NULL) { chr_err("charger is not rdy ,skip1\n"); return; }
if (pinfo->init_done != true) { chr_err("charger is not rdy ,skip2\n"); return; }
if (mt_get_charger_type() == CHARGER_UNKNOWN) { mutex_lock(&pinfo->cable_out_lock); pinfo->cable_out_cnt++; chr_err("cable_out_cnt=%d\n", pinfo->cable_out_cnt); mutex_unlock(&pinfo->cable_out_lock); charger_manager_notifier(pinfo, CHARGER_NOTIFY_STOP_CHARGING); } else charger_manager_notifier(pinfo, CHARGER_NOTIFY_START_CHARGING);
chr_err("wake_up_charger\n"); _wake_up_charger(pinfo); } |
C Code /kernel-4.14/drivers/power/supply/mediatek/charger/mtk_charger.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | | void _wake_up_charger(struct charger_manager *info) { unsigned long flags;
if (info == NULL) return;
spin_lock_irqsave(&info->slock, flags); if (!info->charger_wakelock.active) __pm_stay_awake(&info->charger_wakelock); spin_unlock_irqrestore(&info->slock, flags); info->charger_thread_timeout = true; wake_up(&info->wait_que); //唤醒等待队列 } |
C Code /kernel-4.14/drivers/power/supply/mediatek/charger/mtk_charger.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | | static int charger_routine_thread(void *arg) { struct charger_manager *info = arg; unsigned long flags; bool is_charger_on; int bat_current, chg_current;
while (1) { wait_event(info->wait_que, //等待队列 (info->charger_thread_timeout == true));
mutex_lock(&info->charger_lock); spin_lock_irqsave(&info->slock, flags); if (!info->charger_wakelock.active) __pm_stay_awake(&info->charger_wakelock); spin_unlock_irqrestore(&info->slock, flags);
info->charger_thread_timeout = false; bat_current = battery_get_bat_current(); chg_current = pmic_get_charging_current(); chr_err("Vbat=%d,Ibat=%d,I=%d,VChr=%d,T=%d,Soc=%d:%d,CT:%d:%d hv:%d pd:%d:%d\n", battery_get_bat_voltage(), bat_current, chg_current, battery_get_vbus(), battery_get_bat_temperature(), battery_get_soc(), battery_get_uisoc(), mt_get_charger_type(), info->chr_type, info->enable_hv_charging, info->pd_type, info->pd_reset);
if (info->pd_reset == true) { mtk_pe40_plugout_reset(info); info->pd_reset = false; }
is_charger_on = mtk_is_charger_on(info);
if (info->charger_thread_polling == true) mtk_charger_start_timer(info);
charger_update_data(info); check_battery_exist(info); check_dynamic_mivr(info); charger_check_status(info); kpoc_power_off_check(info);
if (is_disable_charger() == false) { if (is_charger_on == true) { if (info->do_algorithm) info->do_algorithm(info); } } else chr_debug("disable charging\n");
spin_lock_irqsave(&info->slock, flags); __pm_relax(&info->charger_wakelock); spin_unlock_irqrestore(&info->slock, flags); chr_debug("%s end , %d\n", __func__, info->charger_thread_timeout); mutex_unlock(&info->charger_lock); }
return 0; } |