1 /*
2 * Copyright (c) 2023-2024 Analog Devices, Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT adi_max32_adc
8
9 #include <errno.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/device.h>
12 #include <zephyr/drivers/adc.h>
13 #include <zephyr/drivers/pinctrl.h>
14 #include <zephyr/drivers/clock_control/adi_max32_clock_control.h>
15
16 #include <zephyr/logging/log.h>
17 LOG_MODULE_REGISTER(adc_max32, CONFIG_ADC_LOG_LEVEL);
18
19 #include <wrap_max32_adc.h>
20
21 #define ADC_CONTEXT_USES_KERNEL_TIMER
22 #include "adc_context.h"
23
24 /* reference voltage for the ADC */
25 #define MAX32_ADC_VREF_MV DT_INST_PROP(0, vref_mv)
26
27 struct max32_adc_config {
28 uint8_t channel_count;
29 mxc_adc_regs_t *regs;
30 int clock_divider;
31 int track_count;
32 int idle_count;
33 const struct pinctrl_dev_config *pctrl;
34 const struct device *clock;
35 struct max32_perclk perclk;
36 void (*irq_func)(void);
37 };
38
39 struct max32_adc_data {
40 const struct device *dev;
41 struct adc_context ctx;
42 uint16_t *buffer;
43 uint16_t *repeat_buffer;
44 uint32_t channels;
45 uint32_t sample_channels;
46 const uint8_t resolution;
47 };
48
49 #ifdef CONFIG_ADC_ASYNC
adc_complete_cb(void * req,int error)50 static void adc_complete_cb(void *req, int error)
51 {
52 ARG_UNUSED(req);
53 ARG_UNUSED(error);
54 }
55 #endif /* CONFIG_ADC_ASYNC */
56
adc_max32_start_channel(const struct device * dev)57 static void adc_max32_start_channel(const struct device *dev)
58 {
59 struct max32_adc_data *data = dev->data;
60 int ret = 0;
61
62 #if defined(CONFIG_ADC_ASYNC)
63 if (data->ctx.asynchronous) {
64 ret = Wrap_MXC_ADC_StartConversionAsync(&data->sample_channels, adc_complete_cb);
65 if (ret < 0) {
66 LOG_ERR("Error starting conversion (%d)", ret);
67 }
68 } else {
69 #endif /* CONFIG_ADC_ASYNC */
70 while (data->sample_channels) {
71 ret = Wrap_MXC_ADC_StartConversion(&data->sample_channels);
72 if (ret < 0) {
73 LOG_ERR("Error starting conversion (%d)", ret);
74 return;
75 }
76 Wrap_MXC_ADC_GetData(&data->buffer);
77 }
78
79 Wrap_MXC_ADC_DisableConversion();
80 adc_context_on_sampling_done(&data->ctx, dev);
81 #if defined(CONFIG_ADC_ASYNC)
82 }
83 #endif /* CONFIG_ADC_ASYNC */
84 }
85
adc_context_start_sampling(struct adc_context * ctx)86 static void adc_context_start_sampling(struct adc_context *ctx)
87 {
88 struct max32_adc_data *data = CONTAINER_OF(ctx, struct max32_adc_data, ctx);
89
90 data->sample_channels = ctx->sequence.channels;
91 data->repeat_buffer = data->buffer;
92
93 adc_max32_start_channel(data->dev);
94 }
95
adc_context_update_buffer_pointer(struct adc_context * ctx,bool repeat_sampling)96 static void adc_context_update_buffer_pointer(struct adc_context *ctx, bool repeat_sampling)
97 {
98 struct max32_adc_data *data = CONTAINER_OF(ctx, struct max32_adc_data, ctx);
99
100 if (repeat_sampling) {
101 data->buffer = data->repeat_buffer;
102 }
103 }
104
start_read(const struct device * dev,const struct adc_sequence * seq)105 static int start_read(const struct device *dev, const struct adc_sequence *seq)
106 {
107 struct max32_adc_data *data = dev->data;
108 uint32_t num_of_sample_channels = POPCOUNT(seq->channels);
109 uint32_t num_of_sample = 1;
110 int ret = 0;
111
112 if (seq->resolution != data->resolution) {
113 LOG_ERR("Unsupported resolution (%d)", seq->resolution);
114 return -ENOTSUP;
115 }
116 if (seq->channels == 0) {
117 return -EINVAL;
118 }
119 if ((data->channels & seq->channels) != seq->channels) {
120 return -EINVAL;
121 }
122
123 ret = Wrap_MXC_ADC_AverageConfig(seq->oversampling);
124 if (ret != 0) {
125 return -EINVAL;
126 }
127
128 if (seq->options) {
129 num_of_sample += seq->options->extra_samplings;
130 }
131 if (seq->buffer_size < (num_of_sample * num_of_sample_channels)) { /* Buffer size control */
132 return -ENOMEM;
133 }
134
135 data->buffer = seq->buffer;
136 adc_context_start_read(&data->ctx, seq);
137
138 return adc_context_wait_for_completion(&data->ctx);
139 }
140
adc_max32_read(const struct device * dev,const struct adc_sequence * seq)141 static int adc_max32_read(const struct device *dev, const struct adc_sequence *seq)
142 {
143 struct max32_adc_data *data = dev->data;
144 int ret;
145
146 adc_context_lock(&data->ctx, false, NULL);
147 ret = start_read(dev, seq);
148 adc_context_release(&data->ctx, ret);
149
150 return ret;
151 }
152
153 #ifdef CONFIG_ADC_ASYNC
adc_max32_read_async(const struct device * dev,const struct adc_sequence * seq,struct k_poll_signal * async)154 static int adc_max32_read_async(const struct device *dev, const struct adc_sequence *seq,
155 struct k_poll_signal *async)
156 {
157 struct max32_adc_data *data = dev->data;
158 int ret;
159
160 adc_context_lock(&data->ctx, true, async);
161 ret = start_read(dev, seq);
162 adc_context_release(&data->ctx, ret);
163
164 return ret;
165 }
166 #endif /* CONFIG_ADC_ASYNC */
167
adc_max32_channel_setup(const struct device * dev,const struct adc_channel_cfg * cfg)168 static int adc_max32_channel_setup(const struct device *dev, const struct adc_channel_cfg *cfg)
169 {
170 const struct max32_adc_config *conf = dev->config;
171 struct max32_adc_data *data = dev->data;
172 wrap_mxc_adc_scale_t wrap_mxc_scale;
173 uint8_t adc_reference;
174 int ret = 0;
175
176 if (cfg->channel_id >= conf->channel_count) {
177 LOG_ERR("Invalid channel (%u)", cfg->channel_id);
178 return -EINVAL;
179 }
180
181 if (cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) {
182 LOG_ERR("Invalid channel acquisition time");
183 return -EINVAL;
184 }
185
186 if (cfg->differential) {
187 LOG_ERR("Differential sampling not supported");
188 return -ENOTSUP;
189 }
190
191 switch (cfg->reference) {
192 case ADC_REF_INTERNAL:
193 adc_reference = ADI_MAX32_ADC_REF_INTERNAL;
194 break;
195 case ADC_REF_VDD_1_2:
196 adc_reference = ADI_MAX32_ADC_REF_VDD_1_2;
197 break;
198 case ADC_REF_EXTERNAL0:
199 adc_reference = ADI_MAX32_ADC_REF_EXT0;
200 break;
201 default:
202 return -ENOTSUP;
203 }
204 ret = Wrap_MXC_ADC_ReferenceSelect(adc_reference);
205 if (ret != 0) {
206 LOG_ERR("Reference is not supported.");
207 return -ENOTSUP;
208 }
209
210 switch (cfg->gain) {
211 case ADC_GAIN_1_6:
212 wrap_mxc_scale = WRAP_MXC_ADC_SCALE_6;
213 break;
214 case ADC_GAIN_1_4:
215 wrap_mxc_scale = WRAP_MXC_ADC_SCALE_4;
216 break;
217 case ADC_GAIN_1_3:
218 wrap_mxc_scale = WRAP_MXC_ADC_SCALE_3;
219 break;
220 case ADC_GAIN_1_2:
221 wrap_mxc_scale = WRAP_MXC_ADC_SCALE_2;
222 break;
223 case ADC_GAIN_1:
224 wrap_mxc_scale = WRAP_MXC_ADC_SCALE_1;
225 break;
226 case ADC_GAIN_2:
227 wrap_mxc_scale = WRAP_MXC_ADC_SCALE_2X;
228 break;
229 default:
230 return -ENOTSUP;
231 }
232 ret = Wrap_MXC_ADC_SetExtScale(wrap_mxc_scale);
233 if (ret != 0) {
234 LOG_ERR("Gain value is not supported.");
235 return -ENOTSUP;
236 }
237
238 data->channels |= BIT(cfg->channel_id);
239 return 0;
240 }
241
adc_max32_init(const struct device * dev)242 static int adc_max32_init(const struct device *dev)
243 {
244 const struct max32_adc_config *config = dev->config;
245 struct max32_adc_data *data = dev->data;
246 uint32_t ret;
247 wrap_mxc_adc_req_t req = {
248 .clock = config->perclk.clk_src,
249 .clkdiv = config->clock_divider,
250 .cal = 1, /* Initial calibration enabled. */
251 .ref = 1, /* Reference set to internal reference until user define it. */
252 .trackCount = config->track_count,
253 .idleCount = config->idle_count};
254
255 /* Enable clock */
256 ret = clock_control_on(config->clock, (clock_control_subsys_t)&config->perclk);
257 if (ret) {
258 return ret;
259 }
260
261 ret = Wrap_MXC_ADC_Init(&req);
262 if (ret) {
263 return -EINVAL;
264 }
265
266 ret = pinctrl_apply_state(config->pctrl, PINCTRL_STATE_DEFAULT);
267 if (ret) {
268 return ret;
269 }
270
271 config->irq_func();
272 data->dev = dev;
273
274 adc_context_unlock_unconditionally(&data->ctx);
275
276 return 0;
277 }
278
adc_max32_isr(const struct device * dev)279 static void adc_max32_isr(const struct device *dev)
280 {
281 struct max32_adc_data *const data = dev->data;
282 uint32_t flags = MXC_ADC_GetFlags();
283
284 MXC_ADC_Handler();
285 MXC_ADC_ClearFlags(flags);
286
287 if (flags & WRAP_MXC_F_ADC_CONV_DONE_IF) {
288 Wrap_MXC_ADC_GetData(&data->buffer);
289
290 if (data->sample_channels != 0) {
291 adc_max32_start_channel(dev);
292 } else {
293 Wrap_MXC_ADC_DisableConversion();
294 adc_context_on_sampling_done(&data->ctx, dev);
295 }
296 }
297 }
298
299 static DEVICE_API(adc, adc_max32_driver_api) = {
300 .channel_setup = adc_max32_channel_setup,
301 .read = adc_max32_read,
302 #ifdef CONFIG_ADC_ASYNC
303 .read_async = adc_max32_read_async,
304 #endif /* CONFIG_ADC_ASYNC */
305 .ref_internal = MAX32_ADC_VREF_MV,
306 };
307
308 #define MAX32_ADC_INIT(_num) \
309 PINCTRL_DT_INST_DEFINE(_num); \
310 static void max32_adc_irq_init_##_num(void) \
311 { \
312 IRQ_CONNECT(DT_INST_IRQN(_num), DT_INST_IRQ(_num, priority), adc_max32_isr, \
313 DEVICE_DT_INST_GET(_num), 0); \
314 irq_enable(DT_INST_IRQN(_num)); \
315 }; \
316 static const struct max32_adc_config max32_adc_config_##_num = { \
317 .channel_count = DT_INST_PROP(_num, channel_count), \
318 .regs = (mxc_adc_regs_t *)DT_INST_REG_ADDR(_num), \
319 .pctrl = PINCTRL_DT_INST_DEV_CONFIG_GET(_num), \
320 .clock = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(_num)), \
321 .clock_divider = DT_INST_PROP_OR(_num, clock_divider, 1), \
322 .track_count = DT_INST_PROP_OR(_num, track_count, 0), \
323 .idle_count = DT_INST_PROP_OR(_num, idle_count, 0), \
324 .perclk.bus = DT_INST_CLOCKS_CELL(_num, offset), \
325 .perclk.bit = DT_INST_CLOCKS_CELL(_num, bit), \
326 .perclk.clk_src = \
327 DT_INST_PROP_OR(_num, clock_source, ADI_MAX32_PRPH_CLK_SRC_PCLK), \
328 .irq_func = max32_adc_irq_init_##_num, \
329 }; \
330 static struct max32_adc_data max32_adc_data_##_num = { \
331 ADC_CONTEXT_INIT_TIMER(max32_adc_data_##_num, ctx), \
332 ADC_CONTEXT_INIT_LOCK(max32_adc_data_##_num, ctx), \
333 ADC_CONTEXT_INIT_SYNC(max32_adc_data_##_num, ctx), \
334 .resolution = DT_INST_PROP(_num, resolution), \
335 }; \
336 DEVICE_DT_INST_DEFINE(_num, &adc_max32_init, NULL, &max32_adc_data_##_num, \
337 &max32_adc_config_##_num, POST_KERNEL, CONFIG_ADC_INIT_PRIORITY, \
338 &adc_max32_driver_api);
339
340 DT_INST_FOREACH_STATUS_OKAY(MAX32_ADC_INIT)
341