1 /******************************************************************************
2 *
3 * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by
4 * Analog Devices, Inc.),
5 * Copyright (C) 2023-2024 Analog Devices, Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 ******************************************************************************/
20
21 /* **** Includes **** */
22 #include "mxc_device.h"
23 #include "mxc_assert.h"
24 #include "wut.h"
25 #include "wut_reva.h"
26
27 /* **** Definitions **** */
28
29 /* **** Globals **** */
30
31 /* **** Local Variables **** */
32 static uint32_t wut_count;
33 static uint32_t wut_snapshot;
34
35 /* **** Functions **** */
36
37 /* ************************************************************************** */
MXC_WUT_RevA_Init(mxc_wut_reva_regs_t * wut,mxc_wut_reva_pres_t pres)38 void MXC_WUT_RevA_Init(mxc_wut_reva_regs_t *wut, mxc_wut_reva_pres_t pres)
39 {
40 // Disable timer and clear settings
41 wut->ctrl = 0;
42
43 // Clear interrupt flag
44 wut->intfl = MXC_F_WUT_REVA_INTFL_IRQ_CLR;
45
46 // Set the prescaler
47 wut->ctrl |= pres;
48
49 // Initialize the compare register
50 wut->cmp = 0xFFFFFFFF;
51
52 // Initialize the local variables
53 wut_count = 0;
54 wut_snapshot = 0;
55 }
56
MXC_WUT_RevA_Shutdown(mxc_wut_reva_regs_t * wut)57 void MXC_WUT_RevA_Shutdown(mxc_wut_reva_regs_t *wut)
58 {
59 // Disable timer and clear settings
60 wut->ctrl = 0;
61 }
62
63 /* ************************************************************************** */
MXC_WUT_RevA_Enable(mxc_wut_reva_regs_t * wut)64 void MXC_WUT_RevA_Enable(mxc_wut_reva_regs_t *wut)
65 {
66 wut->ctrl |= MXC_F_WUT_REVA_CTRL_TEN;
67 }
68
69 /* ************************************************************************** */
MXC_WUT_RevA_Disable(mxc_wut_reva_regs_t * wut)70 void MXC_WUT_RevA_Disable(mxc_wut_reva_regs_t *wut)
71 {
72 wut->ctrl &= ~(MXC_F_WUT_REVA_CTRL_TEN);
73 }
74
75 /* ************************************************************************** */
MXC_WUT_RevA_Config(mxc_wut_reva_regs_t * wut,const mxc_wut_reva_cfg_t * cfg)76 void MXC_WUT_RevA_Config(mxc_wut_reva_regs_t *wut, const mxc_wut_reva_cfg_t *cfg)
77 {
78 // Configure the timer
79 uint32_t wut_ctrl = wut->ctrl;
80 wut->ctrl |= (wut_ctrl & ~(MXC_F_WUT_REVA_CTRL_TMODE | MXC_F_WUT_REVA_CTRL_TPOL)) |
81 ((cfg->mode << MXC_F_WUT_REVA_CTRL_TMODE_POS) & MXC_F_WUT_REVA_CTRL_TMODE);
82
83 wut->cnt = 0x1;
84
85 wut->cmp = cfg->cmp_cnt;
86 }
87
88 /* ************************************************************************** */
MXC_WUT_RevA_GetCompare(mxc_wut_reva_regs_t * wut)89 uint32_t MXC_WUT_RevA_GetCompare(mxc_wut_reva_regs_t *wut)
90 {
91 return wut->cmp;
92 }
93
94 /* ************************************************************************** */
MXC_WUT_RevA_GetCapture(mxc_wut_reva_regs_t * wut)95 uint32_t MXC_WUT_RevA_GetCapture(mxc_wut_reva_regs_t *wut)
96 {
97 return wut->pwm;
98 }
99
100 /* ************************************************************************* */
MXC_WUT_RevA_GetCount(mxc_wut_reva_regs_t * wut)101 uint32_t MXC_WUT_RevA_GetCount(mxc_wut_reva_regs_t *wut)
102 {
103 return wut->cnt;
104 }
105
106 /* ************************************************************************* */
MXC_WUT_RevA_IntClear(mxc_wut_reva_regs_t * wut)107 void MXC_WUT_RevA_IntClear(mxc_wut_reva_regs_t *wut)
108 {
109 wut->intfl = MXC_F_WUT_REVA_INTFL_IRQ_CLR;
110 }
111
112 /* ************************************************************************* */
MXC_WUT_RevA_IntStatus(mxc_wut_reva_regs_t * wut)113 uint32_t MXC_WUT_RevA_IntStatus(mxc_wut_reva_regs_t *wut)
114 {
115 return wut->intfl;
116 }
117
118 /* ************************************************************************* */
MXC_WUT_RevA_SetCompare(mxc_wut_reva_regs_t * wut,uint32_t cmp_cnt)119 void MXC_WUT_RevA_SetCompare(mxc_wut_reva_regs_t *wut, uint32_t cmp_cnt)
120 {
121 wut->cmp = cmp_cnt;
122 }
123
124 /* ************************************************************************* */
MXC_WUT_RevA_SetCount(mxc_wut_reva_regs_t * wut,uint32_t cnt)125 void MXC_WUT_RevA_SetCount(mxc_wut_reva_regs_t *wut, uint32_t cnt)
126 {
127 wut->cnt = cnt;
128 }
129
130 /* ************************************************************************* */
MXC_WUT_RevA_GetTicks(mxc_wut_reva_regs_t * wut,uint32_t timerClock,uint32_t time,mxc_wut_reva_unit_t units,uint32_t * ticks)131 int MXC_WUT_RevA_GetTicks(mxc_wut_reva_regs_t *wut, uint32_t timerClock, uint32_t time,
132 mxc_wut_reva_unit_t units, uint32_t *ticks)
133 {
134 uint32_t unit_div0, unit_div1;
135 uint32_t prescale;
136 uint64_t temp_ticks;
137
138 uint32_t wut_ctrl = wut->ctrl;
139
140 prescale = ((wut_ctrl & MXC_F_WUT_REVA_CTRL_PRES) >> MXC_F_WUT_REVA_CTRL_PRES_POS) |
141 (((wut_ctrl & MXC_F_WUT_REVA_CTRL_PRES3) >> (MXC_F_WUT_REVA_CTRL_PRES3_POS)) << 3);
142
143 switch (units) {
144 case MXC_WUT_REVA_UNIT_NANOSEC:
145 unit_div0 = 1000000;
146 unit_div1 = 1000;
147 break;
148
149 case MXC_WUT_REVA_UNIT_MICROSEC:
150 unit_div0 = 1000;
151 unit_div1 = 1000;
152 break;
153
154 case MXC_WUT_REVA_UNIT_MILLISEC:
155 unit_div0 = 1;
156 unit_div1 = 1000;
157 break;
158
159 case MXC_WUT_REVA_UNIT_SEC:
160 unit_div0 = 1;
161 unit_div1 = 1;
162 break;
163
164 default:
165 return E_BAD_PARAM;
166 }
167
168 temp_ticks = (uint64_t)time * (timerClock / unit_div0) / (unit_div1 * (1 << (prescale & 0xF)));
169
170 //make sure ticks is within a 32 bit value
171 if (!(temp_ticks & 0xffffffff00000000) && (temp_ticks & 0xffffffff)) {
172 *ticks = temp_ticks;
173 return E_NO_ERROR;
174 }
175
176 return E_INVALID;
177 }
178
179 /* ************************************************************************* */
MXC_WUT_RevA_GetTime(mxc_wut_reva_regs_t * wut,uint32_t timerClock,uint32_t ticks,uint32_t * time,mxc_wut_reva_unit_t * units)180 int MXC_WUT_RevA_GetTime(mxc_wut_reva_regs_t *wut, uint32_t timerClock, uint32_t ticks,
181 uint32_t *time, mxc_wut_reva_unit_t *units)
182 {
183 uint64_t temp_time = 0;
184 uint32_t wut_ctrl = wut->ctrl;
185 uint32_t prescale =
186 ((wut_ctrl & MXC_F_WUT_REVA_CTRL_PRES) >> MXC_F_WUT_REVA_CTRL_PRES_POS) |
187 (((wut_ctrl & MXC_F_WUT_REVA_CTRL_PRES3) >> (MXC_F_WUT_REVA_CTRL_PRES3_POS)) << 3);
188
189 temp_time = (uint64_t)ticks * 1000 * (1 << (prescale & 0xF)) / (timerClock / 1000000);
190
191 if (!(temp_time & 0xffffffff00000000)) {
192 *time = temp_time;
193 *units = MXC_WUT_REVA_UNIT_NANOSEC;
194 return E_NO_ERROR;
195 }
196
197 temp_time = (uint64_t)ticks * 1000 * (1 << (prescale & 0xF)) / (timerClock / 1000);
198
199 if (!(temp_time & 0xffffffff00000000)) {
200 *time = temp_time;
201 *units = MXC_WUT_REVA_UNIT_MICROSEC;
202 return E_NO_ERROR;
203 }
204
205 temp_time = (uint64_t)ticks * 1000 * (1 << (prescale & 0xF)) / timerClock;
206
207 if (!(temp_time & 0xffffffff00000000)) {
208 *time = temp_time;
209 *units = MXC_WUT_REVA_UNIT_MILLISEC;
210 return E_NO_ERROR;
211 }
212
213 temp_time = (uint64_t)ticks * (1 << (prescale & 0xF)) / timerClock;
214
215 if (!(temp_time & 0xffffffff00000000)) {
216 *time = temp_time;
217 *units = MXC_WUT_REVA_UNIT_SEC;
218 return E_NO_ERROR;
219 }
220
221 return E_INVALID;
222 }
223
224 /* ************************************************************************** */
MXC_WUT_RevA_Edge(mxc_wut_reva_regs_t * wut)225 void MXC_WUT_RevA_Edge(mxc_wut_reva_regs_t *wut)
226 {
227 // Wait for a WUT edge
228 uint32_t tmp = wut->cnt;
229
230 while (tmp == wut->cnt) {}
231 }
232
233 /* ************************************************************************** */
MXC_WUT_RevA_GetSleepTicks(mxc_wut_reva_regs_t * wut)234 uint32_t MXC_WUT_RevA_GetSleepTicks(mxc_wut_reva_regs_t *wut)
235 {
236 return (wut->cnt - wut_count);
237 }
238
239 /* ************************************************************************** */
MXC_WUT_RevA_Store(mxc_wut_reva_regs_t * wut)240 void MXC_WUT_RevA_Store(mxc_wut_reva_regs_t *wut)
241 {
242 MXC_WUT_RevA_Edge(wut);
243 wut_count = wut->cnt;
244 wut_snapshot = wut->snapshot;
245 }
246
247 /* ************************************************************************** */
MXC_WUT_RevA_RestoreBBClock(mxc_wut_reva_regs_t * wut,uint32_t dbbFreq,uint32_t timerClock)248 void MXC_WUT_RevA_RestoreBBClock(mxc_wut_reva_regs_t *wut, uint32_t dbbFreq, uint32_t timerClock)
249 {
250 /* restore DBB clock from WUT */
251 MXC_WUT_RevA_Edge(wut);
252 wut->preset = wut_snapshot + (uint64_t)(wut->cnt - wut_count + 1) * dbbFreq / timerClock;
253 wut->reload = 1; // arm DBB_CNT update on the next rising WUT clock
254 MXC_WUT_RevA_Edge(wut);
255 }
256
257 /* ************************************************************************** */
MXC_WUT_RevA_Delay_MS(mxc_wut_reva_regs_t * wut,uint32_t waitMs,uint32_t timerClock)258 void MXC_WUT_RevA_Delay_MS(mxc_wut_reva_regs_t *wut, uint32_t waitMs, uint32_t timerClock)
259 {
260 /* assume WUT is already running */
261 uint32_t tmp = wut->cnt;
262
263 tmp += (waitMs * (timerClock / (0x1 << ((wut->ctrl & MXC_F_WUT_REVA_CTRL_PRES) >>
264 MXC_F_WUT_REVA_CTRL_PRES_POS))) +
265 500) /
266 1000;
267
268 while (wut->cnt < tmp) {}
269 }
270