regulator系統(2)


一、Regulator 簡介
1. Regulator,中文名翻譯為“穩定器”,在電子工程中,是voltage regulator(穩壓器)或者current regulator(穩流器)的簡稱,指可以自動維持恆定電壓(或電流)的裝置。從設備驅動的角度看,regulator的控制應該很簡單,就是輸出的enable/disable、輸出電壓或電流的大小的控制。軟件架構分consumer、provider、core

Linux regulator framework的目的:提供標准的內核接口,控制系統的voltage/current regulators,並提供相應的機制,在系統運行的過程中,動態改變regulators的輸
出,以達到省電的目的。

2. regulator driver

driver模塊的功能,是抽象regulator設備。可以參考 qcom_smd-regulator.c
(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 進行后續的操作。struct regulator_dev *rdev; regulator deriver對regulator的抽象

3. consumer
consumer 的功能,是從 regulator consumer 的角度,抽象 regulator 設備(struct regulator 是對 consumer 設備的抽象描述),並提供 regulator 操作相關的接口。
struct regulator consumer視角對regulator的抽象。

4. core
core負責上述邏輯的具體實現,並以sysfs的形式,向用戶空間提供接口。

 

二、相關接口介紹
1. regulator framework 向內核空間 consumer 提供的接口位於“include/linux/regulator/consumer.h”中,包括 regulator 的獲取、使能、修改等接口,如下。

(1) struct regulator
struct regulator結構用於從 consumer 的角度抽象一個regulator,consumer不需要關心該結構的細節,當作一個句柄使用即可。

(2) regulator的get/put接口

struct regulator *__must_check regulator_get(struct device *dev, const char *id);
struct regulator *__must_check devm_regulator_get(struct device *dev, const char *id);
struct regulator *__must_check regulator_get_exclusive(struct device *dev, const char *id);
struct regulator *__must_check devm_regulator_get_exclusive(struct device *dev, const char *id);
struct regulator *__must_check regulator_get_optional(struct device *dev, const char *id);
struct regulator *__must_check devm_regulator_get_optional(struct device *dev, const char *id);
void regulator_put(struct regulator *regulator);
void devm_regulator_put(struct regulator *regulator);

(3) 根據是否獨占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。

(4) supply alias相關的接口

int regulator_register_supply_alias(struct device *dev, const char *id, struct device *alias_dev, const char *alias_id);
void regulator_unregister_supply_alias(struct device *dev, const char *id);
int devm_regulator_register_supply_alias(struct device *dev, const char *id, struct device *alias_dev, const char *alias_id);
void devm_regulator_unregister_supply_alias(struct device *dev, const char *id);
int devm_regulator_bulk_register_supply_alias(struct device *dev, const char *const *id, struct device *alias_dev, const char *const *alias_id, nt num_id);
void devm_regulator_bulk_unregister_supply_alias(struct device *dev, const char *const *id, int num_id);

(5) regulator的控制、狀態獲取接口

int __must_check regulator_enable(struct regulator *regulator);
int regulator_disable(struct regulator *regulator);
int regulator_force_disable(struct regulator *regulator);
int regulator_is_enabled(struct regulator *regulator);
int regulator_disable_deferred(struct regulator *regulator, int ms);

int regulator_can_change_voltage(struct regulator *regulator);
int regulator_count_voltages(struct regulator *regulator);
int regulator_list_voltage(struct regulator *regulator, unsigned selector);
int regulator_is_supported_voltage(struct regulator *regulator, int min_uV, int max_uV);
unsigned int regulator_get_linear_step(struct regulator *regulator);
int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV);
int regulator_set_voltage_time(struct regulator *regulator, int old_uV, int new_uV);
int regulator_get_voltage(struct regulator *regulator);
int regulator_sync_voltage(struct regulator *regulator);
int regulator_set_current_limit(struct regulator *regulator, int min_uA, int max_uA);
int regulator_get_current_limit(struct regulator *regulator);

int regulator_set_mode(struct regulator *regulator, unsigned int mode);
unsigned int regulator_get_mode(struct regulator *regulator);
int regulator_set_optimum_mode(struct regulator *regulator, int load_uA);

int regulator_allow_bypass(struct regulator *regulator, bool allow);

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);

控制有關的包括enable、disable、電壓設置、電流設置、mode設置、狀態獲取等,其中disable又包括normal、強制、退出等類型。
狀態獲取包括:是否enable,是否可以改變電壓,支持的電壓列表,是否支持指定范圍的電壓,當前輸出電壓,當前電流限制,當前mode,等等。

