13
13
#include <zephyr/kernel.h>
14
14
#include <zephyr/drivers/clock_control/nrf_clock_control.h>
15
15
#include <nrf_sys_event.h>
16
+ #include <hal/nrf_egu.h>
17
+
18
+ /**
19
+ * The implementation uses EGU to de-escalate execution context from ZLI to a regular interrupt
20
+ * to ensure that Zephyr APIs can be used safely.
21
+ *
22
+ * Both the nrf_802154_clock_hfclk_start() and nrf_802154_clock_hfclk_stop() can potentially be
23
+ * called from ZLI and non-ZLI contexts and consecutive calls are not guaranteed to be alternating.
24
+ *
25
+ * For example, it is possible that _stop() may be called multiple times in succession and the
26
+ * same thing applies to _start(). What is known however is that the last call always takes
27
+ * the precedence.
28
+ */
29
+
30
+ #define SWI_INT NRFX_CONCAT_2(NRF_EGU_INT_TRIGGERED, NRF_802154_SL_EGU_CLOCK_CHANNEL_NO)
31
+ #define SWI_TASK NRFX_CONCAT_2(NRF_EGU_TASK_TRIGGER, NRF_802154_SL_EGU_CLOCK_CHANNEL_NO)
32
+ #define SWI_EVENT NRFX_CONCAT_2(NRF_EGU_EVENT_TRIGGERED, NRF_802154_SL_EGU_CLOCK_CHANNEL_NO)
33
+
34
+ #define CLOCK_NONE 0u
35
+ #define CLOCK_REQUEST 1u
36
+ #define CLOCK_RELEASE 2u
16
37
17
38
static bool hfclk_is_running ;
39
+ static bool enabled ;
40
+ static atomic_t request = CLOCK_NONE ;
41
+
42
+ /* Forward declarations. */
43
+ static void hfclk_start (void );
44
+ static void hfclk_stop (void );
18
45
19
46
void nrf_802154_clock_init (void )
20
47
{
@@ -23,11 +50,13 @@ void nrf_802154_clock_init(void)
23
50
24
51
nrf_802154_clock_hfclk_latency_set (clock_latency_us );
25
52
#endif
53
+
54
+ nrf_egu_int_enable (NRF_802154_EGU_INSTANCE , SWI_INT );
26
55
}
27
56
28
57
void nrf_802154_clock_deinit (void )
29
58
{
30
- /* Intentionally empty. */
59
+ nrf_egu_int_disable ( NRF_802154_EGU_INSTANCE , SWI_INT );
31
60
}
32
61
33
62
bool nrf_802154_clock_hfclk_is_running (void )
@@ -47,8 +76,44 @@ static void hfclk_on_callback(struct onoff_manager *mgr,
47
76
nrf_802154_clock_hfclk_ready ();
48
77
}
49
78
50
- #if defined(CONFIG_CLOCK_CONTROL_NRF )
79
+ void nrf_802154_sl_clock_swi_irq_handler (void )
80
+ {
81
+ if (nrf_egu_event_check (NRF_802154_EGU_INSTANCE , SWI_EVENT )) {
82
+ nrf_egu_event_clear (NRF_802154_EGU_INSTANCE , SWI_EVENT );
83
+
84
+ atomic_val_t previous = atomic_set (& request , CLOCK_NONE );
85
+
86
+ __ASSERT_NO_MSG (previous == CLOCK_REQUEST || previous == CLOCK_RELEASE );
87
+
88
+ switch (previous ) {
89
+ case CLOCK_REQUEST :
90
+ hfclk_start ();
91
+ break ;
92
+
93
+ case CLOCK_RELEASE :
94
+ hfclk_stop ();
95
+ break ;
96
+
97
+ default :
98
+ break ;
99
+ }
100
+ }
101
+ }
102
+
51
103
void nrf_802154_clock_hfclk_start (void )
104
+ {
105
+ atomic_set (& request , CLOCK_REQUEST );
106
+ nrf_egu_task_trigger (NRF_802154_EGU_INSTANCE , SWI_TASK );
107
+ }
108
+
109
+ void nrf_802154_clock_hfclk_stop (void )
110
+ {
111
+ atomic_set (& request , CLOCK_RELEASE );
112
+ nrf_egu_task_trigger (NRF_802154_EGU_INSTANCE , SWI_TASK );
113
+ }
114
+
115
+ #if defined(CONFIG_CLOCK_CONTROL_NRF )
116
+ static void hfclk_start (void )
52
117
{
53
118
struct onoff_manager * mgr =
54
119
z_nrf_clock_control_get_onoff (CLOCK_CONTROL_NRF_SUBSYS_HF );
@@ -57,56 +122,91 @@ void nrf_802154_clock_hfclk_start(void)
57
122
58
123
sys_notify_init_callback (& hfclk_cli .notify , hfclk_on_callback );
59
124
60
- /*
61
- * todo: replace constlat request with PM policy API when
62
- * controlling the event latency becomes possible.
63
- */
64
- if (IS_ENABLED (CONFIG_NRF_802154_CONSTLAT_CONTROL )) {
65
- nrf_sys_event_request_global_constlat ();
125
+ if (!enabled ) {
126
+ unsigned int key = irq_lock ();
127
+
128
+ /*
129
+ * todo: replace constlat request with PM policy API when
130
+ * controlling the event latency becomes possible.
131
+ */
132
+ if (IS_ENABLED (CONFIG_NRF_802154_CONSTLAT_CONTROL )) {
133
+ nrf_sys_event_request_global_constlat ();
134
+ }
135
+
136
+ int ret = onoff_request (mgr , & hfclk_cli );
137
+
138
+ __ASSERT_NO_MSG (ret >= 0 );
139
+ (void )ret ;
140
+
141
+ irq_unlock (key );
66
142
}
67
143
68
- int ret = onoff_request (mgr , & hfclk_cli );
69
- __ASSERT_NO_MSG (ret >= 0 );
70
- (void )ret ;
144
+ enabled = true;
71
145
}
72
146
73
- void nrf_802154_clock_hfclk_stop (void )
147
+ static void hfclk_stop (void )
74
148
{
75
149
struct onoff_manager * mgr =
76
150
z_nrf_clock_control_get_onoff (CLOCK_CONTROL_NRF_SUBSYS_HF );
77
151
78
152
__ASSERT_NO_MSG (mgr != NULL );
79
153
80
- int ret = onoff_cancel_or_release (mgr , & hfclk_cli );
81
- __ASSERT_NO_MSG (ret >= 0 );
82
- (void )ret ;
154
+ if (enabled ) {
155
+ unsigned int key = irq_lock ();
156
+
157
+ int ret = onoff_cancel_or_release (mgr , & hfclk_cli );
158
+
159
+ __ASSERT_NO_MSG (ret >= 0 );
160
+ (void )ret ;
161
+
162
+ if (IS_ENABLED (CONFIG_NRF_802154_CONSTLAT_CONTROL )) {
163
+ nrf_sys_event_release_global_constlat ();
164
+ }
165
+
166
+ hfclk_is_running = false;
83
167
84
- if (IS_ENABLED (CONFIG_NRF_802154_CONSTLAT_CONTROL )) {
85
- nrf_sys_event_release_global_constlat ();
168
+ irq_unlock (key );
86
169
}
87
170
88
- hfclk_is_running = false;
171
+ enabled = false;
89
172
}
90
173
91
174
#elif DT_NODE_HAS_STATUS (DT_NODELABEL (hfxo ), okay ) && \
92
175
DT_NODE_HAS_COMPAT (DT_NODELABEL (hfxo ), nordic_nrf54h_hfxo )
93
176
94
- void nrf_802154_clock_hfclk_start (void )
177
+ static void hfclk_start (void )
95
178
{
96
- sys_notify_init_callback (& hfclk_cli .notify , hfclk_on_callback );
97
- int ret = nrf_clock_control_request (DEVICE_DT_GET (DT_NODELABEL (hfxo )), NULL , & hfclk_cli );
179
+ if (!enabled ) {
180
+ unsigned int key = irq_lock ();
181
+
182
+ sys_notify_init_callback (& hfclk_cli .notify , hfclk_on_callback );
183
+ int ret = nrf_clock_control_request (DEVICE_DT_GET (DT_NODELABEL (hfxo )),
184
+ NULL , & hfclk_cli );
185
+
186
+ __ASSERT_NO_MSG (ret >= 0 );
187
+ (void )ret ;
188
+
189
+ irq_unlock (key );
190
+ }
98
191
99
- __ASSERT_NO_MSG (ret >= 0 );
100
- (void )ret ;
192
+ enabled = true;
101
193
}
102
194
103
- void nrf_802154_clock_hfclk_stop (void )
195
+ static void hfclk_stop (void )
104
196
{
105
- int ret = nrf_clock_control_cancel_or_release (DEVICE_DT_GET (DT_NODELABEL (hfxo )),
106
- NULL , & hfclk_cli );
197
+ if (enabled ) {
198
+ unsigned int key = irq_lock ();
199
+
200
+ int ret = nrf_clock_control_cancel_or_release (DEVICE_DT_GET (DT_NODELABEL (hfxo )),
201
+ NULL , & hfclk_cli );
202
+
203
+ __ASSERT_NO_MSG (ret >= 0 );
204
+ (void )ret ;
205
+
206
+ irq_unlock (key );
207
+ }
107
208
108
- __ASSERT_NO_MSG (ret >= 0 );
109
- (void )ret ;
209
+ enabled = false;
110
210
}
111
211
112
212
#endif
0 commit comments