pxa920 88pm860x充電

http://www.cnblogs.com/to7str/archive/2013/03/24/2978699.html


1.       引言

1.1.  編寫目的

TF303充電部分做一個整理,內容涉及到電池的基礎知識、8607中斷、power supply子系統、 電池和充電電器驅動、充電流程和電量計算等。

 

1.2.  環境

硬件環境:TF303

軟件環境:svn://172.16.0.70/svn_android/PXA920/branch/Kernel/W1225.03_8390_Kernel   版本8538

 

2.       充電基礎知識

2.1.  名詞解釋

恆流充電:保持恆定電流對電池進行充電。

恆壓充電:保持恆定電壓對電池進行充電。

熱敏電阻:對熱敏感的半導體電阻,其阻值隨溫度變化的曲線呈非線性或線性。

記憶效應:電池的記憶效應是指在下一次充電時所能充電的百分比。爲了消除電池的記憶效應,在下一次充電之前,必須先完全放電,然後再充電。只有這樣,才能百分之百的充滿電池。

涓流充電以一微小的電流對電池充電涓流充電用來先對完全放電的電池單元進行預充(恢復性充電)。。

電池容量:電池容量的國標單位爲庫侖,常用單位爲mAh 1mAh=0.001安培*3600=3.6安培秒=3.6庫侖,比如一顆900mAh的電池可以提供300mA恆流的持續3小時的供電能力.

 

2.2.  電池參數

電池的五個主要參數爲:電池的容量、標稱電壓、內阻、放電終止電壓和充電終止電壓。

電池的容量:通常用mAh(毫安時)表示,1000mAh就是能在1000mA的電流下放電 1小時。

標稱電壓:通常指的是開路輸出電壓,也就是不接任何負載,沒有電流輸出的電壓值。

 

2.3.  鋰電池原理

電池由正極鋰化合物、中間的電解質膜及負極碳組成。

clip_image002[1]

當電池充電時,鋰離子從正極中脫嵌,在負極中嵌入,放電時反之。一般採用嵌鋰過渡金屬氧化物做正極,如LiCoO2LiNiO2LiMn2O4

 

2.4.  電量計算

常見的方法:ADC和庫侖計

2.5.  ADC

   鋰離子電池有一個對電量計量很有用的特性,就是在放電的時候,電池電壓隨電量的流逝會逐漸降低,並且有相當大的斜率.這就提供給我們另外一種近似的電量計量途徑.

clip_image004[1]

clip_image006

   用電壓來估計電池的剩餘容量有以下幾個不穩定性:

1.同一個電池,在同等剩餘容量的情況下,電壓值因放電電流的大小而變化放電電流越大,電壓越低.在沒有電流的情況下,電壓最高.

2.環境溫度對電池電壓的影響溫度越低,同等容量電池電壓越低.

3.循環對電池放電平臺的影響隨着循環的進行,鋰離子電池的放電平臺趨於惡化.放電平臺降低.所以相同電壓所代表的容量也相應變化了.

4.不同廠家,不同容量的鋰離子電池,其放電的平臺略有差異.

5.不同類型的電極材料的鋰離子電池,放電平臺有較大差異.鈷鋰和錳鋰的放電平臺就完全不同.

 

2.6.  庫侖計法

通過統計流入和流出電池的電荷數,使用庫侖計時需要通過其他方法獲得電池在使用前的電量。

 

2.7.  鋰電池充電

鋰電池的充電過程:涓充---恆流---恆壓---停止

充電曲線

clip_image008[1]

 

2.8.  TF303充電電路

(1)80678606和電池的連接圖

clip_image010[1]圖摘自8607 datasheet

 

(2)8607中斷引腳

8607PMIC_INTN引腳接到APPMIC_INT引腳

 

(3)i2c通信

86068607SCL引腳連接到APGPIO_53SDA連接到GPIO_53

 

 

3.       Android 電池管理

clip_image012[1]圖摘自網絡

kernel中,驅動會在文件系統中生成battery相關的文件,包括電池電量、狀態等,驅動更新硬件信息時會調用power_supply提供的接口,power_supply收到這個事件後通過uevent機制利用netlink將這個event上報給app層,app層收event後再去讀sysfs中的相關文件獲取數據。

 

 

3.1.  相關代碼

(1)java代碼:

frameworks/base/services/java/com/android/server/BatteryService.java

frameworks/base/services/java/com/android/server/ SystemServer.java

frameworks/base/core/java/android/os/UEventObserver.java

 

(2)JNI代碼:

frameworks/base/services/jni/com_android_server_BatteryService.cpp

