"battery charging" when it's not - an analysis

Werner Almesberger werner at openmoko.org
Wed May 13 02:21:40 CEST 2009


Joerg asked me why the battery claimed to be be charging when it was
in fact discharging. Here is a brief summary of what I found, in case
someone wants to rearrange these things. Sorry if all this sounds a
little cryptic :)

The situation appears to be that the PMU's charger is set to charge,
or at least the kernel reports it is, but that this doesn't reflect
the actual state of the battery.

- in general, the battery can discharge even if the PMU is delivering
  a "charge" current to the battery, since the GSM modem (and any other
  consumer fed directly from the battery [2]) can drain battery power
  without the PMU knowing.

- the "charging state" of the "battery" supposedly reported when reading
  /sys/class/power_supply/battery/status is in fact the state of the
  charger circuit in the PMU.

  It is provided by power/bq27000_battery.c:bq27000_battery_get_property
  which in turn uses the callback pdata->get_charger_online_status,
  i.e., arch/arm/mach-s3c2442/mach-gta02.c:gta02_get_charger_active_status
  which calls drivers/power/pcf50633-charger.c:pcf50633_mbc_get_status
  and reports the battery to be charging if the "MBC state" is
  PCF50633_MBC_USB_ACTIVE.

  pcf50633_mbc_get_status returns PCF50633_MBC_USB_ACTIVE if
  mbc->usb_active is set.

- usb_active itself may not be entirely reliable. In GTA02, it is set
  when

  - drivers/power/pcf50633-charger.c:pcf50633_mbc_usb_curlim_set is
    called with a non-zero charge current and the driver thus attempts
    to start the charging process.

    (Note that setting PCF50633_MBCC1_CHGENA there only has an effect
    at most once, i.e., if we booted with chgena disabled.)

    pcf50633_mbc_usb_curlim_set is called with a potentially non-zero
    current limit from a number of places:

    - the PMU bringup code surrounding
      arch/arm/mach-s3c2442/mach-gta02.c:gta02_charger_worker
      This also includes
      arch/arm/mach-s3c2442/mach-gta02.c:gta02_configure_pmu_for_charger

    - drivers/power/pcf50633-charger.c:set_usblim
      When manually setting the current limit though sysfs.

 - charging is restarted by
   drivers/power/pcf50633-charger.c:pcf50633_mbc_charging_restart
   (this is the periodic charging restart mechanism that tries to
   keep to let the PMU discharge to 96% of the battery voltage [1])

 - when the system current falls below the USB current [2].
   This happens in pcf50633_mbc_irq_handler on PCF50633_IRQ_USBLIMOFF.

 usb_active is cleared when:

 - drivers/power/pcf50633-charger.c:pcf50633_mbc_usb_curlim_set is
   called with a current limit of zero. This can happen in all the
   calls listed above, plus from
   drivers/power/pcf50633-charger.c:pcf50633_mbc_irq_handler
   when USB has gone offline.

 - one of the following conditions is signaled to
   pcf50633_mbc_irq_handler:

   - USB has been disconnected (PCF50633_IRQ_USBREM)

   - PMU charger has entered "Battery Full Mode" (PCF50633_IRQ_BATFULL)

   - system current rises above USB current (PCF50633_IRQ_USBLIMON)

  Note that there is no change of usb_active when the charger exits
  Battery Full Mode upon reaching the 96% threshold. This happens if
  MBCC1.autores is set. Both u-boot and Qi set this and the kernel
  never changes it.

- sampling usb_active (or anything derived from it) can itself be
  unreliable since the state of usb_active can change rapidly due to
  the following mechanisms:

  - drivers/power/pcf50633-charger.c:pcf50633_mbc_charging_restart
    tries to resume charging while we're in Battery Full Mode, in an
    attempt to keep the charger from discharging to 96% of the battery
    full voltage.

  - anytime the system current passes the USB current limit, usb_active
    is updated accordingly

For the above reasons, I think it's not possible to reliably determine
whether the battery is in fact charging or not by just looking at the
PMU state. It appears that you can get false positives when the
USB-to-BAT current is > 0 but is below the current drawn from consumers
directly connected to the battery, and you can get false negatives if
the charger has left Battery Full Mode after the battery voltage has
dropped to 96% of the full voltage and charging automatically resumes.

Furthermore,

[1] The mechanism that prevents discharging to 96% of the batter full
    voltage complicates all this and is in fact bogus. First of all,
    "trickle-charging" Li-Ion batteries or giving them many short
    charge bursts can reduce their life. Second, Joerg mentioned that
    the bug report that led to the implementation of this mechanism
    did in fact describe the underlying problem incorrectly and the
    battery did in fact not need any extra charging.

    The kernel-based restart mechanism can be disabled by setting
    arch/arm/mach-s3c2442/mach-gta02.c:gta02_pcf_pdata.
    charging_restart_interval to zero.

[2] The USB current is split between powering the system (i.e.,
    everything but modem, vibrator, and USB power output) and charging
    the battery. Powering the system takes priority over charging the
    battery.

    So it's correct to change the state of usb_active (being the de
    facto "the PMU is charging" indicator) whenever Isys crosses Iusb.
    However, Isys < Iusb (and the charger being in a state that allows
    charging) still doesn't mean that the battery is actually charging,
    given that

    Iusb+Ibat = Isys+Imodem+Ivibrator+Iusb_out

My conclusions:

- I recommend to get rid of the kernel-driven charger resume. Note that
  this will probably expose the lack of clearing usb_active when the
  charger circuit resumes charging upon hitting the 96% threshold.

- if a reliable indication of whether the battery is charging is desired,
  the Coloumb counter in the GTA02 battery should be used

- with a non-GTA02 battery, i.e., GTA01 or third party, it's not possible
  without additional context to determine whether the battery is being
  charged

Hope this clarifies things ;-)

- Werner



More information about the openmoko-kernel mailing list