Linux regulator framework(1) - 概述【轉】

来源:https://www.cnblogs.com/linhaostudy/archive/2018/03/24/8639124.html
-Advertisement-
Play Games

轉自蝸窩科技:http://www.wowotech.net/pm_subsystem/regulator_framework_overview.html 1. 前言 Regulator,中文名翻譯為“穩定器”,在電子工程中,是voltage regulator(穩壓器)或者current regu ...


轉自蝸窩科技:http://www.wowotech.net/pm_subsystem/regulator_framework_overview.html

 

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的輸出限值(這一般由產品設計、硬體設計決定的)。

 同時,一旦設計確定下來之後,這些限制必須保存在一些相對固定的地方,不能輕易地被軟體修改。

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提供服務的對象。比如LCD使用regulator管理自己,就必須使用regulator core提供的regulator相關介面函數。regulator_get()/regulator_put()函數。

 

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介面,主動添加。

 

 

5、FAQ

kobe.bao 
2016-03-07 20:48 Hi wowo: 

   關於電源管理,有個問題請教,是這樣的(高通soc晶元): 

   需要regulator供電的外設,都會在其DTS中對regulator進行設置(暫且稱之為regulator設置節點),例如: 

   qcom,ctrl-supply-entry@0 { 

         qcom,supply-name = "vdda"; 

         qcom,supply-min-voltage = <1250000>; 

         qcom,supply-max-voltage = <1250000>; 

        ... 

         }; 

    驅動代碼中會對該節點進行解析,利用regulator_get、regulator_count_voltages等API函數進行設置。 

    通常,外設的DTS中還有一個這樣的節點,例如: 

    vdda-supply = <&pm8994_l2> 

    該節點的解釋是“Phandle for vreg regulator device node”,暫且稱為regulator設備節點。但是我在代碼中並沒有找到對該節點的解析,我想請問,regulator設備節點與regulator設置節點是怎麼聯繫起來的? 回覆 wowo 
2016-03-07 22:39 @kobe.bao:qcom,supply-name = "xxx"; 

xxx-supply = <&pm8994_l2> 

這裡的xxx是“vdda”,就是這樣聯繫起來的。 回覆 kobe.bao 
2016-03-08 18:52 @wowo:Hi wowo: 

   感謝回答。 

   我也猜到他們是這樣聯繫起來的,但是在代碼中我沒有找到相關的部分,心裡總覺得不踏實,能否指點下代碼中是如何實現聯繫的?謝謝 回覆 wowo 
2016-03-08 21:20 @kobe.bao:關於regulator的supply,我在“http://www.wowotech.net/pm_subsystem/regulator_driver.html”中有提到,其實就是在regulator_register的時候,解析DTS中“supply-name”的值,然後調用regulator_dev_lookup介面,找到對應的struct regulator指針(就是“xxx-supply = <&pm8994_l2> ”所對應的指針)。  
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • nuget獲取Newtonsoft.Json github地址: "Newtonsoft.Json" ...
  • //定義報表模板 private GridppReport Report = new GridppReport(); //載入報表模板數據 Report.LoadFromFile(GridppReportDemo.Utility.GetReportTemplatePath() + "program\ ...
  • 1、添加引用Newtonsoft.Json.dll 2、具體代碼: ...
  • 概述 前幾天的 Windows Developer Day 正式發佈了 Windows AI Platform,而作為 Windows AI Platform 的模型定義和訓練,更多還是需要藉助雲端來實現。Azure 無疑是一個很好的選擇。 Azure 作為微軟近幾年主推的雲服務,在 AI 和 Ma ...
  • 新建目錄www 下載nodejs 解壓 測試是否安裝成功 進入解壓目錄下的 bin 目錄,執行 ls 命令 有node 和 npm 測試 安裝成功 現在 node 和 npm 還不能全局使用,做個鏈接 可以在任何目錄下執行 node 和 npm 命令 最主要的原因還是在NPM上,因為用了n來管理no ...
  • VMware14安裝Ubuntu16.04教程 久聞Linux(這單詞念做 林尼克斯??)大名,閑來無事就試著給自己筆記本裝一個玩玩,從朋友口中得知可以在Vmware上裝虛擬機,就自己試著嘗試一下,順便隨意記錄一下過程。 1. Vmware14的安裝 百度Vmware14,直接點普通下載就好,接下來 ...
  • 轉自蝸窩科技:http://www.wowotech.net/pm_subsystem/regulator_driver.html 說實話,這篇好難懂啊。。。 1. 前言 本文從regulator driver的角度,描述怎樣基於regulator framework編寫regulator驅動。同時 ...
  • Lvs集群的通用結構 Lvs集群採用IP負載均衡技術,屬於IP層的交換(L4),具有很好的吞吐率。調度器分析客戶端到伺服器的IP報頭信息,將請求均衡地轉移到不同的伺服器上執行,且調度器自動屏蔽掉伺服器的故障,從而將一組伺服器構成一個高性能的、高可用的虛擬伺服器,Lvs集群系統的通用結構如下所示,主要 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...