我是靠谱客的博主 无心烤鸡,最近开发中收集的这篇文章主要介绍regulator框架,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

============================= PMIC =================================

疑问:
1)power down 掉电
这个是指通过 pmic 芯片断电进行掉电吗?

2)

1)regulator_desc 描述符
内核通过一个 struct regulator_desc 结构来描述PMIC提供的每个调节器,该结构描述了调节器的特
征。所谓调节器,我指的是任何独立的调节输出。例如,Intersil 的ISL6271A是一个具有三个独立调
节输出的PMIC。然后在其驱动程序中应该有三个 regulator_desc 实例。

struct regulator_desc {
const char *name;
const char *of_match;

int id;

//
unsigned n_voltages;
const struct regulator_ops *ops;
int irq;
enum regulator_type type;
struct module *owner;

unsigned int min_uV;
unsigned int uV_step;

};

name:
调节器的名称。
of_match:
保存了用于识别DT中的调节器的名称。
id:
调节器的数字标识符。
owner:
代表提供调节器的模块。将该字段设置为 THIS_MODULE。
type:
指示调节器是电压调节器还是电流调节器。它可以是 REGULATOR_VOLTAGE 或 REGULATOR_CURRENT。
任何其他值将导致调节器注册失败。
n_voltage:
表示该调节器可用的选择器数量。它表示调节器能输出的值的数量。输出电压固定时,n_voltage 应设为1。
min_uV:
表示该稳压器能提供的最小电压值。它是由最低的选择器给出的电压。
uV_step:
表示每个选择器增加的电压。
ops:
ops表示调节器操作表。它是一个指向调节器可以支持的一组操作回调的结构。
irq:
调节器的中断号。

3)初始化数据的结构

有两种方法可以将 regulator_init_data 传递给驱动程序,可以通过板级初始化文件中的平台数据或通过 
of_get_regulator_init_data 函数的设备树中的节点来实现:

struct regulator_init_data {

/* 调节器的约束 */
struct regulation_constraints constraints;

/* 可选的回调函数,在核心注册调节器时被调用 */
int (*regulator_init)(void *driver_data);

/* 传递给 regulator_init 函数的数据 */
void *driver_data; 

};

3.1)将初始化数据填充到板级文件中
static struct regulator_init_data isl_init_data[] = {
  [0] = {
    .constraints = {
      .name = “Core Buck”,
      .min_uV = 850000,
      .max_uV = 1600000,
      .valid_modes_mask = REGULATOR_MODE_NORMAL
                | REGULATOR_MODE_STANDBY,
      .valid_ops_mask = REGULATOR_CHANGE_MODE
                | REGULATOR_CHANGE_STATUS,
    },
  },
  [1] = {
    .constraints = {
      .name = “LDO1”,
      .min_uV = 1100000,
      .max_uV = 1100000,
      .always_on = true,
      .valid_modes_mask = REGULATOR_MODE_NORMAL
                | REGULATOR_MODE_STANDBY,
      .valid_ops_mask = REGULATOR_CHANGE_MODE
                | REGULATOR_CHANGE_STATUS,
    },
  },
  [2] = {
    .constraints = {
      .name = “LDO2”,
      .min_uV = 1300000,
      .max_uV = 1300000,
       .always_on = true,
      .valid_modes_mask = REGULATOR_MODE_NORMAL
                | REGULATOR_MODE_STANDBY,
      .valid_ops_mask = REGULATOR_CHANGE_MODE
                | REGULATOR_CHANGE_STATUS,
    },
  },
};

3.2)DT提供初始化数据

提取出:static struct regulator_init_data 数据
为了提取从DT内部传递的init数据,我们需要引入一个新的数据类型,struct of_regulator_match

struct of_regulator_match {
	const char *name;
	void *driver_data;
	struct regulator_init_data *init_data;
	struct device_node *of_node;
	const struct regulator_desc *desc;
};


DT中的每个PMIC节点都应该有一个名为 regulators 的子节点,在这个子节点中,我们必须声明PMIC提供的每个
调节器为专用子节点。

regulator-name: 这是一个字符串,用作调节器输出的描述性名称
regulator-min-microvolt: 这是用户可以设定的最小电压
regulator-max-microvolt: 这是用户可设定的最大电压

regulator-microvolt-offset: 施加在电压上以补偿电压下降的偏移量