(6) bulk型的操作(一次操作多個regulator)

int regulator_bulk_register_supply_alias(struct device *dev, const char *const *id, struct device *alias_dev, const char *const *alias_id, int num_id);
void regulator_bulk_unregister_supply_alias(struct device *dev, const char * const *id, int num_id);
int __must_check regulator_bulk_get(struct device *dev, int num_consumers, struct regulator_bulk_data *consumers);
int __must_check devm_regulator_bulk_get(struct device *dev, int num_consumers, struct regulator_bulk_data *consumers);
int __must_check regulator_bulk_enable(int num_consumers, struct regulator_bulk_data *consumers);
int regulator_bulk_disable(int num_consumers, struct regulator_bulk_data *consumers);
int regulator_bulk_force_disable(int num_consumers, struct regulator_bulk_data *consumers);
void regulator_bulk_free(int num_consumers, struct regulator_bulk_data *consumers);

(7) inotifier相關的接口

int regulator_register_notifier(struct regulator *regulator, struct notifier_block *nb);
int regulator_unregister_notifier(struct regulator *regulator, struct notifier_block *nb);

如果consumer關心某個regulator的狀態變化,可以通過上面接口注冊一個notifier。

(8) 其它接口

/* driver data - core doesn't touch */
void *regulator_get_drvdata(struct regulator *regulator);
void regulator_set_drvdata(struct regulator *regulator, void *data);

用於設置和獲取driver的私有數據。

 

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禁止)。

3. machine 模塊向 regulator driver 提供的接口
machine 模塊主要提供 struct regulator_init_data、struct regulation_constraints constraints 等數據結構,用於描述板級的 regulator 配置。

4. regulator framework 模塊向 regulator driver 提供的接口
regulator framework 向 regulator driver 提供的接口位於“include/linux/regulator/driver.h”中,包括數據結構抽象、regulator注冊等。
(1) 數據結構抽象有 struct regulator_desc、struct regulator_config 和 struct regulator_dev
(2) regulator設備的注冊接口

struct regulator_dev * regulator_register(const struct regulator_desc *regulator_desc, const struct regulator_config *config);
struct regulator_dev * devm_regulator_register(struct device *dev, const struct regulator_desc *regulator_desc, const struct regulator_config *config);
void regulator_unregister(struct regulator_dev *rdev);
void devm_regulator_unregister(struct device *dev, struct regulator_dev *rdev);

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接口,主動添加。位於/sys/class/regulator/.../目錄下,具體可參考:https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-regulator。

 

三、編寫與regulator 設備樹節點對應的driver

1. 這些driver的存在形式是多種多樣的,但所做的工作基本類似:

(1) 初始化regulator的宿主(如tps5163、PMIC、等等),最終的目的是,通過宿主提供的接口,修改regulator的輸出。
(2) 初始化用於描述regulator的靜態信息(struct regulator_desc)和動態信息(struct regulator_config),並以這二者為參數,調用regulator_register接口,將regulator注冊到kernel中。
(3) 靜態信息中包含regulator的操作函數集(struct regulator_ops),后續regulator的控制,將會由regulator framework core直接調用這些回調函數完成。
(4) 后面的事情,例如sysfs attribute創建等,就交給regulator framework core了。

2. 相關結構體

(1) struct regulator_init_data

struct regulator_init_data {
    /* 該regulator的前級regulator,一般在regulator driver中直接指定 */
    const char *supply_regulator;

    /*
     * 該regulator的使用限制,由DTS配置,並可以借助regulator core提供的輔助
     * API(regulator_of_get_init_data)自動解析。
     */
    struct regulation_constraints constraints;

    /*
     * 使用該regulator的consumer的個數,及其設備名和supply名的map。
     * 用於建立consumer設備和regulator之間的關聯.
     */
    int num_consumer_supplies;
    struct regulator_consumer_supply *consumer_supplies;

    /* 
     * 可選的特定於機器的初始化函數,是regulator的init回調,
     * 由regulator driver提供,並在regulator注冊時調用。
     */
    int (*regulator_init)(void *driver_data);
    /* 保存driver的私有數據,並在調用regulator_init時傳入 */
    void *driver_data;    /* core does not touch this */
};

對regulator driver而言,DTS主要用於配置regulator的init data(struct regulator_init_data)。

(2) struct regulation_constraints 

struct regulation_constraints {
    /* 用於描述該constraints */
    const char *name;

    /* 輸出電壓的范圍,[min_uV, max_uV],單位為uV, 只對voltage regulator有效. */
    int min_uV;
    int max_uV;

