1 /*
2 * Copyright 2023 NXP
3 * Copyright (c) 2020 Toby Firth
4 *
5 * Based on adc_mcux_adc16.c and adc_mcux_adc12.c, which are:
6 * Copyright (c) 2017-2018, NXP
7 * Copyright (c) 2019 Vestas Wind Systems A/S
8 *
9 * SPDX-License-Identifier: Apache-2.0
10 */
11
12 #define DT_DRV_COMPAT nxp_lpc_lpadc
13
14 #include <errno.h>
15 #include <zephyr/drivers/adc.h>
16 #include <zephyr/sys/util.h>
17 #include <fsl_lpadc.h>
18 #include <zephyr/drivers/regulator.h>
19
20 #include <zephyr/drivers/pinctrl.h>
21
22 #define LOG_LEVEL CONFIG_ADC_LOG_LEVEL
23 #include <zephyr/logging/log.h>
24 #include <zephyr/irq.h>
25 LOG_MODULE_REGISTER(nxp_mcux_lpadc);
26
27 /*
28 * Currently, no instance of the ADC IP has more than
29 * 8 channels present. Therefore, we treat channels
30 * with an index 8 or higher as a side b channel, with
31 * the channel index given by channel_num % 8
32 */
33 #define CHANNELS_PER_SIDE 0x8
34
35 #define ADC_CONTEXT_USES_KERNEL_TIMER
36 #include "adc_context.h"
37
38
39 struct mcux_lpadc_config {
40 ADC_Type *base;
41 lpadc_reference_voltage_source_t voltage_ref;
42 uint8_t power_level;
43 uint32_t calibration_average;
44 uint32_t offset_a;
45 uint32_t offset_b;
46 void (*irq_config_func)(const struct device *dev);
47 const struct pinctrl_dev_config *pincfg;
48 const struct device **ref_supplies;
49 };
50
51 struct mcux_lpadc_data {
52 const struct device *dev;
53 struct adc_context ctx;
54 uint16_t *buffer;
55 uint16_t *repeat_buffer;
56 uint32_t channels;
57 lpadc_conv_command_config_t cmd_config[CONFIG_LPADC_CHANNEL_COUNT];
58 };
59
60
61
mcux_lpadc_channel_setup(const struct device * dev,const struct adc_channel_cfg * channel_cfg)62 static int mcux_lpadc_channel_setup(const struct device *dev,
63 const struct adc_channel_cfg *channel_cfg)
64 {
65
66
67 struct mcux_lpadc_data *data = dev->data;
68 lpadc_conv_command_config_t *cmd;
69 uint8_t channel_side;
70 uint8_t channel_num;
71
72 /* User may configure maximum number of active channels */
73 if (channel_cfg->channel_id >= CONFIG_LPADC_CHANNEL_COUNT) {
74 LOG_ERR("Channel %d is not valid", channel_cfg->channel_id);
75 return -EINVAL;
76 }
77
78 if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) {
79 LOG_ERR("Invalid channel acquisition time");
80 return -EINVAL;
81 }
82
83 /* Select ADC CMD register to configure based off channel ID */
84 cmd = &data->cmd_config[channel_cfg->channel_id];
85
86 /* If bit 5 of input_positive is set, then channel side B is used */
87 channel_side = 0x20 & channel_cfg->input_positive;
88 /* Channel number is selected by lower 4 bits of input_positive */
89 channel_num = ADC_CMDL_ADCH(channel_cfg->input_positive);
90
91 LOG_DBG("Channel num: %u, channel side: %c", channel_num,
92 channel_side == 0 ? 'A' : 'B');
93
94 LPADC_GetDefaultConvCommandConfig(cmd);
95
96 if (channel_cfg->differential) {
97 /* Channel pairs must match in differential mode */
98 if ((ADC_CMDL_ADCH(channel_cfg->input_positive)) !=
99 (ADC_CMDL_ADCH(channel_cfg->input_negative))) {
100 return -ENOTSUP;
101 }
102
103 #if defined(FSL_FEATURE_LPADC_HAS_CMDL_DIFF) && FSL_FEATURE_LPADC_HAS_CMDL_DIFF
104 /* Check to see which channel is the positive input */
105 if (channel_cfg->input_positive & 0x20) {
106 /* Channel B is positive side */
107 cmd->sampleChannelMode =
108 kLPADC_SampleChannelDiffBothSideBA;
109 } else {
110 /* Channel A is positive side */
111 cmd->sampleChannelMode =
112 kLPADC_SampleChannelDiffBothSideAB;
113 }
114 #else
115 cmd->sampleChannelMode = kLPADC_SampleChannelDiffBothSide;
116 #endif
117 } else if (channel_side != 0) {
118 cmd->sampleChannelMode = kLPADC_SampleChannelSingleEndSideB;
119 } else {
120 /* Default value for sampleChannelMode is SideA */
121 }
122 #if defined(FSL_FEATURE_LPADC_HAS_CMDL_CSCALE) && FSL_FEATURE_LPADC_HAS_CMDL_CSCALE
123 /*
124 * The true scaling factor used by the LPADC is 30/64, instead of
125 * 1/2. Select 1/2 as this is the closest scaling factor available
126 * in Zephyr.
127 */
128 if (channel_cfg->gain == ADC_GAIN_1_2) {
129 LOG_INF("Channel gain of 30/64 selected");
130 cmd->sampleScaleMode = kLPADC_SamplePartScale;
131 } else if (channel_cfg->gain == ADC_GAIN_1) {
132 cmd->sampleScaleMode = kLPADC_SampleFullScale;
133 } else {
134 LOG_ERR("Invalid channel gain");
135 return -EINVAL;
136 }
137 #else
138 if (channel_cfg->gain != ADC_GAIN_1) {
139 LOG_ERR("Invalid channel gain");
140 return -EINVAL;
141 }
142 #endif
143
144 if (channel_cfg->reference != ADC_REF_EXTERNAL0) {
145 LOG_ERR("Invalid channel reference");
146 return -EINVAL;
147 }
148
149 cmd->channelNumber = channel_num;
150 return 0;
151 }
152
mcux_lpadc_start_read(const struct device * dev,const struct adc_sequence * sequence)153 static int mcux_lpadc_start_read(const struct device *dev,
154 const struct adc_sequence *sequence)
155 {
156 const struct mcux_lpadc_config *config = dev->config;
157 struct mcux_lpadc_data *data = dev->data;
158 lpadc_hardware_average_mode_t hardware_average_mode;
159 uint8_t channel, last_enabled;
160 #if defined(FSL_FEATURE_LPADC_HAS_CMDL_MODE) \
161 && FSL_FEATURE_LPADC_HAS_CMDL_MODE
162 lpadc_conversion_resolution_mode_t resolution_mode;
163
164 switch (sequence->resolution) {
165 case 12:
166 case 13:
167 resolution_mode = kLPADC_ConversionResolutionStandard;
168 break;
169 case 16:
170 resolution_mode = kLPADC_ConversionResolutionHigh;
171 break;
172 default:
173 LOG_ERR("Unsupported resolution %d", sequence->resolution);
174 return -ENOTSUP;
175 }
176 #else
177 /* If FSL_FEATURE_LPADC_HAS_CMDL_MODE is not defined
178 only 12/13 bit resolution is supported. */
179 if (sequence->resolution != 12 && sequence->resolution != 13) {
180 LOG_ERR("Unsupported resolution %d", sequence->resolution);
181 return -ENOTSUP;
182 }
183 #endif /* FSL_FEATURE_LPADC_HAS_CMDL_MODE */
184
185 switch (sequence->oversampling) {
186 case 0:
187 hardware_average_mode = kLPADC_HardwareAverageCount1;
188 break;
189 case 1:
190 hardware_average_mode = kLPADC_HardwareAverageCount2;
191 break;
192 case 2:
193 hardware_average_mode = kLPADC_HardwareAverageCount4;
194 break;
195 case 3:
196 hardware_average_mode = kLPADC_HardwareAverageCount8;
197 break;
198 case 4:
199 hardware_average_mode = kLPADC_HardwareAverageCount16;
200 break;
201 case 5:
202 hardware_average_mode = kLPADC_HardwareAverageCount32;
203 break;
204 case 6:
205 hardware_average_mode = kLPADC_HardwareAverageCount64;
206 break;
207 case 7:
208 hardware_average_mode = kLPADC_HardwareAverageCount128;
209 break;
210 default:
211 LOG_ERR("Unsupported oversampling value %d",
212 sequence->oversampling);
213 return -ENOTSUP;
214 }
215
216 /*
217 * Now, look at the selected channels to determine which ADC channels
218 * we need to configure, and set those channels up.
219 *
220 * Since this ADC supports chaining channels in hardware, we will
221 * start with the highest channel ID and work downwards, chaining
222 * channels as we go.
223 */
224 channel = CONFIG_LPADC_CHANNEL_COUNT;
225 last_enabled = 0;
226 while (channel-- > 0) {
227 if (sequence->channels & BIT(channel)) {
228 /* Setup this channel command */
229 #if defined(FSL_FEATURE_LPADC_HAS_CMDL_MODE) && FSL_FEATURE_LPADC_HAS_CMDL_MODE
230 data->cmd_config[channel].conversionResolutionMode =
231 resolution_mode;
232 #endif
233 data->cmd_config[channel].hardwareAverageMode =
234 hardware_average_mode;
235 if (last_enabled) {
236 /* Chain channel */
237 data->cmd_config[channel].chainedNextCommandNumber =
238 last_enabled + 1;
239 LOG_DBG("Chaining channel %u to %u",
240 channel, last_enabled);
241 } else {
242 /* End of chain */
243 data->cmd_config[channel].chainedNextCommandNumber = 0;
244 }
245 last_enabled = channel;
246 LPADC_SetConvCommandConfig(config->base,
247 channel + 1, &data->cmd_config[channel]);
248 }
249 };
250
251 data->buffer = sequence->buffer;
252
253 adc_context_start_read(&data->ctx, sequence);
254 int error = adc_context_wait_for_completion(&data->ctx);
255
256 return error;
257 }
258
mcux_lpadc_read_async(const struct device * dev,const struct adc_sequence * sequence,struct k_poll_signal * async)259 static int mcux_lpadc_read_async(const struct device *dev,
260 const struct adc_sequence *sequence,
261 struct k_poll_signal *async)
262 {
263 struct mcux_lpadc_data *data = dev->data;
264 int error;
265
266 adc_context_lock(&data->ctx, async ? true : false, async);
267 error = mcux_lpadc_start_read(dev, sequence);
268 adc_context_release(&data->ctx, error);
269
270 return error;
271 }
272
mcux_lpadc_read(const struct device * dev,const struct adc_sequence * sequence)273 static int mcux_lpadc_read(const struct device *dev,
274 const struct adc_sequence *sequence)
275 {
276 return mcux_lpadc_read_async(dev, sequence, NULL);
277 }
278
mcux_lpadc_start_channel(const struct device * dev)279 static void mcux_lpadc_start_channel(const struct device *dev)
280 {
281 const struct mcux_lpadc_config *config = dev->config;
282 struct mcux_lpadc_data *data = dev->data;
283 lpadc_conv_trigger_config_t trigger_config;
284 uint8_t first_channel;
285
286 first_channel = find_lsb_set(data->channels) - 1;
287
288 LOG_DBG("Starting channel %d, input %d", first_channel,
289 data->cmd_config[first_channel].channelNumber);
290
291 LPADC_GetDefaultConvTriggerConfig(&trigger_config);
292
293 trigger_config.targetCommandId = first_channel + 1;
294
295 /* configures trigger0. */
296 LPADC_SetConvTriggerConfig(config->base, 0, &trigger_config);
297
298 /* 1 is trigger0 mask. */
299 LPADC_DoSoftwareTrigger(config->base, 1);
300 }
301
adc_context_start_sampling(struct adc_context * ctx)302 static void adc_context_start_sampling(struct adc_context *ctx)
303 {
304 struct mcux_lpadc_data *data =
305 CONTAINER_OF(ctx, struct mcux_lpadc_data, ctx);
306
307 data->channels = ctx->sequence.channels;
308 data->repeat_buffer = data->buffer;
309
310 mcux_lpadc_start_channel(data->dev);
311 }
312
adc_context_update_buffer_pointer(struct adc_context * ctx,bool repeat_sampling)313 static void adc_context_update_buffer_pointer(struct adc_context *ctx,
314 bool repeat_sampling)
315 {
316 struct mcux_lpadc_data *data =
317 CONTAINER_OF(ctx, struct mcux_lpadc_data, ctx);
318
319 if (repeat_sampling) {
320 data->buffer = data->repeat_buffer;
321 }
322 }
323
mcux_lpadc_isr(const struct device * dev)324 static void mcux_lpadc_isr(const struct device *dev)
325 {
326 const struct mcux_lpadc_config *config = dev->config;
327 struct mcux_lpadc_data *data = dev->data;
328 ADC_Type *base = config->base;
329
330 lpadc_conv_result_t conv_result;
331 lpadc_sample_channel_mode_t conv_mode;
332 int16_t result;
333 uint16_t channel;
334
335 #if (defined(FSL_FEATURE_LPADC_FIFO_COUNT) \
336 && (FSL_FEATURE_LPADC_FIFO_COUNT == 2U))
337 LPADC_GetConvResult(base, &conv_result, 0U);
338 #else
339 LPADC_GetConvResult(base, &conv_result);
340 #endif /* FSL_FEATURE_LPADC_FIFO_COUNT */
341
342 channel = conv_result.commandIdSource - 1;
343 LOG_DBG("Finished channel %d. Raw result is 0x%04x",
344 channel, conv_result.convValue);
345 /*
346 * For 12 or 13 bit resolution the the LSBs will be 0, so a bit shift
347 * is needed. For differential modes, the ADC conversion to
348 * millivolts expects to use a shift one less than the resolution.
349 *
350 * For 16 bit modes, the adc value can be left untouched. ADC
351 * API should treat the value as signed if the channel is
352 * in differential mode
353 */
354 conv_mode = data->cmd_config[channel].sampleChannelMode;
355 if (data->ctx.sequence.resolution < 15) {
356 result = ((conv_result.convValue >> 3) & 0xFFF);
357 #if defined(FSL_FEATURE_LPADC_HAS_CMDL_DIFF) && FSL_FEATURE_LPADC_HAS_CMDL_DIFF
358 if (conv_mode == kLPADC_SampleChannelDiffBothSideAB ||
359 conv_mode == kLPADC_SampleChannelDiffBothSideBA) {
360 #else
361 if (conv_mode == kLPADC_SampleChannelDiffBothSide) {
362 #endif
363 if ((conv_result.convValue & 0x8000)) {
364 /* 13 bit mode, MSB is sign bit. (2's complement) */
365 result -= 0x1000;
366 }
367 }
368 *data->buffer++ = result;
369 } else {
370 *data->buffer++ = conv_result.convValue;
371 }
372
373
374 data->channels &= ~BIT(channel);
375
376 /*
377 * Hardware will automatically continue sampling, so no need
378 * to issue new trigger
379 */
380 if (data->channels == 0) {
381 adc_context_on_sampling_done(&data->ctx, dev);
382 }
383 }
384
385 static int mcux_lpadc_init(const struct device *dev)
386 {
387 const struct mcux_lpadc_config *config = dev->config;
388 struct mcux_lpadc_data *data = dev->data;
389 ADC_Type *base = config->base;
390 lpadc_config_t adc_config;
391 int err;
392
393 err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
394 if (err) {
395 return err;
396 }
397
398 /* Enable necessary regulators */
399 const struct device **regulator = config->ref_supplies;
400
401 while (*regulator != NULL) {
402 err = regulator_enable(*(regulator++));
403 if (err) {
404 return err;
405 }
406 }
407
408 LPADC_GetDefaultConfig(&adc_config);
409
410 adc_config.enableAnalogPreliminary = true;
411 adc_config.referenceVoltageSource = config->voltage_ref;
412
413 #if defined(FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS) \
414 && FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS
415 adc_config.conversionAverageMode = config->calibration_average;
416 #endif /* FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS */
417
418 adc_config.powerLevelMode = config->power_level;
419
420 LPADC_Init(base, &adc_config);
421
422 /* Do ADC calibration. */
423 #if defined(FSL_FEATURE_LPADC_HAS_CTRL_CALOFS) \
424 && FSL_FEATURE_LPADC_HAS_CTRL_CALOFS
425 #if defined(FSL_FEATURE_LPADC_HAS_OFSTRIM) \
426 && FSL_FEATURE_LPADC_HAS_OFSTRIM
427 /* Request offset calibration. */
428 #if defined(CONFIG_LPADC_DO_OFFSET_CALIBRATION) \
429 && CONFIG_LPADC_DO_OFFSET_CALIBRATION
430 LPADC_DoOffsetCalibration(base);
431 #else
432 LPADC_SetOffsetValue(base,
433 config->offset_a,
434 config->offset_b);
435 #endif /* DEMO_LPADC_DO_OFFSET_CALIBRATION */
436 #endif /* FSL_FEATURE_LPADC_HAS_OFSTRIM */
437 /* Request gain calibration. */
438 LPADC_DoAutoCalibration(base);
439 #endif /* FSL_FEATURE_LPADC_HAS_CTRL_CALOFS */
440
441 #if (defined(FSL_FEATURE_LPADC_HAS_CFG_CALOFS) \
442 && FSL_FEATURE_LPADC_HAS_CFG_CALOFS)
443 /* Do auto calibration. */
444 LPADC_DoAutoCalibration(base);
445 #endif /* FSL_FEATURE_LPADC_HAS_CFG_CALOFS */
446
447 /* Enable the watermark interrupt. */
448 #if (defined(FSL_FEATURE_LPADC_FIFO_COUNT) \
449 && (FSL_FEATURE_LPADC_FIFO_COUNT == 2U))
450 LPADC_EnableInterrupts(base, kLPADC_FIFO0WatermarkInterruptEnable);
451 #else
452 LPADC_EnableInterrupts(base, kLPADC_FIFOWatermarkInterruptEnable);
453 #endif /* FSL_FEATURE_LPADC_FIFO_COUNT */
454
455 config->irq_config_func(dev);
456 data->dev = dev;
457
458 adc_context_unlock_unconditionally(&data->ctx);
459
460 return 0;
461 }
462
463 static const struct adc_driver_api mcux_lpadc_driver_api = {
464 .channel_setup = mcux_lpadc_channel_setup,
465 .read = mcux_lpadc_read,
466 #ifdef CONFIG_ADC_ASYNC
467 .read_async = mcux_lpadc_read_async,
468 #endif
469 };
470
471 #define LPADC_REGULATOR_DEPENDENCY(node_id, prop, idx) \
472 DEVICE_DT_GET(DT_PHANDLE_BY_IDX(node_id, prop, idx)),
473
474 #define LPADC_REGULATORS_DEFINE(inst) \
475 static const struct device *mcux_lpadc_ref_supplies_##inst[] = { \
476 COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, nxp_reference_supply), \
477 (DT_INST_FOREACH_PROP_ELEM(inst, nxp_reference_supply, \
478 LPADC_REGULATOR_DEPENDENCY)), ()) NULL};
479
480 #define LPADC_MCUX_INIT(n) \
481 LPADC_REGULATORS_DEFINE(n) \
482 \
483 static void mcux_lpadc_config_func_##n(const struct device *dev); \
484 \
485 PINCTRL_DT_INST_DEFINE(n); \
486 static const struct mcux_lpadc_config mcux_lpadc_config_##n = { \
487 .base = (ADC_Type *)DT_INST_REG_ADDR(n), \
488 .voltage_ref = DT_INST_PROP(n, voltage_ref), \
489 .calibration_average = DT_INST_ENUM_IDX_OR(n, calibration_average, 0), \
490 .power_level = DT_INST_PROP(n, power_level), \
491 .offset_a = DT_INST_PROP(n, offset_value_a), \
492 .offset_b = DT_INST_PROP(n, offset_value_b), \
493 .irq_config_func = mcux_lpadc_config_func_##n, \
494 .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
495 .ref_supplies = mcux_lpadc_ref_supplies_##n, \
496 }; \
497 static struct mcux_lpadc_data mcux_lpadc_data_##n = { \
498 ADC_CONTEXT_INIT_TIMER(mcux_lpadc_data_##n, ctx), \
499 ADC_CONTEXT_INIT_LOCK(mcux_lpadc_data_##n, ctx), \
500 ADC_CONTEXT_INIT_SYNC(mcux_lpadc_data_##n, ctx), \
501 }; \
502 \
503 DEVICE_DT_INST_DEFINE(n, \
504 &mcux_lpadc_init, NULL, &mcux_lpadc_data_##n, \
505 &mcux_lpadc_config_##n, POST_KERNEL, \
506 CONFIG_ADC_INIT_PRIORITY, \
507 &mcux_lpadc_driver_api); \
508 \
509 static void mcux_lpadc_config_func_##n(const struct device *dev) \
510 { \
511 IRQ_CONNECT(DT_INST_IRQN(n), \
512 DT_INST_IRQ(n, priority), mcux_lpadc_isr, \
513 DEVICE_DT_INST_GET(n), 0); \
514 \
515 irq_enable(DT_INST_IRQN(n)); \
516 }
517
518 DT_INST_FOREACH_STATUS_OKAY(LPADC_MCUX_INIT)
519