android电池充电以及电量检测驱动分析

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

  平台: cpu        飞思卡尔imx6q 4核

        充电芯片     MAX8903

        电量检测芯片  MAX11801

        Android版本  android4.0

一、电量检测

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



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

[cpp]  view plain  copy
  1. I2C_BOARD_INFO("max11801", 0x48),  
  2. .platform_data = (void *)&max11801_mode,  
  3. .irq = gpio_to_irq(SABRESD_TS_INT),  
  4. ,  
  然后添加这个芯片的驱动文件放在/drivers/input/touchiscreen/max11801_ts.c

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

[cpp]  view plain  copy
  1. static u32 max11801_dcm_sample_aux(struct i2c_client *client)  
  2. {  
  3.     u8 temp_buf;  
  4.     int ret;  
  5.     int aux = 0;  
  6.     u32 sample_data = 0;  
  7.     /* AUX_measurement*/  
  8.     max11801_dcm_write_command(client, AUX_measurement);//发送AD采集命令  
  9.     mdelay(5);  
  10.     ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_AUX_MSB, //读取高字节数据  
  11.                         1, &temp_buf);  
  12.     if (ret < 1)  
  13.         printk(KERN_DEBUG "FIFO_RD_AUX_MSB read fails\n");  
  14.     else  
  15.         aux_buf[0] = temp_buf;  
  16.     mdelay(5);  
  17.     ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_AUX_LSB,    //读取低字节数据  
  18.                         1, &temp_buf);  
  19.     if (ret < 1)  
  20.         printk(KERN_DEBUG "FIFO_RD_AUX_LSB read fails\n");  
  21.     else  
  22.         aux_buf[1] = temp_buf;  
  23.     aux = (aux_buf[0] << 4) +           //视最低4位无效并去掉  
  24.                     (aux_buf[1] >> 4);  
  25.   
  26.     /* 
  27.     10k和18.7k并联后电阻  
  28.     R=18.7*10/(18.7+10)=6.516 
  29.     V(aux) = V(bat)*6.516/(6.516+18.7) 
  30.     V(aux) = aux*3300/0xfff 
  31.     V(bat) = aux*1386880/444717 
  32.     */  
  33.     sample_data = (aux*1386880)/444717; //计算出电池电压  
  34.     return sample_data;  
  35. }  
  36.   
  37. u32  max11801_read_adc(void)  
  38. {  
  39.     u32 adc_data;  
  40.     adc_data = max11801_dcm_sample_aux(max11801_client);  
  41. //  printk("----%s %d\n",__func__,adc_data);    //lijianzhang  
  42.     return adc_data;  
  43. }  
  44. EXPORT_SYMBOL_GPL(max11801_read_adc);  

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

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

[cpp]  view plain  copy
  1. u32 calibration_voltage(struct max8903_data *data)  
  2. {  
  3.     int volt[ADC_SAMPLE_COUNT];  
  4.     u32 voltage_data;  
  5.     int i;  
  6.         for (i = 0; i < ADC_SAMPLE_COUNT; i++) {    //多次采样,防止AD误差  
  7.             if (data->charger_online == 0 && data->usb_charger_online == 0) {  
  8.                 /* ADC offset when battery is discharger*/  
  9.                 volt[i] = max11801_read_adc()-offset_discharger;    //没有充电情况下 电压误差  
  10.                 } else {  
  11.                         if (data->charger_online == 1)  
  12.                         volt[i] = max11801_read_adc()-offset_charger;//DC充电式 电压误差  
  13.                         else if (data->usb_charger_online == 1)  
  14.                         volt[i] = max11801_read_adc()-offset_usb_charger;//usb充电  电压误差  
  15.                         else if (data->charger_online == 1 && data->usb_charger_online == 1)  
  16.                         volt[i] = max11801_read_adc()-offset_charger;  
  17.                 }  
  18.           
  19.     }  
  20.     sort(volt, i, 4, cmp_func, NULL);//对电压排序  
  21.     for (i = 0; i < ADC_SAMPLE_COUNT; i++)  
  22.         pr_debug("volt_sorted[%2d]: %d\n", i, volt[i]);  
  23.     /* get the average of second max/min of remained. */  
  24.     voltage_data = (volt[2] + volt[ADC_SAMPLE_COUNT - 3]) / 2;//去掉最大值最小值 并对剩余数据求平均  
  25.     return voltage_data;  
  26. }  
从上面函数我们读取到了正确的电压值。电池电压是随时变化的,我们要检测电池电量,必须随时采集,因此用一个定时器来做这件事情,代码如下:

[cpp]  view plain  copy
  1. INIT_DELAYED_WORK(&data->work, max8903_battery_work);  
  2.     schedule_delayed_work(&data->work, data->interval);  

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

[cpp]  view plain  copy
  1. static void max8903_battery_work(struct work_struct *work)  
  2. {  
  3.     struct max8903_data *data;  
  4.     data = container_of(work, struct max8903_data, work.work);  
  5.     data->interval = HZ * BATTERY_UPDATE_INTERVAL;  
  6.     max8903_charger_update_status(data);    //检测充电状态  
  7.     max8903_battery_update_status(data);    //检测电池状态  
  8.     /* reschedule for the next time */  
  9.     schedule_delayed_work(&data->work, data->interval);//定时器继续  
  10. }  
检测电池状态函数

[cpp]  view plain  copy
  1. static void max8903_battery_update_status(struct max8903_data *data)  
  2. {  
  3.     int temp;  
  4.     static int temp_last;  
  5.     bool changed_flag;  
  6.     changed_flag = false;  
  7.     mutex_lock(&data->work_lock);  
  8.     temp = calibration_voltage(data);  
  9.     if (temp_last == 0) {  
  10.         data->voltage_uV = temp;  
  11.         temp_last = temp;  
  12.     }  
  13.     if (data->charger_online == 0 && temp_last != 0) {//DC充电状态  
  14.         if (temp < temp_last) {  
  15.         temp_last = temp;  
  16.         data->voltage_uV = temp;  
  17.         } else {  
  18.         data->voltage_uV = temp_last;  
  19.         }  
  20.     }  
  21.     if (data->charger_online == 1 || data->usb_charger_online == 1) {//USB充电状态和DC充电状态  
  22.         data->voltage_uV = temp;  
  23.         temp_last = temp;  
  24.     }  
  25.     data->percent = calibrate_battery_capability_percent(data);//计算电量的百分比  
  26.     if (data->percent != data->old_percent) {   //电池电压有变化  
  27.         data->old_percent = data->percent;  
  28.         changed_flag = true;  
  29.     }  
  30.     if (changed_flag) {         //如果有变化  
  31.         changed_flag = false;  
  32.         power_supply_changed(&data->bat);//告诉android端 电池电量改变了  
  33.     }  
  34.     /* 
  35.         because boot time gap between led framwork and charger 
  36.         framwork,when system boots with charger attatched, charger 
  37.         led framwork loses the first charger online event,add once extra 
  38.         power_supply_changed can fix this issure 
  39.     */  
  40.     if (data->first_delay_count < 200) {  
  41.         data->first_delay_count = data->first_delay_count + 1 ;  
  42.         power_supply_changed(&data->bat);  
  43.     }  
  44.   
  45.     mutex_unlock(&data->work_lock);  
  46. }  
这里我们看到了 power_supply_changed(&data->bat);告诉android端 电池电量改变了,那么下一步android来读取具体电压,就涉及到了power_supply设备文件。
来看设备文件的建立过程

