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