原文网址(转载请注明出处):
源码基于:Android Q
1.查看硬件设计
我们可以看到VBAT-LEVEL管教直接接到芯片管脚上的。
2.DTS配置
电源PMIC DT配置如下:
#sl8541e-1h10wifi5g_32b-overlay.dts
&pmic_fgu {
monitored-battery = <&bat>;
sprd,calib-resistance-real = <10000>;
sprd,calib-resistance-spec = <20000>;
io-channels = <&pmic_adc 0>, <&pmic_adc 3>, <&pmic_adc 14>, <&pmic_adc 4>;
io-channel-names = "adc-batt-id", "bat-temp", "charge-vol", "chg-temp";
};
pmic_fgu是展锐提供的电量计芯片,主要是通过其ADC进行信息采集。根据硬件描述如上的adc管脚就是"chg-temp"这个配置。
2. 获取设备电压值
根据之前的描述,我们知道电量的获取主要是在sc27xx_fuel_gauge.c文件实现的。电压获取如下所示:
```cpp
bsp/kernel/kernel4.14/drivers/power/supply/sc27xx_fuel_gauge.c
static int sc27xx_fgu_get_vbat_vol(struct sc27xx_fgu_data *data, int *val)
{
int ret, vol;
ret = regmap_read(data->regmap, data->base + SC27XX_FGU_VOLTAGE, &vol);
if (ret)
return ret;
/*
* It is ADC values reading from registers which need to convert to
* corresponding voltage values.
*/
*val = sc27xx_fgu_adc_to_voltage(data, vol);
return 0;
}
我们可以参考上面的函数,去找到电压获取方式的调用代码。
3.高压电池设计
由于是高压电池,需要对比电量百分比,我们可以重新添加一个方法,让电压和电量百分比有个对应关系:
//bsp/kernel/kernel4.14/drivers/power/supply/sc27xx_fuel_gauge.c
case POWER_SUPPLY_PROP_CAPACITY:
if (val->intval == CM_BOOT_CAPACITY) {
val->intval = data->boot_cap;
break;
}
// ret = sc27xx_fgu_get_capacity(data, &value, chg_sts); //注销之前的函数
ret = sc27xx_fgu_get_vbat_for_percent(data, &value, chg_sts);
if (ret)
goto error;
SPRD_FGU_DEBUG("POWER_SUPPLY_PROP_CAPACITY value:%d", value);
val->intval = value;
break;
重新修改自己的百分比获取函数,因为没有电量计,只能根据电压值进行简单的百分比换算,如下:
//bsp/kernel/kernel4.14/drivers/power/supply/sc27xx_fuel_gauge.c
static int sc27xx_fgu_get_vbat_for_percent(struct sc27xx_fgu_data *data, int *val, int chg_sts)
{
int ret, vol, temp, voltage;
uint32_t i;
// int vat[21] = {4330, 4249, 4189, 4133, 4081, 4034, 3991, 3953, 3910, 3866, 3836, 3813, 3795, 3782, 3774, 3765, 3750, 3726, 3687, 3658, 3400}; // 根据DTS配置文件写的
int vat[21] = {4330, 4249, 4189, 4133, 4081, 4034, 3991, 3953, 3910, 3866, 3836, 3813, 3795, 3782, 3774, 3765, 3750, 3726, 3687, 930, 925}; // adc4
int percent[21] = {100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40, 35, 30, 25, 20, 15, 10, 5, 30};
ret = regmap_read(data->regmap, data->base + SC27XX_FGU_VOLTAGE, &vol);
if (ret)
return ret;
/*
* It is ADC values reading from registers which need to convert to
* corresponding voltage values.
*/
// *val = sc27xx_fgu_adc_to_voltage(data, vol);
// adc4
if (IS_ERR(data->chg_temp_cha))
{
}
else
{
ret = iio_read_channel_processed(data->chg_temp_cha, val);
SPRD_FGU_DEBUG(" sc27xx_fgu_get_vbat_for_percent val : %d \n", *val);
}
// adc4
voltage = *val;
//adc 4
// if (chg_sts == POWER_SUPPLY_STATUS_CHARGING) { // 插上usb 电压会增高
// voltage = voltage - 60;
// }
// adc 4
if (voltage >= 4330) {
return percent[0];
}
for (i = 0; i < 21; i++)
{
if ((voltage < vat[i]) && (voltage >= vat[i + 1]))
{
temp = percent[i + 1];
}
}
*val = temp;
SPRD_FGU_DEBUG("%s line:%d val = %d temp = %d\n", __func__, __LINE__, voltage, temp);
return 0;
}
ret = iio_read_channel_processed(data->chg_temp_cha, val);此函数是获取adc电压值的关键函数。
adc4 是128管脚,配的adc4, 是测试128管脚的,要用原本的需要把添加了adc4 的代码注释掉,把原本的打开。
因为插入USB会让电压升高60左右,我们需要判断插入状态,如果插入了USB,就减去USB带来的偏移量。
4.电量数据上报
bsp/kernel/kernel4.14/drivers/power/supply/charger-manager.c
case POWER_SUPPLY_PROP_CAPACITY:
if (!is_batt_present(cm)) {
/* There is no battery. Assume 100% */
val->intval = 100;
break;
}
if (cm->desc->cap_debug != -1)
val->intval = cm->desc->cap_debug;
else {
/* Raise cap a bit, by *101/98, the affect is real 97% raised to 100%*/
cap_new = cm->desc->cap;
// cap_new = DIV_ROUND_CLOSEST(cap_new * 101, 960); 注释原本的计算方式
dev_info(cm->dev, "capacity orig: %d, new: %d\n", cm->desc->cap, cap_new);
if (cap_new > 100)
cap_new = 100;
if (cm->desc->cap <= 0) {
get_batt_vol_now(cm, &batt_uV);
if (batt_uV >= CUTOFF_VOLTAGE_UV) {
cap_new = 1;
dev_info(cm->dev, "## force report soc 1, vbat %d\n", batt_uV);
}
}
val->intval = cap_new;
}
break;
...
if (fuel_cap != cm->desc->cap) {
/*if (DIV_ROUND_CLOSEST(fuel_cap, 10) != DIV_ROUND_CLOSEST(cm->desc->cap, 10)) {
cm->desc->cap = fuel_cap;
cm->desc->update_capacity_time = cur_time.tv_sec;
power_supply_changed(cm->charger_psy);
}*/
/*power_supply_changed use ui_cap update strategy*/
if (DIV_ROUND_CLOSEST(fuel_cap * 101, 960)
!= DIV_ROUND_CLOSEST(cm->desc->cap * 101, 960)) {
cm->desc->cap = fuel_cap;
cm->desc->update_capacity_time = cur_time.tv_sec;
power_supply_changed(cm->charger_psy);
}
ret = get_batt_cap(cm, &fuel_cap); // 获取电量
cm->desc->cap = fuel_cap;// 赋值
dev_info(cm->dev, " fuel_cap= %d", fuel_cap);
set_batt_cap(cm, cm->desc->cap);
}