Linux regulator分析

Regulator模塊用於控制系統中某些設備的電壓/電流供應。在嵌入式系統(尤其是手機)中,控制耗電量很重要,直接影響到電池的續航時間。所以,如果系統中某一個模塊暫時不需要使用,就可以通過regulator關閉其電源供應;或者降低提供給該模塊的電壓、電流大小。

Regulator的文檔在KERNEL/Documentation/Power/Regulator中。

 

Regulator與模塊之間是樹狀關係。父regulator可以給設備供電,也可以給子regulator供電:

 父Regulator -+->子Regulator --> [Consumer A @ 1.8 - 2.0V] |

             +-> [Consumer B @ 3.3V]

具體細節可參考內核文檔machine.txt。

regulator_dev

regulator_dev代表一個regulator設備。

struct regulator_dev {

           struct regulator_desc *desc;         // 描述符,包括regulator的名稱、ID、regulator_ops等

           int use_count;                                        // 使用計數

           /* lists we belong to */

           struct list_head list;                     // regulator通過此結構掛到regulator_list鏈表中

           struct list_head slist;                   // 如果有父regulator,通過此域掛到父regulator的鏈表

           /* lists we own */

           struct list_head consumer_list;     // 此regulator負責供電的設備列表

           struct list_head supply_list;                      //此regulator負責供電的子regulator

           struct blocking_notifier_head notifier;      // notifier,具體的值在consumer.h中,比如REGULATOR_EVENT_FAIL

           struct mutex mutex;

           struct module *owner;

           struct device dev;                                              // device結構,屬於class regulator_class

           struct regulation_constraints *constraints; // 限制,比如最大電壓/電流、最小電壓/電流

           struct regulator_dev *supply;                  // 父regulator的指針

           void *reg_data;              /* regulator_dev data */

};

regulator_init_data

regulator_init_data在初始化時使用,用來建立父子regulator、受電模塊之間的樹狀結構,以及一些regulator的基本參數。

struct regulator_init_data {

           struct device *supply_regulator_dev;                    // 父regulator的指針

           struct regulation_constraints constraints;

           int num_consumer_supplies;

           struct regulator_consumer_supply *consumer_supplies;      // 負責供電的設備數組

           /* optional regulator machine specific init */

           int (*regulator_init)(void *driver_data);               // 初始化函數

           void *driver_data;          /* core does not touch this */

};

Regulator的註冊

Regulator的註冊由regulator_register完成。

一般來說,爲了添加regulator_dev,需要實現一個設備驅動程序,以及在板子的設備列表中增加一個該驅動對應的設備(比如platform_device)。在這個設備的struct device->platform_data域,需要設置regulator_init結構,填寫該regulator的相關信息。另外,還需要定義一個regulator_desc結構。這樣,在這個物理設備的驅動程序中,就可以通過regulator_register函數登記生成一個regulator_dev。

struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, struct device *dev, void *driver_data)

           struct regulator_init_data *init_data = dev->platform_data;// 得到init_data

           // 完整性檢查

           …

           // 分配regulator_dev結構

           struct regulator_dev *rdev = kzalloc (sizeof(struct regulator_dev), GFP_KERNEL);

           // 初始化regulator_dev結構

           …

           // 執行regulator_init,該函數中實現regulator代表的硬件設備的初始化

           if (init_data->regulator_init)

                       ret = init_data->regulator_init(rdev->reg_data);

           rdev->dev.class = &regulator_class;          // 指定class爲regulator_class

           rdev->dev.parent = dev;

           device_register(&rdev->dev);                  // 註冊設備

           // 設置constraints,其中可能會包括供電狀態的初始化(設置初始電壓,enable/disable等等)

           set_machine_constraints(rdev, &init_data->constraints);

           add_regulator_attributes (rdev);

           // 如果此regulator有父regulator,設置父regulator

           if (init_data->supply_regulator_dev) {

                       ret = set_supply(rdev,

                                   dev_get_drvdata(init_data->supply_regulator_dev));

                       if (ret < 0)

                                   goto scrub;

           }

           // 設置此regulator與其負責供電的設備之間的聯繫

for (i = 0; i < init_data->num_consumer_supplies; i++)

                       ret = set_consumer_device_supply(rdev, init_data->consumer_supplies[i].dev,

                                   init_data->consumer_supplies[i].supply);

           // 將regulator加入一個鏈表,該鏈表包含所有regulator

list_add(&rdev->list, &regulator_list);

 

set_consumer_device_supply函數用於登記regulator_dev與comsumer_dev(regulator負責供電的設備)之間的對應關係。對於每一個regulator_dev—comsumer_dev的配對,都會有一個regulator_map結構,這些結構會被加入到全局鏈表regulator_map_list中。

Regulator的使用

在設備驅動使用regulator對其驅動的設備供電時,需要首先保證設備與對應regulator之間的匹配關係已經被登記到regulator框架中。這可通過填寫regulator_init_data結構實現。(具體可參考內核文檔machine.txt)

之後,設備驅動通過regulator_get函數得到regulator結構,此函數通過前文所述regulator_map_list找到對應regulator_dev,再生成regulator結構給用戶使用。

通過regulator_enable / regulator_disable打開、關閉regulator,這兩個函數最終都是調用struct regulator_ops裏的對應成員。

除此之外,還有regualtor_set_voltage / regulator_get_voltage等等。

Regulator能夠支持的所有功能列表都在struct regulator_ops中定義,具體可參考代碼中的註釋。

struct regulator_ops {

           /* get/set regulator voltage */

           int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV);

           int (*get_voltage) (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 *);

           /* 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 regulator.h) */

           int (*set_mode) (struct regulator_dev *, unsigned int mode);

           unsigned int (*get_mode) (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);

           /* 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 regulator.h) */

           int (*set_suspend_mode) (struct regulator_dev *, unsigned int mode);

};

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章