hardware/libhardware_legacy/uevent/uevent.c

android底層代碼

hardware/libhardware_legacy/uevent/uevent.c

 

(3)krenel代碼

與平臺無關文件

kernel/drivers/power/power_supply_core.c

kernel/drivers/power/power_supply_sysfs.c

kernel/drivers/usb/gadget/mv_gadget.c

平臺相關代碼

kernel/drivers/power/88pm860x_battery.c

kernel/drivers/power/88pm860x_charger.c

kernel/drivers/usb/misc/88pm860x_vbus.c

kernel/drivers/mfd/88pm860x-core.c

kernel/drivers/mfd/88pm860x-i2c.c

 

3.2.  power系統文件

/sys/class/power_supply/battery/

/sys/class/power_supply/ac/

/sys/class/power_supply/usb/

 

 

 

3.3.  power supply子系統

3.3.1.   數據結構體

struct  power_supply結構體,如下圖

clip_image014[1]

 

此結構體用於描述供電模塊,系統中總過註冊了三個power_supply,分別是:ACUSB hostbattery

下面以batterypower_supply初始化對該結構體成員做簡單的說明

clip_image016[1]

如上圖所示,其中的info->battery爲一個struct  power_supply結構體

const char *name;用於描述模塊的名稱

enum power_supply_type type;用於描述類型,類型如下

clip_image018[1]

enum power_supply_property *properties;用於描述該供電模塊有哪些屬性

battery的屬性如下

clip_image020[1]

 

char **supplied_to; 供電給那個模塊

int (*get_property)(struct power_supply *psy,  enum power_supply_property psp, union power_supply_propval *val); 此函數指針將指向獲得該模塊說屬性的接口函數

struct work_struct changed_work;工作隊列的初始化是在power_supply註冊函數中初始化的(詳細見後)

 

 

3.3.2.   系統api

 

3.3.3.   power_supply_class_init

初始化函數原型如下

clip_image022[1]

Power驅動創建了一個叫struct class *power_supply_class的類容器並且初始化函數指針power_supply_class->dev_uevent 指向power_supply_uevent函數,供電模塊的uevent環境變量的添加都是此函數中是實現的。

 

3.3.4.   power_supply_register

此函數是對外提供的API,作用是註冊power_supply供電模塊,系統中需要調用此函數來註冊BatteryACUSB三個供電模塊。函數的具體實現如下

clip_image024[1]

此函數的主要操作有:

(1)把該設備的class指向power_supply_class 

(2)調用device_add(dev);

(3)綁定函數power_supply_changed_work psy- >changed_work  工作隊列。備註:BATTERY  AC  USB這三個供電模塊的change_work都與power_supply_changed_work 函數綁定。

 

    在調用device_add(dev)(定義在:/kernel/drivers/base/core.c),會執行這一句代碼:klist_add_tail(&dev- >knode_class,  &dev->class- >p- >class_devices); 因爲在上面的函數中dev->class power_supply_class; ,所以device_add(dev) 會把dev- >knode_class 加入到power_supply_class klist鏈表中。也就是說會把usbaccharger三個的dev- >knode_class (備註:是個struct  klist_node結構體)註冊到這個power_supply_class 鏈表中,到時候可以通過class_for_each_device 這個函數通過這個類來找到這三個device,然後通過device在找到power_supply

 

clip_image026[1]

 

3.3.5.   power_supply_uevent

power_supply_uevent 此函數的作用是通過調用uevent的接口函數add_uevent_var添加環境變量,爲Battery AC USB準備好環境變量。

 

 

4.       中斷

4.1.  8607中斷

clip_image028[1]

clip_image030[1]

 

中斷相關寄存器

8607中斷狀態寄存器0x030x04 05 中斷使能寄存器 0x060x070x08

8607PMIC_INTN引腳接到APPMIC_INT引腳

 

4.2.  8607總中斷註冊

 

kernel/arch/arm/mach-mmp/raho_tf302_hwv0.c

clip_image032[1]

 

 

clip_image034[1]

clip_image036[1]

其中pm860x_irq8607總中斷的處理函數

 

4.3.  8607子中斷註冊

 

8607子中斷的資源定義

clip_image038[1]

clip_image040[1]

 

clip_image042[1]

clip_image044[1]

 

舉例88pm860x_battery.c

clip_image046[1]

clip_image048[1]

 

4.4.  中斷的執行流程

APPMIC_INTN引腳中斷信號發生時,則調用8607的總中斷處理函數pm860x_irq 在此函數中通過i2c來讀8607中斷狀態寄存器,遍歷860中斷狀態寄存器各個bit爲,判斷出具體哪個中斷髮生,pm860x_irq函數具體實現如下:

