power supply框架

概述

对于便携式设备,如手机或者pad来说,battery都是必不可少的一个组成部分。kernel中为了方便对battery的管理,专门提供了power supply framework。battery管理我觉得可以分开为两个部分,一个是电池监控(fuelgauge),另一个是充放电管理(charger),所以我们在内核中也是把它分成了两个驱动来管理。fuelgauge驱动主要是负责向上层android系统提供当前电池的电量以及健康状态信息等等,另外除了这个以外,它也向charger驱动提供电池的相关信息;charger驱动主要负责电源线的插拔检测,以及充放电的过程管理。对于battery管理,硬件上有电量计IC和充放电IC,当然有些厂家为了成本的考虑,也会把电量计和充放电功能集成到一个IC上,更有甚者,可能会把PMU功能也集成在一块硅面上,actions就有相关方案。

power supply 框架

内核中有power manager(PM)子系统和power supply子系统,这两者负责的内容是不同的,PM子系统是系统电源管理策略的解决方案,更多的关注功耗控制。

1.编译选项

power supply framework所在的内核目录如下:

 kernel/drivers/power

首先来看一下power目录下的Makefile和Kconfig:

Makefile:

 1 ccflags-$(CONFIG_POWER_SUPPLY_DEBUG) := -DDEBUG

  2 

  3 power_supply-y              := power_supply_core.o

  4 power_supply-$(CONFIG_SYSFS)        += power_supply_sysfs.o

  5 power_supply-$(CONFIG_LEDS_TRIGGERS)    += power_supply_leds.o    

  6 

  7 obj-$(CONFIG_POWER_SUPPLY)  += power_supply.o

Kconfig:

  1 menuconfig POWER_SUPPLY

  2     bool "Power supply class support"

  3     help

  4       Say Y here to enable power supply class support. This allows

  5       power supply (batteries, AC, USB) monitoring by userspace

  6       via sysfs and uevent (if available) and/or APM kernel interface

  7       (if selected below).

由上面的编译选项可以看出,要想使能power supply功能,我们需要在kernel defconfig中定义CONFIG_POWER_SUPPLY功能,主要编译的文件是power_supply_core.c,如果内核中还配置了SYSFS和LEDS_TRIGGERS,那么power_supply_sysfs.c和power_supply_leds.c也会一起编译到内核中。

2.power supply core

内核抽象了一个供电设备为struct power_supply,定义在kernel/include/linux/power_supply.h头文件中:

235 struct power_supply {

236     const char *name;

237     enum power_supply_type type;

238     enum power_supply_property *properties;

239     size_t num_properties;

240 

241     char **supplied_to;

242     size_t num_supplicants;

243 

244     char **supplied_from;

245     size_t num_supplies;

246 #ifdef CONFIG_OF

247     struct device_node *of_node;

248 #endif

249 

250     int (*get_property)(struct power_supply *psy,

251                 enum power_supply_property psp,

252                 union power_supply_propval *val);

253     int (*set_property)(struct power_supply *psy,

254                 enum power_supply_property psp,

255                 const union power_supply_propval *val);

256     int (*property_is_writeable)(struct power_supply *psy,

257                      enum power_supply_property psp);

258     void (*external_power_changed)(struct power_supply *psy);

259     void (*set_charged)(struct power_supply *psy);

260 

261     /* For APM emulation, think legacy userspace. */

262     int use_for_apm;

263 

264     /* private */

265     struct device *dev;

266     struct work_struct changed_work;

267     spinlock_t changed_lock;

268     bool changed;

269     struct wake_lock work_wake_lock;

270 #ifdef CONFIG_THERMAL

271     struct thermal_zone_device *tzd;

272     struct thermal_cooling_device *tcd;

273 #endif

274 

275 #ifdef CONFIG_LEDS_TRIGGERS

276     struct led_trigger *charging_full_trig;

277     char *charging_full_trig_name;

278     struct led_trigger *charging_trig;

279     char *charging_trig_name;

280     struct led_trigger *full_trig;

281     char *full_trig_name;

282     struct led_trigger *online_trig;

283     char *online_trig_name;

284     struct led_trigger *charging_blink_full_solid_trig;

285     char *charging_blink_full_solid_trig_name;

286 #endif

287 };

核心层代码实现了一个power_supply_class,用于抽象power_supply设备,这样有助于设备模型的统一,并且针对该class,可以在core中做统一处理,也方便于对同种类型设备的管理。

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

309 extern struct power_supply *power_supply_get_by_name(const char *name);

310 extern void power_supply_changed(struct power_supply *psy);

311 extern int power_supply_am_i_supplied(struct power_supply *psy);

312 extern int power_supply_set_battery_charged(struct power_supply *psy);

313 extern int power_supply_set_current_limit(struct power_supply *psy, int limit);

314 extern int power_supply_set_online(struct power_supply *psy, bool enable);

315 extern int power_supply_set_present(struct power_supply *psy, bool enable);

316 extern int power_supply_set_scope(struct power_supply *psy, int scope);

317 extern int power_supply_set_charge_type(struct power_supply *psy, int type);

318 extern int power_supply_set_supply_type(struct power_supply *psy,

319                     enum power_supply_type supply_type);

320 extern int power_supply_is_system_supplied(void);

321 extern int power_supply_register(struct device *parent,

322                  struct power_supply *psy);

323 extern void power_supply_unregister(struct power_supply *psy);

324 extern int power_supply_powers(struct power_supply *psy, struct device *dev);

