Skip to content

Commit 04b94b6

Browse files
mmahadevan108jhedberg
authored andcommitted
soc: mcxw: Add Power Management support
Add PM support for MCXW SoC's Signed-off-by: Mahesh Mahadevan <[email protected]>
1 parent 0d4d0cf commit 04b94b6

File tree

6 files changed

+223
-0
lines changed

6 files changed

+223
-0
lines changed

soc/nxp/mcx/mcxw/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ config SOC_FAMILY_MCXW
1818
select SOC_EARLY_INIT_HOOK
1919
select CLOCK_CONTROL
2020
select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE
21+
select HAS_PM

soc/nxp/mcx/mcxw/mcxw7xx/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ zephyr_sources(soc.c)
66
zephyr_sources_ifdef(CONFIG_SOC_MCXW716C mcxw71_platform_init.S)
77
zephyr_sources_ifdef(CONFIG_SOC_MCXW727C mcxw72_platform_init.S)
88

9+
zephyr_sources_ifdef(CONFIG_PM power.c)
10+
911
zephyr_include_directories(./)
1012

1113
set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "")

soc/nxp/mcx/mcxw/mcxw7xx/Kconfig.defconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,13 @@ config NUM_IRQS
88
default 77 if SOC_MCXW727C
99
default 75
1010

11+
config MCUX_LPTMR_TIMER
12+
default y if PM
13+
14+
DT_LPTMR_PATH := $(dt_nodelabel_path,lptmr0)
1115
config SYS_CLOCK_HW_CYCLES_PER_SEC
1216
default 96000000 if CORTEX_M_SYSTICK
17+
default $(dt_node_int_prop_int,$(DT_LPTMR_PATH),clock-frequency) if MCUX_LPTMR_TIMER
1318

1419
config MCUX_FLASH_K4_API
1520
default y