clip_image050[1]

handle_nested_irq函數說明:該函數用於實現一種中斷共享機制,當多箇中斷共享某一根中斷線時,我們可以把這個中斷線作爲父中斷,共享該中斷的各個設備作爲子中斷,在父中斷的中斷線程中決定和分發響應哪個設備的請求,在得出真正發出請求的子設備後,調用handle_nested_irq來響應子中斷。

 

5.       battery

 

5.1.  數據結構

電池d信息的數據結構

clip_image052[1]

 

5.2.  Battery init相關

5.2.1.   Probe函數

 

clip_image054

 

 

函數的主要操作有:

電池初始化,將在後面介紹

初始化並註冊電池的struct  power_supply結構體

註冊8607子中斷PM8607_IRQ_CC的處理函數爲pm860x_coulomb_handler

註冊8607子中斷PM8607_IRQ_BAT的處理函數爲pm860x_batt_handler

初始化monitor_workchanged_work兩個工作 ,其中monitor_work主要用於每隔30s刷新電池信息到用戶空間,changed_work用於更新的電池的狀態。 

 

5.2.2.   pm860x_init_battery

clip_image056

 

 

5.3.  Battery measure api

5.3.1.   測量vbatt

int measure_vbatt(struct pm860x_battery_info *infoint stateint *data);

此函數通過measure_12bit_voltage 函數去讀8607vbatt寄存器PM8607_VBAT_MEAS1 (0x6D)。然後通過校驗算法計算出vbatt的值。

 

5.3.2.   測量ibatt

int measure_current(struct pm860x_battery_info *infoint *data);

通過86070x68  0x6c計算出ibatt

 

5.3.3.   計算開路電壓

static int calc_ocv(struct pm860x_battery_info *infoint *ocv);

開路電壓值是通過測出的電壓、電流和內阻計算而來

 

 

5.3.4.   庫侖計計數

(1)數據結構

struct ccnt {

unsigned long long int pos;

unsigned long long int neg;

unsigned int spos;

unsigned int sneg;

int total_chg/*充電統計*/

int total_dischg/*放電統計*/

};

 

(2)庫侖計計算

static int calc_ccnt(struct pm860x_battery_info *infostruct ccnt *ccnt);

此函數通過86070x470x95寄存器算出total_chgtotal_dischg

 

 

5.3.5.   計算電量

接口函數:static int calc_capacity(struct pm860x_battery_info *infoint *cap);

函數的內部實現如下圖

clip_image058

 

 

5.3.6.   ADC計算電量

接口函數:static int calc_soc(struct pm860x_battery_info *infoint stateint *soc);

函數的流程爲:通過ADC測出電壓,然後再查array_soc 電量與電壓的對應關係表,從而得出電量值

clip_image060[1]

 

 

5.3.7.   充電完成時更新soc

接口函數:int pm860x_battery_update_soc(void)

函數功能:在充電徹底終止後,將庫侖計清零,並將start_soc設爲100

clip_image062

 

5.4.  GET電池屬性API

接口函數:static int pm860x_batt_get_prop(struct power_supply *psyenum power_supply_property psp,

union power_supply_propval *val);

文件系統中,所有電池相關的設備文件都是通過此API來獲取數據,此函數在pm860x_battery_probe  中註冊info->battery.get_property =pm860x_batt_get_prop;  此函數會調用電池相關的測量函數。

 

5.5.  Battery work

Power supply子系統通過uevent機制把信息傳輸到用戶空間上去,當battery的狀態發生改變的時候會向用戶空間上報一個uevent,這樣的話用戶空間就可以知道什麼時候去抓信息

5.5.1.   Driver定時更新battery信息機制

battery driver使用工作隊列來定時更新電池信息,工作隊列定義在struct pm860x_battery_info struct delayed_work monitor_work;成員。monitor_work初始化在如下函數中,相關代碼如下:

 

static __devinit int pm860x_battery_probe(struct platform_device *pdev){

    ...

    INIT_DELAYED_WORK_DEFERRABLE(&info->monitor_workpm860x_battery_work);

    queue_delayed_work(chip->monitor_wqueue&info->monitor_work, MONITOR_INTERVAL);

    ...

}

綁定pm860x_battery_work 函數到monitor_work 工作上,延時30s後將 monitor_work 加入到 monitor_wqueue 工作隊列中。

 

 

static void pm860x_battery_work(struct work_struct *work)

