第一部分 regulator系统的总体概览

彩色框代表最终的regulator抽象,它的前一级表示regulator的载体(可以是PMIC、CPU、等等)。
a)CPU通过I2C controller,连接一个降压控制器(TI tps51632),该控制器输出名称为“vdd-cpu”的电压,就称作vdd-cpu regulator

b)CPU通过I2C controller,连接一个前端电源管理芯片(TI tps65090),该芯片除了具备充电管理功能外,内置了多个regulator,例如dcdc1、dcdc2等等。

c)CPU通过I2C controller,连接另一个电源管理芯片(TI tps65913), 该芯片具有两个功能:GPIO输出和PMIC。PMIC内置了多个regulator,如vddio-ddr、vdd-core等等。(由是观之, 电源管理芯片也是挂在i2c上的)

d)CPU内部也集成了一些regulator,如vdd_ac_bat等等。

regulator是虚拟出的设备,是supply,可用consumer上的受电引脚表示(比如vdd),而consumer则是消耗此supply的设备(比如"lcd")。
regulator系统分为machine部分,supply部分和consumer部分。machine部分主要描述了单板的constraints和consumer_supply的对应关系

第一部分 machine部分的描述(DTS形式)

1)tps51632 下有个regulator

   2: i2c@7000d000 {3:         status = "okay";4:         clock-frequency = <400000>;6:         tps51632@43 {7:                 compatible = "ti,tps51632";8:                 reg = <0x43>;9:                 regulator-name = "vdd-cpu";10:                 regulator-min-microvolt = <500000>;11:                 regulator-max-microvolt = <1520000>;12:                 regulator-boot-on;13:                 regulator-always-on;14:         };16: }

tps51632下面以“regulator-”为前缀的字段,是regulator特有的字段。
kernel在初始化时,只会为二级node(即“/”下面的节点,本文的例子是“i2c@7000d000”)创建platform设备,至于三级node(这里的“tps51632@43”),则由其bus(i2c)创建。

2)tps65090
  tps65090包含charger和regulator,我们看看其DTS怎么写的:

 i2c@7000d000 {2:         status = "okay";3:         ...4:  5:         tps65090@48 {6:                 compatible = "ti,tps65090";7:                 reg = <0x48>;9:  10:                 charger: charger {                   11:                         compatible = "ti,tps65090-charger";12:                         ti,enable-low-current-chrg;13:                 };14:                 15:                 regulators {                      // 两个regulator引脚16:                         tps65090_dcdc1_reg: dcdc1 {17:                                 regulator-name = "vdd-sys-5v0";18:                                 regulator-always-on;19:                                 regulator-boot-on;20:                         };21:                 22:                         tps65090_dcdc2_reg: dcdc2 {23:                                 regulator-name = "vdd-sys-3v3";24:                                 regulator-always-on;25:                                 regulator-boot-on;26:                         };28:                 }29:         }30: }

驱动处理部分代码“drivers/mfd/tps65090.c”、“drivers/power/tps65090-charger.c”和“drivers/regulator/tps65090-regulator.c”,这里面还涉及了MFD(multi-function device,多功能设备)。

虽然这里的regulators没有compatible字段,也会创建相应的 device(具体可参考“drivers/mfd/tps65090.c”)
再来看regulators中子node----regulator,由于数量比较多,就没必要创建 device了。(引脚没必要创建platform_device)

第二部分 regulator的注册

注册主要传入2个参数,regulator_desc 和 regulator_config, regulator_desc中含有各种操作函数,regulator_config的regulator_init_data中含有单板的约束条件和consumer和supply的映射关系。

1.此驱动程序主要使用的结构体:

   3: struct regulator_desc {4:         const char *name;       // 该regulator的名称5:         const char *supply_name;   // 该regulator的输入regulator的名称6:         const char *of_match;  // 提供信息,以便在注册的时候7:         const char *regulators_node; // 自动从DTS中解析init_data8:         int id;                                   // 标识该regulator的一个数字9:         bool continuous_voltage_range;   //为true时,表示该regulator可以在一定范围输出连续的电压10:         unsigned n_voltages;   // 指定可以获取的电压值的个数11:         const struct regulator_ops *ops;  // 该regulator的操作函数集12:         int irq;  //该regulator的中断号(有的话)13:         enum regulator_type type;  // 该regulator的类型,包括REGULATOR_VOLTAGE和REGULATOR_CURRENT两种14:         struct module *owner;};

驱动中定义了此宏对struct regulator_desc进行指定。

#define tps65090_REG_DESC(_id, _sname, _en_reg, _en_bits, _nvolt, _volt, _ops) \
{                           \.name = "TPS65090_RAILS"#_id,           \.supply_name = _sname,                \.id = TPS65090_REGULATOR_##_id,           \.n_voltages = _nvolt,             \.ops = &_ops,                 \.fixed_uV = _volt,                \.enable_reg = _en_reg,                \.enable_val = _en_bits,               \.enable_mask = _en_bits,          \.type = REGULATOR_VOLTAGE,            \.owner = THIS_MODULE,             \
}

结构体关系 : struct regulator_config-----> struct regulator_init_data ------> struct regulation_constraints —> operation mode

   1: struct regulator_config {2:         struct device *dev;   //regulator_register时,由regulator core分配,保存在此3:         const struct regulator_init_data *init_data;  // 在解析DTS后,保存在此4:         void *driver_data;5:         struct device_node *of_node;6:         struct regmap *regmap;7:  8:         int ena_gpio;9:         unsigned int ena_gpio_invert:1;10:         unsigned int ena_gpio_flags;11: };struct regulator_init_data {19:         const char *supply_regulator;        /* or NULL for system supply */                   // /*supply_regulator,该regulator的前级regulator,一般在regulator driver中直接指定;*/20:  21:         struct regulation_constraints constraints//constraints,该regulator的使用限制,由DTS配置,并可以借助regulator core提供的辅助  API(regulator_of_get_init_data)自动解析。后面会详细介绍;*/23:         int num_consumer_supplies;  /*使用该regulator的consumer的个数24:         struct regulator_consumer_supply *consumer_supplies;/*设备名和supply名的map。用于建立consumer设备和regulator之间的关联26:         /* optional regulator machine specific init */27:         int (*regulator_init)(void *driver_data);  //regulator的init回调,由regulator driver提供,并在regulator注册时调用;28:         void *driver_data;      //保存driver的私有数据,并在调用regulator_init时传入29: };

其中的 struct regulation_constraints constraints,展开为

 struct regulation_constraints {2:  3:         const char *name;   // name,用于描述该constraints;4:  5:         /* voltage output range (inclusive) - for voltage control */6:         int min_uV;7:         int max_uV;8:  9:         int uV_offset; // consumer看到的电压和实际电压之间的偏移值。通常用于补偿压降。只对voltage regulator有效;10:  11:         /* current output range (inclusive) - for current control */12:         int min_uA;13:         int max_uA;14:  15:         /* valid regulator operating modes for this machine */16:         unsigned int valid_modes_mask;18:         /* valid operations for regulator on this machine */19:         unsigned int valid_ops_mask;  // 该regulator支持哪些操作,以bit mask的形式提供21:         /* regulator input voltage - only if supply is another regulator */22:         int input_uV;  // 如果该regulator的输入是另一个regulator,该字段指定regulator期望的输入电压;24:         /* regulator suspend states for global PMIC STANDBY/HIBERNATE */25:         struct regulator_state state_disk;26:         struct regulator_state state_mem;27:         struct regulator_state state_standby;28:         suspend_state_t initial_state; /* suspend state to set at init */29:  30:         /* mode to set on startup */31:         unsigned int initial_mode;32:  33:         unsigned int ramp_delay;34:         unsigned int enable_time;35:  36:         /* constraint flags */37:         unsigned always_on:1;   /* regulator never off when system is on   是否一直保持使能状态;*/38:         unsigned boot_on:1;     /* bootloader/firmware enabled regulator  是否在启动时使能*/39:         unsigned apply_uV:1;    /* apply uV constraint if min == max 在regulator注册到kernel时,是否将电压设置为min_uV/max_uV。*/40:         unsigned ramp_disable:1; /* disable ramp delay */41: };struct regulator_init_data {19:         const char *supply_regulator;        /* or NULL for system supply */                   // /*supply_regulator,该regulator的前级regulator,一般在regulator driver中直接指定;*/20:  21:         struct regulation_constraints constraints//constraints,该regulator的使用限制,由DTS配置,并可以借助regulator core提供的辅助  API(regulator_of_get_init_data)自动解析。后面会详细介绍;*/23:         int num_consumer_supplies;  /*使用该regulator的consumer的个数24:         struct regulator_consumer_supply *consumer_supplies;/*设备名和supply名的map。用于建立consumer设备和regulator之间的关联26:         /* optional regulator machine specific init */27:         int (*regulator_init)(void *driver_data);  //regulator的init回调,由regulator driver提供,并在regulator注册时调用;28:         void *driver_data;      //保存driver的私有数据,并在调用regulator_init时传入29: };

其中regulator的操作模式(operation mode)

regulator的主要功能,是输出电压/电流的调整(或改变)。由于模拟器件的特性,电压/电流的改变,是需要一定的时间的。对有些regulator而言,可以工作在不同的模式,这些模式有不同的改变速度,可想而知,较快的速度,有较大的功耗。

 40: #define REGULATOR_MODE_FAST                     0x141: #define REGULATOR_MODE_NORMAL                   0x242: #define REGULATOR_MODE_IDLE                     0x443: #define REGULATOR_MODE_STANDBY                  0x8

可以更改操作模式的地方:
1)struct regulation_constraints中用于表示初始模式的字段initial_mode。
2)regulator ops中的set_mode/get_mode回调函数

2.tps65090 的regulator driver(path : drivers/regulator/tps65090-regulator.c):
以下为 TPS65090 芯片含有的regulators

/* TPS65090 Regulator ID */
enum {TPS65090_REGULATOR_DCDC1,TPS65090_REGULATOR_DCDC2,TPS65090_REGULATOR_DCDC3,TPS65090_REGULATOR_FET1,TPS65090_REGULATOR_FET2,TPS65090_REGULATOR_FET3,TPS65090_REGULATOR_FET4,TPS65090_REGULATOR_FET5,TPS65090_REGULATOR_FET6,TPS65090_REGULATOR_FET7,TPS65090_REGULATOR_LDO1,TPS65090_REGULATOR_LDO2,/* Last entry for maximum ID */TPS65090_REGULATOR_MAX,
};static int tps65090_regulator_probe(struct platform_device *pdev)
{struct tps65090 *tps65090_mfd = dev_get_drvdata(pdev->dev.parent);struct tps65090_regulator *ri = NULL;struct regulator_config config = { };struct regulator_dev *rdev;struct tps65090_regulator_plat_data *tps_pdata;struct tps65090_regulator *pmic;struct tps65090_platform_data *tps65090_pdata;struct of_regulator_match *tps65090_reg_matches = NULL;int num;int ret;tps65090_pdata = dev_get_platdata(pdev->dev.parent);    // 从platform_device中获取tps65090_platform_dataif (!tps65090_pdata && tps65090_mfd->dev->of_node)tps65090_pdata = tps65090_parse_dt_reg_data(pdev,&tps65090_reg_matches);     // 从DTS中获取tps65090_platform_datapmic = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*pmic),GFP_KERNEL);for (num = 0; num < TPS65090_REGULATOR_MAX; num++) {tps_pdata = tps65090_pdata->reg_pdata[num];ri = &pmic[num];ri->dev = &pdev->dev;ri->desc = &tps65090_regulator_desc[num];  // 对于芯片的每一个regulator引脚,指定了tps65090_reg_control_ops,内含regulator_enable_regmap等供consumer使用的函数。此驱动定义了一个tps65090_regulator_desc数组,对每个regulator设备定义了其regulator_desc结构体,内含其操作函数/** TPS5090 DCDC support the control from external digital input.* Configure it as per platform data.*/if (tps_pdata && is_dcdc(num) && tps_pdata->reg_init_data) {if (tps_pdata->enable_ext_control) {tps65090_configure_regulator_config(tps_pdata, &config);ri->desc->ops = &tps65090_ext_control_ops;} else {ret = tps65090_regulator_disable_ext_control(ri, tps_pdata);if (ret < 0) {dev_err(&pdev->dev,"failed disable ext control\n");return ret;}}}config.dev = pdev->dev.parent;config.driver_data = ri;config.regmap = tps65090_mfd->rmap;if (tps_pdata)config.init_data = tps_pdata->reg_init_data; //从平台设备获取而来,内含单板约束条件及consumer_supply的映射关系,此参数会注册进设备,每个regulator_dev会对应有1个consumer_supply的映射关系elseconfig.init_data = NULL;if (tps65090_reg_matches)config.of_node = tps65090_reg_matches[num].of_node;elseconfig.of_node = NULL;rdev = devm_regulator_register(&pdev->dev, ri->desc, &config);ri->rdev = rdev;if (ri->overcurrent_wait_valid) {ret = tps65090_reg_set_overcurrent_wait(ri, rdev);if (ret < 0)return ret;}/* Enable external control if it is require */if (tps_pdata && is_dcdc(num) && tps_pdata->reg_init_data &&tps_pdata->enable_ext_control) {ret = tps65090_config_ext_control(ri, true);if (ret < 0)return ret;}}platform_set_drvdata(pdev, pmic);return 0;
}static struct platform_driver tps65090_regulator_driver = {.driver    = {.name   = "tps65090-pmic",   },.probe        = tps65090_regulator_probe,
};static int __init tps65090_regulator_init(void)
{return platform_driver_register(&tps65090_regulator_driver);
}
subsys_initcall(tps65090_regulator_init);

注册流程:

rdev = devm_regulator_register(&pdev->dev, ri->desc, &config);  // Returns a* valid pointer to struct regulator_dev on success ---> rdev = regulator_register(regulator_desc, config);--> rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL); // 分配1个regulator_dev---> config = kmemdup(cfg, sizeof(*cfg), GFP_KERNEL); // 复制config文件---> init_data = regulator_of_get_init_data(dev, regulator_desc, config,&rdev->dev.of_node);dev = cfg->dev;search = dev->of_node;
for_each_available_child_of_node(search, child) {name = of_get_property(child, "regulator-compatible", NULL);if (desc->regulators_node)                                    search = of_get_child_by_name(dev->of_node,desc->regulators_node);elsesearch = dev->of_node;                //  调用者提供parent node// (struct device指针中,代表regulators的宿主设备,如上面的tps65090@48),// 以及该regulator在DTS中的名称(由desc->of_match提供)。从宿主设备节点处开始搜索if (strcmp(desc->of_match, name))                         // 以parent device的node,或者指定的子node为基准,//查找其下所有的node,如果node的名字或者“regulator-compatible”字段  和desc->of_match匹配,则调用of_get_regulator_init_data从中解析DTS信息
--->if (!init_data) {init_data = config->init_data;rdev->dev.of_node = of_node_get(config->of_node);}       //  协助从DTS解析init data,如果解析不到,则使用config中的
--->if (config->regmap)rdev->regmap = config->regmap;else if (dev_get_regmap(dev, NULL))rdev->regmap = dev_get_regmap(dev, NULL);else if (dev->parent)rdev->regmap = dev_get_regmap(dev->parent, NULL);    //协助获取regulator的register map(有的话),并保存在register device指针中---> ret = regulator_ena_gpio_request(rdev, config);  // 申请regulator enable gpio(有的话)--->   if (init_data && init_data->supply_regulator)rdev->supply_name = init_data->supply_regulator;else if (regulator_desc->supply_name)rdev->supply_name = regulator_desc->supply_name;if (regulator_resolve_supply(rdev))rdev_dbg(rdev, "unable to resolve supply\n");
--->constraints = &init_data->constraints; ret = set_machine_constraints(rdev, constraints);
--->ret = device_register(&rdev->dev);    // 将regulator device注册到kernel

第三部分 consumer对操作函数的使用

1)regulator_get:返回 struct regulator

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

对应设备树中的属性为Vcc-supply和Avdd-supply

第一个参数 dev中含有设备的名字,即consumer name,第二个参数为受电引脚的名字,即 supply name,两者即为init_data中的cosumer_supply的映射。以此为参数遍历regulator链表,可找到对应的struct regulator.

2)剩下的一些操作函数回会以regulator_get的返回值为参数,如regulator_get

参考博客: http://www.wowotech.net/pm_subsystem/regulator_driver.html

Linux 内核 regulator 机制相关推荐

  1. Linux内核同步机制之(四):spin lock【转】

    转自:http://www.wowotech.net/kernel_synchronization/spinlock.html 一.前言 在linux kernel的实现中,经常会遇到这样的场景:共享 ...

  2. 深度剖析Linux内核地址映射机制

    深度剖析Linux内核地址映射机制 1.虚拟空间数据结构   2.进程虚拟空间  3.内存映射 视频讲解如下,点击观看: Linux内核开发系列第7讲--深度剖析Linux内核地址映射机制 C/C++ ...

  3. linux 内核mmap,Linux内核mmap机制

    1. 问:如何将物理地址映射到用户空间的虚拟地址上? 2.linux内核mmap机制 2.1.回顾LED驱动数据流的操作过程 通过分析LED驱动,得出以下结论: 如果利用read,write,ioct ...

  4. Linux内核OOM机制的浅析

    Linux内核根据应用程序的要求分配内存,通常来说应用程序分配了内存但是并没有实际全部使用,为了提高性能,这部分没用的内存可以留作它用,这部分内存是属于每个进程的,内核直接回收利用的话比较麻烦,所以内 ...

  5. linux内核锁机制学习

    在现代操作系统里,同一时间可能有多个内核执行流在执行,因此内核其实象多进程多线程编程一样也需要一些同步机制来同步各执行单元对共享数据的访问.尤其是在多处理器系统上,更需要一些同步机制来同步不同处理器上 ...

  6. linux内核 RCU机制概述

    简介 RCU(Read-Copy Update)是数据同步的一种方式,在当前的Linux内核中发挥着重要的作用.RCU主要针对的数据对象是链表,目的是提高遍历读取数据的效率,为了达到目的使用RCU机制 ...

  7. Linux 内核配置机制(make menuconfig、Kconfig、makefile)讲解

    前面我们介绍模块编程的时候介绍了驱动进入内核有两种方式:模块和直接编译进内核,并介绍了模块的一种编译方式--在一个独立的文件夹通过makefile配合内核源码路径完成   那么如何将驱动直接编译进内核 ...

  8. Linux内核OOM机制的详细分析

    Linux 内核有个机制叫OOM killer(Out-Of-Memory killer),该机制会监控那些占用内存过大,尤其是瞬间很快消耗大量内存的进程,为了防止内存耗尽而内核会把该进程杀掉.典型的 ...

  9. Linux内核同步机制之信号量与锁

    Linux内核同步控制方法有很多,信号量.锁.原子量.RCU等等,不同的实现方法应用于不同的环境来提高操作系统效率.首先,看看我们最熟悉的两种机制--信号量.锁. 一.信号量 首先还是看看内核中是怎么 ...

  10. linux驱动基础开发3——linux 内核配置机制(make menuconfig、Kconfig、makefile)讲解-转

    前面我们介绍模块编程的时候介绍了驱动进入内核有两种方式:模块和直接编译进内核,并介绍了模块的一种编译方式--在一个独立的文件夹通过makefile配合内核源码路径完成 那么如何将驱动直接编译进内核呢? ...

最新文章

  1. 如何查找并干掉僵尸进程
  2. linux pcl 转图片,PCL转图片工具Mgosoft PCL To Image Converter
  3. 南通大学16级软嵌班软件工程课程成绩汇总
  4. tensorflow版本及其对应环境
  5. Asp.Net中global.asax文件的描述
  6. 样本方差的期望_如何理解方差和偏差
  7. 4)Thymeleaf th:each 循环迭代与 th:if、th:switch 条件判断
  8. 进价移动加权核算体系
  9. 读取cpu温度的api_获取CPU的温度的方法
  10. 如何在Microsoft Excel电子表格之间交叉引用单元格
  11. Unity基础案例讲解:创建小型太空射击游戏(二)
  12. 手机通讯录式排序php,Android获取手机通讯录-根据排序方式进行
  13. 2014-07-23 .NET实现微信公众号接入
  14. 学习 Java 的历程和体会『写给新手看,欢迎老司机批评和建议』
  15. 关于插画师,大家不知道的“秘密”
  16. 智能家居项目进度控制表
  17. 外包程序员的水平真的很垃圾吗?
  18. c语言考试系统外文文献,C语言考试系统的设计[文献翻译]
  19. JavaUDP通信程序
  20. 企业为什么着急签三方_为什么很多企业都在使用电子劳动合同?要怎么签?

热门文章

  1. 计算机工程与应用期刊投稿经验
  2. luci html 页面,luci更改登录账号.htm
  3. 题8.9:写一函数,将一个3x3的整型矩阵转置。
  4. 计算机声音音乐小星星,迷你世界电路音乐教学 小星星音乐电路
  5. 随机森林里oob_score以及用oob判断特征重要性的理解
  6. 牛顿法 泰勒二次展开式
  7. css鼠标经过改变盒子,鼠标经过盒子出现边框(伪元素,定位,css3盒子模型)...
  8. 阿里云CDN介绍以及如何配合OSS使用
  9. 通灵学院|游戏设计研习3:人类的内在人群特征★(1000字)
  10. java源代码实现判断闰年和平年