消費者接口只要求驅動程序包含一個頭文件:
#include <linux/regulator/consumer.h>
消費者可以是靜態的,也可以是動態的。靜態調節器只需要一個固定的電源,而動態調節器需要在運行時對調節器進行主動管理。從消費者的角度來看,調節器設備在內核中被表示為一個struct regulator 結構的實例,在drivers/regulator/internal.h中定義,如下所示:
/* * struct regulator * * One for each consumer device. */ struct regulator { struct device *dev; struct list_head list; unsigned int always_on:1; unsigned int bypass:1; int uA_load; int min_uV; int max_uV; char *supply_name; struct device_attribute dev_attr; struct regulator_dev *rdev; struct dentry *debugfs; };
這個結構足夠有意義,不需要我們添加任何注釋。為了了解消費一個調節器是多么容易,這里有一個消費者如何獲得一個調節器的小例子:
[...] int ret; struct regulator *reg; const char *supply = "vdd1"; int min_uV, max_uV; reg = regulator_get(dev, supply); [...]
regulator設備請求
在獲得對調節器的訪問權之前,使用者必須通過 regulator_get() 函數請求內核。也可以使用托管版本的 devm_regulator_get() 函數:
struct regulator *regulator_get(struct device *dev, const char *id)
使用該函數的示例如下:
reg = regulator_get(dev, "Vcc");
消費者在其結構體中傳遞設備指針和電源ID。核心將通過咨詢DT或特定於機器的查找表來尋找正確的調節器。如果我們只關注設備樹,*id應該匹配設備樹中調節器提供的<name>模式。如果查找成功,則此調用將返回一個指向提供此消費者的struct regulator 的指針。
為了釋放 regulator,消費者驅動者應該調用:
void regulator_put(struct regulator *regulator)
在調用這個函數之前,驅動程序應該確保對這個調節器源的所有regulator_enable()調用都被regulator_disable()調用平衡。
一個消費者可以由多個 regulator 提供。例如,使用模擬和數字設備的編解碼器消費者:
digital = regulator_get(dev, "Vcc"); /* digital core */ analog = regulator_get(dev, "Avdd"); /* analog */
消費者 probe() 和 remove() 函數是獲取和釋放調節器的合適位置。
控制 regulator 設備
調節器控制包括調節器的啟用、禁用和設置輸出值。
啟用和禁用 regulator 輸出
消費者可以通過調用以下命令來啟用它的電源:
int regulator_enable(regulator);
如果函數執行成功,將返回0。反向操作包括禁用電源,調用如下:
int regulator_disable(regulator);
要檢查調節器是否已經啟用,消費者應該調用這個:
int regulator_is_enabled(regulator);
如果啟用了調節器,該函數將返回一個大於0的值。由於調節器可能由引導加載程序提前啟用或與另一個使用者共享,您可以使用regulator_is_enabled()函數來檢查調節器狀態。
printk (KERN_INFO "Regulator Enabled = %d\n", regulator_is_enabled(reg));
對於共享調節器,regulator_disable()實際上只在啟用的引用計數為零時禁用調節器。也就是說,你可以在緊急情況下強制禁用。例如,通過調用regulator_force_disable():
int regulator_force_disable(regulator);
在接下來內容討論的每個函數實際上都是對 regulator_ops 操作的包裝。例如,regulator_set_voltage() 在內部調用 regulator_ops.set_voltage 在檢查了相應的掩碼后允許設置此操作。
電壓控制與狀態
於需要根據操作模式調整電源的用戶,內核提供了如下功能:
int regulator_set_voltage(regulator, min_uV, max_uV);
min_uV和max_uV是以微伏為單位的最小和最大可接受電壓。
如果在穩壓器被禁用時調用該功能,則該功能將改變電壓配置,以便在穩壓器下次啟用時物理設置電壓。也就是說,消費者可以通過調用regulator_get_voltage()獲得調節器配置的電壓輸出,無論調節器是否啟用,它都會返回配置的輸出電壓:
int regulator_get_voltage(regulator);
printk (KERN_INFO "Regulator Voltage = %d\n", regulator_get_voltage(reg));
電流控制及狀態
我們在電壓部分所討論的問題在這里也適用。例如,USB驅動程序可能希望在供電時將限制設置為500 mA。
消費者可以通過調用以下函數來控制他們的供電電流限制:
int regulator_set_current_limit(regulator, min_uA, max_uA);
min_uA 和 max_uA 是以微安為單位的最小和最大可接受電流限制。
同樣,消費者可以通過調用 regulator_get_current_limit() 得到調節器配置的電流限制,無論調節器是否啟用,調節器都會返回電流限制的值:
int regulator_get_current_limit(regulator);
操作模式控制和狀態
為了高效的電源管理,一些用戶可能會在其(用戶)運行狀態發生變化時改變其電源的運行模式。消費者驅動可通過以下方式請求改變供應調節器的工作模式:
int regulator_set_optimum_mode(struct regulator *regulator, int load_uA); int regulator_set_mode(struct regulator *regulator, unsigned int mode); unsigned int regulator_get_mode(struct regulator *regulator);
只有當消費者知道調節器並且不與其他消費者共享調節器時,才應該在調節器上使用regulator_set_mode()。這被稱為直接模式。現在,regulator_set_uptimum_mode() 導致核心進行一些后台工作,以確定對請求的當前操作模式是最好的。這被稱為間接模式。
Regulator binding
這里只討論消費者接口綁定。消費者節點可以使用以下綁定引用一個或多個供應/調節器:
<name>-supply: phandle to the regulator node
它與PWM消費者綁定的原理相同。現在,<name>應該足夠有意義了,以便驅動程序可以在請求調節器時輕松地引用它。也就是說,<name>必須匹配 regulator_get() 函數的*id參數:
twl_reg1: regulator@0 { [...] };
twl_reg2: regulator@1 { [...] };
mmc: mmc@0x0 { [...] vmmc-supply = <&twl_reg1>; vmmcaux-supply = <&twl_reg2>; };
實際請求它的供應的消費者代碼(即MMC驅動程序)可能是這樣的:
1 struct regulator *main_regulator; 2 struct regulator *aux_regulator; 3 int ret; 4 main_regulator = devm_regulator_get(dev, "vmmc"); 5 6 /* 7 * It is a good practice to apply the config before 8 * enabling the regulator 9 */ 10 if (!IS_ERR(io_regulator)) { 11 regulator_set_voltage(main_regulator, 12 MMC_VOLTAGE_DIGITAL, 13 MMC_VOLTAGE_DIGITAL); 14 ret = regulator_enable(io_regulator); 15 } 16 [...] 17 aux_regulator = devm_regulator_get(dev, "vmmcaux"); 18 [...]