summaryrefslogtreecommitdiff
path: root/drivers/power
diff options
context:
space:
mode:
authorRob Herring <r.herring@freescale.com>2009-10-19 14:43:19 -0500
committerAlejandro Gonzalez <alex.gonzalez@digi.com>2010-02-12 17:19:16 +0100
commitcdde68e3a7d4cbf4701005ab6032366e76009419 (patch)
tree5690552665f0b7843e6552e4d5fe7b63cbc78f51 /drivers/power
parent57d1417ea543b83760b3fd76a46b9d29deb2e444 (diff)
ENGR00117389 Port 5.0.0 release to 2.6.31
This is i.MX BSP 5.0.0 release ported to 2.6.31 Signed-off-by: Rob Herring <r.herring@freescale.com> Signed-off-by: Alan Tull <r80115@freescale.com> Signed-off-by: Xinyu Chen <xinyu.chen@freescale.com>
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/Kconfig7
-rw-r--r--drivers/power/Makefile1
-rw-r--r--drivers/power/stmp37xx/Makefile8
-rw-r--r--drivers/power/stmp37xx/ddi_bc_api.c566
-rw-r--r--drivers/power/stmp37xx/ddi_bc_hw.c474
-rw-r--r--drivers/power/stmp37xx/ddi_bc_hw.h93
-rw-r--r--drivers/power/stmp37xx/ddi_bc_init.c204
-rw-r--r--drivers/power/stmp37xx/ddi_bc_internal.h52
-rw-r--r--drivers/power/stmp37xx/ddi_bc_ramp.c724
-rw-r--r--drivers/power/stmp37xx/ddi_bc_ramp.h50
-rw-r--r--drivers/power/stmp37xx/ddi_bc_sm.c1122
-rw-r--r--drivers/power/stmp37xx/ddi_bc_sm.h46
-rw-r--r--drivers/power/stmp37xx/ddi_power_battery.c998
-rw-r--r--drivers/power/stmp37xx/ddi_power_battery.h67
-rw-r--r--drivers/power/stmp37xx/linux.c623
15 files changed, 5035 insertions, 0 deletions
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index bdbc4f73fcdc..e7b1040b410e 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -103,4 +103,11 @@ config CHARGER_PCF50633
help
Say Y to include support for NXP PCF50633 Main Battery Charger.
+config BATTERY_STMP3XXX
+ tristate "Sigmatel STMP3xxx SoC battery charger driver"
+ depends on ARCH_STMP3XXX
+ help
+ Say Y to enable support for the battery charger state machine
+ for the Sigmatel STMP3xxx based SoC's.
+
endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 380d17c9ae29..0d6b10db79b7 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -28,3 +28,4 @@ obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
+obj-$(CONFIG_BATTERY_STMP3XXX) += stmp37xx/
diff --git a/drivers/power/stmp37xx/Makefile b/drivers/power/stmp37xx/Makefile
new file mode 100644
index 000000000000..25b340e5b014
--- /dev/null
+++ b/drivers/power/stmp37xx/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the STMP3xxx battery charger driver
+#
+
+obj-$(CONFIG_BATTERY_STMP3XXX) += stmp3xxx-battery.o
+
+stmp3xxx-battery-objs := ddi_bc_api.o ddi_bc_hw.o ddi_bc_init.o \
+ ddi_bc_ramp.o ddi_bc_sm.o ddi_power_battery.o linux.o
diff --git a/drivers/power/stmp37xx/ddi_bc_api.c b/drivers/power/stmp37xx/ddi_bc_api.c
new file mode 100644
index 000000000000..5fd062ec4eb9
--- /dev/null
+++ b/drivers/power/stmp37xx/ddi_bc_api.c
@@ -0,0 +1,566 @@
+/*
+ * 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_api.c
+//! \brief Contains the Battery Charger API.
+//! \date 06/2005
+//!
+//! This file contains Battery Charger API.
+//!
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+// Includes
+////////////////////////////////////////////////////////////////////////////////
+
+#include "ddi_bc_internal.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// Variables
+////////////////////////////////////////////////////////////////////////////////
+
+//! This structure holds the current Battery Charger configuration.
+
+ddi_bc_Cfg_t g_ddi_bc_Configuration;
+
+extern uint32_t g_ddi_bc_u32StateTimer;
+extern ddi_bc_BrokenReason_t ddi_bc_gBrokenReason;
+extern bool bRestartChargeCycle;
+
+////////////////////////////////////////////////////////////////////////////////
+// Code
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Report the Battery Charger configuration.
+//!
+//! \fntype Function
+//!
+//! This function reports the Battery Charger configuration.
+//!
+//! Note that, if the Battery Charger has not yet been initialized, the data
+//! returned by this function is unknown.
+//!
+//! \param[in,out] pCfg A pointer to a structure that will receive the data.
+//!
+////////////////////////////////////////////////////////////////////////////////
+void ddi_bc_QueryCfg(ddi_bc_Cfg_t * pCfg)
+{
+
+ //--------------------------------------------------------------------------
+ // Return the current configuration.
+ //--------------------------------------------------------------------------
+
+ *pCfg = g_ddi_bc_Configuration;
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Shut down the Battery Charger.
+//!
+//! \fntype Function
+//!
+//! This function immediately shuts down the Battery Charger hardware and
+//! returns the state machine to the Uninitialized state. Use this function to
+//! safely “mummify” the battery charger before retiring it from memory.
+//!
+////////////////////////////////////////////////////////////////////////////////
+void ddi_bc_ShutDown()
+{
+
+ //--------------------------------------------------------------------------
+ // Reset the current ramp.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampReset();
+
+ //--------------------------------------------------------------------------
+ // Move to the Uninitialized state.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_State = DDI_BC_STATE_UNINITIALIZED;
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Advances the state machine.
+//!
+//! \fntype Function
+//!
+//! This function advances the state machine.
+//!
+//! \retval DDI_BC_STATUS_SUCCESS If all goes well
+//! \retval DDI_BC_STATUS_NOT_INITIALIZED If the Battery Charger is not yet
+//! initialized.
+//! \retval DDI_BC_STATUS_BROKEN If the battery violated a time-out
+//! and has been declared broken.
+//!
+////////////////////////////////////////////////////////////////////////////////
+ddi_bc_Status_t ddi_bc_StateMachine()
+{
+
+ //--------------------------------------------------------------------------
+ // Check if we've been initialized yet.
+ //--------------------------------------------------------------------------
+
+ if (g_ddi_bc_State == DDI_BC_STATE_UNINITIALIZED) {
+ return (DDI_BC_STATUS_NOT_INITIALIZED);
+ }
+ //--------------------------------------------------------------------------
+ // Execute the function for the current state.
+ //--------------------------------------------------------------------------
+
+ return (stateFunctionTable[g_ddi_bc_State] ());
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Get the Battery Charger's current state.
+//!
+//! \fntype Function
+//!
+//! This function returns the current state.
+//!
+//! \retval The current state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+ddi_bc_State_t ddi_bc_GetState()
+{
+ //--------------------------------------------------------------------------
+ // Return the current state.
+ //--------------------------------------------------------------------------
+
+ return (g_ddi_bc_State);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Disable the Battery Charger.
+//!
+//! \fntype Function
+//!
+//! This function forces the Battery Charger into the Disabled state.
+//!
+//! \retval DDI_BC_STATUS_SUCCESS If all goes well
+//! \retval DDI_BC_STATUS_NOT_INITIALIZED If the Battery Charger is not yet
+//! initialized.
+//!
+////////////////////////////////////////////////////////////////////////////////
+ddi_bc_Status_t ddi_bc_SetDisable()
+{
+
+ //--------------------------------------------------------------------------
+ // Check if we've been initialized yet.
+ //--------------------------------------------------------------------------
+
+ if (g_ddi_bc_State == DDI_BC_STATE_UNINITIALIZED) {
+ return (DDI_BC_STATUS_NOT_INITIALIZED);
+ }
+ //--------------------------------------------------------------------------
+ // Check if we've been initialized yet.
+ //--------------------------------------------------------------------------
+
+ if (g_ddi_bc_State == DDI_BC_STATE_BROKEN) {
+ return (DDI_BC_STATUS_BROKEN);
+ }
+ //--------------------------------------------------------------------------
+ // Reset the current ramp. This will jam the current to zero and power off
+ // the charging hardware.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampReset();
+
+ //--------------------------------------------------------------------------
+ // Reset the state timer.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_u32StateTimer = 0;
+
+ //--------------------------------------------------------------------------
+ // Move to the Disabled state.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_State = DDI_BC_STATE_DISABLED;
+
+ //--------------------------------------------------------------------------
+ // Return success.
+ //--------------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Enable the Battery Charger.
+//!
+//! \fntype Function
+//!
+//! If the Battery Charger is in the Disabled state, this function moves it to
+//! the Waiting to Charge state.
+//!
+//! \retval DDI_BC_STATUS_SUCCESS If all goes well
+//! \retval DDI_BC_STATUS_NOT_INITIALIZED If the Battery Charger is not yet
+//! initialized.
+//! \retval DDI_BC_STATUS_NOT_DISABLED If the Battery Charger is not
+//! disabled.
+//!
+////////////////////////////////////////////////////////////////////////////////
+ddi_bc_Status_t ddi_bc_SetEnable()
+{
+
+ //--------------------------------------------------------------------------
+ // Check if we've been initialized yet.
+ //--------------------------------------------------------------------------
+
+ if (g_ddi_bc_State == DDI_BC_STATE_UNINITIALIZED) {
+ return (DDI_BC_STATUS_NOT_INITIALIZED);
+ }
+ //--------------------------------------------------------------------------
+ // If we're not in the Disabled state, this is pointless.
+ //--------------------------------------------------------------------------
+
+ if (g_ddi_bc_State != DDI_BC_STATE_DISABLED) {
+ return (DDI_BC_STATUS_NOT_DISABLED);
+ }
+ //--------------------------------------------------------------------------
+ // Reset the state timer.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_u32StateTimer = 0;
+ //--------------------------------------------------------------------------
+ // Move to the Waiting to Charge state.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_State = DDI_BC_STATE_WAITING_TO_CHARGE;
+
+ //--------------------------------------------------------------------------
+ // Return success.
+ //--------------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Declare the battery to be broken.
+//!
+//! \fntype Function
+//!
+//! This function forces the Battery Charger into the Broken state.
+//!
+//! \retval DDI_BC_STATUS_SUCCESS If all goes well
+//! \retval DDI_BC_STATUS_NOT_INITIALIZED If the Battery Charger is not yet
+//! initialized.
+//!
+////////////////////////////////////////////////////////////////////////////////
+ddi_bc_Status_t ddi_bc_SetBroken()
+{
+
+ //--------------------------------------------------------------------------
+ // Check if we've been initialized yet.
+ //--------------------------------------------------------------------------
+
+ if (g_ddi_bc_State == DDI_BC_STATE_UNINITIALIZED) {
+ return (DDI_BC_STATUS_NOT_INITIALIZED);
+ }
+ //--------------------------------------------------------------------------
+ // Reset the current ramp. This will jam the current to zero and power off
+ // the charging hardware.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampReset();
+
+ //--------------------------------------------------------------------------
+ // Reset the state timer.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_u32StateTimer = 0;
+
+ //--------------------------------------------------------------------------
+ // Move to the Broken state.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_gBrokenReason = DDI_BC_BROKEN_CHARGING_TIMEOUT;
+
+ g_ddi_bc_State = DDI_BC_STATE_BROKEN;
+
+ //--------------------------------------------------------------------------
+ // Return success.
+ //--------------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Declare the battery to be fixed.
+//!
+//! \fntype Function
+//!
+//! If the Battery Charger is in the Broken state, this function moves it to
+//! the Disabled state.
+//!
+//! \retval DDI_BC_STATUS_SUCCESS If all goes well
+//! \retval DDI_BC_STATUS_NOT_INITIALIZED If the Battery Charger is not yet
+//! initialized.
+//! \retval DDI_BC_STATUS_NOT_BROKEN If the Battery Charger is not broken.
+//!
+////////////////////////////////////////////////////////////////////////////////
+ddi_bc_Status_t ddi_bc_SetFixed()
+{
+
+ //--------------------------------------------------------------------------
+ // Check if we've been initialized yet.
+ //--------------------------------------------------------------------------
+
+ if (g_ddi_bc_State == DDI_BC_STATE_UNINITIALIZED) {
+ return (DDI_BC_STATUS_NOT_INITIALIZED);
+ }
+ //--------------------------------------------------------------------------
+ // If we're not in the Broken state, this is pointless.
+ //--------------------------------------------------------------------------
+
+ if (g_ddi_bc_State != DDI_BC_STATE_BROKEN) {
+ return (DDI_BC_STATUS_NOT_BROKEN);
+ }
+ //--------------------------------------------------------------------------
+ // Reset the state timer.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_u32StateTimer = 0;
+
+ //--------------------------------------------------------------------------
+ // Unitialize the Broken Reason
+ //--------------------------------------------------------------------------
+
+ ddi_bc_gBrokenReason = DDI_BC_BROKEN_UNINITIALIZED;
+
+ //--------------------------------------------------------------------------
+ // Move to the Disabled state.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_State = DDI_BC_STATE_DISABLED;
+
+ //--------------------------------------------------------------------------
+ // Return success.
+ //--------------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Set the current limit.
+//!
+//! \fntype Function
+//!
+//! This function applies a limit to the current that the Battery Charger can
+//! draw.
+//!
+//! \param[in] u16Limit The maximum current the Battery Charger can draw
+//! (in mA).
+//!
+//! \retval The expressible version of the limit.
+//!
+////////////////////////////////////////////////////////////////////////////////
+uint16_t ddi_bc_SetCurrentLimit(uint16_t u16Limit)
+{
+
+ //--------------------------------------------------------------------------
+ // Set the limit and return what is actually expressible.
+ //--------------------------------------------------------------------------
+
+ return (ddi_bc_RampSetLimit(u16Limit));
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Report the current limit.
+//!
+//! \fntype Function
+//!
+//! This function reports the limit to the current that the Battery Charger can
+//! draw.
+//!
+//! \retval The current limit.
+//!
+////////////////////////////////////////////////////////////////////////////////
+uint16_t ddi_bc_GetCurrentLimit(void)
+{
+
+ //--------------------------------------------------------------------------
+ // Set the limit and return what is actually expressible.
+ //--------------------------------------------------------------------------
+
+ return (ddi_bc_RampGetLimit());
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Set the battery charger state machine period.
+//!
+//! \fntype Function
+//!
+//! This function sets a new state machine period. The Period and Slope should
+//! be coordinated to achieve the minimal ramp step current which will minimize
+//! transients on the system.
+//!
+//! \param[in] u32StateMachinePeriod (in milliseconds)
+//! \param[in] u16CurrentRampSlope (in mA/s)
+//!
+//! \retval SUCCESS If all goes well
+//! \retval ERROR_DDI_BCM_NOT_INITIALIZED If the Battery Charger is not yet
+//! initialized.
+//!
+////////////////////////////////////////////////////////////////////////////////
+ddi_bc_Status_t ddi_bc_SetNewPeriodAndSlope(uint32_t u32StateMachinePeriod,
+ uint16_t u16CurrentRampSlope)
+{
+ //--------------------------------------------------------------------------
+ // Check if we've been initialized yet.
+ //--------------------------------------------------------------------------
+ bool bDisableRequired;
+
+ if (g_ddi_bc_State == DDI_BC_STATE_UNINITIALIZED) {
+ return (DDI_BC_STATUS_NOT_INITIALIZED);
+ }
+
+ if (g_ddi_bc_State == DDI_BC_STATE_DISABLED)
+ bDisableRequired = false;
+ else {
+ bDisableRequired = true;
+ ddi_bc_SetDisable();
+ }
+
+ // Looking at the code, changing the period while the battery charger is running
+ // doesn't seem to have a negative affect. One could wrap this in the mutex
+ // or implement further coordination if it did.
+ g_ddi_bc_Configuration.u32StateMachinePeriod = u32StateMachinePeriod;
+ g_ddi_bc_Configuration.u16CurrentRampSlope = u16CurrentRampSlope;
+
+ if (bDisableRequired)
+ ddi_bc_SetEnable();
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Report the state machine period.
+//!
+//! \fntype Function
+//!
+//! This function reports the battery charger period.
+//!
+//! \retval The battery charger period (in milliseconds).
+//!
+////////////////////////////////////////////////////////////////////////////////
+uint32_t ddi_bc_GetStateMachinePeriod()
+{
+ return (g_ddi_bc_Configuration.u32StateMachinePeriod);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Report the current ramp slope.
+//!
+//! \fntype Function
+//!
+//! This function reports the current ramp slope.
+//!
+//! \retval The current ramp slope (in mA/s).
+//!
+////////////////////////////////////////////////////////////////////////////////
+uint32_t ddi_bc_GetCurrentRampSlope()
+{
+ return (g_ddi_bc_Configuration.u16CurrentRampSlope);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Report the time spent in the present state (milliseconds)
+//!
+//! \fntype Function
+//!
+//! This function reports the time spent in the present charging state. Note that
+//! for the states that actually charge the battery, this time does not include the
+//! time spent under alarm conditions such as die termperature alarm or battery
+//! temperature alarm.
+//!
+//! \retval The time spent in the current state in milliseconds.
+//!
+////////////////////////////////////////////////////////////////////////////////
+uint32_t ddi_bc_GetStateTime(void)
+{
+ return g_ddi_bc_u32StateTimer;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Report the reason for being in the broken state
+//!
+//! \fntype Function
+//!
+//!
+//! \retval ddi_bc_BrokenReason_t enumeration
+//!
+////////////////////////////////////////////////////////////////////////////////
+ddi_bc_BrokenReason_t ddi_bc_GetBrokenReason(void)
+{
+ return ddi_bc_gBrokenReason;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Restart the charge cycle
+//!
+//! \fntype Function
+//!
+//!
+//! \retval SUCCESS
+//!
+////////////////////////////////////////////////////////////////////////////////
+ddi_bc_Status_t ddi_bc_ForceChargingToStart(void)
+{
+ static int16_t restarts = 0;
+
+ if (restarts < DDI_BC_MAX_RESTART_CYCLES) {
+ restarts++;
+ bRestartChargeCycle = true;
+ }
+
+ return (DDI_BC_STATUS_SUCCESS);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// End of file
+////////////////////////////////////////////////////////////////////////////////
+//! @}
diff --git a/drivers/power/stmp37xx/ddi_bc_hw.c b/drivers/power/stmp37xx/ddi_bc_hw.c
new file mode 100644
index 000000000000..fab82a738b01
--- /dev/null
+++ b/drivers/power/stmp37xx/ddi_bc_hw.c
@@ -0,0 +1,474 @@
+/*
+ * 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
+ */
+
+#include "ddi_bc_internal.h"
+
+////////////////////////////////////////////////////////////////////////////////
+//! \addtogroup ddi_bc
+//! @{
+//
+// Copyright (c) 2004-2005 SigmaTel, Inc.
+//
+//! \file ddi_bc_hw.c
+//! \brief Contains the Battery Charger hardware operations.
+//! \date 06/2005
+//!
+//! This file contains Battery Charger hardware operations.
+//!
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+// Includes and external references
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+// Variables
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+// Code
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Report if the battery charging hardware is available.
+//!
+//! \fntype Function
+//!
+//! This function reports if the battery charging hardware is available by
+//! reading the corresponding laser fuse bit.
+//!
+//! \retval Zero if the battery charging hardware is not available. Non-zero
+//! otherwise.
+//!
+////////////////////////////////////////////////////////////////////////////////
+int ddi_bc_hwBatteryChargerIsEnabled(void)
+{
+ //TODO: replace ddi_bc_hwBatteryChargerIsEnabled with the function below in the code
+ return (int)ddi_power_GetBatteryChargerEnabled();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Report the battery configuration.
+//!
+//! \fntype Function
+//!
+//! This function reports the hardware battery configuration.
+//!
+//! \retval A value that indicates the battery configuration.
+//!
+////////////////////////////////////////////////////////////////////////////////
+ddi_bc_BatteryMode_t ddi_bc_hwGetBatteryMode(void)
+{
+ //TODO: replace ddi_bc_hwGetBatteryMode() with the function below.
+ return (ddi_bc_BatteryMode_t) ddi_power_GetBatteryMode();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Report the bias current source.
+//!
+//! \fntype Function
+//!
+//! This function Battery Charger.
+//!
+//! \retval A value that indicates the current bias current source.
+//!
+////////////////////////////////////////////////////////////////////////////////
+ddi_bc_BiasCurrentSource_t ddi_bc_hwGetBiasCurrentSource(void)
+{
+ // TODO: replace ddi_bc_BiasCurrentSource_t() with the function below.
+ return (ddi_bc_BiasCurrentSource_t) ddi_power_GetBiasCurrentSource();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Sets the bias current source.
+//!
+//! \fntype Function
+//!
+//! This function sets the bias current source used by the battery charger
+//! hardware. The battery charger is usually configured to use an externally
+//! generated bias current, which is expected to be quite precise. To reduce
+//! component count, for example, it can be configured to generate a lesser-
+//! quality bias current internally.
+//!
+//! \param[in] source Indicates the source of the bias current.
+//!
+//! \retval DDI_BC_STATUS_SUCCESS If the operation succeeded.
+//! \retval DDI_BC_STATUS_BAD_ARGUMENT If the given source argument isn't one
+//! of the expected values.
+//!
+////////////////////////////////////////////////////////////////////////////////
+ddi_bc_Status_t ddi_bc_hwSetBiasCurrentSource(ddi_bc_BiasCurrentSource_t source)
+{
+ ddi_power_BiasCurrentSource_t eSource =
+ (ddi_power_BiasCurrentSource_t) source;
+
+ //--------------------------------------------------------------------------
+ // In the following code, there are two points that can be confusing. Both
+ // of these problems derive from silliness in the data sheet.
+ //
+ // The field of interest here is HW_POWER_BATTCHRG.USE_EXTERN_R. This is
+ // poorly named for two reasons:
+ //
+ // 1) What we're really doing is selecting the source of the bias current.
+ // If the application chooses to use an external bias current, then
+ // there will, of course, be a resistor involved (apparently, a good-
+ // quality one at about 620 Ohms).
+ //
+ // 2) If the bit is SET, that tells the hardware to use the INTERNAL bias
+ // current. If this bit is CLEAR, that tells the hardware to use the
+ // EXTERNAL bias current. Thus, the actual logic for this bit is
+ // reversed from the sense indicated by its name.
+ //--------------------------------------------------------------------------
+
+ // TODO: replace all ddi_bc_hwSetBiasCurrentSource() with function below.
+ return (ddi_bc_Status_t) ddi_power_SetBiasCurrentSource(eSource);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Report the voltage across the battery.
+//!
+//! \fntype Function
+//!
+//! This function reports the voltage across the battery.
+//!
+//! \retval The voltage across the battery, in mV.
+//!
+////////////////////////////////////////////////////////////////////////////////
+uint16_t ddi_bc_hwGetBatteryVoltage(void)
+{
+ //TODO: replace ddi_bc_hwGetBattery with function below
+ return ddi_power_GetBattery();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Report on the presence of the power supply.
+//!
+//! \fntype Function
+//!
+//! This function repots on whether or not the 5V power supply is present.
+//!
+//! \retval Zero if the power supply is not present. Non-zero otherwise.
+//!
+////////////////////////////////////////////////////////////////////////////////
+int ddi_bc_hwPowerSupplyIsPresent(void)
+{
+ // TODO: replace ddi_bc_hwPowerSupplyIsPresent with the functino below.
+ return (int)ddi_power_Get5vPresentFlag();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Report the maximum charging current.
+//!
+//! \fntype Function
+//!
+//! This function reports the maximum charging current that will be offered to
+//! the battery, as currently set in the hardware.
+//!
+//! \retval The maximum current setting in the hardware.
+//!
+////////////////////////////////////////////////////////////////////////////////
+uint16_t ddi_bc_hwGetMaxCurrent(void)
+{
+ // TODO: replace ddi_bc_hwGetMaxCurrent() with the below function
+ return (uint16_t) ddi_power_GetMaxBatteryChargeCurrent();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Set the maximum charging current.
+//!
+//! \fntype Function
+//!
+//! This function sets the maximum charging current that will be offered to the
+//! battery.
+//!
+//! Note that the hardware has a minimum resolution of 10mA and a maximum
+//! expressible value of 780mA (see the data sheet for details). If the given
+//! current cannot be expressed exactly, then the largest expressible smaller
+//! value will be used. The return reports the actual value that was effected.
+//!
+//! \param[in] u16Limit The maximum charging current, in mA.
+//!
+//! \retval The actual value that was effected.
+//!
+////////////////////////////////////////////////////////////////////////////////
+uint16_t ddi_bc_hwSetMaxCurrent(uint16_t u16Limit)
+{
+ //TODO: replace ddi_bc_hwSetMaxChargeCurrent
+ return ddi_power_SetMaxBatteryChargeCurrent(u16Limit);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Set the charging current threshold.
+//!
+//! \fntype Function
+//!
+//! This function sets the charging current threshold. When the actual current
+//! flow to the battery is less than this threshold, the HW_POWER_STS.CHRGSTS
+//! flag is clear.
+//!
+//! Note that the hardware has a minimum resolution of 10mA and a maximum
+//! expressible value of 180mA (see the data sheet for details). If the given
+//! current cannot be expressed exactly, then the largest expressible smaller
+//! value will be used. The return reports the actual value that was effected.
+//!
+//! \param[in] u16Threshold The charging current threshold, in mA.
+//!
+//! \retval The actual value that was effected.
+//!
+////////////////////////////////////////////////////////////////////////////////
+uint16_t ddi_bc_hwSetCurrentThreshold(uint16_t u16Threshold)
+{
+ //TODO: replace calls to ddi_bc_hwSetCurrentThreshold with the one below
+ return ddi_power_SetBatteryChargeCurrentThreshold(u16Threshold);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Report the charging current threshold.
+//!
+//! \fntype Function
+//!
+//! This function reports the charging current threshold. When the actual
+//! current flow to the battery is less than this threshold, the
+//! HW_POWER_STS.CHRGSTS flag is clear.
+//!
+//! Note that the hardware has a minimum resolution of 10mA and a maximum
+//! expressible value of 180mA (see the data sheet for details).
+//!
+//! \retval The charging current threshold, in mA.
+//!
+////////////////////////////////////////////////////////////////////////////////
+uint16_t ddi_bc_hwGetCurrentThreshold(void)
+{
+ //TODO: replace calls to ddi_bc_hwGetCurrentThreshold with function below
+ return ddi_power_GetBatteryChargeCurrentThreshold();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Report if the charger hardware power is on.
+//!
+//! \fntype Function
+//!
+//! This function reports if the charger hardware power is on.
+//!
+//! \retval Zero if the charger hardware is not powered. Non-zero otherwise.
+//!
+////////////////////////////////////////////////////////////////////////////////
+int ddi_bc_hwChargerPowerIsOn(void)
+{
+
+ //--------------------------------------------------------------------------
+ // Note that the bit we're looking at is named PWD_BATTCHRG. The "PWD"
+ // stands for "power down". Thus, when the bit is set, the battery charger
+ // hardware is POWERED DOWN.
+ //--------------------------------------------------------------------------
+
+ //--------------------------------------------------------------------------
+ // Read the register and return the result.
+ //--------------------------------------------------------------------------
+
+ //TODO: replace ddi_bc_hwChargerPowerIsOn with function below
+ return ddi_power_GetChargerPowered();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Turn the charging hardware on or off.
+//!
+//! \fntype Function
+//!
+//! This function turns the charging hardware on or off.
+//!
+//! \param[in] on Indicates whether the charging hardware should be on or off.
+//!
+////////////////////////////////////////////////////////////////////////////////
+void ddi_bc_hwSetChargerPower(int on)
+{
+
+ //--------------------------------------------------------------------------
+ // Note that the bit we're looking at is named PWD_BATTCHRG. The "PWD"
+ // stands for "power down". Thus, when the bit is set, the battery charger
+ // hardware is POWERED DOWN.
+ //--------------------------------------------------------------------------
+
+ //--------------------------------------------------------------------------
+ // Hit the power switch.
+ //--------------------------------------------------------------------------
+
+ //TODO: replace ddi_bc_hwSetChargerPower with functino below
+ ddi_power_SetChargerPowered(on);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Reports if the charging current has fallen below the threshold.
+//!
+//! \fntype Function
+//!
+//! This function reports if the charging current that the battery is accepting
+//! has fallen below the threshold.
+//!
+//! Note that this bit is regarded by the hardware guys as very slightly
+//! unreliable. They recommend that you don't believe a value of zero until
+//! you've sampled it twice.
+//!
+//! \retval Zero if the battery is accepting less current than indicated by the
+//! charging threshold. Non-zero otherwise.
+//!
+////////////////////////////////////////////////////////////////////////////////
+int ddi_bc_hwGetChargeStatus(void)
+{
+ return ddi_power_GetChargeStatus();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Report on the die temperature.
+//!
+//! \fntype Function
+//!
+//! This function reports on the die temperature.
+//!
+//! \param[out] pLow The low end of the temperature range.
+//! \param[out] pHigh The high end of the temperature range.
+//!
+////////////////////////////////////////////////////////////////////////////////
+void ddi_bc_hwGetDieTemp(int16_t * pLow, int16_t * pHigh)
+{
+ // TODO: replace ddi_bc_hwGetDieTemp with function below
+ ddi_power_GetDieTemp(pLow, pHigh);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Report the battery temperature reading.
+//!
+//! \fntype Function
+//!
+//! This function examines the configured LRADC channel and reports the battery
+//! temperature reading.
+//!
+//! \param[out] pReading A pointer to a variable that will receive the
+//! temperature reading.
+//!
+//! \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_hwGetBatteryTemp(uint16_t * pReading)
+{
+ return (ddi_bc_Status_t)DDI_BC_STATUS_HARDWARE_DISABLED;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Convert a current in mA to a hardware setting.
+//!
+//! \fntype Function
+//!
+//! This function converts a current measurement in mA to a hardware setting
+//! used by HW_POWER_BATTCHRG.STOP_ILIMIT or HW_POWER_BATTCHRG.BATTCHRG_I.
+//!
+//! Note that the hardware has a minimum resolution of 10mA and a maximum
+//! expressible value of 780mA (see the data sheet for details). If the given
+//! current cannot be expressed exactly, then the largest expressible smaller
+//! value will be used.
+//!
+//! \param[in] u16Current The current of interest.
+//!
+//! \retval The corresponding setting.
+//!
+////////////////////////////////////////////////////////////////////////////////
+uint8_t ddi_bc_hwCurrentToSetting(uint16_t u16Current)
+{
+ return ddi_power_convert_current_to_setting(u16Current);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Convert a hardware current setting to a value in mA.
+//!
+//! \fntype Function
+//!
+//! This function converts a setting used by HW_POWER_BATTCHRG.STOP_ILIMIT or
+//! HW_POWER_BATTCHRG.BATTCHRG_I into an actual current measurement in mA.
+//!
+//! Note that the hardware current fields are 6 bits wide. The higher bits in
+//! the 8-bit input parameter are ignored.
+//!
+//! \param[in] u8Setting A hardware current setting.
+//!
+//! \retval The corresponding current in mA.
+//!
+////////////////////////////////////////////////////////////////////////////////
+uint16_t ddi_bc_hwSettingToCurrent(uint8_t u8Setting)
+{
+ return ddi_power_convert_setting_to_current(u8Setting);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Compute the actual current expressible in the hardware.
+//!
+//! \fntype Function
+//!
+//! Given a desired current, this function computes the actual current
+//! expressible in the hardware.
+//!
+//! Note that the hardware has a minimum resolution of 10mA and a maximum
+//! expressible value of 780mA (see the data sheet for details). If the given
+//! current cannot be expressed exactly, then the largest expressible smaller
+//! value will be used.
+//!
+//! \param[in] u16Current The current of interest.
+//!
+//! \retval The corresponding current in mA.
+//!
+////////////////////////////////////////////////////////////////////////////////
+uint16_t ddi_bc_hwExpressibleCurrent(uint16_t u16Current)
+{
+ //TODO: replace the bc function with this one
+ return ddi_power_ExpressibleCurrent(u16Current);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Checks to see if the DCDC has been manually enabled
+//!
+//! \fntype Function
+//!
+//! \retval true if DCDC is ON, false if DCDC is OFF.
+//!
+////////////////////////////////////////////////////////////////////////////////
+bool ddi_bc_hwIsDcdcOn(void)
+{
+ return ddi_power_IsDcdcOn();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// End of file
+////////////////////////////////////////////////////////////////////////////////
+//! @}
diff --git a/drivers/power/stmp37xx/ddi_bc_hw.h b/drivers/power/stmp37xx/ddi_bc_hw.h
new file mode 100644
index 000000000000..68ef98aa4303
--- /dev/null
+++ b/drivers/power/stmp37xx/ddi_bc_hw.h
@@ -0,0 +1,93 @@
+/*
+ * 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_hw.h
+//! \brief Internal header file for Battery Charger hardware operations.
+//! \date 06/2005
+//!
+//! This file contains internal declarations for Battery Charger hardware
+//! operations.
+//!
+//! \see ddi_bc.c and related files.
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef _DDI_BC_HW_H
+#define _DDI_BC_HW_H
+
+////////////////////////////////////////////////////////////////////////////////
+// Definitions
+////////////////////////////////////////////////////////////////////////////////
+
+//! The enumeration of battery modes.
+
+typedef enum _ddi_bc_BatteryMode {
+ DDI_BC_BATTERY_MODE_LI_ION_2_CELLS = 0,
+ DDI_BC_BATTERY_MODE_LI_ION_1_CELL = 1,
+ DDI_BC_BATTERY_MODE_2_CELLS = 2,
+ DDI_BC_BATTERY_MODE_1_CELL = 3
+} ddi_bc_BatteryMode_t;
+
+//! The enumeration of bias current sources.
+
+typedef enum _ddi_bc_BiasCurrentSource {
+ DDI_BC_EXTERNAL_BIAS_CURRENT = 0,
+ DDI_BC_INTERNAL_BIAS_CURRENT = 1,
+} ddi_bc_BiasCurrentSource_t;
+
+////////////////////////////////////////////////////////////////////////////////
+// Prototypes
+////////////////////////////////////////////////////////////////////////////////
+
+extern int ddi_bc_hwBatteryChargerIsEnabled(void);
+extern ddi_bc_BatteryMode_t ddi_bc_hwGetBatteryMode(void);
+extern ddi_bc_BiasCurrentSource_t ddi_bc_hwGetBiasCurrentSource(void);
+extern ddi_bc_Status_t
+ddi_bc_hwSetBiasCurrentSource(ddi_bc_BiasCurrentSource_t);
+extern ddi_bc_Status_t ddi_bc_hwSetChargingVoltage(uint16_t);
+extern uint16_t ddi_bc_hwGetBatteryVoltage(void);
+extern int ddi_bc_hwPowerSupplyIsPresent(void);
+extern uint16_t ddi_bc_hwSetMaxCurrent(uint16_t);
+extern uint16_t ddi_bc_hwGetMaxCurrent(void);
+extern uint16_t ddi_bc_hwSetCurrentThreshold(uint16_t);
+extern uint16_t ddi_bc_hwGetCurrentThreshold(void);
+extern int ddi_bc_hwChargerPowerIsOn(void);
+extern void ddi_bc_hwSetChargerPower(int);
+extern int ddi_bc_hwGetChargeStatus(void);
+extern void ddi_bc_hwGetDieTemp(int16_t *, int16_t *);
+extern ddi_bc_Status_t ddi_bc_hwGetBatteryTemp(uint16_t *);
+uint8_t ddi_bc_hwCurrentToSetting(uint16_t);
+uint16_t ddi_bc_hwSettingToCurrent(uint8_t);
+uint16_t ddi_bc_hwExpressibleCurrent(uint16_t);
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Checks to see if the DCDC has been manually enabled
+//!
+//! \fntype Function
+//!
+//! \retval true if DCDC is ON, false if DCDC is OFF.
+//!
+////////////////////////////////////////////////////////////////////////////////
+bool ddi_bc_hwIsDcdcOn(void);
+
+////////////////////////////////////////////////////////////////////////////////
+// End of file
+////////////////////////////////////////////////////////////////////////////////
+#endif // _DDI_BC_H
+//! @}
diff --git a/drivers/power/stmp37xx/ddi_bc_init.c b/drivers/power/stmp37xx/ddi_bc_init.c
new file mode 100644
index 000000000000..ef323b33b74f
--- /dev/null
+++ b/drivers/power/stmp37xx/ddi_bc_init.c
@@ -0,0 +1,204 @@
+/*
+ * 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
+ */
+
+#include "ddi_bc_internal.h"
+
+////////////////////////////////////////////////////////////////////////////////
+//! \addtogroup ddi_bc
+//! @{
+//
+// Copyright (c) 2004-2005 SigmaTel, Inc.
+//
+//! \file ddi_bc_init.c
+//! \brief Contains the Battery Charger initialization function.
+//! \date 06/2005
+//!
+//! This file contains Battery Charger initialization function.
+//!
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+// Includes and external references
+////////////////////////////////////////////////////////////////////////////////
+#include <mach/ddi_bc.h>
+#include "ddi_bc_internal.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// Code
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//! \brief Initialize the Battery Charger.
+//!
+//! \fntype Function
+//!
+//! This function initializes the Battery Charger.
+//!
+//! \param[in] pCfg A pointer to the new configuration.
+//!
+//! \retval DDI_BC_STATUS_SUCCESS
+//! If the operation succeeded.
+//! \retval DDI_BC_STATUS_ALREADY_INITIALIZED
+//! If the Battery Charger is already initialized.
+//! \retval DDI_BC_STATUS_HARDWARE_DISABLED
+//! If the Battery Charger hardware is disabled by a laser fuse.
+//! \retval DDI_BC_STATUS_BAD_BATTERY_MODE
+//! If the power supply is set up for a non-rechargeable battery.
+//! \retval DDI_BC_STATUS_CLOCK_GATE_CLOSED
+//! If the clock gate for the power supply registers is closed.
+//! \retval DDI_BC_STATUS_CFG_BAD_CHARGING_VOLTAGE
+//! If the charging voltage is not either 4100 or 4200.
+//! \retval DDI_BC_STATUS_CFG_BAD_BATTERY_TEMP_CHANNEL
+//! If the LRADC channel number for monitoring battery temperature
+//! is bad.
+//!
+////////////////////////////////////////////////////////////////////////////////
+ddi_bc_Status_t ddi_bc_Init(ddi_bc_Cfg_t * pCfg)
+{
+
+ //--------------------------------------------------------------------------
+ // We can only be initialized if we're in the Uninitialized state.
+ //--------------------------------------------------------------------------
+
+ if (g_ddi_bc_State != DDI_BC_STATE_UNINITIALIZED) {
+ return (DDI_BC_STATUS_ALREADY_INITIALIZED);
+ }
+ //--------------------------------------------------------------------------
+ // Check if the battery charger hardware has been disabled by laser fuse.
+ //--------------------------------------------------------------------------
+
+ if (!ddi_power_GetBatteryChargerEnabled())
+ return (DDI_BC_STATUS_HARDWARE_DISABLED);
+
+ //--------------------------------------------------------------------------
+ // Check if the power supply has been set up for a non-rechargeable battery.
+ //--------------------------------------------------------------------------
+
+ switch (ddi_power_GetBatteryMode()) {
+
+ case DDI_POWER_BATT_MODE_LIION:
+ break;
+
+ // TODO: we'll need to do NiMH also
+ default:
+ return (DDI_BC_STATUS_BAD_BATTERY_MODE);
+ //break;
+
+ }
+
+ //--------------------------------------------------------------------------
+ // Make sure that the clock gate has been opened for the power supply
+ // registers. If not, then none of our writes to those registers will
+ // succeed, which will kind of slow us down...
+ //--------------------------------------------------------------------------
+
+ if (ddi_power_GetPowerClkGate()) {
+ return (DDI_BC_STATUS_CLOCK_GATE_CLOSED);
+ }
+ //--------------------------------------------------------------------------
+ // Check the incoming configuration for nonsense.
+ //--------------------------------------------------------------------------
+
+ //
+ // Only permitted charging voltage: 4200mV.
+ //
+
+ if (pCfg->u16ChargingVoltage != DDI_BC_LIION_CHARGING_VOLTAGE) {
+ return (DDI_BC_STATUS_CFG_BAD_CHARGING_VOLTAGE);
+ }
+ //
+ // There are 8 LRADC channels.
+ //
+
+ if (pCfg->u8BatteryTempChannel > 7) {
+ return (DDI_BC_STATUS_CFG_BAD_BATTERY_TEMP_CHANNEL);
+ }
+ //--------------------------------------------------------------------------
+ // Accept the configuration.
+ //--------------------------------------------------------------------------
+
+ //--------------------------------------------------------------------------
+ // ddi_bc_Cfg_t.u16ChargingThresholdCurrent is destined for the
+ // register field HW_POWER_BATTCHRG.STOP_ILIMIT. This 4-bit field
+ // is unevenly quantized to provide a useful range of currents. A
+ // side effect of the quantization is that the field can only be
+ // set to certain unevenly-spaced values.
+ //
+ // Here, we use the two functions that manipulate the register field
+ // to adjust u16ChargingThresholdCurrent to match the quantized value.
+ //--------------------------------------------------------------------------
+ pCfg->u16ChargingThresholdCurrent =
+ ddi_power_ExpressibleCurrent(pCfg->u16ChargingThresholdCurrent);
+
+ //--------------------------------------------------------------------------
+ // ...similar situation with ddi_bc_Cfg_t.u16BatteryTempSafeCurrent and
+ // u16DieTempSafeCurrent.
+ //--------------------------------------------------------------------------
+ pCfg->u16BatteryTempSafeCurrent =
+ ddi_power_ExpressibleCurrent(pCfg->u16BatteryTempSafeCurrent);
+ pCfg->u16DieTempSafeCurrent =
+ ddi_power_ExpressibleCurrent(pCfg->u16DieTempSafeCurrent);
+
+ g_ddi_bc_Configuration = *pCfg;
+
+ //--------------------------------------------------------------------------
+ // Set the bias current source.
+ //--------------------------------------------------------------------------
+
+ {
+ ddi_power_BiasCurrentSource_t Flag;
+
+ Flag =
+ g_ddi_bc_Configuration.useInternalBias ?
+ DDI_POWER_INTERNAL_BIAS_CURRENT :
+ DDI_POWER_EXTERNAL_BIAS_CURRENT;
+
+ ddi_power_SetBiasCurrentSource(Flag);
+
+ }
+
+ //--------------------------------------------------------------------------
+ // Turn the charger hardware off. This is a very important initial condition
+ // because we only flip the power switch on the hardware when we make
+ // transitions. Baseline, it needs to be off.
+ //--------------------------------------------------------------------------
+
+ ddi_power_SetChargerPowered(0);
+
+ //--------------------------------------------------------------------------
+ // Reset the current ramp. This will jam the current to zero and power off
+ // the charging hardware.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampReset();
+
+ //--------------------------------------------------------------------------
+ // Move to the Disabled state.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_State = DDI_BC_STATE_DISABLED;
+
+ //--------------------------------------------------------------------------
+ // Return success.
+ //--------------------------------------------------------------------------
+#ifdef CONFIG_POWER_SUPPLY_DEBUG
+ printk("%s: success\n", __func__);
+#endif
+ return (DDI_BC_STATUS_SUCCESS);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// End of file
+////////////////////////////////////////////////////////////////////////////////
+//! @}
diff --git a/drivers/power/stmp37xx/ddi_bc_internal.h b/drivers/power/stmp37xx/ddi_bc_internal.h
new file mode 100644
index 000000000000..c1fb1b20f271
--- /dev/null
+++ b/drivers/power/stmp37xx/ddi_bc_internal.h
@@ -0,0 +1,52 @@
+/*
+ * 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_internal.h
+//! \brief Internal header file for the Battery Charger device driver.
+//! \date 06/2005
+//!
+//! This file contains internal declarations for the Battery Charger device
+//! driver.
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef _DDI_BC_INTERNAL_H
+#define _DDI_BC_INTERNAL_H
+
+////////////////////////////////////////////////////////////////////////////////
+// Includes
+////////////////////////////////////////////////////////////////////////////////
+
+#include <mach/ddi_bc.h>
+#include "ddi_bc_hw.h"
+#include "ddi_bc_ramp.h"
+#include "ddi_bc_sm.h"
+#include "ddi_power_battery.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// Externs
+////////////////////////////////////////////////////////////////////////////////
+
+extern bool g_ddi_bc_Configured;
+extern ddi_bc_Cfg_t g_ddi_bc_Configuration;
+
+////////////////////////////////////////////////////////////////////////////////
+// End of file
+////////////////////////////////////////////////////////////////////////////////
+#endif // _DDI_BC_H
+//! @}
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
+////////////////////////////////////////////////////////////////////////////////
+//! @}
diff --git a/drivers/power/stmp37xx/ddi_bc_ramp.h b/drivers/power/stmp37xx/ddi_bc_ramp.h
new file mode 100644
index 000000000000..5111a5496fcf
--- /dev/null
+++ b/drivers/power/stmp37xx/ddi_bc_ramp.h
@@ -0,0 +1,50 @@
+/*
+ * 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.h
+//! \brief Internal header file for Battery Charger current ramp controller.
+//! \date 06/2005
+//!
+//! This file contains internal declarations for Battery current ramp
+//! controller.
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef _DDI_BC_RAMP_H
+#define _DDI_BC_RAMP_H
+
+////////////////////////////////////////////////////////////////////////////////
+// Prototypes
+////////////////////////////////////////////////////////////////////////////////
+
+extern void ddi_bc_RampReset(void);
+extern uint16_t ddi_bc_RampSetTarget(uint16_t);
+extern uint16_t ddi_bc_RampGetTarget(void);
+extern uint16_t ddi_bc_RampSetLimit(uint16_t);
+extern uint16_t ddi_bc_RampGetLimit(void);
+extern void ddi_bc_RampUpdateAlarms(void);
+extern int ddi_bc_RampGetDieTempAlarm(void);
+extern int ddi_bc_RampGetBatteryTempAlarm(void);
+extern int ddi_bc_RampGetAmbientTempAlarm(void);
+extern ddi_bc_Status_t ddi_bc_RampStep(uint32_t);
+
+////////////////////////////////////////////////////////////////////////////////
+// End of file
+////////////////////////////////////////////////////////////////////////////////
+#endif // _DDI_BC_H
+//! @}
diff --git a/drivers/power/stmp37xx/ddi_bc_sm.c b/drivers/power/stmp37xx/ddi_bc_sm.c
new file mode 100644
index 000000000000..8bd8d2cbb58b
--- /dev/null
+++ b/drivers/power/stmp37xx/ddi_bc_sm.c
@@ -0,0 +1,1122 @@
+/*
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+////////////////////////////////////////////////////////////////////////////////
+//! \addtogroup ddi_bc
+//! @{
+//
+// Copyright (c) 2004-2005 SigmaTel, Inc.
+//
+//! \file ddi_bc_sm.c
+//! \brief Contains the Battery Charger state machine.
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+// Includes
+////////////////////////////////////////////////////////////////////////////////
+
+#include <mach/ddi_bc.h>
+#include "ddi_bc_internal.h"
+
+#include <linux/delay.h>
+
+////////////////////////////////////////////////////////////////////////////////
+// Definitions
+////////////////////////////////////////////////////////////////////////////////
+
+// This is the minimum time we must charge before we transition from
+// the charging state to the topping off. If we reach the
+// u16ChargingThresholdCurrent charge curent before then, the battery was
+// already full so we can avoid the risk of charging it past .1C for
+// too long.
+
+#define TRANSITION_TO_TOPOFF_MINIMUM_CHARGE_TIME_mS 1 * 60 * 1000 // 1 minute
+
+// If DCDCs are active, we can't complete the charging cycle. Once
+// they are stay off for this amount of time, we will restart the
+// charge cycle.
+#define DCDC_INACTIVITY_TIMER_THRESHOLD 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);
+static ddi_bc_Status_t ddi_bc_DcdcModeWaitingToCharge(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, ddi_bc_DcdcModeWaitingToCharge};
+
+// Used by states that need to watch the time.
+uint32_t g_ddi_bc_u32StateTimer = 0;
+
+// If DCDCs are active, we can't complete the charging cycle. Once
+// they are stay off for this amount of time, we will restart the
+// charge cycle.
+static uint32_t DcdcInactityTimer = DCDC_INACTIVITY_TIMER_THRESHOLD;
+
+// Always attempt to charge on first 5V connection even if DCDCs are ON.
+bool bRestartChargeCycle = true;
+
+#ifdef CONFIG_POWER_SUPPLY_DEBUG
+static uint16_t u16ExternalBatteryPowerVoltageCheck = 0;
+#endif
+
+ddi_bc_BrokenReason_t ddi_bc_gBrokenReason = DDI_BC_BROKEN_UNINITIALIZED;
+
+////////////////////////////////////////////////////////////////////////////////
+// Code
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Transition to the DCDC mode Waiting to Charge state.
+//!
+//! \fntype Function
+//!
+//! This function implements the transition to the DCDC Mode Waiting
+//! to Charge state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Transition to the DCDC mode Waiting to Charge state.
+//!
+//! \fntype Function
+//!
+//! This function implements the transition to the DCDC Mode Waiting
+//! to Charge state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static void TransitionToDcdcModeWaitingToCharge(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_DCDC_MODE_WAITING_TO_CHARGE;
+
+#ifdef CONFIG_POWER_SUPPLY_DEBUG
+ printk("Battery charger: now waiting to charge (DCDC Mode)\n");
+#endif
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Transition to the Waiting to Charge state.
+//!
+//! \fntype Function
+//!
+//! This function implements the transition to the Waiting to Charge state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static void TransitionToWaitingToCharge(void)
+{
+
+ //--------------------------------------------------------------------------
+ // Reset the state timer.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_u32StateTimer = 0;
+
+ //--------------------------------------------------------------------------
+ // Reset the current ramp.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampReset();
+
+ //--------------------------------------------------------------------------
+ // Move to the Waiting to Charge state.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_State = DDI_BC_STATE_WAITING_TO_CHARGE;
+
+#ifdef CONFIG_POWER_SUPPLY_DEBUG
+ printk("Battery charger: now waiting to charge\n");
+#endif
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Transition to the Conditioning state.
+//!
+//! \fntype Function
+//!
+//! This function implements the transition to the Conditioning state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static void TransitionToConditioning(void)
+{
+
+ //--------------------------------------------------------------------------
+ // Reset the state timer.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_u32StateTimer = 0;
+
+ //--------------------------------------------------------------------------
+ // Set up the current ramp for conditioning.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampSetTarget(g_ddi_bc_Configuration.u16ConditioningCurrent);
+
+ //--------------------------------------------------------------------------
+ // Move to the Conditioning state.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_State = DDI_BC_STATE_CONDITIONING;
+
+#ifdef CONFIG_POWER_SUPPLY_DEBUG
+ printk("Battery charger: now conditioning\n");
+#endif
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Transition to the Charging state.
+//!
+//! \fntype Function
+//!
+//! This function implements the transition to the Charging state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static void TransitionToCharging(void)
+{
+
+ //--------------------------------------------------------------------------
+ // Reset the state timer.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_u32StateTimer = 0;
+
+ //--------------------------------------------------------------------------
+ // Set up the current ramp for charging.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampSetTarget(g_ddi_bc_Configuration.u16ChargingCurrent);
+
+ //--------------------------------------------------------------------------
+ // We'll be finished charging when the current flow drops below this level.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_hwSetCurrentThreshold(g_ddi_bc_Configuration.
+ u16ChargingThresholdCurrent);
+
+ //--------------------------------------------------------------------------
+ // Move to the Charging state.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_State = DDI_BC_STATE_CHARGING;
+#ifdef CONFIG_POWER_SUPPLY_DEBUG
+ printk("Battery charger: now charging\n");
+#endif
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Transition to the Topping Off state.
+//!
+//! \fntype Function
+//!
+//! This function implements the transition to the Topping Off state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static void TransitionToToppingOff(void)
+{
+
+ //--------------------------------------------------------------------------
+ // Reset the state timer.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_u32StateTimer = 0;
+
+ //--------------------------------------------------------------------------
+ // Set up the current ramp for topping off.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampSetTarget(g_ddi_bc_Configuration.u16ChargingCurrent);
+
+ //--------------------------------------------------------------------------
+ // Move to the Topping Off state.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_State = DDI_BC_STATE_TOPPING_OFF;
+
+#ifdef CONFIG_POWER_SUPPLY_DEBUG
+ printk("Battery charger: now topping off\n");
+#endif
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Transition to the Broken state.
+//!
+//! \fntype Function
+//!
+//! This function implements the transition to the Broken state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static void TransitionToBroken(void)
+{
+
+ //--------------------------------------------------------------------------
+ // Reset the state timer.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_u32StateTimer = 0;
+
+ //--------------------------------------------------------------------------
+ // Reset the current ramp.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampReset();
+
+ //--------------------------------------------------------------------------
+ // Move to the Broken state.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_State = DDI_BC_STATE_BROKEN;
+
+#ifdef CONFIG_POWER_SUPPLY_DEBUG
+ printk("Battery charger: declaring a broken battery\n");
+#endif
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Uninitialized state function.
+//!
+//! \fntype Function
+//!
+//! This function implements the Uninitialized state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static ddi_bc_Status_t ddi_bc_Uninitialized(void)
+{
+
+ //--------------------------------------------------------------------------
+ // The first order of business is to update alarms.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampUpdateAlarms();
+
+ //--------------------------------------------------------------------------
+ // Increment the state timer.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_u32StateTimer += g_ddi_bc_Configuration.u32StateMachinePeriod;
+
+ //--------------------------------------------------------------------------
+ // The only way to leave this state is with a call to ddi_bc_Initialize. So,
+ // calling this state function does nothing.
+ //--------------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Broken state function.
+//!
+//! \fntype Function
+//!
+//! This function implements the Broken state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static ddi_bc_Status_t ddi_bc_Broken(void)
+{
+
+ //--------------------------------------------------------------------------
+ // The first order of business is to update alarms.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampUpdateAlarms();
+
+ //--------------------------------------------------------------------------
+ // Increment the state timer.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_u32StateTimer += g_ddi_bc_Configuration.u32StateMachinePeriod;
+
+ //--------------------------------------------------------------------------
+ // The only way to leave this state is with a call to ddi_bc_SetFixed. So,
+ // calling this state function does nothing.
+ //--------------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Disabled state function.
+//!
+//! \fntype Function
+//!
+//! This function implements the Disabled state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static ddi_bc_Status_t ddi_bc_Disabled(void)
+{
+
+ //--------------------------------------------------------------------------
+ // The first order of business is to update alarms.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampUpdateAlarms();
+
+ //--------------------------------------------------------------------------
+ // Increment the state timer.
+ //--------------------------------------------------------------------------
+
+ g_ddi_bc_u32StateTimer += g_ddi_bc_Configuration.u32StateMachinePeriod;
+
+ //--------------------------------------------------------------------------
+ // The only way to leave this state is with a call to ddi_bc_SetEnable. So,
+ // calling this state function does nothing.
+ //--------------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Waitin to Charge state function.
+//!
+//! \fntype Function
+//!
+//! This function implements the Waiting to Charge state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static ddi_bc_Status_t ddi_bc_DcdcModeWaitingToCharge(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()) {
+ TransitionToCharging();
+ 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();
+
+ //--------------------------------------------------------------------------
+ // If topping off has not yet occurred, we do not care if DCDCs are on or not.
+ // If we have already topped off at least once, then we want to delay so that
+ // we give the battery a chance to discharge some instead of constantly topping
+ // it off.
+ //--------------------------------------------------------------------------
+
+ if (ddi_bc_hwIsDcdcOn()) {
+
+ //--------------------------------------------------------------------------
+ // If DCDCs have turned on, restert the DCDCInactivityTimer;
+ //--------------------------------------------------------------------------
+ DcdcInactityTimer = 0;
+
+ //--------------------------------------------------------------------------
+ // If the battery voltage measurement is at or below the LowDcdcBatteryVoltage
+ // level, we should definetly start charging the battery. The
+ // LowDcdcBatteryVoltage value should be low enough to account for IR voltage
+ // drop from the battery under heavy DCDC load.
+ //--------------------------------------------------------------------------
+
+ if (u16BatteryVoltage <
+ g_ddi_bc_Configuration.u16LowDcdcBatteryVoltage_mv) {
+ bRestartChargeCycle = true;
+
+ } else {
+ return (DDI_BC_STATUS_SUCCESS);
+ }
+ } else if (DcdcInactityTimer < DCDC_INACTIVITY_TIMER_THRESHOLD) {
+ DcdcInactityTimer +=
+ g_ddi_bc_Configuration.u32StateMachinePeriod;
+ if (DcdcInactityTimer >= DCDC_INACTIVITY_TIMER_THRESHOLD) {
+ bRestartChargeCycle = true;
+ }
+ }
+
+ if (bRestartChargeCycle) {
+ bRestartChargeCycle = false;
+ // start charging
+ 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 (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. If the DCDCs are on and this voltage drops too quickly,
+ // it will cause large droops and possible brownouts so we disable
+ // charging.
+ //----------------------------------------------------------------------
+
+ 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
+
+ //--------------------------------------------------------------------------
+ // In addition to 5V, is DCDC on also? If so, swith to DCDC Mode Waiting
+ // to Charge state.
+ //--------------------------------------------------------------------------
+
+ if (ddi_bc_hwIsDcdcOn()) {
+ TransitionToDcdcModeWaitingToCharge();
+ return (DDI_BC_STATUS_SUCCESS);
+ }
+
+ //--------------------------------------------------------------------------
+ // If the battery voltage isn't low, we don't need to be charging it. We
+ // use a 5% margin to decide.
+ //--------------------------------------------------------------------------
+
+ if (!bRestartChargeCycle) {
+ uint16_t x;
+
+ x = u16BatteryVoltage + (u16BatteryVoltage / 20);
+
+ if (x >= g_ddi_bc_Configuration.u16ChargingVoltage)
+ return (DDI_BC_STATUS_SUCCESS);
+
+ }
+
+ bRestartChargeCycle = false;
+ //--------------------------------------------------------------------------
+ // If control arrives here, the battery is low. How low?
+ //--------------------------------------------------------------------------
+
+ if (u16BatteryVoltage <
+ g_ddi_bc_Configuration.u16ConditioningThresholdVoltage) {
+
+ //----------------------------------------------------------------------
+ // If control arrives here, the battery is very low and it needs to be
+ // conditioned.
+ //----------------------------------------------------------------------
+
+ TransitionToConditioning();
+
+ } else {
+
+ //----------------------------------------------------------------------
+ // If control arrives here, the battery isn't too terribly low.
+ //----------------------------------------------------------------------
+
+ TransitionToCharging();
+
+ }
+
+ //--------------------------------------------------------------------------
+ // Return success.
+ //--------------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Conditioning state function.
+//!
+//! \fntype Function
+//!
+//! This function implements the Conditioning state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static ddi_bc_Status_t ddi_bc_Conditioning(void)
+{
+
+ //--------------------------------------------------------------------------
+ // The first order of business is to update alarms.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampUpdateAlarms();
+
+ //--------------------------------------------------------------------------
+ // If we're not under an alarm, increment the state timer.
+ //--------------------------------------------------------------------------
+
+ if (!ddi_bc_RampGetDieTempAlarm() && !ddi_bc_RampGetBatteryTempAlarm()) {
+ g_ddi_bc_u32StateTimer +=
+ g_ddi_bc_Configuration.u32StateMachinePeriod;
+ }
+ //--------------------------------------------------------------------------
+ // Check if the power supply is still around.
+ //--------------------------------------------------------------------------
+
+ if (!ddi_bc_hwPowerSupplyIsPresent()) {
+
+ //----------------------------------------------------------------------
+ // If control arrives here, the power supply has been removed. Go back
+ // and wait.
+ //----------------------------------------------------------------------
+
+ TransitionToWaitingToCharge();
+
+ //----------------------------------------------------------------------
+ // Return success.
+ //----------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+ }
+
+ //--------------------------------------------------------------------------
+ // If control arrives here, we're still connected to a power supply.
+ // Check if a battery is connected. If the voltage rises to high with only
+ // conditioning charge current, we determine that a battery is not connected.
+ // If that is not the case and a battery is connected, check
+ // if the battery voltage indicates it still needs conditioning.
+ //--------------------------------------------------------------------------
+
+// if (ddi_bc_hwGetBatteryVoltage() >= 3900) {
+ if ((ddi_bc_hwGetBatteryVoltage() >
+ g_ddi_bc_Configuration.u16ConditioningMaxVoltage) &&
+ (ddi_power_GetMaxBatteryChargeCurrent() <
+ g_ddi_bc_Configuration.u16ConditioningCurrent)) {
+ //----------------------------------------------------------------------
+ // If control arrives here, voltage has risen too quickly for so
+ // little charge being applied so their must be no battery connected.
+ //----------------------------------------------------------------------
+
+ ddi_bc_gBrokenReason = DDI_BC_BROKEN_NO_BATTERY_DETECTED;
+
+ TransitionToBroken();
+
+ //----------------------------------------------------------------------
+ // Tell our caller the battery appears to be broken.
+ //----------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_BROKEN);
+
+ }
+
+ if (ddi_bc_hwGetBatteryVoltage() >=
+ g_ddi_bc_Configuration.u16ConditioningMaxVoltage) {
+
+ //----------------------------------------------------------------------
+ // If control arrives here, this battery no longer needs conditioning.
+ //----------------------------------------------------------------------
+
+ TransitionToCharging();
+
+ //----------------------------------------------------------------------
+ // Return success.
+ //----------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+ }
+ //--------------------------------------------------------------------------
+ // Have we been in this state too long?
+ //--------------------------------------------------------------------------
+
+ if (g_ddi_bc_u32StateTimer >=
+ g_ddi_bc_Configuration.u32ConditioningTimeout) {
+
+ //----------------------------------------------------------------------
+ // If control arrives here, we've been here too long.
+ //----------------------------------------------------------------------
+
+ ddi_bc_gBrokenReason = DDI_BC_BROKEN_CHARGING_TIMEOUT;
+
+ TransitionToBroken();
+
+ //----------------------------------------------------------------------
+ // Tell our caller the battery appears to be broken.
+ //----------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_BROKEN);
+
+ }
+ //--------------------------------------------------------------------------
+ // If control arrives here, we're staying in this state. Step the current
+ // ramp.
+ //--------------------------------------------------------------------------
+
+ ddi_bc_RampStep(g_ddi_bc_Configuration.u32StateMachinePeriod);
+
+ //--------------------------------------------------------------------------
+ // Return success.
+ //--------------------------------------------------------------------------
+
+ return (DDI_BC_STATUS_SUCCESS);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Charging state function.
+//!
+//! \fntype Function
+//!
+//! This function implements the Charging state.
+//!
+////////////////////////////////////////////////////////////////////////////////
+static ddi_bc_Status_t ddi_bc_Charging(void)
+{
+
+ //--------------------------------------------------------------------------
+ // This variable counts the number of times we've seen the charging status
+ // bit cleared.
+ //--------------------------------------------------------------------------
+
+ static int iStatusCount = 0;
+ bool bIsDcdcOn;
+
+ //--------------------------------------------------------------------------
+ // 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).
+ //
+ //--------------------------------------------------------------------------
+
+ bIsDcdcOn = ddi_bc_hwIsDcdcOn();
+ if (bIsDcdcOn) {
+ ddi_bc_hwSetCurrentThreshold(g_ddi_bc_Configuration.
+ u16DdcdModeChargingThresholdCurrent);
+ } else {
+ 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++;
+
+ //----------------------------------------------------------------------
+ // If we are in DCDC operting mode, we only need this criteria to be true
+ // once before we advance to topping off. In 5V only mode, we want 10
+ // consecutive times before advancing to topping off.
+ //----------------------------------------------------------------------
+
+ if (bIsDcdcOn)
+ u8IlimitThresholdLimit = 1;
+ else
+ 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 back to the waiting to charge
+ // state if DCDCs are present or move to the Topping Off state if
+ // no DCDCs are present. Because we can't measure only the current
+ // going to the battery when the DCDCs are active, we don't know when
+ // to start topping off or how long to top off.
+ //
+ // 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
+
+ if (bIsDcdcOn) {
+ // We will restart the charge cycle once the DCDCs are no
+ // longer present.
+ DcdcInactityTimer = 0;
+
+ TransitionToWaitingToCharge();
+ } else if (g_ddi_bc_u32StateTimer <=
+ TRANSITION_TO_TOPOFF_MINIMUM_CHARGE_TIME_mS)
+ {
+ //------------------------------------------------------------------
+ // If we haven't actually didn't have to charge very long
+ // then the battery was already full. In this case, we do
+ // not top off so that we do not needlessly overcharge the
+ // battery.
+ //------------------------------------------------------------------
+ TransitionToWaitingToCharge();
+ } else {
+
+ //------------------------------------------------------------------
+ // 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
+////////////////////////////////////////////////////////////////////////////////
+//! @}
diff --git a/drivers/power/stmp37xx/ddi_bc_sm.h b/drivers/power/stmp37xx/ddi_bc_sm.h
new file mode 100644
index 000000000000..0e5fd8a1f144
--- /dev/null
+++ b/drivers/power/stmp37xx/ddi_bc_sm.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+////////////////////////////////////////////////////////////////////////////////
+//! \addtogroup ddi_bc
+//! @{
+//
+// Copyright (c) 2004-2005 SigmaTel, Inc.
+//
+//! \file ddi_bc_sm.h
+//! \brief Header file for the Battery Charger state machine.
+//! \date 06/2005
+//!
+//! This file contains declarations for the Battery Charger state machine.
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef _DDI_BC_SM_H
+#define _DDI_BC_SM_H
+
+////////////////////////////////////////////////////////////////////////////////
+// Externs
+////////////////////////////////////////////////////////////////////////////////
+
+//! The current state.
+
+extern ddi_bc_State_t g_ddi_bc_State;
+
+//! The state function table.
+
+extern ddi_bc_Status_t(*const (stateFunctionTable[])) (void);
+
+////////////////////////////////////////////////////////////////////////////////
+// End of file
+////////////////////////////////////////////////////////////////////////////////
+#endif // _DDI_BC_H
+//! @}
diff --git a/drivers/power/stmp37xx/ddi_power_battery.c b/drivers/power/stmp37xx/ddi_power_battery.c
new file mode 100644
index 000000000000..f9079fcce916
--- /dev/null
+++ b/drivers/power/stmp37xx/ddi_power_battery.c
@@ -0,0 +1,998 @@
+/*
+ * 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_power
+//! @{
+//
+// Copyright(C) 2005 SigmaTel, Inc.
+//
+//! \file ddi_power_battery.c
+//! \brief Implementation file for the power driver battery charger.
+//!
+////////////////////////////////////////////////////////////////////////////////
+// Includes and external references
+////////////////////////////////////////////////////////////////////////////////
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <asm/processor.h> /* cpu_relax */
+#include <mach/hardware.h>
+#include <mach/ddi_bc.h>
+#include <mach/lradc.h>
+#include <mach/regs-power.h>
+#include <mach/regs-lradc.h>
+#include <mach/lradc.h>
+#include "ddi_bc_internal.h"
+#include <mach/platform.h>
+
+//! \brief Base voltage to start battery calculations for LiIon
+#define BATT_BRWNOUT_LIION_BASE_MV 2800
+//! \brief Constant to help with determining whether to round up or
+//! not during calculation
+#define BATT_BRWNOUT_LIION_CEILING_OFFSET_MV 39
+//! \brief Number of mV to add if rounding up in LiIon mode
+#define BATT_BRWNOUT_LIION_LEVEL_STEP_MV 40
+//! \brief Constant value to be calculated by preprocessing
+#define BATT_BRWNOUT_LIION_EQN_CONST \
+ (BATT_BRWNOUT_LIION_BASE_MV - BATT_BRWNOUT_LIION_CEILING_OFFSET_MV)
+//! \brief Base voltage to start battery calculations for Alkaline/NiMH
+#define BATT_BRWNOUT_ALKAL_BASE_MV 800
+//! \brief Constant to help with determining whether to round up or
+//! not during calculation
+#define BATT_BRWNOUT_ALKAL_CEILING_OFFSET_MV 19
+//! \brief Number of mV to add if rounding up in Alkaline/NiMH mode
+#define BATT_BRWNOUT_ALKAL_LEVEL_STEP_MV 20
+//! \brief Constant value to be calculated by preprocessing
+#define BATT_BRWNOUT_ALKAL_EQN_CONST \
+ (BATT_BRWNOUT_ALKAL_BASE_MV - BATT_BRWNOUT_ALKAL_CEILING_OFFSET_MV)
+
+#define GAIN_CORRECTION 1012 // 1.012
+
+/* NOTE: the below define is different for 37xx and 378x */
+#define VBUSVALID_THRESH_4_30V 0x4
+#define LINREG_OFFSET_STEP_BELOW 0x2
+#define BP_POWER_BATTMONITOR_BATT_VAL 16
+#define BP_POWER_CHARGE_BATTCHRG_I 0
+#define BP_POWER_CHARGE_STOP_ILIMIT 8
+
+////////////////////////////////////////////////////////////////////////////////
+// Globals & Variables
+////////////////////////////////////////////////////////////////////////////////
+
+// FIXME
+/* We cant use VBUSVALID signal for VDD5V detection, since setting in
+ * USB driver POWER_DEBUG.VBUSVALIDPIOLOCK bit locks the POWER_STS.VBUSVALID to
+ * active state for all power states (even if the 5v went away). The
+ * POWER_CTRL.VBUSVALID_IRQ is also affected and it's impossible to get
+ * valid information about 5v presence.
+ */
+/* static ddi_power_5vDetection_t DetectionMethod =
+ DDI_POWER_5V_VDD5V_GT_VDDIO; */
+static ddi_power_5vDetection_t DetectionMethod = DDI_POWER_5V_VBUSVALID;
+
+////////////////////////////////////////////////////////////////////////////////
+// Code
+////////////////////////////////////////////////////////////////////////////////
+
+#if 0
+static void dump_regs(void)
+{
+ printk("HW_POWER_CHARGE 0x%08x\n", __raw_readl(REGS_POWER_BASE + HW_POWER_CHARGE));
+ printk("HW_POWER_STS 0x%08x\n", __raw_readl(REGS_POWER_BASE + HW_POWER_STS));
+ printk("HW_POWER_BATTMONITOR 0x%08x\n", __raw_readl(REGS_POWER_BASE + HW_POWER_BATTMONITOR));
+}
+#endif
+
+//! This array maps bit numbers to current increments, as used in the register
+//! fields HW_POWER_CHARGE.STOP_ILIMIT and HW_POWER_CHARGE.BATTCHRG_I.
+static const uint16_t currentPerBit[] = { 10, 20, 50, 100, 200, 400 };
+
+uint16_t ddi_power_convert_current_to_setting(uint16_t u16Current)
+{
+ int i;
+ uint16_t u16Mask;
+ uint16_t u16Setting = 0;
+
+ // Scan across the bit field, adding in current increments.
+ u16Mask = (0x1 << 5);
+
+ for (i = 5; (i >= 0) && (u16Current > 0); i--, u16Mask >>= 1) {
+ if (u16Current >= currentPerBit[i]) {
+ u16Current -= currentPerBit[i];
+ u16Setting |= u16Mask;
+ }
+ }
+
+ // Return the result.
+ return(u16Setting);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//! See hw_power.h for details.
+////////////////////////////////////////////////////////////////////////////////
+uint16_t ddi_power_convert_setting_to_current(uint16_t u16Setting)
+{
+ int i;
+ uint16_t u16Mask;
+ uint16_t u16Current = 0;
+
+ // Scan across the bit field, adding in current increments.
+ u16Mask = (0x1 << 5);
+
+ for (i = 5; i >= 0; i--, u16Mask >>= 1) {
+ if (u16Setting & u16Mask) u16Current += currentPerBit[i];
+ }
+
+ // Return the result.
+ return(u16Current);
+}
+
+void ddi_power_Enable5vDetection(void)
+{
+ u32 val;
+ // Disable hardware power down when 5V is inserted or removed
+ stmp3xxx_clearl(BM_POWER_5VCTRL_PWDN_5VBRNOUT, REGS_POWER_BASE + HW_POWER_5VCTRL);
+
+ /*
+ * Prepare the hardware for the detection method. We used to set
+ * and clear the VBUSVALID_5VDETECT bit, but that is also used for
+ * the DCDC 5V detection. It is sufficient to just check the status
+ * bits to see if 5V is present.
+ *
+ * Use VBUSVALID for DCDC 5V detection. The DCDC's detection is
+ * different than the USB/5V detection used to switch profiles. This
+ * is used to determine when a handoff should occur.
+ */
+ stmp3xxx_setl(BM_POWER_5VCTRL_VBUSVALID_5VDETECT, REGS_POWER_BASE + HW_POWER_5VCTRL);
+
+ // Set 5V detection threshold to 4.3V for VBUSVALID.
+ stmp3xxx_setl(
+ BF(VBUSVALID_THRESH_4_30V, POWER_5VCTRL_VBUSVALID_TRSH), REGS_POWER_BASE + HW_POWER_5VCTRL);
+
+ // gotta set LINREG_OFFSET to STEP_BELOW according to manual
+ val = __raw_readl(REGS_POWER_BASE + HW_POWER_VDDIOCTRL);
+ val &= ~(BM_POWER_VDDIOCTRL_LINREG_OFFSET);
+ val |= BF(LINREG_OFFSET_STEP_BELOW, POWER_VDDIOCTRL_LINREG_OFFSET);
+ __raw_writel(val, REGS_POWER_BASE + HW_POWER_VDDIOCTRL);
+
+ val = __raw_readl(REGS_POWER_BASE + HW_POWER_VDDACTRL);
+ val &= ~(BM_POWER_VDDACTRL_LINREG_OFFSET);
+ val |= BF(LINREG_OFFSET_STEP_BELOW, POWER_VDDACTRL_LINREG_OFFSET);
+ __raw_writel(val, REGS_POWER_BASE + HW_POWER_VDDACTRL);
+
+ val = __raw_readl(REGS_POWER_BASE + HW_POWER_VDDDCTRL);
+ val &= ~(BM_POWER_VDDDCTRL_LINREG_OFFSET);
+ val |= BF(LINREG_OFFSET_STEP_BELOW, POWER_VDDDCTRL_LINREG_OFFSET);
+ __raw_writel(val, REGS_POWER_BASE + HW_POWER_VDDDCTRL);
+
+ /* Clear vbusvalid interrupt flag */
+// stmp3xxx_clearl(BM_POWER_CTRL_VBUSVALID_IRQ, REGS_POWER_BASE + HW_POWER_CTRL);
+ stmp3xxx_clearl(BM_POWER_CTRL_VDD5V_GT_VDDIO_IRQ, REGS_POWER_BASE + HW_POWER_CTRL);
+ /* enable vbusvalid irq */
+// stmp3xxx_setl(BM_POWER_CTRL_ENIRQ_VBUS_VALID, REGS_POWER_BASE + HW_POWER_CTRL);
+ stmp3xxx_setl(BM_POWER_CTRL_ENIRQ_VDD5V_GT_VDDIO, REGS_POWER_BASE + HW_POWER_CTRL);
+}
+
+/*
+ * This function prepares the hardware for a 5V-to-battery handoff. It assumes
+ * the current configuration is using 5V as the power source. The 5V
+ * interrupt will be set up for a 5V removal.
+ */
+void ddi_power_enable_5v_to_battery_handoff(void)
+{
+ /* Clear vbusvalid interrupt flag */
+// stmp3xxx_clearl(BM_POWER_CTRL_VBUSVALID_IRQ, REGS_POWER_BASE + HW_POWER_CTRL);
+ stmp3xxx_clearl(BM_POWER_CTRL_VDD5V_GT_VDDIO_IRQ, REGS_POWER_BASE + HW_POWER_CTRL);
+
+ /* detect 5v unplug */
+// stmp3xxx_clearl(BM_POWER_CTRL_POLARITY_VBUSVALID, REGS_POWER_BASE + HW_POWER_CTRL);
+ stmp3xxx_clearl(BM_POWER_CTRL_POLARITY_VDD5V_GT_VDDIO, REGS_POWER_BASE + HW_POWER_CTRL);
+
+ // Enable automatic transition to DCDC
+ stmp3xxx_setl(BM_POWER_5VCTRL_DCDC_XFER, REGS_POWER_BASE + HW_POWER_5VCTRL);
+}
+
+/*
+ * This function will handle all the power rail transitions necesarry to power
+ * the chip from the battery when it was previously powered from the 5V power
+ * source.
+ */
+void ddi_power_execute_5v_to_battery_handoff(void)
+{
+ u32 val;
+ // VDDD has different configurations depending on the battery type
+ // and battery level.
+
+ // For LiIon battery, we will use the DCDC to power VDDD.
+ // Use LinReg offset for DCDC mode.
+ // Turn on the VDDD DCDC output and turn off the VDDD LinReg output.
+ // Make sure stepping is enabled when using DCDC.
+ val = __raw_readl(REGS_POWER_BASE + HW_POWER_VDDDCTRL);
+ val &= ~(BM_POWER_VDDDCTRL_DISABLE_FET | BM_POWER_VDDDCTRL_ENABLE_LINREG |
+ BM_POWER_VDDDCTRL_DISABLE_STEPPING | BM_POWER_VDDDCTRL_LINREG_OFFSET);
+ val |= BF(LINREG_OFFSET_STEP_BELOW, POWER_VDDDCTRL_LINREG_OFFSET);
+ __raw_writel(val, REGS_POWER_BASE + HW_POWER_VDDDCTRL);
+
+ // Power VDDA and VDDIO from the DCDC.
+ // Use LinReg offset for DCDC mode.
+ val = __raw_readl(REGS_POWER_BASE + HW_POWER_VDDACTRL);
+ val &= ~(BM_POWER_VDDACTRL_LINREG_OFFSET);
+ val |= BF(LINREG_OFFSET_STEP_BELOW, POWER_VDDACTRL_LINREG_OFFSET);
+ __raw_writel(val, REGS_POWER_BASE + HW_POWER_VDDACTRL);
+
+ // Turn on the VDDA DCDC converter output and turn off LinReg output.
+ // Make sure stepping is enabled when using DCDC.
+ val = __raw_readl(REGS_POWER_BASE + HW_POWER_VDDACTRL);
+ val &= ~(BM_POWER_VDDACTRL_DISABLE_FET |
+ BM_POWER_VDDACTRL_ENABLE_LINREG |
+ BM_POWER_VDDACTRL_DISABLE_STEPPING);
+ __raw_writel(val, REGS_POWER_BASE + HW_POWER_VDDACTRL);
+
+ // Use LinReg offset for DCDC mode.
+ val = __raw_readl(REGS_POWER_BASE + HW_POWER_VDDIOCTRL);
+ val &= ~(BM_POWER_VDDIOCTRL_LINREG_OFFSET);
+ val |= BF(LINREG_OFFSET_STEP_BELOW, POWER_VDDIOCTRL_LINREG_OFFSET);
+ __raw_writel(val, REGS_POWER_BASE + HW_POWER_VDDIOCTRL);
+ // Turn on the VDDIO DCDC output and turn on the LinReg output.
+ val = __raw_readl(REGS_POWER_BASE + HW_POWER_VDDIOCTRL);
+ val &= ~(BM_POWER_VDDIOCTRL_DISABLE_FET);
+ __raw_writel(val, REGS_POWER_BASE + HW_POWER_VDDIOCTRL);
+
+ stmp3xxx_clearl(BM_POWER_5VCTRL_ILIMIT_EQ_ZERO, REGS_POWER_BASE + HW_POWER_5VCTRL);
+ // Make sure stepping is enabled when using DCDC.
+ val = __raw_readl(REGS_POWER_BASE + HW_POWER_VDDIOCTRL);
+ val &= ~(BM_POWER_VDDIOCTRL_DISABLE_STEPPING);
+ __raw_writel(val, REGS_POWER_BASE + HW_POWER_VDDIOCTRL);
+}
+
+/*
+ * This function sets up battery-to-5V handoff. The power switch from
+ * battery to 5V is automatic. This funtion enables the 5V present detection
+ * such that the 5V interrupt can be generated if it is enabled. (The interrupt
+ * handler can inform software the 5V present event.) To deal with noise or
+ * a high current, this function enables DCDC1/2 based on the battery mode.
+ */
+void ddi_power_enable_battery_to_5v_handoff(void)
+{
+ /* Clear vbusvalid interrupt flag */
+// stmp3xxx_clearl(BM_POWER_CTRL_VBUSVALID_IRQ, REGS_POWER_BASE + HW_POWER_CTRL);
+ stmp3xxx_clearl(BM_POWER_CTRL_VDD5V_GT_VDDIO_IRQ, REGS_POWER_BASE + HW_POWER_CTRL);
+
+ /* detect 5v plug-in */
+// stmp3xxx_setl(BM_POWER_CTRL_POLARITY_VBUSVALID, REGS_POWER_BASE + HW_POWER_CTRL);
+ stmp3xxx_setl(BM_POWER_CTRL_POLARITY_VDD5V_GT_VDDIO, REGS_POWER_BASE + HW_POWER_CTRL);
+
+ // Force current from 5V to be zero by disabling its entry source.
+ stmp3xxx_setl(BM_POWER_5VCTRL_ILIMIT_EQ_ZERO, REGS_POWER_BASE + HW_POWER_5VCTRL);
+
+ // Allow DCDC be to active when 5V is present.
+ stmp3xxx_setl(BM_POWER_5VCTRL_ENABLE_DCDC, REGS_POWER_BASE + HW_POWER_5VCTRL);
+}
+
+/* This function handles the transitions on each of the power rails necessary
+ * to power the chip from the 5V power supply when it was previously powered
+ * from the battery power supply.
+ */
+void ddi_power_execute_battery_to_5v_handoff(void)
+{
+ u32 val;
+ // Disable the DCDC during 5V connections.
+ stmp3xxx_clearl(BM_POWER_5VCTRL_ENABLE_DCDC, REGS_POWER_BASE + HW_POWER_5VCTRL);
+
+ // Power the VDDD/VDDA/VDDIO rail from the linear regulator. The DCDC
+ // is ready to automatically power the chip when 5V is removed.
+ // Use this configuration when powering from 5V
+
+ // Use LinReg offset for LinReg mode
+ val = __raw_readl(REGS_POWER_BASE + HW_POWER_VDDDCTRL);
+ val &= ~BM_POWER_VDDDCTRL_LINREG_OFFSET;
+ val |= BF(LINREG_OFFSET_STEP_BELOW, POWER_VDDDCTRL_LINREG_OFFSET);
+ __raw_writel(val, REGS_POWER_BASE + HW_POWER_VDDDCTRL);
+
+ // Turn on the VDDD LinReg and turn on the VDDD DCDC output. The
+ // ENABLE_DCDC must be cleared to avoid LinReg and DCDC conflict.
+ val = __raw_readl(REGS_POWER_BASE + HW_POWER_VDDDCTRL);
+ val &= ~(BM_POWER_VDDDCTRL_ENABLE_LINREG | BM_POWER_VDDDCTRL_DISABLE_FET);
+ val |= BM_POWER_VDDDCTRL_ENABLE_LINREG;
+ __raw_writel(val, REGS_POWER_BASE + HW_POWER_VDDDCTRL);
+ // Make sure stepping is disabled when using linear regulators
+ val = __raw_readl(REGS_POWER_BASE + HW_POWER_VDDDCTRL);
+ val &= ~(BM_POWER_VDDDCTRL_DISABLE_STEPPING);
+ val |= BM_POWER_VDDDCTRL_DISABLE_STEPPING;
+ __raw_writel(val, REGS_POWER_BASE + HW_POWER_VDDDCTRL);
+
+ // Use LinReg offset for LinReg mode
+ val = __raw_readl(REGS_POWER_BASE + HW_POWER_VDDACTRL);
+ val &= ~(BM_POWER_VDDACTRL_LINREG_OFFSET);
+ val |= BF(LINREG_OFFSET_STEP_BELOW, POWER_VDDACTRL_LINREG_OFFSET);
+ __raw_writel(val, REGS_POWER_BASE + HW_POWER_VDDACTRL);
+
+ // Turn on the VDDA LinReg output and prepare the DCDC for transfer.
+ // ENABLE_DCDC must be clear to avoid DCDC and LinReg conflict.
+ // Make sure stepping is disabled when using linear regulators
+ val = __raw_readl(REGS_POWER_BASE + HW_POWER_VDDACTRL);
+ val &= ~(BM_POWER_VDDACTRL_ENABLE_LINREG | BM_POWER_VDDACTRL_DISABLE_FET |
+ BM_POWER_VDDACTRL_DISABLE_STEPPING);
+ val |= BM_POWER_VDDACTRL_ENABLE_LINREG | BM_POWER_VDDACTRL_DISABLE_STEPPING;
+ __raw_writel(val, REGS_POWER_BASE + HW_POWER_VDDACTRL);
+
+ // Use LinReg offset for LinReg mode.
+ val = __raw_readl(REGS_POWER_BASE + HW_POWER_VDDIOCTRL);
+ val &= ~(BM_POWER_VDDIOCTRL_LINREG_OFFSET);
+ val |= BF(LINREG_OFFSET_STEP_BELOW, POWER_VDDIOCTRL_LINREG_OFFSET);
+ __raw_writel(val, REGS_POWER_BASE + HW_POWER_VDDIOCTRL);
+
+ // Turn on the VDDIO LinReg output and prepare the VDDIO DCDC output.
+ // ENABLE_DCDC must be cleared to prevent DCDC and LinReg conflict.
+ val = __raw_readl(REGS_POWER_BASE + HW_POWER_VDDIOCTRL);
+ val &= ~(BM_POWER_VDDIOCTRL_DISABLE_FET);
+ __raw_writel(val, REGS_POWER_BASE + HW_POWER_VDDIOCTRL);
+
+ stmp3xxx_clearl(BM_POWER_5VCTRL_ILIMIT_EQ_ZERO, REGS_POWER_BASE + HW_POWER_5VCTRL);
+ // Make sure stepping is disabled when using DCDC.
+ val = __raw_readl(REGS_POWER_BASE + HW_POWER_VDDIOCTRL);
+ val |= BM_POWER_VDDIOCTRL_DISABLE_STEPPING;
+ __raw_writel(val, REGS_POWER_BASE + HW_POWER_VDDIOCTRL);
+}
+
+void ddi_power_init_handoff(void)
+{
+ u32 val;
+ /*
+ * The following settings give optimal power supply capability and
+ * efficiency. Extreme loads will need HALF_FETS cleared and
+ * possibly DOUBLE_FETS set. The below setting are probably also
+ * the best for alkaline mode also but more characterization is
+ * needed to know for sure.
+ */
+ // Increase the RCSCALE_THRESHOLD
+ stmp3xxx_setl(BM_POWER_LOOPCTRL_RCSCALE_THRESH,
+ REGS_POWER_BASE + HW_POWER_LOOPCTRL);
+ // Increase the RCSCALE level for quick DCDC response to dynamic load
+ stmp3xxx_setl(BF(3, POWER_LOOPCTRL_EN_RCSCALE),
+ REGS_POWER_BASE + HW_POWER_LOOPCTRL); // 8x
+
+ // Enable half fets for increase efficiency.
+ stmp3xxx_setl(BM_POWER_MINPWR_HALF_FETS, REGS_POWER_BASE + HW_POWER_MINPWR);
+
+ // enable 5v presence detection
+ ddi_power_Enable5vDetection();
+
+ if (ddi_power_Get5vPresentFlag())
+ /* It's 5V mode, enable 5V-to-battery handoff */
+ ddi_power_enable_5v_to_battery_handoff();
+ else
+ /* It's battery mode, enable battery-to-5V handoff */
+ ddi_power_enable_battery_to_5v_handoff();
+
+ // Finally enable the battery adjust
+ val = __raw_readl(REGS_POWER_BASE + HW_POWER_BATTMONITOR);
+ val |= BM_POWER_BATTMONITOR_EN_BATADJ;
+ __raw_writel(val, REGS_POWER_BASE + HW_POWER_BATTMONITOR);
+}
+
+int ddi_power_init_battery(void)
+{
+ int ret;
+
+ // Init LRADC channel 7
+ ret = hw_lradc_init_ladder(BATTERY_VOLTAGE_CH,
+ LRADC_DELAY_TRIGGER_BATTERY,
+ 200);
+ if (ret) {
+ printk(KERN_ERR "%s: hw_lradc_init_ladder failed\n", __func__);
+ return ret;
+ }
+
+ stmp3xxx_setl(BM_LRADC_CONVERSION_AUTOMATIC, REGS_LRADC_BASE + HW_LRADC_CONVERSION);
+
+ // Set li-ion mode
+ stmp3xxx_setl(BF(2, LRADC_CONVERSION_SCALE_FACTOR), REGS_LRADC_BASE + HW_LRADC_CONVERSION);
+
+ // Turn off divide-by-two - we already have a divide-by-four
+ // as part of the hardware
+ stmp3xxx_clearl(
+ BF(1 << BATTERY_VOLTAGE_CH, LRADC_CTRL2_DIVIDE_BY_TWO), REGS_LRADC_BASE + HW_LRADC_CTRL2);
+
+ stmp3xxx_setl(BM_POWER_CHARGE_ENABLE_FAULT_DETECT, REGS_POWER_BASE + HW_POWER_CHARGE);
+
+ // kick off the trigger
+ hw_lradc_set_delay_trigger_kick(LRADC_DELAY_TRIGGER_BATTERY, 1);
+
+ /* prepare handoff */
+ ddi_power_init_handoff();
+
+ return 0;
+}
+
+/*
+ * Use the the lradc7 channel dedicated for battery voltage measurement to
+ * get the die temperature from on-chip sensor.
+ */
+uint16_t MeasureInternalDieTemperature(void)
+{
+ uint32_t ch8Value, ch9Value;
+
+ /* power up internal tep sensor block */
+ stmp3xxx_clearl(BM_LRADC_CTRL2_TEMPSENSE_PWD, REGS_LRADC_BASE + HW_LRADC_CTRL2);
+
+ /* mux to the lradc 8th temp channel */
+ stmp3xxx_clearl(BF(0xF, LRADC_CTRL4_LRADC7SELECT), REGS_LRADC_BASE + HW_LRADC_CTRL4);
+ stmp3xxx_setl(BF(8, LRADC_CTRL4_LRADC7SELECT), REGS_LRADC_BASE + HW_LRADC_CTRL4);
+
+ /* Clear the interrupt flag */
+ stmp3xxx_clearl(BM_LRADC_CTRL1_LRADC7_IRQ, REGS_LRADC_BASE + HW_LRADC_CTRL1);
+ stmp3xxx_setl(BF(1 << BATTERY_VOLTAGE_CH, LRADC_CTRL0_SCHEDULE), REGS_LRADC_BASE + HW_LRADC_CTRL0);
+ // Wait for conversion complete
+ while (!(__raw_readl(REGS_LRADC_BASE + HW_LRADC_CTRL1) & BM_LRADC_CTRL1_LRADC7_IRQ))
+ cpu_relax();
+ /* Clear the interrupt flag again */
+ stmp3xxx_clearl(BM_LRADC_CTRL1_LRADC7_IRQ, REGS_LRADC_BASE + HW_LRADC_CTRL1);
+ // read temperature value and clr lradc
+ ch8Value = __raw_readl(REGS_LRADC_BASE + HW_LRADC_CHn(BATTERY_VOLTAGE_CH)) & BM_LRADC_CHn_VALUE;
+ stmp3xxx_clearl(BM_LRADC_CHn_VALUE, REGS_LRADC_BASE + HW_LRADC_CHn(BATTERY_VOLTAGE_CH));
+
+ /* mux to the lradc 9th temp channel */
+ stmp3xxx_clearl(BF(0xF, LRADC_CTRL4_LRADC7SELECT), REGS_LRADC_BASE + HW_LRADC_CTRL4);
+ stmp3xxx_setl(BF(9, LRADC_CTRL4_LRADC7SELECT), REGS_LRADC_BASE + HW_LRADC_CTRL4);
+
+ /* Clear the interrupt flag */
+ stmp3xxx_clearl(BM_LRADC_CTRL1_LRADC7_IRQ, REGS_LRADC_BASE + HW_LRADC_CTRL1);
+ stmp3xxx_setl(BF(1 << BATTERY_VOLTAGE_CH, LRADC_CTRL0_SCHEDULE), REGS_LRADC_BASE + HW_LRADC_CTRL0);
+ // Wait for conversion complete
+ while (!(__raw_readl(REGS_LRADC_BASE + HW_LRADC_CTRL1) & BM_LRADC_CTRL1_LRADC7_IRQ))
+ cpu_relax();
+ /* Clear the interrupt flag */
+ stmp3xxx_clearl(BM_LRADC_CTRL1_LRADC7_IRQ, REGS_LRADC_BASE + HW_LRADC_CTRL1);
+ // read temperature value
+ ch9Value = __raw_readl(REGS_LRADC_BASE + HW_LRADC_CHn(BATTERY_VOLTAGE_CH)) & BM_LRADC_CHn_VALUE;
+ stmp3xxx_clearl(BM_LRADC_CHn_VALUE, REGS_LRADC_BASE + HW_LRADC_CHn(BATTERY_VOLTAGE_CH));
+
+ /* power down temp sensor block */
+ stmp3xxx_setl(BM_LRADC_CTRL2_TEMPSENSE_PWD, REGS_LRADC_BASE + HW_LRADC_CTRL2);
+
+ /* mux back to the lradc 7th battery voltage channel */
+ stmp3xxx_clearl(BF(0xF, LRADC_CTRL4_LRADC7SELECT), REGS_LRADC_BASE + HW_LRADC_CTRL4);
+ stmp3xxx_setl(BF(7, LRADC_CTRL4_LRADC7SELECT), REGS_LRADC_BASE + HW_LRADC_CTRL4);
+
+ /* Clear the interrupt flag */
+ stmp3xxx_clearl(BM_LRADC_CTRL1_LRADC7_IRQ, REGS_LRADC_BASE + HW_LRADC_CTRL1);
+ stmp3xxx_setl(BF(1 << BATTERY_VOLTAGE_CH, LRADC_CTRL0_SCHEDULE), REGS_LRADC_BASE + HW_LRADC_CTRL0);
+ // Wait for conversion complete
+ while (!(__raw_readl(REGS_LRADC_BASE + HW_LRADC_CTRL1) & BM_LRADC_CTRL1_LRADC7_IRQ))
+ cpu_relax();
+ /* Clear the interrupt flag */
+ stmp3xxx_clearl(BM_LRADC_CTRL1_LRADC7_IRQ, REGS_LRADC_BASE + HW_LRADC_CTRL1);
+
+ return (uint16_t)((ch9Value-ch8Value)*GAIN_CORRECTION/4000);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//! Name: ddi_power_GetBatteryMode
+//!
+//! \brief
+////////////////////////////////////////////////////////////////////////////////
+ddi_power_BatteryMode_t ddi_power_GetBatteryMode(void)
+{
+#if 0
+ return (__raw_readl(REGS_POWER_BASE + HW_POWER_STS) & BM_POWER_STS_MODE) ?
+ DDI_POWER_BATT_MODE_ALKALINE_NIMH :
+ DDI_POWER_BATT_MODE_LIION;
+#endif
+ return DDI_POWER_BATT_MODE_LIION;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//! Name: ddi_power_GetBatteryChargerEnabled
+//!
+//! \brief
+////////////////////////////////////////////////////////////////////////////////
+bool ddi_power_GetBatteryChargerEnabled(void)
+{
+#if 0
+ return (__raw_readl(REGS_POWER_BASE + HW_POWER_STS) & BM_POWER_STS_BATT_CHRG_PRESENT) ? 1 : 0;
+#endif
+ return 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Report if the charger hardware power is on.
+//!
+//! \fntype Function
+//!
+//! This function reports if the charger hardware power is on.
+//!
+//! \retval Zero if the charger hardware is not powered. Non-zero otherwise.
+//!
+//! Note that the bit we're looking at is named PWD_BATTCHRG. The "PWD"
+//! stands for "power down". Thus, when the bit is set, the battery charger
+//! hardware is POWERED DOWN.
+////////////////////////////////////////////////////////////////////////////////
+bool ddi_power_GetChargerPowered(void)
+{
+ return (__raw_readl(REGS_POWER_BASE + HW_POWER_CHARGE) & BM_POWER_CHARGE_PWD_BATTCHRG) ? 0 : 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Turn the charging hardware on or off.
+//!
+//! \fntype Function
+//!
+//! This function turns the charging hardware on or off.
+//!
+//! \param[in] on Indicates whether the charging hardware should be on or off.
+//!
+//! Note that the bit we're looking at is named PWD_BATTCHRG. The "PWD"
+//! stands for "power down". Thus, when the bit is set, the battery charger
+//! hardware is POWERED DOWN.
+////////////////////////////////////////////////////////////////////////////////
+void ddi_power_SetChargerPowered(bool bPowerOn)
+{
+ // Hit the battery charge power switch.
+ if (bPowerOn) {
+ stmp3xxx_clearl(BM_POWER_CHARGE_PWD_BATTCHRG, REGS_POWER_BASE + HW_POWER_CHARGE);
+ stmp3xxx_clearl(BM_POWER_5VCTRL_PWD_CHARGE_4P2, REGS_POWER_BASE + HW_POWER_5VCTRL);
+ } else {
+ stmp3xxx_setl(BM_POWER_CHARGE_PWD_BATTCHRG, REGS_POWER_BASE + HW_POWER_CHARGE);
+ stmp3xxx_setl(BM_POWER_5VCTRL_PWD_CHARGE_4P2, REGS_POWER_BASE + HW_POWER_5VCTRL);
+ }
+
+//#ifdef CONFIG_POWER_SUPPLY_DEBUG
+#if 0
+ printk("Battery charger: charger %s\n", bPowerOn ? "ON!" : "OFF");
+ dump_regs();
+#endif
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Reports if the charging current has fallen below the threshold.
+//!
+//! \fntype Function
+//!
+//! This function reports if the charging current that the battery is accepting
+//! has fallen below the threshold.
+//!
+//! Note that this bit is regarded by the hardware guys as very slightly
+//! unreliable. They recommend that you don't believe a value of zero until
+//! you've sampled it twice.
+//!
+//! \retval Zero if the battery is accepting less current than indicated by the
+//! charging threshold. Non-zero otherwise.
+//!
+////////////////////////////////////////////////////////////////////////////////
+int ddi_power_GetChargeStatus(void)
+{
+ return (__raw_readl(REGS_POWER_BASE + HW_POWER_STS) & BM_POWER_STS_CHRGSTS) ? 1 : 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Battery Voltage
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Report the voltage across the battery.
+//!
+//! \fntype Function
+//!
+//! This function reports the voltage across the battery. Should return a
+//! value in range ~3000 - 4200 mV.
+//!
+//! \retval The voltage across the battery, in mV.
+//!
+////////////////////////////////////////////////////////////////////////////////
+
+//! \brief Constant value for 8mV steps used in battery translation
+#define BATT_VOLTAGE_8_MV 8
+
+uint16_t ddi_power_GetBattery(void)
+{
+ uint32_t u16BattVolt;
+
+ // Get the raw result of battery measurement
+ u16BattVolt = __raw_readl(REGS_POWER_BASE + HW_POWER_BATTMONITOR);
+ u16BattVolt &= BM_POWER_BATTMONITOR_BATT_VAL;
+ u16BattVolt >>= BP_POWER_BATTMONITOR_BATT_VAL;
+
+ // Adjust for 8-mV LSB resolution and return
+ u16BattVolt *= BATT_VOLTAGE_8_MV;
+
+//#ifdef CONFIG_POWER_SUPPLY_DEBUG
+#if 0
+ printk("Battery charger: %u mV\n", u16BattVolt);
+#endif
+
+ return u16BattVolt;
+}
+
+#if 0
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Report the voltage across the battery.
+//!
+//! \fntype Function
+//!
+//! This function reports the voltage across the battery.
+//!
+//! \retval The voltage across the battery, in mV.
+//!
+////////////////////////////////////////////////////////////////////////////////
+uint16_t ddi_power_GetBatteryBrownout(void)
+{
+ uint32_t u16BatteryBrownoutLevel;
+
+ // Get battery brownout level
+ u16BatteryBrownoutLevel = __raw_readl(REGS_POWER_BASE + HW_POWER_BATTMONITOR);
+ u16BatteryBrownoutLevel &= BM_POWER_BATTMONITOR_BRWNOUT_LVL;
+ u16BatteryBrownoutLevel >>= BP_POWER_BATTMONITOR_BRWNOUT_LVL;
+
+ // Calculate battery brownout level
+ switch (ddi_power_GetBatteryMode()) {
+ case DDI_POWER_BATT_MODE_LIION:
+ u16BatteryBrownoutLevel *= BATT_BRWNOUT_LIION_LEVEL_STEP_MV;
+ u16BatteryBrownoutLevel += BATT_BRWNOUT_LIION_BASE_MV;
+ break;
+ case DDI_POWER_BATT_MODE_ALKALINE_NIMH:
+ u16BatteryBrownoutLevel *= BATT_BRWNOUT_ALKAL_LEVEL_STEP_MV;
+ u16BatteryBrownoutLevel += BATT_BRWNOUT_ALKAL_BASE_MV;
+ break;
+ default:
+ u16BatteryBrownoutLevel = 0;
+ break;
+ }
+ return u16BatteryBrownoutLevel;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Set battery brownout level
+//!
+//! \fntype Reentrant Function
+//!
+//! This function sets the battery brownout level in millivolt. It transforms the
+//! input brownout value from millivolts to the hardware register bit field value
+//! taking the ceiling value in the calculation.
+//!
+//! \param[in] u16BattBrownout_mV Battery battery brownout level in mV
+//!
+//! \return SUCCESS
+//!
+////////////////////////////////////////////////////////////////////////////////
+int ddi_power_SetBatteryBrownout(uint16_t u16BattBrownout_mV)
+{
+ int16_t i16BrownoutLevel;
+ int ret = 0;
+
+ // Calculate battery brownout level
+ switch (ddi_power_GetBatteryMode()) {
+ case DDI_POWER_BATT_MODE_LIION:
+ i16BrownoutLevel = u16BattBrownout_mV -
+ BATT_BRWNOUT_LIION_EQN_CONST;
+ i16BrownoutLevel /= BATT_BRWNOUT_LIION_LEVEL_STEP_MV;
+ break;
+ case DDI_POWER_BATT_MODE_ALKALINE_NIMH:
+ i16BrownoutLevel = u16BattBrownout_mV -
+ BATT_BRWNOUT_ALKAL_EQN_CONST;
+ i16BrownoutLevel /= BATT_BRWNOUT_ALKAL_LEVEL_STEP_MV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ // Do a check to make sure nothing went wrong.
+ if (i16BrownoutLevel <= 0x0f) {
+ //Write the battery brownout level
+ stmp3xxx_setl(
+ BF(i16BrownoutLevel, POWER_BATTMONITOR_BRWNOUT_LVL), REGS_POWER_BASE + HW_POWER_BATTMONITOR);
+ } else
+ ret = -EINVAL;
+
+ return ret;
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Currents
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//! Name: ddi_power_SetBiasCurrentSource
+//!
+//! \brief
+////////////////////////////////////////////////////////////////////////////////
+int ddi_power_SetBiasCurrentSource(ddi_power_BiasCurrentSource_t eSource)
+{
+ switch (eSource) {
+ case DDI_POWER_INTERNAL_BIAS_CURRENT:
+ stmp3xxx_setl(BM_POWER_CHARGE_USE_EXTERN_R, REGS_POWER_BASE + HW_POWER_CHARGE);
+ break;
+ case DDI_POWER_EXTERNAL_BIAS_CURRENT:
+ stmp3xxx_clearl(BM_POWER_CHARGE_USE_EXTERN_R, REGS_POWER_BASE + HW_POWER_CHARGE);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//! Name: ddi_power_GetBiasCurrentSource
+//!
+//! \brief
+////////////////////////////////////////////////////////////////////////////////
+ddi_power_BiasCurrentSource_t ddi_power_GetBiasCurrentSource(void)
+{
+ return (__raw_readl(REGS_POWER_BASE + HW_POWER_CHARGE) & BM_POWER_CHARGE_USE_EXTERN_R) ?
+ DDI_POWER_INTERNAL_BIAS_CURRENT :
+ DDI_POWER_EXTERNAL_BIAS_CURRENT;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//! Name: ddi_power_SetMaxBatteryChargeCurrent
+//!
+//! \brief
+////////////////////////////////////////////////////////////////////////////////
+uint16_t ddi_power_SetMaxBatteryChargeCurrent(uint16_t u16MaxCur)
+{
+ uint32_t u16OldSetting;
+ uint32_t u16NewSetting;
+ uint32_t u16ToggleMask;
+
+ // Get the old setting.
+ u16OldSetting = (__raw_readl(REGS_POWER_BASE + HW_POWER_CHARGE) & BM_POWER_CHARGE_BATTCHRG_I) >>
+ BP_POWER_CHARGE_BATTCHRG_I;
+
+ // Convert the new threshold into a setting.
+ u16NewSetting = ddi_power_convert_current_to_setting(u16MaxCur);
+
+ // Write to the toggle register.
+ u16ToggleMask = __raw_readl(REGS_POWER_BASE + HW_POWER_CHARGE);
+ u16ToggleMask &= ~BM_POWER_CHARGE_BATTCHRG_I;
+ u16ToggleMask |= u16NewSetting << BP_POWER_CHARGE_BATTCHRG_I;
+
+ __raw_writel(u16ToggleMask, REGS_POWER_BASE + HW_POWER_CHARGE);
+
+ // Tell the caller what current we're set at now.
+ return ddi_power_convert_setting_to_current(u16NewSetting);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//! Name: ddi_power_GetMaxBatteryChargeCurrent
+//!
+//! \brief
+////////////////////////////////////////////////////////////////////////////////
+uint16_t ddi_power_GetMaxBatteryChargeCurrent(void)
+{
+ uint32_t u8Bits;
+
+ // Get the raw data from register
+ u8Bits = (__raw_readl(REGS_POWER_BASE + HW_POWER_CHARGE) & BM_POWER_CHARGE_BATTCHRG_I) >>
+ BP_POWER_CHARGE_BATTCHRG_I;
+
+ // Translate raw data to current (in mA) and return it
+ return ddi_power_convert_setting_to_current(u8Bits);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//! Name: ddi_power_GetMaxChargeCurrent
+//!
+//! \brief
+////////////////////////////////////////////////////////////////////////////////
+uint16_t ddi_power_SetBatteryChargeCurrentThreshold(uint16_t u16Thresh)
+{
+ uint32_t u16OldSetting;
+ uint32_t u16NewSetting;
+ uint32_t u16ToggleMask;
+
+ //-------------------------------------------------------------------
+ // See ddi_power_SetMaxBatteryChargeCurrent for an explanation of
+ // why we're using the toggle register here.
+ //
+ // Since this function doesn't have any major hardware effect,
+ // we could use the usual macros for writing to this bit field. But,
+ // for the sake of parallel construction and any potentially odd
+ // effects on the status bit, we use the toggle register in the same
+ // way as ddi_bc_hwSetMaxCurrent.
+ //-------------------------------------------------------------------
+
+ //-------------------------------------------------------------------
+ // The threshold hardware can't express as large a range as the max
+ // current setting, but we can use the same functions as long as we
+ // add an extra check here.
+ //
+ // Thresholds larger than 180mA can't be expressed.
+ //-------------------------------------------------------------------
+
+ if (u16Thresh > 180)
+ u16Thresh = 180;
+
+ ////////////////////////////////////////
+ // Create the mask
+ ////////////////////////////////////////
+
+ // Get the old setting.
+ u16OldSetting = (__raw_readl(REGS_POWER_BASE + HW_POWER_CHARGE) & BM_POWER_CHARGE_STOP_ILIMIT) >>
+ BP_POWER_CHARGE_STOP_ILIMIT;
+
+ // Convert the new threshold into a setting.
+ u16NewSetting = ddi_power_convert_current_to_setting(u16Thresh);
+
+ // Compute the toggle mask.
+ u16ToggleMask = u16OldSetting ^ u16NewSetting;
+
+ /////////////////////////////////////////
+ // Write to the register
+ /////////////////////////////////////////
+
+ // Write to the toggle register.
+ u16ToggleMask = __raw_readl(REGS_POWER_BASE + HW_POWER_CHARGE);
+ u16ToggleMask &= ~BM_POWER_CHARGE_STOP_ILIMIT;
+ u16ToggleMask |= u16NewSetting << BP_POWER_CHARGE_STOP_ILIMIT;
+
+ // Tell the caller what current we're set at now.
+ return ddi_power_convert_setting_to_current(u16NewSetting);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//! Name: ddi_power_GetBatteryChargeCurrentThreshold
+//!
+//! \brief
+////////////////////////////////////////////////////////////////////////////////
+uint16_t ddi_power_GetBatteryChargeCurrentThreshold(void)
+{
+ uint32_t u16Threshold;
+
+ u16Threshold = (__raw_readl(REGS_POWER_BASE + HW_POWER_CHARGE) & BM_POWER_CHARGE_STOP_ILIMIT) >>
+ BP_POWER_CHARGE_STOP_ILIMIT;
+
+ return ddi_power_convert_setting_to_current(u16Threshold);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Conversion
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Compute the actual current expressible in the hardware.
+//!
+//! \fntype Function
+//!
+//! Given a desired current, this function computes the actual current
+//! expressible in the hardware.
+//!
+//! Note that the hardware has a minimum resolution of 10mA and a maximum
+//! expressible value of 780mA (see the data sheet for details). If the given
+//! current cannot be expressed exactly, then the largest expressible smaller
+//! value will be used.
+//!
+//! \param[in] u16Current The current of interest.
+//!
+//! \retval The corresponding current in mA.
+//!
+////////////////////////////////////////////////////////////////////////////////
+uint16_t ddi_power_ExpressibleCurrent(uint16_t u16Current)
+{
+ return ddi_power_convert_setting_to_current(
+ ddi_power_convert_current_to_setting(u16Current));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//! Name: ddi_power_Get5VPresent
+//!
+//! \brief
+////////////////////////////////////////////////////////////////////////////////
+bool ddi_power_Get5vPresentFlag(void)
+{
+ switch (DetectionMethod) {
+ case DDI_POWER_5V_VBUSVALID:
+ // Check VBUSVALID for 5V present
+ return ((__raw_readl(REGS_POWER_BASE + HW_POWER_STS) & BM_POWER_STS_VBUSVALID) != 0);
+ case DDI_POWER_5V_VDD5V_GT_VDDIO:
+ // Check VDD5V_GT_VDDIO for 5V present
+ return ((__raw_readl(REGS_POWER_BASE + HW_POWER_STS) & BM_POWER_STS_VDD5V_GT_VDDIO) != 0);
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Report on the die temperature.
+//!
+//! \fntype Function
+//!
+//! This function reports on the die temperature.
+//!
+//! \param[out] pLow The low end of the temperature range.
+//! \param[out] pHigh The high end of the temperature range.
+//!
+////////////////////////////////////////////////////////////////////////////////
+// Temperature constant
+#define TEMP_READING_ERROR_MARGIN 5
+#define KELVIN_TO_CELSIUS_CONST 273
+
+void ddi_power_GetDieTemp(int16_t * pLow, int16_t * pHigh)
+{
+ int16_t i16High, i16Low;
+ uint16_t u16Reading;
+
+ // Get the reading in Kelvins
+ u16Reading = MeasureInternalDieTemperature();
+
+ // Adjust for error margin
+ i16High = u16Reading + TEMP_READING_ERROR_MARGIN;
+ i16Low = u16Reading - TEMP_READING_ERROR_MARGIN;
+
+ // Convert to Celsius
+ i16High -= KELVIN_TO_CELSIUS_CONST;
+ i16Low -= KELVIN_TO_CELSIUS_CONST;
+
+//#ifdef CONFIG_POWER_SUPPLY_DEBUG
+#if 0
+ printk("Battery charger: Die temp %d to %d C\n", i16Low, i16High);
+#endif
+ // Return the results
+ *pHigh = i16High;
+ *pLow = i16Low;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//!
+//! \brief Checks to see if the DCDC has been manually enabled
+//!
+//! \fntype Function
+//!
+//! \retval true if DCDC is ON, false if DCDC is OFF.
+//!
+////////////////////////////////////////////////////////////////////////////////
+bool ddi_power_IsDcdcOn(void)
+{
+ return (__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL) & BM_POWER_5VCTRL_ENABLE_DCDC) ? 1 : 0;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//! See hw_power.h for details.
+////////////////////////////////////////////////////////////////////////////////
+void ddi_power_SetPowerClkGate(bool bGate)
+{
+ // Gate/Ungate the clock to the power block
+ if (bGate) {
+ stmp3xxx_setl(BM_POWER_CTRL_CLKGATE, REGS_POWER_BASE + HW_POWER_CTRL);
+ } else {
+ stmp3xxx_clearl(BM_POWER_CTRL_CLKGATE, REGS_POWER_BASE + HW_POWER_CTRL);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//! See hw_power.h for details.
+////////////////////////////////////////////////////////////////////////////////
+bool ddi_power_GetPowerClkGate(void)
+{
+ return (__raw_readl(REGS_POWER_BASE + HW_POWER_CTRL) & BM_POWER_CTRL_CLKGATE) ? 1 : 0;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// End of file
+////////////////////////////////////////////////////////////////////////////////
+//! @}
diff --git a/drivers/power/stmp37xx/ddi_power_battery.h b/drivers/power/stmp37xx/ddi_power_battery.h
new file mode 100644
index 000000000000..2d7c1a5411ad
--- /dev/null
+++ b/drivers/power/stmp37xx/ddi_power_battery.h
@@ -0,0 +1,67 @@
+/*
+ * 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
+ */
+
+//! \brief Battery modes
+typedef enum {
+ // 37xx battery modes
+ //! \brief LiIon battery powers the player
+ DDI_POWER_BATT_MODE_LIION = 0,
+ //! \brief Alkaline/NiMH battery powers the player
+ DDI_POWER_BATT_MODE_ALKALINE_NIMH = 1,
+} ddi_power_BatteryMode_t;
+
+
+//! \brief Available sources for bias currents
+typedef enum {
+ //! \brief Use external resistor to generate bias current
+ DDI_POWER_EXTERNAL_BIAS_CURRENT = 0x0,
+ //! \brief Use internal resistor to generate bias current
+ DDI_POWER_INTERNAL_BIAS_CURRENT = 0x1
+} ddi_power_BiasCurrentSource_t;
+
+//! \brief Possible 5V detection methods
+typedef enum {
+ //! \brief Use VBUSVALID comparator for detection
+ DDI_POWER_5V_VBUSVALID,
+ //! \brief Use VDD5V_GT_VDDIO comparison for detection
+ DDI_POWER_5V_VDD5V_GT_VDDIO
+} ddi_power_5vDetection_t;
+
+
+uint16_t ddi_power_convert_current_to_setting(uint16_t u16Current);
+uint16_t ddi_power_convert_setting_to_current(uint16_t u16Setting);
+void ddi_power_enable_5v_to_battery_handoff(void);
+void ddi_power_execute_5v_to_battery_handoff(void);
+void ddi_power_enable_battery_to_5v_handoff(void);
+void ddi_power_execute_battery_to_5v_handoff(void);
+int ddi_power_init_battery(void);
+ddi_power_BatteryMode_t ddi_power_GetBatteryMode(void);
+bool ddi_power_GetBatteryChargerEnabled(void);
+bool ddi_power_GetChargerPowered(void);
+void ddi_power_SetChargerPowered(bool bPowerOn);
+int ddi_power_GetChargeStatus(void);
+uint16_t ddi_power_GetBattery(void);
+uint16_t ddi_power_GetBatteryBrownout(void);
+int ddi_power_SetBatteryBrownout(uint16_t u16BattBrownout_mV);
+int ddi_power_SetBiasCurrentSource(ddi_power_BiasCurrentSource_t eSource);
+ddi_power_BiasCurrentSource_t ddi_power_GetBiasCurrentSource(void);
+uint16_t ddi_power_SetMaxBatteryChargeCurrent(uint16_t u16MaxCur);
+uint16_t ddi_power_GetMaxBatteryChargeCurrent(void);
+uint16_t ddi_power_SetBatteryChargeCurrentThreshold(uint16_t u16Thresh);
+uint16_t ddi_power_GetBatteryChargeCurrentThreshold(void);
+uint16_t ddi_power_ExpressibleCurrent(uint16_t u16Current);
+bool ddi_power_Get5vPresentFlag(void);
+void ddi_power_GetDieTemp(int16_t * pLow, int16_t * pHigh);
+bool ddi_power_IsDcdcOn(void);
+void ddi_power_SetPowerClkGate(bool bGate);
+bool ddi_power_GetPowerClkGate(void);
diff --git a/drivers/power/stmp37xx/linux.c b/drivers/power/stmp37xx/linux.c
new file mode 100644
index 000000000000..178255eceea6
--- /dev/null
+++ b/drivers/power/stmp37xx/linux.c
@@ -0,0 +1,623 @@
+/*
+ * Linux glue to STMP3xxx battery state machine.
+ *
+ * Author: Steve Longerbeam <stevel@embeddedalley.com>
+ *
+ * Copyright (C) 2008 EmbeddedAlley Solutions Inc.
+ * Copyright 2008-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <mach/ddi_bc.h>
+#include "ddi_bc_internal.h"
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+#include <mach/regulator.h>
+#include <mach/regs-power.h>
+#include <mach/regs-usbphy.h>
+#include <mach/platform.h>
+#include <linux/delay.h>
+
+#include <linux/interrupt.h>
+
+
+struct stmp3xxx_info {
+ struct device *dev;
+ struct regulator *regulator;
+
+ struct power_supply bat;
+ struct power_supply ac;
+ struct power_supply usb;
+
+ ddi_bc_Cfg_t *sm_cfg;
+ struct mutex sm_lock;
+ struct timer_list sm_timer;
+ struct work_struct sm_work;
+ struct resource *vdd5v_irq;
+ int is_ac_online;
+#define USB_ONLINE 0x01
+#define USB_REG_SET 0x02
+#define USB_SM_RESTART 0x04
+#define USB_SHUTDOWN 0x08
+#define USB_N_SEND 0x10
+ int is_usb_online;
+};
+
+#define to_stmp3xxx_info(x) container_of((x), struct stmp3xxx_info, bat)
+
+/* There is no direct way to detect wall power presence, so assume the AC
+ * power source is valid if 5V presents and USB device is disconnected.
+ * If USB device is connected then assume that AC is offline and USB power
+ * is online.
+ */
+#define is_usb_plugged()(__raw_readl(REGS_USBPHY_BASE + HW_USBPHY_STATUS) & \
+ BM_USBPHY_STATUS_DEVPLUGIN_STATUS)
+#define is_ac_online() \
+ (ddi_power_Get5vPresentFlag() ? (!is_usb_plugged()) : 0)
+#define is_usb_online() \
+ (ddi_power_Get5vPresentFlag() ? (!!is_usb_plugged()) : 0)
+
+/*
+ * Power properties
+ */
+static enum power_supply_property stmp3xxx_power_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+static int stmp3xxx_power_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ if (psy->type == POWER_SUPPLY_TYPE_MAINS)
+ /* ac online */
+ val->intval = is_ac_online();
+ else
+ /* usb online */
+ val->intval = is_usb_online();
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+/*
+ * Battery properties
+ */
+static enum power_supply_property stmp3xxx_bat_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_TEMP,
+};
+
+static int stmp3xxx_bat_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct stmp3xxx_info *info = to_stmp3xxx_info(psy);
+ ddi_bc_State_t state;
+ ddi_bc_BrokenReason_t reason;
+ int temp_alarm;
+ int16_t temp_lo, temp_hi;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ state = ddi_bc_GetState();
+ switch (state) {
+ case DDI_BC_STATE_CONDITIONING:
+ case DDI_BC_STATE_CHARGING:
+ case DDI_BC_STATE_TOPPING_OFF:
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ break;
+ case DDI_BC_STATE_DISABLED:
+ val->intval = ddi_power_Get5vPresentFlag() ?
+ POWER_SUPPLY_STATUS_NOT_CHARGING :
+ POWER_SUPPLY_STATUS_DISCHARGING;
+ break;
+ default:
+ /* TODO: detect full */
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ }
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ /* is battery present */
+ state = ddi_bc_GetState();
+ switch (state) {
+ case DDI_BC_STATE_WAITING_TO_CHARGE:
+ case DDI_BC_STATE_DCDC_MODE_WAITING_TO_CHARGE:
+ case DDI_BC_STATE_CONDITIONING:
+ case DDI_BC_STATE_CHARGING:
+ case DDI_BC_STATE_TOPPING_OFF:
+ case DDI_BC_STATE_DISABLED:
+ val->intval = 1;
+ break;
+ case DDI_BC_STATE_BROKEN:
+ val->intval = !(ddi_bc_GetBrokenReason() ==
+ DDI_BC_BROKEN_NO_BATTERY_DETECTED);
+ break;
+ default:
+ val->intval = 0;
+ break;
+ }
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ temp_alarm = ddi_bc_RampGetDieTempAlarm();
+ if (temp_alarm) {
+ val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+ } else {
+ state = ddi_bc_GetState();
+ switch (state) {
+ case DDI_BC_STATE_BROKEN:
+ reason = ddi_bc_GetBrokenReason();
+ val->intval =
+ (reason == DDI_BC_BROKEN_CHARGING_TIMEOUT) ?
+ POWER_SUPPLY_HEALTH_DEAD :
+ POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+ break;
+ case DDI_BC_STATE_UNINITIALIZED:
+ val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
+ break;
+ default:
+ val->intval = POWER_SUPPLY_HEALTH_GOOD;
+ break;
+ }
+ }
+ break;
+ case POWER_SUPPLY_PROP_TECHNOLOGY:
+ val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ /* uV */
+ val->intval = ddi_power_GetBattery() * 1000;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ /* uA */
+ val->intval = ddi_power_GetMaxBatteryChargeCurrent() * 1000;
+ break;
+ case POWER_SUPPLY_PROP_TEMP:
+ mutex_lock(&info->sm_lock);
+ ddi_power_GetDieTemp(&temp_lo, &temp_hi);
+ mutex_unlock(&info->sm_lock);
+ val->intval = temp_lo + (temp_hi - temp_lo) / 2;
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void state_machine_timer(unsigned long data)
+{
+ struct stmp3xxx_info *info = (struct stmp3xxx_info *)data;
+ ddi_bc_Cfg_t *cfg = info->sm_cfg;
+ int ret;
+
+ /* schedule next call to state machine */
+ mod_timer(&info->sm_timer,
+ jiffies + msecs_to_jiffies(cfg->u32StateMachinePeriod));
+
+ ret = schedule_work(&info->sm_work);
+ if (!ret)
+ dev_dbg(info->dev, "state machine failed to schedule\n");
+
+}
+/*
+ * Assumtion:
+ * AC power can't be switched to USB w/o system reboot
+ * and vice-versa
+ */
+static void state_machine_work(struct work_struct *work)
+{
+ struct stmp3xxx_info *info =
+ container_of(work, struct stmp3xxx_info, sm_work);
+
+ mutex_lock(&info->sm_lock);
+
+ if (info->is_usb_online & USB_SHUTDOWN) {
+ info->is_usb_online = 0;
+ if (!info->regulator)
+ goto out;
+ regulator_set_current_limit(info->regulator, 0, 0);
+ goto out;
+ }
+
+ if (is_ac_online()) {
+ if (info->is_ac_online)
+ goto done;
+
+ /* ac supply connected */
+ dev_info(info->dev, "changed power connection to ac/5v \n");
+
+ info->is_ac_online = 1;
+ info->is_usb_online = 0;
+ ddi_bc_SetCurrentLimit(600 /*mA*/);
+ ddi_power_execute_battery_to_5v_handoff();
+ ddi_power_enable_5v_to_battery_handoff();
+ goto done;
+ }
+
+ if (!is_usb_online())
+ goto out;
+
+ if (info->is_usb_online & USB_REG_SET)
+ goto done;
+
+ info->is_ac_online = 0;
+ info->is_usb_online |= USB_ONLINE;
+
+ if (!info->regulator) {
+ info->regulator = regulator_get(NULL, "charger-1");
+ if (!info->regulator || IS_ERR(info->regulator)) {
+ dev_err(info->dev,
+ "%s: failed to get regulator\n", __func__);
+ info->regulator = NULL;
+ ddi_bc_SetCurrentLimit(350 /*mA*/);
+ ddi_power_execute_battery_to_5v_handoff();
+ ddi_power_enable_5v_to_battery_handoff();
+ goto done;
+ } else
+ regulator_set_mode(info->regulator,
+ REGULATOR_MODE_FAST);
+ }
+
+ if (!(info->is_usb_online & USB_N_SEND)) {
+ info->is_usb_online |= USB_N_SEND;
+ }
+
+ if (regulator_set_current_limit(info->regulator, 150000, 150000)) {
+ dev_err(info->dev, "reg_set_current(150000) failed\n");
+
+ ddi_bc_SetCurrentLimit(0 /*mA*/);
+ dev_dbg(info->dev, "charge current set to 0\n");
+ mod_timer(&info->sm_timer, jiffies + msecs_to_jiffies(1000));
+ goto done;
+ }
+
+ dev_dbg(info->dev, "%s: charge current set to 100mA\n", __func__);
+ ddi_bc_SetCurrentLimit(100 /*mA*/);
+ regulator_set_current_limit(info->regulator, 100000, 100000);
+ if (info->is_usb_online & USB_SM_RESTART) {
+ info->is_usb_online &= ~USB_SM_RESTART;
+ ddi_bc_SetEnable();
+ }
+
+ info->is_usb_online |= USB_REG_SET;
+
+ dev_info(info->dev, "changed power connection to usb/5v present\n");
+ ddi_power_execute_battery_to_5v_handoff();
+ ddi_power_enable_5v_to_battery_handoff();
+ ddi_bc_SetEnable();
+
+done:
+ ddi_bc_StateMachine();
+out:
+ mutex_unlock(&info->sm_lock);
+}
+
+static int bc_sm_restart(struct stmp3xxx_info *info)
+{
+ ddi_bc_Status_t bcret;
+ int ret = 0;
+
+ mutex_lock(&info->sm_lock);
+
+ /* ungate power clk */
+ ddi_power_SetPowerClkGate(0);
+
+ /*
+ * config battery charger state machine and move it to the Disabled
+ * state. This must be done before starting the state machine.
+ */
+ bcret = ddi_bc_Init(info->sm_cfg);
+ if (bcret != DDI_BC_STATUS_SUCCESS) {
+ dev_err(info->dev, "state machine init failed: %d\n", bcret);
+ ret = -EIO;
+ goto out;
+ }
+
+ /*
+ * Check what power supply options we have right now. If
+ * we're able to do any battery charging, then set the
+ * appropriate current limit and enable. Otherwise, leave
+ * the battery charger disabled.
+ */
+ if (is_ac_online()) {
+ /* ac supply connected */
+ dev_info(info->dev, "ac/5v present, enabling state machine\n");
+
+ info->is_ac_online = 1;
+ info->is_usb_online = 0;
+ ddi_bc_SetCurrentLimit(600 /*mA*/);
+ ddi_bc_SetEnable();
+ } else if (is_usb_online()) {
+ /* usb supply connected */
+ dev_info(info->dev, "usb/5v present, enabling state machine\n");
+
+ info->is_ac_online = 0;
+ info->is_usb_online = USB_ONLINE | USB_SM_RESTART;
+ } else {
+ /* not powered */
+ dev_info(info->dev, "%s: 5v not present\n", __func__);
+
+ info->is_ac_online = 0;
+ info->is_usb_online = 0;
+ ddi_bc_SetDisable();
+ }
+
+ /* schedule first call to state machine */
+ mod_timer(&info->sm_timer, jiffies + 1);
+out:
+ mutex_unlock(&info->sm_lock);
+ return ret;
+}
+
+static irqreturn_t stmp3xxx_vdd5v_irq(int irq, void *cookie)
+{
+ struct stmp3xxx_info *info = (struct stmp3xxx_info *)cookie;
+
+ if (ddi_power_Get5vPresentFlag()) {
+ dev_info(info->dev, "5v present, reenable state machine\n");
+
+ ddi_bc_SetEnable();
+
+ /*
+ * We only ack/negate the interrupt here,
+ * as we can't decide yet if we really can
+ * switch to 5V (USB bits not ready)
+ */
+ ddi_power_enable_5v_to_battery_handoff();
+ } else {
+ dev_info(info->dev, "5v went away, disabling state machine\n");
+
+ ddi_bc_SetDisable();
+
+ info->is_ac_online = 0;
+ if (info->is_usb_online)
+ info->is_usb_online = USB_SHUTDOWN;
+
+ ddi_power_execute_5v_to_battery_handoff();
+ ddi_power_enable_battery_to_5v_handoff();
+ mod_timer(&info->sm_timer, jiffies + 1);
+
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int stmp3xxx_bat_probe(struct platform_device *pdev)
+{
+ struct stmp3xxx_info *info;
+ int ret = 0;
+
+ if (!pdev->dev.platform_data) {
+ printk(KERN_ERR "%s: missing platform data\n", __func__);
+ return -ENODEV;
+ }
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->vdd5v_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (info->vdd5v_irq == NULL) {
+ printk(KERN_ERR "%s: failed to get irq resouce\n", __func__);
+ goto free_info;
+ }
+
+ platform_set_drvdata(pdev, info);
+
+ info->dev = &pdev->dev;
+ info->sm_cfg = pdev->dev.platform_data;
+
+ /* initialize bat power_supply struct */
+ info->bat.name = "battery";
+ info->bat.type = POWER_SUPPLY_TYPE_BATTERY;
+ info->bat.properties = stmp3xxx_bat_props;
+ info->bat.num_properties = ARRAY_SIZE(stmp3xxx_bat_props);
+ info->bat.get_property = stmp3xxx_bat_get_property;
+
+ /* initialize ac power_supply struct */
+ info->ac.name = "ac";
+ info->ac.type = POWER_SUPPLY_TYPE_MAINS;
+ info->ac.properties = stmp3xxx_power_props;
+ info->ac.num_properties = ARRAY_SIZE(stmp3xxx_power_props);
+ info->ac.get_property = stmp3xxx_power_get_property;
+
+ /* initialize usb power_supply struct */
+ info->usb.name = "usb";
+ info->usb.type = POWER_SUPPLY_TYPE_USB;
+ info->usb.properties = stmp3xxx_power_props;
+ info->usb.num_properties = ARRAY_SIZE(stmp3xxx_power_props);
+ info->usb.get_property = stmp3xxx_power_get_property;
+
+ init_timer(&info->sm_timer);
+ info->sm_timer.data = (unsigned long)info;
+ info->sm_timer.function = state_machine_timer;
+
+ mutex_init(&info->sm_lock);
+ INIT_WORK(&info->sm_work, state_machine_work);
+
+ /* init LRADC channels to measure battery voltage and die temp */
+ ddi_power_init_battery();
+ stmp3xxx_clearl(BM_POWER_5VCTRL_ENABLE_LINREG_ILIMIT, REGS_POWER_BASE + HW_POWER_5VCTRL);
+
+ ret = bc_sm_restart(info);
+ if (ret)
+ goto free_info;
+
+ ret = request_irq(info->vdd5v_irq->start,
+ stmp3xxx_vdd5v_irq, IRQF_DISABLED,
+ pdev->name, info);
+ if (ret) {
+ dev_err(info->dev, "failed to request irq\n");
+ goto stop_sm;
+ }
+
+ ret = power_supply_register(&pdev->dev, &info->bat);
+ if (ret) {
+ dev_err(info->dev, "failed to register battery\n");
+ goto free_irq;
+ }
+
+ ret = power_supply_register(&pdev->dev, &info->ac);
+ if (ret) {
+ dev_err(info->dev, "failed to register ac power supply\n");
+ goto unregister_bat;
+ }
+
+ ret = power_supply_register(&pdev->dev, &info->usb);
+ if (ret) {
+ dev_err(info->dev, "failed to register usb power supply\n");
+ goto unregister_ac;
+ }
+
+ /* enable usb device presence detection */
+ stmp3xxx_setl(BM_USBPHY_CTRL_ENDEVPLUGINDETECT, REGS_USBPHY_BASE + HW_USBPHY_CTRL);
+
+ return 0;
+
+unregister_ac:
+ power_supply_unregister(&info->ac);
+unregister_bat:
+ power_supply_unregister(&info->bat);
+free_irq:
+ free_irq(info->vdd5v_irq->start, pdev);
+stop_sm:
+ ddi_bc_ShutDown();
+free_info:
+ kfree(info);
+ return ret;
+}
+
+static int stmp3xxx_bat_remove(struct platform_device *pdev)
+{
+ struct stmp3xxx_info *info = platform_get_drvdata(pdev);
+
+ if (info->regulator)
+ regulator_put(info->regulator);
+ free_irq(info->vdd5v_irq->start, pdev);
+ ddi_bc_ShutDown();
+ power_supply_unregister(&info->usb);
+ power_supply_unregister(&info->ac);
+ power_supply_unregister(&info->bat);
+ return 0;
+}
+
+static void stmp3xxx_bat_shutdown(struct platform_device *pdev)
+{
+ ddi_bc_ShutDown();
+}
+
+
+#ifdef CONFIG_PM
+
+static int stmp3xxx_bat_suspend(struct platform_device *pdev, pm_message_t msg)
+{
+ struct stmp3xxx_info *info = platform_get_drvdata(pdev);
+
+ mutex_lock(&info->sm_lock);
+
+ /* disable 5v irq */
+ stmp3xxx_clearl(BM_POWER_CTRL_ENIRQ_VDD5V_GT_VDDIO, REGS_POWER_BASE + HW_POWER_CTRL);
+
+ ddi_bc_SetDisable();
+ /* cancel state machine timer */
+ del_timer_sync(&info->sm_timer);
+
+ mutex_unlock(&info->sm_lock);
+ return 0;
+}
+
+static int stmp3xxx_bat_resume(struct platform_device *pdev)
+{
+ struct stmp3xxx_info *info = platform_get_drvdata(pdev);
+ ddi_bc_Cfg_t *cfg = info->sm_cfg;
+
+ mutex_lock(&info->sm_lock);
+
+ if (is_ac_online()) {
+ /* ac supply connected */
+ dev_info(info->dev, "ac/5v present, enabling state machine\n");
+
+ info->is_ac_online = 1;
+ info->is_usb_online = 0;
+ ddi_bc_SetCurrentLimit(600 /*mA*/);
+ ddi_bc_SetEnable();
+ } else if (is_usb_online()) {
+ /* usb supply connected */
+ dev_info(info->dev, "usb/5v present, enabling state machine\n");
+
+ info->is_ac_online = 0;
+ info->is_usb_online = 1;
+ ddi_bc_SetCurrentLimit(350 /*mA*/);
+ ddi_bc_SetEnable();
+ } else {
+ /* not powered */
+ dev_info(info->dev, "%s: 5v not present\n", __func__);
+
+ info->is_ac_online = 0;
+ info->is_usb_online = 0;
+ }
+
+ /* enable 5v irq */
+ stmp3xxx_setl(BM_POWER_CTRL_ENIRQ_VDD5V_GT_VDDIO, REGS_POWER_BASE + HW_POWER_CTRL);
+
+ /* reschedule calls to state machine */
+ mod_timer(&info->sm_timer,
+ jiffies + msecs_to_jiffies(cfg->u32StateMachinePeriod));
+
+ mutex_unlock(&info->sm_lock);
+ return 0;
+}
+
+#else
+#define stmp3xxx_bat_suspend NULL
+#define stmp3xxx_bat_resume NULL
+#endif
+
+static struct platform_driver stmp3xxx_batdrv = {
+ .probe = stmp3xxx_bat_probe,
+ .remove = stmp3xxx_bat_remove,
+ .shutdown = stmp3xxx_bat_shutdown,
+ .suspend = stmp3xxx_bat_suspend,
+ .resume = stmp3xxx_bat_resume,
+ .driver = {
+ .name = "stmp3xxx-battery",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init stmp3xxx_bat_init(void)
+{
+ return platform_driver_register(&stmp3xxx_batdrv);
+}
+
+static void __exit stmp3xxx_bat_exit(void)
+{
+ platform_driver_unregister(&stmp3xxx_batdrv);
+}
+
+module_init(stmp3xxx_bat_init);
+module_exit(stmp3xxx_bat_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Steve Longerbeam <stevel@embeddedalley.com>");
+MODULE_DESCRIPTION("Linux glue to STMP3xxx battery state machine");