电源排序 API

作者:

Bartosz Golaszewski

简介

此框架旨在抽象 Linux 内核中多个逻辑设备之间共享的复杂加电顺序。

目的是允许使用者获取电源序列提供者公开的电源排序句柄,并委派底层资源的实际请求和控制,并允许提供者在幕后减轻多个用户之间可能存在的冲突。

词汇表

电源排序 API 使用许多特定于子系统的术语

单元

单元是电源序列的离散块。例如,一个单元可以启用一组稳压器,另一个单元可以启用特定的 GPIO。单元可以定义依赖关系,即必须在其本身启用之前启用的其他单元。

目标

目标是一组单元(由“最终”单元及其依赖项组成),使用者在请求电源排序器句柄时按其名称选择。通过依赖关系系统,多个目标可以共享电源序列的相同部分,但忽略不相关的部分。

描述符

由 pwrseq 核心传递给每个使用者的句柄,用作提供者层的入口点。它确保不同用户之间的一致性,并保持引用计数一致。

使用者接口

使用者 API 旨在尽可能简单。有兴趣从电源排序器获取描述符的驱动程序应调用 pwrseq_get(),并在调用 pwrseq_power_up() 之后指定它希望在序列中达到的目标的名称。可以通过调用 pwrseq_put() 释放描述符,使用者可以使用 pwrseq_power_off() 请求关闭其目标的电源。请注意,不能保证 pwrseq_power_off() 会产生任何影响,因为可能存在底层资源的多个用户可能使其保持活动状态。

提供者接口

不可否认,提供者 API 不像使用者的 API 那样简单,但它在灵活性方面弥补了这一点。

每个提供者都可以将加电序列从逻辑上拆分为离散的块(单元)并定义它们的依赖关系。然后,他们可以公开命名目标,使用者可以将这些目标用作他们希望达到的序列中的最终点。

为此,提供者填写一组配置结构,并通过调用 pwrseq_device_register() 向 pwrseq 子系统注册。

动态使用者匹配

pwrseq 与其他 Linux 内核提供者的主要区别在于动态匹配使用者和提供者的机制。每个电源序列提供者驱动程序都必须实现 match() 回调,并在向子系统注册时将其传递给 pwrseq 核心。

当客户端请求排序器句柄时,核心将为每个已注册的提供者调用此回调,并使其灵活地确定提议的客户端设备是否确实是其使用者。例如:如果提供者绑定到代表芯片组电源管理单元的设备树节点,并且使用者驱动程序控制其模块之一,则提供者驱动程序可以解析设备树中相关的稳压器电源属性,并查看它们是否从 PMU 引导到使用者。

API 参考

struct pwrseq_unit_data

单个电源排序单元的配置。

定义:

struct pwrseq_unit_data {
    const char *name;
    const struct pwrseq_unit_data **deps;
    pwrseq_power_state_func enable;
    pwrseq_power_state_func disable;
};

成员

name

单元的名称。

deps

必须在此单元之前启用并在其之后禁用的单元,顺序与此数组中的顺序相同。必须以 NULL 结尾。

enable

回调运行此单元提供的加电序列的一部分。

disable

回调运行此单元提供的断电序列的一部分。

struct pwrseq_target_data

电源排序目标的配置。

定义:

struct pwrseq_target_data {
    const char *name;
    const struct pwrseq_unit_data *unit;
    pwrseq_power_state_func post_enable;
};

成员

name

目标的名称。

unit

此目标必须达到的最终单元,才能被视为已启用。

post_enable

在启用目标单元之后,释放状态锁后运行的回调。它对于实现启动延迟而不会阻止其他用户使用相同的电源排序器来加电非常有用。

struct pwrseq_config

用于注册新提供者的配置。

定义:

struct pwrseq_config {
    struct device *parent;
    struct module *owner;
    void *drvdata;
    pwrseq_match_func match;
    const struct pwrseq_target_data **targets;
};

成员

parent

排序器的父设备。必须设置。

owner

提供此设备的模块。

drvdata

私有驱动程序数据。

match

用于将使用者设备与排序器匹配的提供者回调。

targets

此电源排序器的目标数组。必须以 NULL 结尾。

struct pwrseq_device *pwrseq_device_register(const struct pwrseq_config *config)

注册新的电源排序器。

参数

const struct pwrseq_config *config

新电源排序设备的配置。

描述

config 结构仅在调用期间使用,并且可以在函数返回后释放。 config 结构必须具有父设备以及 match() 回调和至少一个目标集。

返回

返回新 pwrseq 设备的地址,如果失败,则返回 ERR_PTR()

void pwrseq_device_unregister(struct pwrseq_device *pwrseq)

注销电源排序器。

参数

struct pwrseq_device *pwrseq

要注销的电源排序器。

struct pwrseq_device *devm_pwrseq_device_register(struct device *dev, const struct pwrseq_config *config)

pwrseq_device_register() 的托管变体。

参数

struct device *dev

管理设备。

const struct pwrseq_config *config

新电源排序设备的配置。

返回

返回新 pwrseq 设备的地址,如果失败,则返回 ERR_PTR()

void *pwrseq_device_get_drvdata(struct pwrseq_device *pwrseq)

获取与此排序器关联的驱动程序私有数据。

参数

struct pwrseq_device *pwrseq

电源排序器对象。

返回

私有驱动程序数据的地址。

struct pwrseq_desc *pwrseq_get(struct device *dev, const char *target)

获取与此设备关联的电源排序器。

参数

struct device *dev

要获取排序器的设备。

const char *target

此设备要达到的排序器公开的目标的名称。

返回

供使用者驱动程序使用的新电源排序器描述符,如果失败,则返回 ERR_PTR()

void pwrseq_put(struct pwrseq_desc *desc)

释放电源排序器描述符。

参数

struct pwrseq_desc *desc

要释放的描述符。

struct pwrseq_desc *devm_pwrseq_get(struct device *dev, const char *target)

pwrseq_get() 的托管变体。

参数

struct device *dev

用于获取排序器的设备,该设备也管理其生命周期。

const char *target

此设备要达到的排序器公开的目标的名称。

返回

供使用者驱动程序使用的新电源排序器描述符,如果失败,则返回 ERR_PTR()

int pwrseq_power_on(struct pwrseq_desc *desc)

代表使用者设备发出加电请求。

参数

struct pwrseq_desc *desc

引用电源排序器的描述符。

描述

此函数告诉电源排序器使用者想要加电。排序器可能已经为设备加电,在这种情况下,函数返回 0。如果加电序列已经在进行中,该函数将阻塞直到完成并返回 0。如果这是第一个请求,则设备将被加电。

返回

成功时返回 0,失败时返回负错误编号。

int pwrseq_power_off(struct pwrseq_desc *desc)

代表使用者设备发出断电请求。

参数

struct pwrseq_desc *desc

引用电源排序器的描述符。

描述

这会撤消 pwrseq_power_on() 的效果。它代表使用者发出断电请求,当最后剩余的用户这样做时,将启动断电序列。如果某个断电序列正在进行中,该函数将阻塞直到完成然后返回。

返回

成功时返回 0,失败时返回负错误编号。