Linux regulator框架理解及使用

简述

Regulator,即LDO(low dropout regulator),低压差线性稳压器,简称稳压器。

作为电源管理中的基础设施,regulator被视作为Linux系统的供电单元;这是一个抽象出来的概念,他的provider可以是PMIC,tpsxx,lpxxx等各种power supply,/kernel/msm-3.18/drivers/regulator目录下保存了各种电源芯片对应的regulator驱动程序,同时他也提供一个dummy regulator驱动作为参考;由于各provider的控制方法不同,所以在向系统注册regulator设备时,需要自备ops,即操作函数,用于对其进行各种控制。

Linux中Regulator的抽象概念,其最大的意义在于为各consumer的使用提供了统一的接口,例如获取跟设置电压输出,控制其使能等;在不同的场景下动态的调整regulator使能,已达到省电的目的,这一点在移动设备上尤为重要。

Regulator framework大致框图如下,下面将针对其源码部分进行简单的解析,以及从一个consumer使用者的角度介绍regulator在实践中的应用。

数据结构及API

1.regulator register

用于各provider向系统注册regulator资源,其中的参数通过provider driver指定,或分析dts获取;

源码位置/kernel/msm-3.18/drivers/regulator/core.c

struct regulator_dev *
regulator_register(const struct regulator_desc *regulator_desc,
		   const struct regulator_config *config);
struct regulator_dev *
devm_regulator_register(struct device *dev,
			const struct regulator_desc *regulator_desc,
			const struct regulator_config *config);
void regulator_unregister(struct regulator_dev *rdev);
void devm_regulator_unregister(struct device *dev, struct regulator_dev *rdev);

2.regulator ops

provider注册regulator时,需要提前填好该结构体,用于控制provider,该结构体作为成员保存在struct regulator_desc内部(注册regulator时用到的参数),结构体太长不全贴了;

源码位置/kernel/msm-3.18/include/linux/regulator/driver.h

struct regulator_ops {
	...
	/* get/set regulator voltage */
	int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV,
			    unsigned *selector);
	int (*map_voltage)(struct regulator_dev *, int min_uV, int max_uV);
	int (*set_voltage_sel) (struct regulator_dev *, unsigned selector);
	int (*get_voltage) (struct regulator_dev *);
	int (*get_voltage_sel) (struct regulator_dev *);

	/* enable/disable regulator */
	int (*enable) (struct regulator_dev *);
	int (*disable) (struct regulator_dev *);
	int (*is_enabled) (struct regulator_dev *);
	/* get/set regulator operating mode (defined in consumer.h) */
	int (*set_mode) (struct regulator_dev *, unsigned int mode);
	unsigned int (*get_mode) (struct regulator_dev *);
	...
};

3.consumer API

用于consumer控制regulator的接口,包括获取/释放regulator handler,获取/设置电压值,控制使能,获取使能状态等

头文件路径/kernel/msm-3.18/include/linux/regulator/consumer.h

/* regulator get and put */
struct regulator *__must_check regulator_get(struct device *dev, const char *id);
struct regulator *__must_check devm_regulator_get(struct device *dev, const char *id);
void regulator_put(struct regulator *regulator);
void devm_regulator_put(struct regulator *regulator);

/* regulator output control and status */
int __must_check regulator_enable(struct regulator *regulator);
int regulator_disable(struct regulator *regulator);
int regulator_force_disable(struct regulator *regulator);
int regulator_is_enabled(struct regulator *regulator);
int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV);
int regulator_get_voltage(struct regulator *regulator);

应用实例

1.regulator在dts中的配置

rpm-regulator-ldoa22 {
	compatible = "qcom,rpm-smd-regulator-resource";
	qcom,resource-name = "ldoa";
	qcom,resource-id = <22>;
	qcom,regulator-type = <0>;
	qcom,hpm-min-load = <10000>;
	status = "disabled";

	regulator-l22 {
		compatible = "qcom,rpm-smd-regulator";
		regulator-name = "pm8953_l22";
		qcom,set = <3>;
		status = "disabled";
	};
};

rpm-regulator-ldoa22 {
	status = "okay";
	pm8953_l22: regulator-l22 {
		regulator-min-microvolt = <1800000>;
		regulator-max-microvolt = <1800000>;
		qcom,init-voltage = <1800000>;
		status = "okay";
	};
};

补充一点, 上述dts中定义的电压值即为该LDO支持的电压,如需调整该电压值,需提前确认LDO是否支持。以高通配平台为例,pm8953 LDO22的电压默认值就是1v8,如需调整该电压,光改dts是不够的,BP也会有相应改动才能调整该LDO电压输出。目前本人尚未遇到调整LDO电压输出的场景,基本都是支持多少用多少。

2.consumer对regulator的引用

cam_vio-supply = <&pm8953_l22>;

3.consumer driver解析dts获取regulator handler,我们将其命名为“cam-vio”;

此处通过sysfs提供attribute file,用于获取并控制regulator cam-vio,其中全局变量g_dev即为该driver的platform device

static ssize_t pateo_cam_vio_store(struct class *dev,
		struct class_attribute *attr, const char *buf,
		size_t count)
{
	if(!strncmp(buf, "1", strlen("1"))) {
		camera_vio = regulator_get(&g_dev->dev, "cam_vio");

		printk(KERN_INFO"%s: enable cam_vio device", __func__);
		regulator_enable(camera_vio);
	} else {
		printk(KERN_INFO"%s: disable cam_vio device", __func__);
		regulator_disable(camera_vio);
		regulator_put(camera_vio);
	}

	return count;
}

4.通过debugfs中regulator的节点可以检查配置是否成功

msm8953_32:/d/regulator/pm8953_l22 # pwd
/d/regulator/pm8953_l22
msm8953_32:/d/regulator/pm8953_l22 # ls -al
total 0
drwxr-xr-x  4 root root 0 1970-01-01 08:00 .
drwxr-xr-x 49 root root 0 1970-01-01 08:00 ..
-r--r--r--  1 root root 0 1970-01-01 08:00 bypass_count
-r--r--r--  1 root root 0 1970-01-01 08:00 consumers
-rw-r--r--  1 root root 0 1970-01-01 08:00 enable
-rw-r--r--  1 root root 0 1970-01-01 08:00 force_disable
-rw-r--r--  1 root root 0 1970-01-01 08:00 mode
-r--r--r--  1 root root 0 1970-01-01 08:00 open_count
-rw-r--r--  1 root root 0 1970-01-01 08:00 optimum_mode
drwxr-xr-x  2 root root 0 1970-01-01 08:00 pm8953_l22
drwxr-xr-x  2 root root 0 1970-01-01 08:00 soc:pateo_gpio-cam_vio
-r--r--r--  1 root root 0 1970-01-01 08:00 use_count
-rw-r--r--  1 root root 0 1970-01-01 08:00 voltage
msm8953_32:/d/regulator/pm8953_l22 # cat voltage                               
1800000
msm8953_32:/d/regulator/pm8953_l22 # cat enable                                
1
msm8953_32:/d/regulator/pm8953_l22 # cat use_count                             
1

补充一点,通过debugfs可以明确获取当前regulator打开次数,所以如过需要关闭该regulator,需要关闭所有打开过的地方,如有一个未关闭,regulator都将处于打开状态。这个过程可以理解为资源释放,有超过一个driver访问了当前资源,如果想释放该资源,一定是所有driver都释放了,该资源最终才会被释放掉。

 

参考链接https://blog.csdn.net/lurayvis/article/details/26642641

  • 3
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值