「Linux驅動」安卓手機充電晶片bq24735調試詳解

一口linux 發佈 2022-04-16T04:50:46.303420+00:00

一、bq24735簡介bq24735 是一款高效率同步電池充電器。當系統供電需求暫時高於適配器最大供電水平的時候, bq24735 使用智能加速技術來允許電池向系統中釋放能量,這樣的話將保護適配器不被損壞。

一、bq24735簡介

bq24735 是一款高效率同步電池充電器。

當系統供電需求暫時高於適配器最大供電水平的時候, bq24735 使用智能加速技術來允許電池向系統中釋放能量,這樣的話將保護適配器不被損壞。

bq24735 為滿足自動系統電源選擇的需要,使用 2 個充電泵來分別驅動 n-通道 MOSFET (ACFET, RBFET 和 BATFET) 。

SMBus(I2C總線) 控制的輸入電流, 充電電流, 和充電電壓DAC允許非常高的調節精度,此調節精度可通過系統功率管理微控制器很容易地進行編程。

bq24735 使用內部輸入電流寄存器或者外部ILIM引腳來減緩PWM調製速度以減小充電電流。

二、Linux內核充電架構

要想理解bq24735驅動,必須首先理解Android供電系統框架,最重要的知識點是power supply。

1. Android供電系統框架

power supply(以下簡稱psy)是Linux中從供電驅動抽象出來的子系統,是Linux電源管理的重要組成部分。

psy是一個中間層,在kernel中是屬於設備驅動的一部分,psy的作用主要是向用戶空間匯總各類供電的狀態信息。

抽象出來的各類信息稱為property,比如供電設備是否連接就對應著POWER_SUPPLY_PROP_ONLINE

2. power supply功能

power_supply的軟體架構:


power supply framework功能包括:

  1. 抽象PSY設備的共性,向用戶空間提供統一的API;
  2. 為底層PSY驅動的編寫,提供簡單、統一的方式,同時封裝並實現公共邏輯。

power supply class位於drivers/power/目錄中,主要由3部分組成(可參考下圖的軟體架構):

  • 1)power_supply_core,用於抽象核心數據結構、實現公共邏輯。位於drivers/power/power_supply_core.c中。
  • 2)power_supply_sysfs,實現sysfs以及uevent功能。位於drivers/power/power_supply_sysfs.c中。
  • 3)power_supply_leds,基於Linux led class,提供PSY設備狀態指示的通用實現。位於drivers/power/power_suppply_leds.c中。

最後,驅動工程師可以基於power supply class,實現具體的PSY drivers,主要處理平台相關、硬體相關的邏輯。這些drivers都位於drivers/power/power_supply目錄下。

3. 驅動層功能

在驅動層,主要是兩大模塊,與電池監控(fuelgauge)和與充放電管理(charger)相關的驅動(對應圖中的battery.c和charger.c),這兩大模塊主要處理硬體相關的邏輯,在硬體狀態發生變化時,會觸發相關的中斷,驅動層會調用相應的中斷函數,並更新修改相應的psy節點值。

fuelgauge驅動主要是負責向上層android系統提供當前電池的電量以及健康狀態信息等等,另外除了這個以外,它也向charger驅動提供電池的相關信息;charger驅動主要負責電源線的插拔檢測,以及充放電的過程管理。

對於battery管理,硬體上有電量計IC和充放電IC,當然有些廠家為了成本的考慮,也會把電量計和充放電功能集成到一個IC上,更有甚者,可能會把PMU功能也集成在一塊矽面上。

4. 其他問題

問:android怎麼知道當前是什麼供電,充電中與否?

答:uevent機制(實質是net_link方式的socket)(廣泛應用於hotplug),充電插入與斷開時,內核通過發送uevent信息,告訴android。

問:android如何知道各種參數並更新的?

答:通過kobject_uevent發送通知給上層,上層讀取sys相關文件屬性

以下是某平台sysfs文件目錄

root@********_arm64:/sys/class # pwd
sys/class/power_supply
root@********_arm64:/sys/class/power_supply # ls
ac
battery
bq24735@5-0009
usb
root@********_arm64:/sys/class/power_supply # cd bq24735@5-0009
cd bq24735@5-0009
root@*********_arm64:/sys/class/power_supply/bq24735@5-0009 # ls
device
online
power
status
subsystem
type
uevent                                                                              

【文章福利】小編自己整理了一些個人覺得比較好的學習書籍資料有需要的可以私信回復【內核】自行免費領取哦!!


三、bq24735驅動實現

下面基於某款soc來講解如何讓我們的產品支持bq24735。

1. 硬體連接圖圖

下面是一個典型的bq24735電路連接圖:

當沒有電源供電的時候,bq24735會直接將電池傳遞給降壓電路,給系統供電 當有電源供電的時候,bq24735會給電池充電。

2. 引腳說明

在此我們只介紹與驅動相關的引腳

3. 寄存器

bq24735用到的寄存器如下:

  1. 充電選項寄存器Charge Options Register [reset = 0x12H]

其中最重要的兩個位bit[4]/bit[0] bit:[4]

0: AC adapter不在 (ACDET < 2.4 V)  
1: AC adapter存在(ACDET > 2.4 V)

bit:[0]

