轉自蝸窩科技:http://www.wowotech.net/pm_subsystem/regulator_driver.html 說實話,這篇好難懂啊。。。 1. 前言 本文從regulator driver的角度,描述怎樣基於regulator framework編寫regulator驅動。同時 ...
轉自蝸窩科技:http://www.wowotech.net/pm_subsystem/regulator_driver.html
說實話,這篇好難懂啊。。。
1. 前言
本文從regulator driver的角度,描述怎樣基於regulator framework編寫regulator驅動。同時,以此為契機,學習、理解regulator有關的物理特性,以便能夠更好的使用它們。
2. regulator driver的實現步驟
2.1 確定系統中regulator有關的硬體組成
提起硬體,最好能有個例子,好在有device tree,一個活生生的硬體拓撲結構。這裡以NVIDIA Tegra Dalmore A04開發板為例(regulator有關的device tree位於“arch\arm\boot\dts\tegra114-dalmore.dts”):
這裡的regulator結構是相當複雜的,其中彩色框代表最終的regulator抽象,它的前一級表示regulator的載體(可以是PMIC、CPU、等等)。下麵將會詳細說明:
a)CPU通過I2C controller,連接一個降壓控制器(TI tps51632),該控制器輸出名稱為“vdd-cpu”的電壓,就稱作vdd-cpu regulator吧(因此,在kernel中,regulator是一個虛擬設備)。
b)CPU通過I2C controller,連接一個前端電源管理晶元(TI tps65090),該晶元除了具備充電管理功能外,內置了多個regulator,例如dcdc1、dcdc2等等。
c)CPU通過I2C controller,連接另一個電源管理晶元(TI tps65913),該晶元具有兩個功能:GPIO輸出和PMIC。PMIC內置了多個regulator,如vddio-ddr、vdd-core等等。
d)CPU內部也集成了一些regulator,如vdd_ac_bat等等。
這些思考在本文的例子(NVIDIA Tegra Dalmore A04的regulator)中體現尤為突出,它的本質是軟體設計中的模塊劃分,從而決定了regulator在DTS中的呈現方式和層次。
2.2 使用DTS,將硬體拓撲呈現出來
1)tps51632(是一種電源管理模塊)
tps51632是一個簡單的器件,位於i2c匯流排下麵,包含一個regulator器件,因此其DTS比較簡單,如下:
1: /* arch\arm\boot\dts\tegra114-dalmore.dts */ 2: i2c@7000d000 { 3: status = "okay"; 4: clock-frequency = <400000>; 5: 6: tps51632@43 { 7: compatible = "ti,tps51632"; 8: reg = <0x43>; 9: regulator-name = "vdd-cpu"; 10: regulator-min-microvolt = <500000>; 11: regulator-max-microvolt = <1520000>; 12: regulator-boot-on; 13: regulator-always-on; 14: }; 15: ... 16: }
i2c控制器的node為“i2c@7000d000”,tps51632是其下的一個子node,名稱為“tps51632@43”,compatible為“ti,tps51632”。tps51632下麵以“regulator-”為首碼的欄位,是regulator特有的欄位,後面會統一介紹。
註2:為什麼“i2c@7000d000”中沒有compatible欄位?其實是有的,可參考“arch\arm\boot\dts\tegra114.dtsi”,DTC在編譯DTS時,會將這兩個文件中的node合併。
註3:kernel在初始化時,只會為二級node(即“/”下麵的節點,本文的例子是“i2c@7000d000”)創建platform設備,至於三級node(這裡的“tps51632@43”),則由其bus(i2c)創建。後面我們會遇到其它的情況,到時再介紹。
2)tps65090
tps65090相對比較複雜,它位於相同的i2c匯流排下麵,但包含兩個相對複雜的功能實體,charger和PMIC,我們看看其DTS怎麼寫的:
1: i2c@7000d000 { 2: status = "okay"; 3: ... 4: 5: tps65090@48 { 6: compatible = "ti,tps65090"; 7: reg = <0x48>; 8: ... 9: 10: charger: charger { 11: compatible = "ti,tps65090-charger"; 12: ti,enable-low-current-chrg; 13: }; 14: 15: regulators { 16: tps65090_dcdc1_reg: dcdc1 { 17: regulator-name = "vdd-sys-5v0"; 18: regulator-always-on; 19: regulator-boot-on; 20: }; 21: 22: tps65090_dcdc2_reg: dcdc2 { 23: regulator-name = "vdd-sys-3v3"; 24: regulator-always-on; 25: regulator-boot-on; 26: }; 27: ... 28: } 29: } 30: }
和tps51632類似,但它下麵又包含了兩個子node:charger和regulators。其中charger竟然還有compatible欄位。
回憶一下上面“註3”,kernel只會為"i2c@7000d000”創建platform device,“tps65090@48”則由i2c core創建,那麼它下麵的子node呢?一定是tps65090 driver處理了,感興趣的讀者可以閱讀“drivers/mfd/tps65090.c”、“drivers/power/tps65090-charger.c”和“drivers/regulator/tps65090-regulator.c”,這裡面還涉及了MFD(multi-function device,多功能設備),很有意思。
回到本文的主題上,雖然這裡的regulators沒有compatible欄位,也會創建相應的platform device(具體可參考“drivers/mfd/tps65090.c”),這從側面回答了上面的一個思考:從物理範疇,tps65090是一個獨立的設備,但它內部有兩個功能模塊,因此會存在兩個platform device。
3)tps65913,和tps65090類似,不再介紹。
4)CPU中的regulator
這一類regulator比較特殊,直接集成在CPU內部,DTS如下:
1: regulators { 2: compatible = "simple-bus"; 3: #address-cells = <1>; 4: #size-cells = <0>; 5: 6: vdd_ac_bat_reg: regulator@0 { 7: compatible = "regulator-fixed"; 8: reg = <0>; 9: regulator-name = "vdd_ac_bat"; 10: regulator-min-microvolt = <5000000>; 11: regulator-max-microvolt = <5000000>; 12: regulator-always-on; 13: }; 14: 15: dvdd_ts_reg: regulator@1 { 16: compatible = "regulator-fixed"; 17: reg = <1>; 18: regulator-name = "dvdd_ts"; 19: regulator-min-microvolt = <1800000>; 20: regulator-max-microvolt = <1800000>; 21: enable-active-high; 22: gpio = <&gpio TEGRA_GPIO(H, 5) GPIO_ACTIVE_HIGH>; 23: }; 24: ... 25: };
在回到剛纔的話題上,kernel只為二級node創建platform device(這裡的“regulators”),那三級node(一個個的regulator)呢?沒有相對標準的bus幫它們創建怎麼辦?藉助“simple-bus”,具體可以參考of_platform_bus_create(“Device Tree(三):代碼分析”)。
另外,這裡的例子比較簡單,都是fixed regulator,regulator framework core可以幫忙實現fixed類型的regulator的驅動,後面會說明。
2.3 編寫與DTS節點對應的driver
這些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了。
3. DTS相關的實現邏輯
3.1 DTS的內容
回憶一下“Linux Regulator Framework(1)_概述”中介紹的machine的主要功能:使用軟體語言(struct regulator_init_data),靜態的描述regulator在板級的物理現狀。對regulator driver而言,DTS主要用於配置regulator的init data。先看一下struct regulator_init_data:
1: /** 2: * struct regulator_init_data - regulator platform initialisation data. 3: * 4: * Initialisation constraints, our supply and consumers supplies. 5: * 6: * @supply_regulator: Parent regulator. Specified using the regulator name 7: * as it appears in the name field in sysfs, which can 8: * be explicitly set using the constraints field 'name'. 9: * 10: * @constraints: Constraints. These must be specified for the regulator to 11: * be usable. 12: * @num_consumer_supplies: Number of consumer device supplies. 13: * @consumer_supplies: Consumer device supply configuration. 14: * 15: * @regulator_init: Callback invoked when the regulator has been registered. 16: * @driver_data: Data passed to regulator_init. 17: */ 18: struct regulator_init_data { 19: const char *supply_regulator; /* or NULL for system supply */ 20: 21: struct regulation_constraints constraints; 22: 23: int num_consumer_supplies; 24: struct regulator_consumer_supply *consumer_supplies; 25: 26: /* optional regulator machine specific init */ 27: int (*regulator_init)(void *driver_data); 28: void *driver_data; /* core does not touch this */ 29: };
supply_regulator,該regulator的前級regulator,一般在regulator driver中直接指定;
constraints,該regulator的使用限制,由DTS配置,並可以藉助regulator core提供的輔助API(regulator_of_get_init_data)自動解析。後面會詳細介紹;
num_consumer_supplies、consumer_supplies,使用該regulator的consumer的個數,及其設備名和supply名的map。用於建立consumer設備和regulator之間的關聯,後面介紹consumer DTS時再詳細說明;
regulator_init,regulator的init回調,由regulator driver提供,併在regulator註冊時調用;
driver_data,保存driver的私有數據,併在調用regulator_init時傳入。
看來DTS的內容都在struct regulation_constraints中,該結構保存了該regulator所有的物理限制,如下:
1: struct regulation_constraints { 2: 3: const char *name; 4: 5: /* voltage output range (inclusive) - for voltage control */ 6: int min_uV; 7: int max_uV; 8: 9: int uV_offset; 10: 11: /* current output range (inclusive) - for current control */ 12: int min_uA; 13: int max_uA; 14: 15: /* valid regulator operating modes for this machine */ 16: unsigned int valid_modes_mask; 17: 18: /* valid operations for regulator on this machine */ 19: unsigned int valid_ops_mask; 20: 21: /* regulator input voltage - only if supply is another regulator */ 22: int input_uV; 23: 24: /* regulator suspend states for global PMIC STANDBY/HIBERNATE */ 25: struct regulator_state state_disk; 26: struct regulator_state state_mem; 27: struct regulator_state state_standby; 28: suspend_state_t initial_state; /* suspend state to set at init */ 29: 30: /* mode to set on startup */ 31: unsigned int initial_mode; 32: 33: unsigned int ramp_delay; 34: unsigned int enable_time; 35: 36: /* constraint flags */ 37: unsigned always_on:1; /* regulator never off when system is on */ 38: unsigned boot_on:1; /* bootloader/firmware enabled regulator */ 39: unsigned apply_uV:1; /* apply uV constraint if min == max */ 40: unsigned ramp_disable:1; /* disable ramp delay */ 41: };
3.2 DTS的解析
regulator的DTS信息,可以通過兩種方法解析:
1)在regulator註冊前,調用of_get_regulator_init_data介面自行解析,該介面的實現如下:
1: struct regulator_init_data *of_get_regulator_init_data(struct device *dev, 2: struct device_node *node) 3: { 4: struct regulator_init_data *init_data; 5: 6: if (!node) 7: return NULL; 8: 9: init_data = devm_kzalloc(dev, sizeof(*init_data), GFP_KERNEL); 10: if (!init_data) 11: return NULL; /* Out of memory? */ 12: 13: of_get_regulation_constraints(node, &init_data); 14: return init_data; 15: } 16: EXPORT_SYMBOL_GPL(of_get_regulator_init_data);
該介面有兩個輸入參數:設備指針,以及包含了DTS信息的node指針(以3.1中的例子,即“tps51632@43”所在的node)。
它會分配一個struct regulator_init_data變數,並調用of_get_regulation_constraints解析DTS,把結果保存在該變數中。
最後返回struct regulator_init_data變數的地址。
2)在regulator註冊時,由regulator_register調用regulator_of_get_init_data幫忙解析,該介面的實現如下:
1: struct regulator_init_data *regulator_of_get_init_data(struct device *dev, 2: const struct regulator_desc *desc, 3: struct device_node **node) 4: { 5: struct device_node *search, *child; 6: struct regulator_init_data *init_data = NULL; 7: const char *name; 8: 9: if (!dev->of_node || !desc->of_match) 10: return NULL; 11: 12: if (desc->regulators_node) 13: search = of_get_child_by_name(dev->of_node, 14: desc->regulators_node); 15: else 16: search = dev->of_node; 17: 18: if (!search) { 19: dev_dbg(dev, "Failed to find regulator container node '%s'\n", 20: desc->regulators_node); 21: return NULL; 22: } 23: 24: for_each_child_of_node(search, child) { 25: name = of_get_property(child, "regulator-compatible", NULL); 26: if (!name) 27: name = child->name; 28: 29: if (strcmp(desc->of_match, name)) 30: continue; 31: 32: init_data = of_get_regulator_init_data(dev, child); 33: if (!init_data) { 34: dev_err(dev, 35: "failed to parse DT for regulator %s\n", 36: child->name); 37: break; 38: } 39: 40: of_node_get(child); 41: *node = child; 42: break; 43: } 44: of_node_put(search); 45: 46: return init_data; 47: }
與of_get_regulator_init_data不同的是,該介面以struct regulator_desc指針為參數,該參數提供了regulator DTS有關的搜索信息(desc->of_match),根據這些信息,可以獲得包含regulator信息的DTS node。
它本質上是一種通用的DTS匹配邏輯(和kernel解析platform device的標準資源類似),大致如下:
a)調用者提供parent node(struct device指針中,代表regulators的宿主設備,如上面的tps65090@48),以及該regulator在DTS中的名稱(由desc->of_match提供)。
b)還可以在struct regulator_desc中提供包含regulator DTS信息的node名稱(可選,用於regulator不直接在parent node下的情況)。
c)以parent device的node,或者指定的子node為基準,查找其下所有的node,如果node的名字或者“regulator-compatible”欄位和desc->of_match匹配,則調用of_get_regulator_init_data從中解析DTS信息。
總結:1、2兩種DTS解析的方法,各有優缺點:1直接,方便,容易理解,但會有冗餘代碼;2簡潔,但需要regulator driver開發者非常熟悉解析的原理,並以此設計DTS和struct regulator_desc變數。大家可以根據實際情況,靈活使用。
4. 主要數據結構
4.1 struct regulator_desc
1: /* include/linux/regulator/driver.h */ 2: 3: struct regulator_desc { 4: const char *name; 5: const char *supply_name; 6: const char *of_match; 7: const char *regulators_node; 8: int id; 9: bool continuous_voltage_range; 10: unsigned n_voltages; 11: const struct regulator_ops *ops; 12: int irq; 13: enum regulator_type type; 14: struct module *owner; 15: 16: unsigned int min_uV; 17: unsigned int uV_step; 18: unsigned int linear_min_sel; 19: int fixed_uV; 20: unsigned int ramp_delay; 21: 22: const struct regulator_linear_range *linear_ranges; 23: int n_linear_ranges; 24: 25: const unsigned int *volt_table; 26: 27: unsigned int vsel_reg; 28: unsigned int vsel_mask; 29: unsigned int apply_reg; 30: unsigned int apply_bit; 31: unsigned int enable_reg; 32: unsigned int enable_mask; 33: unsigned int enable_val; 34: unsigned int disable_val; 35: bool enable_is_inverted; 36: unsigned int bypass_reg; 37: unsigned int bypass_mask; 38: unsigned int bypass_val_on; 39: unsigned int bypass_val_off; 40: 41: unsigned int enable_time; 42: 43: unsigned int off_on_delay; 44: };
4.2 struct regulator_config
struct regulator_config保存了regulator的動態信息,所謂的動態信息,是指那些會在driver運行過程中改變、或者driver運行後才會確定的信息,如下:
1: struct regulator_config { 2: struct device *dev; 3: const struct regulator_init_data *init_data; 4: void *driver_data; 5: struct device_node *of_node; 6: struct regmap *regmap; 7: 8: int ena_gpio; 9: unsigned int ena_gpio_invert:1; 10: unsigned int ena_gpio_flags; 11: };
dev,對應的struct device指針。會在regulator_register時,由regulator core分配,保存在此,以便後續使用;
init_data,init data指針,在解析DTS後,保存在此,以便後續使用;
of_node,可以為空;
regmap,參考後續描述;
ena_gpio、ena_gpio_invert、ena_gpio_flags,控制regulator使能的GPIO及其active極性。
4.3 struct regulator_dev
struct regulator_dev是regulator設備的抽象,當driver以struct regulator_desc、struct regulator_config兩個類型的參數,調用regulator_register將regulator註冊到kernel之後,regulator就會分配一個struct regulator_dev變數,後續所有的regulator操作,都將以該變數為對象。
1: struct regulator_dev { 2: const struct regulator_desc *desc; 3: int exclusive; 4: u32 use_count; 5: u32 open_count; 6: u32 bypass_count; 7: 8: /* lists we belong to */ 9: struct list_head list; /* list of all regulators */ 10: 11: /* lists we own */ 12: struct list_head consumer_list; /* consumers we supply */ 13: 14: struct blocking_notifier_head notifier; 15: struct mutex mutex; /* consumer lock */ 16: struct module *owner; 17: struct device dev; 18: struct regulation_constraints *constraints; 19: struct regulator *supply; /* for tree */ 20: struct regmap *regmap; 21: 22: struct delayed_work disable_work; 23: int deferred_disables; 24: 25: void *reg_data; /* regulator_dev data */ 26: 27: struct dentry *debugfs; 28: 29: struct regulator_enable_gpio *ena_pin; 30: unsigned int ena_gpio_state:1; 31: 32: /* time when this regulator was disabled last time */ 33: unsigned long last_off_jiffy; 34: };
desc,保存了regulator靜態描述信息的指針(從這個角度看,所謂的靜態描述,其變數必須為全局變數);
exclusive、use_count、open_count、bypass_count,一些狀態記錄;
constraints,保存了regulator的constraints指針;
supply,該regulator的supply;
等等。
5 實現邏輯分析
本章簡單的分析一下regulator driver相關的實現邏輯。如果要理解有些邏輯,必須具備一些regulator的基礎知識,因此在需要的時候,會穿插介紹這些知識。
5.1 regulator core的初始化
regulator core的初始化操作由regulator_init介面負責,主要工作包括:
1)註冊regulator class(/sys/class/regulator/)。
2)註冊用於調試的debugfs。
和power switch class、input class等類似,regulator framework也是一種class,可以稱作regulator class。
5.2 regulator register
regulator的註冊,由regulator_register/devm_regulator_register介面負責,如下:
1: /** 2: * regulator_register - register regulator 3: * @regulator_desc: regulator to register 4: * @config: runtime configuration for regulator 5: * 6: * Called by regulator drivers to register a regulator. 7: * Returns a valid pointer to struct regulator_dev on success 8: * or an ERR_PTR() on error. 9: */ 10: struct regulator_dev * 11: regulator_register(const struct regulator_desc *regulator_desc, 12: const struct regulator_config *config) 13: { 14: const struct regulation_constraints *constraints = NULL; 15: const struct regulator_init_data *init_data; 16: static atomic_t regulator_no = ATOMIC_INIT(0); 17: struct regulator_dev *rdev; 18: struct device *dev; 19: int ret, i; 20: const char *supply = NULL; 21: 22: if (regulator_desc == NULL || config == NULL) 23: return ERR_PTR(-EINVAL); 24: 25: dev = config->dev; 26: WARN_ON(!dev); 27: 28: if (regulator_desc->name == NULL || regulator_desc->ops == NULL) 29: return ERR_PTR(-EINVAL); 30: 31: if (regulator_desc->type != REGULATOR_VOLTAGE && 32: regulator_desc->type != REGULATOR_CURRENT) 33: return ERR_PTR(-EINVAL); 34: 35: /* Only one of each should be implemented */ 36: WARN_ON(regulator_desc->ops->get_voltage && 37: regulator_desc->ops->get_voltage_sel); 38: WARN_ON(regulator_desc->ops->set_voltage && 39: regulator_desc->ops->set_voltage_sel); 40: 41: /* If we're using selectors we must implement list_voltage. */ 42: if (regulator_desc->ops->get_voltage_sel && 43: !regulator_desc->ops->list_voltage) { 44: return ERR_PTR(-EINVAL); 45: } 46: if (regulator_desc->ops->set_voltage_sel && 47: !regulator_desc->ops->list_voltage) { 48: return ERR_PTR(-EINVAL); 49: } 50: 51: rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL); 52: if (rdev == NULL) 53: return ERR_PTR(-ENOMEM); 54: 55: init_data = regulator_of_get_init_data(dev, regulator_desc, 56: &rdev->dev.of_node); 57: if (!init_data) { 58: init_data = config->init_data; 59: rdev->dev.of_node = of_node_get(config->of_node); 60: } 61: 62: mutex_lock(®ulator_list_mutex); 63: 64: mutex_init(&rdev->mutex); 65: rdev->reg_data = config->driver_data; 66: rdev->owner = regulator_desc->owner; 67: rdev->desc = regulator_desc; 68: if (config->regmap) 69: rdev->regmap = config->regmap; 70: else if (dev_get_regmap(dev, NULL)) 71: rdev->regmap = dev_get_regmap(dev, NULL); 72: else if (dev->parent) 73: rdev->regmap = dev_get_regmap(dev->parent, NULL); 74: INIT_LIST_HEAD(&rdev->consumer_list); 75: INIT_LIST_HEAD(&rdev->list); 76: BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier); 77: INIT_DELAYED_WORK(&rdev->disable_work, regulator_disable_work); 78: 79: