1 /******************************************************************************
2 *
3 * Copyright (C) 2023-2025 Analog Devices, Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 #ifndef LIBRARIES_ZEPHYR_MAX_INCLUDE_WRAP_MAX32_ADC_H_
20 #define LIBRARIES_ZEPHYR_MAX_INCLUDE_WRAP_MAX32_ADC_H_
21
22 /***** Includes *****/
23 #include <adc.h>
24 #include <wrap_utils.h>
25 #include <mxc_delay.h>
26
27 #ifdef __cplusplus
28 extern "C" {
29 #endif
30
31 typedef struct {
32 uint8_t clock; ///< clock to use
33 uint8_t clkdiv; ///< clock divider
34 uint8_t cal; ///< skip calibration
35 uint8_t ref; ///< ADC reference voltage
36 uint32_t trackCount; ///< Sample Clock High time
37 uint32_t idleCount; ///< Sample Clock Low time
38 } wrap_mxc_adc_req_t;
39
40 typedef enum {
41 WRAP_MXC_ADC_SCALE_2X, // ADC Scale by 2x (this scales ADC Reference by 1/2)
42 WRAP_MXC_ADC_SCALE_1, // ADC Scale by 1x (no scaling)
43 WRAP_MXC_ADC_SCALE_2, // ADC Scale by 1/2
44 WRAP_MXC_ADC_SCALE_3, // ADC Scale by 1/3
45 WRAP_MXC_ADC_SCALE_4, // ADC Scale by 1/4
46 WRAP_MXC_ADC_SCALE_6, // ADC Scale by 1/6 (this uses 1/3 and an additional 1/2 scaling)
47 } wrap_mxc_adc_scale_t;
48
49 #define ADI_MAX32_ADC_REF_EXT0 0
50 #define ADI_MAX32_ADC_REF_INTERNAL 1
51 #define ADI_MAX32_ADC_REF_VDD_1_2 2
52
53 /*
54 * MAX32655, MAX32665, MAX32666, MAX78000 related mapping
55 */
56 #if defined(CONFIG_SOC_MAX32655) || defined(CONFIG_SOC_MAX32665) || \
57 defined(CONFIG_SOC_MAX32666) || defined(CONFIG_SOC_MAX32680) || \
58 defined(CONFIG_SOC_MAX78000)
59
60 #define WRAP_MXC_F_ADC_CONV_DONE_IE MXC_F_ADC_INTR_DONE_IE
61 #define WRAP_MXC_F_ADC_CONV_DONE_IF MXC_F_ADC_INTR_DONE_IF
62
Wrap_MXC_ADC_Init(wrap_mxc_adc_req_t * req)63 static inline int Wrap_MXC_ADC_Init(wrap_mxc_adc_req_t *req)
64 {
65 (void)req;
66 return MXC_ADC_Init();
67 }
68
Wrap_MXC_ADC_ChannelSelect(uint32_t * sample_channels)69 static inline void Wrap_MXC_ADC_ChannelSelect(uint32_t *sample_channels)
70 {
71 mxc_adc_regs_t *adc = MXC_ADC;
72 int channel_id;
73
74 channel_id = wrap_utils_find_lsb_set(*sample_channels);
75 if (channel_id == 0) {
76 return;
77 }
78 --channel_id;
79
80 adc->ctrl &= ~(MXC_F_ADC_CTRL_CH_SEL);
81 adc->ctrl |= (channel_id << MXC_F_ADC_CTRL_CH_SEL_POS) & MXC_F_ADC_CTRL_CH_SEL;
82 }
83
Wrap_MXC_ADC_SetExtScale(wrap_mxc_adc_scale_t scale)84 static inline int Wrap_MXC_ADC_SetExtScale(wrap_mxc_adc_scale_t scale)
85 {
86 MXC_ADC_SetExtScale(scale);
87 return 0;
88 }
89
Wrap_MXC_ADC_AverageConfig(uint8_t oversampling)90 static inline int Wrap_MXC_ADC_AverageConfig(uint8_t oversampling)
91 {
92 if (oversampling != 0) {
93 return -1; /* Oversampling is not supported */
94 }
95
96 return 0;
97 }
98
Wrap_MXC_ADC_ReferenceSelect(uint8_t ref)99 static inline int Wrap_MXC_ADC_ReferenceSelect(uint8_t ref)
100 {
101 mxc_adc_regs_t *adc = MXC_ADC;
102
103 if (ref == ADI_MAX32_ADC_REF_INTERNAL) {
104 adc->ctrl &= ~MXC_F_ADC_CTRL_REF_SEL;
105 } else if (ref == ADI_MAX32_ADC_REF_VDD_1_2) {
106 adc->ctrl |= MXC_F_ADC_CTRL_REF_SEL;
107 } else {
108 return -1;
109 }
110
111 return 0;
112 }
113
Wrap_MXC_ADC_DisableConversion(void)114 static inline void Wrap_MXC_ADC_DisableConversion(void)
115 {
116 return;
117 }
118
Wrap_MXC_ADC_StartConversion(uint32_t * sample_channels)119 static inline int Wrap_MXC_ADC_StartConversion(uint32_t *sample_channels)
120 {
121 int channel_id;
122
123 channel_id = wrap_utils_find_lsb_set(*sample_channels);
124 if (channel_id == 0) {
125 return -1;
126 }
127 --channel_id;
128 *sample_channels &= ~(1 << channel_id);
129
130 return MXC_ADC_StartConversion((mxc_adc_chsel_t)channel_id);
131 }
132
Wrap_MXC_ADC_StartConversionAsync(uint32_t * sample_channels,mxc_adc_complete_cb_t callback)133 static inline int Wrap_MXC_ADC_StartConversionAsync(uint32_t *sample_channels,
134 mxc_adc_complete_cb_t callback)
135 {
136 int channel_id;
137
138 channel_id = wrap_utils_find_lsb_set(*sample_channels);
139 if (channel_id == 0) {
140 return -1;
141 }
142 --channel_id;
143 *sample_channels &= ~(1 << channel_id);
144
145 return MXC_ADC_StartConversionAsync((mxc_adc_chsel_t)channel_id, callback);
146 }
147
Wrap_MXC_ADC_GetData(uint16_t ** outdata)148 static inline void Wrap_MXC_ADC_GetData(uint16_t **outdata)
149 {
150 MXC_ADC_GetData(*outdata);
151 *outdata += 1;
152 }
153
154 /*
155 * MAX32690, related mapping
156 */
157 #elif defined(CONFIG_SOC_MAX32690) || (CONFIG_SOC_MAX32672) || (CONFIG_SOC_MAX32662) || \
158 (CONFIG_SOC_MAX78002)
159
160 #define WRAP_MXC_F_ADC_CONV_DONE_IE MXC_F_ADC_INTEN_SEQ_DONE
161 #define WRAP_MXC_F_ADC_CONV_DONE_IF MXC_F_ADC_INTFL_SEQ_DONE
162
163 #define MAX_OVERSAMPLING_VALUE 7
164
Wrap_MXC_ADC_Init(wrap_mxc_adc_req_t * req)165 static inline int Wrap_MXC_ADC_Init(wrap_mxc_adc_req_t *req)
166 {
167 mxc_adc_req_t mxc_req;
168
169 mxc_req.clock = (mxc_adc_clock_t)req->clock;
170 mxc_req.cal = (mxc_adc_calibration_t)req->cal;
171 mxc_req.ref = (mxc_adc_refsel_t)req->ref;
172 mxc_req.trackCount = req->trackCount;
173 mxc_req.idleCount = req->idleCount;
174
175 switch (req->clkdiv) {
176 case 1:
177 mxc_req.clkdiv = MXC_ADC_CLKDIV_1;
178 break;
179 case 2:
180 mxc_req.clkdiv = MXC_ADC_CLKDIV_2;
181 break;
182 case 4:
183 mxc_req.clkdiv = MXC_ADC_CLKDIV_4;
184 break;
185 case 8:
186 mxc_req.clkdiv = MXC_ADC_CLKDIV_8;
187 break;
188 case 16:
189 mxc_req.clkdiv = MXC_ADC_CLKDIV_16;
190 break;
191 default:
192 return -1;
193 }
194
195 /*
196 TODO: MXC_ADC_RevB_Init function calls MXC_Delay function which uses SysTick and
197 program stucks in this function. Added following line to solve the problem until
198 develop a Zephyr compatible 'mxc_delay.c' file.
199 */
200 MXC_DelayAsync(1000, NULL);
201
202 return MXC_ADC_Init(&mxc_req);
203 }
204
Wrap_MXC_ADC_SetExtScale(wrap_mxc_adc_scale_t scale)205 static inline int Wrap_MXC_ADC_SetExtScale(wrap_mxc_adc_scale_t scale)
206 {
207 if (scale != WRAP_MXC_ADC_SCALE_1) {
208 return -1; /* Scaling is not supported */
209 }
210 return 0;
211 }
212
Wrap_MXC_ADC_AverageConfig(uint8_t oversampling)213 static inline int Wrap_MXC_ADC_AverageConfig(uint8_t oversampling)
214 {
215 if (oversampling > MAX_OVERSAMPLING_VALUE) {
216 return -EINVAL; /* Oversampling value too high */
217 }
218
219 MXC_ADC_AverageConfig(oversampling << MXC_F_ADC_CTRL1_AVG_POS);
220 return 0;
221 }
222
Wrap_MXC_ADC_ChannelSelect(uint32_t * sample_channels)223 static inline void Wrap_MXC_ADC_ChannelSelect(uint32_t *sample_channels)
224 {
225 const uint8_t num_of_channels = POPCOUNT(*sample_channels);
226 mxc_adc_slot_req_t slots[MAX_ADC_SLOT_NUM];
227 mxc_adc_conversion_req_t req;
228 uint8_t slot_index = 0;
229 int channel_id;
230
231 req.num_slots = num_of_channels - 1;
232
233 for (slot_index = 0; slot_index < num_of_channels; slot_index++) {
234 channel_id = wrap_utils_find_lsb_set(*sample_channels);
235 if (channel_id == 0) {
236 continue;
237 }
238 --channel_id;
239
240 slots[slot_index].channel = (mxc_adc_chsel_t)channel_id;
241 *sample_channels &= ~(1 << channel_id);
242 }
243
244 MXC_ADC_Clear_ChannelSelect();
245 MXC_ADC_SlotsConfig(&req);
246 MXC_ADC_SlotConfiguration(slots, num_of_channels - 1);
247 }
248
Wrap_MXC_ADC_ReferenceSelect(uint8_t ref)249 static inline int Wrap_MXC_ADC_ReferenceSelect(uint8_t ref)
250 {
251 if ((ref != ADI_MAX32_ADC_REF_EXT0) && (ref != ADI_MAX32_ADC_REF_INTERNAL)) {
252 return -1;
253 }
254
255 MXC_ADC_ReferenceSelect(ref); /* Sets MXC_ADC_REF_EXT or MXC_ADC_REF_INT_1V25 for reference. */
256 return 0;
257 }
258
Wrap_MXC_ADC_DisableConversion(void)259 static inline void Wrap_MXC_ADC_DisableConversion(void)
260 {
261 MXC_ADC_DisableConversion();
262 }
263
Wrap_MXC_ADC_StartConversion(uint32_t * sample_channels)264 static inline int Wrap_MXC_ADC_StartConversion(uint32_t *sample_channels)
265 {
266 int ret = 0;
267
268 MXC_ADC_FIFO_Threshold_Config(MAX_ADC_FIFO_LEN >> 1);
269 Wrap_MXC_ADC_ChannelSelect(sample_channels);
270
271 ret = MXC_ADC_StartConversion();
272 while ((MXC_ADC_GetFlags() & WRAP_MXC_F_ADC_CONV_DONE_IF) != WRAP_MXC_F_ADC_CONV_DONE_IF) {
273 {
274 }
275 }
276
277 return ret;
278 }
279
Wrap_MXC_ADC_StartConversionAsync(uint32_t * sample_channels,mxc_adc_complete_cb_t callback)280 static inline int Wrap_MXC_ADC_StartConversionAsync(uint32_t *sample_channels,
281 mxc_adc_complete_cb_t callback)
282 {
283 MXC_ADC_FIFO_Threshold_Config(MAX_ADC_FIFO_LEN >> 1);
284 Wrap_MXC_ADC_ChannelSelect(sample_channels);
285 return MXC_ADC_StartConversionAsync(callback);
286 }
287
Wrap_MXC_ADC_GetData(uint16_t ** outdata)288 static inline void Wrap_MXC_ADC_GetData(uint16_t **outdata)
289 {
290 mxc_adc_regs_t *adc = MXC_ADC;
291 uint32_t loop_counter, length;
292
293 length = (adc->status & MXC_F_ADC_STATUS_FIFO_LEVEL) >> MXC_F_ADC_STATUS_FIFO_LEVEL_POS;
294
295 for (loop_counter = 0; loop_counter < length; loop_counter++) {
296 **outdata = adc->data & MXC_F_ADC_DATA_DATA;
297 *outdata += 1;
298 }
299 }
300
301 #endif // part number
302
303 #ifdef __cplusplus
304 }
305 #endif
306
307 #endif // LIBRARIES_ZEPHYR_MAX_INCLUDE_WRAP_MAX32_ADC_H_
308