2. 内核PWM子系统核心数据结构

PWM子系统的核心由三个紧密关联的数据结构构成:struct pwm_chip(控制器抽象)、struct pwm_device(通道抽象)和 struct pwm_ops(操作函数集)。理解这三者的定义、字段含义及关联关系,是分析PWM控制器注册耗时的前提。

PWM子系统核心数据结构关系 struct pwm_chip • dev: struct device * • npwm: unsigned int • pwms: struct pwm_device * • ops: const struct pwm_ops * • of_xlate: of_xlate_func struct pwm_device • chip: struct pwm_chip * • pwm: unsigned int • period: unsigned int • duty_cycle: unsigned int • enabled: bool struct pwm_ops • request() • free() • config() • enable() / disable() • apply() 1:N 1:1 反向指针 关联关系说明 ① pwm_chip.pwms 指向一个 pwm_device 数组,长度为 npwm ② pwm_device.chip 反向指向所属的 pwm_chip,形成双向引用 ③ pwm_chip.ops 指向静态定义的 pwm_ops,同一芯片所有通道共享操作函数 ④ of_xlate 负责将设备树中的 PWM 说明符解析为 pwm_device 索引 ⑤ 注册耗时主要发生在 pwm_device 数组分配、of_xlate 注册和 sysfs 创建

2.1 struct pwm_chip —— PWM控制器抽象

struct pwm_chip 代表一个物理PWM控制器,是子系统中最顶层的结构。每个PWM控制器驱动在注册时,必须分配并填充该结构,然后调用 pwmchip_add() 或 pwmchip_add_with_polarity() 将其加入内核。

字段类型作用说明
devstruct device *关联的Linux设备模型节点,用于电源管理、sysfs 和设备树绑定
npwmunsigned int该控制器支持的PWM通道数量,决定 pwm_device 数组大小
pwmsstruct pwm_device *指向 pwm_device 数组的指针,由 PWM 核心在注册时分配
opsconst struct pwm_ops *操作函数集指针,所有通道共享同一套底层硬件操作
of_xlateof_xlate_func设备树解析回调,将 <pwm-specifier> 映射到通道索引
of_pwm_n_cellsint设备树PWM说明符的 cell 数量,通常为 2 或 3
baseint全局PWM编号的起始值(旧API,新驱动建议设为 -1 动态分配)
can_sleepbool标记该控制器的操作是否可能睡眠(影响原子上下文调用)

性能关注点: npwm 字段直接决定了 pwm_device 数组的分配大小。对于具有大量通道(如 8/16 路)的控制器,内存分配和初始化耗时不可忽略。部分 SoC 的 PWM 控制器在注册阶段会遍历所有通道进行硬件状态同步,进一步增加耗时。

2.2 struct pwm_device —— PWM通道抽象

struct pwm_device 代表一个独立的PWM输出通道,是消费者(consumer)直接操作的对象。每个通道对应一个物理PWM输出引脚。

字段类型作用说明
chipstruct pwm_chip *反向指针,指向所属的 PWM 控制器
pwmunsigned int通道在芯片内的索引(0 ~ npwm-1)
periodunsigned int当前配置的周期(单位:ns)
duty_cycleunsigned int当前配置的占空比(单位:ns)
polarityenum pwm_polarity输出极性:PWM_POLARITY_NORMAL 或 PWM_POLARITY_INVERSED
enabledbool通道是否已使能
labelconst char *使用者名称,用于调试和 sysfs 展示
flagsunsigned long状态标志位,如 PWMF_REQUESTED、PWMF_EXPORTED 等

设计意图: pwm_device 将硬件通道状态缓存到软件层面,避免每次操作都读取硬件寄存器。在注册阶段,核心会为每个通道初始化默认状态(period=0, duty_cycle=0, enabled=false),这部分循环在 npwm 较大时会产生可测量的延迟。

2.3 struct pwm_ops —— 硬件操作函数集

