1 /*
2 * Copyright (c) 2018 Foundries.io Ltd
3 * Copyright (c) 2019 STMicroelectronics
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/init.h>
9 #include <soc.h>
10 #include <stm32_ll_lptim.h>
11 #include <stm32_ll_bus.h>
12 #include <stm32_ll_rcc.h>
13 #include <stm32_ll_pwr.h>
14 #include <stm32_ll_system.h>
15 #include <zephyr/drivers/clock_control.h>
16 #include <zephyr/drivers/clock_control/stm32_clock_control.h>
17 #include <zephyr/drivers/timer/system_timer.h>
18 #include <zephyr/sys_clock.h>
19 #include <zephyr/irq.h>
20 #include <zephyr/drivers/counter.h>
21 #include <zephyr/pm/policy.h>
22
23 #include <zephyr/spinlock.h>
24
25 #define DT_DRV_COMPAT st_stm32_lptim
26
27 #if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) > 1
28 #error Only one LPTIM instance should be enabled
29 #endif
30
31 #define LPTIM (LPTIM_TypeDef *) DT_INST_REG_ADDR(0)
32
33 #if DT_INST_NUM_CLOCKS(0) == 1
34 #warning Kconfig for LPTIM source clock (LSI/LSE) is deprecated, use device tree.
35 static const struct stm32_pclken lptim_clk[] = {
36 STM32_CLOCK_INFO(0, DT_DRV_INST(0)),
37 /* Use Kconfig to configure source clocks fields */
38 /* Fortunately, values are consistent across enabled series */
39 #ifdef CONFIG_STM32_LPTIM_CLOCK_LSI
40 {.bus = STM32_SRC_LSI, .enr = LPTIM1_SEL(1)}
41 #else
42 {.bus = STM32_SRC_LSE, .enr = LPTIM1_SEL(3)}
43 #endif
44 };
45 #else
46 static const struct stm32_pclken lptim_clk[] = STM32_DT_INST_CLOCKS(0);
47 #endif
48
49 static const struct device *const clk_ctrl = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
50
51 /*
52 * Assumptions and limitations:
53 *
54 * - system clock based on an LPTIM instance, clocked by LSI or LSE
55 * - prescaler is set to a 2^value from 1 (division of the LPTIM source clock by 1)
56 * to 128 (division of the LPTIM source clock by 128)
57 * - using LPTIM AutoReload capability to trig the IRQ (timeout irq)
58 * - when timeout irq occurs the counter is already reset
59 * - the maximum timeout duration is reached with the lptim_time_base value
60 * - with prescaler of 1, the max timeout (LPTIM_TIMEBASE) is 2 seconds:
61 * 0xFFFF / (LSE freq (32768Hz) / 1)
62 * - with prescaler of 128, the max timeout (LPTIM_TIMEBASE) is 256 seconds:
63 * 0xFFFF / (LSE freq (32768Hz) / 128)
64 */
65
66 static int32_t lptim_time_base;
67 static uint32_t lptim_clock_freq = CONFIG_STM32_LPTIM_CLOCK;
68 /* The prescaler given by the DTS and to apply to the lptim_clock_freq */
69 static uint32_t lptim_clock_presc = DT_PROP(DT_DRV_INST(0), st_prescaler);
70
71 /* Minimum nb of clock cycles to have to set autoreload register correctly */
72 #define LPTIM_GUARD_VALUE 2
73
74 /* A 32bit value cannot exceed 0xFFFFFFFF/LPTIM_TIMEBASE counting cycles.
75 * This is for example about of 65000 x 2000ms when clocked by LSI
76 */
77 static uint32_t accumulated_lptim_cnt;
78 /* Next autoreload value to set */
79 static uint32_t autoreload_next;
80 /* Indicate if the autoreload register is ready for a write */
81 static bool autoreload_ready = true;
82
83 static struct k_spinlock lock;
84
85 #ifdef CONFIG_STM32_LPTIM_STDBY_TIMER
86
87 #define CURRENT_CPU \
88 (COND_CODE_1(CONFIG_SMP, (arch_curr_cpu()->id), (_current_cpu->id)))
89
90 #define cycle_t uint32_t
91
92 /* This local variable indicates that the timeout was set right before
93 * entering standby state.
94 *
95 * It is used for chips that has to use a separate standby timer in such
96 * case because the LPTIM is not clocked in some low power mode state.
97 */
98 static bool timeout_stdby;
99
100 /* Cycle counter before entering the standby state. */
101 static cycle_t lptim_cnt_pre_stdby;
102
103 /* Standby timer value before entering the standby state. */
104 static uint32_t stdby_timer_pre_stdby;
105
106 /* Standby timer used for timer while entering the standby state */
107 static const struct device *stdby_timer = DEVICE_DT_GET(DT_CHOSEN(st_lptim_stdby_timer));
108
109 #endif /* CONFIG_STM32_LPTIM_STDBY_TIMER */
110
arrm_state_get(void)111 static inline bool arrm_state_get(void)
112 {
113 return (LL_LPTIM_IsActiveFlag_ARRM(LPTIM) && LL_LPTIM_IsEnabledIT_ARRM(LPTIM));
114 }
115
lptim_irq_handler(const struct device * unused)116 static void lptim_irq_handler(const struct device *unused)
117 {
118
119 ARG_UNUSED(unused);
120
121 uint32_t autoreload = LL_LPTIM_GetAutoReload(LPTIM);
122
123 if ((LL_LPTIM_IsActiveFlag_ARROK(LPTIM) != 0)
124 && LL_LPTIM_IsEnabledIT_ARROK(LPTIM) != 0) {
125 LL_LPTIM_ClearFlag_ARROK(LPTIM);
126 if ((autoreload_next > 0) && (autoreload_next != autoreload)) {
127 /* the new autoreload value change, we set it */
128 autoreload_ready = false;
129 LL_LPTIM_SetAutoReload(LPTIM, autoreload_next);
130 } else {
131 autoreload_ready = true;
132 }
133 }
134
135 if (arrm_state_get()) {
136 k_spinlock_key_t key = k_spin_lock(&lock);
137
138 /* do not change ARR yet, sys_clock_announce will do */
139 LL_LPTIM_ClearFLAG_ARRM(LPTIM);
140
141 /* increase the total nb of autoreload count
142 * used in the sys_clock_cycle_get_32() function.
143 */
144 autoreload++;
145
146 accumulated_lptim_cnt += autoreload;
147
148 k_spin_unlock(&lock, key);
149
150 /* announce the elapsed time in ms (count register is 16bit) */
151 uint32_t dticks = (autoreload
152 * CONFIG_SYS_CLOCK_TICKS_PER_SEC)
153 / lptim_clock_freq;
154
155 sys_clock_announce(IS_ENABLED(CONFIG_TICKLESS_KERNEL)
156 ? dticks : (dticks > 0));
157 }
158 }
159
lptim_set_autoreload(uint32_t arr)160 static void lptim_set_autoreload(uint32_t arr)
161 {
162 /* Update autoreload register */
163 autoreload_next = arr;
164
165 if (!autoreload_ready)
166 return;
167
168 /* The ARR register ready, we could set it directly */
169 if ((arr > 0) && (arr != LL_LPTIM_GetAutoReload(LPTIM))) {
170 /* The new autoreload value change, we set it */
171 autoreload_ready = false;
172 LL_LPTIM_ClearFlag_ARROK(LPTIM);
173 LL_LPTIM_SetAutoReload(LPTIM, arr);
174 }
175 }
176
z_clock_lptim_getcounter(void)177 static inline uint32_t z_clock_lptim_getcounter(void)
178 {
179 uint32_t lp_time;
180 uint32_t lp_time_prev_read;
181
182 /* It should be noted that to read reliably the content
183 * of the LPTIM_CNT register, two successive read accesses
184 * must be performed and compared
185 */
186 lp_time = LL_LPTIM_GetCounter(LPTIM);
187 do {
188 lp_time_prev_read = lp_time;
189 lp_time = LL_LPTIM_GetCounter(LPTIM);
190 } while (lp_time != lp_time_prev_read);
191 return lp_time;
192 }
193
sys_clock_set_timeout(int32_t ticks,bool idle)194 void sys_clock_set_timeout(int32_t ticks, bool idle)
195 {
196 /* new LPTIM AutoReload value to set (aligned on Kernel ticks) */
197 uint32_t next_arr = 0;
198 int err;
199
200 ARG_UNUSED(idle);
201
202 #ifdef CONFIG_STM32_LPTIM_STDBY_TIMER
203 const struct pm_state_info *next;
204
205 next = pm_policy_next_state(CURRENT_CPU, ticks);
206
207 /* Check if STANBY or STOP3 is requested */
208 timeout_stdby = false;
209 if ((next != NULL) && idle) {
210 #ifdef CONFIG_PM_S2RAM
211 if (next->state == PM_STATE_SUSPEND_TO_RAM) {
212 timeout_stdby = true;
213 }
214 #endif
215 #ifdef CONFIG_STM32_STOP3_LP_MODE
216 if ((next->state == PM_STATE_SUSPEND_TO_IDLE) && (next->substate_id == 4)) {
217 timeout_stdby = true;
218 }
219 #endif
220 }
221
222 if (timeout_stdby) {
223 uint64_t timeout_us =
224 ((uint64_t)ticks * USEC_PER_SEC) / CONFIG_SYS_CLOCK_TICKS_PER_SEC;
225
226 struct counter_alarm_cfg cfg = {
227 .callback = NULL,
228 .ticks = counter_us_to_ticks(stdby_timer, timeout_us),
229 .user_data = NULL,
230 .flags = 0,
231 };
232
233 /* Set the alarm using timer that runs the standby.
234 * Needed rump-up/setting time, lower accurency etc. should be
235 * included in the exit-latency in the power state definition.
236 */
237 counter_cancel_channel_alarm(stdby_timer, 0);
238 counter_set_channel_alarm(stdby_timer, 0, &cfg);
239
240 /* Store current values to calculate a difference in
241 * measurements after exiting the standby state.
242 */
243 counter_get_value(stdby_timer, &stdby_timer_pre_stdby);
244 lptim_cnt_pre_stdby = z_clock_lptim_getcounter();
245
246 /* Stop clocks for LPTIM, since RTC is used instead */
247 clock_control_off(clk_ctrl, (clock_control_subsys_t) &lptim_clk[0]);
248
249 return;
250 }
251 #endif /* CONFIG_STM32_LPTIM_STDBY_TIMER */
252
253 if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
254 return;
255 }
256
257 /*
258 * When CONFIG_SYSTEM_CLOCK_SLOPPY_IDLE = y, ticks equals to -1
259 * is treated as a lptim off ; never waking up ; lptim not clocked anymore
260 */
261 if (ticks == K_TICKS_FOREVER) {
262 clock_control_off(clk_ctrl, (clock_control_subsys_t) &lptim_clk[0]);
263 return;
264 }
265 /*
266 * When CONFIG_SYSTEM_CLOCK_SLOPPY_IDLE = n, ticks equals to INT_MAX
267 * is treated as a maximum possible value LPTIM_MAX_TIMEBASE (16bit counter)
268 */
269
270 /* if LPTIM clock was previously stopped, it must now be restored */
271 err = clock_control_on(clk_ctrl, (clock_control_subsys_t) &lptim_clk[0]);
272
273 if (err < 0) {
274 return;
275 }
276 /* passing ticks==1 means "announce the next tick",
277 * ticks value of zero (or even negative) is legal and
278 * treated identically: it simply indicates the kernel would like the
279 * next tick announcement as soon as possible.
280 */
281 ticks = CLAMP(ticks - 1, 1, lptim_time_base);
282
283 k_spinlock_key_t key = k_spin_lock(&lock);
284
285 /* read current counter value (cannot exceed 16bit) */
286
287 uint32_t lp_time = z_clock_lptim_getcounter();
288
289 uint32_t autoreload = LL_LPTIM_GetAutoReload(LPTIM);
290
291 if (LL_LPTIM_IsActiveFlag_ARRM(LPTIM)
292 || ((autoreload - lp_time) < LPTIM_GUARD_VALUE)) {
293 /* interrupt happens or happens soon.
294 * It's impossible to set autoreload value.
295 */
296 k_spin_unlock(&lock, key);
297 return;
298 }
299
300 /* calculate the next arr value (cannot exceed 16bit)
301 * adjust the next ARR match value to align on Ticks
302 * from the current counter value to first next Tick
303 */
304 next_arr = (((lp_time * CONFIG_SYS_CLOCK_TICKS_PER_SEC)
305 / lptim_clock_freq) + 1) * lptim_clock_freq
306 / (CONFIG_SYS_CLOCK_TICKS_PER_SEC);
307 next_arr = next_arr + ((uint32_t)(ticks) * lptim_clock_freq)
308 / CONFIG_SYS_CLOCK_TICKS_PER_SEC;
309 /* if the lptim_clock_freq < one ticks/sec, then next_arr must be > 0 */
310
311 /* maximise to TIMEBASE */
312 if (next_arr > lptim_time_base) {
313 next_arr = lptim_time_base;
314 }
315 /* The new autoreload value must be LPTIM_GUARD_VALUE clock cycles
316 * after current lptim to make sure we don't miss
317 * an autoreload interrupt
318 */
319 else if (next_arr < (lp_time + LPTIM_GUARD_VALUE)) {
320 next_arr = lp_time + LPTIM_GUARD_VALUE;
321 }
322 /* with slow lptim_clock_freq, LPTIM_GUARD_VALUE of 1 is enough */
323 next_arr = next_arr - 1;
324
325 /* Update autoreload register */
326 lptim_set_autoreload(next_arr);
327
328 k_spin_unlock(&lock, key);
329 }
330
sys_clock_lp_time_get(void)331 static uint32_t sys_clock_lp_time_get(void)
332 {
333 uint32_t lp_time;
334
335 do {
336 /* In case of counter roll-over, add the autoreload value,
337 * because the irq has not yet been handled
338 */
339 if (arrm_state_get()) {
340 lp_time = LL_LPTIM_GetAutoReload(LPTIM) + 1;
341 lp_time += z_clock_lptim_getcounter();
342 break;
343 }
344
345 lp_time = z_clock_lptim_getcounter();
346
347 /* Check if the flag ARRM wasn't be set during the process */
348 } while (arrm_state_get());
349
350 return lp_time;
351 }
352
353
sys_clock_elapsed(void)354 uint32_t sys_clock_elapsed(void)
355 {
356 if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
357 return 0;
358 }
359
360 k_spinlock_key_t key = k_spin_lock(&lock);
361
362 uint32_t lp_time = sys_clock_lp_time_get();
363
364 k_spin_unlock(&lock, key);
365
366 /* gives the value of LPTIM counter (ms)
367 * since the previous 'announce'
368 */
369 uint64_t ret = ((uint64_t)lp_time * CONFIG_SYS_CLOCK_TICKS_PER_SEC) / lptim_clock_freq;
370
371 return (uint32_t)(ret);
372 }
373
sys_clock_cycle_get_32(void)374 uint32_t sys_clock_cycle_get_32(void)
375 {
376 /* just gives the accumulated count in a number of hw cycles */
377
378 k_spinlock_key_t key = k_spin_lock(&lock);
379
380 uint32_t lp_time = sys_clock_lp_time_get();
381
382 lp_time += accumulated_lptim_cnt;
383
384 /* convert lptim count in a nb of hw cycles with precision */
385 uint64_t ret = ((uint64_t)lp_time * sys_clock_hw_cycles_per_sec()) / lptim_clock_freq;
386
387 k_spin_unlock(&lock, key);
388
389 /* convert in hw cycles (keeping 32bit value) */
390 return (uint32_t)(ret);
391 }
392
393 /* Wait for the IER register of the stm32U5 ready, after any bit write operation */
stm32_lptim_wait_ready(void)394 void stm32_lptim_wait_ready(void)
395 {
396 #ifdef CONFIG_SOC_SERIES_STM32U5X
397 while (LL_LPTIM_IsActiveFlag_DIEROK(LPTIM) == 0) {
398 }
399 LL_LPTIM_ClearFlag_DIEROK(LPTIM);
400 #else
401 /* Empty : not relevant */
402 #endif
403 }
404
sys_clock_driver_init(void)405 static int sys_clock_driver_init(void)
406 {
407 uint32_t count_per_tick;
408 int err;
409
410 if (!device_is_ready(clk_ctrl)) {
411 return -ENODEV;
412 }
413
414 /* Enable LPTIM bus clock */
415 err = clock_control_on(clk_ctrl, (clock_control_subsys_t) &lptim_clk[0]);
416 if (err < 0) {
417 return -EIO;
418 }
419
420 #if defined(LL_SRDAMR_GRP1_PERIPH_LPTIM1AMEN)
421 LL_SRDAMR_GRP1_EnableAutonomousClock(LL_SRDAMR_GRP1_PERIPH_LPTIM1AMEN);
422 #endif
423
424 /* Enable LPTIM clock source */
425 err = clock_control_configure(clk_ctrl,
426 (clock_control_subsys_t) &lptim_clk[1],
427 NULL);
428 if (err < 0) {
429 return -EIO;
430 }
431
432 /* Get LPTIM clock freq */
433 err = clock_control_get_rate(clk_ctrl, (clock_control_subsys_t) &lptim_clk[1],
434 &lptim_clock_freq);
435
436 if (err < 0) {
437 return -EIO;
438 }
439 #if defined(CONFIG_SOC_SERIES_STM32L0X)
440 /* Driver only supports freqs up to 32768Hz. On L0, LSI freq is 37KHz,
441 * which will overflow the LPTIM counter.
442 * Previous LPTIM configuration using device tree was doing forcing this
443 * with a Kconfig default. Impact is that time is 1.13 faster than reality.
444 * Following lines reproduce this behavior in order not to change behavior.
445 * This issue will be fixed by implementation LPTIM prescaler support.
446 */
447 if (lptim_clk[1].bus == STM32_SRC_LSI) {
448 lptim_clock_freq = KHZ(32);
449 }
450 #endif
451
452 /* Set LPTIM time base based on clock source freq */
453 if (lptim_clock_freq == KHZ(32)) {
454 lptim_time_base = 0xF9FF;
455 } else if (lptim_clock_freq == 32768) {
456 lptim_time_base = 0xFFFF;
457 } else {
458 return -EIO;
459 }
460
461 #if !defined(CONFIG_STM32_LPTIM_TICK_FREQ_RATIO_OVERRIDE)
462 /*
463 * Check coherency between CONFIG_SYS_CLOCK_TICKS_PER_SEC
464 * and the lptim_clock_freq which is the CONFIG_STM32_LPTIM_CLOCK reduced
465 * by the lptim_clock_presc
466 */
467 if (lptim_clock_presc <= 8) {
468 __ASSERT(CONFIG_STM32_LPTIM_CLOCK / 8 >= CONFIG_SYS_CLOCK_TICKS_PER_SEC,
469 "It is recommended to set SYS_CLOCK_TICKS_PER_SEC to CONFIG_STM32_LPTIM_CLOCK/8");
470 } else {
471 __ASSERT(CONFIG_STM32_LPTIM_CLOCK / lptim_clock_presc >=
472 CONFIG_SYS_CLOCK_TICKS_PER_SEC,
473 "Set SYS_CLOCK_TICKS_PER_SEC to CONFIG_STM32_LPTIM_CLOCK/lptim_clock_presc");
474 }
475 #endif /* !CONFIG_STM32_LPTIM_TICK_FREQ_RATIO_OVERRIDE */
476
477 /* Actual lptim clock freq when the clock source is reduced by the prescaler */
478 lptim_clock_freq = lptim_clock_freq / lptim_clock_presc;
479
480 /* Clear the event flag and possible pending interrupt */
481 IRQ_CONNECT(DT_INST_IRQN(0),
482 DT_INST_IRQ(0, priority),
483 lptim_irq_handler, 0, 0);
484 irq_enable(DT_INST_IRQN(0));
485
486 #ifdef CONFIG_SOC_SERIES_STM32WLX
487 /* Enable the LPTIM wakeup EXTI line */
488 LL_EXTI_EnableIT_0_31(LL_EXTI_LINE_29);
489 #endif
490
491 /* configure the LPTIM counter */
492 LL_LPTIM_SetClockSource(LPTIM, LL_LPTIM_CLK_SOURCE_INTERNAL);
493 /* the LPTIM clock freq is affected by the prescaler */
494 LL_LPTIM_SetPrescaler(LPTIM, (__CLZ(__RBIT(lptim_clock_presc)) << LPTIM_CFGR_PRESC_Pos));
495
496 #if defined(CONFIG_SOC_SERIES_STM32U5X) || \
497 defined(CONFIG_SOC_SERIES_STM32H5X) || \
498 defined(CONFIG_SOC_SERIES_STM32WBAX)
499 LL_LPTIM_OC_SetPolarity(LPTIM, LL_LPTIM_CHANNEL_CH1,
500 LL_LPTIM_OUTPUT_POLARITY_REGULAR);
501 #else
502 LL_LPTIM_SetPolarity(LPTIM, LL_LPTIM_OUTPUT_POLARITY_REGULAR);
503 #endif
504 LL_LPTIM_SetUpdateMode(LPTIM, LL_LPTIM_UPDATE_MODE_IMMEDIATE);
505 LL_LPTIM_SetCounterMode(LPTIM, LL_LPTIM_COUNTER_MODE_INTERNAL);
506 LL_LPTIM_DisableTimeout(LPTIM);
507 /* counting start is initiated by software */
508 LL_LPTIM_TrigSw(LPTIM);
509
510 #if defined(CONFIG_SOC_SERIES_STM32U5X) || \
511 defined(CONFIG_SOC_SERIES_STM32H5X) || \
512 defined(CONFIG_SOC_SERIES_STM32WBAX)
513 /* Enable the LPTIM before proceeding with configuration */
514 LL_LPTIM_Enable(LPTIM);
515
516 LL_LPTIM_DisableIT_CC1(LPTIM);
517 stm32_lptim_wait_ready();
518 LL_LPTIM_ClearFLAG_CC1(LPTIM);
519 #else
520 /* LPTIM interrupt set-up before enabling */
521 /* no Compare match Interrupt */
522 LL_LPTIM_DisableIT_CMPM(LPTIM);
523 LL_LPTIM_ClearFLAG_CMPM(LPTIM);
524 #endif
525
526 /* Autoreload match Interrupt */
527 LL_LPTIM_EnableIT_ARRM(LPTIM);
528 stm32_lptim_wait_ready();
529 LL_LPTIM_ClearFLAG_ARRM(LPTIM);
530
531 /* ARROK bit validates the write operation to ARR register */
532 LL_LPTIM_EnableIT_ARROK(LPTIM);
533 stm32_lptim_wait_ready();
534 LL_LPTIM_ClearFlag_ARROK(LPTIM);
535
536 #if !defined(CONFIG_SOC_SERIES_STM32U5X) && \
537 !defined(CONFIG_SOC_SERIES_STM32H5X) && \
538 !defined(CONFIG_SOC_SERIES_STM32WBAX)
539 /* Enable the LPTIM counter */
540 LL_LPTIM_Enable(LPTIM);
541 #endif
542
543 /* Set the Autoreload value once the timer is enabled */
544 if (IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
545 /* LPTIM is triggered on a LPTIM_TIMEBASE period */
546 lptim_set_autoreload(lptim_time_base);
547 } else {
548 /* nb of LPTIM counter unit per kernel tick (depends on lptim clock prescaler) */
549 count_per_tick = (lptim_clock_freq / CONFIG_SYS_CLOCK_TICKS_PER_SEC);
550 /* LPTIM is triggered on a Tick period */
551 lptim_set_autoreload(count_per_tick - 1);
552 }
553
554 /* Start the LPTIM counter in continuous mode */
555 LL_LPTIM_StartCounter(LPTIM, LL_LPTIM_OPERATING_MODE_CONTINUOUS);
556
557 #ifdef CONFIG_DEBUG
558 /* stop LPTIM during DEBUG */
559 #if defined(LL_DBGMCU_APB1_GRP1_LPTIM1_STOP)
560 LL_DBGMCU_APB1_GRP1_FreezePeriph(LL_DBGMCU_APB1_GRP1_LPTIM1_STOP);
561 #elif defined(LL_DBGMCU_APB3_GRP1_LPTIM1_STOP)
562 LL_DBGMCU_APB3_GRP1_FreezePeriph(LL_DBGMCU_APB3_GRP1_LPTIM1_STOP);
563 #endif
564
565 #endif
566 return 0;
567 }
568
stm32_clock_control_standby_exit(void)569 void stm32_clock_control_standby_exit(void)
570 {
571 #ifdef CONFIG_STM32_LPTIM_STDBY_TIMER
572 if (clock_control_get_status(clk_ctrl,
573 (clock_control_subsys_t) &lptim_clk[0])
574 != CLOCK_CONTROL_STATUS_ON) {
575 sys_clock_driver_init();
576 }
577 #endif /* CONFIG_STM32_LPTIM_STDBY_TIMER */
578 }
579
sys_clock_idle_exit(void)580 void sys_clock_idle_exit(void)
581 {
582 #ifdef CONFIG_STM32_LPTIM_STDBY_TIMER
583 if (timeout_stdby) {
584 cycle_t missed_lptim_cnt;
585 uint32_t stdby_timer_diff, stdby_timer_post, dticks;
586 uint64_t stdby_timer_us;
587
588 /* Get current value for standby timer and reset LPTIM counter value
589 * to start anew.
590 */
591 LL_LPTIM_ResetCounter(LPTIM);
592 counter_get_value(stdby_timer, &stdby_timer_post);
593
594 /* Calculate how much time has passed since last measurement for standby timer */
595 /* Check IDLE timer overflow */
596 if (stdby_timer_pre_stdby > stdby_timer_post) {
597 stdby_timer_diff =
598 (counter_get_top_value(stdby_timer) - stdby_timer_pre_stdby) +
599 stdby_timer_post + 1;
600
601 } else {
602 stdby_timer_diff = stdby_timer_post - stdby_timer_pre_stdby;
603 }
604 stdby_timer_us = counter_ticks_to_us(stdby_timer, stdby_timer_diff);
605
606 /* Convert standby time in LPTIM cnt */
607 missed_lptim_cnt = (sys_clock_hw_cycles_per_sec() * stdby_timer_us) /
608 USEC_PER_SEC;
609 /* Add the LPTIM cnt pre standby */
610 missed_lptim_cnt += lptim_cnt_pre_stdby;
611
612 /* Update the cycle counter to include the cycles missed in standby */
613 accumulated_lptim_cnt += missed_lptim_cnt;
614
615 /* Announce the passed ticks to the kernel */
616 dticks = (missed_lptim_cnt * CONFIG_SYS_CLOCK_TICKS_PER_SEC)
617 / lptim_clock_freq;
618 sys_clock_announce(dticks);
619
620 /* We've already performed all needed operations */
621 timeout_stdby = false;
622 }
623 #endif /* CONFIG_STM32_LPTIM_STDBY_TIMER */
624 }
625
626 SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2,
627 CONFIG_SYSTEM_CLOCK_INIT_PRIORITY);
628