Regulator 框架(二):Regulators 消费者接口

消费者接口只要求驱动程序包含一个头文件:

#include <linux/regulator/consumer.h>

消费者可以是静态的,也可以是动态的。静态调节器只需要一个固定的电源,而动态调节器需要在运行时对调节器进行主动管理。从消费者的角度来看,调节器设备在内核中被表示为一个struct regulator 结构的实例,在drivers/regulator/internal.h中定义,如下所示:

/*
* struct regulator
*
* One for each consumer device.
*/
struct regulator {
  struct device *dev;
  struct list_head list;
  unsigned int always_on:1;
  unsigned int bypass:1;
  int uA_load;
  int min_uV;
  int max_uV;
  char *supply_name;
  struct device_attribute dev_attr;
  struct regulator_dev *rdev;
  struct dentry *debugfs;
};

这个结构足够有意义,不需要我们添加任何注释。为了了解消费一个调节器是多么容易,这里有一个消费者如何获得一个调节器的小例子:

[...]
int ret;
struct regulator *reg;
const char *supply = "vdd1";
int min_uV, max_uV;
reg = regulator_get(dev, supply);
[...]

regulator设备请求

在获得对调节器的访问权之前,使用者必须通过 regulator_get() 函数请求内核。也可以使用托管版本的 devm_regulator_get() 函数:

struct regulator *regulator_get(struct device *dev, const char *id)

使用该函数的示例如下:

reg = regulator_get(dev, "Vcc");

消费者在其结构体中传递设备指针和电源ID。核心将通过咨询DT或特定于机器的查找表来寻找正确的调节器。如果我们只关注设备树,*id应该匹配设备树中调节器提供的<name>模式。如果查找成功,则此调用将返回一个指向提供此消费者的struct regulator 的指针。

为了释放 regulator,消费者驱动者应该调用:

void regulator_put(struct regulator *regulator)

在调用这个函数之前,驱动程序应该确保对这个调节器源的所有regulator_enable()调用都被regulator_disable()调用平衡。

一个消费者可以由多个 regulator 提供。例如,使用模拟和数字设备的编解码器消费者:

digital = regulator_get(dev, "Vcc"); /* digital core */
analog = regulator_get(dev, "Avdd"); /* analog */

消费者 probe() 和 remove() 函数是获取和释放调节器的合适位置。

控制 regulator 设备

调节器控制包括调节器的启用、禁用和设置输出值。

启用和禁用 regulator 输出

消费者可以通过调用以下命令来启用它的电源:

int regulator_enable(regulator);

如果函数执行成功,将返回0。反向操作包括禁用电源,调用如下:

int regulator_disable(regulator);

要检查调节器是否已经启用,消费者应该调用这个:

int regulator_is_enabled(regulator);

如果启用了调节器,该函数将返回一个大于0的值。由于调节器可能由引导加载程序提前启用或与另一个使用者共享,您可以使用regulator_is_enabled()函数来检查调节器状态。

printk (KERN_INFO "Regulator Enabled = %d
", regulator_is_enabled(reg));

对于共享调节器,regulator_disable()实际上只在启用的引用计数为零时禁用调节器。也就是说,你可以在紧急情况下强制禁用。例如,通过调用regulator_force_disable():

int regulator_force_disable(regulator);

在接下来内容讨论的每个函数实际上都是对 regulator_ops 操作的包装。例如,regulator_set_voltage() 在内部调用 regulator_ops.set_voltage 在检查了相应的掩码后允许设置此操作。

电压控制与状态

于需要根据操作模式调整电源的用户,内核提供了如下功能:

int regulator_set_voltage(regulator, min_uV, max_uV);

min_uV和max_uV是以微伏为单位的最小和最大可接受电压。

如果在稳压器被禁用时调用该功能,则该功能将改变电压配置,以便在稳压器下次启用时物理设置电压。也就是说,消费者可以通过调用regulator_get_voltage()获得调节器配置的电压输出,无论调节器是否启用,它都会返回配置的输出电压:

int regulator_get_voltage(regulator);
printk (KERN_INFO "Regulator Voltage = %d
", regulator_get_voltage(reg));

电流控制及状态

我们在电压部分所讨论的问题在这里也适用。例如,USB驱动程序可能希望在供电时将限制设置为500 mA。

消费者可以通过调用以下函数来控制他们的供电电流限制:

int regulator_set_current_limit(regulator, min_uA, max_uA);

min_uA 和 max_uA 是以微安为单位的最小和最大可接受电流限制。

同样,消费者可以通过调用 regulator_get_current_limit() 得到调节器配置的电流限制,无论调节器是否启用,调节器都会返回电流限制的值:

int regulator_get_current_limit(regulator);

操作模式控制和状态

为了高效的电源管理,一些用户可能会在其(用户)运行状态发生变化时改变其电源的运行模式。消费者驱动可通过以下方式请求改变供应调节器的工作模式:

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

只有当消费者知道调节器并且不与其他消费者共享调节器时,才应该在调节器上使用regulator_set_mode()。这被称为直接模式。现在,regulator_set_uptimum_mode() 导致核心进行一些后台工作,以确定对请求的当前操作模式是最好的。这被称为间接模式。

Regulator binding

这里只讨论消费者接口绑定。消费者节点可以使用以下绑定引用一个或多个供应/调节器:

<name>-supply: phandle to the regulator node

它与PWM消费者绑定的原理相同。现在,<name>应该足够有意义了,以便驱动程序可以在请求调节器时轻松地引用它。也就是说,<name>必须匹配 regulator_get() 函数的*id参数:

twl_reg1: regulator@0 {
  [...]
};
twl_reg2: regulator@
1 {   [...] };
mmc: mmc@
0x0 {   [...]   vmmc-supply = <&twl_reg1>;   vmmcaux-supply = <&twl_reg2>; };

实际请求它的供应的消费者代码(即MMC驱动程序)可能是这样的:

 1 struct regulator *main_regulator;
 2 struct regulator *aux_regulator;
 3 int ret;
 4 main_regulator = devm_regulator_get(dev, "vmmc");
 5 
 6 /*
 7 * It is a good practice to apply the config before
 8 * enabling the regulator
 9 */
10 if (!IS_ERR(io_regulator)) {
11   regulator_set_voltage(main_regulator,
12                MMC_VOLTAGE_DIGITAL,
13                MMC_VOLTAGE_DIGITAL);
14   ret = regulator_enable(io_regulator);
15 }
16 [...]
17 aux_regulator = devm_regulator_get(dev, "vmmcaux");
18 [...]

 

本文来自博客园,作者:王楼小子,转载请注明原文链接:https://www.cnblogs.com/wanglouxiaozi/p/15091263.html

原文地址:https://www.cnblogs.com/wanglouxiaozi/p/15091263.html