diff options
Diffstat (limited to 'drivers/power/mxs/ddi_bc_ramp.c')
-rw-r--r-- | drivers/power/mxs/ddi_bc_ramp.c | 724 |
1 files changed, 724 insertions, 0 deletions
diff --git a/drivers/power/mxs/ddi_bc_ramp.c b/drivers/power/mxs/ddi_bc_ramp.c new file mode 100644 index 000000000000..76efc0d5c32d --- /dev/null +++ b/drivers/power/mxs/ddi_bc_ramp.c @@ -0,0 +1,724 @@ +/* + * Copyright (C) 2010 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 */ + +/* @} */ |