summaryrefslogtreecommitdiff
path: root/drivers/power/mxs/ddi_bc_sm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power/mxs/ddi_bc_sm.c')
-rw-r--r--drivers/power/mxs/ddi_bc_sm.c918
1 files changed, 918 insertions, 0 deletions
diff --git a/drivers/power/mxs/ddi_bc_sm.c b/drivers/power/mxs/ddi_bc_sm.c
new file mode 100644
index 000000000000..6626ed82c192
--- /dev/null
+++ b/drivers/power/mxs/ddi_bc_sm.c
@@ -0,0 +1,918 @@
+/*
+ * Copyright (C) 2010 Freescale Semiconductor, Inc.
+ */
+
+/*
+ * 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;
+
+/* Always attempt to charge on first 5V connection */
+bool bRestartChargeCycle = true;
+
+#ifdef CONFIG_POWER_SUPPLY_DEBUG
+static uint16_t u16ExternalBatteryPowerVoltageCheck;
+#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;
+
+ pr_info("charger------ ddi_bc_gBrokenReason=%d\n",
+ ddi_bc_gBrokenReason);
+#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;
+ /* -------------------------------------------------------------------------- */
+ /* 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 */
+
+/* @} */