zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    MySql数据库时区异常,java.sql.SQLException: The server time zone value '?й???׼ʱ?' is unrecognized or represents more than one time zone.
    SpringBoot中自定义properties文件配置参数并带有输入提示
    Springboot2.x 集成jsp
    Spring Boot使用AOP实现REST接口简易灵活的安全认证
    Spring Boot使用过滤器和拦截器分别实现REST接口简易安全认证
    Spring Boot使用RestTemplate消费REST服务的几个问题记录
    Spring Boot开发MongoDB应用实践
    Spring Boot定时任务应用实践
    Spring Boot缓存应用实践
    Spring Boot消息队列应用实践
  • 原文地址:https://www.cnblogs.com/wanglouxiaozi/p/15091263.html
Copyright © 2011-2022 走看看