前段时间比较烦躁,各种不想学习不想工作,于是休息了几天。这几天又下来任务了--调试充电电路和电池电量检测电路,于是又开始工作,顺便把调试过程记录下来。

平台: cpu        飞思卡尔imx6q 4核

充电芯片     MAX8903

电量检测芯片  MAX11801

android版本  android4.0

一、电量检测

我们用的电池电量检测芯片MAX11801其实是一款电阻触摸屏的驱动芯片,它外带一个AD采集引脚,因此我们用这个引脚来检测电池电压。MAX11801电源为3.3V而电池电压范围可能是0~4.2V,因此我们需要给电池电压分压。我们所用的电路如下

知道了硬件电路下面来 添加这个芯片的驱动,这是一个i2c的芯片,因此首先在board文件中添加i2c设备

		I2C_BOARD_INFO("max11801", 0x48),
.platform_data = (void *)&max11801_mode,
.irq = gpio_to_irq(SABRESD_TS_INT),
},

然后添加这个芯片的驱动文件放在/drivers/input/touchiscreen/max11801_ts.c

对于这个驱动文件我们只要读取出AD的值就可以了,对于触摸屏部分我们并不需要,因此主要是下面几个函数

static u32 max11801_dcm_sample_aux(struct i2c_client *client)
{
u8 temp_buf;
int ret;
int aux = 0;
u32 sample_data = 0;
/* AUX_measurement*/
max11801_dcm_write_command(client, AUX_measurement);//发送AD采集命令
mdelay(5);
ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_AUX_MSB, //读取高字节数据
1, &temp_buf);
if (ret < 1)
printk(KERN_DEBUG "FIFO_RD_AUX_MSB read fails\n");
else
aux_buf[0] = temp_buf;
mdelay(5);
ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_AUX_LSB, //读取低字节数据
1, &temp_buf);
if (ret < 1)
printk(KERN_DEBUG "FIFO_RD_AUX_LSB read fails\n");
else
aux_buf[1] = temp_buf;
aux = (aux_buf[0] << 4) + //视最低4位无效并去掉
(aux_buf[1] >> 4); /*
10k和18.7k并联后电阻
R=18.7*10/(18.7+10)=6.516
V(aux) = V(bat)*6.516/(6.516+18.7)
V(aux) = aux*3300/0xfff
V(bat) = aux*1386880/444717
*/
sample_data = (aux*1386880)/444717; //计算出电池电压
return sample_data;
} u32 max11801_read_adc(void)
{
u32 adc_data;
adc_data = max11801_dcm_sample_aux(max11801_client);
// printk("----%s %d\n",__func__,adc_data); //lijianzhang
return adc_data;
}
EXPORT_SYMBOL_GPL(max11801_read_adc);

由于电池电量检测的驱动非常简单,而且和充电驱动关系非常密切,因此一般都卸载充电驱动里面,我们也是这么做的。下面的代码都是从充电驱动中摘出来的,因此当大家看到,一些设备文件和函数参数类型 都是充电驱动中的  时候不要太奇怪。

通过上面的max11801_read_adc函数我们已经得到了理论计算的电池的电压,但实际应用中由于分压电阻误差,焊接问题等,这个电压会有一定的误差因此需要一个校正函数

u32 calibration_voltage(struct max8903_data *data)
{
int volt[ADC_SAMPLE_COUNT];
u32 voltage_data;
int i;
for (i = 0; i < ADC_SAMPLE_COUNT; i++) { //多次采样,防止AD误差
if (data->charger_online == 0 && data->usb_charger_online == 0) {
/* ADC offset when battery is discharger*/
volt[i] = max11801_read_adc()-offset_discharger; //没有充电情况下 电压误差
} else {
if (data->charger_online == 1)
volt[i] = max11801_read_adc()-offset_charger;//DC充电式 电压误差
else if (data->usb_charger_online == 1)
volt[i] = max11801_read_adc()-offset_usb_charger;//usb充电 电压误差
else if (data->charger_online == 1 && data->usb_charger_online == 1)
volt[i] = max11801_read_adc()-offset_charger;
} }
sort(volt, i, 4, cmp_func, NULL);//对电压排序
for (i = 0; i < ADC_SAMPLE_COUNT; i++)
pr_debug("volt_sorted[%2d]: %d\n", i, volt[i]);
/* get the average of second max/min of remained. */
voltage_data = (volt[2] + volt[ADC_SAMPLE_COUNT - 3]) / 2;//去掉最大值最小值 并对剩余数据求平均
return voltage_data;
}

