linux物理接口数据结构,Linux Regulator Framework(1)_概述
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)_概述相关推荐
- Linux cpuidle framework(1)_概述和软件架构 -- wowo
文章目录 1. 前言 2. 功能概述 3. 软件架构 1)kernel schedule模块 2)cpuidle core 3)cpuidle drivers 4)cpuidle governors ...
- linux clock头文件,Linux common clock framework(1)_概述
Linux common clock framework(1)_概述 作者:wowo 发布于:2014-10-20 23:06 分类:电源管理子系统 1. 前言 common clock framew ...
- linux cpu do idle,Linux cpuidle framework(1)_概述和软件架构
1. 前言 在计算机系统中,CPU的功能是执行程序,总结起来就是我们在教科书上学到的:取指.译码.执行.那么问题来了,如果没有程序要执行,CPU要怎么办?也许您会说,停掉就是了啊.确实,是要停掉,但何 ...
- linux 进程数据结构,Linux进程数据结构详解
1.Linux的进程简介: 支持多线程的操作系统中,进程是资源分配的最小单位,线程是调度的基本单位.Linux是现代的32位或64位的支持多线程的操作系统,不过Linux是一种以轻量级进程作为线程,多 ...
- Linux创始人数据结构,Linux 通用数据结构说明
device_driver include/linux/device.h struct device_driver { const char * name; /* 驱动名称 * ...
- Linux DMA Engine framework(2)_功能介绍及解接口分析
转载.蜗窝科技,www.wowotech.net. Linux DMA Engine framework(2)_功能介绍及解接口分析 作者:wowo 发布于:2017-5-2 22:47 分类:Lin ...
- go移植linux内核书名叫啥,Go语言移植Linux内核数据结构hlist
hlist(哈希链表)可以通过相应的Hash算法,迅速找到相关的链表Head及节点. 在有些应用场景,比Go标准库提供的list(一种双向链表)更合适. 依照list.h中的源码,我实现了一个Go语言 ...
- 【Linux】Linux内核数据结构:IDR(redix树)
1. 引言 最近在系统里遇到了IDR结构体,后来看了一下,是内核的一个基础结构. 这个是怎么引入的,引入是为了什么呢? 最早的时候,我们的结构体是一个类似于大结构体套小结构体. struct A {i ...
- 深度实践嵌入式linux系,深度实践嵌入式Linux系统移植 完整pdf_操作系统教程_源雷技术空间...
资源名称:深度实践嵌入式Linux系统移植 完整pdf 第1章嵌入式系统架构与移植环境搭建2 第2章u-boot工程与编译系统14 第3章u-boot启动流程分析41 第4章ARM9/S3C2440 ...
- 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 ...
最新文章
- jQuery队列控制方法详解queue()/dequeue()/clearQueue()
- 使用infinite-scroll实现Ghost博文列表的滚动加载
- 【Shall脚本】定时在线备份上传
- 七十七、SpringBoot整合Rabbitmq
- PHP——MySQL数据库分页查询
- 模仿网易(163)首页Ajax功能中的鼠标延时触发
- linux shell trap的使用
- js获取viewbag
- datatable中某一列最小值_Asp.net中获取DataTable选择第一行某一列值
- linux文件目录解释
- javascript实现页面滚屏效果
- 这个韩国女星在节目里吃了“巨型蛤蜊” 可能要坐牢5年了...
- UE4 无法include “filename.generated.h”
- java堆内存_java堆内存详解
- 马克·扎克伯格帝国的衰落
- 大数据SQL如何实现笛卡尔积
- c语言小熊时钟报告,C语言——小熊时钟.doc
- What Android Is
- swarm测试网如何查票?查票流程
- 差异数据的对比和整理