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/你的电池名称/就可以知道属性值。参考资料:
http://www.wowotech.net/pm_architecture.html