    /* 
     * consumer看到的電壓和實際電壓之間的偏移值。通常 用於補償壓降。只對voltage
     * regulator有效;
     */
    int uV_offset;

    /* 輸出電流的范圍,[min_uA, max_uA],單位為uA。只對current regulator有效 */
    int min_uA;
    int max_uA;
    int ilim_uA;

    int system_load;

    /* valid regulator operating modes for this machine */
    unsigned int valid_modes_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. 
     *    REGULATOR_CHANGE_BYPASS,支持bypass模式。
     */
    unsigned int valid_ops_mask;

    /*
     * 如果該regulator的輸入是另一個regulator,該字段指定regulator期望的輸入電壓;
     * regulator input voltage - only if supply is another regulator 
     */
    int input_uV;

    /*
     * regulator電源管理有關的字段
     * regulator suspend states for global PMIC STANDBY/HIBERNATE
     */
    struct regulator_state state_disk;
    struct regulator_state state_mem;
    struct regulator_state state_standby;
    suspend_state_t initial_state; /* suspend state to set at init */

    /* 初始mode mode to set on startup */
    unsigned int initial_mode;

    /*
     * 由於模擬器件的特性,電壓改變,需要一定的生效時間。在一定的范圍內,生效時間和電
     * 壓的變化值成比例。該變量就是描述regulator器件的這個特性,單位為uV/us,即1us可
     * 以產生多大的電壓變化。在rapm_disable不為1的情況下,當consumer要求改變電壓時,
     * regulator framework core會根據該變量,以及電壓改變量,計算出需要等待的時間,
     * 進行延時操作.
     */
    unsigned int ramp_delay;
    /*
     * regulator的開啟時間,單位為us。consumer enable regulator時,
     * regulator framework會根據該變量進行延時操作
     */
    unsigned int enable_time;

    /* 是否一直保持使能狀態 */
    unsigned always_on:1;    /* regulator never off when system is on */
    /* 是否在啟動時使能 */
    unsigned boot_on:1;    /* bootloader/firmware enabled regulator */
    /*
     * 如果min_uV和max_uV相同,該變量指示“在regulator注冊到kernel時,
     * 是否將電壓設置為min_uV/max_uV。 
     */
    unsigned apply_uV:1;    /* apply uV constraint if min == max */
    /* 是否禁止延時操作 */
    unsigned ramp_disable:1; /* disable ramp delay */
    unsigned soft_start:1;    /* ramp voltage slowly */
    unsigned pull_down:1;    /* pull down resistor when regulator off */
    unsigned over_current_protection:1; /* auto disable on over current */
};

DTS的內容都在struct regulation_constraints中,該結構保存了該regulator所有的物理限制

結合struct regulation_constraints結構,我們解釋DTS:

tps51632@43 {
    compatible = "ti,tps51632";
    reg = <0x43>;
    regulator-name = "vdd-cpu";
    regulator-min-microvolt = <500000>;
    regulator-max-microvolt = <1520000>;
    regulator-boot-on;
    regulator-always-on;
};

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) struct regulator_desc

struct regulator_desc {
    /* 該regulator的名稱,唯一標識該regulator,必須提供 */
    const char *name;
    /* 該regulator的輸入regulator的名稱 */
    const char *supply_name;
    const char *of_match;
    const char *regulators_node;
    int (*of_parse_cb)(struct device_node *, const struct regulator_desc *, struct regulator_config *);
    /* 標識該regulator的一個數字 */
    int id;
    /* 為true時,表示該regulator可以在一定范圍輸出連續的電壓 */
    bool continuous_voltage_range;
    /*
     * consumer可以通過ops.list_voltage()接口,獲取該regulator可以輸出的電壓值。
     * 該變量指定可以獲取的電壓值的個數
     */
    unsigned n_voltages;
    /* 該regulator的操作函數集 */
    const struct regulator_ops *ops;
    /* 該regulator的中斷號(有的話) */
    int irq;
    /* 該regulator的類型,包括REGULATOR_VOLTAGE和REGULATOR_CURRENT兩種 */
    enum regulator_type type;
    struct module *owner;

    unsigned int min_uV;
    unsigned int uV_step;
    unsigned int linear_min_sel;
    int fixed_uV;
    unsigned int ramp_delay;
    int min_dropout_uV;

    const struct regulator_linear_range *linear_ranges;
    int n_linear_ranges;

    const unsigned int *volt_table;

