1 /*
2  * Copyright (c) 2017 Oticon A/S
3  * Copyright (c) 2023 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 /*
9  * CLOCK - Clock control
10  * https://infocenter.nordicsemi.com/topic/ps_nrf52833/clock.html?cp=5_1_0_4_3
11  * https://infocenter.nordicsemi.com/topic/ps_nrf5340/chapters/clock/doc/clock.html?cp=4_0_0_3_10
12  * POWER - POWER control
13  * https://infocenter.nordicsemi.com/topic/ps_nrf52833/power.html?cp=5_1_0_4_2
14  * https://infocenter.nordicsemi.com/topic/ps_nrf5340/chapters/power/doc/power.html?cp=4_0_0_3_5
15  * RESET - RESET control
16  * https://infocenter.nordicsemi.com/topic/ps_nrf5340/chapters/reset/doc/reset.html?cp=4_0_0_3_9
17  *
18  * Notes POWER / RESET:
19  * 1. The POWER and (nrf5340) RESET peripherals are just stubs with no functionality
20  *
21  * Note: CLOCK:
22  * 1. The clocks are ready in 1 delta cycle (i.e. almost instantaneously),
23  *    HFXODEBOUNCE and LFXODEBOUNCE are ignored together with the XTALs
24  *    power up times
25  *
26  * 2. The models do not check the requirement of having the HFXO clock running to be
27  *    able to run the radio. The radio models will run just fine without it.
28  *
29  * 3. The LFRC oscillator calibration TASK_CAL finishes in 1 delta cycle.
30  *    The models do not do anything during the LFRC calibration (apart from
31  *    generating the done event/interrupt).
32  *
33  * 4. We assume the 32.768 KHz clock does not drift relative to the 64MHz one.
34  *    This would only be the case if they had the same source or there was a tracking
35  *    and adjustment loop of one based on the other.
36  *
37  * 5. LFCLKSRC is ignored (beyond copying LFCLKSRC.SRC to LFCLKSRCCOPY and LFCLKSTAT)
38  *
39  * 6. TRACECONFIG is ignored
40  *
41  * 7. The calibration timer timing is exact: it will take exactly CTIV*0.25s to
42  *    finish.
43  *
44  * 8. After TASK_CTSTART EVENTS_CTSTARTED is raised immediately,
45  *    After TASK_CTSTOP EVENTS_CTSTOPPED is raised immediately.
46  *
47  * 9. For the nrf5340 CLOCK. Almost all new functionality is missing
48  *     (beyond connection to the DPPI, and having one instance per core)
49  *    * The extra app core clocks are not implemented yet (Audio or 192M)
50  *    * Automatic HW clock requests are not implemented yet
51  */
52 
53 #include <string.h>
54 #include <stdint.h>
55 #include "NHW_common_types.h"
56 #include "NHW_config.h"
57 #include "NHW_peri_types.h"
58 #include "NHW_CLOCK.h"
59 #include "nsi_hw_scheduler.h"
60 #include "NHW_xPPI.h"
61 #include "NHW_RTC.h"
62 #include "irq_ctrl.h"
63 #include "bs_tracing.h"
64 #include "bs_utils.h"
65 #include "nsi_tasks.h"
66 #include "nsi_hws_models_if.h"
67 
68 enum clock_states {Stopped = 0, Starting, Started, Stopping};
69 
70 struct clkpwr_status {
71   NRF_CLOCK_Type *CLOCK_regs;
72   NRF_POWER_Type *POWER_regs;
73 #if (NHW_CLKPWR_HAS_RESET)
74   NRF_RESET_Type *RESET_regs;
75 #endif
76 
77   uint inst;
78 
79   uint32_t INTEN; //interrupt enable
80 
81   bs_time_t Timer_CLOCK_LF;
82   bs_time_t Timer_CLOCK_HF;
83   bs_time_t Timer_LF_cal;
84   bs_time_t Timer_caltimer;
85 
86   enum clock_states HF_Clock_state;
87   enum clock_states LF_Clock_state;
88   enum clock_states LF_cal_state;
89   enum clock_states caltimer_state;
90 
91 #if (NHW_HAS_DPPI)
92   uint dppi_map;   //To which DPPI instance are this CLOCK/POWER subscribe&publish ports connected to
93   //Which of the subscription ports are currently connected, and to which channel:
94   struct nhw_subsc_mem subscribed_HFCLKSTART;
95   struct nhw_subsc_mem subscribed_HFCLKSTOP;
96   struct nhw_subsc_mem subscribed_LFCLKSTART;
97   struct nhw_subsc_mem subscribed_LFCLKSTOP;
98   struct nhw_subsc_mem subscribed_CAL;
99   struct nhw_subsc_mem subscribed_HFCLKAUDIOSTART;
100   struct nhw_subsc_mem subscribed_HFCLKAUDIOSTOP;
101   struct nhw_subsc_mem subscribed_HFCLK192MSTART;
102   struct nhw_subsc_mem subscribed_HFCLK192MSTOP;
103 #endif
104 };
105 
106 static bs_time_t Timer_PWRCLK = TIME_NEVER;
107 static struct clkpwr_status nhw_clkpwr_st[NHW_CLKPWR_TOTAL_INST];
108 union NRF_CLKPWR_Type NRF_CLKPWR_regs[NHW_CLKPWR_TOTAL_INST];
109 
110 NRF_CLOCK_Type *NRF_CLOCK_regs[NHW_CLKPWR_TOTAL_INST];
111 NRF_POWER_Type *NRF_POWER_regs[NHW_CLKPWR_TOTAL_INST];
112 #if (NHW_CLKPWR_HAS_RESET)
113 NRF_RESET_Type *NRF_RESET_regs[NHW_CLKPWR_TOTAL_INST];
114 #endif /* (NHW_CLKPWR_HAS_RESET) */
115 
nhw_clock_update_master_timer(void)116 static void nhw_clock_update_master_timer(void) {
117 
118   Timer_PWRCLK = TIME_NEVER;
119 
120   for (int i = 0; i < NHW_CLKPWR_TOTAL_INST; i++) {
121     struct clkpwr_status * c_el = &nhw_clkpwr_st[i];
122 
123     bs_time_t t1 = BS_MIN(c_el->Timer_CLOCK_HF, c_el->Timer_CLOCK_LF);
124     bs_time_t t2 = BS_MIN(c_el->Timer_LF_cal, c_el->Timer_caltimer);
125 
126     bs_time_t el_min = BS_MIN(t1, t2);
127     if (el_min < Timer_PWRCLK) {
128       Timer_PWRCLK = el_min;
129     }
130   }
131 
132   nsi_hws_find_next_event();
133 }
134 
nhw_clock_init(void)135 static void nhw_clock_init(void) {
136 #if (NHW_HAS_DPPI)
137   /* Mapping of peripheral instance to DPPI instance */
138   uint nhw_clkpwr_dppi_map[NHW_CLKPWR_TOTAL_INST] = NHW_CLKPWR_DPPI_MAP;
139 #endif
140 
141   memset(NRF_CLKPWR_regs, 0, sizeof(NRF_CLKPWR_regs));
142 
143   for (int i = 0; i < NHW_CLKPWR_TOTAL_INST; i++) {
144     struct clkpwr_status * c_el = &nhw_clkpwr_st[i];
145 
146     c_el->inst = i;
147 
148     NRF_CLOCK_regs[i] = (NRF_CLOCK_Type *)&NRF_CLKPWR_regs[i];
149     c_el->CLOCK_regs = (NRF_CLOCK_Type *)&NRF_CLKPWR_regs[i];
150     NRF_POWER_regs[i] = (NRF_POWER_Type *)&NRF_CLKPWR_regs[i];
151     c_el->POWER_regs = (NRF_POWER_Type *)&NRF_CLKPWR_regs[i];
152 #if (NHW_CLKPWR_HAS_RESET)
153     NRF_RESET_regs[i] = (NRF_RESET_Type *)&NRF_CLKPWR_regs[i];
154     c_el->RESET_regs = (NRF_RESET_Type *)&NRF_CLKPWR_regs[i];
155 #endif /* (NHW_CLKPWR_HAS_RESET) */
156 
157     c_el->Timer_CLOCK_LF = TIME_NEVER;
158     c_el->Timer_CLOCK_HF = TIME_NEVER;
159     c_el->Timer_LF_cal   = TIME_NEVER;
160     c_el->Timer_caltimer = TIME_NEVER;
161 
162     c_el->HF_Clock_state = Stopped;
163     c_el->LF_Clock_state = Stopped;
164     c_el->LF_cal_state   = Stopped;
165     c_el->caltimer_state = Stopped;
166 #if (NHW_HAS_DPPI)
167     c_el->dppi_map = nhw_clkpwr_dppi_map[i];
168 #endif
169 
170 #if defined(CLOCK_HFXODEBOUNCE_HFXODEBOUNCE_Pos)
171     NRF_CLOCK_regs[i]->HFXODEBOUNCE = 0x00000010;
172 #endif
173   }
174 }
175 
176 NSI_TASK(nhw_clock_init, HW_INIT, 100);
177 
nhw_pwrclk_eval_interrupt(int inst)178 static void nhw_pwrclk_eval_interrupt(int inst) {
179   /* Mapping of peripheral instance to {int controller instance, int number} */
180   static struct nhw_irq_mapping nhw_clock_irq_map[NHW_CLKPWR_TOTAL_INST] = NHW_CLKPWR_INT_MAP;
181   static bool clock_int_line[NHW_CLKPWR_TOTAL_INST]; /* Is the CLOCK currently driving its interrupt line high */
182   bool new_int_line = false;
183 
184   struct clkpwr_status *this = &nhw_clkpwr_st[inst];
185 
186 #define check_interrupt(x) \
187 	if (NRF_CLOCK_regs[inst]->EVENTS_##x \
188 	    && (this->INTEN & CLOCK_INTENCLR_##x##_Msk)){ \
189 	  new_int_line = true; \
190 	} \
191 
192   check_interrupt(HFCLKSTARTED);
193   check_interrupt(LFCLKSTARTED);
194   check_interrupt(DONE);
195 #if (NHW_CLKPWR_HAS_CALTIMER)
196   check_interrupt(CTTO);
197   check_interrupt(CTSTARTED);
198   check_interrupt(CTSTOPPED);
199 #endif /* NHW_CLKPWR_HAS_CALTIMER */
200 #if (NHW_CLKPWR_HAS_HFCLKAUDIOCLK)
201   check_interrupt(HFCLKAUDIOSTARTED);
202 #endif
203 #if (NHW_CLKPWR_HAS_HFCLK192MCLK)
204   check_interrupt(HFCLK192MSTARTED);
205 #endif
206 
207   if (clock_int_line[inst] == false && new_int_line == true) {
208     clock_int_line[inst] = true;
209     hw_irq_ctrl_raise_level_irq_line(nhw_clock_irq_map[inst].cntl_inst,
210                                       nhw_clock_irq_map[inst].int_nbr);
211   } else if (clock_int_line[inst] == true && new_int_line == false) {
212     clock_int_line[inst] = false;
213     hw_irq_ctrl_lower_level_irq_line(nhw_clock_irq_map[inst].cntl_inst,
214                                       nhw_clock_irq_map[inst].int_nbr);
215   }
216 }
217 
218 #if (NHW_HAS_PPI)
219 #define nhw_clock_signal_handler(x)         \
220   static void nhw_clock_signal_##x(int i) { \
221     NRF_CLOCK_regs[i]->EVENTS_##x = 1;     \
222     nhw_pwrclk_eval_interrupt(i);           \
223     nrf_ppi_event(CLOCK_EVENTS_##x);       \
224   }
225 #else
226 #define nhw_clock_signal_handler(x)         \
227   static void nhw_clock_signal_##x(int i) { \
228     NRF_CLOCK_regs[i]->EVENTS_##x = 1;     \
229     nhw_pwrclk_eval_interrupt(i);           \
230     nhw_dppi_event_signal_if(nhw_clkpwr_st[i].dppi_map,      \
231                              NRF_CLOCK_regs[i]->PUBLISH_##x);\
232   }
233 #endif
234 
235 /*
236  * CLOCK POWER & RESET do not have shortcuts, so all we need to do
237  * is set the corresponding event and evaluate the interrupt.
238  */
239 nhw_clock_signal_handler(HFCLKSTARTED)
nhw_clock_signal_handler(LFCLKSTARTED)240 nhw_clock_signal_handler(LFCLKSTARTED)
241 nhw_clock_signal_handler(DONE)
242 #if (NHW_CLKPWR_HAS_CALTIMER)
243 nhw_clock_signal_handler(CTTO)
244 nhw_clock_signal_handler(CTSTARTED)
245 nhw_clock_signal_handler(CTSTOPPED)
246 #endif /* NHW_CLKPWR_HAS_CALTIMER */
247 #if (NHW_CLKPWR_HAS_HFCLKAUDIOCLK)
248 //nhw_clock_signal_handler(HFCLKAUDIOSTARTED)
249 #endif
250 #if (NHW_CLKPWR_HAS_HFCLK192MCLK)
251 //nhw_clock_signal_handler(HFCLK192MSTARTED)
252 #endif
253 
254 void nhw_clock_TASKS_LFCLKSTART(uint inst) {
255   struct clkpwr_status *this = &nhw_clkpwr_st[inst];
256   NRF_CLOCK_Type *CLOCK_regs = this->CLOCK_regs;
257 
258   CLOCK_regs->LFCLKSRCCOPY = CLOCK_regs->LFCLKSRC & CLOCK_LFCLKSRC_SRC_Msk;
259   CLOCK_regs->LFCLKRUN = CLOCK_LFCLKRUN_STATUS_Msk;
260   this->LF_Clock_state = Starting;
261 
262   this->Timer_CLOCK_LF = nsi_hws_get_time(); //we assume the clock is ready in 1 delta
263   nhw_clock_update_master_timer();
264 }
265 
nhw_clock_TASKS_LFCLKSTOP(uint inst)266 void nhw_clock_TASKS_LFCLKSTOP(uint inst) {
267   // There is no effect of turning the clock off that is actually modeled
268   if ((NRF_CLOCK_regs[inst]->LFCLKSTAT & CLOCK_LFCLKRUN_STATUS_Msk) == 0) { /* LCOV_EXCL_START */
269     bs_trace_info_line(3, "%s(%u) Triggered LF oscillator stop while the clock was not running "
270                           "(the model does not have a problem with this, but this is against "
271                           "the spec)\n", __func__, inst);
272   } /* LCOV_EXCL_STOP */
273 
274   struct clkpwr_status *this = &nhw_clkpwr_st[inst];
275 
276   if ((this->LF_Clock_state == Started) || (this->LF_Clock_state == Starting)) {
277     NRF_CLOCK_regs[inst]->LFCLKRUN = 0;
278     this->LF_Clock_state = Stopping;
279     this->Timer_CLOCK_LF = nsi_hws_get_time(); //we assume the clock is stopped in 1 delta
280     nhw_clock_update_master_timer();
281   }
282 }
283 
nhw_clock_TASKS_HFCLKSTART(uint inst)284 void nhw_clock_TASKS_HFCLKSTART(uint inst) {
285   struct clkpwr_status *this = &nhw_clkpwr_st[inst];
286 
287   if ((this->HF_Clock_state == Stopped ) || (this->HF_Clock_state == Stopping)) {
288     this->HF_Clock_state = Starting;
289     NRF_CLOCK_regs[inst]->HFCLKRUN = CLOCK_HFCLKRUN_STATUS_Msk;
290     this->Timer_CLOCK_HF = nsi_hws_get_time(); //we assume the clock is ready in 1 delta
291     nhw_clock_update_master_timer();
292   }
293 }
294 
nhw_clock_TASKS_HFCLKSTOP(uint inst)295 void nhw_clock_TASKS_HFCLKSTOP(uint inst) {
296   struct clkpwr_status *this = &nhw_clkpwr_st[inst];
297 
298   if ((this->HF_Clock_state == Started) || (this->HF_Clock_state == Starting)) {
299     NRF_CLOCK_regs[inst]->HFCLKRUN = 0;
300     this->HF_Clock_state = Stopping;
301     this->Timer_CLOCK_HF = nsi_hws_get_time(); //we assume the clock is stopped in 1 delta
302     nhw_clock_update_master_timer();
303   }
304 }
305 
306 #define HAS_CLOCK_CHECK(CLK_NAME)                                                 \
307 	  bool has_this_clock[NHW_CLKPWR_TOTAL_INST] = NHW_CLKPWR_HAS_##CLK_NAME##CLK_I;\
308 	  if (!has_this_clock[inst]) {                                                  \
309 	    bs_trace_error_time_line("CLOCK#%i does not have "                          \
310          "this type of clock (" #CLK_NAME ")", inst);                             \
311 	  }
312 
nhw_clock_TASKS_HFCLKAUDIOSTART(uint inst)313 void nhw_clock_TASKS_HFCLKAUDIOSTART(uint inst) {
314   HAS_CLOCK_CHECK(HFCLKAUDIO);
315 
316   bs_trace_warning_time_line("%s not yet implemented\n", __func__);
317 }
318 
nhw_clock_TASKS_HFCLKAUDIOSTOP(uint inst)319 void nhw_clock_TASKS_HFCLKAUDIOSTOP(uint inst) {
320   HAS_CLOCK_CHECK(HFCLKAUDIO);
321 
322   bs_trace_warning_time_line("%s not yet implemented\n", __func__);
323 }
324 
nhw_clock_TASKS_HFCLK192MSTART(uint inst)325 void nhw_clock_TASKS_HFCLK192MSTART(uint inst) {
326   HAS_CLOCK_CHECK(HFCLK192M);
327 
328   bs_trace_warning_time_line("%s not yet implemented\n", __func__);
329 }
330 
nhw_clock_TASKS_HFCLK192MSTOP(uint inst)331 void nhw_clock_TASKS_HFCLK192MSTOP(uint inst) {
332   HAS_CLOCK_CHECK(HFCLK192M);
333 
334   bs_trace_warning_time_line("%s not yet implemented\n", __func__);
335 }
336 
337 
nhw_clock_TASKS_CAL(uint inst)338 void nhw_clock_TASKS_CAL(uint inst) {
339   struct clkpwr_status *this = &nhw_clkpwr_st[inst];
340 
341   if (this->HF_Clock_state != Started) { /* LCOV_EXCL_START */
342     bs_trace_warning_line("%s(%u): Triggered RC oscillator calibration with the HF CLK stopped "
343                           "(the model does not have a problem with this, but this is against "
344                           "the spec)\n", __func__, inst);
345   } /* LCOV_EXCL_STOP */
346 
347   this->LF_cal_state = Started; //We don't check for re-triggers, as we are going to be done right away
348   this->Timer_LF_cal = nsi_hws_get_time(); //we assume the calibration is done in 1 delta
349   nhw_clock_update_master_timer();
350 }
351 
352 #if (NHW_CLKPWR_HAS_CALTIMER)
nhw_clock_TASKS_CTSTART(uint inst)353 void nhw_clock_TASKS_CTSTART(uint inst) {
354   struct clkpwr_status *this = &nhw_clkpwr_st[inst];
355 
356   if ( this->caltimer_state == Started ) { /* LCOV_EXCL_START */
357     bs_trace_warning_line("%s(%u) Calibration timer was already running. "
358                           "Raising CTSTARTED event immediately. "
359                           "Timeout is not affected.\n", __func__, inst);
360   } else {  /* LCOV_EXCL_STOP */
361     this->caltimer_state = Started;
362     this->Timer_caltimer = nsi_hws_get_time() + (bs_time_t)NRF_CLOCK_regs[inst]->CTIV * 250000;
363     nhw_clock_update_master_timer();
364   }
365   nhw_clock_signal_CTSTARTED(inst);
366 }
367 
nhw_clock_TASKS_CTSTOP(uint inst)368 void nhw_clock_TASKS_CTSTOP(uint inst) {
369   struct clkpwr_status *this = &nhw_clkpwr_st[inst];
370 
371   if ( this->caltimer_state == Stopped ) { /* LCOV_EXCL_START */
372     bs_trace_info_line(3, "%s(%u) Calibration timer was already stopped. "
373                           "Raising CTSTOPPED event immediately.\n", __func__, inst);
374   } /* LCOV_EXCL_STOP */
375   this->caltimer_state = Stopped;
376   this->Timer_caltimer = TIME_NEVER;
377   nhw_clock_update_master_timer();
378   nhw_clock_signal_CTSTOPPED(inst);
379 }
380 #endif /* NHW_CLKPWR_HAS_CALTIMER */
381 
nhw_clock_regw_sideeffects_INTENSET(uint i)382 void nhw_clock_regw_sideeffects_INTENSET(uint i) {
383   if (NRF_CLOCK_regs[i]->INTENSET) { /* LCOV_EXCL_BR_LINE */
384     struct clkpwr_status *this = &nhw_clkpwr_st[i];
385 
386     this->INTEN |= NRF_CLOCK_regs[i]->INTENSET;
387     NRF_CLOCK_regs[i]->INTENSET = this->INTEN;
388     nhw_pwrclk_eval_interrupt(i);
389   }
390 }
391 
nhw_clock_regw_sideeffects_INTENCLR(uint i)392 void nhw_clock_regw_sideeffects_INTENCLR(uint i) {
393   if (NRF_CLOCK_regs[i]->INTENCLR) { /* LCOV_EXCL_BR_LINE */
394     struct clkpwr_status *this = &nhw_clkpwr_st[i];
395 
396     this->INTEN  &= ~NRF_CLOCK_regs[i]->INTENCLR;
397     NRF_CLOCK_regs[i]->INTENSET = this->INTEN;
398     NRF_CLOCK_regs[i]->INTENCLR = 0;
399     nhw_pwrclk_eval_interrupt(i);
400   }
401 }
402 
403 #define nhw_clock_regw_sideeffects_TASKS_(x)                   \
404   void nhw_clock_regw_sideeffects_TASKS_##x(uint i) {          \
405     if (NRF_CLOCK_regs[i]->TASKS_##x) { /* LCOV_EXCL_BR_LINE */\
406       NRF_CLOCK_regs[i]->TASKS_##x = 0;                        \
407       nhw_clock_TASKS_##x(i);                                  \
408     }                                                          \
409   }
410 
411 nhw_clock_regw_sideeffects_TASKS_(LFCLKSTART)
nhw_clock_regw_sideeffects_TASKS_(LFCLKSTOP)412 nhw_clock_regw_sideeffects_TASKS_(LFCLKSTOP)
413 nhw_clock_regw_sideeffects_TASKS_(HFCLKSTART)
414 nhw_clock_regw_sideeffects_TASKS_(HFCLKSTOP)
415 
416 #if (NHW_CLKPWR_HAS_HFCLKAUDIOCLK)
417 nhw_clock_regw_sideeffects_TASKS_(HFCLKAUDIOSTART)
418 nhw_clock_regw_sideeffects_TASKS_(HFCLKAUDIOSTOP)
419 #endif
420 #if (NHW_CLKPWR_HAS_HFCLK192MCLK)
421 nhw_clock_regw_sideeffects_TASKS_(HFCLK192MSTART)
422 nhw_clock_regw_sideeffects_TASKS_(HFCLK192MSTOP)
423 #endif
424 nhw_clock_regw_sideeffects_TASKS_(CAL)
425 #if (NHW_CLKPWR_HAS_CALTIMER)
426 nhw_clock_regw_sideeffects_TASKS_(CTSTART)
427 nhw_clock_regw_sideeffects_TASKS_(CTSTOP)
428 #endif /* NHW_CLKPWR_HAS_CALTIMER */
429 
430 void nhw_pwrclk_regw_sideeffects_EVENTS_all(uint i) {
431   nhw_pwrclk_eval_interrupt(i);
432 }
433 
nhw_clock_LFTimer_triggered(struct clkpwr_status * this)434 void nhw_clock_LFTimer_triggered(struct clkpwr_status *this) {
435   NRF_CLOCK_Type *CLOCK_regs = this->CLOCK_regs;
436 
437   //For simplicity we assume the enable comes at the same instant as the first
438   //tick of the clock so we start ticking in this same instant
439 
440   if (this->LF_Clock_state == Starting) { /* LCOV_EXCL_BR_LINE */
441     CLOCK_regs->LFCLKSTAT = CLOCK_LFCLKSTAT_STATE_Msk
442                           | (CLOCK_regs->LFCLKSRCCOPY << CLOCK_LFCLKSTAT_SRC_Pos);
443 
444     nhw_clock_signal_LFCLKSTARTED(this->inst);
445 
446     nhw_rtc_notify_first_lf_tick();
447   } else if (this->LF_Clock_state == Stopping) {
448     this->LF_Clock_state = Stopped;
449     CLOCK_regs->LFCLKSTAT &= ~CLOCK_LFCLKSTAT_STATE_Msk;
450   }
451 
452   this->Timer_CLOCK_LF = TIME_NEVER;
453   nhw_clock_update_master_timer();
454 }
455 
456 #ifndef CLOCK_HFCLKSTAT_SRC_Xtal
457 #define CLOCK_HFCLKSTAT_SRC_Xtal CLOCK_HFCLKSTAT_SRC_HFXO /* Bit name change from 52 -> 53 series but same meaning*/
458 #endif
459 
nhw_clock_HFTimer_triggered(struct clkpwr_status * this)460 void nhw_clock_HFTimer_triggered(struct clkpwr_status *this) {
461   NRF_CLOCK_Type *CLOCK_regs = this->CLOCK_regs;
462 
463   if ( this->HF_Clock_state == Starting ){
464     this->HF_Clock_state = Started;
465 
466     CLOCK_regs->HFCLKSTAT = CLOCK_HFCLKSTAT_STATE_Msk
467                                | ( CLOCK_HFCLKSTAT_SRC_Xtal << CLOCK_HFCLKSTAT_SRC_Pos);
468 
469     nhw_clock_signal_HFCLKSTARTED(this->inst);
470 
471   } else if ( this->HF_Clock_state == Stopping ){
472     this->HF_Clock_state = Stopped;
473     CLOCK_regs->HFCLKSTAT = 0;
474   }
475 
476   this->Timer_CLOCK_HF = TIME_NEVER;
477   nhw_clock_update_master_timer();
478 }
479 
nhw_clock_LF_cal_triggered(struct clkpwr_status * this)480 void nhw_clock_LF_cal_triggered(struct clkpwr_status *this) {
481   this->LF_cal_state = Stopped;
482   this->Timer_LF_cal = TIME_NEVER;
483   nhw_clock_update_master_timer();
484 
485   nhw_clock_signal_DONE(this->inst);
486 }
487 
488 #if (NHW_CLKPWR_HAS_CALTIMER)
nhw_clock_caltimer_triggered(struct clkpwr_status * this)489 void nhw_clock_caltimer_triggered(struct clkpwr_status *this) {
490 
491   if (this->caltimer_state != Started) { /* LCOV_EXCL_START */
492     bs_trace_error_time_line("%s: programming error\n", __func__);
493   } /* LCOV_EXCL_STOP */
494   this->caltimer_state = Stopped;
495   this->Timer_caltimer = TIME_NEVER;
496   nhw_clock_update_master_timer();
497   nhw_clock_signal_CTTO(this->inst);
498 }
499 #endif /* NHW_CLKPWR_HAS_CALTIMER */
500 
nhw_pwrclk_timer_triggered(void)501 static void nhw_pwrclk_timer_triggered(void) {
502   bool any = false;
503   for (int i = 0; i < NHW_CLKPWR_TOTAL_INST; i++) {
504     struct clkpwr_status * c_el = &nhw_clkpwr_st[i];
505     if (Timer_PWRCLK == c_el->Timer_CLOCK_HF) {
506       nhw_clock_HFTimer_triggered(c_el);
507       any = true;
508     } else if (Timer_PWRCLK == c_el->Timer_CLOCK_LF) {
509       nhw_clock_LFTimer_triggered(c_el);
510       any = true;
511     } else if (Timer_PWRCLK == c_el->Timer_LF_cal) {
512       nhw_clock_LF_cal_triggered(c_el);
513       any = true;
514   #if (NHW_CLKPWR_HAS_CALTIMER)
515     } else if (Timer_PWRCLK == c_el->Timer_caltimer) {
516       nhw_clock_caltimer_triggered(c_el);
517       any = true;
518   #endif
519     }
520   }
521   if (!any) { /* LCOV_EXCL_START */
522     bs_trace_error_time_line("%s programming error\n", __func__);
523   } /* LCOV_EXCL_STOP */
524 }
525 
526 NSI_HW_EVENT(Timer_PWRCLK, nhw_pwrclk_timer_triggered, 50);
527 
528 #if (NHW_HAS_DPPI)
529 
530 #define NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(TASK_N)                                 \
531   static void nhw_clock_task##TASK_N##_wrap(void* param)                            \
532   {                                                                                 \
533     nhw_clock_TASKS_##TASK_N((int) param);                                          \
534   }                                                                                 \
535                                                                                     \
536   void nhw_clock_regw_sideeffects_SUBSCRIBE_##TASK_N(uint inst)                     \
537   {                                                                                 \
538      struct clkpwr_status *this = &nhw_clkpwr_st[inst];                             \
539                                                                                     \
540      nhw_dppi_common_subscribe_sideeffect(this->dppi_map,                           \
541                                           this->CLOCK_regs->SUBSCRIBE_##TASK_N,     \
542                                           &this->subscribed_##TASK_N,               \
543                                           nhw_clock_task##TASK_N##_wrap,            \
544                                           (void*) inst);                            \
545   }
546 
547 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLKSTART)
NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLKSTOP)548 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLKSTOP)
549 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(LFCLKSTART)
550 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(LFCLKSTOP)
551 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(CAL)
552 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLKAUDIOSTART)
553 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLKAUDIOSTOP)
554 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLK192MSTART)
555 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLK192MSTOP)
556 
557 #endif /* NHW_HAS_DPPI */
558 
559 #if (NHW_HAS_PPI)
560 void nhw_clock0_TASKS_LFCLKSTART(void) { nhw_clock_TASKS_LFCLKSTART(0); }
nhw_clock0_TASKS_LFCLKSTOP(void)561 void nhw_clock0_TASKS_LFCLKSTOP(void) { nhw_clock_TASKS_LFCLKSTOP(0); }
nhw_clock0_TASKS_HFCLKSTART(void)562 void nhw_clock0_TASKS_HFCLKSTART(void) { nhw_clock_TASKS_HFCLKSTART(0); }
nhw_clock0_TASKS_HFCLKSTOP(void)563 void nhw_clock0_TASKS_HFCLKSTOP(void) { nhw_clock_TASKS_HFCLKSTOP(0); }
nhw_clock0_TASKS_CAL(void)564 void nhw_clock0_TASKS_CAL(void) { nhw_clock_TASKS_CAL(0); }
nhw_clock0_TASKS_CTSTART(void)565 void nhw_clock0_TASKS_CTSTART(void) { nhw_clock_TASKS_CTSTART(0); }
nhw_clock0_TASKS_CTSTOP(void)566 void nhw_clock0_TASKS_CTSTOP(void) { nhw_clock_TASKS_CTSTOP(0); }
567 #endif /* (NHW_HAS_PPI) */
568