From 2d7219e87a4e40d9f1b31db3867669341a1699bd Mon Sep 17 00:00:00 2001 From: Jakub Zymelka Date: Tue, 5 Aug 2025 14:00:57 +0200 Subject: [PATCH] [nrf fromlist] drivers: adc: nrfx: enable negative values for single-ended ADC readings The ADC driver API already supports ADC readings which can return signed values, these are differential readings. In Nordic's datasheet, we have a mode called "single ended", but its just a name. "Single ended" is a differential reading, with the negative channel tied to GND. This is not compatible with zephyrs definition of a single ended reading. To support Nordic's "single ended" mode, the user must configure a differential reading, with the negative input tied to ground, which the saadc driver can then use to configure the reading as Nordic SAADC "single ended", and return negative values as expected. Upstream PR #: 94069 Signed-off-by: Jakub Zymelka (cherry picked from commit 84ab620777ceec9b286f3fe6640ed0869c682c0b) --- drivers/adc/adc_nrfx_saadc.c | 20 ++++++++++++------ include/zephyr/dt-bindings/adc/nrf-saadc.h | 24 ++++++++++++++++++++++ 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/drivers/adc/adc_nrfx_saadc.c b/drivers/adc/adc_nrfx_saadc.c index 2ba7b6efd00..d7f7cb7286f 100644 --- a/drivers/adc/adc_nrfx_saadc.c +++ b/drivers/adc/adc_nrfx_saadc.c @@ -201,7 +201,6 @@ static int input_assign(nrf_saadc_input_t *pin_p, if (channel_cfg->differential) { if (channel_cfg->input_negative > ARRAY_SIZE(saadc_psels) || - channel_cfg->input_negative < NRF_SAADC_AIN0 || (IS_ENABLED(CONFIG_NRF_PLATFORM_HALTIUM) && (channel_cfg->input_positive > NRF_SAADC_AIN7) != (channel_cfg->input_negative > NRF_SAADC_AIN7))) { @@ -209,14 +208,17 @@ static int input_assign(nrf_saadc_input_t *pin_p, channel_cfg->input_negative); return -EINVAL; } - *pin_n = saadc_psels[channel_cfg->input_negative]; + *pin_n = channel_cfg->input_negative == NRF_SAADC_GND ? + NRF_SAADC_INPUT_DISABLED : + saadc_psels[channel_cfg->input_negative]; } else { *pin_n = NRF_SAADC_INPUT_DISABLED; } #else *pin_p = channel_cfg->input_positive; - *pin_n = channel_cfg->differential ? channel_cfg->input_negative - : NRF_SAADC_INPUT_DISABLED; + *pin_n = (channel_cfg->differential && (channel_cfg->input_negative != NRF_SAADC_GND)) + ? channel_cfg->input_negative + : NRF_SAADC_INPUT_DISABLED; #endif LOG_DBG("ADC positive input: %d", *pin_p); LOG_DBG("ADC negative input: %d", *pin_n); @@ -366,8 +368,14 @@ static int adc_nrfx_channel_setup(const struct device *dev, * after ADC sequence ends. */ if (channel_cfg->differential) { - ch_cfg->mode = NRF_SAADC_MODE_DIFFERENTIAL; - m_data.single_ended_channels &= ~BIT(channel_cfg->channel_id); + if (channel_cfg->input_negative == NRF_SAADC_GND) { + ch_cfg->mode = NRF_SAADC_MODE_SINGLE_ENDED; + /* Do not mark as single-ended to not correct negative values. */ + m_data.single_ended_channels &= ~BIT(channel_cfg->channel_id); + } else { + ch_cfg->mode = NRF_SAADC_MODE_DIFFERENTIAL; + m_data.single_ended_channels &= ~BIT(channel_cfg->channel_id); + } } else { ch_cfg->mode = NRF_SAADC_MODE_SINGLE_ENDED; m_data.single_ended_channels |= BIT(channel_cfg->channel_id); diff --git a/include/zephyr/dt-bindings/adc/nrf-saadc.h b/include/zephyr/dt-bindings/adc/nrf-saadc.h index 4a3deb95cff..e5a86150cd4 100644 --- a/include/zephyr/dt-bindings/adc/nrf-saadc.h +++ b/include/zephyr/dt-bindings/adc/nrf-saadc.h @@ -7,6 +7,30 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ADC_NRF_SAADC_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_ADC_NRF_SAADC_H_ +/** + * @brief Short ADC negative input to ground + * + * @details The nRF SAADC hardware only supports differential readings. + * The nRF SAADC SE (single ended) mode is differential with the negative + * input shorted to GND (ground). To use the nRF SAADC SE mode, set the + * negative input to NRF_SAADC_GND: + * + * @code{.dts} + * zephyr,input-positive = ; + * zephyr,input-negative = ; + * @endcode + * + * The nRF SAADC driver also supports using the nRF SAADC SE mode in + * emulated "single-ended" mode, as defined by zephyr. In this mode, + * negative readings will be clamped to 0 by software to emulate the + * behavior of an ADC in "single-ended" mode, as defined by zephyr. To + * do this, only define the positive input: + * + * @code{.dts} + * zephyr,input-positive = ; + * @endcode + */ +#define NRF_SAADC_GND 0 #define NRF_SAADC_AIN0 1 #define NRF_SAADC_AIN1 2 #define NRF_SAADC_AIN2 3