三、linux电源框架
参考自linux-2.6.32.61\Documentation\power\regulator
一、简介
电源框架能够动态调节电源输出,以达到省电效果。
二、基本术语
-
Regulator
供其他设备电源的电子设备,一些电源具有开关及控制输出的电压电流。
-
PMIC(Power Management IC)
电源管理芯片,内涵多个电源甚至其他子系统。
-
Consumer
由regulator供电的设备统称为consumer,其可分为静态和动态两类。
静态:不需要改变电压电流,只需要开关电源,通常在bootloader、firmware、kernel board阶段被设置。
动态:根据操作需求改变电压电流。
-
Power Domain
由电源或者其他电源域的输出作为输入的电路。
电源在开关之后,如下图所示:
Regulator -+-> Switch-1 -+->
Switch-2 --> [Consumer A]
|
|
| +->
[Consumer B], [Consumer C]
|
+-> [Consumer D], [Consumer E]
其为一个电源和三个电源域:
Domain 1: Switch-1, Consumers D &
E.
Domain 2: Switch-2, Consumers B
& C.
Domain 3: Consumer
A.
其三者有输出关系(1的输出作为2的输入,2的输出作为3的输入):
Domain-1 --> Domain-2 --> Domain-3.
一个电源域的电源还可以由其他电源提供,如:
Regulator-1 -+-> Regulator-2 -+->
[Consumer A]
|
+-> [Consumer B]
这里有两个电源域:
Domain 1: Regulator-2, Consumer
B.
Domain 2: Consumer
A.
其输出关系:
Domain-1 --> Domain-2
-
Constraints
约束,用于定义电源特性和保护硬件,可划分为以下三方面:
Regulator Level:
定义了电源硬件的参数规格,如:
- voltage output is in the range 800mV ->
3500mV.
- regulator current output
limit is 20mA @ 5V but is 10mA @ 10V.
Power Domain Level:
由kernel board初始化代码定义,其约束电源域的电源范围,如:
- Domain-1 voltage is 3300mV
- Domain-2 voltage is 1400mV ->
1600mV
- Domain-3 current limit is 0mA
-> 20mA.
Consumer Level:
由驱动设置,动态调整电流电压。
约束示例:
e.g. a consumer backlight driver asks for a
current increase from 5mA to 10mA to increase LCD illumination. This passes to
through the levels as follows :-
Consumer: need to increase LCD brightness. Lookup and
request next current mA value in brightness table (the consumer driver could be
used on several different personalities based upon the same reference
device).
Power Domain: is the new
current limit within the domain operating limits for this domain and system
state (e.g.battery power, USB power)
Regulator Domains: is the new current limit within the
regulator operating parameters for input/output voltage.
If
the regulator request passes all the constraint tests then the new regulator
value is applied.
三、Regulator Consumer Driver Interface
-
Consumer Regulator Access (static & dynamic drivers)
regulator = regulator_get(dev, "Vcc");
通过此接口获取该驱动对应的regulator。dev为驱动对应的设备指针,“Vcc"为电源ID。内核会查表找到电源ID对应的regulator。
regulator_put(regulator);
通过此接口释放regulator。
regulator_get和regulator_put通常在driver的probe和remove中调用。
-
Regulator Output Enable & Disable (static & dynamic drivers)
int regulator_enable(regulator);
通过此接口使能电源输出。
注:在调此函数前,电源输出可能已经被使能了。
NOTE: The supply may already be enabled before
regulator_enabled() is called.
This may
happen if the consumer shares the regulator or the regulator has
been
previously enabled by bootloader
or kernel board initialization code.
int regulator_is_enabled(regulator);
通过此接口判断电源输出是否已被使能。返回值大于0时已使能。
int regulator_disable(regulator);
通过此接口关闭电源输出。
注:在调此函数后,电源未必立刻关闭,存在共享电源场景。
NOTE: This may not disable the supply if it‘s
shared with other consumers. The
regulator will only be disabled when the enabled
reference count is zero.
int regulator_force_disable(regulator);
通过此接口立刻关闭电源。
-
Regulator Voltage Control & Status (dynamic drivers)
int regulator_set_voltage(regulator, min_uV, max_uV);
通过此接口能调节电压的最小和最大输出。
注:调用时机
NOTE: this can be called when the regulator is
enabled or disabled. If called
when
enabled, then the voltage changes instantly, otherwise the
voltage
configuration changes and the
voltage is physically set when the regulator is
next
enabled.
int regulator_get_voltage(regulator);
通过此接口获取配置的输出电压。
NOTE: get_voltage() will return the configured
output voltage whether the
regulator is
enabled or disabled and should NOT be used to determine
regulator
output state. However this
can be used in conjunction with is_enabled() to
determine
the regulator physical output voltage.
四、Regulator Machine Driver Interface
之前提到的电源域具有拓扑结构,当子节点的电源被打开时,对应的一系列父节点也会打开,在如下regulator machine中会提及:
1 Regulator Machine Driver Interface 2 =================================== 3 4 The regulator machine driver interface is intended for board/machine specific 5 initialisation code to configure the regulator subsystem. 6 7 Consider the following machine :- 8 9 Regulator-1 -+-> Regulator-2 --> [Consumer A @ 1.8 - 2.0V] 10 | 11 +-> [Consumer B @ 3.3V] 12 13 The drivers for consumers A & B must be mapped to the correct regulator in 14 order to control their power supply. This mapping can be achieved in machine 15 initialisation code by creating a struct regulator_consumer_supply for 16 each regulator. 17 18 struct regulator_consumer_supply { 19 struct device *dev; /* consumer */ 20 const char *supply; /* consumer supply - e.g. "vcc" */ 21 }; 22 23 e.g. for the machine above 24 25 static struct regulator_consumer_supply regulator1_consumers[] = { 26 { 27 .dev = &platform_consumerB_device.dev, 28 .supply = "Vcc", 29 },}; 30 31 static struct regulator_consumer_supply regulator2_consumers[] = { 32 { 33 .dev = &platform_consumerA_device.dev, 34 .supply = "Vcc", 35 },}; 36 37 This maps Regulator-1 to the ‘Vcc‘ supply for Consumer B and maps Regulator-2 38 to the ‘Vcc‘ supply for Consumer A. 39 40 Constraints can now be registered by defining a struct regulator_init_data 41 for each regulator power domain. This structure also maps the consumers 42 to their supply regulator :- 43 44 static struct regulator_init_data regulator1_data = { 45 .constraints = { 46 .min_uV = 3300000, 47 .max_uV = 3300000, 48 .valid_modes_mask = REGULATOR_MODE_NORMAL, 49 }, 50 .num_consumer_supplies = ARRAY_SIZE(regulator1_consumers), 51 .consumer_supplies = regulator1_consumers, 52 }; 53 54 Regulator-1 supplies power to Regulator-2. This relationship must be registered 55 with the core so that Regulator-1 is also enabled when Consumer A enables it‘s 56 supply (Regulator-2). The supply regulator is set by the supply_regulator_dev 57 field below:- 58 59 static struct regulator_init_data regulator2_data = { 60 .supply_regulator_dev = &platform_regulator1_device.dev, 61 .constraints = { 62 .min_uV = 1800000, 63 .max_uV = 2000000, 64 .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, 65 .valid_modes_mask = REGULATOR_MODE_NORMAL, 66 }, 67 .num_consumer_supplies = ARRAY_SIZE(regulator2_consumers), 68 .consumer_supplies = regulator2_consumers, 69 }; 70 71 Finally the regulator devices must be registered in the usual manner. 72 73 static struct platform_device regulator_devices[] = { 74 { 75 .name = "regulator", 76 .id = DCDC_1, 77 .dev = { 78 .platform_data = ®ulator1_data, 79 }, 80 }, 81 { 82 .name = "regulator", 83 .id = DCDC_2, 84 .dev = { 85 .platform_data = ®ulator2_data, 86 }, 87 }, 88 }; 89 /* register regulator 1 device */ 90 platform_device_register(®ulator_devices[0]); 91 92 /* register regulator 2 device */ 93 platform_device_register(®ulator_devices[1]);