regulator-min-microamp: 这是用户可以设定的最小电流
regulator-max-microamp: 这是用户可以设定的最大电流
regulator-always-on: 这是一个布尔值,表示不应该禁用调节器。
regulator-boot-on: 这是一个bootloader/firmware 阶段使能的调节器。
<name>-supply: 这是一个指向父供应/调节节点的phandle。
regulator-ramp-delay: 这是调节器的斜坡延迟(用uV/uS表示)

isl6271a@3c {
  compatible = “isl6271a”;
  reg = <0x3c>;
  interrupts = <0 86 0x4>;

/* supposing our regulator is powered by another regulator */
  in-v1-supply = <&some_reg>;
  […]

regulators {
    reg1: core_buck {
      regulator-name = “Core Buck”;
      regulator-min-microvolt = <850000>;
      regulator-max-microvolt = <1600000>;
    };

reg2: ldo1 {
      regulator-name = “LDO1”;
      regulator-min-microvolt = <1100000>;
      regulator-max-microvolt = <1100000>;
      regulator-always-on;
    };

reg3: ldo2 {
      regulator-name = “LDO2”;
      regulator-min-microvolt = <1300000>;
      regulator-max-microvolt = <1300000>;
      regulator-always-on;
    };
  };
};

Regulator与模块之间是树状关系。父regulator可以给设备供电,也可以给子regulator供电

父Regulator

--> 子Regulator  --> [supply]

--> 设备[Consumer]

PMIC驱动程序的probe函数可以分为几个步骤,具体如下:

1)为PMIC提供的所有调节器定义一个struct regulator_desc对象数组。在这一步中,您应该定义一个有效的
struct regulator_ops,以链接到适当的regulator_desc。所有的regulator_ops都可以是相同的,假设它
们都支持相同的操作。

现在,在probe函数中,对于每个调节器,做以下操作:
1)从平台数据中获取适当的 struct regulator_init_data 结构体(其中必须已经包含有效的
struct regulator_constraints 结构体),或者从DT中构建一个 struct regulator_constraints 结构体,
以便构建一个新的 struct regulator_init_data 对象。

2)使用前面的 struct regulator_init_data 来设置 struct regulator_config 结构体。如果驱动程序支持 DT,你可以让 regulator_config.of_node 指向用于提取调节器属性的节点。
调用 regulator_register()(或托管版本,devm_regulator_register())将调节器注册到核心,并给出之前的 regulator_desc 和 regulator_config 作为参数。
调节器使用 regulator_register() 函数或 devm_regulator_register() 向内核注册:

2)约束结构

当PMIC向消费者公开一个调节器时,它必须借助结构体regulation_constraints结构对这个调节器施加一些名义上的
限制。它是一种结构,收集调节器的安全限制,并定义消费者不能跨越的边界。

struct regulation_constraints 结构是 init data 的一部分。这可以用以下事实来解释: 在调节器初始化时,它的
约束直接应用于它,远远早于任何消费者可以使用它。

struct regulation_constraints {
  const char *name;

/* 电压输出范围(包括)-用于电压控制 */
  int min_uV;
  int max_uV;

/* 电压从消费者补偿电压下降的偏移量 */

int uV_offset;

/* 电流输出范围(包括)-用于电流控制 */
  int min_uA;
  int max_uA;

/* 模式和操作的掩码,可以由消费者配置/执行 */
  unsigned int valid_modes_mask;

/* 调节器在本机上的有效操作 */
  unsigned int valid_ops_mask;

/*定义了当系统在磁盘模式、mem模式或备用模式下挂起时调节器的状态*/

struct regulator_state state_disk;
  struct regulator_state state_mem;
  struct regulator_state state_standby;

/* 在init时设置挂起状态 */

suspend_state_t initial_state;

/* 启动时设置的模式 */
  unsigned int initial_mode;

/* 约束的标志 /
  unsigned always_on:1; /
当系统开启时,调节器永不关闭 /
  unsigned boot_on:1; /
bootloader/firmware 使能调节器 /
  unsigned apply_uV:1; /
当min == max时,应用uV约束 */
};

#define DUMMY_VOLTAGE_MIN 850000
#define DUMMY_VOLTAGE_MAX 1600000
#define DUMMY_VOLTAGE_STEP 50000

struct regulator_init_data {

/* 调节器的约束 */
struct regulation_constraints constraints;

/* 可选的回调函数,在核心注册调节器时被调用 */
int (*regulator_init)(void *driver_data);

/* 传递给 regulator_init 函数的数据 */
void *driver_data; 

};