[cpp]  view plain  copy
  1. data->bat.name = "max8903-charger";  
  2. data->bat.type = POWER_SUPPLY_TYPE_BATTERY;  
  3. data->bat.properties = max8903_battery_props;  
  4. data->bat.num_properties = ARRAY_SIZE(max8903_battery_props);  
  5. data->bat.get_property = max8903_battery_get_property;  
  6. data->bat.use_for_apm = 1;  
  7. retval = power_supply_register(&pdev->dev, &data->bat);//注册设备文件  
  8. if (retval) {  
  9.     dev_err(data->dev, "failed to register battery\n");  
  10.     goto battery_failed;  
  11. }  
这里注册了一个名为max8903-charger的 power_supply设备文件,这个设备文件包含了ARRAY_SIZE(max8903_battery_props)个操作分别为

[cpp]  view plain  copy
  1. static enum power_supply_property max8903_battery_props[] = {  
  2.     POWER_SUPPLY_PROP_VOLTAGE_NOW,//当前电压  
  3.     POWER_SUPPLY_PROP_STATUS,       //当前充电状态  
  4.     POWER_SUPPLY_PROP_PRESENT,      //不太清除  
  5.     POWER_SUPPLY_PROP_CAPACITY,     //电量百分比  
  6.     POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,//电池极限电压 最大值  
  7.     POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,//电池极限电压 最小值  
  8.     POWER_SUPPLY_PROP_HEALTH,       //电池健康状态  
  9.     POWER_SUPPLY_PROP_CAPACITY_LEVEL,//电量水平,low或者normal  
  10. };  
这些状态是通过max8903_battery_get_property()这个函数来读取的

[cpp]  view plain  copy
  1. static int max8903_battery_get_property(struct power_supply *bat,  
  2.                        enum power_supply_property psp,  
  3.                        union power_supply_propval *val)  
  4. {  
  5.     struct max8903_data *di = container_of(bat,  
  6.             struct max8903_data, bat);  
  7.     switch (psp) {  
  8.     case POWER_SUPPLY_PROP_STATUS:  
  9.         val->intval = POWER_SUPPLY_STATUS_UNKNOWN;  
  10.                 if (gpio_get_value(di->pdata->chg) == 0) {  
  11.                     di->battery_status = POWER_SUPPLY_STATUS_CHARGING;  //正在充电  
  12.                 } else if (di->ta_in &&  
  13.                     gpio_get_value(di->pdata->chg) == 1) {  
  14.                     if (di->percent >= 99)  
  15.                         di->battery_status = POWER_SUPPLY_STATUS_FULL;//电量大于99就充满了  
  16.                     else  
  17.                         di->battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING;  
  18.                     }  
  19.                   else if (di->usb_in &&  
  20.                     gpio_get_value(di->pdata->chg) == 1) {  
  21.                     if (di->percent >= 99)  
  22.                         di->battery_status = POWER_SUPPLY_STATUS_FULL;  
  23.                     else  
  24.                       di->battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING;  
  25.                     }  
  26.         val->intval = di->battery_status;  
  27.         return 0;  
  28.     default:  
  29.         break;  
  30.     }  
  31.   
  32.     switch (psp) {  
  33.     case POWER_SUPPLY_PROP_VOLTAGE_NOW:  
  34.         val->intval = di->voltage_uV;  
  35.         break;  
  36.     case POWER_SUPPLY_PROP_CHARGE_NOW:  
  37.         val->intval = 0;  
  38.         break;  
  39.     case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:  
  40.         val->intval = HIGH_VOLT_THRESHOLD;  
  41.         break;  
  42.     case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:  
  43.         val->intval = LOW_VOLT_THRESHOLD;  
  44.         break;  
  45.     case POWER_SUPPLY_PROP_PRESENT:  
  46.         val->intval = 1;  
  47.         break;  
  48.     case POWER_SUPPLY_PROP_CAPACITY:  
  49.         val->intval = di->percent < 0 ? 0 :  
  50.                 (di->percent > 100 ? 100 : di->percent);  
  51.         break;  
  52.     case POWER_SUPPLY_PROP_HEALTH:  
  53.         val->intval = POWER_SUPPLY_HEALTH_GOOD;  
  54.         if (di->fault)  
  55.             val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;  
  56.         break;  
  57.     case POWER_SUPPLY_PROP_CAPACITY_LEVEL:  
  58.         if (di->battery_status == POWER_SUPPLY_STATUS_FULL)  
  59.             val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;  
  60.         else if (di->percent <= 15)  
  61.             val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;<span style="white-space:pre"> </span>//电量小于15%就报低电量  
  62.         else  
  63.             val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;//否则就报正常  
  64.         break;  
  65.     default:  
  66.         return -EINVAL;  
  67.     }  
  68.   
  69.     return 0;  
  70. }  
