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