static struct regulator_init_data dummy_initdata[] = {
[0] = {

	//struct regulation_constraints constraints 限制调节器
    .constraints = {
	
		//当系统开启时,调节器永不关闭
       .always_on = 0,
       .min_uV = DUMMY_VOLTAGE_MIN,
       .max_uV = DUMMY_VOLTAGE_MAX,
    },
},
[1] = {
		.constraints = {
        .always_on = 1,
    },
},

};

//每个输出都有一个ops
static struct regulator_ops dummy_fixed_ops = {
.list_voltage = regulator_list_voltage_linear,
};

static struct regulator_ops dummy_core_ops = {
.get_voltage_sel = isl6271a_get_voltage_sel,
.set_voltage_sel = isl6271a_set_voltage_sel,
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
};

//PMIC 新的输出电压调节都会有一个 regulator_desc 描述符
static const struct regulator_desc dummy_desc[] = {

{
    .name = "Dummy Core",
    .id = 0,
	
	//调节器输出数量 (max_uv - min_uv)/uV_step +1
    .n_voltages = 16,
    .ops = &dummy_core_ops,
	
	//电压/电流
    .type = REGULATOR_VOLTAGE,
    .owner = THIS_MODULE,
    .min_uV = DUMMY_VOLTAGE_MIN,
	
	//步进值
    .uV_step = DUMMY_VOLTAGE_STEP,
}, {
    .name = "Dummy Fixed",
    .id = 1,
	
	//1表示输出固定
    .n_voltages = 1,
    .ops = &dummy_fixed_ops,
    .type = REGULATOR_VOLTAGE,
    .owner = THIS_MODULE,
    .min_uV = 1300000,
},

};

static int my_pdrv_probe (struct platform_device *pdev)

struct regulator_config config = { };
config.dev = &pdev->dev;
struct regulator_dev *dummy_regulator_rdev[2];

for (i = 0; i < 2; i++){
	config.init_data = &dummy_initdata[i];
	dummy_regulator_rdev[i] = regulator_register(&dummy_desc[i], &config);

二. 注册regulator过程

先说明下两具在regulator的core中有两个关键的全局变量链表:

regulator_list 每注册一个regulator都会挂到这里

regulator_map_list  每一个regulator都会为多个consumer供电,此表为挂consumer

==================================== regulator 消费者 =========================

静态调节器只需要一个固定的电源,而动态调节器需要在运行时对调节器进行主动管理。从消费者的角度来看,调

节器设备在内核中被表示为一个struct regulator 结构的实例

/*

  • 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;
    };

消费者怎么获取调节器:
struct regulator *reg;
const char *supply = “vdd1”;
int min_uV, max_uV;
reg = regulator_get(dev, supply);

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

*id应该匹配设备树中调节器提供的<name>模式

启用和禁用 regulator 输出

消费者可以通过调用以下命令来启用它的电源:
int regulator_enable(regulator);


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


要检查调节器是否已经启用,消费者应该调用这个:
int regulator_is_enabled(regulator);

电压控制与状态
regulator_get_voltage

int regulator_set_voltage(regulator, min_uV, max_uV);
min_uV和max_uV是以微伏为单位的最小和最大可接受电压。
注意:
	调用 regulator_get_voltage()获得调节器配置的电压输出,无论调节器是否启用,它都会返回配置的输出电压


int regulator_get_voltage(regulator);

电流控制及状态

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);

bulk型的操作

int regulator_bulk_register_supply_alias(struct device *dev,
const char *const *id,
struct device *alias_dev,
const char *const *alias_id,
int num_id);

void regulator_bulk_unregister_supply_alias(struct device *dev,
const char * const *id, int num_id);

int __must_check regulator_bulk_get(struct device *dev, int num_consumers,
struct regulator_bulk_data *consumers);

int __must_check devm_regulator_bulk_get(struct device *dev, int num_consumers,
struct regulator_bulk_data *consumers);

int __must_check regulator_bulk_enable(int num_consumers,
struct regulator_bulk_data *consumers);

int regulator_bulk_disable(int num_consumers,
struct regulator_bulk_data *consumers);

int regulator_bulk_force_disable(int num_consumers,
struct regulator_bulk_data *consumers);

void regulator_bulk_free(int num_consumers,
struct regulator_bulk_data *consumers);

最后

以上就是无心烤鸡为你收集整理的regulator框架的全部内容,希望文章能够帮你解决regulator框架所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(63)

评论列表共有 0 条评论

立即
投稿
返回
顶部