当我们注册设备文件以后,可以在/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文件系统的设备文件,创建代码为

[cpp]  view plain  copy
  1. ret = device_create_file(&pdev->dev, &max8903_discharger_dev_attr);  
  2. if (ret)  
  3.     dev_err(&pdev->dev, "create device file failed!\n");  
  4. ret = device_create_file(&pdev->dev, &max8903_charger_dev_attr);  
  5. if (ret)  
  6.     dev_err(&pdev->dev, "create device file failed!\n");  
  7. ret = device_create_file(&pdev->dev, &max8903_usb_charger_dev_attr);  
  8. if (ret)  
  9.     dev_err(&pdev->dev, "create device file failed!\n");  
设备文件的实现代码为

[cpp]  view plain  copy
  1. static ssize_t max8903_voltage_offset_discharger_show(struct device *dev,  
  2.                 struct device_attribute *attr, char *buf)  
  3. {  
  4.     return sprintf(buf, "read offset_discharger:%04d\n",  
  5.         offset_discharger);  
  6. }  
  7.   
  8. static ssize_t max8903_voltage_offset_discharger_store(struct device *dev,  
  9.                  struct device_attribute *attr, const char *buf,  
  10.                  size_t count)  
  11. {  
  12.     offset_discharger = simple_strtoul(buf, NULL, 10);  
  13.     pr_info("read offset_discharger:%04d\n", offset_discharger);  
  14.     return count;  
  15. }  
  16.   
  17. static ssize_t max8903_voltage_offset_charger_show(struct device *dev,  
  18.                 struct device_attribute *attr, char *buf)  
  19. {  
  20.     return sprintf(buf, "read offset_charger:%04d\n",  
  21.         offset_charger);  
  22. }  
  23.   
  24. static ssize_t max8903_voltage_offset_charger_store(struct device *dev,  
  25.                  struct device_attribute *attr, const char *buf,  
  26.                  size_t count)  
  27. {  
  28.     offset_charger = simple_strtoul(buf, NULL, 10);  
  29.     pr_info("read offset_charger:%04d\n", offset_charger);  
  30.     return count;  
  31. }  
  32.   
  33. static ssize_t max8903_voltage_offset_usb_charger_show(struct device *dev,  
  34.                 struct device_attribute *attr, char *buf)  
  35. {  
  36.     return sprintf(buf, "read offset_usb_charger:%04d\n",  
  37.         offset_usb_charger);  
  38. }  
  39.   
  40. static ssize_t max8903_voltage_offset_usb_charger_store(struct device *dev,  
  41.                  struct device_attribute *attr, const char *buf,  
  42.                  size_t count)  
  43. {  
  44.     offset_usb_charger = simple_strtoul(buf, NULL, 10);  
  45.     pr_info("read offset_charger:%04d\n", offset_usb_charger);  
  46.     return count;  
  47. }  
  48.   
  49. static struct device_attribute max8903_discharger_dev_attr = {  
  50.     .attr = {  
  51.          .name = "max8903_ctl_offset_discharger",  
  52.          .mode = S_IRUSR | S_IWUSR,  
  53.          },  
  54.     .show = max8903_voltage_offset_discharger_show,  
  55.     .store = max8903_voltage_offset_discharger_store,  
  56. };  
  57.   
  58. static struct device_attribute max8903_charger_dev_attr = {  
  59.     .attr = {  
  60.          .name = "max8903_ctl_offset_charger",  
  61.          .mode = S_IRUSR | S_IWUSR,  
  62.          },  
  63.     .show = max8903_voltage_offset_charger_show,  
  64.     .store = max8903_voltage_offset_charger_store,  
  65. };  
  66.   
  67. static struct device_attribute max8903_usb_charger_dev_attr = {  
  68.     .attr = {  
  69.          .name = "max8903_ctl_offset_usb_charger",  
  70.          .mode = S_IRUSR | S_IWUSR,  
  71.          },  
  72.     .show = max8903_voltage_offset_usb_charger_show,  
  73.     .store = max8903_voltage_offset_usb_charger_store,  
  74. };  
