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

平台: cpu        飞思卡尔imx6q 4核

充电芯片     MAX8903

电量检测芯片  MAX11801

android版本  android4.0

一、电量检测

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

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

  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的值就可以了,对于触摸屏部分我们并不需要,因此主要是下面几个函数

  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函数我们已经得到了理论计算的电池的电压,但实际应用中由于分压电阻误差,焊接问题等,这个电压会有一定的误差因此需要一个校正函数

  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. }

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

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

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

  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. }

检测电池状态函数

  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设备文件。
来看设备文件的建立过程

  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)个操作分别为

  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()这个函数来读取的

  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;//电量小于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文件系统的设备文件,创建代码为

  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");

设备文件的实现代码为

  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阶段增加这么三行

  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_BDC插入

CHG_STATUS1_B 充电状态

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

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

  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. };
  1. platform_device_register(&sabresd_max8903_charger_1);

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

申请IO

  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充电的设备文件

  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充电的设备文件

  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. }

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

  1. static enum power_supply_property max8903_charger_props[] = {
  2. POWER_SUPPLY_PROP_ONLINE,
  3. };

操作函数也很简单

  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中断

  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的中断处理函数很类似

  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电池充电以及电量检测驱动分析的更多相关文章

  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开发中xib和Storyboard中需要注意的事项

    使用xib注意事项: 1.只有自带view的控件才可以使用xib,因为它本身就是一个view 2.在使用可视化控件添加属性(代码)时候,如果删除了属性代码,一定要在xib上解除关联(不然会崩溃) 3. ...

  2. [置顶] java的foreach循环

    foreach语句是java5之后的新特征之一,在循环遍历数组.集合方面更加简洁. 使用foreach循环遍历数组和集合时,无需获得数组和集合的长度,无须根据索引来访问数组元素和集合元素,foreac ...

  3. SQL Server 基础 01 数据库、表操作

    对着书慢慢学习,一天一点点! 数据库操作 (create.alter.drop)  --3-3-1 /create database 语句创建数据库 create database testSQL - ...

  4. [转]使用xftp连接centos6.5

    首先要在windows上安装xftp软件,这个是傻瓜式操作就不说了 安装完成之后,在centos上查看是否装了xftpd服务,[root@centos Desktop]# rpm -qa | grep ...

  5. ZOJ 3483 简单if-else

    提醒:答案要约分,不然会错! #include<iostream> #include<cstdio> #include<cstring> #include<a ...

  6. initialize和init区别

    Objective-C很有趣的一个地方是,它非常非常像C.实际上,它就是C语言加上一些其他扩展和一个运行时间(runtime). 有了这个在每个Objective-C程序中都会起作用的附加运行时间,给 ...

  7. win10 系统下获取系统版本号为6.2的问题(manifest如何写)

    近期赶时髦升级了win10,用着挺爽.但是某天在测试一个bug时发现要对win10做特殊处理,于是直接调用了GetVersionEx,并取出版本号进行判断,但是发现得到的版本竟然是6.2.当时就被雷到 ...

  8. Fedora20安装完Nvidia后启动一直黑屏解决办法。

    安装完Fedora20后,把Nvidia驱动装上后重起机器一直黑屏时,切换到命令行下:Alt+F2  登陆上去,然后直接更新: su -c ‘yum update’ ,再重起就OK了.

  9. 查询SystemFeature的方法

    查询SystemFeature的方法可以在adb shell下敲如下的命令: dumpsys package 然后搜feature关键字. 例如,我的平台的SystemFeature,如下所示: Fe ...

  10. lua语法 - 基础篇

    1. 注释 单行注释:--,类似于C++的// 多行注释:--[[ ... ]],类似于C++的/*...*/ 2. 语句 分隔符:分号或者空格,一般多行写一起,建议用分号 语句块:do ... en ...