    unsigned int vsel_reg;
    unsigned int vsel_mask;
    unsigned int apply_reg;
    unsigned int apply_bit;
    unsigned int enable_reg;
    unsigned int enable_mask;
    unsigned int enable_val;
    unsigned int disable_val;
    bool enable_is_inverted;
    unsigned int bypass_reg;
    unsigned int bypass_mask;
    unsigned int bypass_val_on;
    unsigned int bypass_val_off;

    unsigned int enable_time;

    unsigned int off_on_delay;

    unsigned int (*of_map_mode)(unsigned int mode);
};

在注冊regulator的時候,需要使用 struct regulator_desc 結構提供該regulator的靜態描述。所謂的靜態,是指這些描述不會在運行時改變,代表了設備的一種屬性,

(4) struct regulator_config

struct regulator_config {
    /*會在regulator_register時,由regulator core分配,保存在此,以便后續使用*/
    struct device *dev;
    /*init data指針,在解析DTS后,保存在此,以便后續使用*/
    const struct regulator_init_data *init_data;
    void *driver_data;
    struct device_node *of_node;
    struct regmap *regmap;

    bool ena_gpio_initialized;
    int ena_gpio;
    unsigned int ena_gpio_invert:1;
    unsigned int ena_gpio_flags;
};

struct regulator_config保存了regulator的動態信息,所謂的動態信息,是指那些會在driver運行過程中改變、或者driver運行后才會確定的信息.

(5) struct regulator_dev

struct regulator_dev {
    const struct regulator_desc *desc;
    int exclusive;
    u32 use_count;
    u32 open_count;
    u32 open_offset;
    u32 bypass_count;

    /* lists we belong to */
    struct list_head list; /* list of all regulators */

    /* lists we own */
    struct list_head consumer_list; /* consumers we supply */

    struct blocking_notifier_head notifier;
    struct mutex mutex; /* consumer lock */
    struct module *owner;
    struct device dev;
    struct regulation_constraints *constraints;
    struct regulator *supply;    /* for tree */
    const char *supply_name;
    struct regmap *regmap;

    struct delayed_work disable_work;
    int deferred_disables;

    void *reg_data;        /* regulator_dev data */

    struct dentry *debugfs;

    struct regulator_enable_gpio *ena_pin;
    unsigned int ena_gpio_state:1;

    /* time when this regulator was disabled last time */
    unsigned long last_off_jiffy;
    struct proxy_consumer *proxy_consumer;
    struct regulator *debug_consumer;
};

struct regulator_dev是regulator設備的抽象,當driver以struct regulator_desc、struct regulator_config兩個類型的參數,調用regulator_register將regulator注冊
到kernel之后,regulator就會分配一個struct regulator_dev變量,后續所有的regulator操作,都將以該變量為對象。

3. regulator的操作模式(operation mode)

regulator的主要功能,是輸出電壓/電流的調整。由於模擬器件的特性,電壓/電流的改變,是需要一定的時間的。對有些regulator而言,可以工作在不同的模式,這些模式
有不同的改變速度(一般較快的速度,有較大的功耗)。下面是operation mode定義(位於include/linux/regulator/consumer.h中):

#define REGULATOR_MODE_FAST            0x1
#define REGULATOR_MODE_NORMAL        0x2
#define REGULATOR_MODE_IDLE            0x4
#define REGULATOR_MODE_STANDBY        0x8

相應的,regulator framework 提供了一些機制,用於 operation mode 的操作,包括:
(1) struct regulation_constraints 中用於表示初始模式的字段 initial_mode。
(2) regulator ops中的set_mode/get_mode回調函數。

4. kernel抽象了兩種電壓操作的方法:

(1) 直接操作電壓,對應struct regulator_ops中的list_voltage、get_voltage、set_voltage回調函數:

set_voltage:用於將電壓設置為min_uV和max_uV范圍內、和min_uV最接近的電壓。該接口可以返回一個selector參數,用於告知調用者,實際的電壓值;
get_voltage:用於返回當前的電壓值;
list_voltage:以selector為參數,獲取對應的電壓值。

(2) selector的形式

regulator driver以selector的形式,反映電壓值。selector是一個從0開始的整數,driver提供的相關接口為struct regulator_ops中的list_voltage、map_voltage、
set_voltage_sel、get_voltage_sel回調函數。
map_voltage: 是和list_voltage相對的接口,用於將電壓范圍map成一個selector值;
set_voltage_sel/get_voltage_sel:以selector的形式,操作電壓。

regulator driver可以根據實際情況,選擇一種實

 


免責聲明!

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



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