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