版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhou12314/article/details/79379276
电池管理在Android系统中是一个重要的组成部分,它起的主要作用是检测我们的电池状态,剩余电量实时更新,高温报警,低电量关机等功能的实现。
Android的电池管理模块,从内核层到Android的应用层我大概分为了4层来理解,从上到下依次为,应用展示层,framwork层,本地框架层,内核驱动层,计划用3篇文章从下到上对这四个模块进行一个大概的介绍。
本篇文章着重介绍Linux内核电池驱动的实现细节。
驱动部分大概概括下流程是这样的:
Android内核中的电池驱动采取的是linux 内核驱动中的 power_supply子系统框架进行上报电池状态。power_supply主要通过sys文件系统向用户层提供读取电池状态的接口,路径为 /sys/class/power_supply/ , 该目录下通常会有 ac , battery, usb 三个目录,代表给Android系统供电的三种能源类型,其中电池的状态就在battery的目录下,当电池状态变化的时候会通过uevent通知上层,然后上层通过读取该目录下相应的值来动态的显示电池状态。
以充电芯片bq27x00为例,驱动具体代码分析如下:
定义设备结构体,里面包含struct power_supply这个结构体,
struct bq27x00_device_info {
struct device *dev;
int id;
enum bq27x00_chip chip;
struct bq27x00_reg_cache cache;
int charge_design_full;
unsigned long last_update;
struct delayed_work work;
struct power_supply bat;
struct bq27x00_access_methods bus;
struct mutex lock;
};
绑定I2C设备和驱动:
static int __init bq27x00_battery_init(void)
{
int ret;
ret = bq27x00_battery_i2c_init(); //初始化i2c驱动
if (ret)
return ret;
ret = bq27x00_battery_platform_init(); //绑定i2c设备
if (ret)
bq27x00_battery_i2c_exit();
return ret;
在i2c驱动的bq27x00_battery_probe的函数中,调用bq27x00_powersupply_init函数,对power_supply这个结构体进行填充并调用power_supply_register进行注册,初始化定时器队列INIT_DELAYED_WORK(&di->work, bq27x00_battery_poll); 然后调用bq27x00_update通过i2c对电池状态数据进行请求,然后更新sys/class/power_supply下的节点
static int bq27x00_powersupply_init(struct bq27x00_device_info *di)
{
int ret;
di->bat.name = name;
di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
di->bat.properties = bq27x00_battery_props;
di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props);
di->bat.get_property = bq27x00_battery_get_property;
di->bat.external_power_changed = bq27x00_external_power_changed;
//初始化定时器队列
INIT_DELAYED_WORK(&di->work, bq27x00_battery_poll);
mutex_init(&di->lock);
ret = power_supply_register(di->dev, &di->bat);
if (ret) {
dev_err(di->dev, "failed to register battery: %d\n", ret);
return ret;
}
dev_info(di->dev, "support ver. %s enabled\n", DRIVER_VERSION);
bq27x00_update(di);
return 0;
}
在bq27x00_battery_poll中开启定时器队列定时调用bq27x00_update()更新电池状态数据
static void bq27x00_battery_poll(struct work_struct *work)
{
struct bq27x00_device_info *di =
container_of(work, struct bq27x00_device_info, work.work);
bq27x00_update(di);
if (poll_interval > 0) {
/* The timer does not have to be accurate. */
//通过改变poll_interval可以改变定时器轮询时间
set_timer_slack(&di->work.timer, poll_interval * HZ / 4);
schedule_delayed_work(&di->work, poll_interval * HZ);
}
}
bq27x00_update中主要做的事情如下:
static void bq27x00_update(struct bq27x00_device_info *di)
{
struct bq27x00_reg_cache cache = {0, };
bool is_bq27500 = di->chip == BQ27500;
cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, !is_bq27500);
if (cache.flags >= 0) {
if (!is_bq27500 && (cache.flags & BQ27000_FLAG_CI)) {
dev_info(di->dev, "battery is not calibrated! ignoring capacity values\n");
cache.capacity = -ENODATA;
cache.energy = -ENODATA;
cache.time_to_empty = -ENODATA;
cache.time_to_empty_avg = -ENODATA;
cache.time_to_full = -ENODATA;
cache.charge_full = -ENODATA;
} else {
//以下对电池状态进行读取
cache.capacity = bq27x00_battery_reaad_rsoc(di);
cache.energy = bq27x00_battery_read_energy(di);
cache.time_to_empty = bq27x00_battery_read_time(di, BQ27x00_REG_TTE);
cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP);
cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF);
cache.charge_full = bq27x00_battery_read_lmd(di);
}
cache.temperature = bq27x00_battery_read_temperature(di);
cache.cycle_count = bq27x00_battery_read_cyct(di);
/* We only have to read charge design full once */
if (di->charge_design_full <= 0)
di->charge_design_full = bq27x00_battery_read_ilmd(di);
}
if (memcmp(&di->cache, &cache, sizeof(cache)) != 0) {
di->cache = cache;
//对/sys/class/power_supply节点进行更新
power_supply_changed(&di->bat);
}
di->last_update = jiffies;
}