在 Linux 内核中,Power Supply Framework是用于描述和管理电池、充电器、外部电源的一套标准子系统。
- 1. 抽象 PSY 设备的共性,向用户空间提供统一的 API。
- 2. 为底层 PSY 驱动的编写,提供简单、统一的方式。同时封装并实现公共逻辑,驱动工程师只需把精力集中在和硬件相关的部分即可。
一、Power Supply Framework 在内核中负责什么?
Power Supply Framework 的核心目标只有两个:
- • 抽象 power supply(PSY)设备的共性,并向用户空间提供统一接口
- • 为电池/充电相关驱动提供一致、低成本的接入框架,并封装公共逻辑
它并不关心具体芯片型号,也不直接实现充电策略,而是提供一个标准化的“电源状态模型”。
二、Power Supply Framework 在内核中的位置
- • Battery(电池 / Fuel Gauge)
最终,这些设备都会统一出现在:/sys/class/power_supply/
三、Power Supply Class 的整体架构
Power Supply 子系统主要由三部分组成:
路径:drivers/power/power_supply_core.c
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);voidpower_supply_changed(struct power_supply *psy);intpower_supply_am_i_supplied(struct power_supply *psy);intpower_supply_set_battery_charged(struct power_supply *psy);intpower_supply_set_current_limit(struct power_supply *psy, int limit);intpower_supply_set_online(struct power_supply *psy, bool enable);intpower_supply_set_present(struct power_supply *psy, bool enable);intpower_supply_set_scope(struct power_supply *psy, int scope);intpower_supply_set_charge_type(struct power_supply *psy, int type);intpower_supply_set_supply_type(struct power_supply *psy,enum power_supply_type supply_type);intpower_supply_is_system_supplied(void);intpower_supply_register(struct device *parent,struct power_supply *psy);voidpower_supply_unregister(struct power_supply *psy);intpower_supply_powers(struct power_supply *psy, struct device *dev);
上面的 register 和 unregister 接口是用来注册和反注册 power supply 设备的接口,当该 power supply 设备中有监测信息变化时,使用 power_supply_changed 接口用来通知上层,这种通知机制采用的是 netlink socket 接口来实现的,具体实现参见该函数体。最终函数会通过netlink socket发送出来一系列的字符串,比如 POWER_SUPPLY_NAME=battery,当上层daemon服务程序收到该提醒后,就会去读取相应驱动提供的 sysfs 接口文件来获取相应的信息。
路径:drivers/power/power_supply_sysfs.c
- • 创建
/sys/class/power_supply/*
enum power_supply_property *properties;size_t num_properties;
路径:drivers/power/power_supply_leds.c
voidpower_supply_update_leds(struct power_supply *psy);intpower_supply_create_triggers(struct power_supply *psy);voidpower_supply_remove_triggers(struct power_supply *psy);
这几个 API 分别就是创建和删除 led_trigger,以及触发 LED。
struct power_supply 用于抽象一个 PSY 设备实例:
- • 管理 notifier、thermal、led 等资源
它代表的是运行时实体,通常由框架维护,驱动不直接操作其内部成员。
2. struct power_supply_desc(驱动最核心部分) power_supply_desc 用于描述一个 PSY 设备“对外提供什么能力”。
- • PSY 类型(battery / usb / mains 等)
3. power_supply_battery_info 用于描述静态电池参数(容量、内阻、设计电压等),推荐用于 battery/fuel gauge 驱动,避免将固定参数散落在代码中。
写至此处,也该画上句号了。常言道,程序员的世界由0和1构成,但我逐渐意识到——更多的时候,我们面对的是“咦?这怎么又出错了?”感谢您的阅读,希望我的些许探索,能够助您避开一些陷阱,更接近事实的真相。