Files
mongoose/tutorials/nxp/frdm-rw612-xpresso-freertos-lwip/drivers/fsl_power.c
T

1464 lines
47 KiB
C

/*
* Copyright 2020-2023 NXP
*
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "fsl_power.h"
#include <string.h>
/*******************************************************************************
* Definitions
******************************************************************************/
/* Component ID definition, used by tools. */
#ifndef FSL_COMPONENT_ID
#define FSL_COMPONENT_ID "platform.drivers.power"
#endif
#define IS_XIP_FLEXSPI() \
((((uint32_t)POWER_EnableWakeup >= 0x08000000U) && ((uint32_t)POWER_EnableWakeup < 0x10000000U)) || \
(((uint32_t)POWER_EnableWakeup >= 0x18000000U) && ((uint32_t)POWER_EnableWakeup < 0x20000000U)))
#define FLEXSPI_DLL_LOCK_RETRY (10U)
/* Wait some PMU cycles */
#define POWER_WAIT_PMU() \
do \
{ \
volatile uint32_t dummy; \
dummy = PMU->PWR_MODE_STATUS; \
dummy = PMU->PWR_MODE_STATUS; \
dummy = PMU->PWR_MODE_STATUS; \
dummy = PMU->PWR_MODE_STATUS; \
dummy = PMU->PWR_MODE_STATUS; \
(void)dummy; \
} while (false)
#define POWER_WLAN_POWER_STATUS() (SOCCTRL->WLAN_POWER_STATUS & 0x3U)
#define POWER_BLE_POWER_STATUS() (SOCCTRL->BLE_POWER_STATUS & 0x3U)
#define POWER_WLAN_BLE_POWER_ON (0U)
#define POWER_WLAN_BLE_POWER_SLP (2U)
#define POWER_WLAN_BLE_POWER_OFF (3U)
#define ITRC_OUT_SEL_MASK (0x0C000FF0U)
#define ITRC_OUT_SEL_DISABLE (0x08000AA0U)
#define ITRC_OUT_SEL_EVENT_MASK (0xFU)
#define ITRC_OUT_SEL_EVENT_DISABLE (0xAU)
#define POWER_WRITE_MEM32(addr, val) \
do \
{ \
*((volatile uint32_t *)(addr)) = (val); \
} while (false)
typedef struct _power_nvic_context
{
uint32_t PriorityGroup;
uint32_t ISER[5];
uint8_t IPR[160];
uint8_t SHPR[12];
uint32_t ICSR;
uint32_t VTOR;
uint32_t AIRCR;
uint32_t SCR;
uint32_t CCR;
uint32_t SHCSR;
uint32_t MMFAR;
uint32_t BFAR;
uint32_t CPACR;
uint32_t NSACR;
} power_nvic_context_t;
typedef struct _power_systick_context
{
uint32_t CTRL;
uint32_t LOAD;
} power_systick_context_t;
typedef struct _power_clock_context
{
uint32_t SOURCE_CLK_GATE;
} power_clock_context_t;
typedef struct _power_gdet_sensor_context
{
int32_t disableCount;
uint32_t VSEN_CTRL_1_REG_1;
uint32_t VSEN_CTRL_2_REG_1;
uint32_t VSEN_CTRL_3_REG_1;
uint32_t ITRC_OUT0_SEL0;
uint32_t ITRC_OUT1_SEL0;
uint32_t ITRC_OUT0_SEL0_EVENT16_31;
uint32_t ITRC_OUT1_SEL0_EVENT16_31;
uint32_t ELS_INT_ENABLE;
uint32_t ELS_EN;
} power_gdet_sensor_context_t;
typedef struct _power_threshold_params
{
uint32_t param1;
uint32_t param2;
uint32_t margin;
} power_threshold_params_t;
/*******************************************************************************
* Variables
******************************************************************************/
static power_nvic_context_t s_nvicContext;
static power_systick_context_t s_systickContext;
static power_clock_context_t s_clockContext;
static power_gdet_sensor_context_t s_gdetSensorContext;
static capt_pulse_timer_callback_t s_captPulseCb;
static void *s_captPulseCbParam;
static power_switch_callback_t s_preSwitch;
static void *s_preSwitchParam;
static power_switch_callback_t s_postSwitch;
static void *s_postSwitchParam;
static const uint8_t s_droTable[19] = {0x40U, 0x43U, 0x46U, 0x48U, 0x4CU, 0x4FU, 0x52U, 0x54U, 0x57U, 0x5AU,
0x5DU, 0x5FU, 0x62U, 0x65U, 0x67U, 0x69U, 0x69U, 0x69U, 0x69U};
static power_load_gdet_cfg s_gdetCfgloadFunc;
static power_gdet_data_t s_gdetCfgData;
/*******************************************************************************
* Prototypes
******************************************************************************/
/*******************************************************************************
* Code
******************************************************************************/
AT_QUICKACCESS_SECTION_CODE(static void POWER_Delay(uint32_t loop))
{
if (loop > 0U)
{
__ASM volatile(
"1: \n"
" SUBS %0, %0, #1 \n"
" CMP %0, #0 \n"
" BNE 1b \n"
:
: "r"(loop));
}
}
AT_QUICKACCESS_SECTION_CODE(static void POWER_DelayUs(uint32_t us))
{
uint32_t instNum;
instNum = ((SystemCoreClock + 999999UL) / 1000000UL) * us;
POWER_Delay((instNum + 2U) / 3U);
}
static void POWER_GetThresholdParams(uint32_t pack,
power_threshold_params_t *v11,
power_threshold_params_t *v18,
power_threshold_params_t *v33)
{
assert(v11);
assert(v18);
assert(v33);
v11->param1 = 38307U;
v11->param2 = 514850000U;
v11->margin = 750;
switch (pack)
{
case 0: /* QFN */
v18->param1 = 22034U;
v18->param2 = 507580000U;
v18->margin = 500U + 380U;
v33->param1 = 12924U;
v33->param2 = 503960000U;
v33->margin = 1000U + 200U;
break;
case 1: /* CSP */
v18->param1 = 21903U;
v18->param2 = 514170000U;
v18->margin = 500U + 305U;
v33->param1 = 12924U;
v33->param2 = 503960000U;
v33->margin = 1000U + 200U;
break;
case 2: /* BGA */
v18->param1 = 22156U;
v18->param2 = 512500000U;
v18->margin = 500U + 305U;
v33->param1 = 12917U;
v33->param2 = 513300000U;
v33->margin = 1000U + 200U;
break;
default:
assert(false);
break;
}
}
static void POWER_SaveNvicState(void)
{
uint32_t i;
uint32_t irqRegs;
uint32_t irqNum;
irqRegs = (SCnSCB->ICTR & SCnSCB_ICTR_INTLINESNUM_Msk) + 1U;
irqNum = irqRegs * 32U;
assert(irqRegs <= ARRAY_SIZE(s_nvicContext.ISER));
assert(irqNum <= ARRAY_SIZE(s_nvicContext.IPR));
s_nvicContext.PriorityGroup = NVIC_GetPriorityGrouping();
for (i = 0U; i < irqRegs; i++)
{
s_nvicContext.ISER[i] = NVIC->ISER[i];
}
for (i = 0U; i < irqNum; i++)
{
s_nvicContext.IPR[i] = NVIC->IPR[i];
}
/* Save SCB configuration */
s_nvicContext.ICSR = SCB->ICSR;
s_nvicContext.VTOR = SCB->VTOR;
s_nvicContext.AIRCR = SCB->AIRCR;
s_nvicContext.SCR = SCB->SCR;
s_nvicContext.CCR = SCB->CCR;
s_nvicContext.SHCSR = SCB->SHCSR;
s_nvicContext.MMFAR = SCB->MMFAR;
s_nvicContext.BFAR = SCB->BFAR;
s_nvicContext.CPACR = SCB->CPACR;
s_nvicContext.NSACR = SCB->NSACR;
for (i = 0U; i < ARRAY_SIZE(s_nvicContext.SHPR); i++)
{
s_nvicContext.SHPR[i] = SCB->SHPR[i];
}
}
static void POWER_RestoreNvicState(void)
{
uint32_t i;
uint32_t irqRegs;
uint32_t irqNum;
irqRegs = (SCnSCB->ICTR & SCnSCB_ICTR_INTLINESNUM_Msk) + 1U;
irqNum = irqRegs * 32U;
NVIC_SetPriorityGrouping(s_nvicContext.PriorityGroup);
for (i = 0U; i < irqRegs; i++)
{
NVIC->ISER[i] = s_nvicContext.ISER[i];
}
for (i = 0U; i < irqNum; i++)
{
NVIC->IPR[i] = s_nvicContext.IPR[i];
}
/* Restore SCB configuration */
SCB->ICSR = s_nvicContext.ICSR;
SCB->VTOR = s_nvicContext.VTOR;
SCB->AIRCR = s_nvicContext.AIRCR;
SCB->SCR = s_nvicContext.SCR;
SCB->CCR = s_nvicContext.CCR;
SCB->SHCSR = s_nvicContext.SHCSR;
SCB->MMFAR = s_nvicContext.MMFAR;
SCB->BFAR = s_nvicContext.BFAR;
SCB->CPACR = s_nvicContext.CPACR;
SCB->NSACR = s_nvicContext.NSACR;
for (i = 0U; i < ARRAY_SIZE(s_nvicContext.SHPR); i++)
{
SCB->SHPR[i] = s_nvicContext.SHPR[i];
}
}
AT_QUICKACCESS_SECTION_CODE(static void POWER_SaveGdetVSensorConfig(void))
{
s_gdetSensorContext.VSEN_CTRL_1_REG_1 =
SENSOR_CTRL->VSEN_CTRL_1_REG_1 & SENSOR_CTRL_VSEN_CTRL_1_REG_1_VSEN_SW_ENABLE_MASK;
s_gdetSensorContext.VSEN_CTRL_2_REG_1 =
SENSOR_CTRL->VSEN_CTRL_2_REG_1 & SENSOR_CTRL_VSEN_CTRL_2_REG_1_VSEN_SW_ENABLE_MASK;
s_gdetSensorContext.VSEN_CTRL_3_REG_1 =
SENSOR_CTRL->VSEN_CTRL_3_REG_1 & SENSOR_CTRL_VSEN_CTRL_3_REG_1_VSEN_SW_ENABLE_MASK;
s_gdetSensorContext.ITRC_OUT0_SEL0 = ITRC->OUT0_SEL0;
s_gdetSensorContext.ITRC_OUT1_SEL0 = ITRC->OUT1_SEL0;
s_gdetSensorContext.ITRC_OUT0_SEL0_EVENT16_31 = ITRC->OUT0_SEL0_EVENT16_31;
s_gdetSensorContext.ITRC_OUT1_SEL0_EVENT16_31 = ITRC->OUT1_SEL0_EVENT16_31;
}
AT_QUICKACCESS_SECTION_CODE(static void POWER_RestoreGdetVSensorConfig(void))
{
SENSOR_CTRL->VSEN_CTRL_1_REG_1 =
(SENSOR_CTRL->VSEN_CTRL_1_REG_1 & ~SENSOR_CTRL_VSEN_CTRL_1_REG_1_VSEN_SW_ENABLE_MASK) |
s_gdetSensorContext.VSEN_CTRL_1_REG_1;
SENSOR_CTRL->VSEN_CTRL_2_REG_1 =
(SENSOR_CTRL->VSEN_CTRL_2_REG_1 & ~SENSOR_CTRL_VSEN_CTRL_2_REG_1_VSEN_SW_ENABLE_MASK) |
s_gdetSensorContext.VSEN_CTRL_2_REG_1;
SENSOR_CTRL->VSEN_CTRL_3_REG_1 =
(SENSOR_CTRL->VSEN_CTRL_3_REG_1 & ~SENSOR_CTRL_VSEN_CTRL_3_REG_1_VSEN_SW_ENABLE_MASK) |
s_gdetSensorContext.VSEN_CTRL_3_REG_1;
ITRC->OUT0_SEL0 = s_gdetSensorContext.ITRC_OUT0_SEL0;
ITRC->OUT1_SEL0 = s_gdetSensorContext.ITRC_OUT1_SEL0;
ITRC->OUT0_SEL0_EVENT16_31 = s_gdetSensorContext.ITRC_OUT0_SEL0_EVENT16_31;
ITRC->OUT1_SEL0_EVENT16_31 = s_gdetSensorContext.ITRC_OUT1_SEL0_EVENT16_31;
}
void CAPT_PULSE_DriverIRQHandler(void);
void CAPT_PULSE_DriverIRQHandler(void)
{
/* Clear IRQ status */
PMU->CAPT_PULSE |= PMU_CAPT_PULSE_IRQ_CLR_MASK;
/* Call user callback */
if (s_captPulseCb != NULL)
{
s_captPulseCb(s_captPulseCbParam);
}
}
/**
* @brief Check if IRQ is the wakeup source
* @param irq : IRQ number
* @return true if IRQ is the wakeup source, false otherwise.
*/
bool POWER_GetWakeupStatus(IRQn_Type irq)
{
uint32_t status;
uint32_t irqNum = (uint32_t)irq;
assert((int32_t)irq >= 0);
if (irq <= HWVAD0_IRQn)
{
status = PMU->WAKEUP_PM2_STATUS0 & (1UL << irqNum);
}
else if (irq <= POWERQUAD_IRQn)
{
status = PMU->WAKEUP_PM2_STATUS1 & (1UL << (irqNum - 32U));
}
else if ((irq <= ITRC_IRQn) && (irq >= GAU_GPDAC_INT_FUNC11_IRQn))
{
status = PMU->WAKEUP_PM2_STATUS3 & (1UL << (irqNum - 96U));
}
else
{
status = 0U;
}
switch (irq)
{
case PIN0_INT_IRQn:
status = PMU->WAKEUP_STATUS & PMU_WAKEUP_STATUS_PIN0_MASK;
break;
case PIN1_INT_IRQn:
status = PMU->WAKEUP_STATUS & PMU_WAKEUP_STATUS_PIN1_MASK;
break;
case RTC_IRQn:
/* PM2 wakeup status is at WAKEUP_PM2_STATUS1, PM3/PM4 wakeup status is at WAKEUP_STATUS */
status |= PMU->WAKEUP_STATUS & PMU_WAKEUP_STATUS_RTC_MASK;
break;
case CAPT_PULSE_IRQn:
status = PMU->WAKEUP_STATUS & PMU_WAKEUP_STATUS_CAPT_MASK;
break;
case WL_MCI_WAKEUP0_IRQn:
status = PMU->WAKEUP_STATUS & (1UL << PMU_WAKEUP_STATUS_WL_SHIFT);
break;
case WL_MCI_WAKEUP1_IRQn:
status = PMU->WAKEUP_STATUS & (2UL << PMU_WAKEUP_STATUS_WL_SHIFT);
break;
case BLE_MCI_WAKEUP0_IRQn:
status = PMU->WAKEUP_STATUS & (1UL << PMU_WAKEUP_STATUS_BLE_SHIFT);
break;
case BLE_MCI_WAKEUP1_IRQn:
status = PMU->WAKEUP_STATUS & (2UL << PMU_WAKEUP_STATUS_BLE_SHIFT);
break;
default:
/* Do nothing */
break;
}
return (status != 0U);
}
/**
* @brief Clear wakeup status
* @param irq : IRQ number
*/
void POWER_ClearWakeupStatus(IRQn_Type irq)
{
uint32_t irqNum = (uint32_t)irq;
assert((int32_t)irq >= 0);
if (irq <= HWVAD0_IRQn)
{
PMU->WAKEUP_PM2_SRC_CLR0 = (1UL << irqNum);
}
else if (irq <= POWERQUAD_IRQn)
{
PMU->WAKEUP_PM2_SRC_CLR1 = (1UL << (irqNum - 32U));
}
else if ((irq <= ITRC_IRQn) && (irq >= GAU_GPDAC_INT_FUNC11_IRQn))
{
PMU->WAKEUP_PM2_SRC_CLR3 = (1UL << (irqNum - 96U));
}
else
{
/* Do nothing */
}
switch (irq)
{
case PIN0_INT_IRQn:
PMU->WAKE_SRC_CLR = PMU_WAKE_SRC_CLR_PIN0_CLR_MASK;
break;
case PIN1_INT_IRQn:
PMU->WAKE_SRC_CLR = PMU_WAKE_SRC_CLR_PIN1_CLR_MASK;
break;
case RTC_IRQn:
PMU->WAKE_SRC_CLR = PMU_WAKE_SRC_CLR_RTC_CLR_MASK;
break;
case CAPT_PULSE_IRQn:
PMU->WAKE_SRC_CLR = PMU_WAKE_SRC_CLR_CAPT_CLR_MASK;
break;
case WL_MCI_WAKEUP0_IRQn:
PMU->WAKE_SRC_CLR = (1UL << PMU_WAKE_SRC_CLR_WL_CLR_SHIFT);
break;
case WL_MCI_WAKEUP1_IRQn:
PMU->WAKE_SRC_CLR = (2UL << PMU_WAKE_SRC_CLR_WL_CLR_SHIFT);
break;
case BLE_MCI_WAKEUP0_IRQn:
PMU->WAKE_SRC_CLR = (1UL << PMU_WAKE_SRC_CLR_BLE_CLR_SHIFT);
break;
case BLE_MCI_WAKEUP1_IRQn:
PMU->WAKE_SRC_CLR = (2UL << PMU_WAKE_SRC_CLR_BLE_CLR_SHIFT);
break;
default:
/* Do nothing */
break;
}
}
/**
* @brief Enable the Wakeup interrupt.
* @param irq : IRQ number
*/
void POWER_EnableWakeup(IRQn_Type irq)
{
uint32_t irqNum = (uint32_t)irq;
assert((int32_t)irq >= 0);
if (irq <= HWVAD0_IRQn)
{
PMU->WAKEUP_PM2_MASK0 |= (1UL << irqNum);
}
else if (irq <= POWERQUAD_IRQn)
{
PMU->WAKEUP_PM2_MASK1 |= (1UL << (irqNum - 32U));
}
else if ((irq <= ITRC_IRQn) && (irq >= GAU_GPDAC_INT_FUNC11_IRQn))
{
PMU->WAKEUP_PM2_MASK3 |= (1UL << (irqNum - 96U));
}
else
{
/* Do nothing */
}
switch (irq)
{
case PIN0_INT_IRQn:
PMU->WAKEUP_MASK |= PMU_WAKEUP_MASK_PIN0_MASK_MASK;
break;
case PIN1_INT_IRQn:
PMU->WAKEUP_MASK |= PMU_WAKEUP_MASK_PIN1_MASK_MASK;
break;
case RTC_IRQn:
PMU->WAKEUP_MASK |= PMU_WAKEUP_MASK_RTC_MASK_MASK;
break;
case CAPT_PULSE_IRQn:
PMU->WAKEUP_MASK |= PMU_WAKEUP_MASK_CAPT_MASK_MASK;
break;
case WL_MCI_WAKEUP0_IRQn:
PMU->WAKEUP_MASK |= (1UL << PMU_WAKEUP_MASK_WL_MASK_SHIFT);
break;
case WL_MCI_WAKEUP1_IRQn:
PMU->WAKEUP_MASK |= (2UL << PMU_WAKEUP_MASK_WL_MASK_SHIFT);
break;
case BLE_MCI_WAKEUP0_IRQn:
PMU->WAKEUP_MASK |= (1UL << PMU_WAKEUP_MASK_BLE_MASK_SHIFT);
break;
case BLE_MCI_WAKEUP1_IRQn:
PMU->WAKEUP_MASK |= (2UL << PMU_WAKEUP_MASK_BLE_MASK_SHIFT);
break;
default:
/* Do nothing */
break;
}
}
/**
* @brief Disable the Wakeup interrupts.
* @param irq : IRQ number
*/
void POWER_DisableWakeup(IRQn_Type irq)
{
uint32_t irqNum = (uint32_t)irq;
assert((int32_t)irq >= 0);
if (irq <= HWVAD0_IRQn)
{
PMU->WAKEUP_PM2_MASK0 &= ~(1UL << irqNum);
}
else if (irq <= POWERQUAD_IRQn)
{
PMU->WAKEUP_PM2_MASK1 &= ~(1UL << (irqNum - 32U));
}
else if ((irq <= ITRC_IRQn) && (irq >= GAU_GPDAC_INT_FUNC11_IRQn))
{
PMU->WAKEUP_PM2_MASK3 &= ~(1UL << (irqNum - 96U));
}
else
{
/* Do nothing */
}
switch (irq)
{
case PIN0_INT_IRQn:
PMU->WAKEUP_MASK &= ~PMU_WAKEUP_MASK_PIN0_MASK_MASK;
break;
case PIN1_INT_IRQn:
PMU->WAKEUP_MASK &= ~PMU_WAKEUP_MASK_PIN1_MASK_MASK;
break;
case RTC_IRQn:
PMU->WAKEUP_MASK &= ~PMU_WAKEUP_MASK_RTC_MASK_MASK;
break;
case CAPT_PULSE_IRQn:
PMU->WAKEUP_MASK &= ~PMU_WAKEUP_MASK_CAPT_MASK_MASK;
break;
case WL_MCI_WAKEUP0_IRQn:
PMU->WAKEUP_MASK &= ~(1UL << PMU_WAKEUP_MASK_WL_MASK_SHIFT);
break;
case WL_MCI_WAKEUP1_IRQn:
PMU->WAKEUP_MASK &= ~(2UL << PMU_WAKEUP_MASK_WL_MASK_SHIFT);
break;
case BLE_MCI_WAKEUP0_IRQn:
PMU->WAKEUP_MASK &= ~(1UL << PMU_WAKEUP_MASK_BLE_MASK_SHIFT);
break;
case BLE_MCI_WAKEUP1_IRQn:
PMU->WAKEUP_MASK &= ~(2UL << PMU_WAKEUP_MASK_BLE_MASK_SHIFT);
break;
default:
/* Do nothing */
break;
}
}
/**
* @brief Set sleep mode on idle.
* @param mode : 0 ~ 4 stands for PM0 ~ PM4.
*/
void POWER_SetSleepMode(uint32_t mode)
{
assert(mode <= 4U);
if (mode == 0U)
{
mode = 1U; /* PM0/PM1 is same */
}
/* set PMU basic mode */
PMU->PWR_MODE = PMU_PWR_MODE_PWR_MODE(mode - 1U);
/* select deepsleep or not */
if (mode == 1U)
{
SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
}
else
{
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
}
}
AT_QUICKACCESS_SECTION_CODE(static void Power_ConfigClkGate(const power_sleep_config_t *config))
{
uint32_t pm2AnaPdCfg = (config->pm2AnaPuCfg ^ (uint32_t)kPOWER_Pm2AnaPuAll) & (uint32_t)kPOWER_Pm2AnaPuAll;
uint32_t clkGate = config->clkGate & (uint32_t)kPOWER_ClkGateAll;
/* If ENET clock is enabled, TDDR power must be on. */
if ((clkGate & SYSCTL2_SOURCE_CLK_GATE_TDDR_MCI_ENET_CLK_CG_MASK) == 0U)
{
pm2AnaPdCfg &= ~SYSCTL2_ANA_PDWN_PM2_TDDR_TOP_ANA_PDWN_PM2_MASK;
}
SYSCTL2->SOURCE_CLK_GATE = (SYSCTL2->SOURCE_CLK_GATE & (~((uint32_t)kPOWER_ClkGateAll))) | clkGate;
SYSCTL2->ANA_PDWN_PM2 = pm2AnaPdCfg;
}
AT_QUICKACCESS_SECTION_CODE(static void deinitXip(void))
{
if (IS_XIP_FLEXSPI())
{ /* FlexSPI */
/* Wait until FLEXSPI is not busy */
while (!(((FLEXSPI->STS0 & FLEXSPI_STS0_ARBIDLE_MASK) != 0U) &&
((FLEXSPI->STS0 & FLEXSPI_STS0_SEQIDLE_MASK) != 0U)))
{
}
/* Disable module. */
FLEXSPI->MCR0 |= FLEXSPI_MCR0_MDIS_MASK;
/* Disable clock. */
CLKCTL0->PSCCTL0_CLR = CLKCTL0_PSCCTL0_CLR_FLEXSPI0_MASK;
}
}
AT_QUICKACCESS_SECTION_CODE(static void initFlexSPI(FLEXSPI_Type *base))
{
uint32_t status;
uint32_t lastStatus;
uint32_t retry;
uint32_t mask = 0;
/* Enable FLEXSPI module */
base->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK;
base->MCR0 |= FLEXSPI_MCR0_SWRESET_MASK;
while ((base->MCR0 & FLEXSPI_MCR0_SWRESET_MASK) != 0U)
{
}
/* Need to wait DLL locked if DLL enabled */
if (0U != (base->DLLCR[0] & FLEXSPI_DLLCR_DLLEN_MASK))
{
lastStatus = base->STS2;
retry = FLEXSPI_DLL_LOCK_RETRY;
/* Flash on port A */
if (((base->FLSHCR0[0] & FLEXSPI_FLSHCR0_FLSHSZ_MASK) > 0U) ||
((base->FLSHCR0[1] & FLEXSPI_FLSHCR0_FLSHSZ_MASK) > 0U))
{
mask |= FLEXSPI_STS2_AREFLOCK_MASK | FLEXSPI_STS2_ASLVLOCK_MASK;
}
/* Flash on port B */
if (((base->FLSHCR0[2] & FLEXSPI_FLSHCR0_FLSHSZ_MASK) > 0U) ||
((base->FLSHCR0[3] & FLEXSPI_FLSHCR0_FLSHSZ_MASK) > 0U))
{
mask |= FLEXSPI_STS2_BREFLOCK_MASK | FLEXSPI_STS2_BSLVLOCK_MASK;
}
/* Wait slave delay line locked and slave reference delay line locked. */
do
{
status = base->STS2;
if ((status & mask) == mask)
{
/* Locked */
retry = 100;
break;
}
else if (status == lastStatus)
{
/* Same delay cell number in calibration */
retry--;
}
else
{
retry = FLEXSPI_DLL_LOCK_RETRY;
lastStatus = status;
}
} while (retry > 0U);
/* According to ERR011377, need to delay at least 100 NOPs to ensure the DLL is locked. */
for (; retry > 0U; retry--)
{
__NOP();
}
}
}
AT_QUICKACCESS_SECTION_CODE(static void initXip(void))
{
if (IS_XIP_FLEXSPI())
{ /* FlexSPI */
/* Enable FLEXSPI clock again */
CLKCTL0->PSCCTL0_SET = CLKCTL0_PSCCTL0_SET_FLEXSPI0_MASK;
/* Re-enable FLEXSPI module */
initFlexSPI(FLEXSPI);
}
}
void POWER_ConfigCauInSleep(bool pdCau)
{
if (pdCau) /* xtal / cau full pd */
{
CAU->PD_CTRL_ONE_REG |= 0x4U;
CAU->SLP_CTRL_ONE_REG = 0xCU;
}
else
{
CAU->PD_CTRL_ONE_REG &= 0xFBU;
CAU->SLP_CTRL_ONE_REG = 0x9EU;
CAU->SLP_CTRL_TWO_REG = 0x6AU;
}
}
/* Prepare to go to low power
* Change clock source to RC32M
* Switch off PLLs, XTAL
* Set Deep sleep bit in SRC register
* Initiate state change
*/
AT_QUICKACCESS_SECTION_CODE(static void POWER_PrePowerMode(uint32_t mode, const power_sleep_config_t *config))
{
uint32_t wlanPowerStatus, blePowerStatus;
assert((mode >= 1U) && (mode <= 4U));
/* Turn off Systick to avoid interrupt
* when entering low power state
*/
s_systickContext.CTRL = SysTick->CTRL;
s_systickContext.LOAD = SysTick->LOAD;
SysTick->CTRL = 0;
SysTick->LOAD = 0;
POWER_SetSleepMode(mode);
if ((mode == 2U) || (mode == 3U) || (mode == 4U))
{
/* To enter PM2/PM3/PM4, GDET sensor must be disabled */
assert(s_gdetSensorContext.disableCount > 0);
}
s_clockContext.SOURCE_CLK_GATE = SYSCTL2->SOURCE_CLK_GATE;
if (mode == 2U)
{
/* Deinit FlexSPI in case XIP */
deinitXip();
/* Keep all modules power on in SW controlled CFG */
SYSCTL2->MEM_PD_CFG = 0U;
/* Enable SW control for modules need be powered on, the others are powered down by HW */
SYSCTL2->MEM_PD_CTRL = config->pm2MemPuCfg & (uint32_t)kPOWER_Pm2MemPuAll;
Power_ConfigClkGate(config);
}
else if (mode >= 3U)
{
/* Turn off the short switch between C18/C11 and V18/V11.
In sleep mode, V11 drops to 0.8V */
BUCK18->BUCK_CTRL_TWENTY_REG = 0x75U;
if (mode == 3U)
{
POWER_SaveNvicState();
PMU->MEM_CFG = (PMU->MEM_CFG & ~PMU_MEM_CFG_MEM_RET_MASK) | (config->memPdCfg & PMU_MEM_CFG_MEM_RET_MASK);
PMU->PMIP_BUCK_CTRL = (PMU->PMIP_BUCK_CTRL & ~((uint32_t)kPOWER_Pm3BuckAll)) |
(config->pm3BuckCfg & (uint32_t)kPOWER_Pm3BuckAll);
/* Clear reset status */
PMU->SYS_RST_CLR = 0x7FU;
}
else if (mode == 4U)
{
wlanPowerStatus = POWER_WLAN_POWER_STATUS();
blePowerStatus = POWER_BLE_POWER_STATUS();
PMU->MEM_CFG =
(PMU->MEM_CFG & ~PMU_MEM_CFG_AON_MEM_RET_MASK) | (config->memPdCfg & PMU_MEM_CFG_AON_MEM_RET_MASK);
if ((wlanPowerStatus == POWER_WLAN_BLE_POWER_OFF) && (blePowerStatus == POWER_WLAN_BLE_POWER_OFF))
{
/* pm422, LDO 0.8V, 1.8V */
PMU->PMIP_LDO_LVL = PMU_PMIP_LDO_LVL_LDO18_SEL(4) | PMU_PMIP_LDO_LVL_LDO11_SEL(1);
}
/* Clear reset status */
PMU->SYS_RST_CLR = 0x7FU;
}
else
{
assert(false);
}
}
else
{
/* PM1: Do nothing */
}
if (s_preSwitch != NULL)
{
s_preSwitch(mode, s_preSwitchParam);
}
}
AT_QUICKACCESS_SECTION_CODE(static bool POWER_PostPowerMode(uint32_t mode))
{
assert((mode >= 1U) && (mode <= 4U));
if (s_postSwitch != NULL)
{
s_postSwitch(mode, s_postSwitchParam);
}
POWER_SetSleepMode(1U);
SYSCTL2->SOURCE_CLK_GATE = s_clockContext.SOURCE_CLK_GATE;
if (mode == 2U)
{
initXip();
}
else if (mode == 3U)
{
SystemInit();
POWER_RestoreNvicState();
initXip();
}
else
{
/* PM1: Do nothing */
}
if ((mode == 3U) && (PMU->PWR_MODE_STATUS == 2U))
{
/* Successfully resumed from PM3, GDET is enabled by ROM. */
assert(s_gdetSensorContext.disableCount > 0);
s_gdetSensorContext.disableCount--;
}
SysTick->CTRL = s_systickContext.CTRL;
SysTick->LOAD = s_systickContext.LOAD;
return (mode == 1U) || (PMU->PWR_MODE_STATUS == (mode - 1U)); /* PM1 doesn't update PWR_MODE_STATUS */
}
AT_QUICKACCESS_SECTION_CODE(static void POWER_EnterPm3Asm(void))
{
uint32_t clk = CLKCTL0->PSCCTL0;
uint32_t rst = RSTCTL0->PRSTCTL0;
uint32_t rtcClk = CLKCTL1->PSCCTL2 & CLKCTL1_PSCCTL2_RTC_LITE_MASK;
/* Enable AON MEM clock/reset. */
CLKCTL0->PSCCTL0_SET = CLKCTL0_PSCCTL0_SET_AON_MEM_MASK;
RSTCTL0->PRSTCTL0_CLR = RSTCTL0_PRSTCTL0_CLR_AON_MEM_MASK;
/* Address: 0x4015C000 is the address in NVRAM which holds address
* where control returns after exit from PM3.
* All general purpose registers and special registers
* are saved by pushing them on current thread's stack
* and finally SP is saved in NVRAM address 0x4015C004. */
__ASM volatile(
"push {r0-r12, lr}\n"
"mrs r1, basepri\n"
"push {r1}\n"
"mrs r1, primask\n"
"push {r1}\n"
"mrs r1, faultmask\n"
"push {r1}\n"
"mrs r1, control\n"
"bic r2, r1, #2\n"
"msr control, r2\n" /* Use MSP */
"push {r1}\n" /* CONTROL */
"mrs r1, psp\n"
"push {r1}\n" /* PSP */
"mrs r1, psplim\n"
"push {r1}\n" /* PSPLIM */
"mrs r1, msplim\n"
"push {r1}\n" /* MSPLIM */
"ldr r0, =0x4015C004\n"
"str sp, [r0]\n" /* MSP */
"ldr r0, =0x4015C000\n"
"mov r1, pc\n"
"add r1, r1 , #21\n"
"str r1, [r0]\n");
/*
* Execute WFI to generate a state change
* and system is in an unresponsive state
* press wakeup key to get it out of standby
* If time_to_standby is set to valid value
* RTC is programmed and RTC generates
* a wakeup signal.
*/
__DSB();
__WFI();
__ISB();
__NOP();
__NOP();
__NOP();
__NOP();
__NOP();
__NOP();
__NOP();
/* When system exits PM3 all registers need to be
* restored as they are lost. */
/*
* When MCU enters PM3 all Core registers
* r0-r12
* lr
* basepri
* primask
* faultmask
* control
* psp
* psplim
* msplim
* are lost (ZERO) as MCU power is tuned off
* On wakeup from PM3, this piece of code restores
* these registers which were saved before entry.
* The location of saving this register was on stack
*/
__ASM volatile(
"ldr r0, =0x4015C004\n"
"ldr sp, [r0]\n"
"pop {r4}\n" /* MSPLIM */
"pop {r5}\n" /* PSPLIM */
"pop {r1}\n" /* PSP */
"pop {r2}\n" /* CONTROL */
"mov r3, sp\n" /* MSP */
"msr msplim, r4\n"
"msr psplim, r5\n"
"msr msp, r3\n"
"msr psp, r1\n"
"msr control, r2\n"
"pop {r1}\n"
"msr faultmask, r1\n"
"pop {r1}\n"
"msr primask, r1\n"
"pop {r1}\n"
"msr basepri, r1\n"
"pop {r0-r12, lr}\n");
/* Restore AON MEM clock/reset */
CLKCTL0->PSCCTL0 = clk;
RSTCTL0->PRSTCTL0 = rst;
CLKCTL1->PSCCTL2_SET = rtcClk;
}
static void POWER_InitVSensorThreshold(uint8_t volt11, uint32_t pack)
{
uint32_t val;
uint32_t svcMv;
power_threshold_params_t v11 = {0};
power_threshold_params_t v18 = {0};
power_threshold_params_t v33 = {0};
POWER_GetThresholdParams(pack, &v11, &v18, &v33);
/* Disable V11 sensor */
val = SENSOR_CTRL->VSEN_CTRL_1_REG_1;
SENSOR_CTRL->VSEN_CTRL_1_REG_1 = val & ~SENSOR_CTRL_VSEN_CTRL_1_REG_1_VSEN_SW_ENABLE_MASK;
/* Configure threshold */
svcMv = (uint32_t)(volt11)*5U + 630U;
val = val & ~(SENSOR_CTRL_VSEN_CTRL_1_REG_1_VSEN_MAX_VOLTAGE_THR_MASK |
SENSOR_CTRL_VSEN_CTRL_1_REG_1_VSEN_MIN_VOLTAGE_THR_MASK);
val |= SENSOR_CTRL_VSEN_CTRL_1_REG_1_VSEN_MAX_VOLTAGE_THR(
(v11.param1 * (svcMv * 10U + v11.margin) + v11.param2 + 999999U) / 1000000U);
val |= SENSOR_CTRL_VSEN_CTRL_1_REG_1_VSEN_MIN_VOLTAGE_THR((v11.param1 * (svcMv * 10U - v11.margin) + v11.param2) /
1000000U);
SENSOR_CTRL->VSEN_CTRL_1_REG_1 = val & ~SENSOR_CTRL_VSEN_CTRL_1_REG_1_VSEN_SW_ENABLE_MASK;
/* Restore V11 sensor */
SENSOR_CTRL->VSEN_CTRL_1_REG_1 = val;
/* Disable V18 sensor */
val = SENSOR_CTRL->VSEN_CTRL_2_REG_1;
SENSOR_CTRL->VSEN_CTRL_2_REG_1 = val & ~SENSOR_CTRL_VSEN_CTRL_2_REG_1_VSEN_SW_ENABLE_MASK;
/* Configure threshold */
val = val & ~(SENSOR_CTRL_VSEN_CTRL_2_REG_1_VSEN_MAX_VOLTAGE_THR_MASK |
SENSOR_CTRL_VSEN_CTRL_2_REG_1_VSEN_MIN_VOLTAGE_THR_MASK);
val |= SENSOR_CTRL_VSEN_CTRL_2_REG_1_VSEN_MAX_VOLTAGE_THR(
(v18.param1 * (1890U * 10U + v18.margin) + v18.param2 + 999999U) / 1000000U);
val |= SENSOR_CTRL_VSEN_CTRL_2_REG_1_VSEN_MIN_VOLTAGE_THR((v18.param1 * (1710U * 10U - v18.margin) + v18.param2) /
1000000U);
SENSOR_CTRL->VSEN_CTRL_2_REG_1 = val & ~SENSOR_CTRL_VSEN_CTRL_2_REG_1_VSEN_SW_ENABLE_MASK;
/* Restore V18 sensor */
SENSOR_CTRL->VSEN_CTRL_2_REG_1 = val;
/* Disable V33 sensor */
val = SENSOR_CTRL->VSEN_CTRL_3_REG_1;
SENSOR_CTRL->VSEN_CTRL_3_REG_1 = val & ~SENSOR_CTRL_VSEN_CTRL_3_REG_1_VSEN_SW_ENABLE_MASK;
/* Configure threshold */
val = val & ~(SENSOR_CTRL_VSEN_CTRL_3_REG_1_VSEN_MAX_VOLTAGE_THR_MASK |
SENSOR_CTRL_VSEN_CTRL_3_REG_1_VSEN_MIN_VOLTAGE_THR_MASK);
val |= SENSOR_CTRL_VSEN_CTRL_3_REG_1_VSEN_MAX_VOLTAGE_THR(
(v33.param1 * (3630U * 10U + v33.margin) + v33.param2 + 999999U) / 1000000U);
val |= SENSOR_CTRL_VSEN_CTRL_3_REG_1_VSEN_MIN_VOLTAGE_THR((v33.param1 * (1850U * 10U - v33.margin) + v33.param2) /
1000000U);
SENSOR_CTRL->VSEN_CTRL_3_REG_1 = val & ~SENSOR_CTRL_VSEN_CTRL_3_REG_1_VSEN_SW_ENABLE_MASK;
/* Restore V33 sensor */
SENSOR_CTRL->VSEN_CTRL_3_REG_1 = val;
}
void POWER_GetCurrentSleepConfig(power_sleep_config_t *config)
{
assert(config != NULL);
config->pm2MemPuCfg = (~SYSCTL2->MEM_PD_CFG) & (SYSCTL2->MEM_PD_CTRL);
config->pm2AnaPuCfg = (~SYSCTL2->ANA_PDWN_PM2) & (uint32_t)kPOWER_Pm2AnaPuAll;
config->clkGate = SYSCTL2->SOURCE_CLK_GATE;
config->memPdCfg = PMU->MEM_CFG;
config->pm3BuckCfg = PMU->PMIP_BUCK_CTRL & (uint32_t)kPOWER_Pm3BuckAll;
}
void POWER_InitPowerConfig(const power_init_config_t *config)
{
uint32_t reg;
bool iBuck, gateCauRefClk;
assert(config != NULL);
iBuck = config->iBuck;
gateCauRefClk = config->gateCauRefClk;
BUCK11->BUCK_CTRL_THREE_REG = 0x10U;
BUCK18->BUCK_CTRL_THREE_REG = 0x10U;
BUCK18->BUCK_CTRL_TWENTY_REG = 0x55U;
SYSCTL0->AUTOCLKGATEOVERRIDE0 = 0U;
/* Enable RAM dynamic clk gate */
SYSCTL0->AUTOCLKGATEOVERRIDE1 = 0U;
/* Enable ROM dynamic clk gate */
SYSCTL2->ROM_DYN_CLK_EN = SYSCTL2_ROM_DYN_CLK_EN_ROM_DYN_CLK_EN_MASK;
PMU->PMIP_LDO_LVL = 0U;
if (iBuck)
{
/* No timeout with internal supply. */
PMU->TIME_OUT_CTRL = PMU_TIME_OUT_CTRL_V11_RDY_NO_TMT_MASK | PMU_TIME_OUT_CTRL_V18_RDY_NO_TMT_MASK |
PMU_TIME_OUT_CTRL_PSW_MCI_RDY_NO_TMT_MASK;
}
else
{
/* Use timeout mode with external supply for VCORE and AVDD18. */
PMU->TIME_OUT_CTRL = PMU_TIME_OUT_CTRL_PSW_MCI_RDY_NO_TMT_MASK;
PMU->TIME_OUT_CFG_VALUE = 0x3FFFFFFFU;
}
PMU->SOC_MEM_PDWN &= ~(PMU_SOC_MEM_PDWN_MSC_MEM_PDWN_CTRL_MASK | PMU_SOC_MEM_PDWN_SOCTOP_OTP_PDWN_CTRL_MASK);
PMU->CAU_SLP_CTRL = gateCauRefClk ? PMU_CAU_SLP_CTRL_CAU_SOC_SLP_CG_MASK : 0U;
/* Open usb clock and release reset */
reg = CLKCTL0->PSCCTL0;
CLKCTL0->PSCCTL0_SET = CLKCTL0_PSCCTL0_SET_USB_MASK;
RSTCTL0->PRSTCTL0_CLR = RSTCTL0_PRSTCTL0_CLR_USB_MASK;
POWER_DelayUs(1U);
/* Restore usb clk. */
CLKCTL0->PSCCTL0 = reg;
/* Disable G2BIST CLK */
CLKCTL0->G2BIST_CLK_EN = 0U;
}
void POWER_SetPowerSwitchCallback(power_switch_callback_t pre,
void *preParam,
power_switch_callback_t post,
void *postParam)
{
s_preSwitch = pre;
s_preSwitchParam = preParam;
s_postSwitch = post;
s_postSwitchParam = postParam;
}
bool POWER_EnterPowerMode(uint32_t mode, const power_sleep_config_t *config)
{
uint32_t primask;
bool ret = true;
assert(mode <= 4U);
/* Needed to make POWER_DelayUs() accurate. */
SystemCoreClockUpdate();
if (mode >= 1U)
{
primask = DisableGlobalIRQ();
POWER_PrePowerMode(mode, config);
if (mode == 3U)
{
POWER_EnterPm3Asm();
}
else
{
__DSB();
__WFI();
__ISB();
}
ret = POWER_PostPowerMode(mode);
EnableGlobalIRQ(primask);
}
return ret;
}
void POWER_PowerOnWlan(void)
{
if (POWER_WLAN_POWER_STATUS() == POWER_WLAN_BLE_POWER_OFF)
{
/* Enable SW control */
PMU->SW_CTRL_WL |= PMU_SW_CTRL_WL_WL_EN_MASK;
/* WLan request buck on, then need wait 5 fast clk_pmu cycles, do psw on, then iso release */
PMU->SW_CTRL_WL |= PMU_SW_CTRL_WL_WL_BUCK_ON_REQ_MASK;
/* Wait buck on */
POWER_WAIT_PMU();
PMU->SW_CTRL_WL &= ~PMU_SW_CTRL_WL_PSW_WL_PD_MASK;
/* Wait PSW ready */
SystemCoreClockUpdate();
POWER_DelayUs(50U);
/* Disable ISO */
PMU->SW_CTRL_WL |= PMU_SW_CTRL_WL_MCI_ISO_WL_N_MASK;
/* Wait about 125us */
POWER_DelayUs(125U);
/* Release WLan */
PMU->SW_CTRL_WL &= ~PMU_SW_CTRL_WL_MCI_WL_PU_RST_MASK;
}
}
void POWER_PowerOffWlan(void)
{
if (POWER_WLAN_POWER_STATUS() != POWER_WLAN_BLE_POWER_OFF)
{
/* Enable SW control */
PMU->SW_CTRL_WL |= PMU_SW_CTRL_WL_WL_EN_MASK;
/* Enable ISO before PSW off */
PMU->SW_CTRL_WL &= ~PMU_SW_CTRL_WL_MCI_ISO_WL_N_MASK;
POWER_WAIT_PMU();
PMU->SW_CTRL_WL |= PMU_SW_CTRL_WL_PSW_WL_PD_MASK;
/* Wait PSW off */
while ((SOCCTRL->PSW_VD2_RDY0 & (1UL << 1)) == 0U)
{
}
/* Reset WLan */
PMU->SW_CTRL_WL |= PMU_SW_CTRL_WL_MCI_WL_PU_RST_MASK;
/* Request buck off */
PMU->SW_CTRL_WL |= PMU_SW_CTRL_WL_WL_BUCK_OFF_REQ_MASK;
}
}
void POWER_PowerOnBle(void)
{
if (POWER_BLE_POWER_STATUS() == POWER_WLAN_BLE_POWER_OFF)
{
/* Enable SW control */
PMU->SW_CTRL_BLE |= PMU_SW_CTRL_BLE_BLE_EN_MASK;
/* BLE request buck on, then need wait 5 fast clk_pmu cycles(about 96ns),do psw on, then iso release */
PMU->SW_CTRL_BLE |= PMU_SW_CTRL_BLE_BLE_BUCK_ON_REQ_MASK;
/* Wait buck on */
POWER_WAIT_PMU();
PMU->SW_CTRL_BLE &= ~PMU_SW_CTRL_BLE_PSW_BLE_PD_MASK;
/* Wait PSW ready */
SystemCoreClockUpdate();
POWER_DelayUs(50U);
/* Disable ISO */
PMU->SW_CTRL_BLE |= PMU_SW_CTRL_BLE_MCI_ISO_BLE_N_MASK;
/* Wait about 125us */
POWER_DelayUs(125U);
/* Release BLE */
PMU->SW_CTRL_BLE &= ~PMU_SW_CTRL_BLE_MCI_BLE_PU_RST_MASK;
}
}
void POWER_PowerOffBle(void)
{
if (POWER_BLE_POWER_STATUS() != POWER_WLAN_BLE_POWER_OFF)
{
/* Enable SW control */
PMU->SW_CTRL_BLE |= PMU_SW_CTRL_BLE_BLE_EN_MASK;
/* Enable ISO before PSW off */
PMU->SW_CTRL_BLE &= ~PMU_SW_CTRL_BLE_MCI_ISO_BLE_N_MASK;
POWER_WAIT_PMU();
PMU->SW_CTRL_BLE |= PMU_SW_CTRL_BLE_PSW_BLE_PD_MASK;
/* Wait PSW off */
while ((SOCCTRL->PSW_VD2_RDY0 & (1UL << 9)) == 0U)
{
}
/* Reset BLE */
PMU->SW_CTRL_BLE |= PMU_SW_CTRL_BLE_MCI_BLE_PU_RST_MASK;
/* Request buck off */
PMU->SW_CTRL_BLE |= PMU_SW_CTRL_BLE_BLE_BUCK_OFF_REQ_MASK;
}
}
void POWER_PowerOnGau(void)
{
GAU_BG->CTRL &= ~BG_CTRL_PD_MASK;
while ((GAU_BG->STATUS & BG_STATUS_RDY_MASK) == 0U)
{
}
}
void POWER_PowerOffGau(void)
{
GAU_BG->CTRL |= BG_CTRL_PD_MASK;
}
void POWER_EnableCaptSlowPulseTimer(capt_slow_pulse_width_t width,
capt_slow_pulse_edge_t edge,
uint32_t timeout,
capt_pulse_timer_callback_t cb,
void *param)
{
s_captPulseCb = cb;
s_captPulseCbParam = param;
PMU->CAPT_PULSE = PMU_CAPT_PULSE_IRQ_CLR_MASK | PMU_CAPT_PULSE_IRQ_MSK_MASK;
PMU->CAPT_PULSE_BASE_VAL = timeout;
PMU->CAPT_PULSE = PMU_CAPT_PULSE_IC_WIDTH_CLK_CNT(width) | PMU_CAPT_PULSE_IC_EDGE_CLK_CNT(edge);
PMU->CAPT_PULSE |= PMU_CAPT_PULSE_CAPTURE_SLOW_PULSE_CNT_EN_MASK;
}
void POWER_EnableCaptFastPulseTimer(uint32_t timeout, capt_pulse_timer_callback_t cb, void *param)
{
s_captPulseCb = cb;
s_captPulseCbParam = param;
PMU->CAPT_PULSE = PMU_CAPT_PULSE_IRQ_CLR_MASK | PMU_CAPT_PULSE_IRQ_MSK_MASK;
PMU->CAPT_PULSE_BASE_VAL = timeout;
PMU->CAPT_PULSE = PMU_CAPT_PULSE_CLK_SEL_MASK;
PMU->CAPT_PULSE |= PMU_CAPT_PULSE_CAPTURE_FAST_PULSE_CNT_EN_MASK;
}
void POWER_DisableCaptPulseTimer(void)
{
PMU->CAPT_PULSE = PMU_CAPT_PULSE_IRQ_CLR_MASK | PMU_CAPT_PULSE_IRQ_MSK_MASK;
}
void Power_InitLoadGdetCfg(power_load_gdet_cfg loadFunc, const power_gdet_data_t *data, uint32_t pack)
{
assert(loadFunc != NULL);
assert(data != NULL);
assert(pack <= 2U);
s_gdetCfgloadFunc = loadFunc;
(void)memcpy(&s_gdetCfgData, data, sizeof(power_gdet_data_t));
s_gdetCfgData.CFG[3] = POWER_TrimSvc(data->CFG[3], pack);
}
/* Configure voltage threshold */
void POWER_InitVoltage(uint32_t dro, uint32_t pack)
{
int32_t i;
uint8_t val;
SystemCoreClockUpdate();
/* LPBG trim */
BUCK11->BUCK_CTRL_EIGHTEEN_REG = 0x6U;
if (dro == 0U)
{ /* Boot voltage 1.11V */
val = 0x60U;
}
else
{
/* Change buck level */
dro /= 1000U;
i = 36 - (int32_t)dro;
assert((i >= 0) && ((uint32_t)i < ARRAY_SIZE(s_droTable)));
val = s_droTable[i];
}
PMU->PMIP_BUCK_LVL = PMU_PMIP_BUCK_LVL_SLEEP_BUCK18_SEL(0x60U) | /* 1.8V */
PMU_PMIP_BUCK_LVL_SLEEP_BUCK11_SEL(0x22U) | /* 0.8V */
PMU_PMIP_BUCK_LVL_NORMAL_BUCK18_SEL(0x60U) | /* 1.8V */
PMU_PMIP_BUCK_LVL_NORMAL_BUCK11_SEL(val);
/* Delay 600us */
POWER_DelayUs(600U);
POWER_InitVSensorThreshold(val, pack);
}
void POWER_DisableGDetVSensors(void)
{
uint32_t val;
uint32_t pscctl0, pscctl1, pscctl2;
uint32_t rstctl0, rstctl1;
if (s_gdetSensorContext.disableCount == 0)
{
pscctl0 = CLKCTL0->PSCCTL0;
pscctl1 = CLKCTL0->PSCCTL1;
pscctl2 = CLKCTL0->PSCCTL2;
rstctl0 = RSTCTL0->PRSTCTL0;
rstctl1 = RSTCTL0->PRSTCTL1;
/* Enable ELS/ITRC clock */
CLKCTL0->PSCCTL0_SET = CLKCTL0_PSCCTL0_ELS_MASK;
CLKCTL0->PSCCTL1_SET = CLKCTL0_PSCCTL1_ELS_APB_MASK;
CLKCTL0->PSCCTL2_SET = CLKCTL0_PSCCTL2_ITRC_MASK;
/* Clear ELS reset */
RSTCTL0->PRSTCTL0_CLR = RSTCTL0_PRSTCTL0_ELS_MASK;
RSTCTL0->PRSTCTL1_CLR = RSTCTL0_PRSTCTL1_ELS_APB_MASK;
s_gdetSensorContext.ELS_EN = ELS->ELS_CTRL & ELS_ELS_CTRL_ELS_EN_MASK;
/* Save GDET VSEN config */
POWER_SaveGdetVSensorConfig();
if (s_gdetSensorContext.ELS_EN != 0U)
{
s_gdetSensorContext.ELS_INT_ENABLE = ELS->ELS_INT_ENABLE;
}
/* Disable ITRC interrupts, especially security sensors */
/* Disable V11 sensor */
val = SENSOR_CTRL->VSEN_CTRL_1_REG_1 & ~SENSOR_CTRL_VSEN_CTRL_1_REG_1_VSEN_SW_ENABLE_MASK;
SENSOR_CTRL->VSEN_CTRL_1_REG_1 = val;
/* Disable V18 sensor */
val = SENSOR_CTRL->VSEN_CTRL_2_REG_1 & ~SENSOR_CTRL_VSEN_CTRL_2_REG_1_VSEN_SW_ENABLE_MASK;
SENSOR_CTRL->VSEN_CTRL_2_REG_1 = val;
/* Disable V33 sensor */
val = SENSOR_CTRL->VSEN_CTRL_3_REG_1 & ~SENSOR_CTRL_VSEN_CTRL_3_REG_1_VSEN_SW_ENABLE_MASK;
SENSOR_CTRL->VSEN_CTRL_3_REG_1 = val;
if (s_gdetSensorContext.ELS_EN != 0U)
{
/* Disable CSS_INT_ENABLE[GDET_INT_EN] bit field */
ELS->ELS_INT_ENABLE &= ~ELS_ELS_INT_ENABLE_GDET_INT_EN_MASK;
}
/* Disable aGDET/LVD/HVD interrupts in ITRC */
val = ITRC->OUT0_SEL0 & ~ITRC_OUT_SEL_MASK;
ITRC->OUT0_SEL0 = val | ITRC_OUT_SEL_DISABLE;
val = ITRC->OUT1_SEL0 & ~ITRC_OUT_SEL_MASK;
ITRC->OUT1_SEL0 = val | ITRC_OUT_SEL_DISABLE;
val = ITRC->OUT0_SEL0_EVENT16_31 & ~ITRC_OUT_SEL_EVENT_MASK;
ITRC->OUT0_SEL0_EVENT16_31 = val | ITRC_OUT_SEL_EVENT_DISABLE;
val = ITRC->OUT1_SEL0_EVENT16_31 & ~ITRC_OUT_SEL_EVENT_MASK;
ITRC->OUT1_SEL0_EVENT16_31 = val | ITRC_OUT_SEL_EVENT_DISABLE;
/* Restore ELS/ITRC clock */
CLKCTL0->PSCCTL0 = pscctl0;
CLKCTL0->PSCCTL1 = pscctl1;
CLKCTL0->PSCCTL2 = pscctl2;
/* Restore ELS reset */
RSTCTL0->PRSTCTL0 = rstctl0;
RSTCTL0->PRSTCTL1 = rstctl1;
}
s_gdetSensorContext.disableCount++;
}
bool POWER_EnableGDetVSensors(void)
{
uint32_t pscctl0, pscctl1, pscctl2;
uint32_t rstctl0, rstctl1;
bool retval = true;
s_gdetSensorContext.disableCount--;
if (s_gdetSensorContext.disableCount == 0)
{
pscctl0 = CLKCTL0->PSCCTL0;
pscctl1 = CLKCTL0->PSCCTL1;
pscctl2 = CLKCTL0->PSCCTL2;
rstctl0 = RSTCTL0->PRSTCTL0;
rstctl1 = RSTCTL0->PRSTCTL1;
/* Enable ELS/ITRC clock */
CLKCTL0->PSCCTL0_SET = CLKCTL0_PSCCTL0_ELS_MASK;
CLKCTL0->PSCCTL1_SET = CLKCTL0_PSCCTL1_ELS_APB_MASK;
CLKCTL0->PSCCTL2_SET = CLKCTL0_PSCCTL2_ITRC_MASK;
/* Clear ELS reset */
RSTCTL0->PRSTCTL0_CLR = RSTCTL0_PRSTCTL0_ELS_MASK;
RSTCTL0->PRSTCTL1_CLR = RSTCTL0_PRSTCTL1_ELS_APB_MASK;
/* Only in the normal flow that GDET_INT_EN is disabled, we will restore GDET config here.
* An exception is that we call POWER_DisableGDetVSensors() before PM3 and then wake up
* from ROM. In that case, ELS_INT_ENABLE will be set by ROM again and we shouldn't config
* GDET here. */
if (((ELS->ELS_CTRL & ELS_ELS_CTRL_ELS_EN_MASK) != 0U) &&
(ELS->ELS_INT_ENABLE & ELS_ELS_INT_ENABLE_GDET_INT_EN_MASK) == 0U)
{
POWER_RestoreGdetVSensorConfig();
if ((s_gdetSensorContext.ELS_EN != 0U) && (s_gdetSensorContext.ELS_INT_ENABLE != 0U))
{
/* To enable GDET, load function must be configured. */
if (s_gdetCfgloadFunc == NULL)
{
retval = false;
}
else
{
/* GDET config must be loaded correctly for GDET working. */
retval = s_gdetCfgloadFunc(&s_gdetCfgData);
}
/* Clear GDET errors */
ELS->ELS_INT_STATUS_CLR =
ELS_ELS_INT_STATUS_CLR_INT_CLR_MASK | ELS_ELS_INT_STATUS_CLR_GDET_INT_CLR_MASK;
ELS->ELS_ERR_STATUS_CLR = ELS_ELS_ERR_STATUS_CLR_ERR_CLR_MASK;
ELS->ELS_GDET_EVTCNT_CLR = ELS_ELS_GDET_EVTCNT_CLR_GDET_EVTCNT_CLR_MASK;
/* Clear Sensor errors */
SENSOR_CTRL->SEN_CLR_REG = 0x3CU;
/* Clear ITRC status */
ITRC->STATUS0 = ITRC->STATUS0;
ITRC->STATUS1 = ITRC->STATUS1;
if (retval)
{
ELS->ELS_INT_ENABLE = s_gdetSensorContext.ELS_INT_ENABLE;
}
}
}
/* Restore ELS/ITRC clock */
CLKCTL0->PSCCTL0 = pscctl0;
CLKCTL0->PSCCTL1 = pscctl1;
CLKCTL0->PSCCTL2 = pscctl2;
/* Restore ELS reset */
RSTCTL0->PRSTCTL0 = rstctl0;
RSTCTL0->PRSTCTL1 = rstctl1;
}
return retval;
}
uint32_t POWER_TrimSvc(uint32_t gdetTrim, uint32_t pack)
{
int32_t x;
int32_t y1, y3;
uint32_t trimSvc = gdetTrim;
uint32_t clk;
uint32_t rst;
uint32_t revision = SOCCTRL->CHIP_INFO & SOCCIU_CHIP_INFO_REV_NUM_MASK;
if (revision == 2U)
{
/* A2 */
/* Autotrim value at [7:0] */
x = (int32_t)(uint32_t)(gdetTrim & 0xFFUL);
if (pack == 0U)
{
/* QFN */
y1 = (18 * x * x) + (801 * x) + 437290;
y3 = y1 / 10000;
}
else if (pack == 1U)
{
/* CSP */
y1 = (82 * x * x) - (5171 * x) + 559320;
y3 = y1 / 10000;
}
else
{
/* BGA */
assert(pack == 2U);
y1 = (25 * x * x) + (1337 * x) + 381140;
y3 = y1 / 10000;
}
trimSvc = ((uint32_t)y3) << 24;
clk = CLKCTL0->PSCCTL0;
rst = RSTCTL0->PRSTCTL0;
/* Enable AON MEM clock/reset. */
CLKCTL0->PSCCTL0_SET = CLKCTL0_PSCCTL0_SET_AON_MEM_MASK;
RSTCTL0->PRSTCTL0_CLR = RSTCTL0_PRSTCTL0_CLR_AON_MEM_MASK;
POWER_WRITE_MEM32(0x4015C00CU, trimSvc);
/* Restore AON MEM clock/reset */
CLKCTL0->PSCCTL0 = clk;
RSTCTL0->PRSTCTL0 = rst;
}
return trimSvc;
}