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 #include <stdio.h>
21 #include "adc.h"
22 #include "dma.h"
23 #include "adc_revb.h"
24 #include "adc_regs.h"
25
26 #include "mxc_device.h"
27 #include "mxc_errors.h"
28 #include "mxc_assert.h"
29 #include "mxc_delay.h"
30 #include "mxc_sys.h"
31 #include "mcr_regs.h"
32 #include "mxc_lock.h"
33
34 // Mask for all Interrupt Enable Fields
35 #define ADC_IE_MASK \
36 (MXC_F_ADC_REVB_INTEN_READY | MXC_F_ADC_REVB_INTEN_ABORT | MXC_F_ADC_REVB_INTEN_START_DET | \
37 MXC_F_ADC_REVB_INTEN_SEQ_STARTED | MXC_F_ADC_REVB_INTEN_SEQ_DONE | \
38 MXC_F_ADC_REVB_INTEN_CONV_DONE | MXC_F_ADC_REVB_INTEN_CLIPPED | \
39 MXC_F_ADC_REVB_INTEN_FIFO_LVL | MXC_F_ADC_REVB_INTEN_FIFO_UFL | \
40 MXC_F_ADC_REVB_INTEN_FIFO_OFL)
41
42 #define ADC_IF_MASK \
43 (MXC_F_ADC_REVB_INTFL_READY | MXC_F_ADC_REVB_INTFL_ABORT | MXC_F_ADC_REVB_INTFL_START_DET | \
44 MXC_F_ADC_REVB_INTFL_SEQ_STARTED | MXC_F_ADC_REVB_INTFL_SEQ_DONE | \
45 MXC_F_ADC_REVB_INTFL_CONV_DONE | MXC_F_ADC_REVB_INTFL_CLIPPED | \
46 MXC_F_ADC_REVB_INTFL_FIFO_LVL | MXC_F_ADC_REVB_INTFL_FIFO_UFL | \
47 MXC_F_ADC_REVB_INTFL_FIFO_OFL)
48
49 static mxc_adc_complete_cb_t async_callback;
50 static mxc_adc_conversion_req_t *async_req;
51 // static volatile uint8_t flag; //indicates to irqhandler where to store data
52
MXC_ADC_RevB_Init(mxc_adc_revb_regs_t * adc,mxc_adc_req_t * req)53 int MXC_ADC_RevB_Init(mxc_adc_revb_regs_t *adc, mxc_adc_req_t *req)
54 {
55 if (req == NULL) {
56 return E_NULL_PTR;
57 }
58
59 if (req->trackCount < 4) {
60 return E_BAD_PARAM;
61 }
62
63 //Enter reset mode
64 adc->ctrl0 &= ~MXC_F_ADC_REVB_CTRL0_RESETB;
65
66 //Power up to Sleep State
67 MXC_SETFIELD(adc->clkctrl, MXC_F_ADC_REVB_CLKCTRL_CLKSEL,
68 (req->clock << MXC_F_ADC_REVB_CLKCTRL_CLKSEL_POS));
69 MXC_SETFIELD(adc->clkctrl, MXC_F_ADC_REVB_CLKCTRL_CLKDIV,
70 (req->clkdiv << MXC_F_ADC_REVB_CLKCTRL_CLKDIV_POS));
71
72 adc->ctrl0 |= MXC_F_ADC_REVB_CTRL0_RESETB;
73
74 //Move to NAP state
75 adc->ctrl0 |= MXC_F_ADC_REVB_CTRL0_BIAS_EN;
76 MXC_Delay(500);
77
78 if (req->cal == MXC_ADC_EN_CAL) {
79 adc->ctrl0 &= ~MXC_F_ADC_REVB_CTRL0_SKIP_CAL;
80 } else {
81 adc->ctrl0 |= MXC_F_ADC_REVB_CTRL0_SKIP_CAL;
82 }
83
84 MXC_SETFIELD(adc->sampclkctrl, MXC_F_ADC_REVB_SAMPCLKCTRL_TRACK_CNT,
85 (req->trackCount << MXC_F_ADC_REVB_SAMPCLKCTRL_TRACK_CNT_POS));
86 MXC_SETFIELD(adc->sampclkctrl, MXC_F_ADC_REVB_SAMPCLKCTRL_IDLE_CNT,
87 (req->idleCount << MXC_F_ADC_REVB_SAMPCLKCTRL_IDLE_CNT_POS));
88
89 adc->ctrl0 |= MXC_F_ADC_REVB_CTRL0_ADC_EN;
90
91 //Wait for 30us
92 MXC_Delay(30);
93
94 //wait for calibration to complete
95 while (!(adc->intfl & MXC_F_ADC_REVB_INTFL_READY)) {}
96
97 async_callback = NULL;
98
99 async_req = NULL;
100
101 return E_NO_ERROR;
102 }
103
MXC_ADC_RevB_Shutdown(mxc_adc_revb_regs_t * adc)104 int MXC_ADC_RevB_Shutdown(mxc_adc_revb_regs_t *adc)
105 {
106 if (async_callback != NULL) {
107 MXC_FreeLock((uint32_t *)&async_callback);
108 }
109
110 if (async_req != NULL) {
111 MXC_FreeLock((uint32_t *)&async_req);
112 }
113
114 adc->ctrl0 &=
115 ~(MXC_F_ADC_REVB_CTRL0_ADC_EN | MXC_F_ADC_REVB_CTRL0_RESETB | MXC_F_ADC_REVB_CTRL0_BIAS_EN);
116
117 return E_NO_ERROR;
118 }
119
MXC_ADC_RevB_EnableInt(mxc_adc_revb_regs_t * adc,uint32_t flags)120 void MXC_ADC_RevB_EnableInt(mxc_adc_revb_regs_t *adc, uint32_t flags)
121 {
122 adc->inten |= (flags & ADC_IE_MASK);
123 }
124
MXC_ADC_RevB_DisableInt(mxc_adc_revb_regs_t * adc,uint32_t flags)125 void MXC_ADC_RevB_DisableInt(mxc_adc_revb_regs_t *adc, uint32_t flags)
126 {
127 adc->inten &= ~(flags & ADC_IE_MASK);
128 }
129
MXC_ADC_RevB_GetFlags(mxc_adc_revb_regs_t * adc)130 int MXC_ADC_RevB_GetFlags(mxc_adc_revb_regs_t *adc)
131 {
132 return (adc->intfl & ADC_IF_MASK);
133 }
134
MXC_ADC_RevB_ClearFlags(mxc_adc_revb_regs_t * adc,uint32_t flags)135 void MXC_ADC_RevB_ClearFlags(mxc_adc_revb_regs_t *adc, uint32_t flags)
136 {
137 // Write 1 to clear flags
138 adc->intfl |= (flags & ADC_IF_MASK);
139 }
140
MXC_ADC_RevB_ClockSelect(mxc_adc_revb_regs_t * adc,mxc_adc_clock_t clock)141 void MXC_ADC_RevB_ClockSelect(mxc_adc_revb_regs_t *adc, mxc_adc_clock_t clock)
142 {
143 MXC_SETFIELD(adc->clkctrl, MXC_F_ADC_REVB_CLKCTRL_CLKSEL,
144 (clock << MXC_F_ADC_REVB_CLKCTRL_CLKSEL_POS));
145 }
146
MXC_ADC_RevB_StartConversion(mxc_adc_revb_regs_t * adc)147 int MXC_ADC_RevB_StartConversion(mxc_adc_revb_regs_t *adc)
148 {
149 adc->fifodmactrl |= MXC_F_ADC_REVB_FIFODMACTRL_FLUSH; //Flush data FIFO
150
151 MXC_ADC_RevB_ClearFlags(adc, ADC_IF_MASK);
152
153 adc->ctrl1 |= MXC_F_ADC_REVB_CTRL1_START;
154
155 return E_NO_ERROR;
156 }
157
MXC_ADC_RevB_StartConversionAsync(mxc_adc_revb_regs_t * adc,mxc_adc_complete_cb_t callback)158 int MXC_ADC_RevB_StartConversionAsync(mxc_adc_revb_regs_t *adc, mxc_adc_complete_cb_t callback)
159 {
160 if (callback == NULL) {
161 return E_BAD_PARAM;
162 }
163
164 adc->fifodmactrl |= MXC_F_ADC_REVB_FIFODMACTRL_FLUSH; //Flush data FIFO
165
166 MXC_ADC_RevB_ClearFlags(adc, ADC_IF_MASK);
167
168 while (MXC_GetLock((uint32_t *)&async_callback, (uint32_t)callback) != E_NO_ERROR) {}
169
170 MXC_ADC_RevB_EnableInt(adc, (MXC_F_ADC_REVB_INTEN_SEQ_DONE | MXC_F_ADC_REVB_INTEN_FIFO_LVL));
171
172 adc->ctrl1 |= MXC_F_ADC_REVB_CTRL1_START;
173
174 return E_NO_ERROR;
175 }
176
MXC_ADC_RevB_StartConversionDMA(mxc_adc_revb_regs_t * adc,mxc_adc_conversion_req_t * req,int * data,void (* callback)(int,int))177 int MXC_ADC_RevB_StartConversionDMA(mxc_adc_revb_regs_t *adc, mxc_adc_conversion_req_t *req,
178 int *data, void (*callback)(int, int))
179 {
180 if (callback == NULL) {
181 return E_BAD_PARAM;
182 }
183
184 if (data == NULL) {
185 return E_NULL_PTR;
186 }
187
188 uint8_t channel;
189 mxc_dma_config_t config;
190 mxc_dma_srcdst_t srcdst;
191 uint8_t num_bytes;
192
193 // Clear interrupt flags
194 MXC_ADC_RevB_ClearFlags(adc, ADC_IF_MASK);
195
196 adc->fifodmactrl |= MXC_F_ADC_REVB_FIFODMACTRL_FLUSH; //Flush data FIFO
197
198 adc->fifodmactrl |=
199 MXC_S_ADC_REVB_FIFODMACTRL_DATA_FORMAT_DATA_STATUS; //Transfer data and status bits
200
201 adc->fifodmactrl |= MXC_F_ADC_REVB_FIFODMACTRL_DMA_EN; //Enable ADC DMA
202
203 num_bytes = (req->num_slots + 1) * 4; //Support 8 slots (32 bytes) only. (TODO)
204
205 channel = req->dma_channel;
206
207 config.reqsel = MXC_DMA_REQUEST_ADC;
208 config.ch = channel;
209
210 config.srcwd = MXC_DMA_WIDTH_WORD;
211 config.dstwd = MXC_DMA_WIDTH_WORD;
212
213 config.srcinc_en = 0;
214 config.dstinc_en = 1;
215
216 srcdst.ch = channel;
217 srcdst.source = NULL;
218 srcdst.dest = data;
219 srcdst.len = num_bytes;
220
221 MXC_DMA_ConfigChannel(config, srcdst);
222
223 MXC_DMA_SetCallback(channel, callback);
224
225 //TODO(ADI): This supports 32 bytes transfer. In MXC_ADC_DATA_STATUS if all channels are used 64 bytes may need to read.
226 MXC_DMA->ch[channel].ctrl |= (num_bytes - 1) << MXC_F_DMA_CTRL_BURST_SIZE_POS;
227
228 MXC_DMA_EnableInt(channel);
229
230 MXC_DMA_Start(channel);
231
232 MXC_DMA_SetChannelInterruptEn(channel, 0, 1);
233
234 adc->ctrl1 |= MXC_F_ADC_REVB_CTRL1_START;
235
236 return E_NO_ERROR;
237 }
238
MXC_ADC_RevB_Handler(mxc_adc_revb_regs_t * adc)239 int MXC_ADC_RevB_Handler(mxc_adc_revb_regs_t *adc)
240 {
241 uint32_t flags;
242
243 flags = MXC_ADC_RevB_GetFlags(adc);
244
245 if (flags & (MXC_F_ADC_REVB_INTEN_SEQ_DONE | MXC_F_ADC_REVB_INTEN_CONV_DONE)) {
246 mxc_adc_complete_cb_t cb = async_callback;
247
248 if (flags & MXC_F_ADC_REVB_INTEN_SEQ_DONE) {
249 MXC_ADC_RevB_ClearFlags(adc, flags);
250
251 // Disable interrupts only when in single conversion mode
252 if (!(adc->ctrl1 & MXC_F_ADC_REVB_CTRL1_CNV_MODE)) {
253 MXC_ADC_RevB_DisableInt(adc, (MXC_F_ADC_REVB_INTFL_SEQ_DONE |
254 MXC_F_ADC_REVB_INTFL_CONV_DONE |
255 MXC_F_ADC_REVB_INTEN_FIFO_LVL));
256
257 MXC_FreeLock((uint32_t *)&async_callback);
258 }
259 }
260
261 if (flags & MXC_F_ADC_REVB_INTEN_CONV_DONE) {
262 MXC_ADC_RevB_ClearFlags(adc, MXC_F_ADC_REVB_INTFL_CONV_DONE);
263 }
264
265 if (flags) {
266 (cb)(NULL, flags);
267 }
268 }
269
270 return E_NO_ERROR;
271 }
272
MXC_ADC_RevB_GetData(mxc_adc_revb_regs_t * adc,int * outdata)273 int MXC_ADC_RevB_GetData(mxc_adc_revb_regs_t *adc, int *outdata)
274 {
275 uint32_t loop_counter, length;
276
277 length = adc->status & MXC_F_ADC_REVB_STATUS_FIFO_LEVEL;
278 length = length >> MXC_F_ADC_REVB_STATUS_FIFO_LEVEL_POS;
279
280 for (loop_counter = 0; loop_counter < length; loop_counter++) {
281 *outdata = adc->data;
282 outdata++;
283 }
284 return length;
285 }
286
MXC_ADC_RevB_EnableConversion(mxc_adc_revb_regs_t * adc)287 void MXC_ADC_RevB_EnableConversion(mxc_adc_revb_regs_t *adc)
288 {
289 adc->ctrl1 |= MXC_F_ADC_REVB_CTRL1_START;
290 }
291
MXC_ADC_RevB_DisableConversion(mxc_adc_revb_regs_t * adc)292 void MXC_ADC_RevB_DisableConversion(mxc_adc_revb_regs_t *adc)
293 {
294 adc->ctrl1 &= ~MXC_F_ADC_REVB_CTRL1_START;
295 }
296
MXC_ADC_RevB_TS_SelectEnable(mxc_adc_revb_regs_t * adc)297 void MXC_ADC_RevB_TS_SelectEnable(mxc_adc_revb_regs_t *adc)
298 {
299 adc->ctrl1 |= MXC_F_ADC_REVB_CTRL1_TS_SEL;
300 }
301
MXC_ADC_RevB_TS_SelectDisable(mxc_adc_revb_regs_t * adc)302 void MXC_ADC_RevB_TS_SelectDisable(mxc_adc_revb_regs_t *adc)
303 {
304 adc->ctrl1 &= ~MXC_F_ADC_REVB_CTRL1_TS_SEL;
305 }
306
MXC_ADC_RevB_FIFO_Level(mxc_adc_revb_regs_t * adc)307 uint16_t MXC_ADC_RevB_FIFO_Level(mxc_adc_revb_regs_t *adc)
308 {
309 return ((adc->status & MXC_F_ADC_REVB_STATUS_FIFO_LEVEL) >>
310 MXC_F_ADC_REVB_STATUS_FIFO_LEVEL_POS);
311 }
312
MXC_ADC_RevB_FIFO_Threshold_Config(mxc_adc_revb_regs_t * adc,uint32_t fifo_threshold)313 int MXC_ADC_RevB_FIFO_Threshold_Config(mxc_adc_revb_regs_t *adc, uint32_t fifo_threshold)
314 {
315 if (fifo_threshold > MAX_ADC_FIFO_LEN) {
316 return E_BAD_PARAM;
317 }
318
319 adc->fifodmactrl &= ~MXC_F_ADC_REVB_FIFODMACTRL_THRESH;
320 adc->fifodmactrl |= (uint32_t)(fifo_threshold << MXC_F_ADC_REVB_FIFODMACTRL_THRESH_POS);
321
322 return E_NO_ERROR;
323 }
324
MXC_ADC_RevB_AverageConfig(mxc_adc_revb_regs_t * adc,mxc_adc_avg_t avg_number)325 int MXC_ADC_RevB_AverageConfig(mxc_adc_revb_regs_t *adc, mxc_adc_avg_t avg_number)
326 {
327 //number of samples to average
328 adc->ctrl1 &= ~MXC_F_ADC_REVB_CTRL1_AVG;
329 adc->ctrl1 |= (avg_number);
330
331 return E_NO_ERROR;
332 }
333
MXC_ADC_RevB_Clear_ChannelSelect(mxc_adc_revb_regs_t * adc)334 void MXC_ADC_RevB_Clear_ChannelSelect(mxc_adc_revb_regs_t *adc)
335 {
336 //Clear channel select registers
337 adc->chsel0 = 0;
338 adc->chsel1 = 0;
339 adc->chsel2 = 0;
340 adc->chsel3 = 0;
341
342 #if TARGET_NUM == 32690
343 adc->chsel4 = 0;
344 #endif
345 }
346
MXC_ADC_RevB_TriggerConfig(mxc_adc_revb_regs_t * adc,mxc_adc_conversion_req_t * req)347 void MXC_ADC_RevB_TriggerConfig(mxc_adc_revb_regs_t *adc, mxc_adc_conversion_req_t *req)
348 {
349 if (req->trig == MXC_ADC_TRIG_SOFTWARE) {
350 adc->ctrl1 &= ~MXC_F_ADC_REVB_CTRL1_TRIG_MODE;
351 } else {
352 adc->ctrl1 |= MXC_F_ADC_REVB_CTRL1_TRIG_MODE;
353 MXC_SETFIELD(adc->ctrl1, MXC_F_ADC_REVB_CTRL1_TRIG_SEL,
354 (req->hwTrig << MXC_F_ADC_REVB_CTRL1_TRIG_SEL_POS));
355 }
356 }
357
MXC_ADC_RevB_ConversionModeConfig(mxc_adc_revb_regs_t * adc,mxc_adc_conversion_req_t * req)358 void MXC_ADC_RevB_ConversionModeConfig(mxc_adc_revb_regs_t *adc, mxc_adc_conversion_req_t *req)
359 {
360 if (req->mode == MXC_ADC_ATOMIC_CONV) {
361 adc->ctrl1 &= ~MXC_F_ADC_REVB_CTRL1_CNV_MODE;
362 } else {
363 adc->ctrl1 |= MXC_F_ADC_REVB_CTRL1_CNV_MODE;
364 }
365 }
366
MXC_ADC_RevB_SetConversionDelay(mxc_adc_revb_regs_t * adc,int delay)367 int MXC_ADC_RevB_SetConversionDelay(mxc_adc_revb_regs_t *adc, int delay)
368 {
369 if (delay > MXC_F_ADC_REVB_RESTART_CNT) {
370 return E_BAD_PARAM;
371 }
372
373 adc->restart &= ~MXC_F_ADC_REVB_RESTART_CNT;
374 adc->restart |= delay << MXC_F_ADC_REVB_RESTART_CNT_POS;
375
376 return E_NO_ERROR;
377 }
378
MXC_ADC_RevB_SlotsConfig(mxc_adc_revb_regs_t * adc,mxc_adc_conversion_req_t * req)379 int MXC_ADC_RevB_SlotsConfig(mxc_adc_revb_regs_t *adc, mxc_adc_conversion_req_t *req)
380 {
381 if (req->num_slots >= MAX_ADC_SLOT_NUM) {
382 return E_BAD_PARAM;
383 }
384
385 adc->ctrl1 &= ~MXC_F_ADC_REVB_CTRL1_NUM_SLOTS;
386 adc->ctrl1 |= (uint32_t)(req->num_slots) << MXC_F_ADC_REVB_CTRL1_NUM_SLOTS_POS;
387
388 return E_NO_ERROR;
389 }
390
391 //TODO(ADI): Need to find out better way to handle this.
MXC_ADC_RevB_ChSelectConfig(mxc_adc_revb_regs_t * adc,mxc_adc_chsel_t ch,uint32_t slot_num)392 int MXC_ADC_RevB_ChSelectConfig(mxc_adc_revb_regs_t *adc, mxc_adc_chsel_t ch, uint32_t slot_num)
393 {
394 uint32_t *pointer = (uint32_t *)(MXC_BASE_ADC + MXC_R_ADC_CHSEL0);
395 uint32_t offset;
396 uint32_t bitposition;
397
398 if (slot_num >= MAX_ADC_SLOT_NUM) {
399 return E_BAD_PARAM;
400 }
401
402 offset = slot_num >> 2;
403
404 bitposition = ch << ((slot_num & 0x03) << 3);
405
406 *(pointer + offset) |= bitposition;
407
408 return E_NO_ERROR;
409 }
410
411 //End
412