找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2280

积分

0

好友

308

主题
发表于 4 天前 | 查看: 15| 回复: 0

在 Linux 内核中,Power Supply Framework 是一套用于描述和管理电池、充电器、外部电源等设备的标准化子系统。它的核心作用可以归纳为两点:

  1. 抽象 PSY 设备的共性,向用户空间提供统一的 API。
  2. 为底层 PSY 驱动的编写,提供简单、统一的方式。同时封装并实现公共逻辑,驱动工程师只需把精力集中在和硬件相关的部分即可。

Power Supply Framework 架构图

一、Power Supply Framework 在内核中的职责

Power Supply Framework 的核心目标只有两个:

  • 抽象 power supply(PSY)设备的共性,并向用户空间提供统一接口
  • 为电池/充电相关驱动提供一致、低成本的接入框架,并封装公共逻辑

它并不关心具体芯片型号,也不直接实现充电策略,而是提供一个标准化的“电源状态模型”。

二、Power Supply Framework 在内核中的位置

源码目录:drivers/power/

典型的 PSY 设备包括:

  • Battery(电池 / Fuel Gauge)
  • USB / AC / DC(外部供电)
  • Charger(充电 IC)
  • Charger Manager(策略层)

最终,这些设备都会统一出现在:/sys/class/power_supply/ 目录下,这正是它通过 sysfs 向用户空间暴露的统一接口。

三、Power Supply Class 的整体架构

Power Supply 子系统主要由三部分组成:

1)Power Supply Core

路径drivers/power/power_supply_core.c

职责

  • 定义核心数据结构
  • 管理 PSY 设备生命周期
  • 处理属性变化
  • 触发 notifier 与 uevent

核心数据结构 struct power_supply 用于抽象一个 PSY 设备实例:

struct power_supply {
     const char *name;
     enum power_supply_type type;
     enum power_supply_property *properties;
     size_t num_properties;
     char **supplied_to;
     size_t num_supplicants; 
     char **supplied_from;
     size_t num_supplies;
#ifdef CONFIG_OF
     struct device_node *of_node;
#endif
     int (*get_property)(struct power_supply *psy,
                 enum power_supply_property psp,
                 union power_supply_propval *val);
     int (*set_property)(struct power_supply *psy,
                 enum power_supply_property psp,
                 const union power_supply_propval *val);
     int (*property_is_writeable)(struct power_supply *psy,
                      enum power_supply_property psp);
     void (*external_power_changed)(struct power_supply *psy);
     void (*set_charged)(struct power_supply *psy);

     /* For APM emulation, think legacy userspace. */
     int use_for_apm;

     /* private */
     struct device *dev;
     struct work_struct changed_work;
     spinlock_t changed_lock;
     bool changed;
     struct wake_lock work_wake_lock;
#ifdef CONFIG_THERMAL
     struct thermal_zone_device *tzd;
     struct thermal_cooling_device *tcd;
#endif

#ifdef CONFIG_LEDS_TRIGGERS
     struct led_trigger *charging_full_trig;
     char *charging_full_trig_name;
     struct led_trigger *charging_trig;
     char *charging_trig_name;
     struct led_trigger *full_trig;
     char *full_trig_name;
     struct led_trigger *online_trig;
     char *online_trig_name;
     struct led_trigger *charging_blink_full_solid_trig;
     char *charging_blink_full_solid_trig_name;
#endif
};

power_supply向外提供了接口以供具体驱动来使用,主要接口如下:

struct power_supply *power_supply_get_by_name(const char *name);
void power_supply_changed(struct power_supply *psy);
int power_supply_am_i_supplied(struct power_supply *psy);
int power_supply_set_battery_charged(struct power_supply *psy);
int power_supply_set_current_limit(struct power_supply *psy, int limit);
int power_supply_set_online(struct power_supply *psy, bool enable);
int power_supply_set_present(struct power_supply *psy, bool enable);
int power_supply_set_scope(struct power_supply *psy, int scope);
int power_supply_set_charge_type(struct power_supply *psy, int type);
int power_supply_set_supply_type(struct power_supply *psy, enum power_supply_type supply_type);
int power_supply_is_system_supplied(void);
int power_supply_register(struct device *parent, struct power_supply *psy);
void power_supply_unregister(struct power_supply *psy);
int power_supply_powers(struct power_supply *psy, struct device *dev);

上面的 registerunregister 接口是用来注册和反注册 power supply 设备的接口。当该 power supply 设备中有监测信息变化时,使用 power_supply_changed 接口来通知上层。

这种通知机制采用的是 netlink socket 接口来实现的。具体实现参见该函数体。最终函数会通过netlink socket发送一系列事件字符串,例如 POWER_SUPPLY_NAME=battery。当上层的 daemon 服务程序收到该事件后,就会去读取相应驱动提供的 sysfs 接口文件来获取最新的状态信息。

2)Power Supply Sysfs

路径drivers/power/power_supply_sysfs.c

职责

  • 创建 /sys/class/power_supply/*
  • 实现属性读写
  • 生成 uevent(change 事件)

struct power_supply_desc 中的以下两个字段决定了向用户空间暴露哪些属性:

enum power_supply_property *properties;
size_t num_properties;

3)Power Supply LEDs

路径drivers/power/power_supply_leds.c

职责

  • 基于 Linux LED class
  • 提供充电、满电、在线状态的通用指示机制

主要API:

void power_supply_update_leds(struct power_supply *psy);
int power_supply_create_triggers(struct power_supply *psy);
void power_supply_remove_triggers(struct power_supply *psy);

这几个 API 分别用于创建和删除 led_trigger,以及触发 LED 状态更新。

四、核心数据结构解析

1. struct power_supply

struct power_supply 用于抽象一个 PSY 设备实例:

  • 内嵌 struct device
  • 维护状态变化的 workqueue
  • 管理 notifierthermalled 等资源

它代表的是运行时实体,通常由框架维护,驱动不直接操作其内部成员。

2. struct power_supply_desc(驱动最核心部分)

power_supply_desc 用于描述一个 PSY 设备“对外提供什么能力”。

关键字段包括:

  • PSY 名称
  • PSY 类型(battery / usb / mains 等)
  • 支持的属性列表
  • 属性的 get / set 回调

驱动开发者主要通过实现这个描述符来接入框架。

3. power_supply_battery_info

用于描述静态电池参数(容量、内阻、设计电压等),推荐用于 battery/fuel gauge 驱动,避免将固定参数散落在代码中。


通过本文的介绍,希望能帮助你更清晰地理解 Linux 内核中 Power Supply Framework 的架构与工作原理。掌握这套框架,对于开发与电源、电池相关的嵌入式驱动至关重要。如果你想深入探讨更多内核或系统底层知识,欢迎在 云栈社区网络/系统板块基础 & 综合 板块与其他开发者交流学习。




上一篇:OpenTelemetry+Jaeger落地Go微服务全链路追踪实战
下一篇:2025 InfoQ技术大会回顾:讲师企业4家上市15家融资,技术驱动资本新周期
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-24 02:48 , Processed in 0.389099 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表