Linux 中power supply软件架构和相关API

一、 概述

电源管理整体上可以分为两个部分,一个是电池监控(fuel gauge),另外一个是充放电管理。这两部分在内核中也是分为两个驱动来管理。fuelgauge驱动的功能主要是负责向上层Android系统提供当前电池的电量和健康信息等等。同时也向charger驱动提供电池的相关信息。charger驱动主要是负责电源线的插拔检测、充电器类型识别和充放电的过程管理等实务。
Power supply class 是为编写供电设备(power supply ,简称PSY)的驱动提供的统一框架
主要功能包括如下部分:
1. 抽象PSY设备共性,向用户空间提供统一的API
2. 为底层PSY驱动的编写提供简单统一的方式,同时封装并且实现公共逻辑,驱动工程师只要专注与硬件细节部分。

设计思路:
PSY driver的主要功能就是向用户空间程序汇总各类状态信息。因此power supply class的思路如下:
PSY driver负责:该PSY设备具有哪些属性,这些属性的值是什么,当属性值发生改变时要通知power supply class
Power supply class负责:将某个PSY设备支持的属性及其value以sysfs的形式提供给用户空间,当属性值改变时以uevent的形式广播给用户空间程序。,另外也会协助处理PSY级联的情况。

软件架构及API接口
Power supply class 位于driver/power目录中,主要由三部分组成:
1. power_supply_core.c 抽象核心数据结构实现公共逻辑
2. power_supply_sysfs.c 实现sysfs和uevent功能
3. power_supply_leds.c 提供PSY设备状态指示的通用实现
核心数据结构:

struct power_supply {
    const struct power_supply_desc *desc;
    char **supplied_to;          //当此电源变化时需要通知的电源模块 name
    size_t num_supplicants;      // supplied_to 数组的大小

    char **supplied_from;        //接收其他电源模块发生变化时的通知 name
    size_t num_supplies;         // supplied_from 数组的大小
    struct device_node *of_node;

    /* Driver private data */
    void *drv_data;

    /* private */
    struct device dev;
//工作队列,相当与一个内核线程,主要思路是该PSY设备状态改变了就启用一个workqueue,查询并通知所有由他发起supplicants 
struct work_struct changed_work;
    struct delayed_work deferred_register_work;
    spinlock_t changed_lock;
    bool changed;
    bool initialized;
    atomic_t use_cnt;
#ifdef CONFIG_THERMAL
    struct thermal_zone_device *tzd;
    struct thermal_cooling_device *tcd;
#endif
#ifdef CONFIG_LEDS_TRIGGERS   //LED相关的操作省略显示。。
#endif
};

其中 power_supply_desc 定义如下:

struct power_supply_desc {
    const char *name;                //电源名称
    enum power_supply_type type;     //电源类型 为电池 USB或者。。
    enum power_supply_property *properties; //该电源的属性
    size_t num_properties;                //该电源属性的数目
    //读取属性值
    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);
    bool no_thermal;                     //设置本电源会不会产生热源
    int use_for_apm;            //For APM emulation, think legacy userspace.
};

向具体的PSY driver提供的API接口
1. PSY的register/unregister API

power_supply_register(struct device *parent,const struct power_supply_desc *desc,
                       const struct power_supply_config *cfg)
power_supply_register_no_ws(struct device *parent,const struct power_supply_desc *desc,const struct power_supply_config *cfg)
power_supply_unregister(struct power_supply *psy)

power_supply_register 和 power_supply_register_no_ws的区别:
power_supply_register_no_ws 没有weakup系统的能力
2. PSY状态发生改变时的API
power_supply_changed(struct power_supply *psy)
当PSY driver 检测到设备某些属性值发生改变时需要调用这个接口,通知我们的
Power supply core ,Power supply core 会有如下动作:
1) 如果该PSY是其他PSY的供电源,调用这些PSY的external_power_changed回调函数,通知他们。
2) 如果配置了CONFIG_LEDS_TRIGGERS,调用power_supply_update_leds更新该PSY有关的LED状态。
3) 发送notifier ,通知那些关心PSY设备状态的drivers.
4) 以统一的格式向用户空间发送uevent
3.其他杂项接口

extern struct power_supply *power_supply_get_by_name(const char *name); 
extern struct power_supply *power_supply_get_by_phandle(struct device_node *np, 
                                                           const char *property); 
extern int power_supply_am_i_supplied(struct power_supply *psy); 
extern int power_supply_set_battery_charged(struct power_supply *psy); 
extern int power_supply_is_system_supplied(void); 
extern int power_supply_powers(struct power_supply *psy, struct device *dev);

power_supply_get_by_name,通过名字获取PSY指针。
power_supply_get_by_phandle,从DTS中,解析出对应的PSY指针。
power_supply_am_i_supplied,查询自己是否由其它PSY供电。
power_supply_set_battery_charged,调用指定PSY的set_charged回调。
power_supply_is_system_supplied,查询系统是否有有效的或者处于online状态的PSY,如果没有,可能为桌面系统。
power_supply_powers,在指定设备(通常是该PSY设备)的sysfs目录(/sys/devices/xxx/)下,创建指定PSY的符号链接(/sys/devices/xxx/powers)。

4.向其它driver提供的用于接收PSY状态改变notifier的API

extern int power_supply_reg_notifier(struct notifier_block *nb); 
extern void power_supply_unreg_notifier(struct notifier_block *nb);

通过notifier注册接口注册notifier之后,系统任何PSY设备的状态发生改变,并调用了power_supply_changed接口,power supply core就是通知notifier的监听者。
5. 向用户空间程序提供的API
power supply class通过两种形式向用户空间提供接口。
1)uevent 以“名字=value”的形式,上报所有property的值
uevent一般会在PSY设备添加到kernel时,或者PSY属性发生改变时(可参考3.3中的介绍)发送。
2)sysfs 如果某个PSY设备具有某个属性,该属性对应的attribute就会体现在sysfs中(一般位于“/sys/class/power_supply/xxx/”中)

发布了27 篇原创文章 · 获赞 18 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_24622489/article/details/81868733