消费者驱动器接口
这段文字描述了用于消费者设备驱动程序的调节器接口。请参阅Linux电压和电流调节器框架,以了解本文中使用的术语。
1. 消费者调节器访问(静态和动态驱动程序)
消费者驱动程序可以通过调用以下方法来获取其供电调节器:
regulator = regulator_get(dev, "Vcc");
消费者将其设备结构指针和电源供应ID传递进去。然后核心通过查询特定于机器的查找表来找到正确的调节器。如果查找成功,这个调用将返回一个指向为该消费者提供电源的调节器结构的指针。
要释放调节器,消费者驱动程序应该调用:
regulator_put(regulator);
一个消费者可以由多个调节器供应,例如带有模拟和数字供应的编解码器消费者:
digital = regulator_get(dev, "Vcc"); /* 数字核心 */ analog = regulator_get(dev, "Avdd"); /* 模拟 */
调节器访问函数regulator_get()
和regulator_put()
通常会在设备驱动程序的probe()
和remove()
中被调用。
2. 调节器输出使能和禁用(静态和动态驱动程序)
消费者可以通过调用以下方法来启用其电源供应:
int regulator_enable(regulator);
注意:
- 在调用
regulator_enable()
之前,电源可能已经被启用。如果消费者共享调节器或者调节器已经被引导加载程序或内核板初始化代码先前启用,就可能发生这种情况。
消费者可以通过调用以下方法来确定调节器是否已启用:
int regulator_is_enabled(regulator);
当调节器已启用时,这将返回大于零的值。
当不再需要电源时,消费者可以通过调用以下方法来禁用其供应:
int regulator_disable(regulator);
注意:
- 如果电源与其他消费者共享,这可能不会禁用电源。只有在启用的引用计数为零时,调节器才会被禁用。
最后,可以在紧急情况下强制关闭调节器:
int regulator_force_disable(regulator);
注意:
- 这将立即强制关闭调节器输出。所有消费者将被断电。
3. 调节器电压控制和状态(动态驱动程序)
一些消费者驱动程序需要能够动态改变其供电电压以匹配系统工作点。例如,CPU频率驱动程序可以随着频率调整电压以节省电力,SD驱动程序可能需要选择正确的卡片电压等。
消费者可以通过调用以下方法来控制其供电电压:
int regulator_set_voltage(regulator, min_uV, max_uV);
其中min_uV
和max_uV
分别是微伏的最小和最大可接受电压。
注意:这可以在调节器启用或禁用时调用。如果在启用时调用,则电压会立即改变;否则,电压配置会改变,并且在下次启用调节器时电压会被物理设置。
可以通过调用以下方法来查找配置的调节器电压输出:
int regulator_get_voltage(regulator);
注意:
get_voltage()
将返回配置的输出电压,无论调节器是否已启用,不应用于确定调节器输出状态。但是,这可以与is_enabled()
一起使用,以确定调节器的物理输出电压。
4. 调节器电流限制控制和状态(动态驱动程序)
一些消费者驱动程序需要能够动态改变其供电电流限制以匹配系统工作点。例如,LCD背光驱动程序可以改变电流限制以调整背光亮度,USB驱动程序可能希望在供电时将限制设置为500mA。
消费者可以通过调用以下方法来控制其供电电流限制:
int regulator_set_current_limit(regulator, min_uA, max_uA);
其中min_uA
和max_uA
分别是微安的最小和最大可接受电流限制。
注意:
- 这可以在调节器启用或禁用时调用。如果在启用时调用,则电流限制会立即改变;否则,电流限制配置会改变,并且在下次启用调节器时电流限制会被物理设置。
可以通过调用以下方法来查找调节器的电流限制:
int regulator_get_current_limit(regulator);
注意:
get_current_limit()
将返回电流限制,无论调节器是否已启用或禁用,不应用于确定调节器电流负载。
5. 调节器工作模式控制和状态(动态驱动程序)
一些消费者可以通过改变其供电调节器的工作模式来进一步节省系统电力,以使其在消费者操作状态改变时更加高效。例如,消费者驱动程序处于空闲状态并且随后消耗的电流减少。
调节器工作模式可以通过间接或直接方式进行控制。
- 间接工作模式控制。
消费者驱动程序可以通过调用以下方法来请求改变其供电调节器的工作模式:
int regulator_set_load(struct regulator *regulator, int load_uA);
这将导致核心重新计算调节器上的总负载(基于所有其消费者),并根据需要和允许的情况改变工作模式,以最好地匹配当前的工作负载。
load_uA
的值可以从消费者的数据表中确定。例如,大多数数据表都会显示在某些情况下消耗的最大电流。
大多数消费者将使用间接工作模式控制,因为它们对调节器或调节器是否与其他消费者共享没有了解。
- 直接工作模式控制。
定制或紧密耦合的驱动程序可能希望根据其工作点直接控制调节器的工作模式。这可以通过调用以下方法来实现:
int regulator_set_mode(struct regulator *regulator, unsigned int mode); unsigned int regulator_get_mode(struct regulator *regulator);
直接模式只会被了解调节器并且不与其他消费者共享调节器的消费者使用。
6. 调节器事件
调节器可以通知消费者外部事件。事件可能在调节器受压力或故障条件下被消费者接收。
消费者可以通过调用以下方法来注册对调节器事件的兴趣:
int regulator_register_notifier(struct regulator *regulator, struct notifier_block *nb);
消费者可以通过调用以下方法来取消注册兴趣:
int regulator_unregister_notifier(struct regulator *regulator, struct notifier_block *nb);
调节器使用内核通知器框架向其感兴趣的消费者发送事件。
7. 调节器直接寄存器访问
某些类型的电源管理硬件或固件被设计为需要对调节器进行低级硬件访问,而不需要内核的参与。这类设备的例子包括:
- 具有电压控制振荡器和控制逻辑以通过I2C改变供电电压以实现期望的输出时钟速率的时钟源
- 在过温条件下执行系统关机的热管理固件
为了设置这样的设备/固件,需要配置各种参数,如调节器的I2C地址、各种调节器寄存器的地址等。调节器框架提供了以下辅助函数来查询这些详细信息。
总线特定的细节,如I2C地址或传输速率,由regmap框架处理。要获取调节器的regmap(如果支持),请使用:
struct regmap *regulator_get_regmap(struct regulator *regulator);
要获取调节器的电压选择器寄存器的硬件寄存器偏移和位掩码,使用:
int regulator_get_hardware_vsel_register(struct regulator *regulator, unsigned *vsel_reg, unsigned *vsel_mask);
要将调节器框架的电压选择器代码(由regulator_list_voltage使用)转换为可以直接写入电压选择器寄存器的硬件特定电压选择器,使用:
int regulator_list_hardware_vsel(struct regulator *regulator, unsigned selector);