1313#include <zephyr/kernel.h>
1414#include <zephyr/drivers/clock_control/nrf_clock_control.h>
1515#include <nrf_sys_event.h>
16+ #include <hal/nrf_egu.h>
1617
17- static bool hfclk_is_running ;
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
37+
38+ static bool hfclk_is_running = false;
39+ static bool enabled = false;
40+ static atomic_t request = CLOCK_NONE ;
41+
42+ /* Forward declarations. */
43+ static void hfclk_start (void );
44+ static void hfclk_stop (void );
1845
1946void nrf_802154_clock_init (void )
2047{
@@ -23,11 +50,13 @@ void nrf_802154_clock_init(void)
2350
2451 nrf_802154_clock_hfclk_latency_set (clock_latency_us );
2552#endif
53+
54+ nrf_egu_int_enable (NRF_802154_EGU_INSTANCE , SWI_INT );
2655}
2756
2857void nrf_802154_clock_deinit (void )
2958{
30- /* Intentionally empty. */
59+ nrf_egu_int_disable ( NRF_802154_EGU_INSTANCE , SWI_INT );
3160}
3261
3362bool nrf_802154_clock_hfclk_is_running (void )
@@ -47,8 +76,45 @@ static void hfclk_on_callback(struct onoff_manager *mgr,
4776 nrf_802154_clock_hfclk_ready ();
4877}
4978
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+ {
83+ nrf_egu_event_clear (NRF_802154_EGU_INSTANCE , SWI_EVENT );
84+
85+ atomic_val_t previous = atomic_set (& request , CLOCK_NONE );
86+
87+ __ASSERT_NO_MSG (previous == CLOCK_REQUEST || previous == CLOCK_RELEASE );
88+
89+ switch (previous ) {
90+ case CLOCK_REQUEST :
91+ hfclk_start ();
92+ break ;
93+
94+ case CLOCK_RELEASE :
95+ hfclk_stop ();
96+ break ;
97+
98+ default :
99+ break ;
100+ }
101+ }
102+ }
103+
51104void nrf_802154_clock_hfclk_start (void )
105+ {
106+ atomic_set (& request , CLOCK_REQUEST );
107+ nrf_egu_task_trigger (NRF_802154_EGU_INSTANCE , SWI_TASK );
108+ }
109+
110+ void nrf_802154_clock_hfclk_stop (void )
111+ {
112+ atomic_set (& request , CLOCK_RELEASE );
113+ nrf_egu_task_trigger (NRF_802154_EGU_INSTANCE , SWI_TASK );
114+ }
115+
116+ #if defined(CONFIG_CLOCK_CONTROL_NRF )
117+ static void hfclk_start (void )
52118{
53119 struct onoff_manager * mgr =
54120 z_nrf_clock_control_get_onoff (CLOCK_CONTROL_NRF_SUBSYS_HF );
@@ -57,56 +123,88 @@ void nrf_802154_clock_hfclk_start(void)
57123
58124 sys_notify_init_callback (& hfclk_cli .notify , hfclk_on_callback );
59125
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 ();
126+ if (!enabled ) {
127+ unsigned int key = irq_lock ();
128+
129+ /*
130+ * todo: replace constlat request with PM policy API when
131+ * controlling the event latency becomes possible.
132+ */
133+ if (IS_ENABLED (CONFIG_NRF_802154_CONSTLAT_CONTROL )) {
134+ nrf_sys_event_request_global_constlat ();
135+ }
136+
137+ int ret = onoff_request (mgr , & hfclk_cli );
138+ __ASSERT_NO_MSG (ret >= 0 );
139+ (void )ret ;
140+
141+ irq_unlock (key );
66142 }
67143
68- int ret = onoff_request (mgr , & hfclk_cli );
69- __ASSERT_NO_MSG (ret >= 0 );
70- (void )ret ;
144+ enabled = true;
71145}
72146
73- void nrf_802154_clock_hfclk_stop (void )
147+ static void hfclk_stop (void )
74148{
75149 struct onoff_manager * mgr =
76150 z_nrf_clock_control_get_onoff (CLOCK_CONTROL_NRF_SUBSYS_HF );
77151
78152 __ASSERT_NO_MSG (mgr != NULL );
79153
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+ __ASSERT_NO_MSG (ret >= 0 );
159+ (void )ret ;
160+
161+ if (IS_ENABLED (CONFIG_NRF_802154_CONSTLAT_CONTROL )) {
162+ nrf_sys_event_release_global_constlat ();
163+ }
164+
165+ hfclk_is_running = false;
83166
84- if (IS_ENABLED (CONFIG_NRF_802154_CONSTLAT_CONTROL )) {
85- nrf_sys_event_release_global_constlat ();
167+ irq_unlock (key );
86168 }
87169
88- hfclk_is_running = false;
170+ enabled = false;
89171}
90172
91173#elif DT_NODE_HAS_STATUS (DT_NODELABEL (hfxo ), okay ) && \
92174 DT_NODE_HAS_COMPAT (DT_NODELABEL (hfxo ), nordic_nrf54h_hfxo )
93175
94- void nrf_802154_clock_hfclk_start (void )
176+ static void hfclk_start (void )
95177{
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 );
178+ if (!enabled ) {
179+ unsigned int key = irq_lock ();
180+
181+ sys_notify_init_callback (& hfclk_cli .notify , hfclk_on_callback );
182+ int ret = nrf_clock_control_request (DEVICE_DT_GET (DT_NODELABEL (hfxo )), NULL , & hfclk_cli );
183+
184+ __ASSERT_NO_MSG (ret >= 0 );
185+ (void )ret ;
186+
187+ irq_unlock (key );
188+ }
98189
99- __ASSERT_NO_MSG (ret >= 0 );
100- (void )ret ;
190+ enabled = true;
101191}
102192
103- void nrf_802154_clock_hfclk_stop (void )
193+ static void hfclk_stop (void )
104194{
105- int ret = nrf_clock_control_cancel_or_release (DEVICE_DT_GET (DT_NODELABEL (hfxo )),
106- NULL , & hfclk_cli );
195+ if (enabled ) {
196+ unsigned int key = irq_lock ();
197+
198+ int ret = nrf_clock_control_cancel_or_release (DEVICE_DT_GET (DT_NODELABEL (hfxo )),
199+ NULL , & hfclk_cli );
200+
201+ __ASSERT_NO_MSG (ret >= 0 );
202+ (void )ret ;
203+
204+ irq_unlock (key );
205+ }
107206
108- __ASSERT_NO_MSG (ret >= 0 );
109- (void )ret ;
207+ enabled = false;
110208}
111209
112210#endif
0 commit comments