基于 bq25601的充电IC驱动调试
扫描二维码
随时随地手机看文章
作者: arunboy
在原有展讯平台下面的bq25601的基础上编写mtk平台下的bq25601代码,参考mtk平台下的.并进行相关调试.
充电IC的移植是在kernel和lk里面,lk里面是mt_battery.c中调用了以下几个函数
#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
首先参考两个代码新建了一个文件,把一些接口函数进行了替换.然后查看数据手册修改数组,寄存器的值.
图中的数组都是查看数据手册然后进行填充,下面那些使用字母的因为在别的文件中定义了数字.
电池充电有三个阶段:预充电阶段,恒流充电,恒压充电.
预充电阶段:设置充电电流一般为500mA以下
恒流充电阶段:电压一般在3.2~4.1v左右,充电器的输入电压会越来越高
恒压充电阶段:4.2v左右,充电ic输出电压不变,电流逐渐减小.
驱动代码分析
1.bq25601.c
/********************************************************** * * [I2C Slave Setting] * *********************************************************/ #define bq25601_SLAVE_ADDR_WRITE 0xD6//根据数据手册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
//充电的一些初始化的值,根据数据手册的某个寄存的的某位代表的什么意思进行设值. 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; }
然后把这几个函数进行填充完整就行,根据项目需求,有的不需要.
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;
主要记录两个函数,i2c的读写数据的函数:
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.对于lk里面,就是实现 bq25601_hw_init(),bq25601_charging_enable(bEnable),bq25601_dump_register()这三个函数,基本上和kernel里面的差不多.
4.参考数据手册几个有关充电IC的参数
Termination Current 截止电流,一般设置为200mA以下
Charge Voltage 充电IC的输出电压
Precharge current 预充电电流,一般设置为500mA以下
VAG OVP 最高电压,bq25601可以支持到14v
Absolute VINDPM Threshold 充电IC的最高输出
总结
编写调试驱动代码一定要认真,特别注意宏定义,加上了没,有没有把以前的宏定义注释掉,而且要查看一下有没有在Makefile,Kconfig中添加修改,报错的话要看错误提示,然后去查错误类型,有的报的这个地方的错误但是错误不在这个文件当中.
kernel-3.18/arch/arm64/boot/dts/project_bat_setting.dtsi可以配置电池曲线,充电属性等相关配置.注意还有一个电阻值的配置,如果与硬件不匹配,会导致误差较大.
问题
pmic检测充电器状态不对,改用了通过读取充电IC的寄存器的状态来判断是否在充电.查寻datasheet后可以看到在REG08里面读取.
添加如下检测代码:
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