Linux Regulator Framework(1)_概述

作者:wowo 发布于:2015-3-20 21:42

分类:电源管理子系统

1. 前言

Regulator,中文名翻译为“稳定器”,在电子工程中,是voltage regulator(稳压器)或者current regulator(稳流器)的简称,指可以自动维持恒定电压(或电流)的装置。

voltage regulator最早应用于功放电路中,主要用于滤除电源纹波(100或者120Hz)和噪声,以及避免“输出电压随负载的变化而变化”的情况。后来,随着IC级别的regulator的出现(便宜了),voltage regulator几乎存在于任何的电子设备中。例如我们常见的嵌入式设备中,基本上每一种电压,都是经过regulator输出的。

相比较voltage regulator的广泛使用,很少见到current regulator的应用场景(相信大多数的嵌入式工程师都没有接触过)。它一般存在于电流源中,除此之外,它广泛存在于近年来新兴的LED照明设备中。current regulator在LED设备中的作用主要有两个:避免驱动电流超出最大额定值,影响其可靠性;获得预期的亮度要求,并保证各个LED亮度、色度的一致性。

虽然原理比较复杂,但从设备驱动的角度看,regulator的控制应该很简单,就是输出的enable/disable、输出电压或电流的大小的控制。那么,linux kernel的regulator framework到底要做什么呢?这就是本文的目的:弄清楚regulator framework背后思考,并总结出其软件架构(和common clock framework类似,consumer/provider/core)。

注2:kernel中有关regulator framework的介绍写的相当好(Documentation\power\regulator\*),因此本文大部分内容会参考这些文件。

2. 背后的思考

Linux regulator framework的目的很直接:提供标准的内核接口,控制系统的voltage/current regulators,并提供相应的机制,在系统运行的过程中,动态改变regulators的输出,以达到省电的目的。

看似简单的背后,有些因素不得不考虑。

1)最重要的,就是安全性: 在一个系统中,错误的regulator配置是非常危险的,严重时可以损毁硬件。而无论是regulator的使用者(consumer),还是regulator提供者(provider,即regulator driver),都不一定有足够的知识和能力,避免危险发生。因此必须从machine的角度,小心的设计regulator的输出限值(这一般由产品设计、硬件设计决定的)。

同时,一旦设计确定下来之后,这些限制必须保存在一些相对固定的地方,不能轻易地被软件修改。

最后,所有的regulator操作,必须是小心的、在可允许范围内的。

2)系统中大部分的设备,都没有动态更改regulator配置的需求,甚至连enable/disable都懒得关心的,framework需要考虑这种情况,尽量简化接口。

3)会存在同一个regulator向多个设备提供power的情况,如果这些设备的需求不同怎么办?

4)regulator之间是否可以级联?如果可以,怎么处理?

这些思考最终都会反映到软件设计上,具体可参考如下的软件架构。

3. 软件架构

基于上面的思考,regulator framework的软件架构如下:

除了machine之外,基本上和common clock framework的consumer/provider框架类似。

3.1 machine

machine的主要功能,是使用软件语言(struct regulator_init_data),静态的描述regulator在板级的物理现状,包括:

1)前级regulator(即该regulator的输出是另一个regulator的输入,简称supply regulator)和后级regulator(即该regulator的输入是其它regulator的输出,简称consumer regulator)。 这主要用于描述regulator在板级的级联关系,需要留意的是,它和clock不同,这种级联关系是非常确定的,以至于需要使用静态的方式描述,而不是像clock那样,在注册的时候动态指定并形成。

2)该regulator的物理限制(struct regulation_constraints),包括: 输出电压的最大值和最小值(voltage regulator);

输出电流的最大值和最小值(current regulator);

允许的操作(修改电压值、修改电流限制、enable、disable等等);

输入电压是多少(当输入是另一个regulator时);

是否不允许关闭(always_on);

是否启动时就要打开(always_on);

等等。

这些限制关系到系统安全,因此必须小心配置。配置完成后,在系统运行的整个过程中,它们都不会再改变了。

3.2 driver

driver模块的功能,是从regulator driver的角度,抽象regulator设备。

1)使用struct regulator_desc描述regulator的静态信息,包括:名字、supply regulator的名字、中断号、操作函数集(struct regulator_ops)、使用regmap时相应的寄存器即bitmap等等。

2)使用struct regulator_config,描述regulator的动态信息(所谓的动态信息,体现在struct regulator_config变量都是局部变量,因此不会永久保存),包括struct regulator_init_data指针、设备指针、enable gpio等等。

3)提供regulator的注册接口(regulator_register/devm_regulator_register),该接口接受描述该regulator的两个变量的指针:struct regulator_desc和struct regulator_config,并分配一个新的数据结构(struct regulator_dev,从设备的角度描述regulator),并把静态指针(struct regulator_desc)和动态指针(struct regulator_config)提供的信息保存在其中。

4)最后,regulator driver将以为struct regulator_dev指针为对象,对regulator进行后续的操作。

3.3 consumer

consumer的功能,是从regulator consumer的角度,抽象regulator设备(struct regulator),并提供regulator操作相关的接口。包括:

3.4 core

core负责上述逻辑的具体实现,并以sysfs的形式,向用户空间提供接口。

4. 接口汇整

本节对regulator framework向各个层次提供的API做一个汇整,具体细节会在后续的文章中详细描述。

4.1 consumer模块向内核空间consumer提供的接口

regulator framework向内核空间consumer提供的接口位于“include/linux/regulator/consumer.h”中,包括regulator的获取、使能、修改等接口,如下。

1)struct regulator

struct regulator结构用于从consumer的角度抽象一个regulator,consumer不需要关心该结构的细节,当作一个句柄使用即可(类似struct clk)。

2)regulator的get/put接口

1: struct regulator *__must_check regulator_get(struct device *dev,

2: const char *id);

3: struct regulator *__must_check devm_regulator_get(struct device *dev,

4: const char *id);

5: struct regulator *__must_check regulator_get_exclusive(struct device *dev,

6: const char *id);

7: struct regulator *__must_check devm_regulator_get_exclusive(struct device *dev,

8: const char *id);

9: struct regulator *__must_check regulator_get_optional(struct device *dev,

10: const char *id);

11: struct regulator *__must_check devm_regulator_get_optional(struct device *dev,

12: const char *id);

13: void regulator_put(struct regulator *regulator);

14: void devm_regulator_put(struct regulator *regulator);

根据是否独占regulator、是否可以多次get,regulator get接口分为三类:

正常的get,非独占、可以重复get,regulator_get/devm_regulator_get;

独占性质的get,独占、不可重复get,regulator_get_exclusive/devm_regulator_get_exclusive;

optional的get,非独占、不可重复get,regulator_get_optional/devm_regulator_get_optional。

get接口的参数为id,会在下一篇文章中详细介绍。

3)supply alias相关的接口

1: int regulator_register_supply_alias(struct device *dev, const char *id,

2: struct device *alias_dev,

3: const char *alias_id);

4: void regulator_unregister_supply_alias(struct device *dev, const char *id);

5:

6: int devm_regulator_register_supply_alias(struct device *dev, const char *id,

7: struct device *alias_dev,

8: const char *alias_id);

9: void devm_regulator_unregister_supply_alias(struct device *dev,

10: const char *id);

11:

12: int devm_regulator_bulk_register_supply_alias(struct device *dev,

13: const char *const *id,

14: struct device *alias_dev,

15: const char *const *alias_id,

16: int num_id);

17: void devm_regulator_bulk_unregister_supply_alias(struct device *dev,

18: const char *const *id,

19: int num_id);

具体意义请参考下一篇文章。

4)regulator的控制、状态获取接口

