Logo Search packages:      
Sourcecode: linux-fsl-imx51 version File versions  Download package

ddi_bc_ramp.c

Go to the documentation of this file.
/*
 * 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.

00041 typedef struct _ddi_bc_RampControl {

      uint32_t u32AccumulatedTime;

00045       //!< 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;

00052       //!< The target current, regardless of expressibility.

      uint16_t u16Limit;

00056       //!< The current limit, regardless of expressibility.

      uint8_t dieTempAlarm:1;

00060       //!< Indicates if we are operating under a die temperature
      //!< alarm.

      uint8_t batteryTempAlarm:1;

00065       //!< Indicates if we are operating under a battery temperature
      //!< alarm.

      uint8_t ambientTempAlarm:1;

00070       //!< Indicates if we are operating under an ambient temperature
      //!< alarm.

} ddi_bc_RampControl_t;

////////////////////////////////////////////////////////////////////////////////
// Variables
////////////////////////////////////////////////////////////////////////////////

//! This structure contains control information for the current ramp.

00081 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.
//!
////////////////////////////////////////////////////////////////////////////////
00099 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.
//!
////////////////////////////////////////////////////////////////////////////////
00136 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.
//!
////////////////////////////////////////////////////////////////////////////////
00173 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.
//!
////////////////////////////////////////////////////////////////////////////////
00197 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.
//!
////////////////////////////////////////////////////////////////////////////////
00234 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.
//!
////////////////////////////////////////////////////////////////////////////////
00255 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.
//!
////////////////////////////////////////////////////////////////////////////////
00435 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.
//!
////////////////////////////////////////////////////////////////////////////////
00451 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.
//!
////////////////////////////////////////////////////////////////////////////////
00467 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.
//!
////////////////////////////////////////////////////////////////////////////////
00487 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
////////////////////////////////////////////////////////////////////////////////
//! @}

Generated by  Doxygen 1.6.0   Back to index