Regulator子系统

基本介绍

Regulator指的是稳定器,有电压稳定器及电流稳定器两种,能够自动维持恒定电流或者电压。其中,电压稳定器voltage regulator在电路中比较常见。从设备驱动的角度来看,regulator的控制比较简单,主要有enable/disable/输出电压或电流大小的控制。Linux利用regulator framework对regulator进行管理和控制。

Linux regulator framework的主要目的:提供标准的内核接口,控制系统的voltage/current regulators,并提供相应的开关、大小设置的机制。在系统运行的过程中,根据具体的需要动态改变regulators的输出,从而达到省电的目的。在系统中如果配错regulator是比较危险的,可能会造成硬件器件的损坏。因此,需要在regulator framework中对电流或者电压的大小做限定,并且不能被ragulator的consumer或者provider更改。

框架说明

regulator属于电源管理部分,主要实现电压、电流的输出操作,本篇文章主要介绍regulator子系统的代码实现,因此我们先熟悉一些regulator子系统的相关概念。对于regulator子系统,我们可以讲其分为三部分

  • 供电端的regulator, 负责电源芯片本身的驱动程序,比如enable/disable函数,使能或者禁止电源芯片,有一些强悍的电源芯片,是可以动态的调整电压或电流的
  • 耗电端的consumer: 比如声卡,网卡, lcd==, 在这些驱动程序里,只是去引用regulator的函数,不关心电源函数如何实现,想使能就调用enable函数
  • 不同类型的单板,regulator和consumer的对应关系是不一致的。
    • regulator和consumer的对应关系,哪一个regulator对哪一个consumer供电
    • 约束条件,在模块单板里可以输出xxx的电压或者电流,在其他的单板里可能就输出xxx的电压或者电流,单板相关的条件,比如电压范围

machine(表示一个单板)

machin使用struct regulator_init_data,静态的描述regulator在板级的硬件连接情况,这些限制通过驱动或dts配置,涉及到系统供电安全,因此必须小心,这些配置主要包括:

1)用于描述regulator在板级的级联关系:前级regulator(即该regulator的输出是另一个regulator的输入,简称supply regulator)和后级regulator(即该regulator的输入是其它regulator的输出,简称consumer regulator)。

2)利用struct regulation_constraints 描述regulator的物理限制,比如:

  • 输出电压的最大值和最小值(voltage regulator);
  • 输出电流的最大值和最小值(current regulator);
  • 允许的操作(修改电压值、修改电流限制、enable、disable等);
  • 输入电压是多少(当输入是另一个regulator时);
  • 是否不允许关闭(always_on);
  • 是否启动时就要打开(always_on);

machin使用struct regulator_init_data,静态的描述regulator在板级的硬件连接情况,这些限制通过驱动或dts配置,涉及到系统供电安全,因此必须小心,这些配置主要包括:

1)用于描述regulator在板级的级联关系:前级regulator(即该regulator的输出是另一个regulator的输入,简称supply regulator)和后级regulator(即该regulator的输入是其它regulator的输出,简称consumer regulator)。

2)利用struct regulation_constraints 描述regulator的物理限制,比如:

  • 输出电压的最大值和最小值(voltage regulator);
  • 输出电流的最大值和最小值(current regulator);
  • 允许的操作(修改电压值、修改电流限制、enable、disable等);
  • 输入电压是多少(当输入是另一个regulator时);
  • 是否不允许关闭(always_on);
  • 是否启动时就要打开(always_on);

regulator 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进行后续的操作。

PMIC
电源管理芯片,一个电源管理芯片可包含多个regulator;

Consumer
表示一个regulator使用者,regulator是电源的提供者,而consumer则是电源的消费者(比如LCD),一个regulator可供多个consumer使用;

regulator consumer抽象出regulator设备(struct regulator),并提供regulator操作相关的接口。包括:regulator_get/regulator_put/regulator_enable/regulator_disable/ regulator_set_voltage/regulator_get_voltage等。

regulator core

regulator core负责上述regulator driver/consumer/machine逻辑的具体实现,对底层的硬件进行封装,并提供接口给内核中其他的consumer(使用当前regulator设备的驱动)提供操作接口,并以sysfs的形式,向用户空间提供接口。

Power Domain
电源域,regulator可以级联,不同的regulator的使用者属于相同的电源域。如下图的regulator,则包含三个电源域:

Domain1: switch-1、consumer D、Consumer E;

Domain2:switch-2、consumer B、consumer C;

Domain3:consumer A;

这三个电源域的关系如下:

img

Domain-1 --> Domain-2 --> Domain-3,在使用时domain-3下consumer相关的电压、电流设置需要满足这三级电源域的电压、电流约束。

Constraints
表示regulator的约束,而针对regulator约束也包含三部分:

该regulator自身的约束信息:这属于regulator相关的约束信息,可通过regulator的datasheet中获取该regulator的约束信息;
Power domain级别的约束信息:这属于该regulator下不同电源域的约束信息,这些约束信息时regulator自身约束信息的子集(如regulator的电压输出约束为1v-3.5v;而domain1的约束信息为2v-3v;domain2的约束信息为2.5v等);
consumer级别的约束信息,可动态设置该consumer所需的输入电压或电流约束等。

  针对regulator子系统基本上就是这几个主要的概念,而linux regulator子系统的实现也是围绕着这几个概念进行子系统的框架设计的。
regulator的简单使用(参考内核tps6105x-regulator.c)
  • regulator driver

    • 注册一个platform driver, 在它的probe函数里面分配,设置,注册一个regulator
    • 设置里面要做的事情: 实现regulator的操作,比如enable, disable, set_voltage’
    static struct regulator_ops tps6105x_regulator_ops = {
    	.enable		= regulator_enable_regmap,     //将对应引脚设置输入/输出电平
    	.disable	= regulator_disable_regmap,    //将对应引脚设置输入/输出电平
    	.is_enabled	= regulator_is_enabled_regmap,
    	.get_voltage_sel = regulator_get_voltage_sel_regmap,
    	.set_voltage_sel = regulator_set_voltage_sel_regmap,
    	.list_voltage	= regulator_list_voltage_table,
    };
    
    
    static const struct regulator_desc tps6105x_regulator_desc = {
    	.name		= "tps6105x-boost",
    	.ops		= &tps6105x_regulator_ops,  //包含regulator的操作函数
    	.type		= REGULATOR_VOLTAGE,
    	.id		= 0,
    	.owner		= THIS_MODULE,
    	.n_voltages	= ARRAY_SIZE(tps6105x_voltages),
    	.volt_table	= tps6105x_voltages,
    	.vsel_reg	= TPS6105X_REG_0,
    	.vsel_mask	= TPS6105X_REG0_VOLTAGE_MASK,
    	.enable_reg	= TPS6105X_REG_0,
    	.enable_mask	= TPS6105X_REG0_MODE_MASK,
    	.enable_val	= TPS6105X_REG0_MODE_VOLTAGE <<
    			  TPS6105X_REG0_MODE_SHIFT,
    };
    
    static int tps6105x_regulator_probe(struct platform_device *pdev)
    {
    	struct tps6105x *tps6105x = dev_get_platdata(&pdev->dev);
    	struct tps6105x_platform_data *pdata = tps6105x->pdata;
    	struct regulator_config config = { };
    	int ret;
    	
    	config.dev = &tps6105x->client->dev;
    	config.init_data = pdata->regulator_data;  // 这个init_data就是单板中regulator的对应关系,约束条件==, 这个从pdev中的私有数据获取
    	config.driver_data = tps6105x;
    	config.regmap = tps6105x->regmap;
    
    	/* Register regulator with framework */
    	tps6105x->regulator = devm_regulator_register(&pdev->dev,
    						      &tps6105x_regulator_desc,
    						      &config);
    }
    
    static struct platform_driver tps6105x_regulator_driver = {
    	.driver = {
    		.name  = "tps6105x-regulator",
    	},
    	.probe = tps6105x_regulator_probe,
    };
    
  • machine: 构造一个regulator的platform_device, 然后填充对应关系和约束条件

    • 注册一个platfrom_device, 在他的私有数据里指定regulator和consumer的对应关系(这个电源芯片给哪一些设备供电)
    • 指定约束条件, 比如电压范围
    • 填充regulator_init_data(在内核搜索)
  • consumer

    • 使用regulator core提供的接口使用,比如regulator_get获取一个regulator, regulator_enable使能regulator
regulator注册流程
static const struct regulator_desc dummy_desc = {
	.name = "regulator-dummy",
	.id = -1,
	.type = REGULATOR_VOLTAGE,
	.owner = THIS_MODULE,
	.ops = &dummy_ops,
};
static struct regulator_init_data dummy_initdata = {
	.constraints = {
		.always_on = 1,
	},
};

config.dev = &pdev->dev;
config.init_data = &dummy_initdata;

regulator_register(&dummy_desc, &config);
	kzalloc(sizeof(struct regulator_dev), GFP_KERNEL); //申请一个regulator dev
	config = kmemdup(cfg, sizeof(*cfg), GFP_KERNEL);  //把config取出来
	regulator_of_get_init_data(dev, regulator_desc, config,
					       &rdev->dev.of_node); //从中取出config配置
	INIT_DELAYED_WORK(&rdev->disable_work, regulator_disable_work);初始化一个工作队列
	rdev->dev.class = &regulator_class;  register with sysfs
	set_machine_constraints(rdev, constraints);   //设置对应关系
	//add consumers devices 
			在regulator_map_list链表里生成一项regulator map它里面有dev->name(consumer的名字,还有supply(consumer的电源引脚名字)
			
	device_register(&rdev->dev);
	
                                                                 
struct regulator *regulator_get(struct device *dev, const char *id)  // 第一个参数就是consumer的名字,第二个参数就是supply电源引脚的名字
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值