1: int __must_check regulator_enable(struct regulator *regulator);

2: int regulator_disable(struct regulator *regulator);

3: int regulator_force_disable(struct regulator *regulator);

4: int regulator_is_enabled(struct regulator *regulator);

5: int regulator_disable_deferred(struct regulator *regulator, int ms);

6:

7: int regulator_can_change_voltage(struct regulator *regulator);

8: int regulator_count_voltages(struct regulator *regulator);

9: int regulator_list_voltage(struct regulator *regulator, unsigned selector);

10: int regulator_is_supported_voltage(struct regulator *regulator,

11: int min_uV, int max_uV);

12: unsigned int regulator_get_linear_step(struct regulator *regulator);

13: int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV);

14: int regulator_set_voltage_time(struct regulator *regulator,

15: int old_uV, int new_uV);

16: int regulator_get_voltage(struct regulator *regulator);

17: int regulator_sync_voltage(struct regulator *regulator);

18: int regulator_set_current_limit(struct regulator *regulator,

19: int min_uA, int max_uA);

20: int regulator_get_current_limit(struct regulator *regulator);

21:

22: int regulator_set_mode(struct regulator *regulator, unsigned int mode);

23: unsigned int regulator_get_mode(struct regulator *regulator);

24: int regulator_set_optimum_mode(struct regulator *regulator, int load_uA);

25:

26: int regulator_allow_bypass(struct regulator *regulator, bool allow);

27:

28: struct regmap *regulator_get_regmap(struct regulator *regulator);

29: int regulator_get_hardware_vsel_register(struct regulator *regulator,

30: unsigned *vsel_reg,

31: unsigned *vsel_mask);

32: int regulator_list_hardware_vsel(struct regulator *regulator,

33: unsigned selector);

34:

控制有关的包括enable、disable、电压设置、电流设置、mode设置等,其中disable又包括normal、强制、退出等类型。

状态获取包括:是否enable;是否可以改变电压;支持的电压列表;是否支持指定范围的电压;当前输出电压;当前电流限制;当前mode;等等。

更为详细的描述,请参考下一篇文章。

5)bulk型的操作(一次操作多个regulator)

1: int regulator_bulk_register_supply_alias(struct device *dev,

2: const char *const *id,

3: struct device *alias_dev,

4: const char *const *alias_id,

5: int num_id);

6: void regulator_bulk_unregister_supply_alias(struct device *dev,

7: const char * const *id, int num_id);

8: int __must_check regulator_bulk_get(struct device *dev, int num_consumers,

9: struct regulator_bulk_data *consumers);

10: int __must_check devm_regulator_bulk_get(struct device *dev, int num_consumers,

11: struct regulator_bulk_data *consumers);

12: int __must_check regulator_bulk_enable(int num_consumers,

13: struct regulator_bulk_data *consumers);

14: int regulator_bulk_disable(int num_consumers,

15: struct regulator_bulk_data *consumers);

16: int regulator_bulk_force_disable(int num_consumers,

17: struct regulator_bulk_data *consumers);

18: void regulator_bulk_free(int num_consumers,

19: struct regulator_bulk_data *consumers);

6)notifier相关的接口

1: int regulator_register_notifier(struct regulator *regulator,

2: struct notifier_block *nb);

3: int regulator_unregister_notifier(struct regulator *regulator,

4: struct notifier_block *nb);

如果consumer关心某个regulator的状态变化,可以通过上面接口注册一个notifier。

7)其它接口

1: /* driver data - core doesn't touch */

2: void *regulator_get_drvdata(struct regulator *regulator);

3: void regulator_set_drvdata(struct regulator *regulator, void *data);

用于设置和获取driver的私有数据。

4.2 consumer模块向用户空间consumer提供的接口

用户空间程序可以通过sysfs接口,使用regulator,就像内核空间consumer一样。这些接口由“drivers/regulator/userspace-consumer.c”实现,主要包括:

sysfs目录位置:/sys/devices/platform/reg-userspace-consumer。

name,读取可以获取该regulator的名字。

state,读取,可以获取该regulator的状态(enabled/disabled);写入可以改变regulator的状态(enabled或者1使能,disabled或者0禁止)。

4.3 machine模块向regulator driver提供的接口

machine模块主要提供struct regulator_init_data、struct regulation_constraints constraints等数据结构,用于描述板级的regulator配置,具体可参考3.1中介绍。

4.4 driver模块向regulator driver提供的接口

regulator framework向regulator driver提供的接口位于“include/linux/regulator/driver.h”中,包括数据结构抽象、regulator注册等。

1)struct regulator_desc、struct regulator_config和struct regulator_dev

见3.2中的介绍。

2)regulator设备的注册接口

1: struct regulator_dev *

2: regulator_register(const struct regulator_desc *regulator_desc,

3: const struct regulator_config *config);

4: struct regulator_dev *

5: devm_regulator_register(struct device *dev,

6: const struct regulator_desc *regulator_desc,

7: const struct regulator_config *config);

8: void regulator_unregister(struct regulator_dev *rdev);

9: void devm_regulator_unregister(struct device *dev, struct regulator_dev *rdev);

见3.2中的介绍。

3)其它接口,请参考后续的文章。

4.5 core模块向用户空间提供的sysfs接口

regulator设备在内核中是以regulator class的形式存在的,regulator core通过class->dev_groups的方式,提供了一些默认的attribute,包括:

name,读取可以获取该regulator的名字;

num_users,读取可获取regulator的使用者数目;

type,读取可以获取该regulator的类型(voltage或者current)。

另外,如果regulator driver需要提供更多的attribute(如状态、最大/最小电压等等),可以调用add_regulator_attributes接口,主动添加。

原创文章,转发请注明出处。蜗窝科技,www.wowotech.net。

评论:

鱼儿

2019-08-06 17:52

请教一下,我遇到这样一个问题,我将一个模块设置为booton,这个模块的电源是有外部i2c连接的一个pmic控制的,然后在probe的时候regulator_enable将这个模块上电,但是奇怪的是,如果我将这个模块编译成ko,这个ko就无法insmod,卡死在regulator_enable当中,如果设置成alwayson的方式,则可以正常insmod

searchthetruth

2018-06-05 21:03

@wowo

===========原文=========

3.2 driver

driver模块的功能,是从regulator driver的角度,抽象regulator设备。

========================

此处driver部分的主要功能是注册regulator(生成struct regulator_dev)并实现针对regulator的各类操作(struct regulator_ops),同时提供notifier机制,当regulator有事件发生时通知其他关心该regulator变化的程序。

不知道这样的理解是否正确呢?

blain

2018-05-10 16:27

是否启动时就要打开(always_on);

这句话括号里是不是应该(boot_on)

黯魂天残

2017-01-12 14:25

不错,谢谢分享!

kobe.bao

2016-03-07 20:48

Hi wowo:

关于电源管理,有个问题请教,是这样的(高通soc芯片):

需要regulator供电的外设,都会在其DTS中对regulator进行设置(暂且称之为regulator设置节点),例如:

qcom,ctrl-supply-entry@0 {

qcom,supply-name = "vdda";

qcom,supply-min-voltage = <1250000>;

qcom,supply-max-voltage = <1250000>;

...

};

驱动代码中会对该节点进行解析,利用regulator_get、regulator_count_voltages等API函数进行设置。

通常,外设的DTS中还有一个这样的节点,例如:

vdda-supply =

该节点的解释是“Phandle for vreg regulator device node”,暂且称为regulator设备节点。但是我在代码中并没有找到对该节点的解析,我想请问,regulator设备节点与regulator设置节点是怎么联系起来的?

2016-03-07 22:39

@kobe.bao:qcom,supply-name = "xxx";

