【电源管理】Linux电源管理之Regular系统

前言

本文简单介绍了Linux电源管理中较为简单的Regular子系统,regular系统使用简单广泛,在各种外设中只要需要电源都可以使用,以减少产品功耗。

一、概念

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

Regulator : 电源芯片, 比如电压转换芯片
Consumer : 消费者,使用电源的部件, Regulator是给Consumer供电的
machine : 单板,上面焊接有Regulator和Consumer
Constraints : 约束, 比如某个电源管理芯片输出的电压范围
Supply : 提供电源的部件, Regulator就是一个Supply; Regulator A可以给Regulator B供电, 那么Regulator B的Supply就是A

二、框架

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jUONADWf-1680666769924)(image/Linux之电源管理/v2-de25e80eac1533cd78bd78caa55ef286_r.jpg)]

1、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);

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

2、regulator consumer

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

2、regulator core

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

三、驱动程序编写思路

  1. regulator:
    注册一个platform_driver: 在它的probe函数里分配、设置、注册一个regulator
    "设置"里要做的事情: 实现regulator的操作, 比如enable, disable, set_voltage
  2. machine:
    注册一个platform_device: 在它的私有数据里指定regulator和consume的对应关系(这个电源芯片给哪一个部件供电)
    指定约束条件(比如电压范围)
  3. consumer: 使用即可: regulator_get, regulator_enable, regulator_disable, regulator_set_voltage…

四、设备树regular节点

  • regular主节点(/Linux-5.4/arch/arm/boot/dts/stm32mp15xx-edx.dtsi +163)
