Regulator 框架(二):Regulators 消費者接口


消費者接口只要求驅動程序包含一個頭文件:

#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 [...]

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM