drivers: adc: Update adc driver to support nRF54L15 device

Expands driver to cover nRF54L15 features like AIN as GPIO configuration,
new reference voltage, different set of supported gain options.

Signed-off-by: Karol Lasończyk <karol.lasonczyk@nordicsemi.no>
This commit is contained in:
Karol Lasończyk 2024-02-07 14:19:30 +01:00 committed by Fabio Baltieri
commit 3ca3131a7d

View file

@ -6,7 +6,7 @@
#define ADC_CONTEXT_USES_KERNEL_TIMER
#include "adc_context.h"
#include <hal/nrf_saadc.h>
#include <haly/nrfy_saadc.h>
#include <zephyr/dt-bindings/adc/nrf-adc.h>
#define LOG_LEVEL CONFIG_ADC_LOG_LEVEL
@ -16,6 +16,20 @@ LOG_MODULE_REGISTER(adc_nrfx_saadc);
#define DT_DRV_COMPAT nordic_nrf_saadc
#if (NRF_SAADC_HAS_AIN_AS_PIN)
static const uint8_t saadc_psels[NRF_SAADC_AIN7 + 1] = {
[NRF_SAADC_AIN0] = NRF_PIN_PORT_TO_PIN_NUMBER(4U, 1),
[NRF_SAADC_AIN1] = NRF_PIN_PORT_TO_PIN_NUMBER(5U, 1),
[NRF_SAADC_AIN2] = NRF_PIN_PORT_TO_PIN_NUMBER(6U, 1),
[NRF_SAADC_AIN3] = NRF_PIN_PORT_TO_PIN_NUMBER(7U, 1),
[NRF_SAADC_AIN4] = NRF_PIN_PORT_TO_PIN_NUMBER(11U, 1),
[NRF_SAADC_AIN5] = NRF_PIN_PORT_TO_PIN_NUMBER(12U, 1),
[NRF_SAADC_AIN6] = NRF_PIN_PORT_TO_PIN_NUMBER(13U, 1),
[NRF_SAADC_AIN7] = NRF_PIN_PORT_TO_PIN_NUMBER(14U, 1),
};
#else
BUILD_ASSERT((NRF_SAADC_AIN0 == NRF_SAADC_INPUT_AIN0) &&
(NRF_SAADC_AIN1 == NRF_SAADC_INPUT_AIN1) &&
(NRF_SAADC_AIN2 == NRF_SAADC_INPUT_AIN2) &&
@ -28,8 +42,12 @@ BUILD_ASSERT((NRF_SAADC_AIN0 == NRF_SAADC_INPUT_AIN0) &&
#if defined(SAADC_CH_PSELP_PSELP_VDDHDIV5)
(NRF_SAADC_VDDHDIV5 == NRF_SAADC_INPUT_VDDHDIV5) &&
#endif
(NRF_SAADC_VDD == NRF_SAADC_INPUT_VDD),
#if defined(SAADC_CH_PSELP_PSELP_VDD)
(NRF_SAADC_VDD == NRF_SAADC_INPUT_VDD) &&
#endif
1,
"Definitions from nrf-adc.h do not match those from nrf_saadc.h");
#endif
struct driver_data {
struct adc_context ctx;
@ -43,85 +61,158 @@ static struct driver_data m_data = {
ADC_CONTEXT_INIT_SYNC(m_data, ctx),
};
/* Helper function to convert number of samples to the byte representation. */
static uint32_t samples_to_bytes(const struct adc_sequence *sequence, uint16_t number_of_samples)
{
if (NRF_SAADC_8BIT_SAMPLE_WIDTH == 8 && sequence->resolution == 8) {
return number_of_samples;
}
return number_of_samples * 2;
}
/* Helper function to convert acquisition time to register TACQ value. */
static int adc_convert_acq_time(uint16_t acquisition_time, nrf_saadc_acqtime_t *p_tacq_val)
{
int result = 0;
#if NRF_SAADC_HAS_ACQTIME_ENUM
switch (acquisition_time) {
case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 3):
*p_tacq_val = NRF_SAADC_ACQTIME_3US;
break;
case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 5):
*p_tacq_val = NRF_SAADC_ACQTIME_5US;
break;
case ADC_ACQ_TIME_DEFAULT:
case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 10):
*p_tacq_val = NRF_SAADC_ACQTIME_10US;
break;
case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 15):
*p_tacq_val = NRF_SAADC_ACQTIME_15US;
break;
case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 20):
*p_tacq_val = NRF_SAADC_ACQTIME_20US;
break;
case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 40):
*p_tacq_val = NRF_SAADC_ACQTIME_40US;
break;
default:
result = -EINVAL;
}
#else
#define MINIMUM_ACQ_TIME_IN_NS 125
#define DEFAULT_ACQ_TIME_IN_NS 10000
nrf_saadc_acqtime_t tacq = 0;
uint16_t acq_time =
(acquisition_time == ADC_ACQ_TIME_DEFAULT
? DEFAULT_ACQ_TIME_IN_NS
: (ADC_ACQ_TIME_VALUE(acquisition_time) *
(ADC_ACQ_TIME_UNIT(acquisition_time) == ADC_ACQ_TIME_MICROSECONDS
? 1000
: 1)));
tacq = (nrf_saadc_acqtime_t)(acq_time / MINIMUM_ACQ_TIME_IN_NS) - 1;
if ((tacq > NRF_SAADC_ACQTIME_MAX) || (acq_time < MINIMUM_ACQ_TIME_IN_NS)) {
result = -EINVAL;
} else {
*p_tacq_val = tacq;
}
#endif
return result;
}
/* Implementation of the ADC driver API function: adc_channel_setup. */
static int adc_nrfx_channel_setup(const struct device *dev,
const struct adc_channel_cfg *channel_cfg)
{
nrf_saadc_channel_config_t config = {
.resistor_p = NRF_SAADC_RESISTOR_DISABLED,
.resistor_n = NRF_SAADC_RESISTOR_DISABLED,
.burst = NRF_SAADC_BURST_DISABLED,
#if NRF_SAADC_HAS_CH_CONFIG_RES
.resistor_p = NRF_SAADC_RESISTOR_DISABLED,
.resistor_n = NRF_SAADC_RESISTOR_DISABLED,
#endif
.burst = NRF_SAADC_BURST_DISABLED,
};
uint8_t channel_id = channel_cfg->channel_id;
uint32_t input_negative = channel_cfg->input_negative;
if (channel_id >= SAADC_CH_NUM) {
return -EINVAL;
}
switch (channel_cfg->gain) {
#if defined(SAADC_CH_CONFIG_GAIN_Gain1_6)
case ADC_GAIN_1_6:
config.gain = NRF_SAADC_GAIN1_6;
break;
#endif
#if defined(SAADC_CH_CONFIG_GAIN_Gain1_5)
case ADC_GAIN_1_5:
config.gain = NRF_SAADC_GAIN1_5;
break;
#endif
#if defined(SAADC_CH_CONFIG_GAIN_Gain1_4)
case ADC_GAIN_1_4:
config.gain = NRF_SAADC_GAIN1_4;
break;
#endif
#if defined(SAADC_CH_CONFIG_GAIN_Gain1_3)
case ADC_GAIN_1_3:
config.gain = NRF_SAADC_GAIN1_3;
break;
#endif
#if defined(SAADC_CH_CONFIG_GAIN_Gain1_2)
case ADC_GAIN_1_2:
config.gain = NRF_SAADC_GAIN1_2;
break;
#endif
#if defined(SAADC_CH_CONFIG_GAIN_Gain2_3)
case ADC_GAIN_2_3:
config.gain = NRF_SAADC_GAIN2_3;
break;
#endif
case ADC_GAIN_1:
config.gain = NRF_SAADC_GAIN1;
break;
case ADC_GAIN_2:
config.gain = NRF_SAADC_GAIN2;
break;
#if defined(SAADC_CH_CONFIG_GAIN_Gain4)
case ADC_GAIN_4:
config.gain = NRF_SAADC_GAIN4;
break;
#endif
default:
LOG_ERR("Selected ADC gain is not valid");
return -EINVAL;
}
switch (channel_cfg->reference) {
#if defined(SAADC_CH_CONFIG_REFSEL_Internal)
case ADC_REF_INTERNAL:
config.reference = NRF_SAADC_REFERENCE_INTERNAL;
break;
#endif
#if defined(SAADC_CH_CONFIG_REFSEL_VDD1_4)
case ADC_REF_VDD_1_4:
config.reference = NRF_SAADC_REFERENCE_VDD4;
break;
#endif
#if defined(SAADC_CH_CONFIG_REFSEL_External)
case ADC_REF_EXTERNAL0:
config.reference = NRF_SAADC_REFERENCE_EXTERNAL;
break;
#endif
default:
LOG_ERR("Selected ADC reference is not valid");
return -EINVAL;
}
switch (channel_cfg->acquisition_time) {
case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 3):
config.acq_time = NRF_SAADC_ACQTIME_3US;
break;
case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 5):
config.acq_time = NRF_SAADC_ACQTIME_5US;
break;
case ADC_ACQ_TIME_DEFAULT:
case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 10):
config.acq_time = NRF_SAADC_ACQTIME_10US;
break;
case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 15):
config.acq_time = NRF_SAADC_ACQTIME_15US;
break;
case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 20):
config.acq_time = NRF_SAADC_ACQTIME_20US;
break;
case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 40):
config.acq_time = NRF_SAADC_ACQTIME_40US;
break;
default:
int ret = adc_convert_acq_time(channel_cfg->acquisition_time, &config.acq_time);
if (ret) {
LOG_ERR("Selected ADC acquisition time is not valid");
return -EINVAL;
}
@ -134,17 +225,37 @@ static int adc_nrfx_channel_setup(const struct device *dev,
* in a sampling sequence.
*/
nrf_saadc_channel_init(NRF_SAADC, channel_id, &config);
nrf_saadc_channel_input_set(NRF_SAADC,
channel_id,
NRF_SAADC_INPUT_DISABLED,
channel_cfg->input_negative);
#if (NRF_SAADC_HAS_AIN_AS_PIN)
if ((channel_cfg->input_positive > NRF_SAADC_AIN7) ||
(channel_cfg->input_positive < NRF_SAADC_AIN0)) {
return -EINVAL;
}
if (config.mode == NRF_SAADC_MODE_DIFFERENTIAL) {
if (input_negative > NRF_SAADC_AIN7 ||
input_negative < NRF_SAADC_AIN0) {
return -EINVAL;
}
input_negative = saadc_psels[input_negative];
} else {
input_negative = NRF_SAADC_INPUT_DISABLED;
}
/* Store the positive input selection in a dedicated array,
* to get it later when the channel is selected for a sampling
* and to mark the channel as configured (ready to be selected).
*/
m_data.positive_inputs[channel_id] = saadc_psels[channel_cfg->input_positive];
#else
m_data.positive_inputs[channel_id] = channel_cfg->input_positive;
#endif
nrf_saadc_channel_init(NRF_SAADC, channel_id, &config);
nrf_saadc_channel_input_set(NRF_SAADC,
channel_id,
NRF_SAADC_INPUT_DISABLED,
input_negative);
return 0;
}
@ -168,10 +279,11 @@ static void adc_context_update_buffer_pointer(struct adc_context *ctx,
ARG_UNUSED(ctx);
if (!repeat) {
nrf_saadc_buffer_pointer_set(
NRF_SAADC,
(uint16_t *)nrf_saadc_buffer_pointer_get(NRF_SAADC) +
nrf_saadc_amount_get(NRF_SAADC));
nrf_saadc_value_t *buffer =
(uint8_t *)nrf_saadc_buffer_pointer_get(NRF_SAADC) +
samples_to_bytes(&ctx->sequence, nrfy_saadc_amount_get(NRF_SAADC));
nrfy_saadc_buffer_pointer_set(NRF_SAADC, buffer);
}
}
@ -256,7 +368,8 @@ static int check_buffer_size(const struct adc_sequence *sequence,
{
size_t needed_buffer_size;
needed_buffer_size = active_channels * sizeof(uint16_t);
needed_buffer_size = samples_to_bytes(sequence, active_channels);
if (sequence->options) {
needed_buffer_size *= (1 + sequence->options->extra_samplings);
}
@ -429,7 +542,11 @@ static const struct adc_driver_api adc_nrfx_driver_api = {
#ifdef CONFIG_ADC_ASYNC
.read_async = adc_nrfx_read_async,
#endif
#if defined(CONFIG_SOC_NRF54L15)
.ref_internal = 900,
#else
.ref_internal = 600,
#endif
};
/*