这样,我们就可以在/sys/devices/platform/max8903-charger.1目录下看到这样三个设备文件


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

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

[cpp]  view plain  copy
  1. #battery charge  
  2.     write /sys/devices/platform/max8903-charger.1/max8903_ctl_offset_charger 150  
  3.     write /sys/devices/platform/max8903-charger.1/max8903_ctl_offset_discharger 200  
  4.     write /sys/devices/platform/max8903-charger.1/max8903_ctl_offset_usb_charger 250  
当然大家也可以把这三行命令写在另外一个脚本里,然后init.rc中调用


三、电池充电

电池充电的电路


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

CHG_FLT1_B    电池检测错误

UOK_B               usb插入

DOK_B DC插入

CHG_STATUS1_B 充电状态

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

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

[cpp]  view plain  copy
  1. static struct max8903_pdata charger1_data = {  
  2.     .dok = SABRESD_CHARGE_DOK_B,  
  3.     .uok = SABRESD_CHARGE_UOK_B,  
  4.     .chg = CHARGE_STATE2,  
  5.     .flt = CHARGE_STATE1,  
  6.     .dcm_always_high = true,  
  7.     .dc_valid = true,  
  8.     .usb_valid = true,   
  9. };  
  10.   
  11. static struct platform_device sabresd_max8903_charger_1 = {  
  12.     .name   = "max8903-charger",  
  13.     .id = 1,  
  14.       
  15.     .dev    = {  
  16.         .platform_data = &charger1_data,  
  17.     },  
  18. };  
[cpp]  view plain  copy
  1. platform_device_register(&sabresd_max8903_charger_1);  
然后在/derivers/power/目录下添加驱动文件。充电状态的变化都是IO电平的变化,我们来看驱动是怎么处理这4个io的,首先在probe函数中

申请IO