上面的register和unregister接口是用来注册和反注册power supply设备的接口,当该power supply设备中有监测信息变化时,使用 power_supply_changed接口用来通知上层的android服务,这种通知机制采用的是netlink socket接口来实现的,具体实现参见该函数体。最终函数会通过netlink socket发送出来一系列的字符串,比如“POWER_SUPPLY_NAME=battery”,当上层daemon服务程序收到该提醒后,就会去读取相应驱动提供的sysfs接口文件来获取相应的信息。

3.power supply sysfs

power supply子系统定义了一系列的sysfs文件,这样做也是为了power supply设备的标准化。虽然power_supply_class定义的一系列sysfs文件,但是它们并不全部显示出来,而是通过不同的struct power_supply结构体来决定显示哪些sysfs节点。

238     enum power_supply_property *properties;

239     size_t num_properties;

这两个成员是用来定义特定power supply设备所具有的属性的,也就是对应着sysfs节点文件。另外power supply设备还要定义get_property和set_property回调函数,用来把相关的设备信息传递给上层。

4.power supply led

对于power supply led功能,比较简单,framework只负责提供几个API以供其他驱动调用:

 31 extern void power_supply_update_leds(struct power_supply *psy);

 32 extern int power_supply_create_triggers(struct power_supply *psy);

 33 extern void power_supply_remove_triggers(struct power_supply *psy);

从函数名字可以看出来,这几个API分别就是创建和删除led_trigger,以及触发led。这几个API的实现基于内核LED框架,我们在power_supply驱动中如果要使能LED显示功能,首先需要定义power_supply结构体中的一系列LED触发器的名字,然后调用power_supply_create_triggers来创建相应名称的led_trigger。那么这个trigger name该如何定义呢?

从led子系统的相关实现来说起,led子系统中把led抽象成了两种设备,分别是led设备和led trigger设备,led设备主要关注于如何操作LED使其亮或者灭,而led trigger顾名思义就是触发器,这两种设备是相互关联的,一个led设备可以对应多个触发器,一个led trigger设备也可以对应多个led设备。在power supply中我们仅仅创建了一个led trigger,那么要想将它和led设备关联起来,就需要一个led设备,并且该led的设备的default trigger名字要设置为该power supply相应的名字,由此在注册led trigger时才能将两者关联起来。那么在接下来的对led trigger的控制操作中,才会最终操作到对应的led设备上去。

fuelgauge & charger driver

通过对上面power supply的介绍,可以对内核中的框架用有个大致的了解,那么如何去编写fuelgauge和charger驱动呢?

其实内核只是提供了一个框架,我们通过相关的API接口,可以生成相同的sysfs文件,内核仅仅是定义了这些统一的模型以及一些标准的功能,那对于单个驱动,我们更关注的是如何驱动特定硬件来实现这些标准的功能。虽然各个环境都有不同,但是不管每个环境的硬件是什么,我们都需要根据datasheet,把硬件的功能封装起来,并最终抽象到一个power supply结构体中,然后注册到内核框架层中,由此来完成驱动。

  • 0
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`power_supply_get_property`、`power_supply_set_property`、`power_supply_property_is_writeable` 是 Linux 内核中与电源管理相关的函数,主要用于获取和设置电源供应设备的属性值。下面分别对这三个函数进行详细说明: 1. `power_supply_get_property` 函数 `power_supply_get_property` 函数用于获取电源供应设备的属性值。其函数原型为: ``` int power_supply_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val); ``` 其中,`psy` 是指向 `struct power_supply` 结构体的指针,用于指定要获取属性的电源供应设备;`psp` 是一个枚举类型的值,用于指定要获取的属性名称;`val` 是一个 `union` 类型的变量,用于存储获取到的属性值。 使用 `power_supply_get_property` 函数时,需要先定义一个 `struct power_supply` 类型的变量,并将其指针传递给函数。同时需要指定要获取的属性名称,可以通过 `enum power_supply_property` 枚举类型来指定。获取到的属性值会被存储在 `union power_supply_propval` 变量中。这个变量包含了多种类型的属性值,可以根据属性的类型来获取相应的值。 2. `power_supply_set_property` 函数 `power_supply_set_property` 函数用于设置电源供应设备的属性值。其函数原型为: ``` int power_supply_set_property(struct power_supply *psy, enum power_supply_property psp, const union power_supply_propval *val); ``` 其中,`psy` 是指向 `struct power_supply` 结构体的指针,用于指定要设置属性的电源供应设备;`psp` 是一个枚举类型的值,用于指定要设置的属性名称;`val` 是一个 `const union` 类型的指针,用于指定要设置的属性值。 使用 `power_supply_set_property` 函数时,需要先定义一个 `struct power_supply` 类型的变量,并将其指针传递给函数。同时需要指定要设置的属性名称和属性值,可以通过 `enum power_supply_property` 枚举类型和 `union power_supply_propval` 变量来指定。需要注意的是,某些属性可能是只读的,不能通过这个函数来设置属性值。 3. `power_supply_property_is_writeable` 函数 `power_supply_property_is_writeable` 函数用于判断电源供应设备的某个属性是否可写。其函数原型为: ``` int power_supply_property_is_writeable(struct power_supply *psy, enum power_supply_property psp); ``` 其中,`psy` 是指向 `struct power_supply` 结构体的指针,用于指定要查询的电源供应设备;`psp` 是一个枚举类型的值,用于指定要查询的属性名称。 使用 `power_supply_property_is_writeable` 函数时,需要先定义一个 `struct power_supply` 类型的变量,并将其指针传递给函数。同时需要指定要查询的属性名称,可以通过 `enum power_supply_property` 枚举类型来指定。函数会返回一个整型值,表示该属性是否可写。如果可写,则返回 1,否则返回 0。 这三个函数是 Linux 内核中电源管理的重要函数,可以用于获取和设置电源供应设备的属性值,帮助开发人员进行电源管理的相关工作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值