基于 bq25601的充電IC驅(qū)動(dòng)調(diào)試
作者: arunboy
在原有展訊平臺(tái)下面的bq25601的基礎(chǔ)上編寫(xiě)mtk平臺(tái)下的bq25601代碼,參考mtk平臺(tái)下的.并進(jìn)行相關(guān)調(diào)試.
充電IC的移植是在kernel和lk里面,lk里面是mt_battery.c中調(diào)用了以下幾個(gè)函數(shù)
#if?defined(MTK_BQ25601_SUPPORT) ????bq25601_hw_init(); ????bq25601_charging_enable(bEnable); ????bq25601_dump_register(); #endif
kernel里面在power/mt6735/Makefile中
ifeq?($(CONFIG_MTK_BQ25601_SUPPORT),y) ????????????????????obj-$(CONFIG_MTK_SMART_BATTERY)?+=?bq25601.o?charging_hw_bq25601.o
首先參考兩個(gè)代碼新建了一個(gè)文件,把一些接口函數(shù)進(jìn)行了替換.然后查看數(shù)據(jù)手冊(cè)修改數(shù)組,寄存器的值.
圖中的數(shù)組都是查看數(shù)據(jù)手冊(cè)然后進(jìn)行填充,下面那些使用字母的因?yàn)樵趧e的文件中定義了數(shù)字.
電池充電有三個(gè)階段:預(yù)充電階段,恒流充電,恒壓充電.
預(yù)充電階段:設(shè)置充電電流一般為500mA以下
恒流充電階段:電壓一般在3.2~4.1v左右,充電器的輸入電壓會(huì)越來(lái)越高
恒壓充電階段:4.2v左右,充電ic輸出電壓不變,電流逐漸減小.
驅(qū)動(dòng)代碼分析
1.bq25601.c
/********************************************************** ??* ??*???[I2C?Slave?Setting] ??* ??*********************************************************/ #define?bq25601_SLAVE_ADDR_WRITE???0xD6//根據(jù)數(shù)據(jù)手冊(cè)i2c的地址是0x6b,左移一位以后得到0xd6 #define?bq25601_SLAVE_ADDR_READ????0xD7 static?struct?i2c_client?*new_client; static?const?struct?i2c_device_id?bq25601_i2c_id[]?=?{?{"bq25601",?0},?{}?}; kal_bool?chargin_hw_init_done?=?KAL_FALSE; static?int?bq25601_driver_probe(struct?i2c_client?*client,?const?struct?i2c_device_id?*id); #ifdef?CONFIG_OF static?const?struct?of_device_id?bq25601_of_match[]?=?{ ????{.compatible?=?"bq25601",}, ????{}, }; MODULE_DEVICE_TABLE(of,?bq25601_of_match); #endif static?struct?i2c_driver?bq25601_driver?=?{ ????.driver?=?{ ???????????.name?=?"bq25601", #ifdef?CONFIG_OF ???????????.of_match_table?=?bq25601_of_match, #endif ???????????}, ????.probe?=?bq25601_driver_probe, ????.id_table?=?bq25601_i2c_id, };
2.charging_hw_bq25601.c
//充電的一些初始化的值,根據(jù)數(shù)據(jù)手冊(cè)的某個(gè)寄存的的某位代表的什么意思進(jìn)行設(shè)值. static?unsigned?int?charging_hw_init(void?*data) { ????unsigned?int?status?=?STATUS_OK; ????battery_log(BAT_LOG_CRTI,?"charging_hw_init!n"); ????bq25601_set_en_hiz(0x0); ????bq25601_set_vindpm(0x8);????/*?VIN?DPM?check?4.70V?*/ ????//bq25601_set_vindpm(0x0); ????bq25601_set_reg_rst(0x0); ????bq25601_set_wdt_rst(0x1);???/*?Kick?watchdog?*/ ????bq25601_set_sys_min(0x5);???/*?Minimum?system?voltage?3.5V?*/ ????bq25601_set_iprechg(0x7);???/*?Precharge?current?480mA?*/ ????bq25601_set_iterm(0x1);?/*?Termination?current?120mA?*/ ????bq25601_set_vreg(0x0B);?/*?VREG?4.208V?*/ ????bq25601_set_min_vbat_sel(0x0);??/*?BATLOWV?2.8V?*/ ????bq25601_set_vrechg(0x0);????/*?VRECHG?0.1V?(4.108V)?*/ ????bq25601_set_en_term(0x1);???/*?Enable?termination?*/ ????bq25601_set_watchdog(0x1);??/*?WDT?40s?*/ ????bq25601_set_en_timer(0x0);??/*?Disable?charge?timer?*/ ????bq25601_set_vindpm_int(0x0);????/*?Disable?fault?vindpm?interrupt?*/ ????bq25601_set_iindpm_int(0x0);????/*?Disable?fault?iindpm?interrupt?*/ ????bq25601_set_ovp(0x3); ????return?status; }
然后把這幾個(gè)函數(shù)進(jìn)行填充完整就行,根據(jù)項(xiàng)目需求,有的不需要.
charging_func[CHARGING_CMD_INIT]?=?charging_hw_init; ????????charging_func[CHARGING_CMD_DUMP_REGISTER]?=?charging_dump_register; ????????charging_func[CHARGING_CMD_ENABLE]?=?charging_enable; ????????charging_func[CHARGING_CMD_SET_CV_VOLTAGE]?=?charging_set_cv_voltage; ????????charging_func[CHARGING_CMD_GET_CURRENT]?=?charging_get_current; ????????charging_func[CHARGING_CMD_SET_CURRENT]?=?charging_set_current; ????????charging_func[CHARGING_CMD_SET_INPUT_CURRENT]?=?charging_set_input_current; ????????charging_func[CHARGING_CMD_GET_CHARGING_STATUS]?=??charging_get_charging_status; ????????charging_func[CHARGING_CMD_RESET_WATCH_DOG_TIMER]?=?charging_reset_watch_dog_timer; ????????charging_func[CHARGING_CMD_SET_HV_THRESHOLD]?=?charging_set_hv_threshold; ????????charging_func[CHARGING_CMD_GET_HV_STATUS]?=?charging_get_hv_status; ????????charging_func[CHARGING_CMD_GET_BATTERY_STATUS]?=?charging_get_battery_status; ????????charging_func[CHARGING_CMD_GET_CHARGER_DET_STATUS]?=?charging_get_charger_det_status; ????????charging_func[CHARGING_CMD_GET_CHARGER_TYPE]?=?charging_get_charger_type; ????????charging_func[CHARGING_CMD_SET_PLATFORM_RESET]?=?charging_set_platform_reset; ????????charging_func[CHARGING_CMD_GET_PLATFORM_BOOT_MODE]?=?charging_get_platform_boot_mode; ????????charging_func[CHARGING_CMD_SET_POWER_OFF]?=?charging_set_power_off; ????????charging_func[CHARGING_CMD_SET_TA_CURRENT_PATTERN]?=?charging_set_ta_current_pattern; ????????charging_func[CHARGING_CMD_SET_ERROR_STATE]?=?charging_set_error_state; ????????charging_func[CHARGING_CMD_DISO_INIT]?=?charging_diso_init; ????????charging_func[CHARGING_CMD_GET_DISO_STATE]?=?charging_get_diso_state; ????????charging_func[CHARGING_CMD_SET_VBUS_OVP_EN]?=?charging_set_vbus_ovp_en; ????????charging_func[CHARGING_CMD_SET_VINDPM]?=?charging_set_vindpm;
主要記錄兩個(gè)函數(shù),i2c的讀寫(xiě)數(shù)據(jù)的函數(shù):
int?bq25601_read_byte(unsigned?char?cmd,?unsigned?char?*returnData) { ????char?cmd_buf[1]?=?{?0x00?}; ????char?readData?=?0; ????int?ret?=?0; ????mutex_lock(&bq25601_i2c_access); ????/*?new_client->addr?=?((new_client->addr)?&?I2C_MASK_FLAG)?|?I2C_WR_FLAG;?*/ ????new_client->ext_flag?= ????????((new_client->ext_flag)?&?I2C_MASK_FLAG)?|?I2C_WR_FLAG?|?I2C_DIRECTION_FLAG; ????cmd_buf[0]?=?cmd; ????ret?=?i2c_master_send(new_client,?&cmd_buf[0],?(1?<<?8?|?1)); ????if?(ret?<?0)?{ ????????/*?new_client->addr?=?new_client->addr?&?I2C_MASK_FLAG;?*/ ????????new_client->ext_flag?=?0; ????????mutex_unlock(&bq25601_i2c_access); ????????return?0; ????} ????readData?=?cmd_buf[0]; ????*returnData?=?readData; ????/*?new_client->addr?=?new_client->addr?&?I2C_MASK_FLAG;?*/ ????new_client->ext_flag?=?0; ????mutex_unlock(&bq25601_i2c_access); ????return?1; } int?bq25601_write_byte(unsigned?char?cmd,?unsigned?char?writeData) { ????char?write_data[2]?=?{?0?}; ????int?ret?=?0; ????mutex_lock(&bq25601_i2c_access); ????write_data[0]?=?cmd; ????write_data[1]?=?writeData; ????new_client->ext_flag?=?((new_client->ext_flag)?&?I2C_MASK_FLAG)?|?I2C_DIRECTION_FLAG; ????ret?=?i2c_master_send(new_client,?write_data,?2); ????if?(ret?<?0)?{ ????????new_client->ext_flag?=?0; ????????mutex_unlock(&bq25601_i2c_access); ????????return?0; ????} ????new_client->ext_flag?=?0; ????mutex_unlock(&bq25601_i2c_access); ????return?1; }
3.對(duì)于lk里面,就是實(shí)現(xiàn) ? bq25601_hw_init(),bq25601_charging_enable(bEnable),bq25601_dump_register()這三個(gè)函數(shù),基本上和kernel里面的差不多.
4.參考數(shù)據(jù)手冊(cè)幾個(gè)有關(guān)充電IC的參數(shù)
Termination Current ? ? 截止電流,一般設(shè)置為200mA以下
Charge Voltage ? ? ? ? ? ? ?充電IC的輸出電壓
Precharge current ? ? ? ? ?預(yù)充電電流,一般設(shè)置為500mA以下
VAG OVP 最高電壓,bq25601可以支持到14v
Absolute VINDPM Threshold 充電IC的最高輸出
總結(jié)
編寫(xiě)調(diào)試驅(qū)動(dòng)代碼一定要認(rèn)真,特別注意宏定義,加上了沒(méi),有沒(méi)有把以前的宏定義注釋掉,而且要查看一下有沒(méi)有在Makefile,Kconfig中添加修改,報(bào)錯(cuò)的話要看錯(cuò)誤提示,然后去查錯(cuò)誤類型,有的報(bào)的這個(gè)地方的錯(cuò)誤但是錯(cuò)誤不在這個(gè)文件當(dāng)中.
kernel-3.18/arch/arm64/boot/dts/project_bat_setting.dtsi可以配置電池曲線,充電屬性等相關(guān)配置.注意還有一個(gè)電阻值的配置,如果與硬件不匹配,會(huì)導(dǎo)致誤差較大.
問(wèn)題
pmic檢測(cè)充電器狀態(tài)不對(duì),改用了通過(guò)讀取充電IC的寄存器的狀態(tài)來(lái)判斷是否在充電.查尋datasheet后可以看到在REG08里面讀取.
添加如下檢測(cè)代碼:
????stat?=?bq25601_get_vbus_stat(); ????if?(stat?==?0x1?||?stat?==?0x2) ????????val?=?KAL_TRUE; ????else ????????val?=?KAL_FALSE;
充電IC的配置
1 device下面的配置
2 kernel 里面的config和dts(i2c地址) ? PS:盡量保證user版和debug版一塊修改.
3 lk里面的config
4 preloader里面的config ?
END