[cpp]  view plain  copy
  1. if (pdata->dc_valid) {  
  2.         if (pdata->dok && gpio_is_valid(pdata->dok)) {  
  3.             gpio = pdata->dok; /* PULL_UPed Interrupt */  
  4.             /* set DOK gpio input */  
  5.             ret = gpio_request(gpio, "max8903-DOK");  
  6.             if (ret) {  
  7.                 printk(KERN_ERR"request max8903-DOK error!!\n");  
  8.                 goto err;  
  9.             } else {  
  10.                 gpio_direction_input(gpio);  
  11.             }  
  12.             ta_in = gpio_get_value(gpio) ? 0 : 1;  
  13.         } else if (pdata->dok && gpio_is_valid(pdata->dok) && pdata->dcm_always_high) {  
  14.             ta_in = pdata->dok; /* PULL_UPed Interrupt */  
  15.             ta_in = gpio_get_value(gpio) ? 0 : 1;  
  16.         } else {  
  17.             dev_err(dev, "When DC is wired, DOK and DCM should"  
  18.                     " be wired as well."  
  19.                     " or set dcm always high\n");  
  20.             ret = -EINVAL;  
  21.             goto err;  
  22.         }  
  23.     }  
  24.     if (pdata->usb_valid) {  
  25.         if (pdata->uok && gpio_is_valid(pdata->uok)) {  
  26.             gpio = pdata->uok;  
  27.             /* set UOK gpio input */  
  28.             ret = gpio_request(gpio, "max8903-UOK");  
  29.             if (ret) {  
  30.                 printk(KERN_ERR"request max8903-UOK error!!\n");  
  31.                 goto err;  
  32.             } else {  
  33.                 gpio_direction_input(gpio);  
  34.             }  
  35.             usb_in = gpio_get_value(gpio) ? 0 : 1;  
  36.         } else {  
  37.             dev_err(dev, "When USB is wired, UOK should be wired."  
  38.                     "as well.\n");  
  39.             ret = -EINVAL;  
  40.             goto err;  
  41.         }  
  42.     }  
  43.     if (pdata->chg) {  
  44.         if (!gpio_is_valid(pdata->chg)) {  
  45.             dev_err(dev, "Invalid pin: chg.\n");  
  46.             ret = -EINVAL;  
  47.             goto err;  
  48.         }  
  49.         /* set CHG gpio input */  
  50.         ret = gpio_request(pdata->chg, "max8903-CHG");  
  51.         if (ret) {  
  52.             printk(KERN_ERR"request max8903-CHG error!!\n");  
  53.             goto err;  
  54.         } else {  
  55.             gpio_direction_input(pdata->chg);  
  56.         }  
  57.     }  
  58.     if (pdata->flt) {  
  59.         if (!gpio_is_valid(pdata->flt)) {  
  60.             dev_err(dev, "Invalid pin: flt.\n");  
  61.             ret = -EINVAL;  
  62.             goto err;  
  63.         }  
  64.         /* set FLT gpio input */  
  65.         ret = gpio_request(pdata->flt, "max8903-FLT");  
  66.         if (ret) {  
  67.             printk(KERN_ERR"request max8903-FLT error!!\n");  
  68.             goto err;  
  69.         } else {  
  70.             gpio_direction_input(pdata->flt);  
  71.         }  
  72.     }  
  73.     if (pdata->usus) {  
  74.         if (!gpio_is_valid(pdata->usus)) {  
  75.             dev_err(dev, "Invalid pin: usus.\n");  
  76.             ret = -EINVAL;  
  77.             goto err;  
  78.         }  
  79.     }  
注册DC充电的设备文件

[cpp]  view plain  copy
  1. mutex_init(&data->work_lock);  
  2.     data->fault = false;  
  3.     data->ta_in = ta_in;  
  4.     data->usb_in = usb_in;  
  5.     data->psy.name = "max8903-ac";  
  6.     data->psy.type = POWER_SUPPLY_TYPE_MAINS;  
  7.     data->psy.get_property = max8903_get_property;  
  8.     data->psy.properties = max8903_charger_props;  
  9.     data->psy.num_properties = ARRAY_SIZE(max8903_charger_props);  
  10.     ret = power_supply_register(dev, &data->psy);  
  11.     if (ret) {  
  12.         dev_err(dev, "failed: power supply register.\n");  
  13.         goto err_psy;  
  14.     }  
注册USB充电的设备文件

[cpp]  view plain  copy
  1. data->usb.name = "max8903-usb";  
  2.     data->usb.type = POWER_SUPPLY_TYPE_USB;  
  3.     data->usb.get_property = max8903_get_usb_property;  
  4.     data->usb.properties = max8903_charger_props;  
  5.     data->usb.num_properties = ARRAY_SIZE(max8903_charger_props);  
  6.     ret = power_supply_register(dev, &data->usb);  
  7.     if (ret) {  
  8.         dev_err(dev, "failed: power supply register.\n");  
  9.         goto err_psy;  
  10.     }  
这两个设备文件都只有一个操作:检测充电器是否在线