0: 使能充電
1: 抑制充電

該寄存器為可讀寫, 如果要判斷當前是否在充電,則可以讀取該寄存器,通過判斷bit[0]是否為0來確認 如果要判斷當前是否存在,則可以讀取該寄存器,通過判斷bit[4]是否為1來確認

  1. 充電電流寄存器Charge Current Register (0x14H)

通過該寄存器可以設置充電電流。

比如我們要設置充電電流為3072mA,
該值為2048+1024,將對應的bite[10]/[11]為1,其他位為0

1100 0000 0000

即設置該寄存器值為:0xC00

  1. 充電電壓寄存器Charge Voltage Register (0x15H) 該寄存器設置方法類似於充電電流寄存器
  2. 輸入電流Input Current Register (0x3FH) 該寄存器設置方法類似於充電電流寄存器
  3. 0xfe,0xff 這兩個寄存器分別讀取MANUFACTURER_ID和DEVICE_ID

這兩個值分別為:0x0040、0x000B

驅動初始化時可以通過讀取這兩個寄存器的值來判斷,驅動是否和硬體匹配。

注意: 通常寄存器0x14、0x15、0x3F值需要詢問硬體工程師

4. 設備樹

bq24735@9 {
 compatible = "ti,bq24735";
 reg = <0x9>;
 ti,ac-detect-gpios = <&gpio 72 0x1>;
 ti,charge-current =<0x600>;
 ti,charge-voltage=<0x41a0>;
 ti,input-current =<0x800>;
}

參數說明

compatible :用於和驅動的結構體i2c_driver的driver.of_match_table->compatible屬性進行匹配
reg:bq24735從設備地址(I2C)
ti,ac-detect-gpios:中斷使用的gpio,第三個參數是該pin默認電平
ti,charge-current :充電電流
ti,charge-voltage :充電電壓
ti,input-current  :輸入電流

5. 驅動講解

  1. 驅動文件 內核代碼中已經有該驅動
drivers\power\bq24735-charger.c

但是該驅動往往需要修改以適配實際的方案。

該驅動是基於I2C總線,對應結構體變量定義如下:

static struct i2c_driver bq24735_charger_driver = {
 .driver = {
  .name = "bq24735-charger",
  .owner = THIS_MODULE,
  .of_match_table = bq24735_match_ids,
 },
 .probe = bq24735_charger_probe,
 .remove = bq24735_charger_remove,
 .id_table = bq24735_charger_id,
};
  1. 主要函數
static bool bq24735_charger_is_present(struct bq24735 *charger)
判斷bq24735 是否存在
其實就是讀取寄存器0x12的值,判斷bit[4]值是否為1
static int bq24735_charger_is_charging(struct bq24735 *charger)
判斷bq24735 是否在充電
其實就是讀取寄存器0x12的值,判斷bit[0]值是否為0
static inline int bq24735_enable_charging(struct bq24735 *charger)
使能充電
將寄存器寄存器0x12的bit[0]置0
static inline int bq24735_disable_charging(struct bq24735 *charger)
禁止充電
將寄存器寄存器0x12的bit[0]置1
static int bq24735_config_charger(struct bq24735 *charger)
配置充電電壓(寄存器0x15)、充電電流(寄存器0x14)、輸入電流(寄存器0x3f)
static irqreturn_t bq24735_charger_isr(int irq, void *devid)
中斷處理函數,
當bq24735充電狀態發生變化的時候,會發送中斷給cpu
此時可以通過I2C來讀取寄存器0x12的內容來獲取bq24735當前狀態
static int bq24735_charger_get_property(struct power_supply *psy,
     enum power_supply_property psp,
     union power_supply_propval *val)
提供給power supply子系統的回調函數
該函數用於獲取bq24735當前狀態

狀態包括
enum {
 POWER_SUPPLY_STATUS_UNKNOWN = 0,
 POWER_SUPPLY_STATUS_CHARGING,  //正在充電
 POWER_SUPPLY_STATUS_DISCHARGING, 
 POWER_SUPPLY_STATUS_NOT_CHARGING,//沒有充電
 POWER_SUPPLY_STATUS_FULL,//充滿
};
  1. probe流程


此處檢測MANUFACTURER_ID和DEVICE_ID流程稍做了修改,只有bq24735 present的時候才會check並配置

此外還有個最重要的機構體

 supply_desc->name = name;
 supply_desc->type = POWER_SUPPLY_TYPE_MAINS;
 supply_desc->properties = bq24735_charger_properties;
 supply_desc->num_properties = ARRAY_SIZE(bq24735_charger_properties);
 supply_desc->get_property = bq24735_charger_get_property;
supply_desc->properties
 提供給power supply架構可以訪問的命令的集合,
 這些命令需要在函數supply_desc->get_property增加對應的命令代碼
supply_desc->get_property
 power supply會定時通過該回調函數獲取充電晶片是否在線、是否在充電等狀態
  1. 代碼架構 這個架構是一口君根據項目中平台所畫的架構,其他平台架構可能會有所不同, 需要具體問題具體分析。

四、 log

下面log是開機啟動流程log, 第一步 用電池供電啟動

啟動後再插入電源充電, 插入電源後,bq24735會觸發中斷:

然後再斷開電源停止充電

關鍵字: