1 /*
2 * Copyright (c) 2023 Renesas Electronics Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/device.h>
8 #include <zephyr/drivers/clock_control.h>
9 #include <zephyr/drivers/clock_control/smartbond_clock_control.h>
10 #include <zephyr/drivers/timer/system_timer.h>
11 #include <zephyr/sys_clock.h>
12 #include <zephyr/spinlock.h>
13 #include <cmsis_core.h>
14 #include <zephyr/irq.h>
15 #include <da1469x_pdc.h>
16
17 #define COUNTER_SPAN BIT(24)
18 #define CYC_PER_TICK k_ticks_to_cyc_ceil32(1)
19 #define TICK_TO_CYC(tick) k_ticks_to_cyc_ceil32(tick)
20 #define CYC_TO_TICK(cyc) k_cyc_to_ticks_ceil32(cyc)
21 #define MAX_TICKS (((COUNTER_SPAN / 2) - CYC_PER_TICK) / (CYC_PER_TICK))
22 #define SMARTBOND_CLOCK_CONTROLLER DEVICE_DT_GET(DT_NODELABEL(osc))
23 /* Margin values are based on DA1469x characterization data */
24 #define RC32K_FREQ_POSITIVE_MARGIN_DUE_TO_VOLTAGE (675)
25 #define RC32K_FREQ_MARGIN_DUE_TO_TEMPERATURE (450)
26
27 static uint32_t last_timer_val_reg;
28 static uint32_t timer_val_31_24;
29
30 static uint32_t last_isr_val;
31 static uint32_t last_isr_val_rounded;
32 static uint32_t announced_ticks;
33
get_rc32k_max_frequency(void)34 static uint32_t get_rc32k_max_frequency(void)
35 {
36 /* According to DA1469x datasheet */
37 uint32_t r32k_frequency = 37000;
38
39 clock_control_get_rate(SMARTBOND_CLOCK_CONTROLLER,
40 (clock_control_subsys_t)SMARTBOND_CLK_RC32K, &r32k_frequency);
41
42 r32k_frequency += RC32K_FREQ_POSITIVE_MARGIN_DUE_TO_VOLTAGE +
43 RC32K_FREQ_MARGIN_DUE_TO_TEMPERATURE;
44 return r32k_frequency;
45 }
46
set_reload(uint32_t val)47 static void set_reload(uint32_t val)
48 {
49 TIMER2->TIMER2_RELOAD_REG = val & TIMER2_TIMER2_RELOAD_REG_TIM_RELOAD_Msk;
50 }
51
timer_val_32(void)52 static uint32_t timer_val_32(void)
53 {
54 uint32_t timer_val_reg;
55 uint32_t val;
56
57 timer_val_reg = TIMER2->TIMER2_TIMER_VAL_REG &
58 TIMER2_TIMER2_TIMER_VAL_REG_TIM_TIMER_VALUE_Msk;
59 if (timer_val_reg < last_timer_val_reg) {
60 timer_val_31_24 += COUNTER_SPAN;
61 }
62 last_timer_val_reg = timer_val_reg;
63
64 val = timer_val_31_24 + timer_val_reg;
65
66 return val;
67 }
68
timer_val_32_noupdate(void)69 static uint32_t timer_val_32_noupdate(void)
70 {
71 uint32_t timer_val_reg;
72 uint32_t val;
73
74 timer_val_reg = TIMER2->TIMER2_TIMER_VAL_REG &
75 TIMER2_TIMER2_TIMER_VAL_REG_TIM_TIMER_VALUE_Msk;
76 val = timer_val_31_24 + timer_val_reg;
77 if (timer_val_reg < last_timer_val_reg) {
78 val += COUNTER_SPAN;
79 }
80
81 return val;
82 }
83
sys_clock_set_timeout(int32_t ticks,bool idle)84 void sys_clock_set_timeout(int32_t ticks, bool idle)
85 {
86 uint32_t target_val;
87 uint32_t timer_val;
88
89 if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
90 return;
91 }
92
93 if (ticks == K_TICKS_FOREVER) {
94 /* FIXME we could disable timer here */
95 }
96
97 /*
98 * When Watchdog is NOT enabled but power management is, system
99 * starts watchdog before PD_SYS is powered off.
100 * Watchdog default reload value is 0x1FFF (~82s for RC32K and 172s for RCX).
101 * After this time watchdog will reset system if not woken up before.
102 * When Watchdog is not configured power management freezes watchdog
103 * as soon as system is awaken. Following code makes sure that
104 * system never goes to sleep for longer time that watchdog reload value.
105 */
106 if (IS_ENABLED(CONFIG_PM)) {
107 uint32_t watchdog_expire_ticks;
108
109 if (CRG_TOP->CLK_RCX_REG & CRG_TOP_CLK_RCX_REG_RCX_ENABLE_Msk) {
110 /*
111 * When LP clock is RCX, the watchdog is clocked by RCX clock
112 * divided by 320.
113 */
114 watchdog_expire_ticks = SYS_WDOG->WATCHDOG_REG * 320;
115 } else {
116 /*
117 * When LP clock is not RCX, the watchdog is clocked by RC32K
118 * divided by 320. In this case watchdog value to LP clock
119 * ticks must be calculated according to XTAL32K frequency and
120 * RC32K maximum frequency.
121 */
122 watchdog_expire_ticks = SYS_WDOG->WATCHDOG_REG *
123 CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC /
124 (get_rc32k_max_frequency() / 320);
125 }
126 if (watchdog_expire_ticks - 2 < ticks) {
127 ticks = watchdog_expire_ticks - 2;
128 }
129 }
130 ticks = (ticks == K_TICKS_FOREVER) ? MAX_TICKS : ticks;
131 ticks = CLAMP(ticks - 1, 0, (int32_t)MAX_TICKS);
132
133 timer_val = timer_val_32_noupdate();
134
135 /* Calculate target timer value and align to full tick */
136 target_val = timer_val + TICK_TO_CYC(ticks);
137 target_val = ((target_val + CYC_PER_TICK - 1) / CYC_PER_TICK) * CYC_PER_TICK;
138
139 set_reload(target_val);
140
141 /*
142 * If time was so small that it already fired or should fire
143 * just now, mark interrupt as pending to avoid losing timer event.
144 * Condition is true when target_val (point in time that should be
145 * used for wakeup) is behind timer value or is equal to it.
146 * In that case we don't know if reload value was set in time or
147 * not but time expired anyway so make sure that interrupt is pending.
148 */
149 if ((int32_t)(target_val - timer_val_32_noupdate() - 1) < 0) {
150 NVIC_SetPendingIRQ(TIMER2_IRQn);
151 }
152 }
153
sys_clock_elapsed(void)154 uint32_t sys_clock_elapsed(void)
155 {
156 if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
157 return 0;
158 }
159
160 return CYC_TO_TICK(timer_val_32_noupdate() - last_isr_val);
161 }
162
sys_clock_cycle_get_32(void)163 uint32_t sys_clock_cycle_get_32(void)
164 {
165 return timer_val_32_noupdate();
166 }
167
sys_clock_idle_exit(void)168 void sys_clock_idle_exit(void)
169 {
170 TIMER2->TIMER2_CTRL_REG |= TIMER2_TIMER2_CTRL_REG_TIM_EN_Msk;
171 }
172
sys_clock_disable(void)173 void sys_clock_disable(void)
174 {
175 TIMER2->TIMER2_CTRL_REG &= ~TIMER2_TIMER2_CTRL_REG_TIM_EN_Msk;
176 }
177
timer2_isr(const void * arg)178 static void timer2_isr(const void *arg)
179 {
180 uint32_t val;
181 int32_t delta;
182 int32_t dticks;
183
184 ARG_UNUSED(arg);
185
186 TIMER2->TIMER2_CLEAR_IRQ_REG = 1;
187
188 val = timer_val_32();
189 delta = (int32_t)(val - last_isr_val_rounded);
190 last_isr_val = val;
191 dticks = CYC_TO_TICK(delta);
192 last_isr_val_rounded += TICK_TO_CYC(dticks);
193 announced_ticks += dticks;
194 sys_clock_announce(dticks);
195 }
196
sys_clock_driver_init(void)197 static int sys_clock_driver_init(void)
198 {
199 #if CONFIG_PM
200 uint8_t pdc_idx;
201 uint8_t en_xtal;
202
203 en_xtal = DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(xtal32m)) ? MCU_PDC_EN_XTAL : 0;
204
205 /* Enable wakeup by TIMER2 */
206 pdc_idx = da1469x_pdc_add(MCU_PDC_TRIGGER_TIMER2, MCU_PDC_MASTER_M33, en_xtal);
207 __ASSERT_NO_MSG(pdc_idx >= 0);
208 da1469x_pdc_set(pdc_idx);
209 da1469x_pdc_ack(pdc_idx);
210 #endif
211
212 TIMER2->TIMER2_CTRL_REG = 0;
213 TIMER2->TIMER2_PRESCALER_REG = 0;
214 TIMER2->TIMER2_CTRL_REG |= TIMER2_TIMER2_CTRL_REG_TIM_CLK_EN_Msk;
215 TIMER2->TIMER2_CTRL_REG |= TIMER2_TIMER2_CTRL_REG_TIM_FREE_RUN_MODE_EN_Msk |
216 TIMER2_TIMER2_CTRL_REG_TIM_IRQ_EN_Msk |
217 TIMER2_TIMER2_CTRL_REG_TIM_EN_Msk;
218
219 IRQ_CONNECT(TIMER2_IRQn, _IRQ_PRIO_OFFSET, timer2_isr, 0, 0);
220 irq_enable(TIMER2_IRQn);
221
222 return 0;
223 }
224
225 SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2, CONFIG_SYSTEM_CLOCK_INIT_PRIORITY);
226