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