Linux系统下电池驱动研究

Linux系统下电池驱动一般有两种方式:

1.外挂PMU芯片,通过I2C接口读取相应的数据;

2.通过芯片 ADC接口获取电量;

本文谈的是第二点。

当我们要写一个锂电池的驱动程序的时候,首先要知道就是当驱动挂载到内核上的时候,内核是怎么知道驱动中的信息的,如何来控制驱动。内核提供给电源驱动的接口就是一个结构体power_supply,struct power_supply 在文件 include\linux\power_supply.h 中:

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;

int (*get_property)(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val);
void (*external_power_changed)(struct power_supply *psy);

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

/* private */
struct device *dev;
struct work_struct changed_work;

#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;
#endif
};

每种属性都有特殊的含义和单位,由于这些属性普遍适用于各种电源,但是实际应用中有些电源可能无法提供某些属性,所以这些属性驱动可以不提供。
电源类是可扩展的,允许驱动程序定义其自身需要的属性,抛弃不需要的属性。
它还集成了LED框架,用来表示电池充电/完全充电状态和AC / USB电源线上状态。

一般我们需要填充的是这几个:

struct power_supply bat_am7x = {
.name = "am7x-battery", //名称 对应于/sys/class/power_supply/xxx文件夹
.type = POWER_SUPPLY_TYPE_BATTERY,//类型:电池
.properties = am7x_bat_main_props,//属性的类别,如电池状态、电量、温度
.num_properties = ARRAY_SIZE(am7x_bat_main_props),//属性的数量
.get_property = am7x_bat_get_property,//获取属性的回调函数
.use_for_apm = 1,
};

err = power_supply_register(&pdev->dev,am7x_battery_info->bat);//将电池注册 power_supply_register调用内核提供的函数device_create和power_supply_create_attrs来实现电池的注册。 注册完成后生成sys/class/power_supply/电池驱动名称,函数在drivers\power\power_supply_core.c 中

使用方法举例:

# cd /sys/class/power_supply/你的电池battery/

# cat type status health present technology capacity

Battery

Charging

Good

1

Li-ion

50

这些宏已经定义过:

enum { // 对应 POWER_SUPPLY_PROP_STATUS

POWER_SUPPLY_STATUS_UNKNOWN = 0,

POWER_SUPPLY_STATUS_CHARGING,

POWER_SUPPLY_STATUS_DISCHARGING,

POWER_SUPPLY_STATUS_NOT_CHARGING,

POWER_SUPPLY_STATUS_FULL,

};

enum { // 对应 POWER_SUPPLY_PROP_CHARGE_TYPE

POWER_SUPPLY_CHARGE_TYPE_UNKNOWN = 0,

POWER_SUPPLY_CHARGE_TYPE_NONE,

POWER_SUPPLY_CHARGE_TYPE_TRICKLE,

POWER_SUPPLY_CHARGE_TYPE_FAST,

};

enum { // 对应 POWER_SUPPLY_PROP_HEALTH

POWER_SUPPLY_HEALTH_UNKNOWN = 0,

POWER_SUPPLY_HEALTH_GOOD,

POWER_SUPPLY_HEALTH_OVERHEAT,

POWER_SUPPLY_HEALTH_DEAD,

POWER_SUPPLY_HEALTH_OVERVOLTAGE,

POWER_SUPPLY_HEALTH_UNSPEC_FAILURE,

POWER_SUPPLY_HEALTH_COLD,

};

enum { // 对应 POWER_SUPPLY_PROP_TECHNOLOGY

POWER_SUPPLY_TECHNOLOGY_UNKNOWN = 0,

POWER_SUPPLY_TECHNOLOGY_NiMH,

POWER_SUPPLY_TECHNOLOGY_LION,

POWER_SUPPLY_TECHNOLOGY_LIPO,

POWER_SUPPLY_TECHNOLOGY_LiFe,

POWER_SUPPLY_TECHNOLOGY_NiCd,

POWER_SUPPLY_TECHNOLOGY_LiMn,

};

enum { // 对应 POWER_SUPPLY_PROP_CAPACITY_LEVEL

POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN = 0,

POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL,

POWER_SUPPLY_CAPACITY_LEVEL_LOW,

POWER_SUPPLY_CAPACITY_LEVEL_NORMAL,

POWER_SUPPLY_CAPACITY_LEVEL_HIGH,

POWER_SUPPLY_CAPACITY_LEVEL_FULL,

};

电源驱动一般需要做以下几个部分的工作:
1、 定义struct power_supply,该定义可以是全局的或者嵌入到驱动专有数据结构中,实现其结构字段
(1) const char *name;字段
名称
(2) enum power_supply_type type;电源类型字段
(3) enum power_supply_property *properties;属性字段
定义一个全局enum power_supply_property类型的数组,数组中保存该电源需要上报的属性。将该数组的首地址赋给properties字段。
(4) 实现get_property函数,用来读取属性值
(5) 如果需要写属性值,则实现set_property函数和property_is_writeable函数, property_is_writeable函数判断是否需要写权限,是则返回1,否则返回0;
2、 调用函数power_supply_register将定义的power_supply注册到内核中
3、 当电源的参数有变化时,调用power_supply_changed函数通知系统和用户,改变相应的属性值,然后用户程序通过/sys/class/power_supply/你的电池名称/就可以知道属性值。

参考资料:

Linux电源管理系统架构和驱动

linux电源驱动解析

http://www.wowotech.net/pm_architecture.html