[cpp]  view plain  copy
  1. static enum power_supply_property max8903_charger_props[] = {  
  2.     POWER_SUPPLY_PROP_ONLINE,  
  3. };  
操作函数也很简单
[cpp]  view plain  copy
  1. static int max8903_get_property(struct power_supply *psy,  
  2.         enum power_supply_property psp,  
  3.         union power_supply_propval *val)  
  4. {  
  5.     struct max8903_data *data = container_of(psy,  
  6.             struct max8903_data, psy);  
  7.   
  8.     switch (psp) {  
  9.     case POWER_SUPPLY_PROP_ONLINE:  
  10.         val->intval = 0;  
  11.         if (data->ta_in)  
  12.             val->intval = 1;  
  13.         data->charger_online = val->intval;  
  14.         break;  
  15.     default:  
  16.         return -EINVAL;  
  17.     }  
  18.     return 0;  
  19. }  
  20. static int max8903_get_usb_property(struct power_supply *usb,  
  21.         enum power_supply_property psp,  
  22.         union power_supply_propval *val)  
  23. {  
  24.     struct max8903_data *data = container_of(usb,  
  25.             struct max8903_data, usb);  
  26.   
  27.     switch (psp) {  
  28.     case POWER_SUPPLY_PROP_ONLINE:  
  29.         val->intval = 0;  
  30.         if (data->usb_in)  
  31.             val->intval = 1;  
  32.         data->usb_charger_online = val->intval;  
  33.         break;  
  34.     default:  
  35.         return -EINVAL;  
  36.     }  
  37.     return 0;  
  38. }  
我们可以通过/sys/devices/platform/max8903-charger.1/power_supply/max8903-ac 目录和/sys/devices/platform/max8903-charger.1/power_supply/max8903-usb目录下的设备文件来访问充电器的状态



接下来是IO中断

[cpp]  view plain  copy
  1. if (pdata->dc_valid) {  
  2.         ret = request_threaded_irq(gpio_to_irq(pdata->dok),  
  3.                 NULL, max8903_dcin,  
  4.                 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,  
  5.                 "MAX8903 DC IN", data);  
  6.         if (ret) {  
  7.             dev_err(dev, "Cannot request irq %d for DC (%d)\n",  
  8.                     gpio_to_irq(pdata->dok), ret);  
  9.             goto err_usb_irq;  
  10.         }  
  11.     }  
  12.   
  13.     if (pdata->usb_valid) {  
  14.         ret = request_threaded_irq(gpio_to_irq(pdata->uok),  
  15.                 NULL, max8903_usbin,  
  16.                 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,  
  17.                 "MAX8903 USB IN", data);  
  18.         if (ret) {  
  19.             dev_err(dev, "Cannot request irq %d for USB (%d)\n",  
  20.                     gpio_to_irq(pdata->uok), ret);  
  21.             goto err_dc_irq;  
  22.         }  
  23.     }  
  24.   
  25.     if (pdata->flt) {  
  26.         ret = request_threaded_irq(gpio_to_irq(pdata->flt),  
  27.                 NULL, max8903_fault,  
  28.                 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,  
  29.                 "MAX8903 Fault", data);  
  30.         if (ret) {  
  31.             dev_err(dev, "Cannot request irq %d for Fault (%d)\n",  
  32.                     gpio_to_irq(pdata->flt), ret);  
  33.             goto err_flt_irq;  
  34.         }  
  35.     }  
  36.   
  37.     if (pdata->chg) {  
  38.         ret = request_threaded_irq(gpio_to_irq(pdata->chg),  
  39.                 NULL, max8903_chg,  
  40.                 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,  
  41.                 "MAX8903 Fault", data);  
  42.         if (ret) {  
  43.             dev_err(dev, "Cannot request irq %d for Fault (%d)\n",  
  44.                     gpio_to_irq(pdata->flt), ret);  
  45.             goto err_chg_irq;  
  46.         }  
  47.     }  
