原文网址(转载请注明出处):
源码基于:Android Q
1.介绍
设备使用的是7.4V 的电池,但是展锐调好的电池曲线没有7.4V 的,所以需要我们自己调试,大概流程就是自己写一个电池百分比与电池电压的数组,通过读取电池电压来匹配我们的电池百分比。
但是在调试过程中发现,当插入适配器瞬间,电压会突然增大很多,所以需要将这突然增加的电压减掉,否则会导致电池百分比突然增大然后再降低的现象,所以有如下两种方式:
检测适配器插入后减去相应的电压
每次检测电压时,与上一次的电压作比较,如果差别过大则表示我们插入了适配器,再减去相应的电压值即可
2.原理
通过看硬件原理图,可以发现当我们插入适配器时,GPIO90 口会被拉低,所以如果要检测适配器是否插入,可以监测GPIO90 口的中断信息。
3.中断实现
3.1.配置PINMAP
由于GPIO90 口没有外部上,所以需要在内部配置GPIO90 口默认为上拉状态
bsp/bootloader/u-boot15/board/spreadtrum/sl8541e_1h10wifi5g_32b/pinmap-sl8541e.c
-{REG_PIN_SPI0_CSN, BITS_PIN_AF(0)},
-{REG_MISC_PIN_SPI0_CSN, BITS_PIN_DS(1)|BIT_PIN_NULL|BIT_PIN_NUL|BIT_PIN_SLP_AP|BIT_PIN_SLP_NUL|BIT_PIN_SLP_OE},//FTID_SPI_CSSPI?FingerPrintID
+{REG_PIN_SPI0_CSN, BITS_PIN_AF(3)},
+{REG_MISC_PIN_SPI0_CSN, BITS_PIN_DS(1)|BIT_PIN_NULL|BIT_PIN_WPU|BIT_PIN_SLP_AP|BIT_PIN_SLP_WPU|BIT_PIN_SLP_IE},//FTID_SPI_CSSPI?FingerPrintID
3.2.配置GPIO90口
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";
+ power-gpio = <&ap_gpio 90 GPIO_ACTIVE_LOW>;
};
3.3.将GPIO90 口配置为上拉和下拉中断
bsp/kernel/kernel4.14/drivers/power/supply/sc27xx_fuel_gauge.c
struct sc27xx_fgu_data {
...
struct gpio_desc *gpiod;
+ struct gpio_desc *gpiop; // 在结构体中添加gpiop, 用来保存gpio90 口
struct iio_channel *channel;
...
}
// gpio90口的中断方法,当发生中断的时候会调用到这个方法
+static irqreturn_t sc27xx_fgu_power_detection(int irq, void *dev_id)
+{
+ struct sc27xx_fgu_data *data = dev_id;
+ int state;
+ mutex_lock(&data->lock);
+ state = gpiod_get_value_cansleep(data->gpiop); // 读取gpio90 口的值,用来判断是上拉发生的中断还是下拉发生的中断
+ if (state < 0) {
+ dev_err(data->dev, "failed to get gpio state\n");
+ mutex_unlock(&data->lock);
+ return IRQ_RETVAL(state);
+ }
+ SPRD_FGU_DEBUG("%s xlf irq_power 2 state = %d \n", __func__, state);
+ dev_err(data->dev, "xlf get gpio state = %d \n", state);
+
+ mutex_unlock(&data->lock);
+ return IRQ_HANDLED;
+}
static int sc27xx_fgu_probe(struct platform_device *pdev)
{
...
const struct sc27xx_fgu_variant_data *pdata;
- int ret, irq;
+ int ret, irq, irq_power;
struct device_node *battery_np = NULL;
...
data->chg_temp_cha = devm_iio_channel_get(&pdev->dev, "chg-temp");
if (IS_ERR(data->chg_temp_cha)) {
dev_err(&pdev->dev, "failed to get IIO channel chg-temp\n");
return PTR_ERR(data->chg_temp_cha);
}
+ // 获取在dtsi中配置的power-gpio 参数
+ data->gpiop = devm_gpiod_get(&pdev->dev, "power", GPIOD_IN);
+ if (IS_ERR(data->gpiop)) {
+ dev_err(&pdev->dev, "failed to get power detection GPIO\n");
+ return PTR_ERR(data->gpiop);
+ }
data->gpiod = devm_gpiod_get(&pdev->dev, "bat-detect", GPIOD_IN);
...
if (ret) {
dev_err(data->dev, "failed to request fgu IRQ\n");
return ret;
}
+ // 将gpio90 口配置为中断模式
+ irq_power = gpiod_to_irq(data->gpiop);
+ if (irq_power < 0) {
+ dev_err(&pdev->dev, "failed to translate GPIO to IRQ\n");
+ return irq_power;
+ }
+
+ // 设置gpio 的中断方式(上拉和下拉时发生中断),配置中断时调用的方法(sc27xx_fgu_power_detection)
+ ret = devm_request_threaded_irq(&pdev->dev, irq_power, NULL,
+ sc27xx_fgu_power_detection,
+ IRQF_ONESHOT | IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING,
+ "power-gpio", data);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request IRQ\n");
+ return ret;
+ }
irq = gpiod_to_irq(data->gpiod);
...
}
4.测试
连上串口,通过串口输出log。
插入电源适配器。
拔出电源适配器。
查看串口log是否有“state =” 相关的log。