从上面函数我们读取到了正确的电压值。电池电压是随时变化的,我们要检测电池电量,必须随时采集,因此用一个定时器来做这件事情,代码如下:

INIT_DELAYED_WORK(&data->work, max8903_battery_work);
schedule_delayed_work(&data->work, data->interval);

电压采集完成后就是将电压上报出去,上报的过程是:我们读取到电压变化->告诉android端电池电压变化了->android会通过power_supply设备文件来读取具体的电压值。
我们来看定时器回调函数

static void max8903_battery_work(struct work_struct *work)
{
struct max8903_data *data;
data = container_of(work, struct max8903_data, work.work);
data->interval = HZ * BATTERY_UPDATE_INTERVAL;
max8903_charger_update_status(data); //检测充电状态
max8903_battery_update_status(data); //检测电池状态
/* reschedule for the next time */
schedule_delayed_work(&data->work, data->interval);//定时器继续
}

检测电池状态函数

static void max8903_battery_update_status(struct max8903_data *data)
{
int temp;
static int temp_last;
bool changed_flag;
changed_flag = false;
mutex_lock(&data->work_lock);
temp = calibration_voltage(data);
if (temp_last == 0) {
data->voltage_uV = temp;
temp_last = temp;
}
if (data->charger_online == 0 && temp_last != 0) {//DC充电状态
if (temp < temp_last) {
temp_last = temp;
data->voltage_uV = temp;
} else {
data->voltage_uV = temp_last;
}
}
if (data->charger_online == 1 || data->usb_charger_online == 1) {//USB充电状态和DC充电状态
data->voltage_uV = temp;
temp_last = temp;
}
data->percent = calibrate_battery_capability_percent(data);//计算电量的百分比
if (data->percent != data->old_percent) { //电池电压有变化
data->old_percent = data->percent;
changed_flag = true;
}
if (changed_flag) { //如果有变化
changed_flag = false;
power_supply_changed(&data->bat);//告诉android端 电池电量改变了
}
/*
because boot time gap between led framwork and charger
framwork,when system boots with charger attatched, charger
led framwork loses the first charger online event,add once extra
power_supply_changed can fix this issure
*/
if (data->first_delay_count < 200) {
data->first_delay_count = data->first_delay_count + 1 ;
power_supply_changed(&data->bat);
} mutex_unlock(&data->work_lock);
}

这里我们看到了 power_supply_changed(&data->bat);告诉android端 电池电量改变了,那么下一步android来读取具体电压,就涉及到了power_supply设备文件。
来看设备文件的建立过程

	data->bat.name = "max8903-charger";
data->bat.type = POWER_SUPPLY_TYPE_BATTERY;
data->bat.properties = max8903_battery_props;
data->bat.num_properties = ARRAY_SIZE(max8903_battery_props);
data->bat.get_property = max8903_battery_get_property;
data->bat.use_for_apm = 1;
retval = power_supply_register(&pdev->dev, &data->bat);//注册设备文件
if (retval) {
dev_err(data->dev, "failed to register battery\n");
goto battery_failed;
}

这里注册了一个名为max8903-charger的 power_supply设备文件,这个设备文件包含了ARRAY_SIZE(max8903_battery_props)个操作分别为

static enum power_supply_property max8903_battery_props[] = {
POWER_SUPPLY_PROP_VOLTAGE_NOW,//当前电压
POWER_SUPPLY_PROP_STATUS, //当前充电状态
POWER_SUPPLY_PROP_PRESENT, //不太清除
POWER_SUPPLY_PROP_CAPACITY, //电量百分比
POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,//电池极限电压 最大值
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,//电池极限电压 最小值
POWER_SUPPLY_PROP_HEALTH, //电池健康状态
POWER_SUPPLY_PROP_CAPACITY_LEVEL,//电量水平,low或者normal
};

