一.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); //電池插入后中斷

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); //根據電壓得到電阻值