summaryrefslogtreecommitdiff
path: root/drivers/power/stmp37xx/ddi_bc_sm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power/stmp37xx/ddi_bc_sm.c')
-rw-r--r--drivers/power/stmp37xx/ddi_bc_sm.c916
1 files changed, 916 insertions, 0 deletions
diff --git a/drivers/power/stmp37xx/ddi_bc_sm.c b/drivers/power/stmp37xx/ddi_bc_sm.c
new file mode 100644
index 000000000000..c4175688d9ab
--- /dev/null
+++ b/drivers/power/stmp37xx/ddi_bc_sm.c
@@ -0,0 +1,916 @@
+/*
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+////////////////////////////////////////////////////////////////////////////////
+//! \addtogroup ddi_bc
+//! @{
+//
+// Copyright (c) 2004-2005 SigmaTel, Inc.
+//
+//! \file ddi_bc_sm.c
+//! \brief Contains the Battery Charger state machine.
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+// Includes
+////////////////////////////////////////////////////////////////////////////////
+
+#include <mach/ddi_bc.h>
+#include "ddi_bc_internal.h"
+
+#include <linux/delay.h>
+
+////////////////////////////////////////////////////////////////////////////////
+// Definitions
+////////////////////////////////////////////////////////////////////////////////
+
+// This is the minimum time we must charge before we transition from
+// the charging state to the topping off. If we reach the
+// u16ChargingThresholdCurrent charge curent before then, the battery was
+// already full so we can avoid the risk of charging it past .1C for
+// too long.
+
+#define TRANSITION_TO_TOPOFF_MINIMUM_CHARGE_TIME_mS 1 * 60 * 1000 // 1 minute
+
+////////////////////////////////////////////////////////////////////////////////
+// Variables
+////////////////////////////////////////////////////////////////////////////////
+
+// The current state.
+
+ddi_bc_State_t g_ddi_bc_State = DDI_BC_STATE_UNINITIALIZED;
+
+// This table contains pointers to the functions that implement states. The
+// table is indexed by state. Note that it's critically important for this
+// table to agree with the state enumeration in ddi_bc.h.
+
+static ddi_bc_Status_t ddi_bc_Uninitialized(void);
+static ddi_bc_Status_t ddi_bc_Broken(void);
+static ddi_bc_Status_t ddi_bc_Disabled(void);
+static ddi_bc_Status_t ddi_bc_WaitingToCharge(void);
+static ddi_bc_Status_t ddi_bc_Conditioning(void);
+static ddi_bc_Status_t ddi_bc_Charging(void);
+static ddi_bc_Status_t ddi_bc_ToppingOff(void);
+
+
+ddi_bc_Status_t(*const (stateFunctionTable[])) (void) = {
+ddi_bc_Uninitialized,
+ ddi_bc_Broken,
+ ddi_bc_Disabled,
+ ddi_bc_WaitingToCharge,
+ ddi_bc_Conditioning,
+ ddi_bc_Charging, ddi_bc_ToppingOff};
+
+// Used by states that need to watch the time.
+uint32_t g_ddi_bc_u32StateTimer = 0;
+
+/* Always attempt to charge on first 5V connection */
+bool bRestartChargeCycle = true;
+
+#ifdef CONFIG_POWER_SUPPLY_DEBUG
+static uint16_t u16ExternalBatteryPowerVoltageCheck = 0;
+#endif
+
+ddi_bc_BrokenReason_t ddi_bc_gBrokenReason = DDI_BC_BROKEN_UNINITIALIZED;
+
+////////////////////////////////////////////////////////////////////////////////
+// Code
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Transition to the Waiting to Charge state.
+//!
+//! \fntype Function
+//!
+//! This function implements the transition to the Waiting to Charge state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static void TransitionToWaitingToCharge(void)
+{
+
+ //--------------------------------------------------------------------------
+ // Reset the state timer.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_u32StateTimer = 0;
+
+ //--------------------------------------------------------------------------
+ // Reset the current ramp.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampReset();
+
+ //--------------------------------------------------------------------------
+ // Move to the Waiting to Charge state.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_State = DDI_BC_STATE_WAITING_TO_CHARGE;
+
+#ifdef CONFIG_POWER_SUPPLY_DEBUG
+ printk("Battery charger: now waiting to charge\n");
+#endif
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Transition to the Conditioning state.
+//!
+//! \fntype Function
+//!
+//! This function implements the transition to the Conditioning state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static void TransitionToConditioning(void)
+{
+
+ //--------------------------------------------------------------------------
+ // Reset the state timer.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_u32StateTimer = 0;
+
+ //--------------------------------------------------------------------------
+ // Set up the current ramp for conditioning.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampSetTarget(g_ddi_bc_Configuration.u16ConditioningCurrent);
+
+ //--------------------------------------------------------------------------
+ // Move to the Conditioning state.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_State = DDI_BC_STATE_CONDITIONING;
+
+#ifdef CONFIG_POWER_SUPPLY_DEBUG
+ printk("Battery charger: now conditioning\n");
+#endif
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Transition to the Charging state.
+//!
+//! \fntype Function
+//!
+//! This function implements the transition to the Charging state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static void TransitionToCharging(void)
+{
+
+ //--------------------------------------------------------------------------
+ // Reset the state timer.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_u32StateTimer = 0;
+
+ //--------------------------------------------------------------------------
+ // Set up the current ramp for charging.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampSetTarget(g_ddi_bc_Configuration.u16ChargingCurrent);
+
+ //--------------------------------------------------------------------------
+ // We'll be finished charging when the current flow drops below this level.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_hwSetCurrentThreshold(g_ddi_bc_Configuration.
+ u16ChargingThresholdCurrent);
+
+ //--------------------------------------------------------------------------
+ // Move to the Charging state.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_State = DDI_BC_STATE_CHARGING;
+#ifdef CONFIG_POWER_SUPPLY_DEBUG
+ printk("Battery charger: now charging\n");
+#endif
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Transition to the Topping Off state.
+//!
+//! \fntype Function
+//!
+//! This function implements the transition to the Topping Off state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static void TransitionToToppingOff(void)
+{
+
+ //--------------------------------------------------------------------------
+ // Reset the state timer.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_u32StateTimer = 0;
+
+ //--------------------------------------------------------------------------
+ // Set up the current ramp for topping off.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampSetTarget(g_ddi_bc_Configuration.u16ChargingCurrent);
+
+ //--------------------------------------------------------------------------
+ // Move to the Topping Off state.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_State = DDI_BC_STATE_TOPPING_OFF;
+
+#ifdef CONFIG_POWER_SUPPLY_DEBUG
+ printk("Battery charger: now topping off\n");
+#endif
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Transition to the Broken state.
+//!
+//! \fntype Function
+//!
+//! This function implements the transition to the Broken state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static void TransitionToBroken(void)
+{
+
+ //--------------------------------------------------------------------------
+ // Reset the state timer.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_u32StateTimer = 0;
+
+ //--------------------------------------------------------------------------
+ // Reset the current ramp.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampReset();
+
+ //--------------------------------------------------------------------------
+ // Move to the Broken state.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_State = DDI_BC_STATE_BROKEN;
+
+#ifdef CONFIG_POWER_SUPPLY_DEBUG
+ printk("Battery charger: declaring a broken battery\n");
+#endif
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Uninitialized state function.
+//!
+//! \fntype Function
+//!
+//! This function implements the Uninitialized state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static ddi_bc_Status_t ddi_bc_Uninitialized(void)
+{
+
+ //--------------------------------------------------------------------------
+ // The first order of business is to update alarms.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampUpdateAlarms();
+
+ //--------------------------------------------------------------------------
+ // Increment the state timer.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_u32StateTimer += g_ddi_bc_Configuration.u32StateMachinePeriod;
+
+ //--------------------------------------------------------------------------
+ // The only way to leave this state is with a call to ddi_bc_Initialize. So,
+ // calling this state function does nothing.
+ //--------------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Broken state function.
+//!
+//! \fntype Function
+//!
+//! This function implements the Broken state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static ddi_bc_Status_t ddi_bc_Broken(void)
+{
+
+ //--------------------------------------------------------------------------
+ // The first order of business is to update alarms.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampUpdateAlarms();
+
+ //--------------------------------------------------------------------------
+ // Increment the state timer.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_u32StateTimer += g_ddi_bc_Configuration.u32StateMachinePeriod;
+
+ //--------------------------------------------------------------------------
+ // The only way to leave this state is with a call to ddi_bc_SetFixed. So,
+ // calling this state function does nothing.
+ //--------------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Disabled state function.
+//!
+//! \fntype Function
+//!
+//! This function implements the Disabled state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static ddi_bc_Status_t ddi_bc_Disabled(void)
+{
+
+ //--------------------------------------------------------------------------
+ // The first order of business is to update alarms.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampUpdateAlarms();
+
+ //--------------------------------------------------------------------------
+ // Increment the state timer.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_u32StateTimer += g_ddi_bc_Configuration.u32StateMachinePeriod;
+
+ //--------------------------------------------------------------------------
+ // The only way to leave this state is with a call to ddi_bc_SetEnable. So,
+ // calling this state function does nothing.
+ //--------------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Waitin to Charge state function.
+//!
+//! \fntype Function
+//!
+//! This function implements the Waiting to Charge state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static ddi_bc_Status_t ddi_bc_WaitingToCharge(void)
+{
+ uint16_t u16BatteryVoltage;
+ //--------------------------------------------------------------------------
+ // The first order of business is to update alarms.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampUpdateAlarms();
+
+ //--------------------------------------------------------------------------
+ // Increment the state timer.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_u32StateTimer += g_ddi_bc_Configuration.u32StateMachinePeriod;
+
+ //--------------------------------------------------------------------------
+ // Check if the power supply is present. If not, we're not going anywhere.
+ //--------------------------------------------------------------------------
+
+ if (!ddi_bc_hwPowerSupplyIsPresent()) {
+#ifdef CONFIG_POWER_SUPPLY_DEBUG
+ u16ExternalBatteryPowerVoltageCheck = 0;
+#endif
+ return (DDI_BC_STATUS_SUCCESS);
+ }
+ //--------------------------------------------------------------------------
+ // If control arrives here, we're connected to a power supply. Have a look
+ // at the battery voltage.
+ //--------------------------------------------------------------------------
+
+ u16BatteryVoltage = ddi_bc_hwGetBatteryVoltage();
+
+#ifdef CONFIG_POWER_SUPPLY_DEBUG
+ if (u16ExternalBatteryPowerVoltageCheck) {
+ if ((u16ExternalBatteryPowerVoltageCheck - u16BatteryVoltage) >
+ 300) {
+ /*
+ * If control arrives here, battery voltage has
+ * dropped too quickly after the first charge
+ * cycle. We think an external voltage regulator is
+ * connected.
+ */
+
+ ddi_bc_gBrokenReason =
+ DDI_BC_BROKEN_EXTERNAL_BATTERY_VOLTAGE_DETECTED;
+
+ TransitionToBroken();
+
+ //----------------------------------------------------------------------
+ // Tell our caller the battery appears to be broken.
+ //----------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_BROKEN);
+ } else {
+ // reset this check
+ u16ExternalBatteryPowerVoltageCheck = 0;
+ }
+
+ }
+#endif
+
+
+ //--------------------------------------------------------------------------
+ // If the battery voltage isn't low, we don't need to be charging it. We
+ // use a 5% margin to decide.
+ //--------------------------------------------------------------------------
+
+ if (!bRestartChargeCycle) {
+ uint16_t x;
+
+ x = u16BatteryVoltage + (u16BatteryVoltage / 20);
+
+ if (x >= g_ddi_bc_Configuration.u16ChargingVoltage)
+ return (DDI_BC_STATUS_SUCCESS);
+
+ }
+
+ bRestartChargeCycle = false;
+ //--------------------------------------------------------------------------
+ // If control arrives here, the battery is low. How low?
+ //--------------------------------------------------------------------------
+
+ if (u16BatteryVoltage <
+ g_ddi_bc_Configuration.u16ConditioningThresholdVoltage) {
+
+ //----------------------------------------------------------------------
+ // If control arrives here, the battery is very low and it needs to be
+ // conditioned.
+ //----------------------------------------------------------------------
+
+ TransitionToConditioning();
+
+ } else {
+
+ //----------------------------------------------------------------------
+ // If control arrives here, the battery isn't too terribly low.
+ //----------------------------------------------------------------------
+
+ TransitionToCharging();
+
+ }
+
+ //--------------------------------------------------------------------------
+ // Return success.
+ //--------------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Conditioning state function.
+//!
+//! \fntype Function
+//!
+//! This function implements the Conditioning state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static ddi_bc_Status_t ddi_bc_Conditioning(void)
+{
+
+ //--------------------------------------------------------------------------
+ // The first order of business is to update alarms.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampUpdateAlarms();
+
+ //--------------------------------------------------------------------------
+ // If we're not under an alarm, increment the state timer.
+ //--------------------------------------------------------------------------
+
+ if (!ddi_bc_RampGetDieTempAlarm() && !ddi_bc_RampGetBatteryTempAlarm()) {
+ g_ddi_bc_u32StateTimer +=
+ g_ddi_bc_Configuration.u32StateMachinePeriod;
+ }
+ //--------------------------------------------------------------------------
+ // Check if the power supply is still around.
+ //--------------------------------------------------------------------------
+
+ if (!ddi_bc_hwPowerSupplyIsPresent()) {
+
+ //----------------------------------------------------------------------
+ // If control arrives here, the power supply has been removed. Go back
+ // and wait.
+ //----------------------------------------------------------------------
+
+ TransitionToWaitingToCharge();
+
+ //----------------------------------------------------------------------
+ // Return success.
+ //----------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+ }
+
+ //--------------------------------------------------------------------------
+ // If control arrives here, we're still connected to a power supply.
+ // Check if a battery is connected. If the voltage rises to high with only
+ // conditioning charge current, we determine that a battery is not connected.
+ // If that is not the case and a battery is connected, check
+ // if the battery voltage indicates it still needs conditioning.
+ //--------------------------------------------------------------------------
+
+// if (ddi_bc_hwGetBatteryVoltage() >= 3900) {
+ if ((ddi_bc_hwGetBatteryVoltage() >
+ g_ddi_bc_Configuration.u16ConditioningMaxVoltage) &&
+ (ddi_power_GetMaxBatteryChargeCurrent() <
+ g_ddi_bc_Configuration.u16ConditioningCurrent)) {
+ //----------------------------------------------------------------------
+ // If control arrives here, voltage has risen too quickly for so
+ // little charge being applied so their must be no battery connected.
+ //----------------------------------------------------------------------
+
+ ddi_bc_gBrokenReason = DDI_BC_BROKEN_NO_BATTERY_DETECTED;
+
+ TransitionToBroken();
+
+ //----------------------------------------------------------------------
+ // Tell our caller the battery appears to be broken.
+ //----------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_BROKEN);
+
+ }
+
+ if (ddi_bc_hwGetBatteryVoltage() >=
+ g_ddi_bc_Configuration.u16ConditioningMaxVoltage) {
+
+ //----------------------------------------------------------------------
+ // If control arrives here, this battery no longer needs conditioning.
+ //----------------------------------------------------------------------
+
+ TransitionToCharging();
+
+ //----------------------------------------------------------------------
+ // Return success.
+ //----------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+ }
+ //--------------------------------------------------------------------------
+ // Have we been in this state too long?
+ //--------------------------------------------------------------------------
+
+ if (g_ddi_bc_u32StateTimer >=
+ g_ddi_bc_Configuration.u32ConditioningTimeout) {
+
+ //----------------------------------------------------------------------
+ // If control arrives here, we've been here too long.
+ //----------------------------------------------------------------------
+
+ ddi_bc_gBrokenReason = DDI_BC_BROKEN_CHARGING_TIMEOUT;
+
+ TransitionToBroken();
+
+ //----------------------------------------------------------------------
+ // Tell our caller the battery appears to be broken.
+ //----------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_BROKEN);
+
+ }
+ //--------------------------------------------------------------------------
+ // If control arrives here, we're staying in this state. Step the current
+ // ramp.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampStep(g_ddi_bc_Configuration.u32StateMachinePeriod);
+
+ //--------------------------------------------------------------------------
+ // Return success.
+ //--------------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Charging state function.
+//!
+//! \fntype Function
+//!
+//! This function implements the Charging state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static ddi_bc_Status_t ddi_bc_Charging(void)
+{
+
+ //--------------------------------------------------------------------------
+ // This variable counts the number of times we've seen the charging status
+ // bit cleared.
+ //--------------------------------------------------------------------------
+
+ static int iStatusCount = 0;
+ //--------------------------------------------------------------------------
+ // The first order of business is to update alarms.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampUpdateAlarms();
+
+ //--------------------------------------------------------------------------
+ // If we're not under an alarm, increment the state timer.
+ //--------------------------------------------------------------------------
+
+ if (!ddi_bc_RampGetDieTempAlarm() && !ddi_bc_RampGetBatteryTempAlarm()) {
+ g_ddi_bc_u32StateTimer +=
+ g_ddi_bc_Configuration.u32StateMachinePeriod;
+ }
+ /* Check if the power supply is still around. */
+
+
+ if (!ddi_bc_hwPowerSupplyIsPresent()) {
+
+ //----------------------------------------------------------------------
+ // If control arrives here, the power supply has been removed. Go back
+ // and wait.
+ //----------------------------------------------------------------------
+
+ TransitionToWaitingToCharge();
+
+ //----------------------------------------------------------------------
+ // Return success.
+ //----------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+ }
+ //--------------------------------------------------------------------------
+ // If control arrives here, we're still connected to a power supply. We need
+ // to decide now if the battery is still charging, or if it's nearly full.
+ // If it's still charging, we'll stay in this state. Otherwise, we'll move
+ // to the Topping Off state.
+ //
+ // Most of the time, we decide that the battery is still charging simply by
+ // checking if the the actual current flow is above the charging threshold
+ // current (as indicated by the charge status bit). However, if we're
+ // still ramping up to full charging current, the hardware may still be set
+ // to deliver an amount that's less than the threshold. In that case, the
+ // charging status bit would *definitely* show a low charging current, but
+ // that doesn't mean the battery is ready for topping off.
+ //
+ // So, in summary, we will move to the Topping Off state if both of the
+ // following are true:
+ //
+ // 1) The maximum current set in the hardware is greater than the charging
+ // threshold.
+ // -AND-
+ // 2) The actual current flow is also higher than the threshold (as
+ // indicated by the charge status bit).
+ //
+ //--------------------------------------------------------------------------
+
+
+
+ ddi_bc_hwSetCurrentThreshold(g_ddi_bc_Configuration.
+ u16ChargingThresholdCurrent);
+
+
+ {
+ uint16_t u16ActualProgrammedCurrent = ddi_bc_hwGetMaxCurrent();
+
+ //----------------------------------------------------------------------
+ // Get the Maximum current that we will ramp to.
+ //----------------------------------------------------------------------
+
+ //----------------------------------------------------------------------
+ // Not all possible values are expressible by the BATTCHRG_I bitfield.
+ // The following coverts the max current value into the the closest hardware
+ // expressible bitmask equivalent. Then, it converts this back to the actual
+ // decimal current value that this bitmask represents.
+ //----------------------------------------------------------------------
+
+ uint16_t u16CurrentRampTarget = ddi_bc_RampGetTarget();
+
+ if (u16CurrentRampTarget > ddi_bc_RampGetLimit())
+ u16CurrentRampTarget = ddi_bc_RampGetLimit();
+
+ //----------------------------------------------------------------------
+ // Not all possible values are expressible by the BATTCHRG_I bitfield.
+ // The following coverts the max current value into the the closest hardware
+ // expressible bitmask equivalent. Then, it converts this back to the actual
+ // decimal current value that this bitmask represents.
+ //----------------------------------------------------------------------
+
+ u16CurrentRampTarget =
+ ddi_bc_hwExpressibleCurrent(u16CurrentRampTarget);
+
+ //----------------------------------------------------------------------
+ // We want to wait before we check the charge status bit until the ramping
+ // up is complete. Because the charge status bit is noisy, we want to
+ // disregard it until the programmed charge currint in BATTCHRG_I is well
+ // beyond the STOP_ILIMIT value.
+ //----------------------------------------------------------------------
+ if ((u16ActualProgrammedCurrent >= u16CurrentRampTarget) &&
+ !ddi_bc_hwGetChargeStatus()) {
+ uint8_t u8IlimitThresholdLimit;
+ //----------------------------------------------------------------------
+ // If control arrives here, the hardware flag is telling us that the
+ // charging current has fallen below the threshold. We need to see this
+ // happen twice consecutively before we believe it. Increment the count.
+ //----------------------------------------------------------------------
+
+ iStatusCount++;
+
+
+ u8IlimitThresholdLimit = 10;
+
+ //----------------------------------------------------------------------
+ // How many times in a row have we seen this status bit low?
+ //----------------------------------------------------------------------
+
+ if (iStatusCount >= u8IlimitThresholdLimit) {
+
+ /*
+ * If control arrives here, we've seen the
+ * CHRGSTS bit low too many times. This means
+ * it's time to move to the Topping Off state.
+ * First, reset the status count for the next
+ * time we're in this state.
+ */
+
+ iStatusCount = 0;
+
+#ifdef CONFIG_POWER_SUPPLY_DEBUG
+ u16ExternalBatteryPowerVoltageCheck =
+ ddi_bc_hwGetBatteryVoltage();
+#endif
+
+
+
+ /* Move to the Topping Off state */
+
+
+ TransitionToToppingOff();
+
+ //------------------------------------------------------------------
+ // Return success.
+ //------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+ }
+
+ } else {
+
+ //----------------------------------------------------------------------
+ // If control arrives here, the battery is still charging. Clear the
+ // status count.
+ //----------------------------------------------------------------------
+
+ iStatusCount = 0;
+
+ }
+
+ }
+
+ //--------------------------------------------------------------------------
+ // Have we been in this state too long?
+ //--------------------------------------------------------------------------
+
+ if (g_ddi_bc_u32StateTimer >= g_ddi_bc_Configuration.u32ChargingTimeout) {
+
+ //----------------------------------------------------------------------
+ // If control arrives here, we've been here too long.
+ //----------------------------------------------------------------------
+
+ ddi_bc_gBrokenReason = DDI_BC_BROKEN_CHARGING_TIMEOUT;
+
+ TransitionToBroken();
+
+ //----------------------------------------------------------------------
+ // Tell our caller the battery appears to be broken.
+ //----------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_BROKEN);
+
+ }
+ //--------------------------------------------------------------------------
+ // If control arrives here, we're staying in this state. Step the current
+ // ramp.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampStep(g_ddi_bc_Configuration.u32StateMachinePeriod);
+
+ //--------------------------------------------------------------------------
+ // Return success.
+ //--------------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Topping Off state function.
+//!
+//! \fntype Function
+//!
+//! This function implements the Topping Off state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static ddi_bc_Status_t ddi_bc_ToppingOff(void)
+{
+
+ //--------------------------------------------------------------------------
+ // The first order of business is to update alarms.
+
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampUpdateAlarms();
+
+ //--------------------------------------------------------------------------
+ // Increment the state timer. Notice that, unlike other states, we increment
+ // the state timer whether or not we're under an alarm.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_u32StateTimer += g_ddi_bc_Configuration.u32StateMachinePeriod;
+
+ //--------------------------------------------------------------------------
+ // Check if the power supply is still around.
+ //--------------------------------------------------------------------------
+
+ if (!ddi_bc_hwPowerSupplyIsPresent()) {
+
+ //----------------------------------------------------------------------
+ // If control arrives here, the power supply has been removed. Go back
+ // and wait.
+ //---------------------------------------------------------------------
+
+ TransitionToWaitingToCharge();
+
+ //----------------------------------------------------------------------
+ // Return success.
+ //----------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+ }
+
+ //--------------------------------------------------------------------------
+ // Are we done topping off?
+ //--------------------------------------------------------------------------
+ if (g_ddi_bc_u32StateTimer >= g_ddi_bc_Configuration.u32TopOffPeriod) {
+
+ //----------------------------------------------------------------------
+ // If control arrives here, we're done topping off.
+ //----------------------------------------------------------------------
+
+ TransitionToWaitingToCharge();
+
+ }
+ //--------------------------------------------------------------------------
+ // If control arrives here, we're staying in this state. Step the current
+ // ramp.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampStep(g_ddi_bc_Configuration.u32StateMachinePeriod);
+
+ //--------------------------------------------------------------------------
+ // Return success.
+ //--------------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// End of file
+////////////////////////////////////////////////////////////////////////////////
+//! @}