电源排序 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,失败时返回负错误编号。