xxx-supply =

这里的xxx是“vdda”,就是这样联系起来的。

kobe.bao

2016-03-08 18:52

@wowo:Hi wowo:

感谢回答。

我也猜到他们是这样联系起来的,但是在代码中我没有找到相关的部分,心里总觉得不踏实,能否指点下代码中是如何实现联系的?谢谢

2016-03-08 21:20

@kobe.bao:关于regulator的supply,我在“http://www.wowotech.net/pm_subsystem/regulator_driver.html”中有提到,其实就是在regulator_register的时候,解析DTS中“supply-name”的值,然后调用regulator_dev_lookup接口,找到对应的struct regulator指针(就是“xxx-supply = ”所对应的指针)。

kobe.bao

2016-03-09 19:40

@wowo:Hi wowo:

还没有空拜读后面的文章呢,我再自己跟下,多谢

另外,刚接触pm,以前没搞过,想系统学习下,我看咱网站“电源管理”栏目有几十篇文章,该按照怎么主线进行学习呢?

谢谢

2016-03-09 21:19

@kobe.bao:按照时间顺序看就行了,我也是按照这个主线写的。

kobe.bao

2016-03-10 21:29

@wowo:好的,多谢,也期待wowo继续完成Linux graphic subsytem

2015-09-07 23:40

请问,这一句是不是有语误,说反了?:

1)前级regulator(即该regulator的输入是另一个regulator的输出,简称supply regulator)和后级regulator(即该regulator的输出是其它regulator的输入,简称consumer regulator)。

2015-09-08 09:31

@coray:感谢指正,确实是写反了,马上修改,谢谢~~~

2015-05-03 16:19

mark ^_^

2015-04-01 16:11

mark

2015-03-24 11:26

hi wowo

我有个问题想请教,我的理解,arm的电,都是靠PMIC给供的。那PMIC的电,跟regulator是怎么对应上的呢??物理上肯定是有连线的。

或者说,比如一个regulator是vdd1v8,那这个肯定是PMIC那边的1V8供过来的?还是随便一个regulator,只是软件写成1v8,然后PMIC就会出这个电?

wowo

2015-03-24 14:38

@tigger:tigger,我不是很明白您的意思。PMIC是一个硬件设备,regulator也是硬件设备。只不过,大多数时候,regulator集成在PMIC的内部了,因此会出现;类似下面的设备拓扑结构(以DTS的形式):

PMICx {

avdd0 {

};

vcc1_8 {

};

...

};

driver的编写形式为:

pmic_probe {

...

regulator_register(1...);

regulator_register(2...);

...

};

因此regulator的控制(包括enable、disable、modify value等),还是需要依赖parent driver(PMIC)的实现的。

2015-03-24 15:18

@wowo:ok 我明白了,我以为regulator是ARM CPU这边的器件了。

发表评论:

昵称

邮件地址 (选填)

个人主页 (选填)

