Linux Regulator Framework(1)_概述
1. 前言
Regulator,中文名翻譯為“穩定器”,在電子工程中,是voltage regulator(穩壓器)或者current regulator(穩流器)的簡稱,指可以自動維持恆定電壓(或電流)的裝置。
voltage regulator最早應用於功放電路中,主要用於濾除電源紋波(100或者120Hz)和噪聲,以及避免“輸出電壓隨負載的變化而變化”的情況。後來,隨著IC級別的regulator的出現(便宜了),voltage regulator幾乎存在於任何的電子裝置中。例如我們常見的嵌入式裝置中,基本上每一種電壓,都是經過regulator輸出的。
相比較voltage regulator的廣泛使用,很少見到current regulator的應用場景(相信大多數的嵌入式工程師都沒有接觸過)。它一般存在於電流源中,除此之外,它廣泛存在於近年來新興的LED照明裝置中。current regulator在LED裝置中的作用主要有兩個:避免驅動電流超出最大額定值,影響其可靠性;獲得預期的亮度要求,並保證各個LED亮度、色度的一致性。
雖然原理比較複雜,但從裝置驅動的角度看,regulator的控制應該很簡單,就是輸出的enable/disable、輸出電壓或電流的大小的控制。那麼,linux kernel的regulator framework到底要做什麼呢?這就是本文的目的:弄清楚regulator framework背後思考,並總結出其軟體架構(和common clock framework類似,consumer/provider/core)。
注1:有關regulator的描述,參考自“http://sound.westhost.com/articles/vi-regulators.html”。
注2:kernel中有關regulator framework的介紹寫的相當好(Documentation\power\regulator*),因此本文大部分內容會參考這些檔案。
2. 背後的思考
Linux regulator framework的目的很直接:提供標準的核心介面,控制系統的voltage/current regulators,並提供相應的機制,在系統執行的過程中,動態改變regulators的輸出,以達到省電的目的。
看似簡單的背後,有些因素不得不考慮。
1)最重要的,就是安全性:
在一個系統中,錯誤的regulator配置是非常危險的,嚴重時可以損毀硬體。而無論是regulator的使用者(consumer),還是regulator提供者(provider,即regulator driver),都不一定有足夠的知識和能力,避免危險發生。因此必須從machine的角度,小心的設計regulator的輸出限值(這一般由產品設計、硬體設計決定的)。
同時,一旦設計確定下來之後,這些限制必須儲存在一些相對固定的地方,不能輕易地被軟體修改。
最後,所有的regulator操作,必須是小心的、在可允許範圍內的
2)系統中大部分的裝置,都沒有動態更改regulator配置的需求,甚至連enable/disable都懶得關心的,framework需要考慮這種情況,儘量簡化介面。
3)會存在同一個regulator向多個裝置提供power的情況,如果這些裝置的需求不同怎麼辦?
4)regulator之間是否可以級聯?如果可以,怎麼處理?
這些思考最終都會反映到軟體設計上,具體可參考如下的軟體架構。
3. 軟體架構
基於上面的思考,regulator framework的軟體架構如下:
除了machine之外,基本上和common clock framework的consumer/provider框架類似。
3.1 machine
machine的主要功能,是使用軟體語言(struct regulator_init_data),靜態的描述regulator在板級的物理現狀,包括:
1)前級regulator(即該regulator的輸出是另一個regulator的輸入,簡稱supply regulator)和後級regulator(即該regulator的輸入是其它regulator的輸出,簡稱consumer regulator)。
這主要用於描述regulator在板級的級聯關係,需要留意的是,它和clock不同,這種級聯關係是非常確定的,以至於需要使用靜態的方式描述,而不是像clock那樣,在註冊的時候動態指定並形成。
2)該regulator的物理限制(struct regulation_constraints),包括:
輸出電壓的最大值和最小值(voltage regulator);
輸出電流的最大值和最小值(current regulator);
允許的操作(修改電壓值、修改電流限制、enable、disable等等);
輸入電壓是多少(當輸入是另一個regulator時);
是否不允許關閉(always_on);
是否啟動時就要開啟(always_on);
等等。
這些限制關係到系統安全,因此必須小心配置。配置完成後,在系統執行的整個過程中,它們都不會再改變了。
3.2 driver
driver模組的功能,是從regulator driver的角度,抽象regulator裝置。
1)使用struct regulator_desc描述regulator的靜態資訊,包括:名字、supply regulator的名字、中斷號、操作函式集(struct regulator_ops)、使用regmap時相應的暫存器即bitmap等等。
2)使用struct regulator_config,描述regulator的動態資訊(所謂的動態資訊,體現在struct regulator_config變數都是區域性變數,因此不會永久儲存),包括struct regulator_init_data指標、裝置指標、enable gpio等等。
3)提供regulator的註冊介面(regulator_register/devm_regulator_register),該介面接受描述該regulator的兩個變數的指標:struct regulator_desc和struct regulator_config,並分配一個新的資料結構(struct regulator_dev,從裝置的角度描述regulator),並把靜態指標(struct regulator_desc)和動態指標(struct regulator_config)提供的資訊儲存在其中。
4)最後,regulator driver將以為struct regulator_dev指標為物件,對regulator進行後續的操作。
3.3 consumer
consumer的功能,是從regulator consumer的角度,抽象regulator裝置(struct regulator),並提供regulator操作相關的介面。包括:
3.4 core
core負責上述邏輯的具體實現,並以sysfs的形式,向用戶空間提供介面。
4. 介面彙整
本節對regulator framework向各個層次提供的API做一個彙整,具體細節會在後續的文章中詳細描述。
4.1 consumer模組向核心空間consumer提供的介面
regulator framework向核心空間consumer提供的介面位於“include/linux/regulator/consumer.h”中,包括regulator的獲取、使能、修改等介面,如下。
1)struct regulator
struct regulator結構用於從consumer的角度抽象一個regulator,consumer不需要關心該結構的細節,當作一個控制代碼使用即可(類似struct clk)。
2)regulator的get/put介面
1: struct regulator *__must_check regulator_get(struct device *dev,
2: const char *id);
3: struct regulator *__must_check devm_regulator_get(struct device *dev,
4: const char *id);
5: struct regulator *__must_check regulator_get_exclusive(struct device *dev,
6: const char *id);
7: struct regulator *__must_check devm_regulator_get_exclusive(struct device *dev,
8: const char *id);
9: struct regulator *__must_check regulator_get_optional(struct device *dev,
10: const char *id);
11: struct regulator *__must_check devm_regulator_get_optional(struct device *dev,
12: const char *id);
13: void regulator_put(struct regulator *regulator);
14: void devm_regulator_put(struct regulator *regulator);
根據是否獨佔regulator、是否可以多次get,regulator get介面分為三類:
正常的get,非獨佔、可以重複get,regulator_get/devm_regulator_get;
獨佔性質的get,獨佔、不可重複get,regulator_get_exclusive/devm_regulator_get_exclusive;
optional的get,非獨佔、不可重複get,regulator_get_optional/devm_regulator_get_optional。
get介面的引數為id,會在下一篇文章中詳細介紹。
3)supply alias相關的介面
1: int regulator_register_supply_alias(struct device *dev, const char *id,
2: struct device *alias_dev,
3: const char *alias_id);
4: void regulator_unregister_supply_alias(struct device *dev, const char *id);
5:
6: int devm_regulator_register_supply_alias(struct device *dev, const char *id,
7: struct device *alias_dev,
8: const char *alias_id);
9: void devm_regulator_unregister_supply_alias(struct device *dev,
10: const char *id);
11:
12: int devm_regulator_bulk_register_supply_alias(struct device *dev,
13: const char *const *id,
14: struct device *alias_dev,
15: const char *const *alias_id,
16: int num_id);
17: void devm_regulator_bulk_unregister_supply_alias(struct device *dev,
18: const char *const *id,
19: int num_id);
具體意義請參考下一篇文章。
4)regulator的控制、狀態獲取介面
1: int __must_check regulator_enable(struct regulator *regulator);
2: int regulator_disable(struct regulator *regulator);
3: int regulator_force_disable(struct regulator *regulator);
4: int regulator_is_enabled(struct regulator *regulator);
5: int regulator_disable_deferred(struct regulator *regulator, int ms);
6:
7: int regulator_can_change_voltage(struct regulator *regulator);
8: int regulator_count_voltages(struct regulator *regulator);
9: int regulator_list_voltage(struct regulator *regulator, unsigned selector);
10: int regulator_is_supported_voltage(struct regulator *regulator,
11: int min_uV, int max_uV);
12: unsigned int regulator_get_linear_step(struct regulator *regulator);
13: int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV);
14: int regulator_set_voltage_time(struct regulator *regulator,
15: int old_uV, int new_uV);
16: int regulator_get_voltage(struct regulator *regulator);
17: int regulator_sync_voltage(struct regulator *regulator);
18: int regulator_set_current_limit(struct regulator *regulator,
19: int min_uA, int max_uA);
20: int regulator_get_current_limit(struct regulator *regulator);
21:
22: int regulator_set_mode(struct regulator *regulator, unsigned int mode);
23: unsigned int regulator_get_mode(struct regulator *regulator);
24: int regulator_set_optimum_mode(struct regulator *regulator, int load_uA);
25:
26: int regulator_allow_bypass(struct regulator *regulator, bool allow);
27:
28: struct regmap *regulator_get_regmap(struct regulator *regulator);
29: int regulator_get_hardware_vsel_register(struct regulator *regulator,
30: unsigned *vsel_reg,
31: unsigned *vsel_mask);
32: int regulator_list_hardware_vsel(struct regulator *regulator,
33: unsigned selector);
34:
控制有關的包括enable、disable、電壓設定、電流設定、mode設定等,其中disable又包括normal、強制、退出等型別。
狀態獲取包括:是否enable;是否可以改變電壓;支援的電壓列表;是否支援指定範圍的電壓;當前輸出電壓;當前電流限制;當前mode;等等。
更為詳細的描述,請參考下一篇文章。
5)bulk型的操作(一次操作多個regulator)
1: int regulator_bulk_register_supply_alias(struct device *dev,
2: const char *const *id,
3: struct device *alias_dev,
4: const char *const *alias_id,
5: int num_id);
6: void regulator_bulk_unregister_supply_alias(struct device *dev,
7: const char * const *id, int num_id);
8: int __must_check regulator_bulk_get(struct device *dev, int num_consumers,
9: struct regulator_bulk_data *consumers);
10: int __must_check devm_regulator_bulk_get(struct device *dev, int num_consumers,
11: struct regulator_bulk_data *consumers);
12: int __must_check regulator_bulk_enable(int num_consumers,
13: struct regulator_bulk_data *consumers);
14: int regulator_bulk_disable(int num_consumers,
15: struct regulator_bulk_data *consumers);
16: int regulator_bulk_force_disable(int num_consumers,
17: struct regulator_bulk_data *consumers);
18: void regulator_bulk_free(int num_consumers,
19: struct regulator_bulk_data *consumers);
6)notifier相關的介面
1: int regulator_register_notifier(struct regulator *regulator,
2: struct notifier_block *nb);
3: int regulator_unregister_notifier(struct regulator *regulator,
4: struct notifier_block *nb);
如果consumer關心某個regulator的狀態變化,可以通過上面介面註冊一個notifier。
7)其它介面
1: /* driver data - core doesn't touch */
2: void *regulator_get_drvdata(struct regulator *regulator);
3: void regulator_set_drvdata(struct regulator *regulator, void *data);
用於設定和獲取driver的私有資料。
4.2 consumer模組向用戶空間consumer提供的介面
使用者空間程式可以通過sysfs介面,使用regulator,就像核心空間consumer一樣。這些介面由“drivers/regulator/userspace-consumer.c”實現,主要包括:
sysfs目錄位置:/sys/devices/platform/reg-userspace-consumer。
name,讀取可以獲取該regulator的名字。
state,讀取,可以獲取該regulator的狀態(enabled/disabled);寫入可以改變regulator的狀態(enabled或者1使能,disabled或者0禁止)。
4.3 machine模組向regulator driver提供的介面
machine模組主要提供struct regulator_init_data、struct regulation_constraints constraints等資料結構,用於描述板級的regulator配置,具體可參考3.1中介紹。
4.4 driver模組向regulator driver提供的介面
regulator framework向regulator driver提供的介面位於“include/linux/regulator/driver.h”中,包括資料結構抽象、regulator註冊等。
1)struct regulator_desc、struct regulator_config和struct regulator_dev
見3.2中的介紹。
2)regulator裝置的註冊介面
1: struct regulator_dev *
2: regulator_register(const struct regulator_desc *regulator_desc,
3: const struct regulator_config *config);
4: struct regulator_dev *
5: devm_regulator_register(struct device *dev,
6: const struct regulator_desc *regulator_desc,
7: const struct regulator_config *config);
8: void regulator_unregister(struct regulator_dev *rdev);
9: void devm_regulator_unregister(struct device *dev, struct regulator_dev *rdev);
見3.2中的介紹。
3)其它介面,請參考後續的文章。
4.5 core模組向用戶空間提供的sysfs介面
regulator裝置在核心中是以regulator class的形式存在的,regulator core通過class->dev_groups的方式,提供了一些預設的attribute,包括:
name,讀取可以獲取該regulator的名字;
num_users,讀取可獲取regulator的使用者數目;
type,讀取可以獲取該regulator的型別(voltage或者current)。
另外,如果regulator driver需要提供更多的attribute(如狀態、最大/最小電壓等等),可以呼叫add_regulator_attributes介面,主動新增。