1 /*
2 * Copyright (c) 2018 omSquare s.r.o.
3 * Copyright (c) 2024 Gerson Fernando Budke <nandojve@gmail.com>
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #define DT_DRV_COMPAT atmel_sam0_rtc
9
10 /**
11 * @file
12 * @brief Atmel SAM0 series RTC-based system timer
13 *
14 * This system timer implementation supports both tickless and ticking modes.
15 * In tickless mode, RTC counts continually in 32-bit mode and timeouts are
16 * scheduled using the RTC comparator. In ticking mode, RTC is configured to
17 * generate an interrupt every tick.
18 */
19
20 #include <zephyr/init.h>
21 #include <soc.h>
22 #include <zephyr/drivers/clock_control.h>
23 #include <zephyr/drivers/timer/system_timer.h>
24 #include <zephyr/drivers/pinctrl.h>
25 #include <zephyr/sys_clock.h>
26 #include <zephyr/irq.h>
27 #include <zephyr/sys/util.h>
28
29 /* clang-format off */
30
31 /* RTC registers. */
32 #define RTC0 ((RtcMode0 *) DT_INST_REG_ADDR(0))
33
34 #ifdef MCLK
35 #define RTC_CLOCK_HW_CYCLES_PER_SEC SOC_ATMEL_SAM0_OSC32K_FREQ_HZ
36 #else
37 #define RTC_CLOCK_HW_CYCLES_PER_SEC SOC_ATMEL_SAM0_GCLK0_FREQ_HZ
38 #endif
39
40 /* Number of sys timer cycles per on tick. */
41 #define CYCLES_PER_TICK (RTC_CLOCK_HW_CYCLES_PER_SEC \
42 / CONFIG_SYS_CLOCK_TICKS_PER_SEC)
43
44 /* Maximum number of ticks. */
45 #define MAX_TICKS (UINT32_MAX / CYCLES_PER_TICK - 2)
46
47 #ifdef CONFIG_TICKLESS_KERNEL
48
49 /*
50 * Due to the nature of clock synchronization, reading from or writing to some
51 * RTC registers takes approximately six RTC_GCLK cycles. This constant defines
52 * a safe threshold for the comparator.
53 */
54 #define TICK_THRESHOLD 7
55
56 BUILD_ASSERT(CYCLES_PER_TICK > TICK_THRESHOLD,
57 "CYCLES_PER_TICK must be greater than TICK_THRESHOLD for "
58 "tickless mode");
59
60 #else /* !CONFIG_TICKLESS_KERNEL */
61
62 /*
63 * For some reason, RTC does not generate interrupts when COMP == 0,
64 * MATCHCLR == 1 and PRESCALER == 0. So we need to check that CYCLES_PER_TICK
65 * is more than one.
66 */
67 BUILD_ASSERT(CYCLES_PER_TICK > 1,
68 "CYCLES_PER_TICK must be greater than 1 for ticking mode");
69
70 #endif /* CONFIG_TICKLESS_KERNEL */
71
72 /* Tick/cycle count of the last announce call. */
73 static volatile uint32_t rtc_last;
74
75 #ifndef CONFIG_TICKLESS_KERNEL
76
77 /* Current tick count. */
78 static volatile uint32_t rtc_counter;
79
80 /* Tick value of the next timeout. */
81 static volatile uint32_t rtc_timeout;
82
83 PINCTRL_DT_INST_DEFINE(0);
84 static const struct pinctrl_dev_config *pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0);
85
86 #endif /* CONFIG_TICKLESS_KERNEL */
87
88 /*
89 * Waits for RTC bus synchronization.
90 */
rtc_sync(void)91 static inline void rtc_sync(void)
92 {
93 /* Wait for bus synchronization... */
94 #ifdef RTC_STATUS_SYNCBUSY
95 while (RTC0->STATUS.reg & RTC_STATUS_SYNCBUSY) {
96 }
97 #else
98 while (RTC0->SYNCBUSY.reg) {
99 }
100 #endif
101 }
102
103 /*
104 * Reads RTC COUNT register. First a read request must be written to READREQ,
105 * then - when bus synchronization completes - the COUNT register is read and
106 * returned.
107 */
rtc_count(void)108 static uint32_t rtc_count(void)
109 {
110 #ifdef RTC_READREQ_RREQ
111 RTC0->READREQ.reg = RTC_READREQ_RREQ;
112 #endif
113 rtc_sync();
114 return RTC0->COUNT.reg;
115 }
116
rtc_reset(void)117 static void rtc_reset(void)
118 {
119 rtc_sync();
120
121 /* Disable interrupt. */
122 RTC0->INTENCLR.reg = RTC_MODE0_INTENCLR_MASK;
123 /* Clear interrupt flag. */
124 RTC0->INTFLAG.reg = RTC_MODE0_INTFLAG_MASK;
125
126 /* Disable RTC module. */
127 #ifdef RTC_MODE0_CTRL_ENABLE
128 RTC0->CTRL.reg &= ~RTC_MODE0_CTRL_ENABLE;
129 #else
130 RTC0->CTRLA.reg &= ~RTC_MODE0_CTRLA_ENABLE;
131 #endif
132
133 rtc_sync();
134
135 /* Initiate software reset. */
136 #ifdef RTC_MODE0_CTRL_SWRST
137 RTC0->CTRL.bit.SWRST = 1;
138 while (RTC0->CTRL.bit.SWRST) {
139 }
140 #else
141 RTC0->CTRLA.bit.SWRST = 1;
142 while (RTC0->CTRLA.bit.SWRST) {
143 }
144 #endif
145 }
146
rtc_isr(const void * arg)147 static void rtc_isr(const void *arg)
148 {
149 ARG_UNUSED(arg);
150
151 /* Read and clear the interrupt flag register. */
152 uint16_t status = RTC0->INTFLAG.reg;
153
154 RTC0->INTFLAG.reg = status;
155
156 #ifdef CONFIG_TICKLESS_KERNEL
157
158 /* Read the current counter and announce the elapsed time in ticks. */
159 uint32_t count = rtc_count();
160
161 if (count != rtc_last) {
162 uint32_t ticks = (count - rtc_last) / CYCLES_PER_TICK;
163
164 sys_clock_announce(ticks);
165 rtc_last += ticks * CYCLES_PER_TICK;
166 }
167
168 #else /* !CONFIG_TICKLESS_KERNEL */
169
170 if (status) {
171 /* RTC just ticked one more tick... */
172 if (++rtc_counter == rtc_timeout) {
173 sys_clock_announce(rtc_counter - rtc_last);
174 rtc_last = rtc_counter;
175 }
176 } else {
177 /* ISR was invoked directly from sys_clock_set_timeout. */
178 sys_clock_announce(0);
179 }
180
181 #endif /* CONFIG_TICKLESS_KERNEL */
182 }
183
sys_clock_set_timeout(int32_t ticks,bool idle)184 void sys_clock_set_timeout(int32_t ticks, bool idle)
185 {
186 ARG_UNUSED(idle);
187
188 #ifdef CONFIG_TICKLESS_KERNEL
189
190 ticks = (ticks == K_TICKS_FOREVER) ? MAX_TICKS : ticks;
191 ticks = CLAMP(ticks - 1, 0, (int32_t) MAX_TICKS);
192
193 /* Compute number of RTC cycles until the next timeout. */
194 uint32_t count = rtc_count();
195 uint32_t timeout = ticks * CYCLES_PER_TICK + count % CYCLES_PER_TICK;
196
197 /* Round to the nearest tick boundary. */
198 timeout = DIV_ROUND_UP(timeout, CYCLES_PER_TICK) * CYCLES_PER_TICK;
199
200 if (timeout < TICK_THRESHOLD) {
201 timeout += CYCLES_PER_TICK;
202 }
203
204 rtc_sync();
205 RTC0->COMP[0].reg = count + timeout;
206
207 #else /* !CONFIG_TICKLESS_KERNEL */
208
209 if (ticks == K_TICKS_FOREVER) {
210 /* Disable comparator for K_TICKS_FOREVER and other negative
211 * values.
212 */
213 rtc_timeout = rtc_counter;
214 return;
215 }
216
217 if (ticks < 1) {
218 ticks = 1;
219 }
220
221 /* Avoid race condition between reading counter and ISR incrementing
222 * it.
223 */
224 unsigned int key = irq_lock();
225
226 rtc_timeout = rtc_counter + ticks;
227 irq_unlock(key);
228
229 #endif /* CONFIG_TICKLESS_KERNEL */
230 }
231
sys_clock_elapsed(void)232 uint32_t sys_clock_elapsed(void)
233 {
234 #ifdef CONFIG_TICKLESS_KERNEL
235 return (rtc_count() - rtc_last) / CYCLES_PER_TICK;
236 #else
237 return rtc_counter - rtc_last;
238 #endif
239 }
240
sys_clock_cycle_get_32(void)241 uint32_t sys_clock_cycle_get_32(void)
242 {
243 /* Just return the absolute value of RTC cycle counter. */
244 return rtc_count();
245 }
246
247 #define ASSIGNED_CLOCKS_CELL_BY_NAME \
248 ATMEL_SAM0_DT_INST_ASSIGNED_CLOCKS_CELL_BY_NAME
249
sys_clock_driver_init(void)250 static int sys_clock_driver_init(void)
251 {
252 volatile uint32_t *mclk = ATMEL_SAM0_DT_INST_MCLK_PM_REG_ADDR_OFFSET(0);
253 uint32_t mclk_mask = ATMEL_SAM0_DT_INST_MCLK_PM_PERIPH_MASK(0, bit);
254
255 *mclk |= mclk_mask;
256
257 #ifdef MCLK
258 OSC32KCTRL->RTCCTRL.reg = OSC32KCTRL_RTCCTRL_RTCSEL_ULP32K;
259 #else
260 GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN
261 | GCLK_CLKCTRL_GEN(ASSIGNED_CLOCKS_CELL_BY_NAME(0, gclk, gen))
262 | GCLK_CLKCTRL_ID(DT_INST_CLOCKS_CELL_BY_NAME(0, gclk, id));
263
264 /* Synchronize GCLK. */
265 while (GCLK->STATUS.bit.SYNCBUSY) {
266 }
267 #endif
268
269 #ifndef CONFIG_TICKLESS_KERNEL
270 int retval = pinctrl_apply_state(pcfg, PINCTRL_STATE_DEFAULT);
271
272 if (retval < 0 && retval != -ENOENT) {
273 return retval;
274 }
275 #endif
276
277 /* Reset module to hardware defaults. */
278 rtc_reset();
279
280 rtc_last = 0U;
281
282 /* Configure RTC with 32-bit mode, configured prescaler and MATCHCLR. */
283 #ifdef RTC_MODE0_CTRL_MODE
284 uint16_t ctrl = RTC_MODE0_CTRL_MODE(0) | RTC_MODE0_CTRL_PRESCALER(0);
285 #else
286 uint16_t ctrl = RTC_MODE0_CTRLA_MODE(0) | RTC_MODE0_CTRLA_PRESCALER(0);
287 #endif
288
289 #ifdef RTC_MODE0_CTRLA_COUNTSYNC
290 ctrl |= RTC_MODE0_CTRLA_COUNTSYNC;
291 #endif
292
293 #ifndef CONFIG_TICKLESS_KERNEL
294 #ifdef RTC_MODE0_CTRL_MATCHCLR
295 ctrl |= RTC_MODE0_CTRL_MATCHCLR;
296 #else
297 ctrl |= RTC_MODE0_CTRLA_MATCHCLR;
298 #endif
299 #endif
300 rtc_sync();
301 #ifdef RTC_MODE0_CTRL_MODE
302 RTC0->CTRL.reg = ctrl;
303 #else
304 RTC0->CTRLA.reg = ctrl;
305 #endif
306
307 #ifdef CONFIG_TICKLESS_KERNEL
308 /* Tickless kernel lets RTC count continually and ignores overflows. */
309 RTC0->INTENSET.reg = RTC_MODE0_INTENSET_CMP0;
310 #else
311 /* Non-tickless mode uses comparator together with MATCHCLR. */
312 rtc_sync();
313 RTC0->COMP[0].reg = CYCLES_PER_TICK;
314 RTC0->INTENSET.reg = RTC_MODE0_INTENSET_OVF;
315 rtc_counter = 0U;
316 rtc_timeout = 0U;
317 #endif
318
319 /* Enable RTC module. */
320 rtc_sync();
321 #ifdef RTC_MODE0_CTRL_ENABLE
322 RTC0->CTRL.reg |= RTC_MODE0_CTRL_ENABLE;
323 #else
324 RTC0->CTRLA.reg |= RTC_MODE0_CTRLA_ENABLE;
325 #endif
326
327 /* Enable RTC interrupt. */
328 NVIC_ClearPendingIRQ(DT_INST_IRQN(0));
329 IRQ_CONNECT(DT_INST_IRQN(0),
330 DT_INST_IRQ(0, priority), rtc_isr, 0, 0);
331 irq_enable(DT_INST_IRQN(0));
332
333 return 0;
334 }
335
336 SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2,
337 CONFIG_SYSTEM_CLOCK_INIT_PRIORITY);
338
339 /* clang-format on */
340