regulators {
164             compatible = "st,stpmic1-regulators";
165             buck1-supply = <&vin>;
166             buck2-supply = <&vin>;
167             buck3-supply = <&vin>;
168             buck4-supply = <&vin>;
169             ldo1-supply = <&v3v3>;
170             ldo2-supply = <&v3v3>;
171             ldo3-supply = <&vdd_ddr>;
172             ldo4-supply = <&vin>;
173             ldo5-supply = <&v3v3>;
174             ldo6-supply = <&v3v3>;
175             vref_ddr-supply = <&vin>;
176             boost-supply = <&vin>;
177             pwr_sw1-supply = <&bst_out>;
178             pwr_sw2-supply = <&bst_out>;
179
180             vddcore: buck1 {
181                 regulator-name = "vddcore";
182                 regulator-min-microvolt = <1200000>;
183                 regulator-max-microvolt = <1350000>;
184                 regulator-always-on;
185                 regulator-initial-mode = <0>;
186                 regulator-over-current-protection;
187             };
188
189             vdd_ddr: buck2 {
190                 regulator-name = "vdd_ddr";
191                 regulator-min-microvolt = <1350000>;
192                 regulator-max-microvolt = <1350000>;
193                 regulator-always-on;
194                 regulator-initial-mode = <0>;
195                 regulator-over-current-protection;
196             };
197
198             vdd: buck3 {
199                 regulator-name = "vdd";
200                 regulator-min-microvolt = <3300000>;
201                 regulator-max-microvolt = <3300000>;
202                 regulator-always-on;
203                 st,mask-reset;
204                 regulator-initial-mode = <0>;
205                 regulator-over-current-protection;
206             };
207
208             v3v3: buck4 {
209                 regulator-name = "v3v3";
210                 regulator-min-microvolt = <3300000>;
211                 regulator-max-microvolt = <3300000>;
212                 regulator-always-on;
213                 regulator-over-current-protection;
214                 regulator-initial-mode = <0>;
215             };
216
217             vdda: ldo1 {
218                 regulator-name = "vdda";
219                 regulator-min-microvolt = <2900000>;
220                 regulator-max-microvolt = <2900000>;
221                 interrupts = <IT_CURLIM_LDO1 0>;
222             };
223
224             v2v8: ldo2 {
225                 regulator-name = "v2v8";
225                 regulator-name = "v2v8";
226                 regulator-min-microvolt = <2800000>;
227                 regulator-max-microvolt = <2800000>;
228                 interrupts = <IT_CURLIM_LDO2 0>;
229             };
230
231             vtt_ddr: ldo3 {
232                 regulator-name = "vtt_ddr";
233                 regulator-min-microvolt = <500000>;
234                 regulator-max-microvolt = <750000>;
235                 regulator-always-on;
236                 regulator-over-current-protection;
237             };
238
239             vdd_usb: ldo4 {
240                 regulator-name = "vdd_usb";
241                 regulator-min-microvolt = <3300000>;
242                 regulator-max-microvolt = <3300000>;
243                 interrupts = <IT_CURLIM_LDO4 0>;
244                 regulator-always-on;
245             };
246
247             vdd_sd: ldo5 {
248                 regulator-name = "vdd_sd";
249                 regulator-min-microvolt = <2900000>;
250                 regulator-max-microvolt = <2900000>;
251                 interrupts = <IT_CURLIM_LDO5 0>;
252                 regulator-boot-on;
253             };
254
255             v1v8: ldo6 {
256                 regulator-name = "v1v8";
257                 regulator-min-microvolt = <1800000>;
258                 regulator-max-microvolt = <1800000>;
259                 interrupts = <IT_CURLIM_LDO6 0>;
260             };
261
262             vref_ddr: vref_ddr {
263                 regulator-name = "vref_ddr";
264                 regulator-always-on;
265                 regulator-over-current-protection;
266             };
267
68             bst_out: boost {
269                 regulator-name = "bst_out";
270                 interrupts = <IT_OCP_BOOST 0>;
271             };
272
273             vbus_otg: pwr_sw1 {
274                 regulator-name = "vbus_otg";
275                 interrupts = <IT_OCP_OTG 0>;
276              };
277
278              vbus_sw: pwr_sw2 {
279                 regulator-name = "vbus_sw";
280                 interrupts = <IT_OCP_SWOUT 0>;
281                 regulator-active-discharge = <1>;
282              };
283         };
284
  • sd卡开关电源管理节点(/Linux-5.4/arch/arm/boot/dts/stm32mp15xx-edx.dtsi 67)
 68     sd_switch: regulator-sd_switch {
 69         compatible = "regulator-gpio";
 70         regulator-name = "sd_switch";
 71         regulator-min-microvolt = <1800000>;
 72         regulator-max-microvolt = <2900000>;
 73         regulator-type = "voltage";
 74         regulator-always-on;
 75
 76         gpios = <&gpiof 14 GPIO_ACTIVE_HIGH>;
 77         gpios-states = <0>;
 78         states = <1800000 0x1 2900000 0x0>;
 79     };

  • 输入电源节点
81     vin: vin {
 82         compatible = "regulator-fixed";
 83         regulator-name = "vin";
 84         regulator-min-microvolt = <5000000>;
 85         regulator-max-microvolt = <5000000>;
 86         regulator-always-on;
 87     };

参考资料

