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>
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
1637
1738static 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 );
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,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 , 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+
51103void 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 )
52117{
53118 struct onoff_manager * mgr =
54119 z_nrf_clock_control_get_onoff (CLOCK_CONTROL_NRF_SUBSYS_HF );
@@ -57,56 +122,91 @@ 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+
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+
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;
83167
84- if (IS_ENABLED (CONFIG_NRF_802154_CONSTLAT_CONTROL )) {
85- nrf_sys_event_release_global_constlat ();
168+ irq_unlock (key );
86169 }
87170
88- hfclk_is_running = false;
171+ enabled = false;
89172}
90173
91174#elif DT_NODE_HAS_STATUS (DT_NODELABEL (hfxo ), okay ) && \
92175 DT_NODE_HAS_COMPAT (DT_NODELABEL (hfxo ), nordic_nrf54h_hfxo )
93176
94- void nrf_802154_clock_hfclk_start (void )
177+ static void hfclk_start (void )
95178{
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+ }
98191
99- __ASSERT_NO_MSG (ret >= 0 );
100- (void )ret ;
192+ enabled = true;
101193}
102194
103- void nrf_802154_clock_hfclk_stop (void )
195+ static void hfclk_stop (void )
104196{
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+ }
107208
108- __ASSERT_NO_MSG (ret >= 0 );
109- (void )ret ;
209+ enabled = false;
110210}
111211
112212#endif
0 commit comments