/* * Copyright 2020-2023 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "fsl_power.h" #include /******************************************************************************* * 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; }