linux物理接口数据结构,Linux Regulator Framework(1)_概述相关推荐

  1. Linux cpuidle framework(1)_概述和软件架构 -- wowo

    文章目录 1. 前言 2. 功能概述 3. 软件架构 1)kernel schedule模块 2)cpuidle core 3)cpuidle drivers 4)cpuidle governors ...

  2. linux clock头文件,Linux common clock framework(1)_概述

    Linux common clock framework(1)_概述 作者:wowo 发布于:2014-10-20 23:06 分类:电源管理子系统 1. 前言 common clock framew ...

  3. linux cpu do idle,Linux cpuidle framework(1)_概述和软件架构

    1. 前言 在计算机系统中,CPU的功能是执行程序,总结起来就是我们在教科书上学到的:取指.译码.执行.那么问题来了,如果没有程序要执行,CPU要怎么办?也许您会说,停掉就是了啊.确实,是要停掉,但何 ...

  4. linux 进程数据结构,Linux进程数据结构详解

    1.Linux的进程简介: 支持多线程的操作系统中,进程是资源分配的最小单位,线程是调度的基本单位.Linux是现代的32位或64位的支持多线程的操作系统,不过Linux是一种以轻量级进程作为线程,多 ...

  5. Linux创始人数据结构,Linux 通用数据结构说明

    device_driver include/linux/device.h struct device_driver { const char             * name; /* 驱动名称 * ...

  6. Linux DMA Engine framework(2)_功能介绍及解接口分析

    转载.蜗窝科技,www.wowotech.net. Linux DMA Engine framework(2)_功能介绍及解接口分析 作者:wowo 发布于:2017-5-2 22:47 分类:Lin ...

  7. go移植linux内核书名叫啥,Go语言移植Linux内核数据结构hlist

    hlist(哈希链表)可以通过相应的Hash算法,迅速找到相关的链表Head及节点. 在有些应用场景,比Go标准库提供的list(一种双向链表)更合适. 依照list.h中的源码,我实现了一个Go语言 ...

  8. 【Linux】Linux内核数据结构:IDR(redix树)

    1. 引言 最近在系统里遇到了IDR结构体,后来看了一下,是内核的一个基础结构. 这个是怎么引入的,引入是为了什么呢? 最早的时候,我们的结构体是一个类似于大结构体套小结构体. struct A {i ...

  9. 深度实践嵌入式linux系,深度实践嵌入式Linux系统移植 完整pdf_操作系统教程_源雷技术空间...

    资源名称:深度实践嵌入式Linux系统移植 完整pdf 第1章嵌入式系统架构与移植环境搭建2 第2章u-boot工程与编译系统14 第3章u-boot启动流程分析41 第4章ARM9/S3C2440 ...

  10. Linux内核4.14版本——mmc框架_软件总体架构

    目录 1. 前言 2. 软件架构 3. 工作流程 4. mmc设备 4.1 mmc type card 4.2 sd type card 4.3 sdio type card 5. mmc协议 5.1 ...

最新文章

  1. jQuery队列控制方法详解queue()/dequeue()/clearQueue()
  2. 使用infinite-scroll实现Ghost博文列表的滚动加载
  3. 【Shall脚本】定时在线备份上传
  4. 七十七、SpringBoot整合Rabbitmq
  5. PHP——MySQL数据库分页查询
  6. 模仿网易(163)首页Ajax功能中的鼠标延时触发
  7. linux shell trap的使用
  8. js获取viewbag
  9. datatable中某一列最小值_Asp.net中获取DataTable选择第一行某一列值
  10. linux文件目录解释
  11. javascript实现页面滚屏效果
  12. 这个韩国女星在节目里吃了“巨型蛤蜊” 可能要坐牢5年了...
  13. UE4 无法include “filename.generated.h”
  14. java堆内存_java堆内存详解
  15. 马克·扎克伯格帝国的衰落
  16. 大数据SQL如何实现笛卡尔积
  17. c语言小熊时钟报告,C语言——小熊时钟.doc
  18. What Android Is
  19. swarm测试网如何查票?查票流程
  20. 差异数据的对比和整理

热门文章

  1. 小象学院 第11章 提升
  2. 手机wifi显示连接到服务器地址,手机连接路由器wifi上网总是提示正在获取IP地址怎么办...
  3. 这才叫高颜值的Markdown编辑神器!
  4. 基于微信图书馆教室座位预约小程序系统设计与实现 开题报告
  5. 蚂蚁金融NLP竞赛——文本语义相似度赛题总结
  6. 华为收入超过阿里腾讯总和!等等,先把鸿蒙说清楚!
  7. 用什么软件编写html语言,可以用什么工具编写javascript?
  8. Android 微信分享不显示分享出去的图标问题
  9. IIS、Asp.net 编译时的临时文件路径
  10. 《卡耐基成功学》阅读笔记