天天看點

Linux 中power supply軟體架構和相關API

一、 概述

電源管理整體上可以分為兩個部分,一個是電池監控(fuel gauge),另外一個是充放電管理。這兩部分在核心中也是分為兩個驅動來管理。fuelgauge驅動的功能主要是負責向上層Android系統提供目前電池的電量和健康資訊等等。同時也向charger驅動提供電池的相關資訊。charger驅動主要是負責電源線的插拔檢測、充電器類型識别和充放電的過程管理等實務。

Power supply class 是為編寫供電裝置(power supply ,簡稱PSY)的驅動提供的統一架構

主要功能包括如下部分:

1. 抽象PSY裝置共性,向使用者空間提供統一的API

2. 為底層PSY驅動的編寫提供簡單統一的方式,同時封裝并且實作公共邏輯,驅動工程師隻要專注與硬體細節部分。

設計思路:

PSY driver的主要功能就是向使用者空間程式彙總各類狀态資訊。是以power supply class的思路如下:

PSY driver負責:該PSY裝置具有哪些屬性,這些屬性的值是什麼,當屬性值發生改變時要通知power supply class

Power supply class負責:将某個PSY裝置支援的屬性及其value以sysfs的形式提供給使用者空間,當屬性值改變時以uevent的形式廣播給使用者空間程式。,另外也會協助處理PSY級聯的情況。

軟體架構及API接口

Power supply class 位于driver/power目錄中,主要由三部分組成:

1. power_supply_core.c 抽象核心資料結構實作公共邏輯

2. power_supply_sysfs.c 實作sysfs和uevent功能

3. power_supply_leds.c 提供PSY裝置狀态訓示的通用實作

核心資料結構:

struct power_supply {
    const struct power_supply_desc *desc;
    char **supplied_to;          //當此電源變化時需要通知的電源子產品 name
    size_t num_supplicants;      // supplied_to 數組的大小

    char **supplied_from;        //接收其他電源子產品發生變化時的通知 name
    size_t num_supplies;         // supplied_from 數組的大小
    struct device_node *of_node;

    /* Driver private data */
    void *drv_data;

    /* private */
    struct device dev;
//工作隊列,相當與一個核心線程,主要思路是該PSY裝置狀态改變了就啟用一個workqueue,查詢并通知所有由他發起supplicants 
struct work_struct changed_work;
    struct delayed_work deferred_register_work;
    spinlock_t changed_lock;
    bool changed;
    bool initialized;
    atomic_t use_cnt;
#ifdef CONFIG_THERMAL
    struct thermal_zone_device *tzd;
    struct thermal_cooling_device *tcd;
#endif
#ifdef CONFIG_LEDS_TRIGGERS   //LED相關的操作省略顯示。。
#endif
};
           

其中 power_supply_desc 定義如下:

struct power_supply_desc {
    const char *name;                //電源名稱
    enum power_supply_type type;     //電源類型 為電池 USB或者。。
    enum power_supply_property *properties; //該電源的屬性
    size_t num_properties;                //該電源屬性的數目
    //讀取屬性值
    int (*get_property)(struct power_supply *psy,
                enum power_supply_property psp,
                union power_supply_propval *val);
    //設定屬性值
    int (*set_property)(struct power_supply *psy,
                enum power_supply_property psp,
                const union power_supply_propval *val);
    //設定屬性為可寫的屬性
    int (*property_is_writeable)(struct power_supply *psy,
                     enum power_supply_property psp);
    //外部電源發生變化時所做的工作
    void (*external_power_changed)(struct power_supply *psy);
    void (*set_charged)(struct power_supply *psy);
    bool no_thermal;                     //設定本電源會不會産生熱源
    int use_for_apm;            //For APM emulation, think legacy userspace.
};
           

向具體的PSY driver提供的API接口

1. PSY的register/unregister API

power_supply_register(struct device *parent,const struct power_supply_desc *desc,
                       const struct power_supply_config *cfg)
power_supply_register_no_ws(struct device *parent,const struct power_supply_desc *desc,const struct power_supply_config *cfg)
power_supply_unregister(struct power_supply *psy)
           

power_supply_register 和 power_supply_register_no_ws的差別:

power_supply_register_no_ws 沒有weakup系統的能力

2. PSY狀态發生改變時的API

power_supply_changed(struct power_supply *psy)

當PSY driver 檢測到裝置某些屬性值發生改變時需要調用這個接口,通知我們的

Power supply core ,Power supply core 會有如下動作:

1) 如果該PSY是其他PSY的供電源,調用這些PSY的external_power_changed回調函數,通知他們。

2) 如果配置了CONFIG_LEDS_TRIGGERS,調用power_supply_update_leds更新該PSY有關的LED狀态。

3) 發送notifier ,通知那些關心PSY裝置狀态的drivers.

4) 以統一的格式向使用者空間發送uevent

3.其他雜項接口

extern struct power_supply *power_supply_get_by_name(const char *name); 
extern struct power_supply *power_supply_get_by_phandle(struct device_node *np, 
                                                           const char *property); 
extern int power_supply_am_i_supplied(struct power_supply *psy); 
extern int power_supply_set_battery_charged(struct power_supply *psy); 
extern int power_supply_is_system_supplied(void); 
extern int power_supply_powers(struct power_supply *psy, struct device *dev);

power_supply_get_by_name,通過名字擷取PSY指針。
power_supply_get_by_phandle,從DTS中,解析出對應的PSY指針。
power_supply_am_i_supplied,查詢自己是否由其它PSY供電。
power_supply_set_battery_charged,調用指定PSY的set_charged回調。
power_supply_is_system_supplied,查詢系統是否有有效的或者處于online狀态的PSY,如果沒有,可能為桌面系統。
power_supply_powers,在指定裝置(通常是該PSY裝置)的sysfs目錄(/sys/devices/xxx/)下,建立指定PSY的符号連結(/sys/devices/xxx/powers)。
           

4.向其它driver提供的用于接收PSY狀态改變notifier的API

extern int power_supply_reg_notifier(struct notifier_block *nb); 
extern void power_supply_unreg_notifier(struct notifier_block *nb);
           

通過notifier注冊接口注冊notifier之後,系統任何PSY裝置的狀态發生改變,并調用了power_supply_changed接口,power supply core就是通知notifier的監聽者。

5. 向使用者空間程式提供的API

power supply class通過兩種形式向使用者空間提供接口。

1)uevent 以“名字=value”的形式,上報所有property的值

uevent一般會在PSY裝置添加到kernel時,或者PSY屬性發生改變時(可參考3.3中的介紹)發送。

2)sysfs 如果某個PSY裝置具有某個屬性,該屬性對應的attribute就會展現在sysfs中(一般位于“/sys/class/power_supply/xxx/”中)