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