这些状态是通过max8903_battery_get_property()这个函数来读取的

static int max8903_battery_get_property(struct power_supply *bat,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct max8903_data *di = container_of(bat,
struct max8903_data, bat);
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
if (gpio_get_value(di->pdata->chg) == 0) {
di->battery_status = POWER_SUPPLY_STATUS_CHARGING; //正在充电
} else if (di->ta_in &&
gpio_get_value(di->pdata->chg) == 1) {
if (di->percent >= 99)
di->battery_status = POWER_SUPPLY_STATUS_FULL;//电量大于99就充满了
else
di->battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
}
else if (di->usb_in &&
gpio_get_value(di->pdata->chg) == 1) {
if (di->percent >= 99)
di->battery_status = POWER_SUPPLY_STATUS_FULL;
else
di->battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
}
val->intval = di->battery_status;
return 0;
default:
break;
} switch (psp) {
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
val->intval = di->voltage_uV;
break;
case POWER_SUPPLY_PROP_CHARGE_NOW:
val->intval = 0;
break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
val->intval = HIGH_VOLT_THRESHOLD;
break;
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
val->intval = LOW_VOLT_THRESHOLD;
break;
case POWER_SUPPLY_PROP_PRESENT:
val->intval = 1;
break;
case POWER_SUPPLY_PROP_CAPACITY:
val->intval = di->percent < 0 ? 0 :
(di->percent > 100 ? 100 : di->percent);
break;
case POWER_SUPPLY_PROP_HEALTH:
val->intval = POWER_SUPPLY_HEALTH_GOOD;
if (di->fault)
val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
break;
case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
if (di->battery_status == POWER_SUPPLY_STATUS_FULL)
val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
else if (di->percent <= 15)
val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;//电量小于15%就报低电量
else
val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;//否则就报正常
break;
default:
return -EINVAL;
} return 0;
}

当我们注册设备文件以后,可以在/sys/devices/platform/max8903-charger.1/power_supply/max8903-charger目录下找到其设备文件如下


我们通过cat命令就可以随时查看电池状态。

二、电池电压校正参数

上面我们知道根据硬件实际情况不同,AD采集出来的电池电压需要校正参数。也就是

static int offset_discharger;
   static int offset_charger;
   static int offset_usb_charger;

对于这三个参数,当然我们可以在驱动力写死,但是为了以后的兼容性我们可以通过android上层来设置,当我们设备出厂时候,通过一配置文件方便的来修改这三个参数,下面我们就来介绍一下,怎么用设备文件和脚本,来修改者三个参数:

我们用的是sys文件系统的设备文件,创建代码为

	ret = device_create_file(&pdev->dev, &max8903_discharger_dev_attr);
if (ret)
dev_err(&pdev->dev, "create device file failed!\n");
ret = device_create_file(&pdev->dev, &max8903_charger_dev_attr);
if (ret)
dev_err(&pdev->dev, "create device file failed!\n");
ret = device_create_file(&pdev->dev, &max8903_usb_charger_dev_attr);
if (ret)
dev_err(&pdev->dev, "create device file failed!\n");

设备文件的实现代码为

static ssize_t max8903_voltage_offset_discharger_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "read offset_discharger:%04d\n",
offset_discharger);
} static ssize_t max8903_voltage_offset_discharger_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
offset_discharger = simple_strtoul(buf, NULL, 10);
pr_info("read offset_discharger:%04d\n", offset_discharger);
return count;
} static ssize_t max8903_voltage_offset_charger_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "read offset_charger:%04d\n",
offset_charger);
} static ssize_t max8903_voltage_offset_charger_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
offset_charger = simple_strtoul(buf, NULL, 10);
pr_info("read offset_charger:%04d\n", offset_charger);
return count;
} static ssize_t max8903_voltage_offset_usb_charger_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "read offset_usb_charger:%04d\n",
offset_usb_charger);
} static ssize_t max8903_voltage_offset_usb_charger_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
offset_usb_charger = simple_strtoul(buf, NULL, 10);
pr_info("read offset_charger:%04d\n", offset_usb_charger);
return count;
} static struct device_attribute max8903_discharger_dev_attr = {
.attr = {
.name = "max8903_ctl_offset_discharger",
.mode = S_IRUSR | S_IWUSR,
},
.show = max8903_voltage_offset_discharger_show,
.store = max8903_voltage_offset_discharger_store,
}; static struct device_attribute max8903_charger_dev_attr = {
.attr = {
.name = "max8903_ctl_offset_charger",
.mode = S_IRUSR | S_IWUSR,
},
.show = max8903_voltage_offset_charger_show,
.store = max8903_voltage_offset_charger_store,
}; static struct device_attribute max8903_usb_charger_dev_attr = {
.attr = {
.name = "max8903_ctl_offset_usb_charger",
.mode = S_IRUSR | S_IWUSR,
},
.show = max8903_voltage_offset_usb_charger_show,
.store = max8903_voltage_offset_usb_charger_store,
};

这样,我们就可以在/sys/devices/platform/max8903-charger.1目录下看到这样三个设备文件


我们用cat命令可以读出当前值,用echo "500">>max8903_ctl_offset_charger 可以修改当前值

这样我们就可以在系统启动的时候,用脚本来自动修改者三个值,我用的办法是在init.rc的on boot阶段增加这么三行

#battery charge
write /sys/devices/platform/max8903-charger.1/max8903_ctl_offset_charger 150
write /sys/devices/platform/max8903-charger.1/max8903_ctl_offset_discharger 200
write /sys/devices/platform/max8903-charger.1/max8903_ctl_offset_usb_charger 250

当然大家也可以把这三行命令写在另外一个脚本里,然后init.rc中调用

三、电池充电

电池充电的电路

一共有4个引脚输出到cpu中:

CHG_FLT1_B    电池检测错误

UOK_B              usb插入

DOK_BDC插入

CHG_STATUS1_B 充电状态

对于充电状态的检测过程,和电量检测基本相同, 检测到状态变化->告诉android层发生变化->android层通过设备文件来读取变化值

知道了这些我们来看驱动,首先在board文件中添加max8903设备

static struct max8903_pdata charger1_data = {
.dok = SABRESD_CHARGE_DOK_B,
.uok = SABRESD_CHARGE_UOK_B,
.chg = CHARGE_STATE2,
.flt = CHARGE_STATE1,
.dcm_always_high = true,
.dc_valid = true,
.usb_valid = true,
}; static struct platform_device sabresd_max8903_charger_1 = {
.name = "max8903-charger",
.id = 1, .dev = {
.platform_data = &charger1_data,
},
};
platform_device_register(&sabresd_max8903_charger_1);

然后在/derivers/power/目录下添加驱动文件。充电状态的变化都是IO电平的变化,我们来看驱动是怎么处理这4个io的,首先在probe函数中

申请IO

if (pdata->dc_valid) {
if (pdata->dok && gpio_is_valid(pdata->dok)) {
gpio = pdata->dok; /* PULL_UPed Interrupt */
/* set DOK gpio input */
ret = gpio_request(gpio, "max8903-DOK");
if (ret) {
printk(KERN_ERR"request max8903-DOK error!!\n");
goto err;
} else {
gpio_direction_input(gpio);
}
ta_in = gpio_get_value(gpio) ? 0 : 1;
} else if (pdata->dok && gpio_is_valid(pdata->dok) && pdata->dcm_always_high) {
ta_in = pdata->dok; /* PULL_UPed Interrupt */
ta_in = gpio_get_value(gpio) ? 0 : 1;
} else {
dev_err(dev, "When DC is wired, DOK and DCM should"
" be wired as well."
" or set dcm always high\n");
ret = -EINVAL;
goto err;
}
}
if (pdata->usb_valid) {
if (pdata->uok && gpio_is_valid(pdata->uok)) {
gpio = pdata->uok;
/* set UOK gpio input */
ret = gpio_request(gpio, "max8903-UOK");
if (ret) {
printk(KERN_ERR"request max8903-UOK error!!\n");
goto err;
} else {
gpio_direction_input(gpio);
}
usb_in = gpio_get_value(gpio) ? 0 : 1;
} else {
dev_err(dev, "When USB is wired, UOK should be wired."
"as well.\n");
ret = -EINVAL;
goto err;
}
}
if (pdata->chg) {
if (!gpio_is_valid(pdata->chg)) {
dev_err(dev, "Invalid pin: chg.\n");
ret = -EINVAL;
goto err;
}
/* set CHG gpio input */
ret = gpio_request(pdata->chg, "max8903-CHG");
if (ret) {
printk(KERN_ERR"request max8903-CHG error!!\n");
goto err;
} else {
gpio_direction_input(pdata->chg);
}
}
if (pdata->flt) {
if (!gpio_is_valid(pdata->flt)) {
dev_err(dev, "Invalid pin: flt.\n");
ret = -EINVAL;
goto err;
}
/* set FLT gpio input */
ret = gpio_request(pdata->flt, "max8903-FLT");
if (ret) {
printk(KERN_ERR"request max8903-FLT error!!\n");
goto err;
} else {
gpio_direction_input(pdata->flt);
}
}
if (pdata->usus) {
if (!gpio_is_valid(pdata->usus)) {
dev_err(dev, "Invalid pin: usus.\n");
ret = -EINVAL;
goto err;
}
}

注册DC充电的设备文件

mutex_init(&data->work_lock);
data->fault = false;
data->ta_in = ta_in;
data->usb_in = usb_in;
data->psy.name = "max8903-ac";
data->psy.type = POWER_SUPPLY_TYPE_MAINS;
data->psy.get_property = max8903_get_property;
data->psy.properties = max8903_charger_props;
data->psy.num_properties = ARRAY_SIZE(max8903_charger_props);
ret = power_supply_register(dev, &data->psy);
if (ret) {
dev_err(dev, "failed: power supply register.\n");
goto err_psy;
}

注册USB充电的设备文件

data->usb.name = "max8903-usb";
data->usb.type = POWER_SUPPLY_TYPE_USB;
data->usb.get_property = max8903_get_usb_property;
data->usb.properties = max8903_charger_props;
data->usb.num_properties = ARRAY_SIZE(max8903_charger_props);
ret = power_supply_register(dev, &data->usb);
if (ret) {
dev_err(dev, "failed: power supply register.\n");
goto err_psy;
}

这两个设备文件都只有一个操作:检测充电器是否在线

static enum power_supply_property max8903_charger_props[] = {
POWER_SUPPLY_PROP_ONLINE,
};

操作函数也很简单

static int max8903_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct max8903_data *data = container_of(psy,
struct max8903_data, psy); switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
val->intval = 0;
if (data->ta_in)
val->intval = 1;
data->charger_online = val->intval;
break;
default:
return -EINVAL;
}
return 0;
}
static int max8903_get_usb_property(struct power_supply *usb,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct max8903_data *data = container_of(usb,
struct max8903_data, usb); switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
val->intval = 0;
if (data->usb_in)
val->intval = 1;
data->usb_charger_online = val->intval;
break;
default:
return -EINVAL;
}
return 0;
}

我们可以通过/sys/devices/platform/max8903-charger.1/power_supply/max8903-ac 目录和/sys/devices/platform/max8903-charger.1/power_supply/max8903-usb目录下的设备文件来访问充电器的状态

接下来是IO中断

if (pdata->dc_valid) {
ret = request_threaded_irq(gpio_to_irq(pdata->dok),
NULL, max8903_dcin,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
"MAX8903 DC IN", data);
if (ret) {
dev_err(dev, "Cannot request irq %d for DC (%d)\n",
gpio_to_irq(pdata->dok), ret);
goto err_usb_irq;
}
} if (pdata->usb_valid) {
ret = request_threaded_irq(gpio_to_irq(pdata->uok),
NULL, max8903_usbin,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
"MAX8903 USB IN", data);
if (ret) {
dev_err(dev, "Cannot request irq %d for USB (%d)\n",
gpio_to_irq(pdata->uok), ret);
goto err_dc_irq;
}
} if (pdata->flt) {
ret = request_threaded_irq(gpio_to_irq(pdata->flt),
NULL, max8903_fault,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
"MAX8903 Fault", data);
if (ret) {
dev_err(dev, "Cannot request irq %d for Fault (%d)\n",
gpio_to_irq(pdata->flt), ret);
goto err_flt_irq;
}
} if (pdata->chg) {
ret = request_threaded_irq(gpio_to_irq(pdata->chg),
NULL, max8903_chg,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
"MAX8903 Fault", data);
if (ret) {
dev_err(dev, "Cannot request irq %d for Fault (%d)\n",
gpio_to_irq(pdata->flt), ret);
goto err_chg_irq;
}
}

这4个IO的中断处理函数很类似

static irqreturn_t max8903_dcin(int irq, void *_data)
{
struct max8903_data *data = _data;
struct max8903_pdata *pdata = data->pdata;
bool ta_in; ta_in = gpio_get_value(pdata->dok) ? false : true; //保存当前dok值 if (ta_in == data->ta_in)
return IRQ_HANDLED; data->ta_in = ta_in;
pr_info("TA(DC-IN) Charger %s.\n", ta_in ?
"Connected" : "Disconnected");
max8903_charger_update_status(data);
max8903_battery_update_status(data);
power_supply_changed(&data->psy); //报告状态改变
power_supply_changed(&data->bat);
return IRQ_HANDLED;
}
static irqreturn_t max8903_usbin(int irq, void *_data)
{
struct max8903_data *data = _data;
struct max8903_pdata *pdata = data->pdata;
bool usb_in;
usb_in = gpio_get_value(pdata->uok) ? false : true; //保存当前uok值
if (usb_in == data->usb_in)
return IRQ_HANDLED; data->usb_in = usb_in;
max8903_charger_update_status(data);
max8903_battery_update_status(data);
pr_info("USB Charger %s.\n", usb_in ?
"Connected" : "Disconnected");
power_supply_changed(&data->bat);
power_supply_changed(&data->usb); //报告状态改变
return IRQ_HANDLED;
} static irqreturn_t max8903_fault(int irq, void *_data)
{
struct max8903_data *data = _data;
struct max8903_pdata *pdata = data->pdata;
bool fault; fault = gpio_get_value(pdata->flt) ? false : true; //保存当前电池错误值 if (fault == data->fault)
return IRQ_HANDLED; data->fault = fault; if (fault)
dev_err(data->dev, "Charger suffers a fault and stops.\n");
else
dev_err(data->dev, "Charger recovered from a fault.\n");
max8903_charger_update_status(data);
max8903_battery_update_status(data);
power_supply_changed(&data->psy);
power_supply_changed(&data->bat);
power_supply_changed(&data->usb); //报告状态改变
return IRQ_HANDLED;
} static irqreturn_t max8903_chg(int irq, void *_data)
{
struct max8903_data *data = _data;
struct max8903_pdata *pdata = data->pdata;
int chg_state; chg_state = gpio_get_value(pdata->chg) ? false : true;//保存电池充电状态 if (chg_state == data->chg_state)
return IRQ_HANDLED; data->chg_state = chg_state;
max8903_charger_update_status(data);
max8903_battery_update_status(data);
power_supply_changed(&data->psy);
power_supply_changed(&data->bat);
power_supply_changed(&data->usb);//报告状态改变
return IRQ_HANDLED;
}

到了这里电池充电的流程就走完了。