struct pwm_ops 定义了驱动层需要实现的硬件操作回调。PWM核心层通过 pwm_chip.ops 调用这些函数,完成对底层硬件的实际控制。

回调函数原型调用时机与作用
requestint (*request)(struct pwm_chip *chip, struct pwm_device *pwm)通道被申请时调用,用于时钟使能、引脚复用配置
freevoid (*free)(struct pwm_chip *chip, struct pwm_device *pwm)通道被释放时调用,用于关闭时钟、恢复引脚
configint (*config)(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns)配置周期和占空比(旧API,新驱动推荐使用 apply)
enableint (*enable)(struct pwm_chip *chip, struct pwm_device *pwm)使能PWM输出,启动波形生成
disablevoid (*disable)(struct pwm_chip *chip, struct pwm_device *pwm)禁用PWM输出,停止波形
applyint (*apply)(struct pwm_chip *chip, struct pwm_device *pwm, const struct pwm_state *state)原子化应用新状态(新API,一次性设置 period/duty/polarity/enable)
get_statevoid (*get_state)(struct pwm_chip *chip, struct pwm_device *pwm, struct pwm_state *state)读取硬件当前状态,用于状态同步和恢复
set_polarityint (*set_polarity)(struct pwm_chip *chip, struct pwm_device *pwm, enum pwm_polarity polarity)设置输出极性(旧API,新驱动合并到 apply 中)

注册阶段的关键回调: get_state 回调在 pwmchip_add() 过程中会被调用,用于读取硬件当前状态并同步到 pwm_device 的缓存中。如果该回调实现中包含了慢速寄存器读取(如通过 I2C/SPI 访问 PWM 控制器),将显著增加注册耗时。这是启动阶段优化的重点之一。

2.4 三者关联关系详解

三个数据结构通过指针形成双向引用网络,理解这个网络是分析注册流程的基础:

  1. 控制器到通道(1:N): pwm_chip.pwms 指向一个连续分配的 pwm_device 数组,数组长度为 npwm。每个元素代表一个物理通道。
  2. 通道到控制器(1:1): 每个 pwm_device.chip 指针反向指向其所属的 pwm_chip,使得在通道操作中可以快速获取控制器上下文。
  3. 控制器到操作集(1:1): pwm_chip.ops 指向一个静态定义的 pwm_ops 实例,同一芯片的所有通道共享同一套操作函数。
  4. 设备树解析桥梁: pwm_chip.of_xlate 回调负责将设备树中的 <&pwm-controller channel flags> 解析为具体的 pwm_device 指针。
pwmchip_add() 注册流程中的数据交互 1. 分配 pwm_device 数组 2. 初始化每个通道状态 3. 调用 get_state 同步 4. 注册到全局链表 + sysfs 注册过程中数据结构的交互细节 ① pwmchip_add() 根据 chip->npwm 调用 kcalloc 分配 pwm_device 数组,赋值给 chip->pwms ② 遍历每个 pwm_device,设置 chip 反向指针、初始化 flags=0、period=0、duty_cycle=0 ③ 如果 ops->get_state 存在,调用它读取硬件状态并更新 pwm_device 的缓存字段 ④ 将 chip 加入全局 pwm_chips 链表,创建 /sys/class/pwm/pwmchipN 目录及属性文件 ⑤ 耗时热点:步骤①的内存分配 + 步骤②的循环初始化 + 步骤③的硬件读取 + 步骤④的 sysfs 创建

2.5 数据结构关系总结

关系对类型方向关键字段注册阶段影响
chip → device1:N 聚合chip.pwms → device[]npwm 决定数组大小npwm 越大,内存分配和初始化循环耗时越长
device → chip1:1 反向引用device.chip → chipchip 指针注册时设置,无额外耗时
chip → ops1:1 组合chip.ops → opsops 指针注册时通过 ops->get_state 产生硬件访问延迟
device → state1:1 缓存device.period/duty_cycle/enabled状态缓存字段get_state 回调负责填充,慢速总线场景耗时显著