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 NTF_INT NRFX_CONCAT_2(NRF_EGU_INT_TRIGGERED, NRF_802154_SL_EGU_CLOCK_CHANNEL_NO)
31+ #define NTF_TASK NRFX_CONCAT_2(NRF_EGU_TASK_TRIGGER, NRF_802154_SL_EGU_CLOCK_CHANNEL_NO)
32+ #define NTF_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 , NTF_INT );
2655}
2756
2857void nrf_802154_clock_deinit (void )
2958{
30- /* Intentionally empty. */
59+ nrf_egu_int_disable ( NRF_802154_EGU_INSTANCE , NTF_INT );
3160}
3261
3362bool nrf_802154_clock_hfclk_is_running (void )
@@ -47,8 +76,44 @@ 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 , NTF_EVENT ))
82+ {
83+ nrf_egu_event_clear (NRF_802154_EGU_INSTANCE , NTF_EVENT );
84+
85+ atomic_val_t previous = atomic_set (& request , CLOCK_NONE );
86+
87+ switch (previous ) {
88+ case CLOCK_REQUEST :
89+ hfclk_start ();
90+ break ;
91+
92+ case CLOCK_RELEASE :
93+ hfclk_stop ();
94+ break ;
95+
96+ default :
97+ __ASSERT_NO_MSG (false);
98+ break ;
99+ }
100+ }
101+ }
102+
51103void nrf_802154_clock_hfclk_start (void )
104+ {
105+ atomic_set (& request , CLOCK_REQUEST );
106+ nrf_egu_task_trigger (NRF_802154_EGU_INSTANCE , NTF_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 , NTF_TASK );
113+ }
114+
115+ #if defined(CONFIG_CLOCK_CONTROL_NRF )
116+ static void hfclk_start (void )
52117{
53118 struct onoff_manager * mgr =
54119 z_nrf_clock_control_get_onoff (CLOCK_CONTROL_NRF_SUBSYS_HF );
@@ -57,56 +122,88 @@ void nrf_802154_clock_hfclk_start(void)
57122
58123 sys_notify_init_callback (& hfclk_cli .notify , hfclk_on_callback );
59124
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+ __ASSERT_NO_MSG (ret >= 0 );
138+ (void )ret ;
139+
140+ irq_unlock (key );
66141 }
67142
68- int ret = onoff_request (mgr , & hfclk_cli );
69- __ASSERT_NO_MSG (ret >= 0 );
70- (void )ret ;
143+ enabled = true;
71144}
72145
73- void nrf_802154_clock_hfclk_stop (void )
146+ static void hfclk_stop (void )
74147{
75148 struct onoff_manager * mgr =
76- z_nrf_clock_control_get_onoff (CLOCK_CONTROL_NRF_SUBSYS_HF );
149+ z_nrf_clock_control_get_onoff (CLOCK_CONTROL_NRF_SUBSYS_HF );
77150
78151 __ASSERT_NO_MSG (mgr != NULL );
79152
80- int ret = onoff_cancel_or_release (mgr , & hfclk_cli );
81- __ASSERT_NO_MSG (ret >= 0 );
82- (void )ret ;
153+ if (enabled ) {
154+ unsigned int key = irq_lock ();
155+
156+ int ret = onoff_cancel_or_release (mgr , & hfclk_cli );
157+ __ASSERT_NO_MSG (ret >= 0 );
158+ (void )ret ;
159+
160+ if (IS_ENABLED (CONFIG_NRF_802154_CONSTLAT_CONTROL )) {
161+ nrf_sys_event_release_global_constlat ();
162+ }
163+
164+ hfclk_is_running = false;
83165
84- if (IS_ENABLED (CONFIG_NRF_802154_CONSTLAT_CONTROL )) {
85- nrf_sys_event_release_global_constlat ();
166+ irq_unlock (key );
86167 }
87168
88- hfclk_is_running = false;
169+ enabled = false;
89170}
90171
91172#elif DT_NODE_HAS_STATUS (DT_NODELABEL (hfxo ), okay ) && \
92173 DT_NODE_HAS_COMPAT (DT_NODELABEL (hfxo ), nordic_nrf54h_hfxo )
93174
94- void nrf_802154_clock_hfclk_start (void )
175+ static void hfclk_start (void )
95176{
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 );
177+ if (!enabled ) {
178+ unsigned int key = irq_lock ();
179+
180+ sys_notify_init_callback (& hfclk_cli .notify , hfclk_on_callback );
181+ int ret = nrf_clock_control_request (DEVICE_DT_GET (DT_NODELABEL (hfxo )), NULL , & hfclk_cli );
182+
183+ __ASSERT_NO_MSG (ret >= 0 );
184+ (void )ret ;
185+
186+ irq_unlock (key );
187+ }
98188
99- __ASSERT_NO_MSG (ret >= 0 );
100- (void )ret ;
189+ enabled = true;
101190}
102191
103- void nrf_802154_clock_hfclk_stop (void )
192+ static void hfclk_stop (void )
104193{
105- int ret = nrf_clock_control_cancel_or_release (DEVICE_DT_GET (DT_NODELABEL (hfxo )),
106- NULL , & hfclk_cli );
194+ if (enabled ) {
195+ unsigned int key = irq_lock ();
196+
197+ int ret = nrf_clock_control_cancel_or_release (DEVICE_DT_GET (DT_NODELABEL (hfxo )),
198+ NULL , & hfclk_cli );
199+
200+ __ASSERT_NO_MSG (ret >= 0 );
201+ (void )ret ;
202+
203+ irq_unlock (key );
204+ }
107205
108- __ASSERT_NO_MSG (ret >= 0 );
109- (void )ret ;
206+ enabled = false;
110207}
111208
112209#endif
0 commit comments