1. Regulator驅動是什么?
Regulator是Linux系統中電源管理的基礎設施之一,用于穩壓電源的管理,是各種驅動子系統中設置 電壓的標準接口。前面介紹的CPUFreq驅動就經常使用它來設定電壓。分為voltage regulator(電壓調節器)和current(電流調節器)。一般電源管理芯片(Power Management IC)中會包含一個甚至多個regulator。
而Regulator則可以管理系統中的供電單元,即穩壓器(Low Dropout Regulator,LDO,即低壓差線性 穩壓器),并提供獲取和設置這些供電單元電壓的接口。一般在ARM電路板上,各個穩壓器和設備會形 成一個Regulator樹形結構,
Regulator的作用是什么?
通常的作用是給電子設備供電。大多數regulator可以啟用(enable)和禁用(disable)其輸出,同時也可以控制其輸出電壓(voltage)和電流(current)。
從上圖可以看出,input power會經過 regulator 轉化為output power,regulator可以做如下的約束:
Voltage control: 限制輸出的電壓
Current limiting: 限制最大輸出電流
Power switch: 可以控制電壓enable/disable
Power Domain
電源域由穩壓器、開關或其他電源域的輸出電源提供其輸入電源的電子電路。電源Regulator可能位于一個或多個開關后面,例如:
Regulator -+-> Switch-1 -+-> Switch-2 --> [Consumer A] | | | +-> [Consumer B], [Consumer C] | +-> [Consumer D], [Consumer E]
這是一個穩壓器和三個電源域:
Domain 1: Switch-1, Consumers D & E. Domain 2: Switch-2, Consumers B & C. Domain 3: Consumer A.
Regulator電壓設計時的約束:
穩壓器級別:這由穩壓器硬件操作參數定義,并在穩壓器數據表中指定,例如:``` 電壓輸出范圍為 800mV -> 3500mV 穩壓器電流輸出限制為 20mA @ 5V,但為 10mA @ 10V
功率域級別:這是由內核級板初始化代碼在軟件中定義的。它用于將功率域限制在特定的功率范圍內,例如:Domain-2 電壓為 1400mV -> 1600mV
Consumer級別:這是由Consumer驅動程序動態設置電壓或電流限制級別定義的。例如 消費類背光驅動器要求將電流從 5mA 增加到 10mA,以增加 LCD 亮度。
2. Regulator框架介紹
Linux regulator framework的主要目的:
提供標準的內核接口,控制系統的voltage/current regulators,并提供相應的開關、大小設置的機制。
在系統運行的過程中,根據具體的需要動態改變regulators的輸出,從而達到省電的目的。
在系統中如果配錯regulator是比較危險的,可能會造成硬件器件的損壞。因此,需要在regulator framework中對電流或者電壓的大小做限定,并且不能被ragulator的consumer或者provider更改。
2.1 regulator consumer
regulator consumer抽象出regulator設備(struct regulator),并提供regulator操作相關的接口。包括:regulator_get/regulator_put/regulator_enable/regulator_disable/ regulator_set_voltage/regulator_get_voltage等。
2.2 regulator core
regulator core負責上述regulator driver/consumer/machine邏輯的具體實現,對底層的硬件進行封裝,并提供接口給內核中其他的consumer(使用當前regulator設備的驅動)提供操作接口,并以sysfs的形式,向用戶空間提供接口。
2.3 regulator 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. DTS配置文件及初始化
例如:arch/arm/boot/dts/100ask_imx6ull_qemu.dts中
regulators { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <0>; reg_can_3v3: regulator@0 { compatible = "regulator-fixed"; reg = <0>; regulator-name = "can-3v3"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; /*gpios = <&gpio_spi 3 GPIO_ACTIVE_LOW>;*/ };
subsys_initcall(regulator_fixed_voltage_init); //系統啟動時候執行
--》platform_driver_register(®ulator_fixed_voltage_driver);
static struct platform_driver regulator_fixed_voltage_driver = { .probe = reg_fixed_voltage_probe, .driver = { .name = "reg-fixed-voltage", .of_match_table = of_match_ptr(fixed_of_match), .pm = ®_fixed_voltage_pm_ops, }, };
reg_fixed_voltage_probe --》devm_regulator_register(&pdev->dev, &drvdata->desc, &cfg); --》rdev = regulator_register(regulator_desc, config);
regulator_ops指針ops是對這個穩壓器硬件操作的封裝,其中包含獲取、設置電壓等的成員函數
//穩壓器硬件操作的封裝,其中包含獲取、設置電壓等 struct regulator_ops { /* enumerate supported voltages */ int (*list_voltage) (struct regulator_dev *, unsigned selector); /* get/set regulator voltage */ int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV, unsigned *selector); int (*map_voltage)(struct regulator_dev *, int min_uV, int max_uV); int (*set_voltage_sel) (struct regulator_dev *, unsigned selector); int (*get_voltage) (struct regulator_dev *); int (*get_voltage_sel) (struct regulator_dev *); /* get/set regulator current */ int (*set_current_limit) (struct regulator_dev *, int min_uA, int max_uA); int (*get_current_limit) (struct regulator_dev *); int (*set_input_current_limit) (struct regulator_dev *, int lim_uA); int (*set_over_current_protection) (struct regulator_dev *); int (*set_active_discharge) (struct regulator_dev *, bool enable); /* enable/disable regulator */ int (*enable) (struct regulator_dev *); int (*disable) (struct regulator_dev *); int (*is_enabled) (struct regulator_dev *); /* get/set regulator operating mode (defined in consumer.h) */ int (*set_mode) (struct regulator_dev *, unsigned int mode); unsigned int (*get_mode) (struct regulator_dev *); /* Time taken to enable or set voltage on the regulator */ int (*enable_time) (struct regulator_dev *); int (*set_ramp_delay) (struct regulator_dev *, int ramp_delay); int (*set_voltage_time) (struct regulator_dev *, int old_uV, int new_uV); int (*set_voltage_time_sel) (struct regulator_dev *, unsigned int old_selector, unsigned int new_selector); int (*set_soft_start) (struct regulator_dev *); /* report regulator status ... most other accessors report * control inputs, this reports results of combining inputs * from Linux (and other sources) with the actual load. * returns REGULATOR_STATUS_* or negative errno. */ int (*get_status)(struct regulator_dev *); /* get most efficient regulator operating mode for load */ unsigned int (*get_optimum_mode) (struct regulator_dev *, int input_uV, int output_uV, int load_uA); /* set the load on the regulator */ int (*set_load)(struct regulator_dev *, int load_uA); /* control and report on bypass mode */ int (*set_bypass)(struct regulator_dev *dev, bool enable); int (*get_bypass)(struct regulator_dev *dev, bool *enable); /* the operations below are for configuration of regulator state when * its parent PMIC enters a global STANDBY/HIBERNATE state */ /* set regulator suspend voltage */ int (*set_suspend_voltage) (struct regulator_dev *, int uV); /* enable/disable regulator in suspend state */ int (*set_suspend_enable) (struct regulator_dev *); int (*set_suspend_disable) (struct regulator_dev *); /* set regulator suspend operating mode (defined in consumer.h) */ int (*set_suspend_mode) (struct regulator_dev *, unsigned int mode); int (*set_pull_down) (struct regulator_dev *); };
4. 運行時調用
調壓前要先獲取regulator handle,然后利用regulator_set_voltage進行調壓
5. Consumer API
5.1 Consumer Regulator Access (static & dynamic drivers)
消費者驅動程序可以通過調用regulator_get訪問其供應調節器:
regulator = regulator_get(dev, "Vcc");
消費者傳入其結構設備指針和電源 ID。然后內核通過查詢特定于機器的查找表找到正確的調節器。如果查找成功,則此調用將返回一個指向提供此使用者的結構調節器的指針。
要釋放調節器,消費者驅動程序應調用:
regulator_put(regulator);
消費者可以由多個調節器供電,例如 具有模擬和數字電源的編解碼器消費者:
digital = regulator_get(dev, "Vcc"); /* digital core */ analog = regulator_get(dev, "Avdd"); /* analog */
調節器訪問函數regulator_get() 和regulator_put() 通常會分別在您的設備驅動程序probe() 和remove() 中調用。
5.2 Regulator Output Enable & Disable (static & dynamic drivers)
消費者可以通過調用regulator_enable啟用調節器:
int regulator_enable(regulator);
在調用regulator_enabled() 之前,電源可能已經啟用。如果消費者共享調節器或調節器先前已由引導加載程序或內核板初始化代碼啟用,則可能會發生這種情況。消費者可以通過調用regulator_is_enabled判斷是否啟用了調節器:
int regulator_is_enabled(regulator);
當調節器啟用時,這將返回大于零。消費者可以在不再需要時通過調用禁用其供應:
int regulator_disable(regulator);
如果它與其他消費者共享,這可能不會禁用供應。僅當啟用的參考計數為零時,才會禁用調節器。最后,在緊急情況下可以強制禁用調節器:
int regulator_force_disable(regulator);
這將立即強制關閉穩壓器輸出。所有消費者都將斷電。
5.3 Regulator Voltage Control & Status (dynamic drivers)
一些消費類驅動器需要能夠動態改變其電源電壓以匹配系統工作點。例如 CPUfreq 驅動程序可以隨頻率調整電壓以節省電量,SD 驅動程序可能需要選擇正確的卡電壓等。
消費者可以通過調用來控制他們的電源電壓:
int regulator_set_voltage(regulator, min_uV, max_uV);
其中 min_uV 和 max_uV 是以微伏為單位的最小和最大可接受電壓。這可以在調節器啟用或禁用時調用。如果在已啟用regulator時調用,則電壓會立即更改,否則電壓配置會更改,并且在下一次啟用穩壓器時會物理設置電壓。調節器配置的電壓輸出可以通過調用找到:
int regulator_get_voltage(regulator);
無論調節器是啟用還是禁用,get_voltage() 都將返回配置的輸出電壓,并且不應用于確定調節器輸出狀態。然而,這可以與 is_enabled() 結合使用來確定穩壓器物理輸出電壓。
5.4 Regulator Current Limit Control & Status (dynamic drivers)
一些消費類驅動程序需要能夠動態更改其電源電流限制以匹配系統工作點。例如 LCD 背光驅動程序可以更改電流限制以改變背光亮度,USB 驅動程序可能希望在供電時將限制設置為 500mA。消費者可以通過調用來控制他們的電源電流限制:
int regulator_set_current_limit(regulator, min_uA, max_uA);
其中 min_uA 和 max_uA 是以微安為單位的最小和最大可接受電流限制。
這可以在調節器啟用或禁用時調用。如果在已啟用電流限制時調用,則電流限制會立即更改,否則電流限制配置會更改,并且在下一次啟用調節器時會設置電流限制。
通過調用可以找到調節器電流限制:
int regulator_get_current_limit(regulator);
無論調節器是啟用還是禁用,get_current_limit() 都將返回電流限制,并且不應用于確定調節器電流負載。
5.5 Regulator Operating Mode Control & Status (dynamic drivers)
一些消費者可以通過改變其電源調節器的工作模式來進一步節省系統功率,以便在消費者工作狀態發生變化時提高效率。例如 消費者驅動程序空閑,隨后消耗較少的電流.調節器操作模式可以間接或直接改變。
間接操作模式控制 消費者驅動程序可以通過以下調用請求更改其電源調節器操作模式:
int regulator_set_load(struct regulator *regulator, int load_uA);
這將導致core重新計算調節器上的總負載(基于其所有消費者)并更改操作模式(如果必要和允許)以最佳匹配當前操作負載。load_uA 值可以從消費者的數據表中確定。例如 大多數數據表都有表格顯示在某些情況下消耗的最大電流。大多數消費者將使用間接操作模式控制,因為他們不了解調節器或調節器是否與其他消費者共享
直接操作模式控制 定制或緊密耦合的驅動器可能希望根據其工作點直接控制調節器的工作模式, 這可以通過調用:
int regulator_set_mode(struct regulator *regulator, unsigned int mode); unsigned int regulator_get_mode(struct regulator *regulator); 直接模式將僅由了解有關調節器且不與其他消費者共享調節器的消費者使用
5.6 Regulator Events
監管機構可以將外部事件通知消費者, 在監管機構壓力或故障條件下,消費者可能會收到事件。消費者調用以下接口注冊感興趣的事件:
int regulator_register_notifier(struct regulator *regulator, struct notifier_block *nb); 消費者調用以下接口反注冊感興趣的事件:
int regulator_unregister_notifier(struct regulator *regulator, struct notifier_block *nb); 監管機構使用內核通知程序框架向感興趣的消費者發送事件。
5.7 Regulator Direct Register Access
某些類型的電源管理硬件或固件被設計為需要對調節器進行低級硬件訪問,而無需內核參與,此類設備的示例有:
帶有壓控振蕩器和控制邏輯的時鐘源,可通過 I2C 改變電源電壓,以實現所需的輸出時鐘速率 熱管理固件,可發出任意 I2C 事務以在過熱條件下執行系統斷電 要設置這樣的設備/固件,需要為其配置各種參數,例如調節器的 I2C 地址、各種調節器寄存器的地址等。監管者框架提供了以下查詢這些詳細信息的幫助程序。
特定于總線的詳細信息,例如 I2C 地址或傳輸速率,由 regmap 框架處理。要獲取監管機構的 regmap(如果支持),請使用:
struct regmap *regulator_get_regmap(struct regulator *regulator); 要獲取穩壓器電壓選擇器寄存器的硬件寄存器偏移量和位掩碼,請使用:
int regulator_get_hardware_vsel_register(struct regulator *regulator, unsigned *vsel_reg, unsigned *vsel_mask); 要將調節器框架電壓選擇器代碼(由調節器列表電壓使用)轉換為可直接寫入電壓選擇器寄存器的特定于硬件的電壓選擇器,請使用:
int regulator_list_hardware_vsel(struct regulator *regulator, unsigned selector);
6. Driver Interface
驅動程序可以通過調用以下接口注冊Regulator:struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, const struct regulator_config *config); 這會將regulator的能力和操作注冊到regulator核心。注銷接口如下:void regulator_unregister(struct regulator_dev *rdev);
調節器可以通過調用以下方式向消費者驅動程序發送事件(例如過熱、欠壓等):int regulator_notifier_call_chain(struct regulator_dev *rdev, unsigned long event, void *data)
最后來個大圖:
審核編輯:劉清
-
穩壓器
+關注
關注
24文章
4258瀏覽量
94183 -
電源管理
+關注
關注
115文章
6193瀏覽量
144952 -
Linux系統
+關注
關注
4文章
595瀏覽量
27510 -
輸出電壓
+關注
關注
2文章
1122瀏覽量
38299 -
電壓調節器
+關注
關注
3文章
150瀏覽量
17953
原文標題:電源管理入門-11Regulator驅動
文章出處:【微信號:OS與AUTOSAR研究,微信公眾號:OS與AUTOSAR研究】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論