MTK快充驱动分析
一.bq24296快充芯片驱动
kernel-3.10/drivers/misc/mediatek/power/mt6735/charging_hw_bq24296.c
1.给上一层提供的函数
kal_int32 chr_control_interface(CHARGING_CTRL_CMD cmd, void *data)
{
kal_int32 status;
if(cmd < CHARGING_CMD_NUMBER)
status = charging_func[cmd](data);
else
return STATUS_UNSUPPORTED;
return status;
}
static kal_uint32 (* const charging_func[CHARGING_CMD_NUMBER])(void *data)=
{
charging_hw_init
,charging_dump_register
,charging_enable
,charging_set_cv_voltage
,charging_get_current
,charging_set_current
,charging_set_input_current
,charging_get_charging_status
,charging_reset_watch_dog_timer
,charging_set_hv_threshold
,charging_get_hv_status
,charging_get_battery_status
,charging_get_charger_det_status
,charging_get_charger_type
,charging_get_is_pcm_timer_trigger
,charging_set_platform_reset
,charging_get_platfrom_boot_mode
,charging_set_power_off
,charging_get_power_source
,charging_get_csdac_full_flag
,charging_set_ta_current_pattern
,charging_set_error_state
,charging_diso_init
,charging_get_diso_state
};
这些函数的实现主要调用 kernel-3.10/drivers/misc/mediatek/power/mt6735/bq24296.c 里面通过I2C操作bq快充芯片。
还有一些函数调用PMIC(mt6328的接口)的函数Upmu_common.c (kernel-3.10\drivers\misc\mediatek\power\mt6735)中的
pmic_set_register_value();
pmic_get_register_value();
设置相应的寄存器,寄存器在const PMU_FLAG_TABLE_ENTRY pmu_flags_table[]= {
{PMIC_THR_DET_DIS, MT6328_PMIC_THR_DET_DIS_ADDR, MT6328_PMIC_THR_DET_DIS_MASK, MT6328_PMIC_THR_DET_DIS_SHIFT},
}
里面相应的地址和地址偏移在Upmu_hw.h (kernel-3.10\drivers\misc\mediatek\mach\mt6735\include\mach)
//mask is HEX; shift is Integer
#define MT6328_PMIC_THR_DET_DIS_ADDR MT6328_STRUP_CON0#define MT6328_PMIC_THR_DET_DIS_MASK 0x1#define MT6328_PMIC_THR_DET_DIS_SHIFT 0
2.电源核心调用Battery_common.c (kernel-3.10\drivers\power\mediatek)
static void get_charging_control(void)
{
battery_charging_control = chr_control_interface;
}
二.快充核心驱动分析
Switch_charging.c (kernel-3.10\drivers\power\mediatek)
1.static BATTERY_VOLTAGE_ENUM select_jeita_cv(void) //设置充满时候的电压
2.PMU_STATUS do_jeita_state_machine(void) //获取温度
cv_voltage = select_jeita_cv(); //获取对应温度的充电截止电压
battery_charging_control(CHARGING_CMD_SET_CV_VOLTAGE, &cv_voltage); //调用bq296的相应函数
3.static void set_jeita_charging_current(void) //设置充电电流,jeita的
4. get_usb_current_unlimited //得到不受限制的情况
5. set_usb_current_unlimited //设置电流不受限制
6.kal_uint32 set_bat_charging_current_limit(int current_limit) //设置电池限制电流
pchr_turn_on_charging();
battery_charging_control(CHARGING_CMD_INIT, NULL); //初始化bq快充芯片
battery_charging_control(CHARGING_CMD_SET_CURRENT,&g_temp_CC_value); //设置电流,前面有一堆判断
battery_charging_control(CHARGING_CMD_ENABLE, &charging_enable); //使能快充充电
7.static kal_uint32 charging_full_check(void) //检测电池是否充满
battery_charging_control(CHARGING_CMD_GET_CHARGING_STATUS, &status);
8.mt_battery_charging_algorithm //充电不同阶段操作的不同的函数
switch (BMT_status.bat_charging_state)
case CHR_PRE: //预充电
BAT_PreChargeModeAction();
select_charging_curret(); //选择合适电流
battery_charging_control(CHARGING_CMD_ENABLE, &charging_enable); //启动充电
pchr_turn_on_charging(); //开始充电
case CHR_CC:
BAT_ConstantCurrentModeAction(); //恒流充电
pchr_turn_on_charging(); //开始充电
case CHR_BATFULL:
BAT_BatteryFullAction();
if (charging_full_check() == KAL_FALSE) //如果没有充满就继续
继续充电
battery_meter_reset(); //
case CHR_HOLD:
BAT_BatteryHoldAction();
charging_enable = KAL_FALSE;
battery_charging_control(CHARGING_CMD_ENABLE, &charging_enable); //停止充电
case CHR_ERROR:
BAT_BatteryStatusFailAction();
if ((g_temp_status == TEMP_ABOVE_POS_60) || (g_temp_status == TEMP_BELOW_NEG_10))
/* Disable charger */
charging_enable = KAL_FALSE;
battery_charging_control(CHARGING_CMD_ENABLE, &charging_enable); //停止充电
三.充电核心Battery_common.c (kernel-3.10\drivers\power\mediatek),初始化
主要结构体
/* ac_data initialization */
static struct wireless_data wireless_main = {
.psy = {
.name = "wireless",
.type = POWER_SUPPLY_TYPE_WIRELESS,
.properties = wireless_props,
.num_properties = ARRAY_SIZE(wireless_props),
.get_property = wireless_get_property,
},
.WIRELESS_ONLINE = 0,
};
static struct ac_data ac_main = {
.psy = {
.name = "ac",
.type = POWER_SUPPLY_TYPE_MAINS,
.properties = ac_props,
.num_properties = ARRAY_SIZE(ac_props),
.get_property = ac_get_property,
},
.AC_ONLINE = 0,
};
static struct usb_data usb_main = {
.psy = {
.name = "usb",
.type = POWER_SUPPLY_TYPE_USB,
.properties = usb_props,
.num_properties = ARRAY_SIZE(usb_props),
.get_property = usb_get_property,
},
.USB_ONLINE = 0,
};
static struct battery_data battery_main = {
.psy = {
.name = "battery",
.type = POWER_SUPPLY_TYPE_BATTERY,
.properties = battery_props,
.num_properties = ARRAY_SIZE(battery_props),
.get_property = battery_get_property,
},
battery_probe
ret = alloc_chrdev_region(&adc_cali_devno, 0, 1, ADC_CALI_DEVNAME); //分配“MT_pmic_adc_cali”设备号
adc_cali_cdev->ops = &adc_cali_fops; //注册操作函数
ret = cdev_add(adc_cali_cdev, adc_cali_devno, 1); //注册
adc_cali_class = class_create(THIS_MODULE, ADC_CALI_DEVNAME); //注册/sys/class/mtk-adc-cali节点
class_dev = (struct class_device *)device_create(adc_cali_class, NULL, adc_cali_devno, NULL, ADC_CALI_DEVNAME); //生成/sys/class/mtk-adc-cali/mtk-adc-cali节点
get_charging_control();
battery_charging_control = chr_control_interface; //得到charging_hw_bq24296.c中的函数数组
ret = power_supply_register(&(dev->dev), &ac_main.psy); // //注册到/sys/class/power_supply/ac/节点
ret = power_supply_register(&(dev->dev), &usb_main.psy); //注册到/sys/class/power_supply/usb/节点
ret = power_supply_register(&(dev->dev), &wireless_main.psy); //注册到/sys/class/power_supply/wireless/节点
ret = power_supply_register(&(dev->dev), &battery_main.psy); // //注册到/sys/class/power_supply/battery/节点
device_create_file(&(dev->dev), &dev_attr_ADC_Channel_0_Slope); ///sys/class/mtk-adc-cali/mtk-adc-cali/ADC_Channel_0_Slope节点,这里有很多
battery_kthread_hrtimer_init(); ///* battery kernel thread for 10s check and charger in/out event */
ktime = ktime_set(1, 0);/* 3s, 10* 1000 ms */
hrtimer_init(&battery_kthread_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
battery_kthread_timer.function = battery_kthread_hrtimer_func; //单独分析
hrtimer_start(&battery_kthread_timer, ktime, HRTIMER_MODE_REL);
kthread_run(bat_thread_kthread, NULL, "bat_thread_kthread"); //执行内核线程bat_thread_kthread,单独分析
charger_hv_detect_sw_workaround_init //单独分析
四.周期检测Battery_common.c (kernel-3.10\drivers\power\mediatek)(10s)
bat_thread_kthread
if(is_charger_detection_rdy()==KAL_FALSE) //如果没有插入充电
wait_event(bat_thread_wq, (is_charger_detection_rdy()==KAL_TRUE)); //等待插入充电
if (((chargin_hw_init_done == KAL_TRUE) && (battery_suspended == KAL_FALSE)) //充电装置初始化完成,电池不是休眠状态
|| ((chargin_hw_init_done == KAL_TRUE) && (fg_wake_up_bat == KAL_TRUE))) ////充电装置初始化完成,电池被电量计唤醒
BAT_thread
if (battery_meter_initilized == KAL_FALSE) { //如果没有初始化
battery_meter_initial();/* move from battery_probe() to decrease booting time */ 初始化
硬件电量计SOC_BY_HW_FG,后面分析
BMT_status.nPercent_ZCV = battery_meter_get_battery_nPercent_zcv(); //电池电压-容量关系曲线-ZCV曲线,这里是3.7V
mt_battery_charger_detect_check(); //检测充电器是否存在
mt_battery_GetBatteryData //得到电池的数据
battery_meter_get_battery_voltage //得到电池电压
battery_meter_get_VSense //得到vsense
battery_meter_get_charging_current(); //如果在充电,得到充电的电流
battery_meter_get_charger_voltage //充电电压
battery_meter_get_battery_temperature //得到电池温度
battery_meter_get_tempV //
battery_meter_get_tempR //
battery_meter_get_battery_percentage //电池的充电百分比
battery_meter_get_battery_zcv //得到电池的容量-电压表
mt_battery_average_method(BATTERY_AVG_CURRENT //平均电流
mt_battery_average_method(BATTERY_AVG_VOLT //平均电压
mt_battery_average_method(BATTERY_AVG_TEMP //平均温度
check_battery_exist //查看电池是否存在
mt_battery_thermal_check //如果大于65度就停止充电重启
mt_battery_notify_check //电池提醒的一些检查
mt_battery_CheckBatteryStatus //检测下电池的状态是否正常
mt_battery_charging_algorithm //改变充电算法,调用Switch_charging.c中的函数
mt_battery_update_status //更新状态
usb_update(&usb_main); //都是/sys/class/power_supply/下的节点
ac_update(&ac_main);
wireless_update(&wireless_main);
battery_update(&battery_main);
mt_kpoc_power_off_check //低电量,就关机
wait_event(bat_thread_wq, (bat_thread_timeout == KAL_TRUE)); //等待唤醒
hrtimer_start(&battery_kthread_timer, ktime, HRTIMER_MODE_REL);
ktime = ktime_set(BAT_TASK_PERIOD, 0); //设置10s后运行定时器
battery_meter_reset
bat_get_ui_percentage //得到电压百分比
reset_parameter_car //
battery_meter_ctrl(BATTERY_METER_CMD_HW_RESET, NULL); //重启下
reset_parameter_dod_full //不知道什么工作
battery_kthread_hrtimer_init
ktime = ktime_set(1, 0); //一秒钟
hrtimer_init(&battery_kthread_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
battery_kthread_timer.function = battery_kthread_hrtimer_func; //回调函数
hrtimer_start(&battery_kthread_timer, ktime, HRTIMER_MODE_REL); //将一个hrtimer加入到一个按照到期时间排序的红黑树
1s钟后执行battery_kthread_hrtimer_func
bat_thread_wakeup
wake_up(&bat_thread_wq); //唤醒等待变量
总结:
没10s中就会运行高精度定时器,然后唤醒bat_thread_kthread里面的等待变量,然后主要是执行BAT_thread,检测一些状态
五.提示charger_hv_detect_sw_workaround_init Battery_common.c (kernel-3.10\drivers\power\mediatek)
charger_hv_detect_sw_workaround_init
ktime_set(0, BAT_MS_TO_NS(2000)); //0.2s
hrtimer_init(&charger_hv_detect_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
charger_hv_detect_timer.function = charger_hv_detect_sw_workaround;
wake_up_interruptible(&charger_hv_detect_waiter);
hrtimer_start(&charger_hv_detect_timer, ktime, HRTIMER_MODE_REL);
charger_hv_detect_thread = kthread_run(charger_hv_detect_sw_thread_handler, 0, "mtk charger_hv_detect_sw_workaround"); //运行
check_battery_exist(); //检测电池是否存在
运行的线程charger_hv_detect_sw_thread_handler
if (BMT_status.charger_exist == KAL_TRUE) //电池存在就是0.02秒
{
ktime = ktime_set(0, BAT_MS_TO_NS(200));
}
else
{
ktime = ktime_set(0, BAT_MS_TO_NS(1000)); //不存在就是0.1s
}
battery_charging_control(CHARGING_CMD_SET_HV_THRESHOLD, &hv_voltage); //设置充电器的最大电压
wait_event_interruptible(charger_hv_detect_waiter, (charger_hv_detect_flag == KAL_TRUE)); //等待变量
charger_plug_out_sw_mode
enable=pmic_get_register_value(PMIC_RG_CHR_EN); //如果在充电
ICharging=battery_meter_get_charging_current_imm();
VCharger=battery_meter_get_charger_voltage();
if(ICharging<70 && VCharger<4400) //如果电流小于70,或者电压少于4400,
battery_charging_control(CHARGING_CMD_ENABLE, &charging_enable); //如果三此都是电流小于70,或者电压少于4400,停止充电
hrtimer_start(&charger_hv_detect_timer, ktime, HRTIMER_MODE_REL); //开始启动定时器
总结:
如果是有电池就是0.02进行一次,如果是没有电池就0.1s进行一次,看看是否可以充电。
六.提示相关Battery_common.c (kernel-3.10\drivers\power\mediatek)
static const struct file_operations battery_cmd_proc_fops = {
.open = proc_utilization_open,
.read = seq_read,
.write = battery_cmd_write,
};
static const struct file_operations current_cmd_proc_fops = {
.open = proc_utilization_open_cur_stop,
.read = seq_read,
.write = current_cmd_write,
};
static const struct file_operations discharging_cmd_proc_fops = {
.open = proc_utilization_open,
.read = seq_read,
.write = discharging_cmd_write,
};
mt_batteryNotify_probe
ret_device_file = device_create_file(&(dev->dev), &dev_attr_BatteryNotify); //读写g_BatteryNotifyCode这个值, /sys/bus/platform/devices/mt-battery/BatteryNotify
ret_device_file = device_create_file(&(dev->dev), &dev_attr_BN_TestMode); //读写g_BN_TestMode这个值, /sys/bus/platform/devices/mt-battery/BN_TestMode
battery_dir = proc_mkdir("mtk_battery_cmd", NULL); //创建/proc/mtk_battery_cmd目录
proc_create("battery_cmd", S_IRUGO | S_IWUSR, battery_dir, &battery_cmd_proc_fops); //proc/mtk_battery_cmd/battery_cmd节点
if (sscanf(desc, "%d %d %d", &bat_tt_enable, &bat_thr_test_mode, &bat_thr_test_value) == 3) { //上层写下这几个变量,并赋值
g_battery_thermal_throttling_flag = bat_tt_enable;
battery_cmd_thermal_test_mode = bat_thr_test_mode;
battery_cmd_thermal_test_mode_value = bat_thr_test_value;
proc_create("current_cmd", S_IRUGO | S_IWUSR, battery_dir, ¤t_cmd_proc_fops); //proc/mtk_battery_cmd/current_cmd节点
if (sscanf(desc, "%d %d", &cmd_current_unlimited, &cmd_discharging) == 2) { //限制充电电流,并进行开关闭充电
set_usb_current_unlimited(cmd_current_unlimited); //
battery_charging_control(CHARGING_CMD_ENABLE, &charging_enable);
proc_create("discharging_cmd", S_IRUGO | S_IWUSR, battery_dir, &discharging_cmd_proc_fops); //proc/mtk_battery_cmd/discharging_cmd节点
if (sscanf(desc, "%d %d", &charging_enable, &adjust_power) //赋值这两个变量,进行充电或者调整
battery_dts_probe
platform_device_register(&battery_device); //导致battery_probe调用
mt_batteryNotify_dts_probe
platform_device_register(&MT_batteryNotify_device); //导致mt_batteryNotify_probe调用
七.Battery_meter.c (kernel-3.10\drivers\power\mediatek)
battery_meter_probe
battery_meter_ctrl = bm_ctrl_cmd; //得到Battery_meter_hal.c (kernel-3.10\drivers\misc\mediatek\power\mt6735)的操作函数
strcpy(temp_strptr, saved_command_line); //得到uboot的参数
strcat(temp_strptr, " androidboot.mode=charger"); //追加字符串
saved_command_line = temp_strptr;
init_proc_log_fg //初始化电量计log
proc_create("fgadc_log", 0644, NULL, &fgadc_proc_fops); //
proc_create("fgadc_log", 0644, NULL, &fgadc_proc_fops); //创建proc/fgadc_log节点,设置是否打印log
ret_device_file = device_create_file(&(dev->dev), &dev_attr_FG_Current); //生成sys/devices/platform/battery_meter/FG_Current等一系列节点
battery_meter_initial
#if defined(SOC_BY_HW_FG)
1.defined(SOC_BY_HW_FG),有硬件FG的情况
fgauge_initialization();
ret = battery_meter_ctrl(BATTERY_METER_CMD_HW_FG_INIT, NULL); /* 1. HW initialization */
fgauge_initialization
pmic_set_register_value(PMIC_RG_FGADC_ANA_CK_PDN,0); //使能模拟
pmic_set_register_value(PMIC_RG_FGADC_DIG_CK_PDN,0); //使能数字
ret=pmic_config_interface(MT6328_FGADC_CON0, 0x0028, 0x00FF, 0x0); //Set current mode, auto-calibration mode and 32KHz clock source
pmic_config_interface(MT6328_FGADC_CON0, 0x0029, 0x00FF, 0x0); //Enable FGADC
pmic_config_interface(MT6328_FGADC_CON0, 0x7100, 0xFF00, 0x0); //reset HW FG
fgauge_read_current(¤t_temp); //读取电流值,能够读取到说明完成初始化
pmic_config_interface(MT6328_FGADC_CON0, 0x0200, 0xFF00, 0x0); //读取命令,读取之后并进行运算和补偿
battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_OCV, &gFG_voltage); //SW algorithm initialization */
read_hw_ocv
get_hw_ocv
adc_result_reg = pmic_get_register_value(PMIC_AUXADC_ADC_OUT_WAKEUP_PCHR); 、、获得开路电压
battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT, &gFG_current); //获得电流
battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CAR, &gFG_columb); //从电量计得到电量的库伦
force_get_tbat //得到电池温度,经过计算得到
battery_meter_ctrl(BATTERY_METER_CMD_GET_ADC_V_BAT_TEMP, &bat_temperature_volt); //得到电池温度的ADC电压值
battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT, &fg_current_temp); //从库伦计得到电池电流
battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT_SIGN, &fg_current_state); //从库伦计得到电池电流指示
fgauge_read_capacity
battery_meter_get_battery_voltage(KAL_TRUE);
battery_meter_ctrl(BATTERY_METER_CMD_GET_ADC_V_BAT_SENSE, &val); //得到电池的sense电压从硬件上
force_get_tbat(KAL_FALSE); //得到电池温度
fgauge_get_dod0 //DOD意思就是放80%的电量,就是得到放了百分之多少电
fgauge_get_profile_r_table(TEMPERATURE_T); //根据温度得到阻值
r_profile_t0 //Cust_battery_meter_table.h (kernel-3.10\drivers\misc\mediatek\mach\mt6735\ck3_01\power
fgauge_get_profile //根据温度得到电压和百分比的数组
battery_profile_t0 //Cust_battery_meter_table.h (kernel-3.10\drivers\misc\mediatek\mach\mt6735\ck3_01\power)
进行一些计算和补偿,
/* Use DOD0 and columb counter to calculate capacity */ 得到电池容量
dvalue = fgauge_update_dod();/* DOD1 = DOD0 + (-CAR)/Qmax */ //得到电池放电深度
fgauge_get_Q_max(gFG_temp); //得到不同温度的电池容量
fgauge_get_Q_max_high_current(gFG_temp); //得带高锻炼的时候的电池容量
pmic_register_interrupt_callback(41,fg_bat_int_handler); //电池插入后中断
wake_up_bat2();
wake_up(&bat_thread_wq); //也就是运行bat_thread_kthread,检测电池,前面有分析
pmic_register_interrupt_callback(40,fg_bat_int_handler); //电池插入后中断
![](https://img2020.cnblogs.com/blog/2060378/202011/2060378-20201125155236268-1972638598.png)
fgauge_algo_run_init(); //初始化算法
/*stop charging for vbat measurement*/
battery_charging_control(CHARGING_CMD_ENABLE,&charging_enable);
battery_meter_get_battery_voltage
battery_meter_ctrl(BATTERY_METER_CMD_GET_ADC_V_BAT_SENSE, &val); //得到isense电压
battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT, &gFG_current); //得到FG电流
battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT_SIGN, &gFG_Is_Charging); //得到电流标记
fgauge_compensate_battery_voltage_recursion //递归得到FG的电池电压的补偿
battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CAR, &gFG_columb); //得到FG容量
/* 1.1 Average FG_voltage */
/* 1.2 Average FG_current */
/* 2. Calculate battery capacity by VBAT */
/* 3. Calculate battery capacity by Coulomb Counter */
/* 4. update DOD0 */
2.defined(SOC_BY_SW_FG)软件FG的情况
table_init();
force_get_tbat(KAL_FALSE); //这里没有做什么事情
/* Re-constructure r-table profile according to current temperature */
profile_p_r_table = fgauge_get_profile_r_table(TEMPERATURE_T); //根据温度得到r_profile_t*,也就是电阻值
fgauge_construct_r_table_profile //构想电阻table
/* Re-constructure battery profile according to current temperature */
profile_p = fgauge_get_profile(TEMPERATURE_T); 再一次得到table
fgauge_construct_battery_profile(temperature, profile_p); //并再次计算
oam_init();
/*stop charging for vbat measurement */
battery_charging_control(CHARGING_CMD_ENABLE, &charging_enable);
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_OCV, &gFG_voltage); //OCV
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_ADC_V_BAT_SENSE, &g_booting_vbat); //isensor
gFG_capacity_by_v = fgauge_read_capacity_by_v(gFG_voltage); //通过电压查表得到容量
dod_init(); //放电深度
battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_OCV, &gFG_voltage); //得到OCV,开路电压
gFG_capacity_by_v = fgauge_read_capacity_by_v(gFG_voltage); //查表得到FG容量
/* compare with hw_ocv & sw_ocv, check if less than or equal to 5% tolerance */
gFG_15_vlot = fgauge_read_v_by_capacity((100 - g_tracking_point)); //从电池容量得到%15的电压
fgauge_get_Q_max(force_get_tbat(KAL_FALSE)); //根据温度得到容量
fgauge_read_v_by_d(gFG_DOD0); //根据放电深度得到电压
fgauge_read_r_bat_by_v(gFG_voltage); //根据电压得到电阻值