1 /*
2  * Copyright (c) 2016 Nordic Semiconductor ASA
3  * Copyright (c) 2016 Vinayak Kariappa Chettimada
4  * Copyright 2019 NXP
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #include <stdint.h>
10 
11 #include <zephyr/dt-bindings/interrupt-controller/openisa-intmux.h>
12 
13 #include "hal/cntr.h"
14 #include "hal/debug.h"
15 
16 #include "ll_irqs.h"
17 
18 #include <fsl_device_registers.h>
19 
20 #define PCS_SOURCE_RTC 2
21 
cntr_init(void)22 void cntr_init(void)
23 {
24 	/* RTC config */
25 	/*
26 	 * Reset all RTC registers except for the SWR bit
27 	 * and the RTC_WAR and RTC_RAR
28 	 */
29 	RTC->CR |= RTC_CR_SWR_MASK;
30 	RTC->CR &= ~RTC_CR_SWR_MASK;
31 
32 	/*
33 	 * Set TSR register to 0x1 to avoid the timer invalid (TIF) bit being
34 	 * set in the SR register
35 	 */
36 	RTC->TSR = 1;
37 
38 	/* Enable the RTC 32.768 kHz oscillator and clock on RTC_CLKOUT  */
39 	RTC->CR |= (RTC_CR_CPS(1) | RTC_CR_OSCE(1));
40 
41 	/* LPTMR config */
42 	/* Disable the timer and clear any pending IRQ. */
43 	LPTMR1->CSR = LPTMR_CSR_TEN(0);
44 
45 	/*
46 	 * TMS = 0: time counter mode, not pulse counter
47 	 * TFC = 1: reset counter on overflow
48 	 * TIE = 1: enable interrupt
49 	 */
50 	LPTMR1->CSR = (LPTMR_CSR_TFC(1) | LPTMR_CSR_TIE(1));
51 
52 	/*
53 	 * PCS = 2: clock source is RTC - 32 kHz clock (SoC dependent)
54 	 * PBYP = 1: bypass the prescaler
55 	 */
56 	LPTMR1->PSR = (LPTMR_PSR_PBYP(1) | LPTMR_PSR_PCS(PCS_SOURCE_RTC));
57 
58 	irq_enable(LL_RTC0_IRQn_2nd_lvl);
59 }
60 
61 static uint8_t refcount;
62 static uint32_t cnt_diff;
63 
cntr_start(void)64 uint32_t cntr_start(void)
65 {
66 	if (refcount++) {
67 		return 1;
68 	}
69 
70 	LPTMR1->CMR = 0xFFFFFFFF;
71 	LPTMR1->CSR |= LPTMR_CSR_TEN(1);
72 
73 	return 0;
74 }
75 
cntr_stop(void)76 uint32_t cntr_stop(void)
77 {
78 	LL_ASSERT(refcount);
79 
80 	if (--refcount) {
81 		return 1;
82 	}
83 
84 	cnt_diff = cntr_cnt_get();
85 	/*
86 	 * When TEN is clear, it resets the LPTMR internal logic,
87 	 * including the CNR and TCF.
88 	 */
89 	LPTMR1->CSR &= ~LPTMR_CSR_TEN_MASK;
90 
91 	return 0;
92 }
93 
cntr_cnt_get(void)94 uint32_t cntr_cnt_get(void)
95 {
96 	/*
97 	 * On each read of the CNR,
98 	 * software must first write to the CNR with any value.
99 	 */
100 	LPTMR1->CNR = 0;
101 	return (LPTMR1->CNR + cnt_diff);
102 }
103 
cntr_cmp_set(uint8_t cmp,uint32_t value)104 void cntr_cmp_set(uint8_t cmp, uint32_t value)
105 {
106 	/*
107 	 * When the LPTMR is enabled, the first increment will take an
108 	 * additional one or two prescaler clock cycles due to
109 	 * synchronization logic.
110 	 */
111 	cnt_diff = cntr_cnt_get() + 1;
112 	LPTMR1->CSR &= ~LPTMR_CSR_TEN_MASK;
113 
114 	value -= cnt_diff;
115 	/*
116 	 * If the CMR is 0, the hardware trigger will remain asserted until
117 	 * the LPTMR is disabled. If the LPTMR is enabled, the CMR must be
118 	 * altered only when TCF is set.
119 	 */
120 	if (value == 0) {
121 		value = 1;
122 	}
123 
124 	LPTMR1->CMR = value;
125 	LPTMR1->CSR |= LPTMR_CSR_TEN(1);
126 }
127