android电池充电以及电量检测驱动分析的更多相关文章

  1. 【转】android电池(四):电池 电量计(MAX17040)驱动分析篇

    关键词:android 电池  电量计  MAX17040 任务初始化宏 power_supply 平台信息:内核:linux2.6/linux3.0系统:android/android4.0 平台: ...

  2. 【转】android电池(五):电池 充电IC(PM2301)驱动分析篇

    关键词:android 电池  电量计  PL2301任务初始化宏 power_supply 中断线程化 平台信息:内核:linux2.6/linux3.0系统:android/android4.0  ...

  3. android电池(四):电池 电量计(MAX17040)驱动分析篇【转】

    本文转载自:http://blog.csdn.net/xubin341719/article/details/8969369 电池电量计,库仑计,用max17040这颗电量IC去计量电池电量,这种方法 ...

  4. Android中Input型输入设备驱动原理分析(一)

    转自:http://blog.csdn.net/eilianlau/article/details/6969361 话说Android中Event输入设备驱动原理分析还不如说Linux输入子系统呢,反 ...

  5. Android中Input型输入设备驱动原理分析<一>

    话说Android中Event输入设备驱动原理分析还不如说Linux输入子系统呢,反正这个是没变的,在android的底层开发中对于Linux的基本驱动程序设计还是没变的,当然Android底层机制也 ...

  6. Android系统--Binder系统具体框架分析(二)Binder驱动情景分析

    Android系统--Binder系统具体框架分析(二)Binder驱动情景分析 1. Binder驱动情景分析 1.1 进程间通信三要素 源 目的:handle表示"服务",即向 ...

  7. Android内存泄漏的检测流程、捕捉以及分析

    https://blog.csdn.net/qq_20280683/article/details/77964208 Android内存泄漏的检测流程.捕捉以及分析 简述: 一个APP的性能,重度关乎 ...

  8. Android应用的电量消耗和优化的策略

     对于Android移动应用的开发者来说,耗电量的控制一直是个老大难问题.      我们想要控制耗电量,必须要有工具或者方法比较准确的定位应用的耗电情况.下面,我们先来分析下如何计算android应 ...

  9. 电量检测芯片BQ27510使用心得

    最近接触到一款TI的电量检测芯片BQ27510,网上很少有人提及该芯片如何使用,大部分博文都是搬得BQ27510的datasheet,至于真正使用过的很少,该芯片我个人感觉还是非常强大的,能自动学习你 ...

随机推荐

  1. IOS开发中UIBarButtonItem上按钮切换或隐藏实现案例

    IOS开发中UIBarButtonItem上按钮切换或隐藏案例实现案例是本文要介绍的内容,这个代码例子的背景是:导航条右侧有个 edit button,左侧是 back button 和 add bu ...

  2. Linux: 信息查看

    Linux log日志查看  http://www.2cto.com/os/201307/227230.html

  3. linux指令(目录类操作指令)

    pwd 显示当前所在的工作目录 cd 目标目录    例如cd  /boot/grub 从当前目录切换到某个目录 cd  切换到根目录 cd.. 切换到当前目录的上层目录 ls  显示当前目录下的内容 ...

  4. redis 消息队列(发布订阅)、持久化(RDB、AOF)、集群(cluster)

    一:订阅: 192.168.10.205:6379> SUBSCRIBE test Reading messages... (press Ctrl-C to quit) 1) "sub ...

  5. CairoSVG - Convert SVG to PNG or PDF - Contents

    CairoSVG - Convert SVG to PNG or PDF - Contents User Documentation Author Guillaume Ayoub Date 2011- ...

  6. C#Windows的HelloWorld

    在MSDN中找到Form类:MSDN-->.NET开发-->.NET Framework SDK 2.0-->Class Library Reference -->System ...

  7. 蛋疼的Apple IOS Push通知协议

    简单介绍 Apple Push通知机制事实上非常easy,就是Apple的APNsserver做为中间人,把消息推送到相应的设备上. 一张来自Apple文档的图: 当然,示意图看起来简单,可是另一些实 ...

  8. PHP - 字符串操作

    第8章 字符串处理 学习要点: 1.字符串格式化 2.操作子字符串 3.字符串比较 4.查找替换字符串 5.处理中文字符 在每天的编程工作中,处理.调整以至最后控制字符串是很重要的一部分,一般也认为这 ...

  9. NET 2016

    .NET 2016   阅读目录 初识 .NET 2016 使用 .NET Framework 4.6 编译应用程序 使用 .NET Core CLI 编译应用程序 小结 厚积薄发这个词是高三英语老师 ...

  10. Dynamic Pivot table wizard SQL Server

    原文 http://www.gyurcit.hu/pivot.html Dynamic Pivot table wizard This stored procedure generate dynami ...