Linux Regulator Framework(2)_regulator driver
1. 前言
本文從regulator driver的角度,描述怎樣基於regulator framework編寫regulator驅動。同時,以此為契機,學習、理解regulator有關的物理特性,以便能夠更好的使用它們。
2. regulator driver的實現步驟
2.1 確定系統中regulator有關的硬體組成
提起硬體,最好能有個例子,好在有device tree,一個活生生的硬體拓撲結構。這裡以NVIDIA Tegra Dalmore A04開發板為例(regulator有關的device tree位於“arch\arm\boot\dts\tegra114-dalmore.dts”):
這裡的regulator結構是相當複雜的,其中彩色框代表最終的regulator抽象,它的前一級表示regulator的載體(可以是PMIC、CPU、等等)。下面將會詳細說明:
a)CPU通過I2C controller,連線一個降壓控制器(TI tps51632),該控制器輸出名稱為“vdd-cpu”的電壓,就稱作vdd-cpu regulator吧(因此,在kernel中,regulator是一個虛擬裝置)。
b)CPU通過I2C controller,連線一個前端電源管理晶片(TI tps65090),該晶片除了具備充電管理功能外,內建了多個regulator,例如dcdc1、dcdc2等等。
c)CPU通過I2C controller,連線另一個電源管理晶片(TI tps65913),該晶片具有兩個功能:GPIO輸出和PMIC。PMIC內建了多個regulator,如vddio-ddr、vdd-core等等。
d)CPU內部也集成了一些regulator,如vdd_ac_bat等等。
注1:單純從硬體的角度看,是不存在圖中"regulators“、PMIC等實體的,它們的出現,已經包含了軟體設計的思路。之所以畫在這裡,是方便後面的描述。
2.2 使用DTS,將硬體拓撲呈現出來
我們都知道,DTS的功能是描述裝置的拓撲結構,並在系統初始化的時候,為被描述的裝置建立並註冊對應的platform device,最終和相應的platform driver相遇,執行其probe介面,實現裝置的列舉功能。但是,在這些基本原則之外,還需要一些更深的思考:
DTS節點(node)怎麼和裝置對應?是以裝置的“物理界限”為單位,還是以裝置的“功能”為單位?
是不是所有的“裝置”都應該在kernel中建立一個platform device?如果不是,建立的依據是什麼?
這些思考在本文的例子(NVIDIA Tegra Dalmore A04的regulator)中體現尤為突出,它的本質是軟體設計中的模組劃分,從而決定了regulator在DTS中的呈現方式和層次。
1)tps51632
tps51632是一個簡單的器件,位於i2c匯流排下面,包含一個regulator器件,因此其DTS比較簡單,如下:
1: /* arch\arm\boot\dts\tegra114-dalmore.dts */
2: i2c@7000d000 {
3: status = "okay";
4: clock-frequency = <400000>;
5:
6: tps51632@43 {
7: compatible = "ti,tps51632";
8: reg = <0x43>;
9: regulator-name = "vdd-cpu";
10: regulator-min-microvolt = <500000>;
11: regulator-max-microvolt = <1520000>;
12: regulator-boot-on;
13: regulator-always-on;
14: };
15: ...
16: }
i2c控制器的node為“i2c@7000d000”,tps51632是其下的一個子node,名稱為“tps51632@43”,compatible為“ti,tps51632”。tps51632下面以“regulator-”為字首的欄位,是regulator特有的欄位,後面會統一介紹。
注2:為什麼“i2c@7000d000”中沒有compatible欄位?其實是有的,可參考“arch\arm\boot\dts\tegra114.dtsi”,DTC在編譯DTS時,會將這兩個檔案中的node合併。
注3:kernel在初始化時,只會為二級node(即“/”下面的節點,本文的例子是“i2c@7000d000”)建立platform裝置,至於三級node(這裡的“tps51632@43”),則由其bus(i2c)建立。後面我們會遇到其它的情況,到時再介紹。
2)tps65090
tps65090相對比較複雜,它位於相同的i2c匯流排下面,但包含兩個相對複雜的功能實體,charger和PMIC,我們看看其DTS怎麼寫的:
1: i2c@7000d000 {
2: status = "okay";
3: ...
4:
5: tps65090@48 {
6: compatible = "ti,tps65090";
7: reg = <0x48>;
8: ...
9:
10: charger: charger {
11: compatible = "ti,tps65090-charger";
12: ti,enable-low-current-chrg;
13: };
14:
15: regulators {
16: tps65090_dcdc1_reg: dcdc1 {
17: regulator-name = "vdd-sys-5v0";
18: regulator-always-on;
19: regulator-boot-on;
20: };
21:
22: tps65090_dcdc2_reg: dcdc2 {
23: regulator-name = "vdd-sys-3v3";
24: regulator-always-on;
25: regulator-boot-on;
26: };
27: ...
28: }
29: }
30: }
和tps51632類似,但它下面又包含了兩個子node:charger和regulators。其中charger竟然還有compatible欄位。
回憶一下上面“注3”,kernel只會為"i2c@7000d000”建立platform device,“tps65090@48”則由i2c core建立,那麼它下面的子node呢?一定是tps65090 driver處理了,感興趣的讀者可以閱讀“drivers/mfd/tps65090.c”、“drivers/power/tps65090-charger.c”和“drivers/regulator/tps65090-regulator.c”,這裡面還涉及了MFD(multi-function device,多功能裝置),很有意思。
回到本文的主題上,雖然這裡的regulators沒有compatible欄位,也會建立相應的platform device(具體可參考“drivers/mfd/tps65090.c”),這從側面回答了上面的一個思考:從物理範疇,tps65090是一個獨立的裝置,但它內部有兩個功能模組,因此會存在兩個platform device。
再來看regulators中子node----regulator,由於數量比較多,就沒必要建立platform device了。同樣,“regulator-”為字首的欄位,是regulator特有的欄位,後面統一介紹。
3)tps65913,和tps65090類似,不再介紹。
4)CPU中的regulator
這一類regulator比較特殊,直接整合在CPU內部,DTS如下:
1: regulators {
2: compatible = "simple-bus";
3: #address-cells = <1>;
4: #size-cells = <0>;
5:
6: vdd_ac_bat_reg: regulator@0 {
7: compatible = "regulator-fixed";
8: reg = <0>;
9: regulator-name = "vdd_ac_bat";
10: regulator-min-microvolt = <5000000>;
11: regulator-max-microvolt = <5000000>;
12: regulator-always-on;
13: };
14:
15: dvdd_ts_reg: regulator@1 {
16: compatible = "regulator-fixed";
17: reg = <1>;
18: regulator-name = "dvdd_ts";
19: regulator-min-microvolt = <1800000>;
20: regulator-max-microvolt = <1800000>;
21: enable-active-high;
22: gpio = <&gpio TEGRA_GPIO(H, 5) GPIO_ACTIVE_HIGH>;
23: };
24: ...
25: };
3)tps65913,和tps65090類似,不再介紹。
4)CPU中的regulator
這一類regulator比較特殊,直接整合在CPU內部,DTS如下:
1: regulators {
2: compatible = "simple-bus";
3: #address-cells = <1>;
4: #size-cells = <0>;
5:
6: vdd_ac_bat_reg: regulator@0 {
7: compatible = "regulator-fixed";
8: reg = <0>;
9: regulator-name = "vdd_ac_bat";
10: regulator-min-microvolt = <5000000>;
11: regulator-max-microvolt = <5000000>;
12: regulator-always-on;
13: };
14:
15: dvdd_ts_reg: regulator@1 {
16: compatible = "regulator-fixed";
17: reg = <1>;
18: regulator-name = "dvdd_ts";
19: regulator-min-microvolt = <1800000>;
20: regulator-max-microvolt = <1800000>;
21: enable-active-high;
22: gpio = <&gpio TEGRA_GPIO(H, 5) GPIO_ACTIVE_HIGH>;
23: };
24: ...
25: };
在回到剛才的話題上,kernel只為二級node建立platform device(這裡的“regulators”),那三級node(一個個的regulator)呢?沒有相對標準的bus幫它們建立怎麼辦?藉助“simple-bus”,具體可以參考of_platform_bus_create(“Device Tree(三):程式碼分析”)。
另外,這裡的例子比較簡單,都是fixed regulator,regulator framework core可以幫忙實現fixed型別的regulator的驅動,後面會說明。
3. DTS相關的實現邏輯
3.1 DTS的內容
回憶一下“Linux Regulator Framework(1)_概述”中介紹的machine的主要功能:使用軟體語言(struct regulator_init_data),靜態的描述regulator在板級的物理現狀。對regulator driver而言,DTS主要用於配置regulator的init data。先看一下struct regulator_init_data:
1: /**
2: * struct regulator_init_data - regulator platform initialisation data.
3: *
4: * Initialisation constraints, our supply and consumers supplies.
5: *
6: * @supply_regulator: Parent regulator. Specified using the regulator name
7: * as it appears in the name field in sysfs, which can
8: * be explicitly set using the constraints field 'name'.
9: *
10: * @constraints: Constraints. These must be specified for the regulator to
11: * be usable.
12: * @num_consumer_supplies: Number of consumer device supplies.
13: * @consumer_supplies: Consumer device supply configuration.
14: *
15: * @regulator_init: Callback invoked when the regulator has been registered.
16: * @driver_data: Data passed to regulator_init.
17: */
18: struct regulator_init_data {
19: const char *supply_regulator; /* or NULL for system supply */
20:
21: struct regulation_constraints constraints;
22:
23: int num_consumer_supplies;
24: struct regulator_consumer_supply *consumer_supplies;
25:
26: /* optional regulator machine specific init */
27: int (*regulator_init)(void *driver_data);
28: void *driver_data; /* core does not touch this */
29: };
supply_regulator,該regulator的前級regulator,一般在regulator driver中直接指定;
constraints,該regulator的使用限制,由DTS配置,並可以藉助regulator core提供的輔助API(regulator_of_get_init_data)自動解析。後面會詳細介紹;
num_consumer_supplies、consumer_supplies,使用該regulator的consumer的個數,及其裝置名和supply名的map。用於建立consumer裝置和regulator之間的關聯,後面介紹consumer DTS時再詳細說明;
regulator_init,regulator的init回撥,由regulator driver提供,並在regulator註冊時呼叫;
driver_data,儲存driver的私有資料,並在呼叫regulator_init時傳入。
看來DTS的內容都在struct regulation_constraints中,該結構儲存了該regulator所有的物理限制,如下:
1: struct regulation_constraints {
2:
3: const char *name;
4:
5: /* voltage output range (inclusive) - for voltage control */
6: int min_uV;
7: int max_uV;
8:
9: int uV_offset;
10:
11: /* current output range (inclusive) - for current control */
12: int min_uA;
13: int max_uA;
14:
15: /* valid regulator operating modes for this machine */
16: unsigned int valid_modes_mask;
17:
18: /* valid operations for regulator on this machine */
19: unsigned int valid_ops_mask;
20:
21: /* regulator input voltage - only if supply is another regulator */
22: int input_uV;
23:
24: /* regulator suspend states for global PMIC STANDBY/HIBERNATE */
25: struct regulator_state state_disk;
26: struct regulator_state state_mem;
27: struct regulator_state state_standby;
28: suspend_state_t initial_state; /* suspend state to set at init */
29:
30: /* mode to set on startup */
31: unsigned int initial_mode;
32:
33: unsigned int ramp_delay;
34: unsigned int enable_time;
35:
36: /* constraint flags */
37: unsigned always_on:1; /* regulator never off when system is on */
38: unsigned boot_on:1; /* bootloader/firmware enabled regulator */
39: unsigned apply_uV:1; /* apply uV constraint if min == max */
40: unsigned ramp_disable:1; /* disable ramp delay */
41: };
name,用於描述該constraints;
min_uV、max_uV,輸出電壓的範圍,[min_uV, max_uV],單位為uV。只對voltage regulator有效;
uV_offset,consumer看到的電壓和實際電壓之間的偏移值。通常用於補償壓降。只對voltage regulator有效;
min_uA、max_uA,輸出電流的範圍,[min_uA, max_uA],單位為uA。只對current regulator有效;
valid_modes_mask,regulator mode相關的內容,和DTS無關,後面再解釋;
valid_ops_mask,該regulator支援哪些操作,以bit mask的形式提供,包括:
REGULATOR_CHANGE_VOLTAGE,可以改變輸出電壓;
REGULATOR_CHANGE_CURRENT,可以改變輸出電流;
REGULATOR_CHANGE_MODE,可以修改mode,後面再介紹;
REGULATOR_CHANGE_STATUS,可以enable/disable;
REGULATOR_CHANGE_DRMS,支援Dynamic Regulator Mode Switching(DRMS),可以動態的調整regulator的mode,有關mode描述可參考5.3章節;
REGULATOR_CHANGE_BYPASS,支援bypass模式。input_uV,如果該regulator的輸入是另一個regulator,該欄位指定regulator期望的輸入電壓;
state_xxx、initial_state,regulator電源管理有關的欄位,後面會專門介紹;
initial_mode,初始mode,具體請參考5.3節的介紹;
always_on,是否一直保持使能狀態;
boot_on,是否在啟動時使能;
rapm_delay,由於模擬器件的特性,電壓改變,需要一定的生效時間。在一定的範圍內,生效時間和電壓的變化值成比例。該變數就是描述regulator器件的這個特性,單位為uV/us,即1us可以產生多大的電壓變化。在rapm_disable不為1的情況下,當consumer要求改變電壓時,regulator framework core會根據該變數,以及電壓改變數,計算出需要等待的時間,進行延時操作;
rapm_disable,是否禁止延時操作;
enable time,regulator的開啟時間,單位為us。consumer enable regulator時,regulator framework會根據該變數進行延時操作;
apply_uV,如果min_uV和max_uV相同,該變數指示“在regulator註冊到kernel時,是否將電壓設定為min_uV/max_uV。
結合struct regulation_constraints結構,我們解釋一下2.2小節中tps51632的DTS:
1: tps51632@43 {
2: compatible = "ti,tps51632";
3: reg = <0x43>;
4: regulator-name = "vdd-cpu";
5: regulator-min-microvolt = <500000>;
6: regulator-max-microvolt = <1520000>;
7: regulator-boot-on;
8: regulator-always-on;
9: };
regulator-name,對應struct regulation_constraints中name;
regulator-min-microvolt,對應struct regulation_constraints中的min_uV;
regulator-max-microvolt,對應struct regulation_constraints中的max_uV;
regulator-boot-on,對應struct regulation_constraints中的boot_on;
regulator-always-on,對應struct regulation_constraints中的always_on。
其它的欄位,可以根據實際情況,自行新增,具體可參考“Documentation/devicetree/bindings/regulator/regulator.txt”中的描述。
3.2 DTS的解析
regulator的DTS資訊,可以通過兩種方法解析:
1)在regulator註冊前,呼叫of_get_regulator_init_data介面自行解析,該介面的實現如下:
1: struct regulator_init_data *of_get_regulator_init_data(struct device *dev,
2: struct device_node *node)
3: {
4: struct regulator_init_data *init_data;
5:
6: if (!node)
7: return NULL;
8:
9: init_data = devm_kzalloc(dev, sizeof(*init_data), GFP_KERNEL);
10: if (!init_data)
11: return NULL; /* Out of memory? */
12:
13: of_get_regulation_constraints(node, &init_data);
14: return init_data;
15: }
16: EXPORT_SYMBOL_GPL(of_get_regulator_init_data);
該介面有兩個輸入引數:裝置指標,以及包含了DTS資訊的node指標(以3.1中的例子,即“tps51632@43”所在的node)。
它會分配一個struct regulator_init_data變數,並呼叫of_get_regulation_constraints解析DTS,把結果儲存在該變數中。
最後返回struct regulator_init_data變數的地址。
2)在regulator註冊時,由regulator_register呼叫regulator_of_get_init_data幫忙解析,該介面的實現如下:
1: struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
2: const struct regulator_desc *desc,
3: struct device_node **node)
4: {
5: struct device_node *search, *child;
6: struct regulator_init_data *init_data = NULL;
7: const char *name;
8:
9: if (!dev->of_node || !desc->of_match)
10: return NULL;
11:
12: if (desc->regulators_node)
13: search = of_get_child_by_name(dev->of_node,
14: desc->regulators_node);
15: else
16: search = dev->of_node;
17:
18: if (!search) {
19: dev_dbg(dev, "Failed to find regulator container node '%s'\n",
20: desc->regulators_node);
21: return NULL;
22: }
23:
24: for_each_child_of_node(search, child) {
25: name = of_get_property(child, "regulator-compatible", NULL);
26: if (!name)
27: name = child->name;
28:
29: if (strcmp(desc->of_match, name))
30: continue;
31:
32: init_data = of_get_regulator_init_data(dev, child);
33: if (!init_data) {
34: dev_err(dev,
35: "failed to parse DT for regulator %s\n",
36: child->name);
37: break;
38: }
39:
40: of_node_get(child);
41: *node = child;
42: break;
43: }
44: of_node_put(search);
45:
46: return init_data;
47: }
與of_get_regulator_init_data不同的是,該介面以struct regulator_desc指標為引數,該引數提供了regulator DTS有關的搜尋資訊(desc->of_match),根據這些資訊,可以獲得包含regulator資訊的DTS node。
它本質上是一種通用的DTS匹配邏輯(和kernel解析platform device的標準資源類似),大致如下:
?a)呼叫者提供parent node(struct device指標中,代表regulators的宿主裝置,如上面的tps65090@48),以及該regulator在DTS中的名稱(由desc->of_match提供)。
b)還可以在struct regulator_desc中提供包含regulator DTS資訊的node名稱(可選,用於regulator不直接在parent node下的情況)。
c)以parent device的node,或者指定的子node為基準,查詢其下所有的node,如果node的名字或者“regulator-compatible”欄位和desc->of_match匹配,則呼叫of_get_regulator_init_data從中解析DTS資訊。
4. 主要資料結構
4.1 struct regulator_desc
在註冊regulator的時候,需要使用struct regulator_desc結構提供該regulator的靜態描述。所謂的靜態,是指這些描述不會在執行時改變,代表了裝置的一種屬性,如下:
1: /* include/linux/regulator/driver.h */
2:
3: struct regulator_desc {
4: const char *name;
5: const char *supply_name;
6: const char *of_match;
7: const char *regulators_node;
8: int id;
9: bool continuous_voltage_range;
10: unsigned n_voltages;
11: const struct regulator_ops *ops;
12: int irq;
13: enum regulator_type type;
14: struct module *owner;
15:
16: unsigned int min_uV;
17: unsigned int uV_step;
18: unsigned int linear_min_sel;
19: int fixed_uV;
20: unsigned int ramp_delay;
21:
22: const struct regulator_linear_range *linear_ranges;
23: int n_linear_ranges;
24:
25: const unsigned int *volt_table;
name,該regulator的名稱,唯一標識該regulator,必須提供;
supply_name,該regulator的輸入regulator的名稱;
of_match、regulators_node,提供資訊,以便在註冊的時候自動從DTS中解析init_data,具體可參考3.2小節的描述;
id,標識該regulator的一個數字;
continuous_voltage_range,為true時,表示該regulator可以在一定範圍輸出連續的電壓;
n_voltages,consumer可以通過ops.list_voltage()介面,獲取該regulator可以輸出的電壓值。該變數指定可以獲取的電壓值的個數,後面講到ops時,再介紹;
ops,該regulator的操作函式集,見後面;
irq,該regulator的中斷號(有的話);
type,該regulator的型別,包括REGULATOR_VOLTAGE和REGULATOR_CURRENT兩種;
其它欄位,和regulator的輸出控制有關,後面會以專題的形式介紹。
struct regulator_ops提供了regulator的所有操作,如下:
1: struct regulator_ops {
2:
3: /* enumerate supported voltages */
4: int (*list_voltage) (struct regulator_dev *, unsigned selector);
5:
6: /* get/set regulator voltage */
7: int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV,
8: unsigned *selector);
9: int (*map_voltage)(struct regulator_dev *, int min_uV, int max_uV);
10: int (*set_voltage_sel) (struct regulator_dev *, unsigned selector);
11: int (*get_voltage) (struct regulator_dev *);
12: int (*get_voltage_sel) (struct regulator_dev *);
13:
14: /* get/set regulator current */
15: int (*set_current_limit) (struct regulator_dev *,
16: int min_uA, int max_uA);
17: int (*get_current_limit) (struct regulator_dev *);
18:
19: /* enable/disable regulator */
20: int (*enable) (struct regulator_dev *);
21: int (*disable) (struct regulator_dev *);
22: int (*is_enabled) (struct regulator_dev *);
23:
24: /* get/set regulator operating mode (defined in consumer.h) */
25: int (*set_mode) (struct regulator_dev *, unsigned int mode);
26: unsigned int (*get_mode) (struct regulator_dev *);
27:
28: /* Time taken to enable or set voltage on the regulator */
29: int (*enable_time) (struct regulator_dev *);
30: int (*set_ramp_delay) (struct regulator_dev *, int ramp_delay);
31: int (*set_voltage_time_sel) (struct regulator_dev *,
32: unsigned int old_selector,
33: unsigned int new_selector);
34:
35: /* report regulator status ... most other accessors report
36: * control inputs, this reports results of combining inputs
37: * from Linux (and other sources) with the actual load.
38: * returns REGULATOR_STATUS_* or negative errno.
39: */
40: int (*get_status)(struct regulator_dev *);
41:
42: /* get most efficient regulator operating mode for load */
43: unsigned int (*get_optimum_mode) (struct regulator_dev *, int input_uV,
44: int output_uV, int load_uA);
45:
46: /* control and report on bypass mode */
47: int (*set_bypass)(struct regulator_dev *dev, bool enable);
48: int (*get_bypass)(struct regulator_dev *dev, bool *enable);
49:
50: /* the operations below are for configuration of regulator state when
51: * its parent PMIC enters a global STANDBY/HIBERNATE state */
52:
53: /* set regulator suspend voltage */
54: int (*set_suspend_voltage) (struct regulator_dev *, int uV);
55:
56: /* enable/disable regulator in suspend state */
57: int (*set_suspend_enable) (struct regulator_dev *);
58: int (*set_suspend_disable) (struct regulator_dev *);
59:
60: /* set regulator suspend operating mode (defined in consumer.h) */
61: int (*set_suspend_mode) (struct regulator_dev *, unsigned int mode);
62: };
這些回撥函式的具體意義,請參考後續的描述。
4.2 struct regulator_config
struct regulator_config儲存了regulator的動態資訊,所謂的動態資訊,是指那些會在driver執行過程中改變、或者driver執行後才會確定的資訊,如下:
1: struct regulator_config {
2: struct device *dev;
3: const struct regulator_init_data *init_data;
4: void *driver_data;
5: struct device_node *of_node;
6: struct regmap *regmap;
7:
8: int ena_gpio;
9: unsigned int ena_gpio_invert:1;
10: unsigned int ena_gpio_flags;
11: };
dev,對應的struct device指標。會在regulator_register時,由regulator core分配,儲存在此,以便後續使用;
init_data,init data指標,在解析DTS後,儲存在此,以便後續使用;
of_node,可以為空;
regmap,參考後續描述;
ena_gpio、ena_gpio_invert、ena_gpio_flags,控制regulator使能的GPIO及其active極性。
4.3 struct regulator_dev
struct regulator_dev是regulator裝置的抽象,當driver以struct regulator_desc、struct regulator_config兩個型別的引數,呼叫regulator_register將regulator註冊到kernel之後,regulator就會分配一個struct regulator_dev變數,後續所有的regulator操作,都將以該變數為物件。
1: struct regulator_dev {
2: const struct regulator_desc *desc;
3: int exclusive;
4: u32 use_count;
5: u32 open_count;
6: u32 bypass_count;
7:
8: /* lists we belong to */
9: struct list_head list; /* list of all regulators */
10:
11: /* lists we own */
12: struct list_head consumer_list; /* consumers we supply */
13:
14: struct blocking_notifier_head notifier;
15: struct mutex mutex; /* consumer lock */
16: struct module *owner;
17: struct device dev;
18: struct regulation_constraints *constraints;
19: struct regulator *supply; /* for tree */
20: struct regmap *regmap;
21:
22: struct delayed_work disable_work;
23: int deferred_disables;
24:
25: void *reg_data; /* regulator_dev data */
26:
27: struct dentry *debugfs;
28:
29: struct regulator_enable_gpio *ena_pin;
30: unsigned int ena_gpio_state:1;
31:
32: /* time when this regulator was disabled last time */
33: unsigned long last_off_jiffy;
34: };
desc,儲存了regulator靜態描述資訊的指標(從這個角度看,所謂的靜態描述,其變數必須為全域性變數);
exclusive、use_count、open_count、bypass_count,一些狀態記錄;
constraints,儲存了regulator的constraints指標;
supply,該regulator的supply;
等等。
5 實現邏輯分析
本章簡單的分析一下regulator driver相關的實現邏輯。如果要理解有些邏輯,必須具備一些regulator的基礎知識,因此在需要的時候,會穿插介紹這些知識。
5.1 regulator core的初始化
regulator core的初始化操作由regulator_init介面負責,主要工作包括:
1)註冊regulator class(/sys/class/regulator/)。
2)註冊用於除錯的debugfs。
和power switch class、input class等類似,regulator framework也是一種class,可以稱作regulator class。
5.2 regulator register
regulator的註冊,由regulator_register/devm_regulator_register介面負責,如下:
1: /**
2: * regulator_register - register regulator
3: * @regulator_desc: regulator to register
4: * @config: runtime configuration for regulator
5: *
6: * Called by regulator drivers to register a regulator.
7: * Returns a valid pointer to struct regulator_dev on success
8: * or an ERR_PTR() on error.
9: */
10: struct regulator_dev *
11: regulator_register(const struct regulator_desc *regulator_desc,
12: const struct regulator_config *config)
13: {
14: const struct regulation_constraints *constraints = NULL;
15: const struct regulator_init_data *init_data;
16: static atomic_t regulator_no = ATOMIC_INIT(0);
17: struct regulator_dev *rdev;
18: struct device *dev;
19: int ret, i;
20: const char *supply = NULL;
21:
22: if (regulator_desc == NULL || config == NULL)
23: return ERR_PTR(-EINVAL);
24:
25: dev = config->dev;
26: WARN_ON(!dev);
27:
28: if (regulator_desc->name == NULL || regulator_desc->ops == NULL)
29: return ERR_PTR(-EINVAL);
30:
31: if (regulator_desc->type != REGULATOR_VOLTAGE &&
32: regulator_desc->type != REGULATOR_CURRENT)
33: return ERR_PTR(-EINVAL);
34:
35: /* Only one of each should be implemented */
36: WARN_ON(regulator_desc->ops->get_voltage &&
37: regulator_desc->ops->get_voltage_sel);
38: WARN_ON(regulator_desc->ops->set_voltage &&
39: regulator_desc->ops->set_voltage_sel);
40:
41: /* If we're using selectors we must implement list_voltage. */
42: if (regulator_desc->ops->get_voltage_sel &&
43: !regulator_desc->ops->list_voltage) {
44: return ERR_PTR(-EINVAL);
45: }
46: if (regulator_desc->ops->set_voltage_sel &&
47: !regulator_desc->ops->list_voltage) {
48: return ERR_PTR(-EINVAL);
49: }
50:
51: rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
52: if (rdev == NULL)
53: return ERR_PTR(-ENOMEM);
54:
55: init_data = regulator_of_get_init_data(dev, regulator_desc,
56: &rdev->dev.of_node);
57: if (!init_data) {
58: init_data = config->init_data;
59: rdev->dev.of_node = of_node_get(config->of_node);
60: }
61:
62: mutex_lock(®ulator_list_mutex);
63:
64: mutex_init(&rdev->mutex);
65: rdev->reg_data = config->driver_data;
66: rdev->owner = regulator_desc->owner;
67: rdev->desc = regulator_desc;
68: if (config->regmap)
69: rdev->regmap = config->regmap;
70: else if (dev_get_regmap(dev, NULL))
71: rdev->regmap = dev_get_regmap(dev, NULL);
72: else if (dev->parent)
73: rdev->regmap = dev_get_regmap(dev->parent, NULL);
74: INIT_LIST_HEAD(&rdev->consumer_list);
75: INIT_LIST_HEAD(&rdev->list);
76: BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
77: INIT_DELAYED_WORK(&rdev->disable_work, regulator_disable_work);
78:
79: /* preform any regulator specific init */
80: if (init_data && init_data->regulator_init) {
81: ret = init_data->regulator_init(rdev->reg_data);
82: if (ret < 0)
83: goto clean;
84: }
85:
86: /* register with sysfs */
87: rdev->dev.class = ®ulator_class;
88: rdev->dev.parent = dev;
89: dev_set_name(&rdev->dev, "regulator.%d",
90: atomic_inc_return(®ulator_no) - 1);
91: ret = device_register(&rdev->dev);
92: if (ret != 0) {
93: put_device(&rdev->dev);
94: goto clean;
95: }
96:
97: dev_set_drvdata(&rdev->dev, rdev);
98:
99: if (config->ena_gpio && gpio_is_valid(config->ena_gpio)) {
100: ret = regulator_ena_gpio_request(rdev, config);
101: if (ret != 0) {
102: rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
103: config->ena_gpio, ret);
104: goto wash;
105: }
106:
107: if (config->ena_gpio_flags & GPIOF_OUT_INIT_HIGH)
108: rdev->ena_gpio_state = 1;
109:
110: if (config->ena_gpio_invert)
111: rdev->ena_gpio_state = !rdev->ena_gpio_state;
112: }
113:
114: /* set regulator constraints */
115: if (init_data)
116: constraints = &init_data->constraints;
117:
118: ret = set_machine_constraints(rdev, constraints);
119: if (ret < 0)
120: goto scrub;
121:
122: /* add attributes supported by this regulator */
123: ret = add_regulator_attributes(rdev);
124: if (ret < 0)
125: goto scrub;
126:
127: if (init_data && init_data->supply_regulator)
128: supply = init_data->supply_regulator;
129: else if (regulator_desc->supply_name)
130: supply = regulator_desc->supply_name;
131:
132: if (supply) {
133: struct regulator_dev *r;
134:
135: r = regulator_dev_lookup(dev, supply, &ret);
136:
137: if (ret == -ENODEV) {
138: /*
139: * No supply was specified for this regulator and
140: * there will never be one.
141: */
142: ret = 0;
143: goto add_dev;
144: } else if (!r) {
145: dev_err(dev, "Failed to find supply %s\n", supply);
146: ret = -EPROBE_DEFER;
147: goto scrub;
148: }
149:
150: ret = set_supply(rdev, r);
151: if (ret < 0)
152: goto scrub;
153:
154: /* Enable supply if rail is enabled */
155: if (_regulator_is_enabled(rdev)) {
156: ret = regulator_enable(rdev->supply);
157: if (ret < 0)
158: goto scrub;
159: }
160: }
161:
162: add_dev:
163: /* add consumers devices */
164: if (init_data) {
165: for (i = 0; i < init_data->num_consumer_supplies; i++) {
166: ret = set_consumer_device_supply(rdev,
167: init_data->consumer_supplies[i].dev_name,
168: init_data->consumer_supplies[i].supply);
169: if (ret < 0) {
170: dev_err(dev, "Failed to set supply %s\n",
171: init_data->consumer_supplies[i].supply);
172: goto unset_supplies;
173: }
174: }
175: }
176:
177: list_add(&rdev->list, ®ulator_list);
178:
179: rdev_init_debugfs(rdev);
180: out:
181: mutex_unlock(®ulator_list_mutex);
182: return rdev;
183:
184: unset_supplies:
185: unset_regulator_supplies(rdev);
186:
187: scrub:
188: if (rdev->supply)
189: _regulator_put(rdev->supply);
190: regulator_ena_gpio_free(rdev);
191: kfree(rdev->constraints);
192: wash:
193: device_unregister(&rdev->dev);
194: /* device core frees rdev */
195: rdev = ERR_PTR(ret);
196: goto out;
197:
198: clean:
199: kfree(rdev);
200: rdev = ERR_PTR(ret);
201: goto out;
202: }
203: EXPORT_SYMBOL_GPL(regulator_register);
主要工作包括:
2249,檢查引數的合法性。其中3549行,涉及到電壓控制的方式,後面後詳細說明;
55~60,協助從DTS解析init data,如果解析不到,則使用config中的;
68~73,協助獲取regulator的register map(有的話),並儲存在register device指標中。regulator driver會在需要的時候使用(通常是在ops回撥函式中);
74~77,初始化一些全域性變數,consumer_list用於儲存所有的consumer,list用於將自己新增到一個全域性的regulator連結串列(regulator_list)上,disable_work是用於disable regulator的work queue;
86~95,將regulator device註冊到kernel;
99~112,申請regulator enable gpio(有的話),並將相應的資訊儲存在regulator device指標中;
114~120,將從DTS中解析的constraints,應用起來(這個過程比較複雜,就不介紹了,感興趣的讀者可以自行分析);
123,根據regulator的操作函式集,註冊相應的attribute(和PSY class類似);
127~160,如果該regulator有supply,根據supply的名字,獲取相應的regulator device指標,同時根據supply指標,分配一個struct regulator結構,儲存在該regulator的supply指標中。最後,如果該regulator處於使能狀態,則需要使能其supply(這些動作,需要以consumer的視角操作,因而需要一個struct regulator變數);
162~175,add consumer devices,等到介紹consumer時,再詳細描述。
注4:register map是kernel提供的一種管理暫存器的機制,特別是較為複雜的暫存器,如codec等。本文不會過多描述,如需要,會專門寫一篇文章介紹該機制。
5.3 regulator的操作模式(operation mode)
regulator的主要功能,是輸出電壓/電流的調整(或改變)。由於模擬器件的特性,電壓/電流的改變,是需要一定的時間的。對有些regulator而言,可以工作在不同的模式,這些模式有不同的改變速度,可想而知,較快的速度,有較大的功耗。下面是operation mode定義(位於include/linux/regulator/consumer.h中):
1: /*
2: * Regulator operating modes.
3: *
4: * Regulators can run in a variety of different operating modes depending on
5: * output load. This allows further system power savings by selecting the
6: * best (and most efficient) regulator mode for a desired load.
7: *
8: * Most drivers will only care about NORMAL. The modes below are generic and
9: * will probably not match the naming convention of your regulator data sheet
10: * but should match the use cases in the datasheet.
11: *
12: * In order of power efficiency (least efficient at top).
13: *
14: * Mode Description
15: * FAST Regulator can handle fast changes in it's load.
16: * e.g. useful in CPU voltage & frequency scaling where
17: * load can quickly increase with CPU frequency increases.
18: *
19: * NORMAL Normal regulator power supply mode. Most drivers will
20: * use this mode.
21: *
22: * IDLE Regulator runs in a more efficient mode for light
23: * loads. Can be used for devices that have a low power
24: * requirement during periods of inactivity. This mode
25: * may be more noisy than NORMAL and may not be able
26: * to handle fast load switching.
27: *
28: * STANDBY Regulator runs in the most efficient mode for very
29: * light loads. Can be used by devices when they are
30: * in a sleep/standby state. This mode is likely to be
31: * the most noisy and may not be able to handle fast load
32: * switching.
33: *
34: * NOTE: Most regulators will only support a subset of these modes. Some
35: * will only just support NORMAL.
36: *
37: * These modes can be OR'ed together to make up a mask of valid register modes.
38: */
39:
40: #define REGULATOR_MODE_FAST 0x1
41: #define REGULATOR_MODE_NORMAL 0x2
42: #define REGULATOR_MODE_IDLE 0x4
43: #define REGULATOR_MODE_STANDBY 0x8
相應的,regulator framework提供了一些機制,用於operation mode的操作,包括:
1)struct regulation_constraints中用於表示初始模式的欄位initial_mode。
2)regulator ops中的set_mode/get_mode回撥函式。
5.4 電壓操作的兩種方式
kernel抽象了兩種電壓操作的方法:
1)直接操作電壓,對應struct regulator_ops中的如下回調函式:
1: /* get/set regulator voltage */
2: int (*list_voltage) (struct regulator_dev *, unsigned selector);
3: int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV,
4: unsigned *selector);
5: int (*get_voltage) (struct regulator_dev *);
其中set_voltage用於將電壓設定為min_uV和max_uV範圍內、和min_uV最接近的電壓。該介面可以返回一個selector引數,用於告知呼叫者,實際的電壓值;
get_voltage,用於返回當前的電壓值;
list_voltage,以selector為引數,獲取對應的電壓值。
注5:有關selector的描述,可參考下面的介紹。
2)selector的形式
regulator driver以selector的形式,反映電壓值。selector是一個從0開始的整數,driver提供如下的介面:
1: /* enumerate supported voltages */
2: int (*list_voltage) (struct regulator_dev *, unsigned selector);
3:
4: int (*map_voltage)(struct regulator_dev *, int min_uV, int max_uV);
5: int (*set_voltage_sel) (struct regulator_dev *, unsigned selector);
6: int (*get_voltage_sel) (struct regulator_dev *);
list_voltage,上面已經介紹;
map_voltage,是和list_voltage相對的介面,用於將電壓範圍map成一個selector值;
set_voltage_sel/get_voltage_sel,以selector的形式,操作電壓。
regulator driver可以根據實際情況,選擇一種實現方式。
5.5 regulator framework提供的sysfs介面
根據regulator提供的ops情況,regulator framework可以通過sysfs提供多種attribute,它們位於/sys/class/regulator/.../目錄下,數量相當多,這裡就不一一描述了,具體可參考:
https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-regulator