summaryrefslogtreecommitdiff
path: root/drivers/power/stmp37xx/ddi_bc_ramp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power/stmp37xx/ddi_bc_ramp.c')
-rw-r--r--drivers/power/stmp37xx/ddi_bc_ramp.c724
1 files changed, 724 insertions, 0 deletions
diff --git a/drivers/power/stmp37xx/ddi_bc_ramp.c b/drivers/power/stmp37xx/ddi_bc_ramp.c
new file mode 100644
index 000000000000..1de3a53259f8
--- /dev/null
+++ b/drivers/power/stmp37xx/ddi_bc_ramp.c
@@ -0,0 +1,724 @@
+/*
+ * 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_ramp.c
+//! \brief Contains the Battery Charger current ramp controller.
+//! \date 06/2005
+//!
+//! This file contains Battery Charger current ramp controller.
+//!
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+// Includes and external references
+////////////////////////////////////////////////////////////////////////////////
+
+#include <mach/ddi_bc.h>
+#include "ddi_bc_internal.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// Definitions
+////////////////////////////////////////////////////////////////////////////////
+
+//! This is the control structure for the current ramp.
+
+typedef struct _ddi_bc_RampControl {
+
+ uint32_t u32AccumulatedTime;
+
+ //!< The accumulated time since we last changed the actual
+ //!< current setting in the hardware. If the time between
+ //!< steps is quite short, we may have to wait for several steps
+ //!< before we can actually change the hardware setting.
+
+ uint16_t u16Target;
+
+ //!< The target current, regardless of expressibility.
+
+ uint16_t u16Limit;
+
+ //!< The current limit, regardless of expressibility.
+
+ uint8_t dieTempAlarm:1;
+
+ //!< Indicates if we are operating under a die temperature
+ //!< alarm.
+
+ uint8_t batteryTempAlarm:1;
+
+ //!< Indicates if we are operating under a battery temperature
+ //!< alarm.
+
+ uint8_t ambientTempAlarm:1;
+
+ //!< Indicates if we are operating under an ambient temperature
+ //!< alarm.
+
+} ddi_bc_RampControl_t;
+
+////////////////////////////////////////////////////////////////////////////////
+// Variables
+////////////////////////////////////////////////////////////////////////////////
+
+//! This structure contains control information for the current ramp.
+
+static ddi_bc_RampControl_t g_RampControl;
+
+////////////////////////////////////////////////////////////////////////////////
+// Code
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Reset the current ramp.
+//!
+//! \fntype Function
+//!
+//! This function resets the current ramp.
+//!
+//! Note that this function does NOT reset the temperature alarms or the current
+//! limit. Those can only be changed explicitly.
+//!
+////////////////////////////////////////////////////////////////////////////////
+void ddi_bc_RampReset()
+{
+
+ //--------------------------------------------------------------------------
+ // Reset the control structure.
+ //--------------------------------------------------------------------------
+
+ g_RampControl.u32AccumulatedTime = 0;
+ g_RampControl.u16Target = 0;
+
+ //--------------------------------------------------------------------------
+ // Step the ramp. Note that we don't care if this function returns an error.
+ // We're stepping the ramp to make sure it takes immediate effect, if
+ // possible. But, for example, if the Battery Charger is not yet
+ // initialized, it doesn't matter.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampStep(0);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Set the target current.
+//!
+//! \fntype Function
+//!
+//! This function sets the target current and implements it immediately.
+//!
+//! Note that this function does NOT reset the temperature alarms. Those can
+//! only be reset explicitly.
+//!
+//! \param[in] u16Target The target current.
+//!
+//! \retval The expressible version of the target.
+//!
+////////////////////////////////////////////////////////////////////////////////
+uint16_t ddi_bc_RampSetTarget(uint16_t u16Target)
+{
+
+ //--------------------------------------------------------------------------
+ // Set the target.
+ //--------------------------------------------------------------------------
+
+ g_RampControl.u16Target = u16Target;
+
+ //--------------------------------------------------------------------------
+ // Step the ramp. Note that we don't care if this function returns an error.
+ // We're stepping the ramp to make sure it takes immediate effect, if
+ // possible. But, for example, if the Battery Charger is not yet
+ // initialized, it doesn't matter.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampStep(0);
+
+ //--------------------------------------------------------------------------
+ // Compute and return the expressible target.
+ //--------------------------------------------------------------------------
+
+ return (ddi_bc_hwExpressibleCurrent(u16Target));
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Report the target.
+//!
+//! \fntype Function
+//!
+//! This function reports the target.
+//!
+//! \retval The target.
+//!
+////////////////////////////////////////////////////////////////////////////////
+uint16_t ddi_bc_RampGetTarget(void)
+{
+
+ //--------------------------------------------------------------------------
+ // Return the target.
+ //--------------------------------------------------------------------------
+
+ return (g_RampControl.u16Target);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Set the current limit.
+//!
+//! \fntype Function
+//!
+//! This function sets the current limit and implements it immediately.
+//!
+//! \param[in] u16Limit The current limit.
+//!
+//! \retval The expressible version of the limit.
+//!
+////////////////////////////////////////////////////////////////////////////////
+uint16_t ddi_bc_RampSetLimit(uint16_t u16Limit)
+{
+
+ //--------------------------------------------------------------------------
+ // Set the limit.
+ //--------------------------------------------------------------------------
+
+ g_RampControl.u16Limit = u16Limit;
+
+ //--------------------------------------------------------------------------
+ // Step the ramp. Note that we don't care if this function returns an error.
+ // We're stepping the ramp to make sure it takes immediate effect, if
+ // possible. But, for example, if the Battery Charger is not yet
+ // initialized, it doesn't matter.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampStep(0);
+
+ //--------------------------------------------------------------------------
+ // Compute and return the expressible limit.
+ //--------------------------------------------------------------------------
+
+ return (ddi_bc_hwExpressibleCurrent(u16Limit));
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Report the current limit.
+//!
+//! \fntype Function
+//!
+//! This function reports the current limit.
+//!
+//! \retval The current limit.
+//!
+////////////////////////////////////////////////////////////////////////////////
+uint16_t ddi_bc_RampGetLimit(void)
+{
+
+ //--------------------------------------------------------------------------
+ // Return the current limit.
+ //--------------------------------------------------------------------------
+
+ return (g_RampControl.u16Limit);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Update alarms.
+//!
+//! \fntype Function
+//!
+//! This function checks for all alarms and updates the current ramp
+//! accordingly.
+//!
+////////////////////////////////////////////////////////////////////////////////
+void ddi_bc_RampUpdateAlarms()
+{
+
+ // Set to true if something changed and we need to step the ramp right away.
+
+ int iStepTheRamp = 0;
+
+ //--------------------------------------------------------------------------
+ // Are we monitoring die temperature?
+ //--------------------------------------------------------------------------
+
+ if (g_ddi_bc_Configuration.monitorDieTemp) {
+
+ //----------------------------------------------------------------------
+ // Get the die temperature range.
+ //----------------------------------------------------------------------
+
+ int16_t i16Low;
+ int16_t i16High;
+
+ ddi_bc_hwGetDieTemp(&i16Low, &i16High);
+
+ //----------------------------------------------------------------------
+ // Now we need to decide if it's time to raise or lower the alarm. The
+ // first question to ask is: Were we already under an alarm?
+ //----------------------------------------------------------------------
+
+ if (g_RampControl.dieTempAlarm) {
+
+ //------------------------------------------------------------------
+ // If control arrives here, we were already under an alarm. We'll
+ // change that if the high end of the temperature range drops below
+ // the low temperature mark.
+ //------------------------------------------------------------------
+
+ if (i16High < g_ddi_bc_Configuration.u8DieTempLow) {
+
+ //--------------------------------------------------------------
+ // If control arrives here, we're safe now. Drop the alarm.
+ //--------------------------------------------------------------
+
+ g_RampControl.dieTempAlarm = 0;
+
+ iStepTheRamp = !0;
+
+#ifdef CONFIG_POWER_SUPPLY_DEBUG
+ printk("Battery charger: releasing "
+ "die temp alarm: [%d, %d] < %d\r\n",
+ (int32_t) i16Low, (int32_t) i16High,
+ (int32_t) g_ddi_bc_Configuration.
+ u8DieTempLow);
+#endif
+
+ }
+
+ } else {
+
+ //------------------------------------------------------------------
+ // If control arrives here, we were not under an alarm. We'll change
+ // that if the high end of the temperature range rises above the
+ // high temperature mark.
+ //------------------------------------------------------------------
+
+ if (i16High >= g_ddi_bc_Configuration.u8DieTempHigh) {
+
+ //--------------------------------------------------------------
+ // If control arrives here, we're running too hot. Raise the
+ // alarm.
+ //--------------------------------------------------------------
+
+ g_RampControl.dieTempAlarm = 1;
+
+ iStepTheRamp = !0;
+
+#ifdef CONFIG_POWER_SUPPLY_DEBUG
+ printk("Battery charger: declaring "
+ "die temp alarm: [%d, %d] >= %d\r\n",
+ (int32_t) i16Low, (int32_t) i16High,
+ (int32_t) g_ddi_bc_Configuration.
+ u8DieTempLow);
+#endif
+ }
+
+ }
+
+ }
+ //--------------------------------------------------------------------------
+ // Are we monitoring battery temperature?
+ //--------------------------------------------------------------------------
+
+ if (g_ddi_bc_Configuration.monitorBatteryTemp) {
+
+ ddi_bc_Status_t status;
+
+ //----------------------------------------------------------------------
+ // Get the battery temperature reading.
+ //----------------------------------------------------------------------
+
+ uint16_t u16Reading;
+
+ status = ddi_bc_hwGetBatteryTemp(&u16Reading);
+
+ //----------------------------------------------------------------------
+ // If there was a problem, then we ignore the reading. Otherwise, let's
+ // have a look.
+ //----------------------------------------------------------------------
+
+ if (status == DDI_BC_STATUS_SUCCESS) {
+
+ //------------------------------------------------------------------
+ // Now we need to decide if it's time to raise or lower the alarm.
+ // The first question to ask is: Were we already under an alarm?
+ //------------------------------------------------------------------
+
+ if (g_RampControl.batteryTempAlarm) {
+
+ //--------------------------------------------------------------
+ // If control arrives here, we were already under an alarm.
+ // We'll change that if the reading drops below the low mark.
+ //--------------------------------------------------------------
+
+ if (u16Reading <
+ g_ddi_bc_Configuration.u16BatteryTempLow) {
+
+ //----------------------------------------------------------
+ // If control arrives here, we're safe now. Drop the alarm.
+ //----------------------------------------------------------
+
+ g_RampControl.batteryTempAlarm = 0;
+
+ iStepTheRamp = !0;
+
+ }
+
+ } else {
+
+ //--------------------------------------------------------------
+ // If control arrives here, we were not under an alarm. We'll
+ // change that if the reading rises above the high mark.
+ //--------------------------------------------------------------
+
+ if (u16Reading >=
+ g_ddi_bc_Configuration.u16BatteryTempHigh) {
+
+ //----------------------------------------------------------
+ // If control arrives here, we're running too hot. Raise the
+ // alarm.
+ //----------------------------------------------------------
+
+ g_RampControl.batteryTempAlarm = 1;
+
+ iStepTheRamp = !0;
+
+ }
+
+ }
+
+ }
+
+ }
+ //--------------------------------------------------------------------------
+ // Do we need to step the ramp?
+ //--------------------------------------------------------------------------
+
+ if (iStepTheRamp)
+ ddi_bc_RampStep(0);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Reports the state of the die temperature alarm.
+//!
+//! \fntype Function
+//!
+//! This function reports the state of the die temperature alarm.
+//!
+//! \retval The state of the die temperature alarm.
+//!
+////////////////////////////////////////////////////////////////////////////////
+int ddi_bc_RampGetDieTempAlarm(void)
+{
+ return (g_RampControl.dieTempAlarm);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Reports the state of the battery temperature alarm.
+//!
+//! \fntype Function
+//!
+//! This function reports the state of the battery temperature alarm.
+//!
+//! \retval The state of the battery temperature alarm.
+//!
+////////////////////////////////////////////////////////////////////////////////
+int ddi_bc_RampGetBatteryTempAlarm(void)
+{
+ return (g_RampControl.batteryTempAlarm);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Reports the state of the ambient temperature alarm.
+//!
+//! \fntype Function
+//!
+//! This function reports the state of the ambient temperature alarm.
+//!
+//! \retval The state of the ambient temperature alarm.
+//!
+////////////////////////////////////////////////////////////////////////////////
+int ddi_bc_RampGetAmbientTempAlarm(void)
+{
+ return (g_RampControl.ambientTempAlarm);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Step the current ramp.
+//!
+//! \fntype Function
+//!
+//! This function steps the current ramp forward through the given amount of time.
+//!
+//! \param[in] u32Time The time increment to add.
+//!
+//! \retval DDI_BC_STATUS_SUCCESS If the operation succeeded.
+//! \retval DDI_BC_STATUS_NOT_INITIALIZED If the Battery Charger is not yet
+//! initialized.
+//!
+////////////////////////////////////////////////////////////////////////////////
+ddi_bc_Status_t ddi_bc_RampStep(uint32_t u32Time)
+{
+
+ uint16_t u16MaxNow;
+ uint16_t u16Target;
+ uint16_t u16Cart;
+ int32_t i32Delta;
+
+ //--------------------------------------------------------------------------
+ // Make sure the Battery Charger is initialized.
+ //--------------------------------------------------------------------------
+
+ if (g_ddi_bc_State == DDI_BC_STATE_UNINITIALIZED) {
+ return (DDI_BC_STATUS_NOT_INITIALIZED);
+ }
+ //--------------------------------------------------------------------------
+ // Figure out how much current the hardware is set to draw right now.
+ //--------------------------------------------------------------------------
+
+ u16MaxNow = ddi_bc_hwGetMaxCurrent();
+
+ //--------------------------------------------------------------------------
+ // Start with the target.
+ //--------------------------------------------------------------------------
+
+ u16Target = g_RampControl.u16Target;
+
+ //--------------------------------------------------------------------------
+ // Check the target against the hard limit.
+ //--------------------------------------------------------------------------
+
+ if (u16Target > g_RampControl.u16Limit)
+ u16Target = g_RampControl.u16Limit;
+
+ //--------------------------------------------------------------------------
+ // Check if the die temperature alarm is active.
+ //--------------------------------------------------------------------------
+
+ if (g_RampControl.dieTempAlarm) {
+
+ //----------------------------------------------------------------------
+ // If control arrives here, we are under a die temperature alarm. Clamp
+ // the target current.
+ //----------------------------------------------------------------------
+
+ if (u16Target > g_ddi_bc_Configuration.u16DieTempSafeCurrent) {
+ u16Target =
+ g_ddi_bc_Configuration.u16DieTempSafeCurrent;
+ }
+
+ }
+ //--------------------------------------------------------------------------
+ // Check if the battery temperature alarm is active.
+ //--------------------------------------------------------------------------
+
+ if (g_RampControl.batteryTempAlarm) {
+
+ //----------------------------------------------------------------------
+ // If control arrives here, we are under a battery temperature alarm.
+ // Clamp the target current.
+ //----------------------------------------------------------------------
+
+ if (u16Target >
+ g_ddi_bc_Configuration.u16BatteryTempSafeCurrent) {
+ u16Target =
+ g_ddi_bc_Configuration.u16BatteryTempSafeCurrent;
+ }
+
+ }
+ //--------------------------------------------------------------------------
+ // Now we know the target current. Figure out what is actually expressible
+ // in the hardware.
+ //--------------------------------------------------------------------------
+
+ u16Target = ddi_bc_hwExpressibleCurrent(u16Target);
+
+ //--------------------------------------------------------------------------
+ // Compute the difference between the expressible target and what's actually
+ // set in the hardware right now.
+ //--------------------------------------------------------------------------
+
+ i32Delta = ((int32_t) u16Target) - ((int32_t) u16MaxNow);
+
+ //--------------------------------------------------------------------------
+ // Check if the delta is zero.
+ //--------------------------------------------------------------------------
+
+ if (i32Delta == 0) {
+
+ //----------------------------------------------------------------------
+ // If control arrives here, there is no difference between what we want
+ // and what's set in the hardware.
+ //
+ // Before we leave, though, we don't want to leave any accumulated time
+ // laying around for the next ramp up. Zero it out.
+ //----------------------------------------------------------------------
+
+ g_RampControl.u32AccumulatedTime = 0;
+
+ //----------------------------------------------------------------------
+ // Return success.
+ //----------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+ }
+ //--------------------------------------------------------------------------
+ // Check if the delta is negative.
+ //--------------------------------------------------------------------------
+
+ if (i32Delta < 0) {
+
+ //----------------------------------------------------------------------
+ // If control arrives here, the new target is lower than what's
+ // currently set in the hardware. Since that means we're *reducing* the
+ // current draw, we can do it right now. Just gimme a sec here...
+ //----------------------------------------------------------------------
+
+ ddi_bc_hwSetMaxCurrent(u16Target);
+
+#ifdef CONFIG_POWER_SUPPLY_DEBUG
+ printk("Battery charger: setting max charge "
+ "current to: %hdmA\r\n", u16Target);
+#endif
+
+ //----------------------------------------------------------------------
+ // Flip the power switch on the charging hardware according to the new
+ // current setting.
+ //----------------------------------------------------------------------
+
+ ddi_bc_hwSetChargerPower(u16Target != 0);
+
+ //----------------------------------------------------------------------
+ // We don't want to leave any accumulated time laying around for the
+ // next ramp up. Zero it out.
+ //----------------------------------------------------------------------
+
+ g_RampControl.u32AccumulatedTime = 0;
+
+ //----------------------------------------------------------------------
+ // Return success.
+ //----------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+ }
+ //--------------------------------------------------------------------------
+ // If control arrives here, the target current is higher than what's set in
+ // the hardware right now. That means we're going to ramp it up. To do that,
+ // we're going to "buy" more milliamps by "spending" milliseconds of time.
+ // Add the time we've "banked" to the time we've been credited in this call.
+ //--------------------------------------------------------------------------
+
+ u32Time += g_RampControl.u32AccumulatedTime;
+
+ //--------------------------------------------------------------------------
+ // Now we know how much we can spend. How much current will it buy?
+ //--------------------------------------------------------------------------
+
+ u16Cart = (g_ddi_bc_Configuration.u16CurrentRampSlope * u32Time) / 1000;
+
+ //--------------------------------------------------------------------------
+ // Check how the current we can afford stacks up against the target we want.
+ //--------------------------------------------------------------------------
+
+ if ((u16MaxNow + u16Cart) < u16Target) {
+
+ //----------------------------------------------------------------------
+ // If control arrives here, we can't afford to buy all the current we
+ // want. Compute the maximum we can afford, and then figure out what we
+ // can actually express in the hardware.
+ //----------------------------------------------------------------------
+
+ u16Target = ddi_bc_hwExpressibleCurrent(u16MaxNow + u16Cart);
+
+ //----------------------------------------------------------------------
+ // Check if the result isn't actually different from what's set in the
+ // the hardware right now.
+ //----------------------------------------------------------------------
+
+ if (u16Target == u16MaxNow) {
+
+ //------------------------------------------------------------------
+ // If control arrives here, we are so poor that we can't yet afford
+ // to buy enough current to make a change in the expressible
+ // hardware setting. Since we didn't spend any of our time, put the
+ // new balance back in the bank.
+ //------------------------------------------------------------------
+
+ g_RampControl.u32AccumulatedTime = u32Time;
+
+ //------------------------------------------------------------------
+ // Leave dispiritedly.
+ //------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+ }
+
+ }
+ //--------------------------------------------------------------------------
+ // If control arrives here, we can afford to buy enough current to get us
+ // all the way to the target. Set it.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_hwSetMaxCurrent(u16Target);
+
+#ifdef CONFIG_POWER_SUPPLY_DEBUG
+ printk("Battery charger: setting max charge"
+ "current to: %hdmA\r\n", u16Target);
+#endif
+
+ //--------------------------------------------------------------------------
+ // Flip the power switch on the charging hardware according to the new
+ // current setting.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_hwSetChargerPower(u16Target != 0);
+
+ //--------------------------------------------------------------------------
+ // We're at the target, so we're finished buying current. Zero out the
+ // account.
+ //--------------------------------------------------------------------------
+
+ g_RampControl.u32AccumulatedTime = 0;
+
+ //--------------------------------------------------------------------------
+ // Return success.
+ //--------------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// End of file
+////////////////////////////////////////////////////////////////////////////////
+//! @}