这4个IO的中断处理函数很类似

[cpp]  view plain  copy
  1. static irqreturn_t max8903_dcin(int irq, void *_data)  
  2. {  
  3.     struct max8903_data *data = _data;  
  4.     struct max8903_pdata *pdata = data->pdata;  
  5.     bool ta_in;  
  6.   
  7.     ta_in = gpio_get_value(pdata->dok) ? false : true;   //保存当前dok值  
  8.   
  9.     if (ta_in == data->ta_in)  
  10.         return IRQ_HANDLED;  
  11.   
  12.     data->ta_in = ta_in;  
  13.     pr_info("TA(DC-IN) Charger %s.\n", ta_in ?  
  14.             "Connected" : "Disconnected");  
  15.     max8903_charger_update_status(data);      
  16.     max8903_battery_update_status(data);      
  17.     power_supply_changed(&data->psy);   //报告状态改变  
  18.     power_supply_changed(&data->bat);  
  19.     return IRQ_HANDLED;  
  20. }  
  21. static irqreturn_t max8903_usbin(int irq, void *_data)  
  22. {  
  23.     struct max8903_data *data = _data;  
  24.     struct max8903_pdata *pdata = data->pdata;  
  25.     bool usb_in;  
  26.     usb_in = gpio_get_value(pdata->uok) ? false : true//保存当前uok值  
  27.     if (usb_in == data->usb_in)  
  28.         return IRQ_HANDLED;  
  29.   
  30.     data->usb_in = usb_in;  
  31.     max8903_charger_update_status(data);  
  32.     max8903_battery_update_status(data);  
  33.     pr_info("USB Charger %s.\n", usb_in ?  
  34.             "Connected" : "Disconnected");  
  35.     power_supply_changed(&data->bat);  
  36.     power_supply_changed(&data->usb);  //报告状态改变  
  37.     return IRQ_HANDLED;  
  38. }  
  39.   
  40. static irqreturn_t max8903_fault(int irq, void *_data)  
  41. {  
  42.     struct max8903_data *data = _data;  
  43.     struct max8903_pdata *pdata = data->pdata;  
  44.     bool fault;  
  45.   
  46.     fault = gpio_get_value(pdata->flt) ? false : true;  //保存当前电池错误值  
  47.   
  48.     if (fault == data->fault)  
  49.         return IRQ_HANDLED;  
  50.   
  51.     data->fault = fault;  
  52.   
  53.     if (fault)  
  54.         dev_err(data->dev, "Charger suffers a fault and stops.\n");  
  55.     else  
  56.         dev_err(data->dev, "Charger recovered from a fault.\n");  
  57.     max8903_charger_update_status(data);  
  58.     max8903_battery_update_status(data);  
  59.     power_supply_changed(&data->psy);  
  60.     power_supply_changed(&data->bat);  
  61.     power_supply_changed(&data->usb);   //报告状态改变  
  62.     return IRQ_HANDLED;  
  63. }  
  64.   
  65. static irqreturn_t max8903_chg(int irq, void *_data)  
  66. {  
  67.     struct max8903_data *data = _data;  
  68.     struct max8903_pdata *pdata = data->pdata;  
  69.     int chg_state;  
  70.   
  71.     chg_state = gpio_get_value(pdata->chg) ? false : true;//保存电池充电状态  
  72.   
  73.     if (chg_state == data->chg_state)  
  74.         return IRQ_HANDLED;  
  75.   
  76.     data->chg_state = chg_state;  
  77.     max8903_charger_update_status(data);  
  78.     max8903_battery_update_status(data);  
  79.     power_supply_changed(&data->psy);  
  80.     power_supply_changed(&data->bat);  
  81.     power_supply_changed(&data->usb);//报告状态改变  
  82.     return IRQ_HANDLED;  
  83. }  
到了这里电池充电的流程就走完了。

你可能感兴趣的:(android电池充电以及电量检测驱动分析)