/* * Copyright (c) 2015, Freescale Semiconductor, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, this list * of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * o Neither the name of Freescale Semiconductor, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "fsl_dcdc.h" /******************************************************************************* * Prototypes ******************************************************************************/ /*! * @brief Get instance number for DCDC module. * * @param base DCDC peripheral base address */ static uint32_t DCDC_GetInstance(DCDC_Type *base); /******************************************************************************* * Variables ******************************************************************************/ /*! @brief Pointers to DCDC bases for each instance. */ const DCDC_Type *s_dcdcBases[] = DCDC_BASE_PTRS; /*! @brief Pointers to DCDC clocks for each instance. */ static const clock_ip_name_t s_dcdcClocks[] = DCDC_CLOCKS; /******************************************************************************* * Code ******************************************************************************/ static uint32_t DCDC_GetInstance(DCDC_Type *base) { uint32_t instance; /* Find the instance index from base address mappings. */ for (instance = 0; instance < FSL_FEATURE_SOC_DCDC_COUNT; instance++) { if (s_dcdcBases[instance] == base) { break; } } assert(instance < FSL_FEATURE_SOC_DCDC_COUNT); return instance; } void DCDC_Init(DCDC_Type *base) { /* Enable the clock. */ CLOCK_EnableClock(s_dcdcClocks[DCDC_GetInstance(base)]); } void DCDC_Deinit(DCDC_Type *base) { /* Disable the clock. */ CLOCK_DisableClock(s_dcdcClocks[DCDC_GetInstance(base)]); } uint32_t DCDC_GetStatusFlags(DCDC_Type *base) { uint32_t tmp32 = 0U; /* kDCDC_LockedOKStatus. */ if (0U != (DCDC_REG0_DCDC_STS_DC_OK_MASK & base->REG0)) { tmp32 |= kDCDC_LockedOKStatus; } /* kDCDC_PSwitchStatus. */ if (0U != (DCDC_REG0_PSWITCH_STATUS_MASK & base->REG0)) { tmp32 |= kDCDC_PSwitchStatus; } /* kDCDC_PSwitchInterruptStatus. */ if (0U != (DCDC_REG6_PSWITCH_INT_STS_MASK & base->REG6)) { tmp32 |= kDCDC_PSwitchInterruptStatus; } return tmp32; } void DCDC_ClearStatusFlags(DCDC_Type *base, uint32_t mask) /* Clear flags indicated by mask. */ { if (0U != (kDCDC_PSwitchInterruptStatus & mask)) { /* Write 1 to clear interrupt. Set to 0 after clear. */ base->REG6 |= DCDC_REG6_PSWITCH_INT_CLEAR_MASK; base->REG6 &= ~DCDC_REG6_PSWITCH_INT_CLEAR_MASK; } } void DCDC_SetPSwitchInterruptConfig(DCDC_Type *base, uint32_t mask) { assert(0U == (mask & ~(DCDC_REG6_PSWITCH_INT_RISE_EN_MASK | DCDC_REG6_PSWITCH_INT_FALL_EN_MASK))); uint32_t tmp32 = base->REG6 & ~(DCDC_REG6_PSWITCH_INT_RISE_EN_MASK | DCDC_REG6_PSWITCH_INT_FALL_EN_MASK); tmp32 |= mask; base->REG6 = tmp32; } void DCDC_GetDefaultLowPowerConfig(dcdc_low_power_config_t *config) { assert(NULL != config); config->workModeInVLPRW = kDCDC_WorkInPulsedMode; config->workModeInVLPS = kDCDC_WorkInPulsedMode; config->enableHysteresisVoltageSense = true; config->enableAdjustHystereticValueSense = false; config->enableHystersisComparator = true; config->enableAdjustHystereticValueComparator = false; config->hystereticUpperThresholdValue = kDCDC_HystereticThresholdOffset75mV; config->hystereticLowerThresholdValue = kDCDC_HystereticThresholdOffset0mV; config->enableDiffComparators = false; } void DCDC_SetLowPowerConfig(DCDC_Type *base, const dcdc_low_power_config_t *config) { uint32_t tmp32; tmp32 = base->REG0 & ~(DCDC_REG0_VLPR_VLPW_CONFIG_DCDC_HP_MASK | DCDC_REG0_VLPS_CONFIG_DCDC_HP_MASK | DCDC_REG0_OFFSET_RSNS_LP_DISABLE_MASK | DCDC_REG0_OFFSET_RSNS_LP_ADJ_MASK | DCDC_REG0_HYST_LP_CMP_DISABLE_MASK | DCDC_REG0_HYST_LP_COMP_ADJ_MASK | DCDC_REG0_DCDC_LP_STATE_HYS_H_MASK | DCDC_REG0_DCDC_LP_STATE_HYS_L_MASK | DCDC_REG0_DCDC_LP_DF_CMP_ENABLE_MASK); if (kDCDC_WorkInContinuousMode == config->workModeInVLPRW) { tmp32 |= DCDC_REG0_VLPR_VLPW_CONFIG_DCDC_HP_MASK; } if (kDCDC_WorkInContinuousMode == config->workModeInVLPS) { tmp32 |= DCDC_REG0_VLPS_CONFIG_DCDC_HP_MASK; } if (!config->enableHysteresisVoltageSense) { tmp32 |= DCDC_REG0_OFFSET_RSNS_LP_DISABLE_MASK; } if (config->enableAdjustHystereticValueSense) { tmp32 |= DCDC_REG0_OFFSET_RSNS_LP_ADJ_MASK; } if (!config->enableHystersisComparator) { tmp32 |= DCDC_REG0_HYST_LP_CMP_DISABLE_MASK; } if (config->enableAdjustHystereticValueComparator) { tmp32 |= DCDC_REG0_HYST_LP_COMP_ADJ_MASK; } tmp32 |= DCDC_REG0_DCDC_LP_STATE_HYS_H(config->hystereticUpperThresholdValue) | DCDC_REG0_DCDC_LP_STATE_HYS_L(config->hystereticLowerThresholdValue); /* true - DCDC compare the lower supply(relative to target value) with DCDC_LP_STATE_HYS_L. When it is lower than * DCDC_LP_STATE_HYS_L, re-charge output. * false - DCDC compare the common mode sense of supply(relative to target value) with DCDC_LP_STATE_HYS_L. When it * is lower than DCDC_LP_STATE_HYS_L, re-charge output. */ if (config->enableDiffComparators) { tmp32 |= DCDC_REG0_DCDC_LP_DF_CMP_ENABLE_MASK; } base->REG0 = tmp32; } void DCDC_GetDefaultLoopControlConfig(dcdc_loop_control_config_t *config) { assert(NULL != config); config->enableDiffHysteresis = false; config->enableCommonHysteresis = false; config->enableDiffHysteresisThresh = false; config->enableCommonHysteresisThresh = false; config->enableInvertHysteresisSign = false; } void DCDC_SetLoopControlConfig(DCDC_Type *base, const dcdc_loop_control_config_t *config) { uint32_t tmp32; /* DCDC_REG1. */ tmp32 = base->REG1 & ~(DCDC_REG1_DCDC_LOOPCTRL_EN_DF_HYST_MASK | DCDC_REG1_DCDC_LOOPCTRL_EN_CM_HYST_MASK | DCDC_REG1_DCDC_LOOPCTRL_DF_HST_THRESH_MASK | DCDC_REG1_DCDC_LOOPCTRL_CM_HST_THRESH_MASK); if (config->enableDiffHysteresis) { tmp32 |= DCDC_REG1_DCDC_LOOPCTRL_EN_DF_HYST_MASK; } if (config->enableCommonHysteresis) { tmp32 |= DCDC_REG1_DCDC_LOOPCTRL_EN_CM_HYST_MASK; } if (config->enableDiffHysteresisThresh) { tmp32 |= DCDC_REG1_DCDC_LOOPCTRL_DF_HST_THRESH_MASK; } if (config->enableCommonHysteresisThresh) { tmp32 |= DCDC_REG1_DCDC_LOOPCTRL_CM_HST_THRESH_MASK; } base->REG1 = tmp32; /* DCDC_REG2. */ if (config->enableInvertHysteresisSign) { base->REG2 |= DCDC_REG2_DCDC_LOOPCTRL_HYST_SIGN_MASK; } else { base->REG2 &= ~DCDC_REG2_DCDC_LOOPCTRL_HYST_SIGN_MASK; } } void DCDC_SetClockSource(DCDC_Type *base, dcdc_clock_source_t clockSource) { uint32_t tmp32; tmp32 = base->REG0 & ~(DCDC_REG0_DCDC_PWD_OSC_INT_MASK | DCDC_REG0_DCDC_SEL_CLK_MASK | DCDC_REG0_DCDC_DISABLE_AUTO_CLK_SWITCH_MASK); switch (clockSource) { case kDCDC_ClockInternalOsc: tmp32 |= DCDC_REG0_DCDC_DISABLE_AUTO_CLK_SWITCH_MASK; break; case kDCDC_ClockExternalOsc: /* Choose the external clock and disable the internal clock. */ tmp32 |= DCDC_REG0_DCDC_DISABLE_AUTO_CLK_SWITCH_MASK | DCDC_REG0_DCDC_SEL_CLK_MASK | DCDC_REG0_DCDC_PWD_OSC_INT_MASK; break; default: break; } base->REG0 = tmp32; } void DCDC_AdjustTargetVoltage(DCDC_Type *base, uint32_t vdd1p45Boost, uint32_t vdd1p45Buck, uint32_t vdd1p8) { uint32_t tmp32; /* Unlock the limitation of setting target voltage. */ base->REG3 &= ~(DCDC_REG3_DCDC_VDD1P8CTRL_DISABLE_STEP_MASK | DCDC_REG3_DCDC_VDD1P5CTRL_DISABLE_STEP_MASK); /* Change the target voltage value. */ tmp32 = base->REG3 & ~(DCDC_REG3_DCDC_VDD1P5CTRL_TRG_BOOST_MASK | DCDC_REG3_DCDC_VDD1P5CTRL_TRG_BUCK_MASK | DCDC_REG3_DCDC_VDD1P8CTRL_TRG_MASK); tmp32 |= DCDC_REG3_DCDC_VDD1P5CTRL_TRG_BOOST(vdd1p45Boost) | DCDC_REG3_DCDC_VDD1P5CTRL_TRG_BUCK(vdd1p45Buck) | DCDC_REG3_DCDC_VDD1P8CTRL_TRG(vdd1p8); base->REG3 = tmp32; /* DCDC_STS_DC_OK bit will be de-asserted after target register changes. After output voltage settling to new * target value, DCDC_STS_DC_OK will be asserted. */ while (0U != (DCDC_REG0_DCDC_STS_DC_OK_MASK & base->REG0)) { } } void DCDC_SetBatteryMonitorValue(DCDC_Type *base, uint32_t battValue) { uint32_t tmp32; /* Disable the monitor before setting the new value */ base->REG2 &= ~DCDC_REG2_DCDC_BATTMONITOR_EN_BATADJ_MASK; if (0U != battValue) { tmp32 = base->REG2 & ~DCDC_REG2_DCDC_BATTMONITOR_BATT_VAL_MASK; /* Enable the monitor with setting value. */ tmp32 |= (DCDC_REG2_DCDC_BATTMONITOR_EN_BATADJ_MASK | DCDC_REG2_DCDC_BATTMONITOR_BATT_VAL(battValue)); base->REG2 = tmp32; } } void DCDC_SetMinPowerConfig(DCDC_Type *base, const dcdc_min_power_config_t *config) { uint32_t tmp32 = base->REG3 & ~(DCDC_REG3_DCDC_MINPWR_HALF_FETS_MASK | DCDC_REG3_DCDC_MINPWR_DOUBLE_FETS_MASK | DCDC_REG3_DCDC_MINPWR_DC_HALFCLK_MASK | DCDC_REG3_DCDC_MINPWR_HALF_FETS_PULSED_MASK | DCDC_REG3_DCDC_MINPWR_DOUBLE_FETS_PULSED_MASK | DCDC_REG3_DCDC_MINPWR_DC_HALFCLK_PULSED_MASK); /* For Continuous mode. */ if (config->enableUseHalfFetForContinuous) { tmp32 |= DCDC_REG3_DCDC_MINPWR_HALF_FETS_MASK; } if (config->enableUseDoubleFetForContinuous) { tmp32 |= DCDC_REG3_DCDC_MINPWR_DOUBLE_FETS_MASK; } if (config->enableUseHalfFreqForContinuous) { tmp32 |= DCDC_REG3_DCDC_MINPWR_DC_HALFCLK_MASK; } /* For Pulsed mode. */ if (config->enableUseHalfFetForPulsed) { tmp32 |= DCDC_REG3_DCDC_MINPWR_HALF_FETS_PULSED_MASK; } if (config->enableUseDoubleFetForPulsed) { tmp32 |= DCDC_REG3_DCDC_MINPWR_DOUBLE_FETS_PULSED_MASK; } if (config->enableUseHalfFreqForPulsed) { tmp32 |= DCDC_REG3_DCDC_MINPWR_DC_HALFCLK_PULSED_MASK; } base->REG3 = tmp32; } void DCDC_GetDefaultMinPowerDefault(dcdc_min_power_config_t *config) { assert(NULL != config); /* For Continuous mode. */ config->enableUseHalfFetForContinuous = false; config->enableUseDoubleFetForContinuous = false; config->enableUseHalfFreqForContinuous = false; /* For Pulsed mode. */ config->enableUseHalfFetForPulsed = false; config->enableUseDoubleFetForPulsed = false; config->enableUseHalfFreqForPulsed = false; } void DCDC_SetPulsedIntegratorConfig(DCDC_Type *base, const dcdc_pulsed_integrator_config_t *config) { if (config->enableUseUserIntegratorValue) /* Enable to use the user integrator value. */ { base->REG7 = (base->REG7 & ~DCDC_REG7_INTEGRATOR_VALUE_MASK) | DCDC_REG7_INTEGRATOR_VALUE_SEL_MASK | DCDC_REG7_INTEGRATOR_VALUE(config->userIntegratorValue); if (config->enablePulseRunSpeedup) { base->REG7 |= DCDC_REG7_PULSE_RUN_SPEEDUP_MASK; } } else { base->REG7 = 0U; } } void DCDC_GetDefaultPulsedIntegratorConfig(dcdc_pulsed_integrator_config_t *config) { assert(NULL != config); config->enableUseUserIntegratorValue = false; config->userIntegratorValue = 0U; config->enablePulseRunSpeedup = false; }