soc/nxp/mcx/mcxw/mcxw7xx/power.c

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
/*
2+
* Copyright 2025 NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#include <zephyr/kernel.h>
7+
#include <zephyr/pm/pm.h>
8+
#include <fsl_cmc.h>
9+
#include <fsl_spc.h>
10+
#include <fsl_vbat.h>
11+
#include <fsl_wuu.h>
12+
13+
#include <zephyr/logging/log.h>
14+
15+
LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL);
16+
17+
#define WUU_WAKEUP_LPTMR_IDX 0
18+
#define MCXW7_WUU_ADDR (WUU_Type *)DT_REG_ADDR(DT_INST(0, nxp_wuu))
19+
#define MCXW7_CMC_ADDR (CMC_Type *)DT_REG_ADDR(DT_INST(0, nxp_cmc))
20+
#define MCXW7_VBAT_ADDR (VBAT_Type *)DT_REG_ADDR(DT_INST(0, nxp_vbat))
21+
#define MCXW7_SPC_ADDR (SPC_Type *)DT_REG_ADDR(DT_INST(0, nxp_spc))
22+
23+
void mcxw7xx_set_wakeup(int32_t sig)
24+
{
25+
WUU_SetInternalWakeUpModulesConfig(MCXW7_WUU_ADDR, sig, kWUU_InternalModuleInterrupt);
26+
}
27+
28+
/*
29+
* 1. Set power mode protection
30+
* 2. Disable low power mode debug
31+
* 3. Enable Flash Doze mode.
32+
*/
33+
static void set_cmc_configuration(void)
34+
{
35+
CMC_SetPowerModeProtection(MCXW7_CMC_ADDR, kCMC_AllowAllLowPowerModes);
36+
CMC_LockPowerModeProtectionSetting(MCXW7_CMC_ADDR);
37+
CMC_EnableDebugOperation(MCXW7_CMC_ADDR, IS_ENABLED(CONFIG_DEBUG));
38+
CMC_ConfigFlashMode(MCXW7_CMC_ADDR, false, false, false);
39+
}
40+
41+
/*
42+
* Disable Backup SRAM regulator, FRO16K and Bandgap which
43+
* locates in VBAT power domain for most of power modes.
44+
*
45+
*/
46+
static void deinit_vbat(void)
47+
{
48+
VBAT_EnableBackupSRAMRegulator(MCXW7_VBAT_ADDR, false);
49+
VBAT_EnableFRO16k(MCXW7_VBAT_ADDR, false);
50+
while (VBAT_CheckFRO16kEnabled(MCXW7_VBAT_ADDR)) {
51+
};
52+
VBAT_EnableBandgap(MCXW7_VBAT_ADDR, false);
53+
while (VBAT_CheckBandgapEnabled(MCXW7_VBAT_ADDR)) {
54+
};
55+
}
56+
57+
/* Invoke Low Power/System Off specific Tasks */
58+
__weak void pm_state_set(enum pm_state state, uint8_t substate_id)
59+
{
60+
/* Set PRIMASK */
61+
__disable_irq();
62+
/* Set BASEPRI to 0 */
63+
irq_unlock(0);
64+
65+
set_cmc_configuration();
66+
deinit_vbat();
67+
68+
switch (state) {
69+
case PM_STATE_SUSPEND_TO_IDLE:
70+
cmc_power_domain_config_t config;
71+
72+
/* Set NBU into Sleep Mode */
73+
RFMC->RF2P4GHZ_CTRL = (RFMC->RF2P4GHZ_CTRL &
74+
(~RFMC_RF2P4GHZ_CTRL_LP_MODE_MASK)) |
75+
RFMC_RF2P4GHZ_CTRL_LP_MODE(0x1);
76+
RFMC->RF2P4GHZ_CTRL |= RFMC_RF2P4GHZ_CTRL_LP_ENTER_MASK;
77+
78+
/* Set MAIN_CORE and MAIN_WAKE power domain into sleep mode. */
79+
config.clock_mode = kCMC_GateAllSystemClocksEnterLowPowerMode;
80+
config.main_domain = kCMC_SleepMode;
81+
config.wake_domain = kCMC_SleepMode;
82+
CMC_EnterLowPowerMode(MCXW7_CMC_ADDR, &config);
83+
84+
break;
85+
case PM_STATE_STANDBY:
86+
/* Enable CORE VDD Voltage scaling. */
87+
SPC_EnableLowPowerModeCoreVDDInternalVoltageScaling(MCXW7_SPC_ADDR, true);
88+
89+
/* Set NBU into Deep Sleep Mode */
90+
RFMC->RF2P4GHZ_CTRL = (RFMC->RF2P4GHZ_CTRL & (~RFMC_RF2P4GHZ_CTRL_LP_MODE_MASK)) |
91+
RFMC_RF2P4GHZ_CTRL_LP_MODE(0x3);
92+
RFMC->RF2P4GHZ_CTRL |= RFMC_RF2P4GHZ_CTRL_LP_ENTER_MASK;
93+
94+
/* Set MAIN_CORE and MAIN_WAKE power domain into Deep Sleep Mode. */
95+
config.clock_mode = kCMC_GateAllSystemClocksEnterLowPowerMode;
96+
config.main_domain = kCMC_DeepSleepMode;
97+
config.wake_domain = kCMC_DeepSleepMode;
98+
99+
CMC_EnterLowPowerMode(MCXW7_CMC_ADDR, &config);
100+
101+
break;
102+
default:
103+
LOG_DBG("Unsupported power state %u", state);
104+
break;
105+
}
106+
}
107+
108+
/* Handle SOC specific activity after Low Power Mode Exit */
109+
__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id)
110+
{
111+
ARG_UNUSED(state);
112+
ARG_UNUSED(substate_id);
113+
114+
/* Clear PRIMASK */
115+
__enable_irq();
116+
117+
if (SPC_CheckPowerDomainLowPowerRequest(MCXW7_SPC_ADDR, kSPC_PowerDomain0)) {
118+
SPC_ClearPowerDomainLowPowerRequestFlag(MCXW7_SPC_ADDR, kSPC_PowerDomain0);
119+
}
120+
if (SPC_CheckPowerDomainLowPowerRequest(MCXW7_SPC_ADDR, kSPC_PowerDomain1)) {
121+
SPC_ClearPowerDomainLowPowerRequestFlag(MCXW7_SPC_ADDR, kSPC_PowerDomain1);
122+
}
123+
if (SPC_CheckPowerDomainLowPowerRequest(MCXW7_SPC_ADDR, kSPC_PowerDomain2)) {
124+
RFMC->RF2P4GHZ_CTRL = (RFMC->RF2P4GHZ_CTRL & (~RFMC_RF2P4GHZ_CTRL_LP_MODE_MASK));
125+
RFMC->RF2P4GHZ_CTRL &= ~RFMC_RF2P4GHZ_CTRL_LP_ENTER_MASK;
126+
SPC_ClearPowerDomainLowPowerRequestFlag(MCXW7_SPC_ADDR, kSPC_PowerDomain2);
127+
}
128+
SPC_ClearLowPowerRequest(MCXW7_SPC_ADDR);
129+
}
130+
131+
/*
132+
* In active mode, all HVDs/LVDs are disabled.
133+
* DCDC regulated to 1.8V, Core LDO regulated to 1.1V;
134+
* In low power modes, all HVDs/LVDs are disabled.
135+
* Bandgap is disabled, DCDC regulated to 1.25V, Core LDO regulated to 1.05V.
136+
*/
137+
__weak void set_spc_configuration(void)
138+
{
139+
/* Disable LVDs and HVDs in Active mode. */
140+
SPC_EnableActiveModeCoreHighVoltageDetect(MCXW7_SPC_ADDR, false);
141+
SPC_EnableActiveModeCoreLowVoltageDetect(MCXW7_SPC_ADDR, false);
142+
SPC_EnableActiveModeSystemHighVoltageDetect(MCXW7_SPC_ADDR, false);
143+
SPC_EnableActiveModeSystemLowVoltageDetect(MCXW7_SPC_ADDR, false);
144+
SPC_EnableActiveModeIOHighVoltageDetect(MCXW7_SPC_ADDR, false);
145+
SPC_EnableActiveModeIOLowVoltageDetect(MCXW7_SPC_ADDR, false);
146+
while (SPC_GetBusyStatusFlag(MCXW7_SPC_ADDR)) {
147+
}
148+
149+
spc_active_mode_regulators_config_t active_mode_regulator;
150+
151+
active_mode_regulator.bandgapMode = kSPC_BandgapEnabledBufferDisabled;
152+
active_mode_regulator.lpBuff = false;
153+
/* DCDC regulate to 1.8V. */
154+
active_mode_regulator.DCDCOption.DCDCVoltage = kSPC_DCDC_SafeModeVoltage;
155+
active_mode_regulator.DCDCOption.DCDCDriveStrength = kSPC_DCDC_NormalDriveStrength;
156+
active_mode_regulator.SysLDOOption.SysLDOVoltage = kSPC_SysLDO_NormalVoltage;
157+
active_mode_regulator.SysLDOOption.SysLDODriveStrength = kSPC_SysLDO_NormalDriveStrength;
158+
/* Core LDO regulate to 1.1V. */
159+
active_mode_regulator.CoreLDOOption.CoreLDOVoltage = kSPC_CoreLDO_MidDriveVoltage;
160+
#if defined(FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS) && FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS
161+
active_mode_regulator.CoreLDOOption.CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength;
162+
#endif /* FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS */
163+
164+
SPC_SetActiveModeDCDCRegulatorConfig(MCXW7_SPC_ADDR, &active_mode_regulator.DCDCOption);
165+
166+
while (SPC_GetBusyStatusFlag(MCXW7_SPC_ADDR)) {
167+
}
168+
169+
SPC_SetActiveModeSystemLDORegulatorConfig(MCXW7_SPC_ADDR,
170+
&active_mode_regulator.SysLDOOption);
171+
172+
SPC_SetActiveModeBandgapModeConfig(MCXW7_SPC_ADDR, active_mode_regulator.bandgapMode);
173+
174+
SPC_SetActiveModeCoreLDORegulatorConfig(MCXW7_SPC_ADDR,
175+
&active_mode_regulator.CoreLDOOption);
176+
177+
SPC_EnableActiveModeCMPBandgapBuffer(MCXW7_SPC_ADDR, active_mode_regulator.lpBuff);
178+
179+
spc_lowpower_mode_regulators_config_t low_power_regulator;
180+
181+
low_power_regulator.lpIREF = false;
182+
low_power_regulator.bandgapMode = kSPC_BandgapDisabled;
183+
low_power_regulator.lpBuff = false;
184+
low_power_regulator.CoreIVS = false;
185+
low_power_regulator.DCDCOption.DCDCVoltage = kSPC_DCDC_LowUnderVoltage;
186+
low_power_regulator.DCDCOption.DCDCDriveStrength = kSPC_DCDC_LowDriveStrength;
187+
low_power_regulator.SysLDOOption.SysLDODriveStrength = kSPC_SysLDO_LowDriveStrength;
188+
low_power_regulator.CoreLDOOption.CoreLDOVoltage = kSPC_CoreLDO_MidDriveVoltage;
189+
low_power_regulator.CoreLDOOption.CoreLDODriveStrength = kSPC_CoreLDO_LowDriveStrength;
190+
191+
SPC_SetLowPowerModeRegulatorsConfig(MCXW7_SPC_ADDR, &low_power_regulator);
192+
193+
SPC_SetLowPowerWakeUpDelay(MCXW7_SPC_ADDR, 0xFFFFU);
194+
}
195+
196+
void nxp_mcxw7x_power_init(void)
197+
{
198+
set_spc_configuration();
199+
/* Enable LPTMR0 as wakeup source */
200+
NXP_ENABLE_WAKEUP_SIGNAL(WUU_WAKEUP_LPTMR_IDX);
201+
}

soc/nxp/mcx/mcxw/mcxw7xx/soc.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,10 @@ void soc_early_init_hook(void)
238238
/* Smart power switch initialization */
239239
vbat_init();
240240

241+
if (IS_ENABLED(CONFIG_PM)) {
242+
nxp_mcxw7x_power_init();
243+
}
244+
241245
/* restore interrupt state */
242246
irq_unlock(oldLevel);
243247

soc/nxp/mcx/mcxw/mcxw7xx/soc.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,14 @@
1313

1414
#define nbu_handler RF_IMU0_IRQHandler
1515

16+
#undef NXP_ENABLE_WAKEUP_SIGNAL
17+
void mcxw7xx_set_wakeup(int32_t sig);
18+
#define NXP_ENABLE_WAKEUP_SIGNAL(sig) mcxw7xx_set_wakeup(sig)
19+
20+
#if CONFIG_PM
21+
void nxp_mcxw7x_power_init(void);
22+
#else
23+
#define nxp_mcxw7x_power_init(...) do { } while (0)
24+
#endif
25+
1626
#endif /* _SOC__H_ */

0 commit comments

Comments
 (0)