{

struct pm860x_battery_info *info container_of(work,

struct pm860x_battery_infomonitor_work.work);

int capvocvitemp;

power_supply_changed(&info->battery);

queue_delayed_work(info->chip->monitor_wqueue&info->monitor_workMONITOR_INTERVAL);

}

函數說明:先調用power_supply_changed 函數,延時30s後將 monitor_work 再加入到 monitor_wqueue 工作隊列中。 操作的結果就是每隔30s會調用一次pm860x_battery_workpower_supply_changed函數

 

5.5.2.   Power supply子系統更新battery信息機制

 

void power_supply_changed(struct power_supply *psy)函數中通過schedule_work(&psy- >changed_work); 去執行changed_work綁定的函數, 此工作隊是在如下函數中初始化。

 

 

int power_supply_register(struct device *parentstruct power_supply *psy){

       INIT_WORK(&psy- >changed_workpower_supply_changed_work)

       ....

}

 

static void power_supply_changed_work(struct work_struct *work){

struct power_supply *psy container_of(workstruct power_supply,    changed_work);

kobject_uevent(&psy- >dev- >kobjKOBJ_CHANGE);

…..

}

 

kobject_uevent  將調用kobject_uevent_env  函數將power_supply_uevent  函數中準備好的環境變量通過netlink發送的app層。

 

 

6.       charger

6.1.  數據結構

clip_image064[1]

 

 

6.2.  中斷

中斷

處理函數

功能

PM8607_IRQ_CHG

pm860x_charger_handler

charger detect

PM8607_IRQ_CHG_DONE

pm860x_done_handler

charging done

PM8607_IRQ_CHG_FAIL

pm860x_exception_handler

charging timeout

PM8607_IRQ_CHG_FAULT

pm860x_exception_handler

charging fault

PM8607_IRQ_GPADC1

pm860x_temp_handler

battery temperature

PM8607_IRQ_VBAT

pm860x_vbattery_handler

battery voltage

PM8607_IRQ_VCHG

pm860x_vchg_handler

vchg voltage

 

 

 

 

6.2.1.   pm860x_charger_handler

插入充電器會執行此中斷

clip_image066

 

 

6.2.2.   pm860x_done_handler

當充電徹底終止後,此中斷會發生。

clip_image068

6.2.3.   pm860x_vbattery_handler

VBATT_INT中斷處理函數

clip_image070

 

6.2.4.   pm860x_vchg_handler

VCHG_INT中斷處理函數

clip_image072

 

6.3.  charger init

6.3.1.   probe函數

clip_image074

 

 

6.3.2.   pm860x_init_charger

 

clip_image076

 

 

6.4.  charger api

6.4.1.   pm860x_set_charger_type

接口函數:void  pm860x_set_charger_type(enum enum_charger_type type);   

函數功能:設置充電器類型

函數入參爲要設置的充電器的類型有:

USB_CHARGER

AC_STANDARD_CHARGER

AC_OTHER_CHARGER

 

函數的內部實現如下圖

clip_image078

 

 

6.4.2.   set_vchg_threshold

函數原型:static void set_vchg_threshold(struct pm860x_charger_info *info,  int minint max)

函數功能:設置VCHG_INT中斷觸發條件,即pm860x_vchg_handler中斷函數的觸發條件。

clip_image080

 

 

6.4.3.   set_vbatt_threshold

函數原型:static void set_vbatt_threshold(struct pm860x_charger_info *info,

int minint max)

函數功能:設置VBAT_INT中斷觸發條件pm860x_vbattery_handler中斷函數的觸發條件。

內部實現如下:

clip_image082

 

 

6.4.4.   set_charging_fsm

函數原型:static int set_charging_fsm(struct pm860x_charger_info *info)

函數功能:維護充電狀態機

函數的內部實現如下圖:

clip_image084

 

 

 

 

 

 

 

 

 

將程序流程圖整理成fsm如下圖

 

clip_image086

 

 

6.5.  充電的步驟

 

6.5.1.   預充

當電池的電壓太低,比如過放保護的電池,需要通過預充一段時間後,再轉入快充。

預充的實現函數是:static int start_precharge(struct pm860x_charger_info *info) 

函數的內部實現如下圖:

clip_image088

 

 

6.6.  快充

快充主要有兩個過程先恆流再恆壓,通過設置86068607相關寄存器來控制恆流和恆壓的過程。函數實現:int start_fastcharge(struct pm860x_charger_info *info)

函數的內部實現如下圖:

clip_image090

 

6.7.  停充

接口函數是:static ssize_t stop_charging(struct device *devstruct device_attribute *attr,

const char *bufsize_t count)

 

clip_image092

 

 

7.       關於電量計算

 

clip_image094

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章