diff options
Diffstat (limited to 'drivers/power/mxs/ddi_power_battery.c')
-rw-r--r-- | drivers/power/mxs/ddi_power_battery.c | 1908 |
1 files changed, 1908 insertions, 0 deletions
diff --git a/drivers/power/mxs/ddi_power_battery.c b/drivers/power/mxs/ddi_power_battery.c new file mode 100644 index 000000000000..762f29bd784e --- /dev/null +++ b/drivers/power/mxs/ddi_power_battery.c @@ -0,0 +1,1908 @@ +/* + * Copyright (C) 2010 Freescale Semiconductor, Inc. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + + +/* addtogroup ddi_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 <linux/io.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" + +/* 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 */ + +#define VBUSVALID_THRESH_2_90V 0x0 +#define VBUSVALID_THRESH_4_00V 0x1 +#define VBUSVALID_THRESH_4_10V 0x2 +#define VBUSVALID_THRESH_4_20V 0x3 +#define VBUSVALID_THRESH_4_30V 0x4 +#define VBUSVALID_THRESH_4_40V 0x5 +#define VBUSVALID_THRESH_4_50V 0x6 +#define VBUSVALID_THRESH_4_60V 0x7 + +#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 + +#define VDD4P2_ENABLED + +#define DDI_POWER_BATTERY_XFER_THRESHOLD_MV 3200 + + +#ifndef BATTERY_VOLTAGE_CMPTRIP100_THRESHOLD_MV +#define BATTERY_VOLTAGE_CMPTRIP100_THRESHOLD_MV 4000 +#endif + +#ifndef BATTERY_VOLTAGE_CMPTRIP105_THRESHOLD_MV +#define BATTERY_VOLTAGE_CMPTRIP105_THRESHOLD_MV 3800 +#endif + +/* #define DEBUG_IRQS */ + +/* to be re-enabled once FIQ functionality is added */ +#define DISABLE_VDDIO_BO_PROTECTION + +#ifdef CONFIG_ARCH_MX28 +#define BM_POWER_STS_VBUSVALID BM_POWER_STS_VBUSVALID0 +#endif + +/* Globals & Variables */ + + + +/* Select your 5V Detection method */ + +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 */ + __raw_writel(BM_POWER_5VCTRL_PWDN_5VBRNOUT, + REGS_POWER_BASE + HW_POWER_5VCTRL_CLR); + + /* Enabling VBUSVALID hardware detection even if VDD5V_GT_VDDIO + * is the detection method being used for 5V status (hardware + * or software). This is in case any other drivers (such as + * USB) are specifically monitoring VBUSVALID status + */ + __raw_writel(BM_POWER_5VCTRL_VBUSVALID_5VDETECT, + REGS_POWER_BASE + HW_POWER_5VCTRL_SET); + + /* Set 5V detection threshold to 4.3V for VBUSVALID. */ + __raw_writel( + BF_POWER_5VCTRL_VBUSVALID_TRSH(VBUSVALID_THRESH_4_30V), + REGS_POWER_BASE + HW_POWER_5VCTRL_SET); + + /* 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_POWER_VDDIOCTRL_LINREG_OFFSET(LINREG_OFFSET_STEP_BELOW); + __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_POWER_VDDACTRL_LINREG_OFFSET(LINREG_OFFSET_STEP_BELOW); + __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_POWER_VDDDCTRL_LINREG_OFFSET(LINREG_OFFSET_STEP_BELOW); + __raw_writel(val, REGS_POWER_BASE + HW_POWER_VDDDCTRL); + + /* Clear vbusvalid interrupt flag */ + __raw_writel(BM_POWER_CTRL_VBUSVALID_IRQ, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + __raw_writel(BM_POWER_CTRL_VDD5V_GT_VDDIO_IRQ, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + /* enable vbusvalid irq */ + + + /* enable 5V Detection interrupt vbusvalid irq */ + switch (DetectionMethod) { + case DDI_POWER_5V_VBUSVALID: + /* Check VBUSVALID for 5V present */ + __raw_writel(BM_POWER_CTRL_ENIRQ_VBUS_VALID, + REGS_POWER_BASE + HW_POWER_CTRL_SET); + break; + case DDI_POWER_5V_VDD5V_GT_VDDIO: + /* Check VDD5V_GT_VDDIO for 5V present */ + __raw_writel(BM_POWER_CTRL_ENIRQ_VDD5V_GT_VDDIO, + REGS_POWER_BASE + HW_POWER_CTRL_SET); + break; + } +} + +/* + * 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 */ + __raw_writel(BM_POWER_CTRL_VBUSVALID_IRQ, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + __raw_writel(BM_POWER_CTRL_VDD5V_GT_VDDIO_IRQ, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + + /* detect 5v unplug */ + __raw_writel(BM_POWER_CTRL_POLARITY_VBUSVALID, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + __raw_writel(BM_POWER_CTRL_POLARITY_VDD5V_GT_VDDIO, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + +#ifndef VDD4P2_ENABLED + /* Enable automatic transition to DCDC */ + __raw_writel(BM_POWER_5VCTRL_DCDC_XFER, + REGS_POWER_BASE + HW_POWER_5VCTRL_SET); +#endif +} + +/* + * 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) +{ + int val; +#ifdef VDD4P2_ENABLED + val = __raw_readl(REGS_POWER_BASE + HW_POWER_DCDC4P2); + val &= ~(BM_POWER_DCDC4P2_ENABLE_DCDC | BM_POWER_DCDC4P2_ENABLE_4P2); + __raw_writel(val, REGS_POWER_BASE + HW_POWER_DCDC4P2); + + __raw_writel(BM_POWER_5VCTRL_PWD_CHARGE_4P2, + REGS_POWER_BASE + HW_POWER_5VCTRL_SET); + + /* make VBUSVALID_TRSH 4400mV and set PWD_CHARGE_4P2 */ + __raw_writel(BM_POWER_5VCTRL_VBUSVALID_TRSH, + REGS_POWER_BASE + HW_POWER_5VCTRL_CLR); + + __raw_writel(BF_POWER_5VCTRL_VBUSVALID_TRSH(VBUSVALID_THRESH_4_40V), + REGS_POWER_BASE + HW_POWER_5VCTRL_SET); + +#else + /* 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. */ + __raw_writel(BF_POWER_VDDDCTRL_LINREG_OFFSET(LINREG_OFFSET_STEP_BELOW), + HW_POWER_BASE + HW_POWER_VDDDCTRL_SET); + /* Turn on the VDDD DCDC output and turn off the VDDD LinReg output. */ + __raw_writel(BM_POWER_VDDDCTRL_DISABLE_FET, + HW_POWER_BASE + HW_POWER_VDDDCTRL_CLR); + + __raw_writel(BM_POWER_VDDDCTRL_ENABLE_LINREG, + HW_POWER_BASE + HW_POWER_VDDDCTRL_CLR); + /* Make sure stepping is enabled when using DCDC. */ + __raw_writel(BM_POWER_VDDDCTRL_DISABLE_STEPPING, + HW_POWER_BASE + HW_POWER_VDDDCTRL_CLR); + + /* Power VDDA and VDDIO from the DCDC. */ + + /* Use LinReg offset for DCDC mode. */ + __raw_writel(BF_POWER_VDDACTRL_LINREG_OFFSET(LINREG_OFFSET_STEP_BELOW), + HW_POWER_BASE + HW_POWER_VDDACTRL_SET); + /* Turn on the VDDA DCDC converter output and turn off LinReg output. */ + __raw_writel(BM_POWER_VDDACTRL_DISABLE_FET, + HW_POWER_BASE + HW_POWER_VDDACTRL_CLR); + __raw_writel(BM_POWER_VDDACTRL_ENABLE_LINREG, + HW_POWER_BASE + HW_POWER_VDDACTRL_CLR); + + /* Make sure stepping is enabled when using DCDC. */ + __raw_writel(BM_POWER_VDDACTRL_DISABLE_STEPPING, + HW_POWER_BASE + HW_POWER_VDDACTRL_CLR); + + /* Use LinReg offset for DCDC mode. */ + __raw_writel(BF_POWER_VDDIOCTRL_LINREG_OFFSET( + LINREG_OFFSET_STEP_BELOW + ), + HW_POWER_BASE + HW_POWER_VDDIOCTRL_SET); + + /* Turn on the VDDIO DCDC output and turn on the LinReg output.*/ + __raw_writel(BM_POWER_VDDIOCTRL_DISABLE_FET, + HW_POWER_BASE + HW_POWER_VDDIOCTRL_CLR); + + __raw_writel(BM_POWER_5VCTRL_ILIMIT_EQ_ZERO, + HW_POWER_BASE + HW_POWER_5VCTRL_CLR_CLR); + + /* Make sure stepping is enabled when using DCDC. */ + __raw_writel(BM_POWER_VDDIOCTRL_DISABLE_STEPPING, + HW_POWER_BASE + HW_POWER_VDDIOCTRL_CLR); +#endif + +} + +/* + * 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 */ + __raw_writel(BM_POWER_CTRL_VBUSVALID_IRQ, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + __raw_writel(BM_POWER_CTRL_VDD5V_GT_VDDIO_IRQ, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + + /* detect 5v plug-in */ + __raw_writel(BM_POWER_CTRL_POLARITY_VBUSVALID, + REGS_POWER_BASE + HW_POWER_CTRL_SET); + __raw_writel(BM_POWER_CTRL_POLARITY_VDD5V_GT_VDDIO, + REGS_POWER_BASE + HW_POWER_CTRL_SET); + +#ifndef VDD4P2_ENABLED + /* Force current from 5V to be zero by disabling its entry source. */ + __raw_writel(BM_POWER_5VCTRL_ILIMIT_EQ_ZERO, + REGS_POWER_BASE + HW_POWER_5VCTRL_SET); +#endif + /* Allow DCDC be to active when 5V is present. */ + __raw_writel(BM_POWER_5VCTRL_ENABLE_DCDC, + REGS_POWER_BASE + HW_POWER_5VCTRL_SET); +} + +/* This function handles the transitions on each of theVDD5V_GT_VDDIO 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) +{ + +#ifdef VDD4P2_ENABLED + ddi_power_Enable4p2(450); +#else + /* Disable the DCDC during 5V connections. */ + __raw_writel(BM_POWER_5VCTRL_ENABLE_DCDC, + HW_POWER_BAE + HW_POWER_5VCTRL_CLR); + + /* 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 */ + __raw_writel(BF_POWER_VDDDCTRL_LINREG_OFFSET(LINREG_OFFSET_STEP_BELOW), + HW_POWER_BAE + HW_POWER_VDDDCTRL_SET); + + /* Turn on the VDDD LinReg and turn on the VDDD DCDC output. The */ + /* ENABLE_DCDC must be cleared to avoid LinReg and DCDC conflict. */ + __raw_writel(BM_POWER_VDDDCTRL_ENABLE_LINREG, + HW_POWER_BAE + HW_POWER_VDDDCTRL_SET); + __raw_writel(BM_POWER_VDDDCTRL_DISABLE_FET, + HW_POWER_BAE + HW_POWER_VDDDCTRL_CLR); + + /* Make sure stepping is disabled when using linear regulators */ + __raw_writel(BM_POWER_VDDDCTRL_DISABLE_STEPPING, + HW_POWER_BAE + HW_POWER_VDDDCTRL_SET); + + /* Use LinReg offset for LinReg mode */ + __raw_writel(BM_POWER_VDDACTRL_LINREG_OFFSET(LINREG_OFFSET_STEP_BELOW), + HW_POWER_BAE + HW_POWER_VDDACTRL_SET); + + + /* Turn on the VDDA LinReg output and prepare the DCDC for transfer. */ + /* ENABLE_DCDC must be clear to avoid DCDC and LinReg conflict. */ + stmp3xxx_set(BM_POWER_VDDACTRL_ENABLE_LINREG, + HW_POWER_BASE + HW_POWER_VDDACTRL_SET); + __raw_writel(BM_POWER_VDDACTRL_DISABLE_FET, + HW_POWER_BASE + HW_POWER_VDDACTRL_CLR); + + /* Make sure stepping is disabled when using linear regulators */ + __raw_writel(BM_POWER_VDDACTRL_DISABLE_STEPPING, + HW_POWER_BASE + HW_POWER_VDDACTRL_SET); + + /* Use LinReg offset for LinReg mode. */ + __raw_writel(BF_POWER_VDDIOCTRL_LINREG_OFFSET( + LINREG_OFFSET_STEP_BELOW), + HW_POWER_BASE + HW_POWER_VDDIOCTRL_SET); + + /* Turn on the VDDIO LinReg output and prepare the VDDIO DCDC output. */ + /* ENABLE_DCDC must be cleared to prevent DCDC and LinReg conflict. */ + __raw_writel(BM_POWER_VDDIOCTRL_DISABLE_FET, + HW_POWER_BASE + HW_POWER_VDDIOCTRL_CLR); + __raw_writel(BM_POWER_5VCTRL_ILIMIT_EQ_ZERO, + REGS_POWER_BASE + HW_POWER_5VCTRL_CLR); + + /* Make sure stepping is disabled when using DCDC. */ + __raw_writel(BM_POWER_VDDIOCTRL_DISABLE_STEPPING, + REGS_POWER_BASE + HW_POWER_VDDIOCTRL_SET); +#endif +} + + +void ddi_power_Start4p2Dcdc(bool battery_ready) +{ + uint32_t temp_reg, old_values; + bool vdda_pwdn = false, vddd_pwdn = false, vddio_pwdn = false; + +#ifndef CONFIG_ARCH_MX28 + /* set vbusvalid threshold to 2.9V because of errata */ + __raw_writel(BM_POWER_5VCTRL_VBUSVALID_TRSH, + REGS_POWER_BASE + HW_POWER_5VCTRL_CLR); +#endif + +#if 0 + if (battery_ready) + ddi_power_EnableBatteryIrq(); + else + enable_4p2_fiq_shutdown(); +#endif + + /* enable hardware shutdown on battery brownout */ + __raw_writel( + BM_POWER_BATTMONITOR_PWDN_BATTBRNOUT | + __raw_readl(REGS_POWER_BASE + HW_POWER_BATTMONITOR), + REGS_POWER_BASE + HW_POWER_BATTMONITOR); + + /* set VBUS DROOP threshold to 4.3V */ + __raw_writel(BM_POWER_5VCTRL_VBUSDROOP_TRSH, + REGS_POWER_BASE + HW_POWER_5VCTRL_CLR); + + /* turn of vbus valid detection. Part of errate + * workaround. */ + __raw_writel(BM_POWER_5VCTRL_PWRUP_VBUS_CMPS, + REGS_POWER_BASE + HW_POWER_5VCTRL_SET); + + __raw_writel(BM_POWER_5VCTRL_VBUSVALID_5VDETECT, + REGS_POWER_BASE + HW_POWER_5VCTRL_CLR); + + if (__raw_readl(REGS_POWER_BASE + HW_POWER_VDDIOCTRL) + & BM_POWER_VDDIOCTRL_PWDN_BRNOUT) + vddio_pwdn = true; + + if (__raw_readl(REGS_POWER_BASE + HW_POWER_VDDDCTRL) + & BM_POWER_VDDDCTRL_PWDN_BRNOUT) + vddd_pwdn = true; + + if (__raw_readl(REGS_POWER_BASE + HW_POWER_VDDACTRL) + & BM_POWER_VDDACTRL_PWDN_BRNOUT) + vdda_pwdn = true; + + __raw_writel(__raw_readl(REGS_POWER_BASE + HW_POWER_VDDACTRL) + & (~BM_POWER_VDDACTRL_PWDN_BRNOUT), + REGS_POWER_BASE + HW_POWER_VDDACTRL); + + __raw_writel(__raw_readl(REGS_POWER_BASE + HW_POWER_VDDDCTRL) + & (~BM_POWER_VDDDCTRL_PWDN_BRNOUT), + REGS_POWER_BASE + HW_POWER_VDDDCTRL); + + __raw_writel(__raw_readl(REGS_POWER_BASE + HW_POWER_VDDIOCTRL) + & (~BM_POWER_VDDIOCTRL_PWDN_BRNOUT), + REGS_POWER_BASE + HW_POWER_VDDIOCTRL); + + if ((__raw_readl(REGS_POWER_BASE + HW_POWER_STS) + & BM_POWER_STS_VDDIO_BO) == 0) + __raw_writel(BM_POWER_CTRL_VDDIO_BO_IRQ, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + + if ((__raw_readl(REGS_POWER_BASE + HW_POWER_STS) + & BM_POWER_STS_VDDD_BO) == 0) + __raw_writel(BM_POWER_CTRL_VDDD_BO_IRQ, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + + if ((__raw_readl(REGS_POWER_BASE + HW_POWER_STS) + & BM_POWER_STS_VDDA_BO) == 0) + __raw_writel(BM_POWER_CTRL_VDDA_BO_IRQ, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + + temp_reg = (BM_POWER_CTRL_ENIRQ_VDDD_BO | + BM_POWER_CTRL_ENIRQ_VDDA_BO | + BM_POWER_CTRL_ENIRQ_VDDIO_BO | + BM_POWER_CTRL_ENIRQ_VDD5V_DROOP | + BM_POWER_CTRL_ENIRQ_VBUS_VALID); + + /* save off old brownout enable values */ + old_values = __raw_readl(REGS_POWER_BASE + HW_POWER_CTRL) & + temp_reg; + + /* disable irqs affected by errata */ + __raw_writel(temp_reg, REGS_POWER_BASE + HW_POWER_CTRL_CLR); + + /* Enable DCDC from 4P2 */ + __raw_writel(__raw_readl(REGS_POWER_BASE + HW_POWER_DCDC4P2) | + BM_POWER_DCDC4P2_ENABLE_DCDC, + REGS_POWER_BASE + HW_POWER_DCDC4P2); + + /* give a delay to check for errate noise problem */ + mdelay(1); + + temp_reg = (BM_POWER_CTRL_VDDD_BO_IRQ | + BM_POWER_CTRL_VDDA_BO_IRQ | + BM_POWER_CTRL_VDDIO_BO_IRQ | + BM_POWER_CTRL_VDD5V_DROOP_IRQ | + BM_POWER_CTRL_VBUSVALID_IRQ); + + __raw_writel(temp_reg, REGS_POWER_BASE + HW_POWER_CTRL_CLR); + /* stay in this loop until the false brownout indciations + * no longer occur or until 5V actually goes away + */ + while ((__raw_readl(REGS_POWER_BASE + HW_POWER_CTRL) & temp_reg) && + !(__raw_readl(REGS_POWER_BASE + HW_POWER_CTRL) & + BM_POWER_CTRL_VDD5V_GT_VDDIO_IRQ)) { + __raw_writel(temp_reg, REGS_POWER_BASE + HW_POWER_CTRL_CLR); + + mdelay(1); + } + /* revert to previous enable irq values */ + __raw_writel(old_values, REGS_POWER_BASE + HW_POWER_CTRL_SET); + + if (vdda_pwdn) + __raw_writel(__raw_readl(REGS_POWER_BASE + HW_POWER_VDDACTRL) + | BM_POWER_VDDACTRL_PWDN_BRNOUT, + REGS_POWER_BASE + HW_POWER_VDDACTRL); + + if (vddd_pwdn) + __raw_writel(__raw_readl(REGS_POWER_BASE + HW_POWER_VDDDCTRL) + | BM_POWER_VDDDCTRL_PWDN_BRNOUT, + REGS_POWER_BASE + HW_POWER_VDDDCTRL); + + if (vddio_pwdn) + __raw_writel(__raw_readl(REGS_POWER_BASE + HW_POWER_VDDIOCTRL) + | BM_POWER_VDDIOCTRL_PWDN_BRNOUT, + REGS_POWER_BASE + HW_POWER_VDDIOCTRL); + + if (DetectionMethod == DDI_POWER_5V_VBUSVALID) + __raw_writel(BM_POWER_5VCTRL_VBUSVALID_5VDETECT, + REGS_POWER_BASE + HW_POWER_5VCTRL_SET); +} + + +/* set the optimal CMPTRIP for the best possible 5V + * disconnection handling but without drawing power + * from the power on a stable 4p2 rails (at 4.2V). + */ +void ddi_power_handle_cmptrip(void) +{ + enum ddi_power_5v_status pmu_5v_status; + uint32_t temp = __raw_readl(REGS_POWER_BASE + HW_POWER_DCDC4P2); + temp &= ~(BM_POWER_DCDC4P2_CMPTRIP); + + pmu_5v_status = ddi_power_GetPmu5vStatus(); + + /* CMPTRIP should remain at 31 when 5v is disconnected + * or 5v is connected but hasn't been handled yet + */ + if (pmu_5v_status != existing_5v_connection) + temp |= (31 << BP_POWER_DCDC4P2_CMPTRIP); + else if (ddi_power_GetBattery() > + BATTERY_VOLTAGE_CMPTRIP100_THRESHOLD_MV) + temp |= (1 << BP_POWER_DCDC4P2_CMPTRIP); + else if (ddi_power_GetBattery() > + BATTERY_VOLTAGE_CMPTRIP105_THRESHOLD_MV) + temp |= (24 << BP_POWER_DCDC4P2_CMPTRIP); + else + temp |= (31 << BP_POWER_DCDC4P2_CMPTRIP); + + + __raw_writel(temp, REGS_POWER_BASE + HW_POWER_DCDC4P2); +} + +void ddi_power_Init4p2Params(void) +{ + uint32_t temp; + + ddi_power_handle_cmptrip(); + + temp = __raw_readl(REGS_POWER_BASE + HW_POWER_DCDC4P2); + + /* DROPOUT CTRL to 10, TRG to 0 */ + temp &= ~(BM_POWER_DCDC4P2_TRG | BM_POWER_DCDC4P2_DROPOUT_CTRL); + temp |= (0xa << BP_POWER_DCDC4P2_DROPOUT_CTRL); + + __raw_writel(temp, REGS_POWER_BASE + HW_POWER_DCDC4P2); + + + temp = __raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL); + + /* HEADROOM_ADJ to 4, CHARGE_4P2_ILIMIT to 0 */ + temp &= ~(BM_POWER_5VCTRL_HEADROOM_ADJ | + BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT); + temp |= (4 << BP_POWER_5VCTRL_HEADROOM_ADJ); + +} + +bool ddi_power_IsBattRdyForXfer(void) +{ + uint16_t u16BatteryVoltage = ddi_power_GetBattery(); + + if (u16BatteryVoltage > DDI_POWER_BATTERY_XFER_THRESHOLD_MV) + return true; + else + return false; +} + +void ddi_power_EnableVbusDroopIrq(void) +{ + + __raw_writel(BM_POWER_CTRL_VDD5V_DROOP_IRQ, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + + __raw_writel(BM_POWER_CTRL_ENIRQ_VDD5V_DROOP, + REGS_POWER_BASE + HW_POWER_CTRL_SET); + +} + + +void ddi_power_Enable4p2(uint16_t target_current_limit_ma) +{ + + uint16_t u16BatteryVoltage; + uint32_t temp_reg; + + ddi_power_Init4p2Params(); + /* disable 4p2 rail brownouts for now. (they + * should have already been off at this point) */ + __raw_writel(BM_POWER_CTRL_ENIRQ_DCDC4P2_BO, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + + u16BatteryVoltage = ddi_power_GetBattery(); + + if (ddi_power_IsBattRdyForXfer()) { + + /* PWD_CHARGE_4P2 should already be set but just in case... */ + __raw_writel(BM_POWER_5VCTRL_PWD_CHARGE_4P2, + REGS_POWER_BASE + HW_POWER_5VCTRL_SET); + + /* set CMPTRIP to DCDC_4P2 pin >= BATTERY pin */ + temp_reg = __raw_readl(REGS_POWER_BASE + HW_POWER_DCDC4P2); + temp_reg &= ~(BM_POWER_DCDC4P2_CMPTRIP); + temp_reg |= (31 << BP_POWER_DCDC4P2_CMPTRIP); + __raw_writel(temp_reg, REGS_POWER_BASE + HW_POWER_DCDC4P2); + + /* since we have a good battery, we can go ahead + * and turn on the Dcdcing from the 4p2 source. + * This is helpful in working around the chip + * errata. + */ + ddi_power_Start4p2Dcdc(true); + + /* Enable VbusDroopIrq to handle errata */ + + /* set vbus droop detection level to 4.3V */ + __raw_writel(BM_POWER_5VCTRL_VBUSDROOP_TRSH, + REGS_POWER_BASE + HW_POWER_5VCTRL_CLR); + + ddi_power_EnableVbusDroopIrq(); + /* now that the DCDC4P2 problems are cleared, + * turn on and ramp up the 4p2 regulator + */ + temp_reg = ddi_power_BringUp4p2Regulator( + target_current_limit_ma, true); + + /* if we still have our 5V connection, we can disable + * battery brownout interrupt. This is because the + * VDD5V DROOP IRQ handler will also shutdown if battery + * is browned out and it will enable the battery brownout + * and bring VBUSVALID_TRSH level back to a normal level + * which caused the hardware battery brownout shutdown + * to be enabled. The benefit of this is that device + * that have detachable batteries (or devices going through + * the assembly line and running this firmware to test + * with) can avoid shutting down if 5V is present and + * battery voltage goes away. + */ + if (!(__raw_readl(REGS_POWER_BASE + HW_POWER_CTRL) & + (BM_POWER_CTRL_VBUSVALID_IRQ | + BM_POWER_CTRL_VDD5V_DROOP_IRQ))) { + ddi_power_EnableBatteryBoInterrupt(false); + } + + + + printk(KERN_DEBUG "4P2 rail started. 5V current limit\ + set to %dmA\n", temp_reg); + + } else { + + printk(KERN_ERR "4P2 rail was attempted to be started \ + from a system\ + with a very low battery voltage. This is not\ + yet handled by the kernel driver, only by the\ + bootlets. Remaining on battery power.\n"); + + if ((__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL) && + BM_POWER_5VCTRL_ENABLE_DCDC)) + ddi_power_EnableBatteryBoInterrupt(true); + +#if 0 + /* enable hardware shutdown (if 5v disconnected) + * on battery brownout */ + __raw_writel( + BM_POWER_BATTMONITOR_PWDN_BATTBRNOUT | + __raw_readl(REGS_POWER_BASE + HW_POWER_BATTMONITOR), + REGS_POWER_BASE + HW_POWER_BATTMONITOR); + + /* turn on and ramp up the 4p2 regulator */ + temp_reg = ddi_power_BringUp4p2Regulator( + target_current_limit_ma, false); + + Configure4p2FiqShutdown(); + + SetVbusValidThresh(0); +#endif + } + +} + +/* enable and ramp up 4p2 regulator */ +uint16_t ddi_power_BringUp4p2Regulator( + uint16_t target_current_limit_ma, + bool b4p2_dcdc_enabled) +{ + uint32_t temp_reg; + uint16_t charge_4p2_ilimit = 0; + + /* initial current limit to 0 */ + __raw_writel(BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT, + REGS_POWER_BASE + HW_POWER_5VCTRL_CLR); + + __raw_writel(__raw_readl(REGS_POWER_BASE + HW_POWER_DCDC4P2) | + BM_POWER_DCDC4P2_ENABLE_4P2, + REGS_POWER_BASE + HW_POWER_DCDC4P2); + + /* set 4p2 target voltage to zero */ + temp_reg = __raw_readl(REGS_POWER_BASE + HW_POWER_DCDC4P2); + temp_reg &= (~BM_POWER_DCDC4P2_TRG); + __raw_writel(temp_reg, REGS_POWER_BASE + HW_POWER_DCDC4P2); + + /* Enable 4P2 regulator*/ + __raw_writel(BM_POWER_5VCTRL_PWD_CHARGE_4P2, + REGS_POWER_BASE + HW_POWER_5VCTRL_CLR); + + if (target_current_limit_ma > 780) + target_current_limit_ma = 780; + + ddi_power_Set4p2BoLevel(4150); + + /* possibly not necessary but recommended for unloaded + * 4p2 rail + */ + __raw_writel(BM_POWER_CHARGE_ENABLE_LOAD, + REGS_POWER_BASE + HW_POWER_CHARGE_SET); + + while (charge_4p2_ilimit < target_current_limit_ma) { + + if (__raw_readl(REGS_POWER_BASE + HW_POWER_CTRL) & + (BM_POWER_CTRL_VBUSVALID_IRQ | + BM_POWER_CTRL_VDD5V_DROOP_IRQ)) + break; + + + charge_4p2_ilimit += 100; + if (charge_4p2_ilimit > target_current_limit_ma) + charge_4p2_ilimit = target_current_limit_ma; + + ddi_power_set_4p2_ilimit(charge_4p2_ilimit); + + /* dcdc4p2 enable_dcdc must be enabled for + * 4p2 bo indication to function. If not enabled, + * skip using bo level detection + */ + if (!(b4p2_dcdc_enabled)) + msleep(1); + else if (__raw_readl(REGS_POWER_BASE + HW_POWER_STS) & + BM_POWER_STS_DCDC_4P2_BO) + msleep(1); + else { + charge_4p2_ilimit = target_current_limit_ma; + ddi_power_set_4p2_ilimit(charge_4p2_ilimit); + } + } + + ddi_power_Set4p2BoLevel(3600); + + __raw_writel(BM_POWER_CTRL_DCDC4P2_BO_IRQ, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + + /* rail should now be up and loaded. Extra + * internal load is not necessary. + */ + __raw_writel(BM_POWER_CHARGE_ENABLE_LOAD, + REGS_POWER_BASE + HW_POWER_CHARGE_CLR); + + return charge_4p2_ilimit; + +} + + +void ddi_power_Set4p2BoLevel(uint16_t bo_voltage_mv) +{ + uint16_t bo_reg_value; + uint32_t temp; + + if (bo_voltage_mv < 3600) + bo_voltage_mv = 3600; + else if (bo_voltage_mv > 4375) + bo_voltage_mv = 4375; + + bo_reg_value = (bo_voltage_mv - 3600) / 25; + + temp = __raw_readl(REGS_POWER_BASE + HW_POWER_DCDC4P2); + temp &= (~BM_POWER_DCDC4P2_BO); + temp |= (bo_reg_value << BP_POWER_DCDC4P2_BO); + __raw_writel(temp, REGS_POWER_BASE + HW_POWER_DCDC4P2); +} + + + +void ddi_power_init_handoff(void) +{ + int val; + /* The following settings give optimal power supply capability */ + + /* 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); +} + + +void ddi_power_EnableBatteryInterrupt(bool enable) +{ + + __raw_writel(BM_POWER_CTRL_BATT_BO_IRQ, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + + __raw_writel(BM_POWER_CTRL_ENIRQBATT_BO, + REGS_POWER_BASE + HW_POWER_CTRL_SET); + +} + + +#define REGS_LRADC_BASE IO_ADDRESS(LRADC_PHYS_ADDR) + +int ddi_power_init_battery(void) +{ + + int ret = 0; + + if (!(__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL) && + BM_POWER_5VCTRL_ENABLE_DCDC)) { + printk(KERN_ERR "WARNING: Power Supply not\ + initialized correctly by \ + pre-kernel bootlets. HW_POWER_5VCTRL \ + ENABLE_DCDC should already be set. Kernel \ + power driver behavior may not be reliable \n"); + ret = 1; + } + if ((__raw_readl(REGS_POWER_BASE + HW_POWER_BATTMONITOR) & + BM_POWER_BATTMONITOR_BATT_VAL) == 0) { + ret = 1; + printk(KERN_INFO "WARNING : No battery connected !\r\n"); + return ret; + } + + /* the following code to enable automatic battery measurement + * should have already been enabled in the boot prep files. Not + * sure if this is necessary or possibly susceptible to + * mis-coordination + */ + + + ret = !hw_lradc_present(BATTERY_VOLTAGE_CH); + + if (ret) { + printk(KERN_ERR "%s: hw_lradc_present failed\n", __func__); + return -ENODEV; + } else { + uint16_t wait_time = 0; + + hw_lradc_configure_channel(BATTERY_VOLTAGE_CH, 0 /* div2 */ , + 0 /* acc */ , + 0 /* num_samples */); + + /* Setup the trigger loop forever */ + hw_lradc_set_delay_trigger(LRADC_DELAY_TRIGGER_BATTERY, + 1 << BATTERY_VOLTAGE_CH, + 1 << LRADC_DELAY_TRIGGER_BATTERY, + 0, 200); + + /* Clear the accumulator & NUM_SAMPLES */ + __raw_writel(0xFFFFFFFF, + REGS_LRADC_BASE + HW_LRADC_CHn_CLR(BATTERY_VOLTAGE_CH)); + + /* clear previous "measurement performed" status */ + __raw_writel(1 << BATTERY_VOLTAGE_CH, + REGS_LRADC_BASE + HW_LRADC_CTRL1_CLR); + + /* set to LiIon scale factor */ + __raw_writel(BM_LRADC_CONVERSION_SCALE_FACTOR, + REGS_LRADC_BASE + HW_LRADC_CONVERSION_SET); + + /* kick off the trigger */ + hw_lradc_set_delay_trigger_kick( + LRADC_DELAY_TRIGGER_BATTERY, 1); + + + /* wait for 1st converstion to be complete before + * enabling automatic copy to power supply + * peripheral + */ + while (!(__raw_readl(REGS_LRADC_BASE + HW_LRADC_CTRL1) & + 1 << BATTERY_VOLTAGE_CH) && + (wait_time < 10)) { + wait_time++; + mdelay(1); + } + + __raw_writel(BM_LRADC_CONVERSION_AUTOMATIC, + REGS_LRADC_BASE + HW_LRADC_CONVERSION_SET); +#ifdef CONFIG_ARCH_MX28 + /* workaround for mx28 lradc result incorrect in the + first several ms */ + for (wait_time = 0; wait_time < 20; wait_time++) + if (ddi_bc_hwGetBatteryVoltage() < 1000) { + pr_info("ddi_bc_hwGetBatteryVoltage=%u\n", + ddi_bc_hwGetBatteryVoltage()); + mdelay(100); + } else + break; +#endif + } + +#ifndef VDD4P2_ENABLED + /* prepare handoff */ + ddi_power_init_handoff(); +#endif + return ret; +} + +/* + * Use the the lradc channel + * get the die temperature from on-chip sensor. + */ +uint16_t MeasureInternalDieTemperature(void) +{ + uint32_t ch8Value, ch9Value, lradc_irq_mask, channel; + + channel = g_ddi_bc_Configuration.u8BatteryTempChannel; + lradc_irq_mask = 1 << channel; + + /* power up internal tep sensor block */ + __raw_writel(BM_LRADC_CTRL2_TEMPSENSE_PWD, + REGS_LRADC_BASE + HW_LRADC_CTRL2_CLR); + + /* mux to the lradc 8th temp channel */ + __raw_writel((0xF << (4 * channel)), + REGS_LRADC_BASE + HW_LRADC_CTRL4_CLR); + __raw_writel((8 << (4 * channel)), + REGS_LRADC_BASE + HW_LRADC_CTRL4_SET); + + /* Clear the interrupt flag */ + __raw_writel(lradc_irq_mask, + REGS_LRADC_BASE + HW_LRADC_CTRL1_CLR); + __raw_writel(BF_LRADC_CTRL0_SCHEDULE(1 << channel), + REGS_LRADC_BASE + HW_LRADC_CTRL0_SET); + + /* Wait for conversion complete*/ + while (!(__raw_readl(REGS_LRADC_BASE + HW_LRADC_CTRL1) + & lradc_irq_mask)) + cpu_relax(); + + /* Clear the interrupt flag again */ + __raw_writel(lradc_irq_mask, + REGS_LRADC_BASE + HW_LRADC_CTRL1_CLR); + + /* read temperature value and clr lradc */ + ch8Value = __raw_readl(REGS_LRADC_BASE + + HW_LRADC_CHn(channel)) & BM_LRADC_CHn_VALUE; + + + __raw_writel(BM_LRADC_CHn_VALUE, + REGS_LRADC_BASE + HW_LRADC_CHn_CLR(channel)); + + /* mux to the lradc 9th temp channel */ + __raw_writel((0xF << (4 * channel)), + REGS_LRADC_BASE + HW_LRADC_CTRL4_CLR); + __raw_writel((9 << (4 * channel)), + REGS_LRADC_BASE + HW_LRADC_CTRL4_SET); + + /* Clear the interrupt flag */ + __raw_writel(lradc_irq_mask, + REGS_LRADC_BASE + HW_LRADC_CTRL1_CLR); + __raw_writel(BF_LRADC_CTRL0_SCHEDULE(1 << channel), + REGS_LRADC_BASE + HW_LRADC_CTRL0_SET); + /* Wait for conversion complete */ + while (!(__raw_readl(REGS_LRADC_BASE + HW_LRADC_CTRL1) + & lradc_irq_mask)) + cpu_relax(); + + /* Clear the interrupt flag */ + __raw_writel(lradc_irq_mask, + REGS_LRADC_BASE + HW_LRADC_CTRL1_CLR); + /* read temperature value */ + ch9Value = __raw_readl( + REGS_LRADC_BASE + HW_LRADC_CHn(channel)) + & BM_LRADC_CHn_VALUE; + + + __raw_writel(BM_LRADC_CHn_VALUE, + REGS_LRADC_BASE + HW_LRADC_CHn_CLR(channel)); + + /* power down temp sensor block */ + __raw_writel(BM_LRADC_CTRL2_TEMPSENSE_PWD, + REGS_LRADC_BASE + HW_LRADC_CTRL2_SET); + + + return (uint16_t)((ch9Value-ch8Value)*GAIN_CORRECTION/4000); +} + + + +/* Name: ddi_power_GetBatteryMode */ +/* */ +/* brief */ + +ddi_power_BatteryMode_t ddi_power_GetBatteryMode(void) +{ + 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) { + __raw_writel(BM_POWER_CHARGE_PWD_BATTCHRG, + REGS_POWER_BASE + HW_POWER_CHARGE_CLR); + __raw_writel(BM_POWER_5VCTRL_PWD_CHARGE_4P2, + REGS_POWER_BASE + HW_POWER_5VCTRL_CLR); + } else { + __raw_writel(BM_POWER_CHARGE_PWD_BATTCHRG, + REGS_POWER_BASE + HW_POWER_CHARGE_SET); +#ifndef VDD4P2_ENABLED + __raw_writel(BM_POWER_5VCTRL_PWD_CHARGE_4P2, + REGS_POWER_BASE + HW_POWER_5VCTRL_SET); +#endif + } + +/* #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 */ + __raw_writel( + BF_POWER_BATTMONITOR_BRWNOUT_LVL(i16BrownoutLevel), + REGS_POWER_BASE + HW_POWER_BATTMONITOR_SET); + } else + ret = -EINVAL; + + return ret; +} +#endif + + +/* Currents */ + + + + +/* 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); + + /* Compute the toggle mask. */ + u16ToggleMask = u16OldSetting ^ u16NewSetting; + + /* Write to the toggle register.*/ + __raw_writel(u16ToggleMask << BP_POWER_CHARGE_BATTCHRG_I, + REGS_POWER_BASE + HW_POWER_CHARGE_TOG); + + /* 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. */ + __raw_writel(BF_POWER_CHARGE_STOP_ILIMIT(u16ToggleMask), + REGS_POWER_BASE + HW_POWER_CHARGE_TOG); + + /* 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 */ +#ifndef CONFIG_ARCH_MX28 + if (bGate) { + __raw_writel(BM_POWER_CTRL_CLKGATE, + REGS_POWER_BASE + HW_POWER_CTRL_SET); + } else { + __raw_writel(BM_POWER_CTRL_CLKGATE, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + } +#endif +} + + +/* See hw_power.h for details. */ + +bool ddi_power_GetPowerClkGate(void) +{ +#ifdef CONFIG_ARCH_MX28 + return 0; +#else + return (__raw_readl(REGS_POWER_BASE + HW_POWER_CTRL) & BM_POWER_CTRL_CLKGATE) ? 1 : 0; +#endif +} + + +enum ddi_power_5v_status ddi_power_GetPmu5vStatus(void) +{ + + if (DetectionMethod == DDI_POWER_5V_VDD5V_GT_VDDIO) { + + if (__raw_readl(REGS_POWER_BASE + HW_POWER_CTRL) & + BM_POWER_CTRL_POLARITY_VDD5V_GT_VDDIO) { + if ((__raw_readl(REGS_POWER_BASE + HW_POWER_CTRL) & + BM_POWER_CTRL_VDD5V_GT_VDDIO_IRQ) || + ddi_power_Get5vPresentFlag()) + return new_5v_connection; + else + return existing_5v_disconnection; + } else { + if ((__raw_readl(REGS_POWER_BASE + HW_POWER_CTRL) & + BM_POWER_CTRL_VDD5V_GT_VDDIO_IRQ) || + !ddi_power_Get5vPresentFlag() || + ddi_power_Get5vDroopFlag()) + return new_5v_disconnection; + else + return existing_5v_connection; + } + } else { + + if (__raw_readl(REGS_POWER_BASE + HW_POWER_CTRL) & + BM_POWER_CTRL_POLARITY_VBUSVALID) { + if ((__raw_readl(REGS_POWER_BASE + HW_POWER_CTRL) & + BM_POWER_CTRL_VBUSVALID_IRQ) || + ddi_power_Get5vPresentFlag()) + return new_5v_connection; + else + return existing_5v_disconnection; + } else { + if ((__raw_readl(REGS_POWER_BASE + HW_POWER_CTRL) & + BM_POWER_CTRL_VBUSVALID_IRQ) || + !ddi_power_Get5vPresentFlag() || + ddi_power_Get5vDroopFlag()) + return new_5v_disconnection; + else + return existing_5v_connection; + } + + } +} + +void ddi_power_disable_5v_connection_irq(void) +{ + + __raw_writel((BM_POWER_CTRL_ENIRQ_VBUS_VALID | + BM_POWER_CTRL_ENIRQ_VDD5V_GT_VDDIO), + REGS_POWER_BASE + HW_POWER_CTRL_CLR); +} + +void ddi_power_enable_5v_disconnect_detection(void) +{ + __raw_writel(BM_POWER_CTRL_POLARITY_VDD5V_GT_VDDIO | + BM_POWER_CTRL_POLARITY_VBUSVALID, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + + __raw_writel(BM_POWER_CTRL_VDD5V_GT_VDDIO_IRQ | + BM_POWER_CTRL_VBUSVALID_IRQ, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + + if (DetectionMethod == DDI_POWER_5V_VDD5V_GT_VDDIO) { + __raw_writel(BM_POWER_CTRL_ENIRQ_VDD5V_GT_VDDIO, + REGS_POWER_BASE + HW_POWER_CTRL_SET); + } else { + __raw_writel(BM_POWER_CTRL_ENIRQ_VBUS_VALID, + REGS_POWER_BASE + HW_POWER_CTRL_SET); + } +} + +void ddi_power_enable_5v_connect_detection(void) +{ + __raw_writel(BM_POWER_CTRL_POLARITY_VDD5V_GT_VDDIO | + BM_POWER_CTRL_POLARITY_VBUSVALID, + REGS_POWER_BASE + HW_POWER_CTRL_SET); + + __raw_writel(BM_POWER_CTRL_VDD5V_GT_VDDIO_IRQ | + BM_POWER_CTRL_VBUSVALID_IRQ, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + + if (DetectionMethod == DDI_POWER_5V_VDD5V_GT_VDDIO) { + __raw_writel(BM_POWER_CTRL_ENIRQ_VDD5V_GT_VDDIO, + REGS_POWER_BASE + HW_POWER_CTRL_SET); + } else { + __raw_writel(BM_POWER_CTRL_ENIRQ_VBUS_VALID, + REGS_POWER_BASE + HW_POWER_CTRL_SET); + } +} + +void ddi_power_EnableBatteryBoInterrupt(bool bEnable) +{ + if (bEnable) { + + __raw_writel(BM_POWER_CTRL_BATT_BO_IRQ, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + __raw_writel(BM_POWER_CTRL_ENIRQBATT_BO, + REGS_POWER_BASE + HW_POWER_CTRL_SET); + /* todo: make sure the battery brownout comparator + * is enabled in HW_POWER_BATTMONITOR + */ + } else { + __raw_writel(BM_POWER_CTRL_ENIRQBATT_BO, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + } +} + +void ddi_power_EnableDcdc4p2BoInterrupt(bool bEnable) +{ + if (bEnable) { + + __raw_writel(BM_POWER_CTRL_DCDC4P2_BO_IRQ, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + __raw_writel(BM_POWER_CTRL_ENIRQ_DCDC4P2_BO, + REGS_POWER_BASE + HW_POWER_CTRL_SET); + } else { + __raw_writel(BM_POWER_CTRL_ENIRQ_DCDC4P2_BO, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + } +} + +void ddi_power_EnableVdd5vDroopInterrupt(bool bEnable) +{ + if (bEnable) { + + __raw_writel(BM_POWER_CTRL_VDD5V_DROOP_IRQ, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + __raw_writel(BM_POWER_CTRL_ENIRQ_VDD5V_DROOP, + REGS_POWER_BASE + HW_POWER_CTRL_SET); + } else { + __raw_writel(BM_POWER_CTRL_ENIRQ_VDD5V_DROOP, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + } +} + + +void ddi_power_Enable5vDisconnectShutdown(bool bEnable) +{ + if (bEnable) { + __raw_writel(BM_POWER_5VCTRL_PWDN_5VBRNOUT, + REGS_POWER_BASE + HW_POWER_5VCTRL_SET); + } else { + __raw_writel(BM_POWER_5VCTRL_PWDN_5VBRNOUT, + REGS_POWER_BASE + HW_POWER_5VCTRL_CLR); + } +} + + +void ddi_power_enable_5v_to_battery_xfer(bool bEnable) +{ + if (bEnable) { + /* order matters */ + + /* we can enable this in in vbus droop or 4p2 fiq handler + * ddi_power_EnableBatteryBoInterrupt(true); + */ + ddi_power_Enable5vDisconnectShutdown(false); + } else { + /* order matters */ + ddi_power_Enable5vDisconnectShutdown(true); + ddi_power_EnableBatteryBoInterrupt(false); + } +} + + +void ddi_power_init_4p2_protection(void) +{ + /* set vbus droop detection level to 4.3V */ + __raw_writel(BM_POWER_5VCTRL_VBUSDROOP_TRSH, + REGS_POWER_BASE + HW_POWER_5VCTRL_CLR); + + /* VBUSDROOP THRESHOLD to 4.3V */ + __raw_writel(BM_POWER_5VCTRL_VBUSDROOP_TRSH, + REGS_POWER_BASE + HW_POWER_5VCTRL_CLR); + + ddi_power_EnableVbusDroopIrq(); + +#ifndef CONFIG_ARCH_MX28 + /* VBUSVALID THRESH = 2.9V */ + __raw_writel(BM_POWER_5VCTRL_VBUSVALID_TRSH, + REGS_POWER_BASE + HW_POWER_5VCTRL_CLR); +#endif + +} + +/* determine if all the bits are in a 'DCDC 4P2 Enabled' state. */ +bool ddi_power_check_4p2_bits(void) +{ + + + uint32_t temp; + + temp = __raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL) & + BM_POWER_5VCTRL_PWD_CHARGE_4P2; + + /* if PWD_CHARGE_4P2 = 1, 4p2 is disabled */ + if (temp) + return false; + + temp = __raw_readl(REGS_POWER_BASE + HW_POWER_DCDC4P2) & + BM_POWER_DCDC4P2_ENABLE_DCDC; + + if (!temp) + return false; + + temp = __raw_readl(REGS_POWER_BASE + HW_POWER_DCDC4P2) & + BM_POWER_DCDC4P2_ENABLE_4P2; + + if (temp) + return true; + else + return false; + +} + +uint16_t ddi_power_set_4p2_ilimit(uint16_t ilimit) +{ + uint32_t temp_reg; + + if (ilimit > 780) + ilimit = 780; + temp_reg = __raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL); + temp_reg &= (~BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT); + temp_reg |= BF_POWER_5VCTRL_CHARGE_4P2_ILIMIT( + ddi_power_convert_current_to_setting( + ilimit)); + __raw_writel(temp_reg, REGS_POWER_BASE + HW_POWER_5VCTRL); + + return ilimit; +} + +void ddi_power_shutdown(void) +{ + __raw_writel(0x3e770001, REGS_POWER_BASE + HW_POWER_RESET); +} + +void ddi_power_handle_dcdc4p2_bo(void) +{ + ddi_power_EnableBatteryBoInterrupt(true); + ddi_power_EnableDcdc4p2BoInterrupt(false); +} + +void ddi_power_enable_vddio_interrupt(bool enable) +{ + if (enable) { + __raw_writel(BM_POWER_CTRL_VDDIO_BO_IRQ, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); +#ifndef DISABLE_VDDIO_BO_PROTECTION + __raw_writel(BM_POWER_CTRL_ENIRQ_VDDIO_BO, + REGS_POWER_BASE + HW_POWER_CTRL_SET); +#endif + } else { + __raw_writel(BM_POWER_CTRL_ENIRQ_VDDIO_BO, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + } + +} + + +void ddi_power_handle_vddio_brnout(void) +{ + if (ddi_power_GetPmu5vStatus() == new_5v_connection || + (ddi_power_GetPmu5vStatus() == new_5v_disconnection)) { + ddi_power_enable_vddio_interrupt(false); + } else { +#ifdef DEBUG_IRQS + ddi_power_enable_vddio_interrupt(false); + printk(KERN_ALERT "VDDIO BO TRIED TO SHUTDOWN!!!\n"); + return; +#else + ddi_power_shutdown(); +#endif + } +} + +void ddi_power_handle_vdd5v_droop(void) +{ + uint32_t temp; + + /* handle errata */ + temp = __raw_readl(REGS_POWER_BASE + HW_POWER_DCDC4P2); + temp |= (BF_POWER_DCDC4P2_CMPTRIP(31) | BM_POWER_DCDC4P2_TRG); + __raw_writel(temp, REGS_POWER_BASE + HW_POWER_DCDC4P2); + + + /* if battery is below brownout level, shutdown asap */ + if (__raw_readl(REGS_POWER_BASE + HW_POWER_STS) & BM_POWER_STS_BATT_BO) + ddi_power_shutdown(); + + /* due to 5v connect vddio bo chip bug, we need to + * disable vddio interrupts until we reset the 5v + * detection for 5v connect detect. We want to allow + * some debounce time before enabling connect detection. + */ + ddi_power_enable_vddio_interrupt(false); + + ddi_power_EnableBatteryBoInterrupt(true); + ddi_power_EnableDcdc4p2BoInterrupt(false); + ddi_power_EnableVdd5vDroopInterrupt(false); + +} + +void ddi_power_InitOutputBrownouts(void) +{ + uint32_t temp; + + __raw_writel(BM_POWER_CTRL_VDDD_BO_IRQ | + BM_POWER_CTRL_VDDA_BO_IRQ | + BM_POWER_CTRL_VDDIO_BO_IRQ, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + + __raw_writel(BM_POWER_CTRL_ENIRQ_VDDD_BO | + BM_POWER_CTRL_ENIRQ_VDDA_BO | + BM_POWER_CTRL_ENIRQ_VDDIO_BO, + REGS_POWER_BASE + HW_POWER_CTRL_SET); + + temp = __raw_readl(REGS_POWER_BASE + HW_POWER_VDDDCTRL); + temp &= ~BM_POWER_VDDDCTRL_PWDN_BRNOUT; + __raw_writel(temp, REGS_POWER_BASE + HW_POWER_VDDDCTRL); + + temp = __raw_readl(REGS_POWER_BASE + HW_POWER_VDDACTRL); + temp &= ~BM_POWER_VDDACTRL_PWDN_BRNOUT; + __raw_writel(temp, REGS_POWER_BASE + HW_POWER_VDDACTRL); + + temp = __raw_readl(REGS_POWER_BASE + HW_POWER_VDDIOCTRL); + temp &= ~BM_POWER_VDDIOCTRL_PWDN_BRNOUT; + __raw_writel(temp, REGS_POWER_BASE + HW_POWER_VDDIOCTRL); +} + +/* used for debugging purposes only */ +void ddi_power_disable_power_interrupts(void) +{ + __raw_writel(BM_POWER_CTRL_ENIRQ_DCDC4P2_BO | + BM_POWER_CTRL_ENIRQ_VDD5V_DROOP | + BM_POWER_CTRL_ENIRQ_PSWITCH | + BM_POWER_CTRL_ENIRQ_DC_OK | + BM_POWER_CTRL_ENIRQBATT_BO | + BM_POWER_CTRL_ENIRQ_VDDIO_BO | + BM_POWER_CTRL_ENIRQ_VDDA_BO | + BM_POWER_CTRL_ENIRQ_VDDD_BO | + BM_POWER_CTRL_ENIRQ_VBUS_VALID | + BM_POWER_CTRL_ENIRQ_VDD5V_GT_VDDIO, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + +} + +bool ddi_power_Get5vDroopFlag(void) +{ + if (__raw_readl(REGS_POWER_BASE + HW_POWER_STS) & + BM_POWER_STS_VDD5V_DROOP) + return true; + else + return false; +} + + +/* End of file */ + +/* @} */ |