1 /*
2 * Copyright 2023, NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <zephyr/kernel.h>
7 #include <zephyr/pm/pm.h>
8 #include <zephyr/init.h>
9 #include <zephyr/drivers/pinctrl.h>
10
11 #include "fsl_power.h"
12
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL);
15
16 /* Active mode */
17 #define POWER_MODE0 0
18 /* Idle mode */
19 #define POWER_MODE1 1
20 /* Standby mode */
21 #define POWER_MODE2 2
22 /* Sleep mode */
23 #define POWER_MODE3 3
24 /* Deep Sleep mode */
25 #define POWER_MODE4 4
26
27 #define NODE_ID DT_INST(0, nxp_pdcfg_power)
28
29 power_sleep_config_t slp_cfg;
30
31 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(pin0)) || DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(pin1))
32 pinctrl_soc_pin_t pin_cfg;
33 #endif
34
35 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(pin0))
pin0_isr(const struct device * dev)36 static void pin0_isr(const struct device *dev)
37 {
38 uint8_t level = ~(DT_ENUM_IDX(DT_NODELABEL(pin0), wakeup_level)) & 0x1;
39
40 POWER_ConfigWakeupPin(kPOWER_WakeupPin0, level);
41 NVIC_ClearPendingIRQ(DT_IRQN(DT_NODELABEL(pin0)));
42 DisableIRQ(DT_IRQN(DT_NODELABEL(pin0)));
43 POWER_DisableWakeup(DT_IRQN(DT_NODELABEL(pin0)));
44 }
45 #endif
46
47 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(pin1))
pin1_isr(const struct device * dev)48 static void pin1_isr(const struct device *dev)
49 {
50 uint8_t level = ~(DT_ENUM_IDX(DT_NODELABEL(pin1), wakeup_level)) & 0x1;
51
52 POWER_ConfigWakeupPin(kPOWER_WakeupPin1, level);
53 NVIC_ClearPendingIRQ(DT_IRQN(DT_NODELABEL(pin1)));
54 DisableIRQ(DT_IRQN(DT_NODELABEL(pin1)));
55 POWER_DisableWakeup(DT_IRQN(DT_NODELABEL(pin1)));
56 }
57 #endif
58
59 /* Invoke Low Power/System Off specific Tasks */
pm_state_set(enum pm_state state,uint8_t substate_id)60 __weak void pm_state_set(enum pm_state state, uint8_t substate_id)
61 {
62 ARG_UNUSED(substate_id);
63
64 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(pin0))
65 pin_cfg = IOMUX_GPIO_IDX(24) | IOMUX_TYPE(IOMUX_GPIO);
66 pinctrl_configure_pins(&pin_cfg, 1, 0);
67 POWER_ConfigWakeupPin(kPOWER_WakeupPin0, DT_ENUM_IDX(DT_NODELABEL(pin0), wakeup_level));
68 POWER_ClearWakeupStatus(DT_IRQN(DT_NODELABEL(pin0)));
69 NVIC_ClearPendingIRQ(DT_IRQN(DT_NODELABEL(pin0)));
70 EnableIRQ(DT_IRQN(DT_NODELABEL(pin0)));
71 POWER_EnableWakeup(DT_IRQN(DT_NODELABEL(pin0)));
72 #endif
73 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(pin1))
74 pin_cfg = IOMUX_GPIO_IDX(25) | IOMUX_TYPE(IOMUX_GPIO);
75 pinctrl_configure_pins(&pin_cfg, 1, 0);
76 POWER_ConfigWakeupPin(kPOWER_WakeupPin1, DT_ENUM_IDX(DT_NODELABEL(pin1), wakeup_level));
77 POWER_ClearWakeupStatus(DT_IRQN(DT_NODELABEL(pin1)));
78 NVIC_ClearPendingIRQ(DT_IRQN(DT_NODELABEL(pin1)));
79 EnableIRQ(DT_IRQN(DT_NODELABEL(pin1)));
80 POWER_EnableWakeup(DT_IRQN(DT_NODELABEL(pin1)));
81 #endif
82
83 /* Set PRIMASK */
84 __disable_irq();
85 /* Set BASEPRI to 0 */
86 irq_unlock(0);
87
88 switch (state) {
89 case PM_STATE_RUNTIME_IDLE:
90 POWER_SetSleepMode(POWER_MODE1);
91 __WFI();
92 break;
93 case PM_STATE_SUSPEND_TO_IDLE:
94 POWER_EnterPowerMode(POWER_MODE2, &slp_cfg);
95 break;
96 default:
97 LOG_DBG("Unsupported power state %u", state);
98 break;
99 }
100 }
101
102 /* Handle SOC specific activity after Low Power Mode Exit */
pm_state_exit_post_ops(enum pm_state state,uint8_t substate_id)103 __weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id)
104 {
105 ARG_UNUSED(state);
106 ARG_UNUSED(substate_id);
107
108 /* Clear PRIMASK */
109 __enable_irq();
110 }
111
nxp_rw6xx_power_init(void)112 void nxp_rw6xx_power_init(void)
113 {
114 uint32_t suspend_sleepconfig[5] = DT_PROP_OR(NODE_ID, deep_sleep_config, {});
115
116 slp_cfg.pm2MemPuCfg = suspend_sleepconfig[0];
117 slp_cfg.pm2AnaPuCfg = suspend_sleepconfig[1];
118 slp_cfg.clkGate = suspend_sleepconfig[2];
119 slp_cfg.memPdCfg = suspend_sleepconfig[3];
120 slp_cfg.pm3BuckCfg = suspend_sleepconfig[4];
121
122 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(pin0))
123 /* PIN 0 uses GPIO0_24, confiure the pin as GPIO */
124 pin_cfg = IOMUX_GPIO_IDX(24) | IOMUX_TYPE(IOMUX_GPIO);
125 pinctrl_configure_pins(&pin_cfg, 1, 0);
126
127 /* Initialize the settings in the PMU for this wakeup interrupt */
128 pin0_isr(NULL);
129
130 IRQ_CONNECT(DT_IRQN(DT_NODELABEL(pin0)), DT_IRQ(DT_NODELABEL(pin0), priority), pin0_isr,
131 NULL, 0);
132 #endif
133
134 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(pin1))
135 /* PIN 1 uses GPIO0_25, confiure the pin as GPIO */
136 pin_cfg = IOMUX_GPIO_IDX(25) | IOMUX_TYPE(IOMUX_GPIO);
137 pinctrl_configure_pins(&pin_cfg, 1, 0);
138
139 /* Initialize the settings in the PMU for this wakeup interrupt */
140 pin1_isr(NULL);
141
142 IRQ_CONNECT(DT_IRQN(DT_NODELABEL(pin1)), DT_IRQ(DT_NODELABEL(pin1), priority), pin1_isr,
143 NULL, 0);
144 #endif
145 }
146