一文搞懂linux regulator子系统 - 知乎 (zhihu.com)

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
学生信息管理系统是一个常见的应用系统,使用C#语言采用三层架构进行开发,可以提高系统的可维护性、可扩展性、可重用性和可测试性等方面的优势。 三层架构是一个比较经典的软件架构,它将应用程序划分为三个主要的部分:表示层、业务逻辑层和数据访问层。每一层都有不同的职责,但它们又协同工作,为应用程序提供了良好的结构和可维护性。 下面我来介绍一下如何使用C#语言来开发一个学生信息管理系统。 一、需求分析 首先,我们需要对学生信息管理系统进行需求分析,明确系统的功能和需求,例如: 1. 学生信息的录入、修改、删除和查询功能。 2. 学生信息的显示和打印功能。 3. 学生信息的统计和分析功能。 4. 具有管理员和普通用户两种角色,管理员可以对学生信息进行管理,而普通用户只能浏览学生信息。 二、设计数据库 接下来,我们需要设计数据库,为系统提供数据存储和管理。在这里,我们可以使用SQL Server数据库管理系统来创建一个名为“Student”的数据库,其中包含一个名为“StudentInfo”的表,用于存储学生信息。 表的结构如下: |字段名称|字段类型|字段长度|是否允许空值| |:----:|:----:|:----:|:----:| |StudentID|nvarchar|10|否| |Name|nvarchar|20|否| |Sex|nvarchar|4|否| |Age|int|4|否| |Class|nvarchar|20|否| |Address|nvarchar|50|是| |Phone|nvarchar|20|是| 在这个表中,我们设置了一个主键StudentID,用于唯一标识每一个学生。 三、设计架构 在这里,我们采用三层架构来设计学生信息管理系统。 1. 表示层:表示层是系统与用户之间的接口,主要负责用户交互和数据展示的工作。在这里,我们使用Windows Forms技术来实现用户界面。 2. 业务逻辑层:业务逻辑层是系统的核心部分,它负责处理系统的业务逻辑,将用户的请求转化为对数据访问层的请求,并将处理结果返回给用户。在这里,我们将业务逻辑层封装为一个名为“StudentBLL”的类。 3. 数据访问层:数据访问层是系统与数据库之间的接口,主要负责对数据库进行访问和操作。在这里,我们将数据访问层封装为一个名为“StudentDAL”的类。 四、编写代码 1. 表示层代码 在表示层中,我们需要实现用户界面和事件响应等功能。在这里,我们使用Windows Forms技术来实现用户界面,例如: ```csharp // MainForm.cs public partial class MainForm : Form { private StudentBLL studentBLL = new StudentBLL(); public MainForm() { InitializeComponent(); } private void MainForm_Load(object sender, EventArgs e) { RefreshData(); } private void RefreshData() { dgvStudent.DataSource = studentBLL.GetAllStudents(); } private void btnAdd_Click(object sender, EventArgs e) { AddStudentForm addStudentForm = new AddStudentForm(); if (addStudentForm.ShowDialog() == DialogResult.OK) { Student student = new Student(); student.StudentID = addStudentForm.txtStudentID.Text; student.Name = addStudentForm.txtName.Text; student.Sex = addStudentForm.cboSex.Text; student.Age = Convert.ToInt32(addStudentForm.txtAge.Text); student.Class = addStudentForm.txtClass.Text; student.Address = addStudentForm.txtAddress.Text; student.Phone = addStudentForm.txtPhone.Text; if (studentBLL.AddStudent(student)) { MessageBox.Show("添加成功!"); RefreshData(); } else { MessageBox.Show("添加失败,请检查输入信息!"); } } } private void btnEdit_Click(object sender, EventArgs e) { if (dgvStudent.CurrentRow != null) { EditStudentForm editStudentForm = new EditStudentForm(); editStudentForm.txtStudentID.Text = dgvStudent.CurrentRow.Cells["StudentID"].Value.ToString(); editStudentForm.txtName.Text = dgvStudent.CurrentRow.Cells["Name"].Value.ToString(); editStudentForm.cboSex.Text = dgvStudent.CurrentRow.Cells["Sex"].Value.ToString(); editStudentForm.txtAge.Text = dgvStudent.CurrentRow.Cells["Age"].Value.ToString(); editStudentForm.txtClass.Text = dgvStudent.CurrentRow.Cells["Class"].Value.ToString(); editStudentForm.txtAddress.Text = dgvStudent.CurrentRow.Cells["Address"].Value.ToString(); editStudentForm.txtPhone.Text = dgvStudent.CurrentRow.Cells["Phone"].Value.ToString(); if (editStudentForm.ShowDialog() == DialogResult.OK) { Student student = new Student(); student.StudentID = editStudentForm.txtStudentID.Text; student.Name = editStudentForm.txtName.Text; student.Sex = editStudentForm.cboSex.Text; student.Age = Convert.ToInt32(editStudentForm.txtAge.Text); student.Class = editStudentForm.txtClass.Text; student.Address = editStudentForm.txtAddress.Text; student.Phone = editStudentForm.txtPhone.Text; if (studentBLL.UpdateStudent(student)) { MessageBox.Show("修改成功!"); RefreshData(); } else { MessageBox.Show("修改失败,请检查输入信息!"); } } } else { MessageBox.Show("请先选择一条记录!"); } } private void btnDelete_Click(object sender, EventArgs e) { if (dgvStudent.CurrentRow != null) { string studentID = dgvStudent.CurrentRow.Cells["StudentID"].Value.ToString(); if (MessageBox.Show("确定要删除学号为" + studentID + "的学生信息吗?", "删除确认", MessageBoxButtons.YesNo) == DialogResult.Yes) { if (studentBLL.DeleteStudent(studentID)) { MessageBox.Show("删除成功!"); RefreshData(); } else { MessageBox.Show("删除失败!"); } } } else { MessageBox.Show("请先选择一条记录!"); } } private void btnSearch_Click(object sender, EventArgs e) { string keyword = txtKeyword.Text.Trim(); dgvStudent.DataSource = studentBLL.SearchStudents(keyword); } private void btnPrint_Click(object sender, EventArgs e) { PrintDialog printDialog = new PrintDialog(); if (printDialog.ShowDialog() == DialogResult.OK) { PrintDocument printDocument = new PrintDocument(); printDocument.PrintPage += new PrintPageEventHandler(printDocument_PrintPage); printDocument.PrinterSettings = printDialog.PrinterSettings; printDocument.Print(); } } private void printDocument_PrintPage(object sender, PrintPageEventArgs e) { Font font = new Font("宋体", 12, FontStyle.Regular); Brush brush = new SolidBrush(Color.Black); int x = e.MarginBounds.Left; int y = e.MarginBounds.Top; int rowHeight = dgvStudent.Rows[0].Height; int columnCount = dgvStudent.Columns.Count; for (int i = 0; i < columnCount; i++) { e.Graphics.DrawString(dgvStudent.Columns[i].HeaderText, font, brush, x, y); x += dgvStudent.Columns[i].Width; } y += rowHeight; for (int i = 0; i < dgvStudent.Rows.Count; i++) { x = e.MarginBounds.Left; for (int j = 0; j < columnCount; j++) { e.Graphics.DrawString(dgvStudent.Rows[i].Cells[j].Value.ToString(), font, brush, x, y); x += dgvStudent.Columns[j].Width; } y += rowHeight; } } } ``` 2. 业务逻辑层代码 在业务逻辑层中,我们需要实现系统的业务逻辑,例如: ```csharp // StudentBLL.cs public class StudentBLL { private StudentDAL studentDAL = new StudentDAL(); public DataTable GetAllStudents() { return studentDAL.GetAllStudents(); } public bool AddStudent(Student student) { if (studentDAL.GetStudentByID(student.StudentID) == null) { return studentDAL.AddStudent(student); } else { return false; } } public bool UpdateStudent(Student student) { if (studentDAL.GetStudentByID(student.StudentID) != null) { return studentDAL.UpdateStudent(student); } else { return false; } } public bool DeleteStudent(string studentID) { if (studentDAL.GetStudentByID(studentID) != null) { return studentDAL.DeleteStudent(studentID); } else { return false; } } public DataTable SearchStudents(string keyword) { return studentDAL.SearchStudents(keyword); } } ``` 3. 数据访问层代码 在数据访问层中,我们需要实现对数据库的访问和操作,例如: ```csharp // StudentDAL.cs public class StudentDAL { private string connectionString = ConfigurationManager.ConnectionStrings["Student"].ConnectionString; public DataTable GetAllStudents() { string sql = "SELECT StudentID, Name, Sex, Age, Class, Address, Phone FROM StudentInfo"; return SqlHelper.ExecuteDataTable(connectionString, CommandType.Text, sql); } public Student GetStudentByID(string studentID) { string sql = "SELECT StudentID, Name, Sex, Age, Class, Address, Phone FROM StudentInfo WHERE StudentID = @StudentID"; SqlParameter[] parameters = new SqlParameter[]{ new SqlParameter("@StudentID", studentID) }; DataTable dataTable = SqlHelper.ExecuteDataTable(connectionString, CommandType.Text, sql, parameters); if (dataTable.Rows.Count == 1) { Student student = new Student(); student.StudentID = dataTable.Rows[0]["StudentID"].ToString(); student.Name = dataTable.Rows[0]["Name"].ToString(); student.Sex = dataTable.Rows[0]["Sex"].ToString(); student.Age = Convert.ToInt32(dataTable.Rows[0]["Age"]); student.Class = dataTable.Rows[0]["Class"].ToString(); student.Address = dataTable.Rows[0]["Address"].ToString(); student.Phone = dataTable.Rows[0]["Phone"].ToString(); return student; } else { return null; } } public bool AddStudent(Student student) { string sql = "INSERT INTO StudentInfo(StudentID, Name, Sex, Age, Class, Address, Phone) VALUES(@StudentID, @Name, @Sex, @Age, @Class, @Address, @Phone)"; SqlParameter[] parameters = new SqlParameter[]{ new SqlParameter("@StudentID", student.StudentID), new SqlParameter("@Name", student.Name), new SqlParameter("@Sex", student.Sex), new SqlParameter("@Age", student.Age), new SqlParameter("@Class", student.Class), new SqlParameter("@Address", student.Address), new SqlParameter("@Phone", student.Phone) }; return SqlHelper.ExecuteNonQuery(connectionString, CommandType.Text, sql, parameters) == 1; } public bool UpdateStudent(Student student) { string sql = "UPDATE StudentInfo SET Name = @Name, Sex = @Sex, Age = @Age, Class = @Class, Address = @Address, Phone = @Phone WHERE StudentID = @StudentID"; SqlParameter[] parameters = new SqlParameter[]{ new SqlParameter("@StudentID", student.StudentID), new SqlParameter("@Name", student.Name), new SqlParameter("@Sex", student.Sex), new SqlParameter("@Age", student.Age), new SqlParameter("@Class", student.Class), new SqlParameter("@Address", student.Address), new SqlParameter("@Phone", student.Phone) }; return SqlHelper.ExecuteNonQuery(connectionString, CommandType.Text, sql, parameters) == 1; } public bool DeleteStudent(string studentID) { string sql = "DELETE FROM StudentInfo WHERE StudentID = @StudentID"; SqlParameter[] parameters = new SqlParameter[]{ new SqlParameter("@StudentID", studentID) }; return SqlHelper.ExecuteNonQuery(connectionString, CommandType.Text, sql, parameters) == 1; } public DataTable SearchStudents(string keyword) { string sql = "SELECT StudentID, Name, Sex, Age, Class, Address, Phone FROM StudentInfo WHERE StudentID LIKE '%' + @Keyword + '%' OR Name LIKE '%' + @Keyword + '%'"; SqlParameter[] parameters = new SqlParameter[]{ new SqlParameter("@Keyword", keyword) }; return SqlHelper.ExecuteDataTable(connectionString, CommandType.Text, sql, parameters); } } ``` 五、总结 通过以上的介绍,我们可以看到,采用C#语言和三层架构开发学生信息管理系统可以提高系统的可维护性、可扩展性、可重用性和可测试性等方面的优势,同时也可以有效地分离业务逻辑和数据访问层,使系统的结构更加清晰和易于维护。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ssq不是上上签

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值