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 
116 void nhw_clock_HFTimer_triggered(struct clkpwr_status *this);
117 void nhw_clock_LFTimer_triggered(struct clkpwr_status *this);
118 
nhw_clock_update_master_timer(void)119 static void nhw_clock_update_master_timer(void) {
120 
121   Timer_PWRCLK = TIME_NEVER;
122 
123   for (int i = 0; i < NHW_CLKPWR_TOTAL_INST; i++) {
124     struct clkpwr_status * c_el = &nhw_clkpwr_st[i];
125 
126     bs_time_t t1 = BS_MIN(c_el->Timer_CLOCK_HF, c_el->Timer_CLOCK_LF);
127     bs_time_t t2 = BS_MIN(c_el->Timer_LF_cal, c_el->Timer_caltimer);
128 
129     bs_time_t el_min = BS_MIN(t1, t2);
130     if (el_min < Timer_PWRCLK) {
131       Timer_PWRCLK = el_min;
132     }
133   }
134 
135   nsi_hws_find_next_event();
136 }
137 
nhw_clock_init(void)138 static void nhw_clock_init(void) {
139 #if (NHW_HAS_DPPI)
140   /* Mapping of peripheral instance to DPPI instance */
141   uint nhw_clkpwr_dppi_map[NHW_CLKPWR_TOTAL_INST] = NHW_CLKPWR_DPPI_MAP;
142 #endif
143 
144   memset(NRF_CLKPWR_regs, 0, sizeof(NRF_CLKPWR_regs));
145 
146   for (int i = 0; i < NHW_CLKPWR_TOTAL_INST; i++) {
147     struct clkpwr_status * c_el = &nhw_clkpwr_st[i];
148 
149     c_el->inst = i;
150 
151     NRF_CLOCK_regs[i] = (NRF_CLOCK_Type *)&NRF_CLKPWR_regs[i];
152     c_el->CLOCK_regs = (NRF_CLOCK_Type *)&NRF_CLKPWR_regs[i];
153     NRF_POWER_regs[i] = (NRF_POWER_Type *)&NRF_CLKPWR_regs[i];
154     c_el->POWER_regs = (NRF_POWER_Type *)&NRF_CLKPWR_regs[i];
155 #if (NHW_CLKPWR_HAS_RESET)
156     NRF_RESET_regs[i] = (NRF_RESET_Type *)&NRF_CLKPWR_regs[i];
157     c_el->RESET_regs = (NRF_RESET_Type *)&NRF_CLKPWR_regs[i];
158 #endif /* (NHW_CLKPWR_HAS_RESET) */
159 
160     c_el->Timer_CLOCK_LF = TIME_NEVER;
161     c_el->Timer_CLOCK_HF = TIME_NEVER;
162     c_el->Timer_LF_cal   = TIME_NEVER;
163     c_el->Timer_caltimer = TIME_NEVER;
164 
165     c_el->HF_Clock_state = Stopped;
166     c_el->LF_Clock_state = Stopped;
167     c_el->LF_cal_state   = Stopped;
168     c_el->caltimer_state = Stopped;
169 #if (NHW_HAS_DPPI)
170     c_el->dppi_map = nhw_clkpwr_dppi_map[i];
171 #endif
172 
173 #if defined(CLOCK_HFXODEBOUNCE_HFXODEBOUNCE_Pos)
174     NRF_CLOCK_regs[i]->HFXODEBOUNCE = 0x00000010;
175 #endif
176   }
177 }
178 
179 NSI_TASK(nhw_clock_init, HW_INIT, 100);
180 
nhw_pwrclk_eval_interrupt(int inst)181 static void nhw_pwrclk_eval_interrupt(int inst) {
182   /* Mapping of peripheral instance to {int controller instance, int number} */
183   static struct nhw_irq_mapping nhw_clock_irq_map[NHW_CLKPWR_TOTAL_INST] = NHW_CLKPWR_INT_MAP;
184   static bool clock_int_line[NHW_CLKPWR_TOTAL_INST]; /* Is the CLOCK currently driving its interrupt line high */
185   bool new_int_line = false;
186 
187   struct clkpwr_status *this = &nhw_clkpwr_st[inst];
188 
189 #define check_interrupt(x) \
190 	if (NRF_CLOCK_regs[inst]->EVENTS_##x \
191 	    && (this->INTEN & CLOCK_INTENCLR_##x##_Msk)){ \
192 	  new_int_line = true; \
193 	} \
194 
195   check_interrupt(HFCLKSTARTED);
196   check_interrupt(LFCLKSTARTED);
197   check_interrupt(DONE);
198 #if (NHW_CLKPWR_HAS_CALTIMER)
199   check_interrupt(CTTO);
200   check_interrupt(CTSTARTED);
201   check_interrupt(CTSTOPPED);
202 #endif /* NHW_CLKPWR_HAS_CALTIMER */
203 #if (NHW_CLKPWR_HAS_HFCLKAUDIOCLK)
204   check_interrupt(HFCLKAUDIOSTARTED);
205 #endif
206 #if (NHW_CLKPWR_HAS_HFCLK192MCLK)
207   check_interrupt(HFCLK192MSTARTED);
208 #endif
209 
210   if (clock_int_line[inst] == false && new_int_line == true) {
211     clock_int_line[inst] = true;
212     hw_irq_ctrl_raise_level_irq_line(nhw_clock_irq_map[inst].cntl_inst,
213                                       nhw_clock_irq_map[inst].int_nbr);
214   } else if (clock_int_line[inst] == true && new_int_line == false) {
215     clock_int_line[inst] = false;
216     hw_irq_ctrl_lower_level_irq_line(nhw_clock_irq_map[inst].cntl_inst,
217                                       nhw_clock_irq_map[inst].int_nbr);
218   }
219 }
220 
221 #if (NHW_HAS_PPI)
222 #define nhw_clock_signal_handler(x)         \
223   static void nhw_clock_signal_##x(int i) { \
224     NRF_CLOCK_regs[i]->EVENTS_##x = 1;     \
225     nhw_pwrclk_eval_interrupt(i);           \
226     nrf_ppi_event(CLOCK_EVENTS_##x);       \
227   }
228 #else
229 #define nhw_clock_signal_handler(x)         \
230   static void nhw_clock_signal_##x(int i) { \
231     NRF_CLOCK_regs[i]->EVENTS_##x = 1;     \
232     nhw_pwrclk_eval_interrupt(i);           \
233     nhw_dppi_event_signal_if(nhw_clkpwr_st[i].dppi_map,      \
234                              NRF_CLOCK_regs[i]->PUBLISH_##x);\
235   }
236 #endif
237 
238 /*
239  * CLOCK POWER & RESET do not have shortcuts, so all we need to do
240  * is set the corresponding event and evaluate the interrupt.
241  */
242 nhw_clock_signal_handler(HFCLKSTARTED)
nhw_clock_signal_handler(LFCLKSTARTED)243 nhw_clock_signal_handler(LFCLKSTARTED)
244 nhw_clock_signal_handler(DONE)
245 #if (NHW_CLKPWR_HAS_CALTIMER)
246 nhw_clock_signal_handler(CTTO)
247 nhw_clock_signal_handler(CTSTARTED)
248 nhw_clock_signal_handler(CTSTOPPED)
249 #endif /* NHW_CLKPWR_HAS_CALTIMER */
250 #if (NHW_CLKPWR_HAS_HFCLKAUDIOCLK)
251 //nhw_clock_signal_handler(HFCLKAUDIOSTARTED)
252 #endif
253 #if (NHW_CLKPWR_HAS_HFCLK192MCLK)
254 //nhw_clock_signal_handler(HFCLK192MSTARTED)
255 #endif
256 
257 void nhw_clock_TASKS_LFCLKSTART(uint inst) {
258   struct clkpwr_status *this = &nhw_clkpwr_st[inst];
259   NRF_CLOCK_Type *CLOCK_regs = this->CLOCK_regs;
260 
261   CLOCK_regs->LFCLKSRCCOPY = CLOCK_regs->LFCLKSRC & CLOCK_LFCLKSRC_SRC_Msk;
262   CLOCK_regs->LFCLKRUN = CLOCK_LFCLKRUN_STATUS_Msk;
263   this->LF_Clock_state = Starting;
264 
265   this->Timer_CLOCK_LF = nsi_hws_get_time(); //we assume the clock is ready in 1 delta
266   nhw_clock_update_master_timer();
267 }
268 
nhw_clock_TASKS_LFCLKSTOP(uint inst)269 void nhw_clock_TASKS_LFCLKSTOP(uint inst) {
270   // There is no effect of turning the clock off that is actually modeled
271   if ((NRF_CLOCK_regs[inst]->LFCLKSTAT & CLOCK_LFCLKRUN_STATUS_Msk) == 0) { /* LCOV_EXCL_START */
272     bs_trace_info_line(3, "%s(%u) Triggered LF oscillator stop while the clock was not running "
273                           "(the model does not have a problem with this, but this is against "
274                           "the spec)\n", __func__, inst);
275   } /* LCOV_EXCL_STOP */
276 
277   struct clkpwr_status *this = &nhw_clkpwr_st[inst];
278 
279   if ((this->LF_Clock_state == Started) || (this->LF_Clock_state == Starting)) {
280     NRF_CLOCK_regs[inst]->LFCLKRUN = 0;
281     this->LF_Clock_state = Stopping;
282     /* Instantaneous stop */
283     nhw_clock_LFTimer_triggered(this);
284   }
285 }
286 
nhw_clock_TASKS_HFCLKSTART(uint inst)287 void nhw_clock_TASKS_HFCLKSTART(uint inst) {
288   struct clkpwr_status *this = &nhw_clkpwr_st[inst];
289 
290   if ((this->HF_Clock_state == Stopped ) || (this->HF_Clock_state == Stopping)) {
291     this->HF_Clock_state = Starting;
292     NRF_CLOCK_regs[inst]->HFCLKRUN = CLOCK_HFCLKRUN_STATUS_Msk;
293     this->Timer_CLOCK_HF = nsi_hws_get_time(); //we assume the clock is ready in 1 delta
294     nhw_clock_update_master_timer();
295   }
296 }
297 
nhw_clock_TASKS_HFCLKSTOP(uint inst)298 void nhw_clock_TASKS_HFCLKSTOP(uint inst) {
299   struct clkpwr_status *this = &nhw_clkpwr_st[inst];
300 
301   if ((this->HF_Clock_state == Started) || (this->HF_Clock_state == Starting)) {
302     NRF_CLOCK_regs[inst]->HFCLKRUN = 0;
303     this->HF_Clock_state = Stopping;
304     /* Instantaneous stop */
305     nhw_clock_HFTimer_triggered(this);
306   }
307 }
308 
309 #define HAS_CLOCK_CHECK(CLK_NAME)                                                 \
310 	  bool has_this_clock[NHW_CLKPWR_TOTAL_INST] = NHW_CLKPWR_HAS_##CLK_NAME##CLK_I;\
311 	  if (!has_this_clock[inst]) {                                                  \
312 	    bs_trace_error_time_line("CLOCK#%i does not have "                          \
313          "this type of clock (" #CLK_NAME ")", inst);                             \
314 	  }
315 
nhw_clock_TASKS_HFCLKAUDIOSTART(uint inst)316 void nhw_clock_TASKS_HFCLKAUDIOSTART(uint inst) {
317   HAS_CLOCK_CHECK(HFCLKAUDIO);
318 
319   bs_trace_warning_time_line("%s not yet implemented\n", __func__);
320 }
321 
nhw_clock_TASKS_HFCLKAUDIOSTOP(uint inst)322 void nhw_clock_TASKS_HFCLKAUDIOSTOP(uint inst) {
323   HAS_CLOCK_CHECK(HFCLKAUDIO);
324 
325   bs_trace_warning_time_line("%s not yet implemented\n", __func__);
326 }
327 
nhw_clock_TASKS_HFCLK192MSTART(uint inst)328 void nhw_clock_TASKS_HFCLK192MSTART(uint inst) {
329   HAS_CLOCK_CHECK(HFCLK192M);
330 
331   bs_trace_warning_time_line("%s not yet implemented\n", __func__);
332 }
333 
nhw_clock_TASKS_HFCLK192MSTOP(uint inst)334 void nhw_clock_TASKS_HFCLK192MSTOP(uint inst) {
335   HAS_CLOCK_CHECK(HFCLK192M);
336 
337   bs_trace_warning_time_line("%s not yet implemented\n", __func__);
338 }
339 
340 
nhw_clock_TASKS_CAL(uint inst)341 void nhw_clock_TASKS_CAL(uint inst) {
342   struct clkpwr_status *this = &nhw_clkpwr_st[inst];
343 
344   if (this->HF_Clock_state != Started) { /* LCOV_EXCL_START */
345     bs_trace_warning_line("%s(%u): Triggered RC oscillator calibration with the HF CLK stopped "
346                           "(the model does not have a problem with this, but this is against "
347                           "the spec)\n", __func__, inst);
348   } /* LCOV_EXCL_STOP */
349 
350   this->LF_cal_state = Started; //We don't check for re-triggers, as we are going to be done right away
351   this->Timer_LF_cal = nsi_hws_get_time(); //we assume the calibration is done in 1 delta
352   nhw_clock_update_master_timer();
353 }
354 
355 #if (NHW_CLKPWR_HAS_CALTIMER)
nhw_clock_TASKS_CTSTART(uint inst)356 void nhw_clock_TASKS_CTSTART(uint inst) {
357   struct clkpwr_status *this = &nhw_clkpwr_st[inst];
358 
359   if ( this->caltimer_state == Started ) { /* LCOV_EXCL_START */
360     bs_trace_warning_line("%s(%u) Calibration timer was already running. "
361                           "Raising CTSTARTED event immediately. "
362                           "Timeout is not affected.\n", __func__, inst);
363   } else {  /* LCOV_EXCL_STOP */
364     this->caltimer_state = Started;
365     this->Timer_caltimer = nsi_hws_get_time() + (bs_time_t)NRF_CLOCK_regs[inst]->CTIV * 250000;
366     nhw_clock_update_master_timer();
367   }
368   nhw_clock_signal_CTSTARTED(inst);
369 }
370 
nhw_clock_TASKS_CTSTOP(uint inst)371 void nhw_clock_TASKS_CTSTOP(uint inst) {
372   struct clkpwr_status *this = &nhw_clkpwr_st[inst];
373 
374   if ( this->caltimer_state == Stopped ) { /* LCOV_EXCL_START */
375     bs_trace_info_line(3, "%s(%u) Calibration timer was already stopped. "
376                           "Raising CTSTOPPED event immediately.\n", __func__, inst);
377   } /* LCOV_EXCL_STOP */
378   this->caltimer_state = Stopped;
379   this->Timer_caltimer = TIME_NEVER;
380   nhw_clock_update_master_timer();
381   nhw_clock_signal_CTSTOPPED(inst);
382 }
383 #endif /* NHW_CLKPWR_HAS_CALTIMER */
384 
nhw_CLOCK_regw_sideeffects_INTENSET(uint i)385 void nhw_CLOCK_regw_sideeffects_INTENSET(uint i) {
386   if (NRF_CLOCK_regs[i]->INTENSET) { /* LCOV_EXCL_BR_LINE */
387     struct clkpwr_status *this = &nhw_clkpwr_st[i];
388 
389     this->INTEN |= NRF_CLOCK_regs[i]->INTENSET;
390     NRF_CLOCK_regs[i]->INTENSET = this->INTEN;
391     nhw_pwrclk_eval_interrupt(i);
392   }
393 }
394 
nhw_CLOCK_regw_sideeffects_INTENCLR(uint i)395 void nhw_CLOCK_regw_sideeffects_INTENCLR(uint i) {
396   if (NRF_CLOCK_regs[i]->INTENCLR) { /* LCOV_EXCL_BR_LINE */
397     struct clkpwr_status *this = &nhw_clkpwr_st[i];
398 
399     this->INTEN  &= ~NRF_CLOCK_regs[i]->INTENCLR;
400     NRF_CLOCK_regs[i]->INTENSET = this->INTEN;
401     NRF_CLOCK_regs[i]->INTENCLR = 0;
402     nhw_pwrclk_eval_interrupt(i);
403   }
404 }
405 
406 #define nhw_clock_regw_sideeffects_TASKS_(x)                   \
407   void nhw_CLOCK_regw_sideeffects_TASKS_##x(uint i) {          \
408     if (NRF_CLOCK_regs[i]->TASKS_##x) { /* LCOV_EXCL_BR_LINE */\
409       NRF_CLOCK_regs[i]->TASKS_##x = 0;                        \
410       nhw_clock_TASKS_##x(i);                                  \
411     }                                                          \
412   }
413 
414 nhw_clock_regw_sideeffects_TASKS_(LFCLKSTART)
nhw_clock_regw_sideeffects_TASKS_(LFCLKSTOP)415 nhw_clock_regw_sideeffects_TASKS_(LFCLKSTOP)
416 nhw_clock_regw_sideeffects_TASKS_(HFCLKSTART)
417 nhw_clock_regw_sideeffects_TASKS_(HFCLKSTOP)
418 
419 #if (NHW_CLKPWR_HAS_HFCLKAUDIOCLK)
420 nhw_clock_regw_sideeffects_TASKS_(HFCLKAUDIOSTART)
421 nhw_clock_regw_sideeffects_TASKS_(HFCLKAUDIOSTOP)
422 #endif
423 #if (NHW_CLKPWR_HAS_HFCLK192MCLK)
424 nhw_clock_regw_sideeffects_TASKS_(HFCLK192MSTART)
425 nhw_clock_regw_sideeffects_TASKS_(HFCLK192MSTOP)
426 #endif
427 nhw_clock_regw_sideeffects_TASKS_(CAL)
428 #if (NHW_CLKPWR_HAS_CALTIMER)
429 nhw_clock_regw_sideeffects_TASKS_(CTSTART)
430 nhw_clock_regw_sideeffects_TASKS_(CTSTOP)
431 #endif /* NHW_CLKPWR_HAS_CALTIMER */
432 
433 void nhw_pwrclk_regw_sideeffects_EVENTS_all(uint i) {
434   nhw_pwrclk_eval_interrupt(i);
435 }
436 
nhw_clock_LFTimer_triggered(struct clkpwr_status * this)437 void nhw_clock_LFTimer_triggered(struct clkpwr_status *this) {
438   NRF_CLOCK_Type *CLOCK_regs = this->CLOCK_regs;
439 
440   //For simplicity we assume the enable comes at the same instant as the first
441   //tick of the clock so we start ticking in this same instant
442 
443   if (this->LF_Clock_state == Starting) { /* LCOV_EXCL_BR_LINE */
444     CLOCK_regs->LFCLKSTAT = CLOCK_LFCLKSTAT_STATE_Msk
445                           | (CLOCK_regs->LFCLKSRCCOPY << CLOCK_LFCLKSTAT_SRC_Pos);
446 
447     nhw_clock_signal_LFCLKSTARTED(this->inst);
448 
449     nhw_rtc_notify_first_lf_tick();
450   } else if (this->LF_Clock_state == Stopping) {
451     this->LF_Clock_state = Stopped;
452     CLOCK_regs->LFCLKSTAT = 0;
453   }
454 
455   this->Timer_CLOCK_LF = TIME_NEVER;
456   nhw_clock_update_master_timer();
457 }
458 
459 #ifndef CLOCK_HFCLKSTAT_SRC_Xtal
460 #define CLOCK_HFCLKSTAT_SRC_Xtal CLOCK_HFCLKSTAT_SRC_HFXO /* Bit name change from 52 -> 53 series but same meaning*/
461 #endif
462 
nhw_clock_HFTimer_triggered(struct clkpwr_status * this)463 void nhw_clock_HFTimer_triggered(struct clkpwr_status *this) {
464   NRF_CLOCK_Type *CLOCK_regs = this->CLOCK_regs;
465 
466   if ( this->HF_Clock_state == Starting ){
467     this->HF_Clock_state = Started;
468 
469     CLOCK_regs->HFCLKSTAT = CLOCK_HFCLKSTAT_STATE_Msk
470                                | ( CLOCK_HFCLKSTAT_SRC_Xtal << CLOCK_HFCLKSTAT_SRC_Pos);
471 
472     nhw_clock_signal_HFCLKSTARTED(this->inst);
473 
474   } else if ( this->HF_Clock_state == Stopping ){
475     this->HF_Clock_state = Stopped;
476     CLOCK_regs->HFCLKSTAT = 0;
477   }
478 
479   this->Timer_CLOCK_HF = TIME_NEVER;
480   nhw_clock_update_master_timer();
481 }
482 
nhw_clock_LF_cal_triggered(struct clkpwr_status * this)483 void nhw_clock_LF_cal_triggered(struct clkpwr_status *this) {
484   this->LF_cal_state = Stopped;
485   this->Timer_LF_cal = TIME_NEVER;
486   nhw_clock_update_master_timer();
487 
488   nhw_clock_signal_DONE(this->inst);
489 }
490 
491 #if (NHW_CLKPWR_HAS_CALTIMER)
nhw_clock_caltimer_triggered(struct clkpwr_status * this)492 void nhw_clock_caltimer_triggered(struct clkpwr_status *this) {
493 
494   if (this->caltimer_state != Started) { /* LCOV_EXCL_START */
495     bs_trace_error_time_line("%s: programming error\n", __func__);
496   } /* LCOV_EXCL_STOP */
497   this->caltimer_state = Stopped;
498   this->Timer_caltimer = TIME_NEVER;
499   nhw_clock_update_master_timer();
500   nhw_clock_signal_CTTO(this->inst);
501 }
502 #endif /* NHW_CLKPWR_HAS_CALTIMER */
503 
nhw_pwrclk_timer_triggered(void)504 static void nhw_pwrclk_timer_triggered(void) {
505   bool any = false;
506   for (int i = 0; i < NHW_CLKPWR_TOTAL_INST; i++) {
507     struct clkpwr_status * c_el = &nhw_clkpwr_st[i];
508     if (Timer_PWRCLK == c_el->Timer_CLOCK_HF) {
509       nhw_clock_HFTimer_triggered(c_el);
510       any = true;
511     } else if (Timer_PWRCLK == c_el->Timer_CLOCK_LF) {
512       nhw_clock_LFTimer_triggered(c_el);
513       any = true;
514     } else if (Timer_PWRCLK == c_el->Timer_LF_cal) {
515       nhw_clock_LF_cal_triggered(c_el);
516       any = true;
517   #if (NHW_CLKPWR_HAS_CALTIMER)
518     } else if (Timer_PWRCLK == c_el->Timer_caltimer) {
519       nhw_clock_caltimer_triggered(c_el);
520       any = true;
521   #endif
522     }
523   }
524   if (!any) { /* LCOV_EXCL_START */
525     bs_trace_error_time_line("%s programming error\n", __func__);
526   } /* LCOV_EXCL_STOP */
527 }
528 
529 NSI_HW_EVENT(Timer_PWRCLK, nhw_pwrclk_timer_triggered, 50);
530 
531 #if (NHW_HAS_DPPI)
532 
533 #define NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(TASK_N)                                 \
534   static void nhw_clock_task##TASK_N##_wrap(void* param)                            \
535   {                                                                                 \
536     nhw_clock_TASKS_##TASK_N((int) param);                                          \
537   }                                                                                 \
538                                                                                     \
539   void nhw_CLOCK_regw_sideeffects_SUBSCRIBE_##TASK_N(uint inst)                     \
540   {                                                                                 \
541      struct clkpwr_status *this = &nhw_clkpwr_st[inst];                             \
542                                                                                     \
543      nhw_dppi_common_subscribe_sideeffect(this->dppi_map,                           \
544                                           this->CLOCK_regs->SUBSCRIBE_##TASK_N,     \
545                                           &this->subscribed_##TASK_N,               \
546                                           nhw_clock_task##TASK_N##_wrap,            \
547                                           (void*) inst);                            \
548   }
549 
550 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLKSTART)
NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLKSTOP)551 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLKSTOP)
552 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(LFCLKSTART)
553 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(LFCLKSTOP)
554 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(CAL)
555 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLKAUDIOSTART)
556 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLKAUDIOSTOP)
557 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLK192MSTART)
558 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLK192MSTOP)
559 
560 #endif /* NHW_HAS_DPPI */
561 
562 #if (NHW_HAS_PPI)
563 void nhw_clock0_TASKS_LFCLKSTART(void) { nhw_clock_TASKS_LFCLKSTART(0); }
nhw_clock0_TASKS_LFCLKSTOP(void)564 void nhw_clock0_TASKS_LFCLKSTOP(void) { nhw_clock_TASKS_LFCLKSTOP(0); }
nhw_clock0_TASKS_HFCLKSTART(void)565 void nhw_clock0_TASKS_HFCLKSTART(void) { nhw_clock_TASKS_HFCLKSTART(0); }
nhw_clock0_TASKS_HFCLKSTOP(void)566 void nhw_clock0_TASKS_HFCLKSTOP(void) { nhw_clock_TASKS_HFCLKSTOP(0); }
nhw_clock0_TASKS_CAL(void)567 void nhw_clock0_TASKS_CAL(void) { nhw_clock_TASKS_CAL(0); }
nhw_clock0_TASKS_CTSTART(void)568 void nhw_clock0_TASKS_CTSTART(void) { nhw_clock_TASKS_CTSTART(0); }
nhw_clock0_TASKS_CTSTOP(void)569 void nhw_clock0_TASKS_CTSTOP(void) { nhw_clock_TASKS_CTSTOP(0); }
570 #endif /* (NHW_HAS_PPI) */
571