/*
 * Copyright (c) 2018 Kokoon Technology Limited
 * Copyright (c) 2019 Song Qiang <songqiang1304521@gmail.com>
 * Copyright (c) 2019 Endre Karlson
 * Copyright (c) 2020 Teslabs Engineering S.L.
 * Copyright (c) 2021 Marius Scholtz, RIC Electronics
 * Copyright (c) 2023 Hein Wessels, Nobleo Technology
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#define DT_DRV_COMPAT st_stm32_adc

#include <errno.h>

#include <zephyr/drivers/adc.h>
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/device.h>
#include <zephyr/kernel.h>
#include <zephyr/init.h>
#include <zephyr/toolchain.h>
#include <soc.h>
#include <stm32_bitops.h>
#include <stm32_cache.h>
#include <zephyr/pm/device.h>
#include <zephyr/pm/policy.h>
#include <stm32_ll_adc.h>
#include <stm32_ll_system.h>
#if defined(CONFIG_SOC_SERIES_STM32N6X) || \
	defined(CONFIG_SOC_SERIES_STM32U3X) || \
	defined(CONFIG_SOC_SERIES_STM32U5X)
#include <stm32_ll_pwr.h>
#endif /* CONFIG_SOC_SERIES_STM32U5X */

#ifdef CONFIG_ADC_STM32_DMA
#include <zephyr/drivers/dma/dma_stm32.h>
#include <zephyr/drivers/dma.h>
#include <zephyr/toolchain.h>
#include <stm32_ll_dma.h>
#endif

#define ADC_CONTEXT_USES_KERNEL_TIMER
#define ADC_CONTEXT_ENABLE_ON_COMPLETE
#include "adc_context.h"

#define LOG_LEVEL CONFIG_ADC_LOG_LEVEL
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(adc_stm32);

#include <zephyr/drivers/clock_control/stm32_clock_control.h>
#include <zephyr/dt-bindings/adc/stm32_adc.h>
#include <zephyr/irq.h>
#include <zephyr/mem_mgmt/mem_attr.h>

#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H7RSX)
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
#include <stm32_ll_system.h>
#endif

#include <zephyr/linker/linker-defs.h>

/* Here are some redefinitions of ADC versions for better readability */
#if defined(CONFIG_SOC_SERIES_STM32F3X)
#if defined(ADC1_V2_5)
#define STM32F37X_ADC /* F37x */
#elif defined(ADC5_V1_1)
#define STM32F3XX_ADC /* Other F3xx */
#endif /* ADC5_V1_1 */
#elif defined(CONFIG_SOC_SERIES_STM32H7X)
#if defined(ADC_VER_V5_V90)
#define STM32H72X_ADC /* H72x and H73x */
#elif defined(ADC_VER_V5_X)
#define STM32H74X_ADC /* H74x and H75x */
#elif defined(ADC_VER_V5_3)
#define STM32H7AX_ADC /* H7Ax and H7Bx */
#endif /* ADC_VER_V5_3 */
#endif /* CONFIG_SOC_SERIES_STM32H7X */

/*
 * Other ADC versions:
 * compat st_stm32f1_adc -> STM32F1, F37x (ADC1_V2_5)
 * compat st_stm32f4_adc -> STM32F2, F4, F7, L1
 */

/* Clock source values */
#define SYNC			1
#define ASYNC			2

/* Sequencer type */
#define SEQUENCER_FIXED		0
#define SEQUENCER_PROGRAMMABLE	1

/* Oversampler type */
#define OVERSAMPLER_NONE	0
#define OVERSAMPLER_MINIMAL	1
#define OVERSAMPLER_EXTENDED	2

/* Internal regulator type */
#define INTERNAL_REGULATOR_NONE			0
#define INTERNAL_REGULATOR_STARTUP_SW_DELAY	1
#define INTERNAL_REGULATOR_STARTUP_HW_STATUS	2

#define ANY_NUM_COMMON_SAMPLING_TIME_CHANNELS_IS(value) \
	(DT_INST_FOREACH_STATUS_OKAY_VARGS(IS_EQ_PROP_OR, \
					   num_sampling_time_common_channels,\
					   0, value) 0)

#define ANY_ADC_SEQUENCER_TYPE_IS(value) \
	(DT_INST_FOREACH_STATUS_OKAY_VARGS(IS_EQ_STRING_PROP, \
					   st_adc_sequencer,\
					   value, SEQUENCER_) 0)

#define ANY_ADC_OVERSAMPLER_TYPE_IS(value) \
	(DT_INST_FOREACH_STATUS_OKAY_VARGS(IS_EQ_STRING_PROP, \
					   st_adc_oversampler,\
					   value, OVERSAMPLER_) 0)

#define ANY_ADC_INTERNAL_REGULATOR_TYPE_IS(value) \
	(DT_INST_FOREACH_STATUS_OKAY_VARGS(IS_EQ_STRING_PROP, \
					   st_adc_internal_regulator,\
					   value, INTERNAL_REGULATOR_) 0)

#define ANY_ADC_HAS_DEEP_POWERDOWN \
	(DT_INST_FOREACH_STATUS_OKAY_VARGS(IS_EQ_PROP_OR, \
					   st_adc_has_deep_powerdown,\
					   0, 1) 0)

#define ANY_ADC_HAS_CHANNEL_PRESELECTION \
	(DT_INST_FOREACH_STATUS_OKAY_VARGS(IS_EQ_PROP_OR, \
					   st_adc_has_channel_preselection,\
					   0, 1) 0)

#define ANY_ADC_HAS_DIFFERENTIAL_SUPPORT \
	(DT_INST_FOREACH_STATUS_OKAY_VARGS(IS_EQ_PROP_OR, \
					   st_adc_has_differential_support,\
					   0, 1) 0)

#define ANY_CHILD_NODE_IS_DIFFERENTIAL(inst) \
	(DT_INST_FOREACH_CHILD_VARGS(inst, IS_EQ_NODE_PROP_OR, \
				     zephyr_differential, \
				     0, 1) 0)

#define IS_EQ_PROP_OR(inst, prop, default_value, compare_value) \
	IS_EQ(DT_INST_PROP_OR(inst, prop, default_value), compare_value) ||

#define IS_EQ_NODE_PROP_OR(node, prop, default_value, compare_value) \
	IS_EQ(DT_PROP_OR(node, prop, default_value), compare_value) ||

#define IS_EQ_STRING_PROP(inst, prop, compare_value, prefix) \
	IS_EQ(CONCAT(prefix, DT_INST_STRING_UPPER_TOKEN(inst, prop)), compare_value) ||

/* reference voltage for the ADC */
#define STM32_ADC_VREF_MV DT_INST_PROP(0, vref_mv)

#if ANY_ADC_SEQUENCER_TYPE_IS(SEQUENCER_PROGRAMMABLE)

#if defined(LL_ADC_REG_RANK_28)
#define MAX_RANK	28
#elif defined(LL_ADC_REG_RANK_27)
#define MAX_RANK	27
#else
#define MAX_RANK	16
#endif

#define RANK(i, _)	_CONCAT_1(LL_ADC_REG_RANK_, UTIL_INC(i))
static const uint32_t table_rank[] = {
	LISTIFY(MAX_RANK, RANK, (,))};

#define SEQ_LEN(i, _)	_CONCAT_2(LL_ADC_REG_SEQ_SCAN_ENABLE_, UTIL_INC(UTIL_INC(i)), RANKS)
/* Length of this array signifies the maximum sequence length */
static const uint32_t table_seq_len[] = {
	LL_ADC_REG_SEQ_SCAN_DISABLE,
	LISTIFY(UTIL_DEC(MAX_RANK), SEQ_LEN, (,))
};

#endif /* ANY_ADC_SEQUENCER_TYPE_IS(SEQUENCER_PROGRAMMABLE) */

/* Number of different sampling time values */
#define STM32_NB_SAMPLING_TIME	8

#ifdef CONFIG_ADC_STM32_DMA
struct stream {
	const struct device *dma_dev;
	uint32_t channel;
	struct dma_config dma_cfg;
	struct dma_block_config dma_blk_cfg;
	uint8_t priority;
	bool src_addr_increment;
	bool dst_addr_increment;
};
#endif /* CONFIG_ADC_STM32_DMA */

#if defined(CONFIG_SOC_SERIES_STM32N6X)
typedef uint32_t adc_data_size_t;
#else
typedef uint16_t adc_data_size_t;
#endif

struct adc_stm32_data {
	struct adc_context ctx;
	const struct device *dev;
	adc_data_size_t *buffer;
	adc_data_size_t *repeat_buffer;

	uint8_t resolution;
	uint32_t channels;
	uint8_t channel_count;
	uint8_t samples_count;
	int8_t acq_time_index[2];

#ifdef CONFIG_ADC_STM32_DMA
	volatile int dma_error;
	struct stream dma;
#endif
};

struct adc_stm32_cfg {
	ADC_TypeDef *base;
	void (*irq_cfg_func)(void);
	const struct stm32_pclken pclken;
	const struct stm32_pclken pclken_ker;
	const struct stm32_pclken pclken_pre;
	uint32_t clk_prescaler;
	const struct pinctrl_dev_config *pcfg;
	const uint16_t sampling_time_table[STM32_NB_SAMPLING_TIME];
	int8_t num_sampling_time_common_channels;
	int8_t sequencer_type;
	int8_t oversampler_type;
	int8_t internal_regulator;
	bool has_pclken_ker		:1;
	bool has_pclken_pre		:1;
	bool has_deep_powerdown		:1;
	bool has_channel_preselection	:1;
	bool has_differential_support	:1;
	bool differential_channels_used	:1;
	int8_t res_table_size;
	const uint32_t res_table[];
};

#ifdef CONFIG_ADC_STM32_DMA
static void adc_stm32_enable_dma_support(ADC_TypeDef *adc)
{
	/* Allow ADC to create DMA request and set to one-shot mode as implemented in HAL drivers */
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc)
	LL_ADC_REG_SetDMATransfer(adc, LL_ADC_REG_DMA_TRANSFER_UNLIMITED);
#elif defined(CONFIG_SOC_SERIES_STM32H7X) || \
	defined(CONFIG_SOC_SERIES_STM32N6X) || \
	defined(CONFIG_SOC_SERIES_STM32U3X) || \
	defined(CONFIG_SOC_SERIES_STM32U5X)
	/* H72x ADC3 and U5 ADC4 are different from the rest, but this call works also for them,
	 * so no need to call their specific function
	 */
	LL_ADC_REG_SetDataTransferMode(adc, LL_ADC_REG_DMA_TRANSFER_LIMITED);
#else
	/* Default mechanism for other MCUs */
	LL_ADC_REG_SetDMATransfer(adc, LL_ADC_REG_DMA_TRANSFER_LIMITED);
#endif
}

static int adc_stm32_dma_start(const struct device *dev,
			       void *buffer, size_t channel_count)
{
	const struct adc_stm32_cfg *config = dev->config;
	ADC_TypeDef *adc = config->base;
	struct adc_stm32_data *data = dev->data;
	struct dma_block_config *blk_cfg;
	int ret;

	struct stream *dma = &data->dma;

	blk_cfg = &dma->dma_blk_cfg;

	/* prepare the block */
	blk_cfg->block_size = channel_count * sizeof(adc_data_size_t);

	/* Source and destination */
	blk_cfg->source_address = (uint32_t)LL_ADC_DMA_GetRegAddr(adc, LL_ADC_DMA_REG_REGULAR_DATA);
	blk_cfg->source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE;
	blk_cfg->source_reload_en = 0;

	blk_cfg->dest_address = (uint32_t)buffer;
	blk_cfg->dest_addr_adj = DMA_ADDR_ADJ_INCREMENT;
	blk_cfg->dest_reload_en = 0;

	/* Manually set the FIFO threshold to 1/4 because the
	 * dmamux DTS entry does not contain fifo threshold
	 */
	blk_cfg->fifo_mode_control = 0;

	/* direction is given by the DT */
	dma->dma_cfg.head_block = blk_cfg;
	dma->dma_cfg.user_data = data;

	ret = dma_config(data->dma.dma_dev, data->dma.channel,
			 &dma->dma_cfg);
	if (ret != 0) {
		LOG_ERR("Problem setting up DMA: %d", ret);
		return ret;
	}

	adc_stm32_enable_dma_support(adc);

	data->dma_error = 0;
	ret = dma_start(data->dma.dma_dev, data->dma.channel);
	if (ret != 0) {
		LOG_ERR("Problem starting DMA: %d", ret);
		return ret;
	}

	LOG_DBG("DMA started");

	return ret;
}
#endif /* CONFIG_ADC_STM32_DMA */

static int check_buffer(const struct adc_sequence *sequence,
			     uint8_t active_channels)
{
	size_t needed_buffer_size;

	needed_buffer_size = active_channels * sizeof(adc_data_size_t);

	if (sequence->options) {
		needed_buffer_size *= (1 + sequence->options->extra_samplings);
	}

	if (sequence->buffer_size < needed_buffer_size) {
		LOG_ERR("Provided buffer is too small (%u/%u)",
				sequence->buffer_size, needed_buffer_size);
		return -ENOMEM;
	}

#if defined(CONFIG_ADC_STM32_DMA)
	/* Buffer is forced to be in non-cacheable SRAM region to avoid cache maintenance */
	if (!stm32_buf_in_nocache((uintptr_t)sequence->buffer, needed_buffer_size)) {
		LOG_ERR("Supplied buffer is not in a non-cacheable region.");
		return -EINVAL;
	}
#endif /* CONFIG_ADC_STM32_DMA */

	return 0;
}

/*
 * Enable ADC peripheral, and wait until ready if required by SOC.
 */
static int adc_stm32_enable(ADC_TypeDef *adc)
{
	if (LL_ADC_IsEnabled(adc) == 1UL) {
		return 0;
	}

#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && \
	!DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc)
	LL_ADC_ClearFlag_ADRDY(adc);
	LL_ADC_Enable(adc);

	/*
	 * Enabling ADC modules in many series may fail if they are
	 * still not stabilized, this will wait for a short time (about 1ms)
	 * to ensure ADC modules are properly enabled.
	 */
	uint32_t count_timeout = 0;

	while (LL_ADC_IsActiveFlag_ADRDY(adc) == 0) {
#ifdef CONFIG_SOC_SERIES_STM32F0X
		/* For F0, continue to write ADEN=1 until ADRDY=1 */
		if (LL_ADC_IsEnabled(adc) == 0UL) {
			LL_ADC_Enable(adc);
		}
#endif /* CONFIG_SOC_SERIES_STM32F0X */
		count_timeout++;
		k_busy_wait(100);
		if (count_timeout >= 10) {
			return -ETIMEDOUT;
		}
	}
#else
	/*
	 * On STM32F1, F2, F37x, F4, F7 and L1, do not re-enable the ADC.
	 * On F1 and F37x if ADON holds 1 (LL_ADC_IsEnabled is true) and 1 is
	 * written, then conversion starts. That's not what is expected.
	 */
	LL_ADC_Enable(adc);
#endif

	return 0;
}

static void adc_stm32_start_conversion(const struct device *dev)
{
	const struct adc_stm32_cfg *config = dev->config;
	ADC_TypeDef *adc = config->base;

	LOG_DBG("Starting conversion");

#if !defined(CONFIG_SOC_SERIES_STM32F1X) && \
	!DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc)
	LL_ADC_REG_StartConversion(adc);
#else
	LL_ADC_REG_StartConversionSWStart(adc);
#endif
}

/*
 * Disable ADC peripheral, and wait until it is disabled
 */
static void adc_stm32_disable(ADC_TypeDef *adc)
{
	if (LL_ADC_IsEnabled(adc) != 1UL) {
		return;
	}

	/* Stop ongoing conversion if any
	 * Software must poll ADSTART (or JADSTART) until the bit is reset before assuming
	 * the ADC is completely stopped.
	 */

#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && \
	!DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc)
	if (LL_ADC_REG_IsConversionOngoing(adc)) {
		LL_ADC_REG_StopConversion(adc);
		while (LL_ADC_REG_IsConversionOngoing(adc)) {
		}
	}
#endif

#if !defined(CONFIG_SOC_SERIES_STM32C0X) && \
	!defined(CONFIG_SOC_SERIES_STM32F0X) && \
	!DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && \
	!DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) && \
	!defined(CONFIG_SOC_SERIES_STM32G0X) && \
	!defined(CONFIG_SOC_SERIES_STM32L0X) && \
	!defined(CONFIG_SOC_SERIES_STM32U0X) && \
	!defined(CONFIG_SOC_SERIES_STM32WBAX) && \
	!defined(CONFIG_SOC_SERIES_STM32WLX)
	if (LL_ADC_INJ_IsConversionOngoing(adc)) {
		LL_ADC_INJ_StopConversion(adc);
		while (LL_ADC_INJ_IsConversionOngoing(adc)) {
		}
	}
#endif

	LL_ADC_Disable(adc);

	/* Wait ADC is fully disabled so that we don't leave the driver into intermediate state
	 * which could prevent enabling the peripheral
	 */
	while (LL_ADC_IsEnabled(adc) == 1UL) {
	}
}

#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc)

#define HAS_CALIBRATION

/* Number of ADC clock cycles to wait before of after starting calibration */
#if defined(LL_ADC_DELAY_CALIB_ENABLE_ADC_CYCLES)
#define ADC_DELAY_CALIB_ADC_CYCLES	LL_ADC_DELAY_CALIB_ENABLE_ADC_CYCLES
#elif defined(LL_ADC_DELAY_ENABLE_CALIB_ADC_CYCLES)
#define ADC_DELAY_CALIB_ADC_CYCLES	LL_ADC_DELAY_ENABLE_CALIB_ADC_CYCLES
#elif defined(LL_ADC_DELAY_DISABLE_CALIB_ADC_CYCLES)
#define ADC_DELAY_CALIB_ADC_CYCLES	LL_ADC_DELAY_DISABLE_CALIB_ADC_CYCLES
#endif

static void adc_stm32_calibration_delay(const struct device *dev)
{
	/*
	 * Calibration of F1 and F3 (ADC1_V2_5) must start two cycles after ADON
	 * is set.
	 * Other ADC modules have to wait for some cycles after calibration to
	 * be enabled.
	 */
	const struct adc_stm32_cfg *config = dev->config;
	const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
	uint32_t adc_rate, wait_cycles;

	if (clock_control_get_rate(clk, (clock_control_subsys_t)&config->pclken, &adc_rate) < 0) {
		LOG_ERR("ADC clock rate get error.");
	}

	if (adc_rate == 0) {
		LOG_ERR("ADC Clock rate null");
		return;
	}
	wait_cycles = SystemCoreClock / adc_rate *
		      ADC_DELAY_CALIB_ADC_CYCLES;

	for (int i = wait_cycles; i >= 0; i--) {
	}
}

#if defined(CONFIG_SOC_SERIES_STM32N6X)
/* Number of ADC measurement during calibration procedure */
#define ADC_CALIBRATION_STEPS (8U)

static void adc_stm32_calibration_measure(ADC_TypeDef *adc, uint32_t *calibration_factor)
{
	uint32_t calib_step;
	uint32_t calib_factor_avg = 0;
	uint8_t done = 0;

	do {
		for (calib_step = 0; calib_step < ADC_CALIBRATION_STEPS; calib_step++) {
			LL_ADC_REG_StartConversion(adc);
			while (LL_ADC_REG_IsConversionOngoing(adc) != 0UL) {
			}

			calib_factor_avg += LL_ADC_REG_ReadConversionData32(adc);
		}

		/* Compute the average data */
		calib_factor_avg /= ADC_CALIBRATION_STEPS;

		if ((calib_factor_avg == 0) && (LL_ADC_IsCalibrationOffsetEnabled(adc) == 0UL)) {
			/* If average is 0 and offset is disabled
			 * set offset and repeat measurements
			 */
			LL_ADC_EnableCalibrationOffset(adc);
		} else {
			*calibration_factor = (uint32_t)(calib_factor_avg);
			done = 1;
		}
	} while (done == 0);
}
#endif

static void adc_stm32_calibration_start(const struct device *dev, bool single_ended)
{
	const struct adc_stm32_cfg *config =
		(const struct adc_stm32_cfg *)dev->config;
	ADC_TypeDef *adc = config->base;
#if defined(LL_ADC_SINGLE_ENDED) && defined(LL_ADC_DIFFERENTIAL_ENDED)
	uint32_t calib_type = single_ended ? LL_ADC_SINGLE_ENDED : LL_ADC_DIFFERENTIAL_ENDED;
#else
	ARG_UNUSED(single_ended);
#endif

#if defined(STM32F3XX_ADC) || \
	defined(CONFIG_SOC_SERIES_STM32L4X) || \
	defined(CONFIG_SOC_SERIES_STM32L5X) || \
	defined(CONFIG_SOC_SERIES_STM32H5X) || \
	defined(CONFIG_SOC_SERIES_STM32H7RSX) || \
	defined(CONFIG_SOC_SERIES_STM32WBX) || \
	defined(CONFIG_SOC_SERIES_STM32G4X)
	LL_ADC_StartCalibration(adc, calib_type);
#elif defined(CONFIG_SOC_SERIES_STM32C0X) || \
	defined(CONFIG_SOC_SERIES_STM32F0X) || \
	DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) || \
	defined(CONFIG_SOC_SERIES_STM32G0X) || \
	defined(CONFIG_SOC_SERIES_STM32L0X) || \
	defined(CONFIG_SOC_SERIES_STM32U0X) || \
	defined(CONFIG_SOC_SERIES_STM32WLX) || \
	defined(CONFIG_SOC_SERIES_STM32WBAX)

	LL_ADC_StartCalibration(adc);
#elif defined(CONFIG_SOC_SERIES_STM32U5X)
	ARG_UNUSED(calib_type);
	if (adc != ADC4) {
		uint32_t dev_id = LL_DBGMCU_GetDeviceID();
		uint32_t rev_id = LL_DBGMCU_GetRevisionID();

		/* Some U5 implement an extended calibration to enhance ADC performance.
		 * It is not available for ADC4.
		 * It is available on all U5 except U575/585 (dev ID 482) revision X (rev ID 2001).
		 * The code below applies the procedure described in RM0456 in the ADC chapter:
		 * "Extended calibration mode"
		 */
		if ((dev_id != 0x482UL) && (rev_id != 0x2001UL)) {
			adc_stm32_enable(adc);
			stm32_reg_modify_bits(&adc->CR, ADC_CR_CALINDEX,
					      0x9UL << ADC_CR_CALINDEX_Pos);
			__DMB();
			stm32_reg_modify_bits(&adc->CALFACT2, 0xFFFFFF00UL, 0x03021100UL);
			__DMB();
			stm32_reg_set_bits(&adc->CALFACT, ADC_CALFACT_LATCH_COEF);
			adc_stm32_disable(adc);
		}
	}
	LL_ADC_StartCalibration(adc, LL_ADC_CALIB_OFFSET);
#elif defined(CONFIG_SOC_SERIES_STM32H7X)
	LL_ADC_StartCalibration(adc, LL_ADC_CALIB_OFFSET, calib_type);
#elif defined(CONFIG_SOC_SERIES_STM32N6X)
	uint32_t calibration_factor;

	ARG_UNUSED(calib_type);
	/* Start ADC calibration */
	LL_ADC_StartCalibration(adc, LL_ADC_SINGLE_ENDED);
	/* Disable additional offset before calibration start */
	LL_ADC_DisableCalibrationOffset(adc);

	adc_stm32_calibration_measure(adc, &calibration_factor);

	LL_ADC_SetCalibrationFactor(adc, LL_ADC_SINGLE_ENDED, calibration_factor);
	LL_ADC_StopCalibration(adc);
#endif
	/* Make sure ADCAL is cleared before returning for proper operations
	 * on the ADC control register, for enabling the peripheral for example
	 */
	while (LL_ADC_IsCalibrationOnGoing(adc)) {
	}
}

static int adc_stm32_calibrate(const struct device *dev)
{
	const struct adc_stm32_cfg *config =
		(const struct adc_stm32_cfg *)dev->config;
	ADC_TypeDef *adc = config->base;
	int err;

#if defined(CONFIG_ADC_STM32_DMA)
#if defined(CONFIG_SOC_SERIES_STM32C0X) || \
	defined(CONFIG_SOC_SERIES_STM32F0X) || \
	defined(CONFIG_SOC_SERIES_STM32G0X) || \
	defined(CONFIG_SOC_SERIES_STM32H7RSX) || \
	defined(CONFIG_SOC_SERIES_STM32L0X) || \
	defined(CONFIG_SOC_SERIES_STM32U0X) || \
	defined(CONFIG_SOC_SERIES_STM32WBAX) || \
	defined(CONFIG_SOC_SERIES_STM32WLX)
	/* Make sure DMA is disabled before starting calibration */
	LL_ADC_REG_SetDMATransfer(adc, LL_ADC_REG_DMA_TRANSFER_NONE);
#elif defined(CONFIG_SOC_SERIES_STM32U5X)
	if (adc == ADC4) {
		/* Make sure DMA is disabled before starting calibration */
		LL_ADC_REG_SetDMATransfer(adc, LL_ADC_REG_DMA_TRANSFER_NONE);
	}
#endif /* CONFIG_SOC_SERIES_* */
#endif /* CONFIG_ADC_STM32_DMA */

#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && \
	!defined(CONFIG_SOC_SERIES_STM32N6X)
	adc_stm32_disable(adc);
	adc_stm32_calibration_start(dev, true);
	if (config->differential_channels_used) {
		adc_stm32_calibration_start(dev, false);
	}
	adc_stm32_calibration_delay(dev);
#endif /* !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) */

	err = adc_stm32_enable(adc);
	if (err < 0) {
		return err;
	}

#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) || \
	defined(CONFIG_SOC_SERIES_STM32N6X)
	adc_stm32_calibration_delay(dev);
	adc_stm32_calibration_start(dev, true);
#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) */

#if defined(CONFIG_SOC_SERIES_STM32H7X) && \
	defined(CONFIG_CPU_CORTEX_M7)
	/*
	 * To ensure linearity the factory calibration values
	 * should be loaded on initialization.
	 */
	uint32_t channel_offset = 0U;
	uint32_t linear_calib_buffer = 0U;

	if (adc == ADC1) {
		channel_offset = 0UL;
	} else if (adc == ADC2) {
		channel_offset = 8UL;
	} else   /*Case ADC3*/ {
		channel_offset = 16UL;
	}
	/* Read factory calibration factors */
	for (uint32_t count = 0UL; count < ADC_LINEAR_CALIB_REG_COUNT; count++) {
		linear_calib_buffer = *(uint32_t *)(
			ADC_LINEAR_CALIB_REG_1_ADDR + channel_offset + count
		);

		LL_ADC_SetCalibrationLinearFactor(
			adc, LL_ADC_CALIB_LINEARITY_WORD1 << count,
			linear_calib_buffer
		);
	}
#endif /* CONFIG_SOC_SERIES_STM32H7X */

	return 0;
}
#endif /* !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) */

#if !defined(CONFIG_SOC_SERIES_STM32F0X) && \
	!defined(CONFIG_SOC_SERIES_STM32F1X) && \
	!defined(CONFIG_SOC_SERIES_STM32F3X) && \
	!DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc)

#define HAS_OVERSAMPLING

#if defined(LL_ADC_OVS_SHIFT_RIGHT_10)
#define MAX_OVS_SHIFT	10
#else
#define MAX_OVS_SHIFT	8
#endif

#define OVS_SHIFT(i, _)	_CONCAT_1(LL_ADC_OVS_SHIFT_RIGHT_, UTIL_INC(i))
static const uint32_t table_oversampling_shift[] = {
	LL_ADC_OVS_SHIFT_NONE,
	LISTIFY(MAX_OVS_SHIFT, OVS_SHIFT, (,))
};

#if ANY_ADC_OVERSAMPLER_TYPE_IS(OVERSAMPLER_MINIMAL)
#define OVS_RATIO(n)		LL_ADC_OVS_RATIO_##n
static const uint32_t table_oversampling_ratio[] = {
	0,
	OVS_RATIO(2),
	OVS_RATIO(4),
	OVS_RATIO(8),
	OVS_RATIO(16),
	OVS_RATIO(32),
	OVS_RATIO(64),
	OVS_RATIO(128),
	OVS_RATIO(256),
};
#endif

/*
 * Function to configure the oversampling scope. It is basically a wrapper over
 * LL_ADC_SetOverSamplingScope() which in addition stops the ADC if needed.
 */
static void adc_stm32_oversampling_scope(ADC_TypeDef *adc, uint32_t ovs_scope)
{
#if defined(CONFIG_SOC_SERIES_STM32G0X) || \
	defined(CONFIG_SOC_SERIES_STM32L0X) || \
	defined(CONFIG_SOC_SERIES_STM32WLX)
	/*
	 * Setting OVS bits is conditioned to ADC state: ADC must be disabled
	 * or enabled without conversion on going : disable it, it will stop.
	 * For the G0 series, ADC must be disabled to prevent CKMODE bitfield
	 * from getting reset, see errata ES0418 section 2.6.4.
	 */
	if (LL_ADC_GetOverSamplingScope(adc) == ovs_scope) {
		return;
	}
	adc_stm32_disable(adc);
#endif
	LL_ADC_SetOverSamplingScope(adc, ovs_scope);
}

/*
 * Function to configure the oversampling ratio and shift. It is basically a
 * wrapper over LL_ADC_SetOverSamplingRatioShift() which in addition stops the
 * ADC if needed.
 */
static void adc_stm32_oversampling_ratioshift(ADC_TypeDef *adc, uint32_t ratio, uint32_t shift)
{
	/*
	 * setting OVS bits is conditioned to ADC state: ADC must be disabled
	 * or enabled without conversion on going : disable it, it will stop
	 */
	if ((LL_ADC_GetOverSamplingRatio(adc) == ratio)
	    && (LL_ADC_GetOverSamplingShift(adc) == shift)) {
		return;
	}
	adc_stm32_disable(adc);

	LL_ADC_ConfigOverSamplingRatioShift(adc, ratio, shift);
}

/*
 * Function to configure the oversampling ratio and shift using stm32 LL
 * ratio is directly the sequence->oversampling (a 2^n value)
 * shift is the corresponding LL_ADC_OVS_SHIFT_RIGHT_x constant
 */
static int adc_stm32_oversampling(const struct device *dev, uint8_t ratio)
{
	const struct adc_stm32_cfg *config = dev->config;
	ADC_TypeDef *adc = config->base;

	if (ratio == 0) {
		adc_stm32_oversampling_scope(adc, LL_ADC_OVS_DISABLE);
		return 0;
	} else if (ratio < ARRAY_SIZE(table_oversampling_shift)) {
		adc_stm32_oversampling_scope(adc, LL_ADC_OVS_GRP_REGULAR_CONTINUED);
	} else {
		LOG_ERR("Invalid oversampling");
		return -EINVAL;
	}

	uint32_t shift = table_oversampling_shift[ratio];

#if ANY_ADC_OVERSAMPLER_TYPE_IS(OVERSAMPLER_MINIMAL)
	if (config->oversampler_type == OVERSAMPLER_MINIMAL) {
		/* the LL function expects a value LL_ADC_OVS_RATIO_x */
		adc_stm32_oversampling_ratioshift(adc, table_oversampling_ratio[ratio], shift);
	}
#endif

#if ANY_ADC_OVERSAMPLER_TYPE_IS(OVERSAMPLER_EXTENDED)
	if (config->oversampler_type == OVERSAMPLER_EXTENDED) {
		/* the LL function expects a value from 1 to 1024 */
		adc_stm32_oversampling_ratioshift(adc, 1 << ratio, shift);
	}
#endif

	return 0;
}
#endif /* CONFIG_SOC_SERIES_STM32xxx */

#ifdef CONFIG_ADC_STM32_DMA
static void dma_callback(const struct device *dev, void *user_data,
			 uint32_t channel, int status)
{
	/* user_data directly holds the adc device */
	struct adc_stm32_data *data = user_data;
#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) /* Avoid unused variables */
	const struct adc_stm32_cfg *config = data->dev->config;
	ADC_TypeDef *adc = config->base;
#endif /* !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) */

	LOG_DBG("dma callback");

	if (channel == data->dma.channel) {
#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc)
		if (LL_ADC_IsActiveFlag_OVR(adc)) {
			LL_ADC_ClearFlag_OVR(adc);
			LOG_ERR("ADC overrun error occurred. Reduce clock source frequency, "
				"increase prescaler value or increase sampling times.");
		}
#endif /* !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) */
		if (status >= 0) {
			data->samples_count = data->channel_count;
			data->buffer += data->channel_count;
			/* Stop the DMA engine, only to start it again when the callback returns
			 * ADC_ACTION_REPEAT or ADC_ACTION_CONTINUE, or the number of samples
			 * haven't been reached Starting the DMA engine is done
			 * within adc_context_start_sampling
			 */
			dma_stop(data->dma.dma_dev, data->dma.channel);
			/* No need to invalidate the cache because it's assumed that
			 * the address is in a non-cacheable SRAM region.
			 */
			adc_context_on_sampling_done(&data->ctx, dev);
			pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE,
						 PM_ALL_SUBSTATES);
			if (IS_ENABLED(CONFIG_PM_S2RAM)) {
				pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_RAM,
							 PM_ALL_SUBSTATES);
			}
		} else if (status < 0) {
			LOG_ERR("DMA sampling complete, but DMA reported error %d", status);
			data->dma_error = status;
#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc)
			LL_ADC_REG_StopConversion(adc);
#endif
			dma_stop(data->dma.dma_dev, data->dma.channel);
			if (data->ctx.options.interval_us != 0U) {
				adc_context_disable_timer(&data->ctx);
			}
			adc_context_complete(&data->ctx, status);
		}
	}
}
#endif /* CONFIG_ADC_STM32_DMA */

static uint8_t get_reg_value(const struct device *dev, uint32_t reg,
			     uint32_t shift, uint32_t mask)
{
	const struct adc_stm32_cfg *config = dev->config;
	ADC_TypeDef *adc = config->base;

	uintptr_t addr = (uintptr_t)adc + reg;

	return ((*(volatile uint32_t *)addr >> shift) & mask);
}

static void set_reg_value(const struct device *dev, uint32_t reg,
			  uint32_t shift, uint32_t mask, uint32_t value)
{
	const struct adc_stm32_cfg *config = dev->config;
	size_t reg32_offset = reg / sizeof(uint32_t);
	volatile uint32_t *addr = (volatile uint32_t *)config->base + reg32_offset;

	stm32_reg_modify_bits(addr, mask << shift, value << shift);
}

static int set_resolution(const struct device *dev,
			  const struct adc_sequence *sequence)
{
	const struct adc_stm32_cfg *config = dev->config;
	ADC_TypeDef *adc = config->base;
	uint8_t res_reg_addr = 0xFF;
	uint8_t res_shift = 0;
	uint8_t res_mask = 0;
	uint8_t res_reg_val = 0;
	int i;

	for (i = 0; i < config->res_table_size; i++) {
		if (sequence->resolution == STM32_ADC_GET_REAL_VAL(config->res_table[i])) {
			res_reg_addr = STM32_ADC_GET_REG(config->res_table[i]);
			res_shift = STM32_ADC_GET_SHIFT(config->res_table[i]);
			res_mask = STM32_ADC_GET_MASK(config->res_table[i]);
			res_reg_val = STM32_ADC_GET_REG_VAL(config->res_table[i]);
			break;
		}
	}

	if (i == config->res_table_size) {
		LOG_ERR("Invalid resolution");
		return -EINVAL;
	}

	/*
	 * Some MCUs (like STM32F1x) have no register to configure resolution.
	 * These MCUs have a register address value of 0xFF and should be
	 * ignored.
	 */
	if (res_reg_addr != 0xFF) {
		/*
		 * We don't use LL_ADC_SetResolution and LL_ADC_GetResolution
		 * because they don't strictly use hardware resolution values
		 * and makes internal conversions for some series.
		 * (see stm32h7xx_ll_adc.h)
		 * Instead we set the register ourselves if needed.
		 */
		if (get_reg_value(dev, res_reg_addr, res_shift, res_mask) != res_reg_val) {
			/*
			 * Writing ADC_CFGR1 register while ADEN bit is set
			 * resets RES[1:0] bitfield. We need to disable and enable adc.
			 */
			adc_stm32_disable(adc);
			set_reg_value(dev, res_reg_addr, res_shift, res_mask, res_reg_val);
		}
	}

	return 0;
}

static int set_sequencer(const struct device *dev)
{
	const struct adc_stm32_cfg *config = dev->config;
	struct adc_stm32_data *data = dev->data;
	ADC_TypeDef *adc = config->base;

	uint8_t channel_id;
	uint8_t channel_index = 0;
	uint32_t channels_mask = 0;

	/* Iterate over selected channels in bitmask keeping track of:
	 * - channel_index: ranging from 0 -> ( data->channel_count - 1 )
	 * - channel_id: ordinal position of channel in data->channels bitmask
	 */
	for (uint32_t channels = data->channels; channels;
		      channels &= ~BIT(channel_id), channel_index++) {
		channel_id = find_lsb_set(channels) - 1;

		uint32_t channel = __LL_ADC_DECIMAL_NB_TO_CHANNEL(channel_id);

		channels_mask |= channel;

#if ANY_ADC_SEQUENCER_TYPE_IS(SEQUENCER_PROGRAMMABLE)
		if (config->sequencer_type == SEQUENCER_PROGRAMMABLE) {
#if ANY_ADC_HAS_CHANNEL_PRESELECTION
			if (config->has_channel_preselection) {
				/*
				 * Each channel in the sequence must be previously enabled in PCSEL.
				 * This register controls the analog switch integrated in the IO
				 * level.
				 */
				LL_ADC_SetChannelPreselection(adc, channel);
			}
#endif /* ANY_ADC_HAS_CHANNEL_PRESELECTION */
			LL_ADC_REG_SetSequencerRanks(adc, table_rank[channel_index], channel);
			LL_ADC_REG_SetSequencerLength(adc, table_seq_len[channel_index]);
		}
#endif /* ANY_ADC_SEQUENCER_TYPE_IS(SEQUENCER_PROGRAMMABLE) */
	}

#if ANY_ADC_SEQUENCER_TYPE_IS(SEQUENCER_FIXED)
	if (config->sequencer_type == SEQUENCER_FIXED) {
		LL_ADC_REG_SetSequencerChannels(adc, channels_mask);

#ifdef LL_ADC_FLAG_CCRDY
		/*
		 * After modifying sequencer it is mandatory to wait for the
		 * assertion of CCRDY flag
		 */
		while (LL_ADC_IsActiveFlag_CCRDY(adc) == 0) {
		}
		LL_ADC_ClearFlag_CCRDY(adc);
#endif /* LL_ADC_FLAG_CCRDY */
	}
#endif /* ANY_ADC_SEQUENCER_TYPE_IS(SEQUENCER_FIXED) */

#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) || \
	DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc)
	LL_ADC_SetSequencersScanMode(adc, LL_ADC_SEQ_SCAN_ENABLE);
#endif /* st_stm32f1_adc || st_stm32f4_adc */

	return 0;
}

static int start_read(const struct device *dev,
		      const struct adc_sequence *sequence)
{
	const struct adc_stm32_cfg *config = dev->config;
	struct adc_stm32_data *data = dev->data;
	ADC_TypeDef *adc = config->base;
	int err;

	data->buffer = sequence->buffer;
	data->channels = sequence->channels;
	data->channel_count = POPCOUNT(data->channels);
	data->samples_count = 0;

	if (data->channel_count == 0) {
		LOG_ERR("No channels selected");
		return -EINVAL;
	}

#if ANY_ADC_SEQUENCER_TYPE_IS(SEQUENCER_PROGRAMMABLE)
	if (data->channel_count > ARRAY_SIZE(table_seq_len)) {
		LOG_ERR("Too many channels for sequencer. Max: %d", ARRAY_SIZE(table_seq_len));
		return -EINVAL;
	}
#endif /* ANY_ADC_SEQUENCER_TYPE_IS(SEQUENCER_PROGRAMMABLE) */

#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && !defined(CONFIG_ADC_STM32_DMA)
	/* Multiple samplings is only supported with DMA for F1 */
	if (data->channel_count > 1) {
		LOG_ERR("Without DMA, this device only supports single channel sampling");
		return -EINVAL;
	}
#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && !CONFIG_ADC_STM32_DMA */

	/* Check and set the resolution */
	err = set_resolution(dev, sequence);
	if (err < 0) {
		return err;
	}

	/* Configure the sequencer */
	err = set_sequencer(dev);
	if (err < 0) {
		return err;
	}

	err = check_buffer(sequence, data->channel_count);
	if (err) {
		return err;
	}

#ifdef HAS_OVERSAMPLING
	err = adc_stm32_oversampling(dev, sequence->oversampling);
	if (err) {
		return err;
	}
#else
	if (sequence->oversampling) {
		LOG_ERR("Oversampling not supported");
		return -ENOTSUP;
	}
#endif /* HAS_OVERSAMPLING */

	if (sequence->calibrate) {
#if defined(HAS_CALIBRATION)
		adc_stm32_calibrate(dev);
#else
		LOG_ERR("Calibration not supported");
		return -ENOTSUP;
#endif
	}

	/*
	 * Make sure the ADC is enabled as it might have been disabled earlier
	 * to set the resolution, to set the oversampling or to perform the
	 * calibration.
	 */
	adc_stm32_enable(adc);

#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc)
	LL_ADC_ClearFlag_OVR(adc);
#endif /* !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) */

#if !defined(CONFIG_ADC_STM32_DMA)
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc)
	/* Trigger an ISR after each sampling (not just end of sequence) */
	LL_ADC_REG_SetFlagEndOfConversion(adc, LL_ADC_REG_FLAG_EOC_UNITARY_CONV);
	LL_ADC_EnableIT_EOCS(adc);
#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc)
	LL_ADC_EnableIT_EOS(adc);
#else
	LL_ADC_EnableIT_EOC(adc);
#endif
#endif /* CONFIG_ADC_STM32_DMA */

	/* This call will start the DMA */
	adc_context_start_read(&data->ctx, sequence);

	int result = adc_context_wait_for_completion(&data->ctx);

#ifdef CONFIG_ADC_STM32_DMA
	/* check if there's anything wrong with dma start */
	result = (data->dma_error ? data->dma_error : result);
#endif

	return result;
}

static void adc_context_start_sampling(struct adc_context *ctx)
{
	struct adc_stm32_data *data =
		CONTAINER_OF(ctx, struct adc_stm32_data, ctx);
	const struct device *dev = data->dev;
	const struct adc_stm32_cfg *config = dev->config;
	__maybe_unused ADC_TypeDef *adc = config->base;

	data->repeat_buffer = data->buffer;

#ifdef CONFIG_ADC_STM32_DMA
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc)
	/* Make sure DMA bit of ADC register CR2 is set to 0 before starting a DMA transfer */
	LL_ADC_REG_SetDMATransfer(adc, LL_ADC_REG_DMA_TRANSFER_NONE);
#endif
	adc_stm32_dma_start(dev, data->buffer, data->channel_count);
#endif
	adc_stm32_start_conversion(dev);
}

static void adc_context_update_buffer_pointer(struct adc_context *ctx,
					      bool repeat_sampling)
{
	struct adc_stm32_data *data =
		CONTAINER_OF(ctx, struct adc_stm32_data, ctx);

	if (repeat_sampling) {
		data->buffer = data->repeat_buffer;
	}
}

#ifndef CONFIG_ADC_STM32_DMA
static void adc_stm32_isr(const struct device *dev)
{
	struct adc_stm32_data *data = dev->data;
	const struct adc_stm32_cfg *config =
		(const struct adc_stm32_cfg *)dev->config;
	ADC_TypeDef *adc = config->base;

#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc)
	if (LL_ADC_IsActiveFlag_OVR(adc)) {
		LL_ADC_ClearFlag_OVR(adc);
		LOG_ERR("ADC overrun error occurred. Use DMA, reduce clock source frequency, "
			"increase prescaler value or increase sampling times.");
	}
#endif /* !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) */

#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc)
	if (LL_ADC_IsActiveFlag_EOS(adc) == 1) {
#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc)
	if (LL_ADC_IsActiveFlag_EOCS(adc) == 1) {
#else
	if (LL_ADC_IsActiveFlag_EOC(adc) == 1) {
#endif
		*data->buffer++ = LL_ADC_REG_ReadConversionData32(adc);
		/* ISR is triggered after each conversion, and at the end-of-sequence. */
		if (++data->samples_count == data->channel_count) {
			data->samples_count = 0;
			adc_context_on_sampling_done(&data->ctx, dev);
			pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE,
						 PM_ALL_SUBSTATES);
			if (IS_ENABLED(CONFIG_PM_S2RAM)) {
				pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_RAM,
							 PM_ALL_SUBSTATES);
			}
		}
	}

	LOG_DBG("%s ISR triggered.", dev->name);
}
#endif /* !CONFIG_ADC_STM32_DMA */

static void adc_context_on_complete(struct adc_context *ctx, int status)
{
	struct adc_stm32_data *data =
		CONTAINER_OF(ctx, struct adc_stm32_data, ctx);
	const struct adc_stm32_cfg *config = data->dev->config;
	__maybe_unused ADC_TypeDef *adc = config->base;

	ARG_UNUSED(status);

	/* Reset acquisition time used for the sequence */
	data->acq_time_index[0] = -1;
	data->acq_time_index[1] = -1;

#if ANY_ADC_HAS_CHANNEL_PRESELECTION
	if (config->has_channel_preselection) {
		/* Reset channel preselection register */
		LL_ADC_SetChannelPreselection(adc, 0);
	}
#endif /* ANY_ADC_HAS_CHANNEL_PRESELECTION */
}

static int adc_stm32_read(const struct device *dev,
			  const struct adc_sequence *sequence)
{
	struct adc_stm32_data *data = dev->data;
	int error;

	adc_context_lock(&data->ctx, false, NULL);
	pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
	if (IS_ENABLED(CONFIG_PM_S2RAM)) {
		pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_RAM, PM_ALL_SUBSTATES);
	}
	error = start_read(dev, sequence);
	adc_context_release(&data->ctx, error);

	return error;
}

#ifdef CONFIG_ADC_ASYNC
static int adc_stm32_read_async(const struct device *dev,
				 const struct adc_sequence *sequence,
				 struct k_poll_signal *async)
{
	struct adc_stm32_data *data = dev->data;
	int error;

	adc_context_lock(&data->ctx, true, async);
	pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
	if (IS_ENABLED(CONFIG_PM_S2RAM)) {
		pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_RAM, PM_ALL_SUBSTATES);
	}
	error = start_read(dev, sequence);
	adc_context_release(&data->ctx, error);

	return error;
}
#endif

static int adc_stm32_sampling_time_check(const struct device *dev, uint16_t acq_time)
{
	const struct adc_stm32_cfg *config =
		(const struct adc_stm32_cfg *)dev->config;

	if (acq_time == ADC_ACQ_TIME_DEFAULT) {
		return 0;
	}

	if (acq_time == ADC_ACQ_TIME_MAX) {
		return STM32_NB_SAMPLING_TIME - 1;
	}

	if (ADC_ACQ_TIME_UNIT(acq_time) != ADC_ACQ_TIME_TICKS) {
		LOG_ERR("Acquisition time expected in ticks only");
		return -EINVAL;
	}

	for (int i = 0; i < STM32_NB_SAMPLING_TIME; i++) {
		if (acq_time == ADC_ACQ_TIME(ADC_ACQ_TIME_TICKS,
					     config->sampling_time_table[i])) {
			return i;
		}
	}

	LOG_ERR("Sampling time value not supported.");
	return -EINVAL;
}

static int adc_stm32_sampling_time_setup(const struct device *dev, uint8_t id,
					 uint16_t acq_time)
{
	const struct adc_stm32_cfg *config =
		(const struct adc_stm32_cfg *)dev->config;
	ADC_TypeDef *adc = config->base;
	__maybe_unused struct adc_stm32_data *data = dev->data;

	int acq_time_index;

	acq_time_index = adc_stm32_sampling_time_check(dev, acq_time);
	if (acq_time_index < 0) {
		return acq_time_index;
	}

	/*
	 * For all series we use the fact that the macros LL_ADC_SAMPLINGTIME_*
	 * that should be passed to the set functions are all coded on 3 bits
	 * with 0 shift (ie 0 to 7). So acq_time_index is equivalent to the
	 * macro we would use for the desired sampling time.
	 */
	switch (config->num_sampling_time_common_channels) {
	case 0:
#if ANY_NUM_COMMON_SAMPLING_TIME_CHANNELS_IS(0)
		LL_ADC_SetChannelSamplingTime(adc,
					      __LL_ADC_DECIMAL_NB_TO_CHANNEL(id),
					      (uint32_t)acq_time_index);
#endif
		break;
	case 1:
#if ANY_NUM_COMMON_SAMPLING_TIME_CHANNELS_IS(1)
		/* Only one sampling time can be selected for all channels.
		 * The first one we find is used, all others must match.
		 */
		if ((data->acq_time_index[0] == -1) ||
			(acq_time_index == data->acq_time_index[0])) {
			/* Reg is empty or value matches */
			data->acq_time_index[0] = acq_time_index;
			LL_ADC_SetSamplingTimeCommonChannels(adc,
							     (uint32_t)acq_time_index);
		} else {
			/* Reg is used and value does not match */
			LOG_ERR("Multiple sampling times not supported");
			return -EINVAL;
		}
#endif
		break;
	case 2:
#if ANY_NUM_COMMON_SAMPLING_TIME_CHANNELS_IS(2)
		/* Two different sampling times can be selected for all channels.
		 * The first two we find are used, all others must match either one.
		 */
		if ((data->acq_time_index[0] == -1) ||
			(acq_time_index == data->acq_time_index[0])) {
			/* 1st reg is empty or value matches 1st reg */
			data->acq_time_index[0] = acq_time_index;
			LL_ADC_SetChannelSamplingTime(adc,
						      __LL_ADC_DECIMAL_NB_TO_CHANNEL(id),
						      LL_ADC_SAMPLINGTIME_COMMON_1);
			LL_ADC_SetSamplingTimeCommonChannels(adc,
							     LL_ADC_SAMPLINGTIME_COMMON_1,
							     (uint32_t)acq_time_index);
		} else if ((data->acq_time_index[1] == -1) ||
			(acq_time_index == data->acq_time_index[1])) {
			/* 2nd reg is empty or value matches 2nd reg */
			data->acq_time_index[1] = acq_time_index;
			LL_ADC_SetChannelSamplingTime(adc,
						      __LL_ADC_DECIMAL_NB_TO_CHANNEL(id),
						      LL_ADC_SAMPLINGTIME_COMMON_2);
			LL_ADC_SetSamplingTimeCommonChannels(adc,
							     LL_ADC_SAMPLINGTIME_COMMON_2,
							     (uint32_t)acq_time_index);
		} else {
			/* Both regs are used, value does not match any of them */
			LOG_ERR("Only two different sampling times supported");
			return -EINVAL;
		}
#endif
		break;
	default:
		LOG_ERR("Number of common sampling time channels not supported");
		return -EINVAL;
	}
	return 0;
}

#if ANY_ADC_HAS_DIFFERENTIAL_SUPPORT
static void set_channel_differential_mode(ADC_TypeDef *adc, uint8_t channel_id, bool differential)
{
	const uint32_t mode = differential ? LL_ADC_DIFFERENTIAL_ENDED : LL_ADC_SINGLE_ENDED;
	const uint32_t channel = __LL_ADC_DECIMAL_NB_TO_CHANNEL(channel_id);

	/* The ADC must be disabled to change the single ended / differential mode setting. The
	 * disable / re-enable cycle can take some time, so avoid doing this if the channel is
	 * already set to the correct mode.
	 */
	if (LL_ADC_GetChannelSingleDiff(adc, channel) == mode) {
		return;
	}

	adc_stm32_disable(adc);
	LL_ADC_SetChannelSingleDiff(adc, channel, mode);
	adc_stm32_enable(adc);
}
#endif

static int adc_stm32_channel_setup(const struct device *dev,
				   const struct adc_channel_cfg *channel_cfg)
{
	const struct adc_stm32_cfg *config = (const struct adc_stm32_cfg *)dev->config;
#if defined(CONFIG_SOC_SERIES_STM32H5X) || ANY_ADC_HAS_DIFFERENTIAL_SUPPORT
	ADC_TypeDef *adc = config->base;
#endif

	if (!config->has_differential_support) {
		if (channel_cfg->differential) {
			LOG_ERR("Differential channels not supported on this ADC");
			return -EINVAL;
		}
	}
#if ANY_ADC_HAS_DIFFERENTIAL_SUPPORT
	else if (channel_cfg->differential && !config->differential_channels_used) {
		/* At least one channel must be set to differential mode in the devicetree
		 * to cause a differential calibration to be performed during init.
		 */
		LOG_ERR("Differential calibration not done, cannot use differential mode");
		return -EINVAL;
	}

	set_channel_differential_mode(adc, channel_cfg->channel_id, channel_cfg->differential);
#endif

	if (channel_cfg->gain != ADC_GAIN_1) {
		LOG_ERR("Invalid channel gain");
		return -EINVAL;
	}

	if (channel_cfg->reference != ADC_REF_INTERNAL) {
		LOG_ERR("Invalid channel reference");
		return -EINVAL;
	}

	if (adc_stm32_sampling_time_setup(dev, channel_cfg->channel_id,
					  channel_cfg->acquisition_time) != 0) {
		LOG_ERR("Invalid sampling time");
		return -EINVAL;
	}

#ifdef CONFIG_SOC_SERIES_STM32H5X
	if (adc == ADC1) {
		if (channel_cfg->channel_id == 0) {
			LL_ADC_EnableChannel0_GPIO(adc);
		}
	}
#endif

	LOG_DBG("Channel setup succeeded!");

	return 0;
}

#if defined(CONFIG_SOC_SERIES_STM32C0X) ||                                                     \
	defined(CONFIG_SOC_SERIES_STM32G0X) ||                                                     \
	defined(CONFIG_SOC_SERIES_STM32L0X) ||                                                     \
	defined(CONFIG_SOC_SERIES_STM32U0X) ||                                                     \
	(defined(CONFIG_SOC_SERIES_STM32WBX) && defined(ADC_SUPPORT_2_5_MSPS)) ||                  \
	defined(CONFIG_SOC_SERIES_STM32WLX)
#define ADC_STM32_HAS_INDIVIDUAL_CLOCKS
#endif

#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(ADC_STM32_HAS_INDIVIDUAL_CLOCKS)
static bool adc_stm32_is_clk_sync(const struct adc_stm32_cfg *config)
{
	if (config->clk_prescaler == LL_ADC_CLOCK_SYNC_PCLK_DIV1 ||
	    config->clk_prescaler == LL_ADC_CLOCK_SYNC_PCLK_DIV2 ||
	    config->clk_prescaler == LL_ADC_CLOCK_SYNC_PCLK_DIV4) {
		return true;
	}

	return false;
}
#endif

#if defined(CONFIG_SOC_SERIES_STM32H7X)
static inline int adc_stm32_get_input_freq_prescaler(void)
{
	int presc = 2;

#ifdef STM32H74X_ADC
	/* For revision Y we have no prescaler of 2 */
	if (LL_DBGMCU_GetRevisionID() <= 0x1003) {
		presc = 1;
	}
#endif

	return presc;
}

static int adc_stm32_get_clock_prescaler(const struct adc_stm32_cfg *config)
{
	switch (config->clk_prescaler) {
	case LL_ADC_CLOCK_SYNC_PCLK_DIV1:
	case LL_ADC_CLOCK_ASYNC_DIV1:
		return 1;
	case LL_ADC_CLOCK_SYNC_PCLK_DIV2:
	case LL_ADC_CLOCK_ASYNC_DIV2:
		return 2;
	case LL_ADC_CLOCK_SYNC_PCLK_DIV4:
	case LL_ADC_CLOCK_ASYNC_DIV4:
		return 4;
	case LL_ADC_CLOCK_ASYNC_DIV6:
		return 6;
	case LL_ADC_CLOCK_ASYNC_DIV8:
		return 8;
	case LL_ADC_CLOCK_ASYNC_DIV10:
		return 10;
	case LL_ADC_CLOCK_ASYNC_DIV12:
		return 12;
	case LL_ADC_CLOCK_ASYNC_DIV16:
		return 16;
	case LL_ADC_CLOCK_ASYNC_DIV32:
		return 32;
	case LL_ADC_CLOCK_ASYNC_DIV64:
		return 64;
	case LL_ADC_CLOCK_ASYNC_DIV128:
		return 128;
	case LL_ADC_CLOCK_ASYNC_DIV256:
		return 256;
	default:
		return -EINVAL;
	}
}

static int adc_stm32h7_setup_boost(const struct adc_stm32_cfg *config, ADC_TypeDef *adc,
				   const struct device *clk)
{
	clock_control_subsys_t clk_src;
	uint32_t input_freq;
	uint32_t boost;
	int presc;

	/* Get the input frequency */
	clk_src = (clock_control_subsys_t)(adc_stm32_is_clk_sync(config) ? &config->pclken
									 : &config->pclken_ker);

	if (clock_control_get_rate(clk, clk_src, &input_freq) != 0) {
		LOG_ERR("Failed to get ADC clock frequency");
		return -EIO;
	}

	/* Adjust the pre-scaler value so that we can divide down the clock */
	presc = adc_stm32_get_clock_prescaler(config);
	if (presc < 0) {
		LOG_ERR("Invalid clock prescaler value");
		return presc;
	}

	input_freq /= presc * adc_stm32_get_input_freq_prescaler();

	if (input_freq <= KHZ(6250)) {
		boost = LL_ADC_BOOST_MODE_6MHZ25;
	} else if (input_freq <= KHZ(12500)) {
		boost = LL_ADC_BOOST_MODE_12MHZ5;
	} else if (input_freq <= MHZ(20)) {
		boost = LL_ADC_BOOST_MODE_20MHZ;
	} else if (input_freq <= MHZ(25)) {
		boost = LL_ADC_BOOST_MODE_25MHZ;
	} else if (input_freq <= MHZ(50)) {
		boost = LL_ADC_BOOST_MODE_50MHZ;
	} else {
		LOG_WRN("ADC clock frequency too high %u", input_freq);
		return -ERANGE;
	}

	LL_ADC_SetBoostMode(adc, boost);

	return 0;
}
#endif

static int adc_stm32_set_clock(const struct device *dev)
{
	const struct adc_stm32_cfg *config = dev->config;
	const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
	__maybe_unused ADC_TypeDef *adc = config->base;
	int ret = 0;

	if (clock_control_on(clk, (clock_control_subsys_t)&config->pclken) != 0) {
		return -EIO;
	}

	/* Enable ADC clock source if applicable */
	if (config->has_pclken_ker &&
	    clock_control_configure(clk, (clock_control_subsys_t)&config->pclken_ker, NULL) != 0) {
		return -EIO;
	}

	/* Configure ADC prescaler (at RCC level) if applicable */
	if (config->has_pclken_pre &&
	    clock_control_configure(clk, (clock_control_subsys_t)&config->pclken_pre, NULL) != 0) {
		return -EIO;
	}

#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(st_adc_clock_source)
#if defined(CONFIG_SOC_SERIES_STM32F0X)
	LL_ADC_SetClock(adc, config->clk_prescaler);
#elif defined(ADC_STM32_HAS_INDIVIDUAL_CLOCKS)
	if (adc_stm32_is_clk_sync(config)) {
		LL_ADC_SetClock(adc, config->clk_prescaler);
	} else {
		LL_ADC_SetCommonClock(__LL_ADC_COMMON_INSTANCE(adc),
				      config->clk_prescaler);
		LL_ADC_SetClock(adc, LL_ADC_CLOCK_ASYNC);
	}
#else
	LL_ADC_SetCommonClock(__LL_ADC_COMMON_INSTANCE(adc),
			      config->clk_prescaler);

#ifdef CONFIG_SOC_SERIES_STM32H7X
	/* Set boost according to input frequency */
	ret = adc_stm32h7_setup_boost(config, adc, clk);
#endif
#endif
#endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(st_adc_clock_source) */

	return ret;
}

static void adc_stm32_enable_analog_supply(void)
{
#if defined(CONFIG_SOC_SERIES_STM32N6X)
	LL_PWR_EnableVddADC();
#elif defined(CONFIG_SOC_SERIES_STM32U5X) || defined(CONFIG_SOC_SERIES_STM32U3X)
	LL_PWR_EnableVDDA();
#endif /* CONFIG_SOC_SERIES_STM32U5X */
}

#ifdef CONFIG_PM_DEVICE
static void adc_stm32_disable_analog_supply(void)
{
#if defined(CONFIG_SOC_SERIES_STM32N6X)
	LL_PWR_DisableVddADC();
#elif defined(CONFIG_SOC_SERIES_STM32U5X) || defined(CONFIG_SOC_SERIES_STM32U3X)
	LL_PWR_DisableVDDA();
#endif /* CONFIG_SOC_SERIES_STM32U5X */
}
#endif

static int adc_stm32_init(const struct device *dev)
{
	struct adc_stm32_data *data = dev->data;
	const struct adc_stm32_cfg *config = dev->config;
	const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
	__maybe_unused ADC_TypeDef *adc = config->base;
	int err;

	LOG_DBG("Initializing %s", dev->name);

	if (!device_is_ready(clk)) {
		LOG_ERR("clock control device not ready");
		return -ENODEV;
	}

	data->dev = dev;

	/*
	 * For series that use common channels for sampling time, all
	 * conversion time for all channels on one ADC instance has to
	 * be the same.
	 * For series that use two common channels, there can be up to two
	 * conversion times selected for all channels in a sequence.
	 * This additional table is for checking that the conversion time
	 * selection of all channels respects these requirements.
	 */
	data->acq_time_index[0] = -1;
	data->acq_time_index[1] = -1;

	adc_stm32_set_clock(dev);

	/* Configure ADC inputs as specified in Device Tree, if any */
	err = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
	if ((err < 0) && (err != -ENOENT)) {
		/*
		 * If the ADC is used only with internal channels, then no pinctrl is
		 * provided in Device Tree, and pinctrl_apply_state returns -ENOENT,
		 * but this should not be treated as an error.
		 */
		LOG_ERR("ADC pinctrl setup failed (%d)", err);
		return err;
	}

	adc_stm32_enable_analog_supply();

#ifdef CONFIG_ADC_STM32_DMA
	if ((data->dma.dma_dev != NULL) &&
	    !device_is_ready(data->dma.dma_dev)) {
		LOG_ERR("%s device not ready", data->dma.dma_dev->name);
		return -ENODEV;
	}
#endif

#if ANY_ADC_HAS_DEEP_POWERDOWN
	if (config->has_deep_powerdown) {
		LL_ADC_DisableDeepPowerDown(adc);
	}
#endif

#if ANY_ADC_INTERNAL_REGULATOR_TYPE_IS(INTERNAL_REGULATOR_STARTUP_SW_DELAY) || \
	ANY_ADC_INTERNAL_REGULATOR_TYPE_IS(INTERNAL_REGULATOR_STARTUP_HW_STATUS)
	/*
	 * Many ADC modules need some time to be stabilized before performing
	 * any enable or calibration actions.
	 */
	if (config->internal_regulator != INTERNAL_REGULATOR_NONE) {
		LL_ADC_EnableInternalRegulator(adc);
	}

	/* Wait for Internal regulator stabilisation
	 * Some series have a dedicated status bit, others rely on a delay
	 */
#if ANY_ADC_INTERNAL_REGULATOR_TYPE_IS(INTERNAL_REGULATOR_STARTUP_SW_DELAY)
	if (config->internal_regulator == INTERNAL_REGULATOR_STARTUP_SW_DELAY) {
		k_busy_wait(LL_ADC_DELAY_INTERNAL_REGUL_STAB_US);
	}
#endif /* ANY_ADC_INTERNAL_REGULATOR_TYPE_IS(INTERNAL_REGULATOR_STARTUP_SW_DELAY) */
#if ANY_ADC_INTERNAL_REGULATOR_TYPE_IS(INTERNAL_REGULATOR_STARTUP_HW_STATUS)
	if (config->internal_regulator == INTERNAL_REGULATOR_STARTUP_HW_STATUS) {
		while (LL_ADC_IsActiveFlag_LDORDY(adc) == 0) {
		}
	}
#endif /* ANY_ADC_INTERNAL_REGULATOR_TYPE_IS(INTERNAL_REGULATOR_STARTUP_HW_STATUS) */

#endif /* INTERNAL_REGULATOR_STARTUP_SW_DELAY || INTERNAL_REGULATOR_STARTUP_HW_STATUS */

	if (config->irq_cfg_func) {
		config->irq_cfg_func();
	}

#if defined(HAS_CALIBRATION)
	adc_stm32_calibrate(dev);
	LL_ADC_REG_SetTriggerSource(adc, LL_ADC_REG_TRIG_SOFTWARE);
#endif /* HAS_CALIBRATION */

	adc_context_unlock_unconditionally(&data->ctx);

	return 0;
}

#ifdef CONFIG_PM_DEVICE
static int adc_stm32_suspend_setup(const struct device *dev)
{
	const struct adc_stm32_cfg *config = dev->config;
	ADC_TypeDef *adc = config->base;
	const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
	int err;

	/* Disable ADC */
	adc_stm32_disable(adc);

#if ANY_ADC_INTERNAL_REGULATOR_TYPE_IS(INTERNAL_REGULATOR_STARTUP_SW_DELAY) || \
	ANY_ADC_INTERNAL_REGULATOR_TYPE_IS(INTERNAL_REGULATOR_STARTUP_HW_STATUS)
	if (config->internal_regulator != INTERNAL_REGULATOR_NONE) {
		LL_ADC_DisableInternalRegulator(adc);
	}
#endif /* INTERNAL_REGULATOR_STARTUP_SW_DELAY || INTERNAL_REGULATOR_STARTUP_HW_STATUS */

#if ANY_ADC_HAS_DEEP_POWERDOWN
	if (config->has_deep_powerdown) {
		LL_ADC_EnableDeepPowerDown(adc);
	}
#endif

	adc_stm32_disable_analog_supply();

	/* Stop device clock. Note: fixed clocks are not handled yet. */
	err = clock_control_off(clk, (clock_control_subsys_t)&config->pclken);
	if (err != 0) {
		LOG_ERR("Could not disable ADC clock");
		return err;
	}

	/* Move pins to sleep state */
	err = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP);
	if ((err < 0) && (err != -ENOENT)) {
		/*
		 * If returning -ENOENT, no pins where defined for sleep mode :
		 * Do not output on console (might sleep already) when going to sleep,
		 * "ADC pinctrl sleep state not available"
		 * and don't block PM suspend.
		 * Else return the error.
		 */
		return err;
	}

	return 0;
}

static int adc_stm32_pm_action(const struct device *dev,
			       enum pm_device_action action)
{
	switch (action) {
	case PM_DEVICE_ACTION_RESUME:
		return adc_stm32_init(dev);
	case PM_DEVICE_ACTION_SUSPEND:
		return adc_stm32_suspend_setup(dev);
	default:
		return -ENOTSUP;
	}

	return 0;
}
#endif /* CONFIG_PM_DEVICE */

static DEVICE_API(adc, api_stm32_driver_api) = {
	.channel_setup = adc_stm32_channel_setup,
	.read = adc_stm32_read,
#ifdef CONFIG_ADC_ASYNC
	.read_async = adc_stm32_read_async,
#endif
	.ref_internal = STM32_ADC_VREF_MV, /* VREF is usually connected to VDD */
};

/* Macros for ADC clock source and prescaler */
#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(st_adc_clock_source)

#if defined(CONFIG_SOC_SERIES_STM32F0X)
/* LL_ADC_CLOCK_ASYNC_DIV1 doesn't exist in F0 LL. Define it here. */
#define LL_ADC_CLOCK_ASYNC_DIV1 LL_ADC_CLOCK_ASYNC
#endif

/* st_prescaler property requires 2 elements : clock ASYNC/SYNC and DIV */
#define ADC_STM32_CLOCK(x)	DT_INST_STRING_UPPER_TOKEN(x, st_adc_clock_source)
#define ADC_STM32_DIV(x)	DT_INST_PROP(x, st_adc_prescaler)

/* Macro to set the prefix depending on the 1st element: check if it is SYNC or ASYNC */
#define ADC_STM32_CLOCK_PREFIX(x)			\
	COND_CODE_1(IS_EQ(ADC_STM32_CLOCK(x), SYNC),	\
		(LL_ADC_CLOCK_SYNC_PCLK_DIV),		\
		(LL_ADC_CLOCK_ASYNC_DIV))

/* Concat prefix (1st element) and DIV value (2nd element) of st,adc-prescaler */
#define ADC_STM32_DT_PRESC(x)	\
	_CONCAT(ADC_STM32_CLOCK_PREFIX(x), ADC_STM32_DIV(x))

/* Macro to check if the ADC instance clock setup is correct */
#define ADC_STM32_CHECK_DT_CLOCK(x)								\
	BUILD_ASSERT(IS_EQ(ADC_STM32_CLOCK(x), SYNC) || DT_INST_CLOCKS_HAS_NAME(x, adc_ker),	\
		     "ASYNC clock mode defined without ASYNC clock defined in device tree")

#else /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(st_adc_clock_source) */

#define ADC_STM32_DT_PRESC(x)	0
#define ADC_STM32_CHECK_DT_CLOCK(x)

#endif /* !DT_ANY_INST_HAS_PROP_STATUS_OKAY(st_adc_clock_source) */


#if defined(CONFIG_ADC_STM32_DMA)

#define ADC_DMA_CHANNEL_INIT(index, src_dev, dest_dev)					\
	.dma = {									\
		.dma_dev = DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_IDX(index, 0)),		\
		.channel = DT_INST_DMAS_CELL_BY_IDX(index, 0, channel),			\
		.dma_cfg = {								\
			.dma_slot = STM32_DMA_SLOT_BY_IDX(index, 0, slot),		\
			.channel_direction = STM32_DMA_CONFIG_DIRECTION(		\
				STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)),		\
			.source_data_size = STM32_DMA_CONFIG_##src_dev##_DATA_SIZE(	\
				STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)),		\
			.dest_data_size = STM32_DMA_CONFIG_##dest_dev##_DATA_SIZE(	\
				STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)),		\
			.source_burst_length = 1,       /* SINGLE transfer */		\
			.dest_burst_length = 1,         /* SINGLE transfer */		\
			.channel_priority = STM32_DMA_CONFIG_PRIORITY(			\
				STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)),		\
			.dma_callback = dma_callback,					\
			.block_count = 2,						\
		},									\
		.src_addr_increment = STM32_DMA_CONFIG_##src_dev##_ADDR_INC(		\
			STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)),			\
		.dst_addr_increment = STM32_DMA_CONFIG_##dest_dev##_ADDR_INC(		\
			STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)),			\
	}

#define ADC_STM32_IRQ_FUNC(index)					\
	.irq_cfg_func = NULL,

#else /* CONFIG_ADC_STM32_DMA */

/*
 * For series that share interrupt lines for multiple ADC instances
 * and have separate interrupt lines for other ADCs (example,
 * STM32G473 has 5 ADC instances, ADC1 and ADC2 share IRQn 18 while
 * ADC3, ADC4 and ADC5 use IRQns 47, 61 and 62 respectively), generate
 * a single common ISR function for each IRQn and call adc_stm32_isr
 * for each device using that interrupt line for all enabled ADCs.
 *
 * To achieve the above, a "first" ADC instance must be chosen for all
 * ADC instances sharing the same IRQn. This "first" ADC instance
 * generates the code for the common ISR and for installing and
 * enabling it while any other ADC sharing the same IRQn skips this
 * code generation and does nothing. The common ISR code is generated
 * to include calls to adc_stm32_isr for all instances using that same
 * IRQn. From the example above, four ISR functions would be generated
 * for IRQn 18, 47, 61 and 62, with possible "first" ADC instances
 * being ADC1, ADC3, ADC4 and ADC5 if all ADCs were enabled, with the
 * ISR function 18 calling adc_stm32_isr for both ADC1 and ADC2.
 *
 * For some of the macros below, pseudo-code is provided to describe
 * its function.
 */

/*
 * return (irqn == device_irqn(index)) ? index : NULL
 */
#define FIRST_WITH_IRQN_INTERNAL(index, irqn)                                                      \
	COND_CODE_1(IS_EQ(irqn, DT_INST_IRQN(index)), (index,), (EMPTY,))

/*
 * Returns the "first" instance's index:
 *
 * instances = []
 * for instance in all_active_adcs:
 *     instances.append(first_with_irqn_internal(device_irqn(index)))
 * for instance in instances:
 *     if instance == NULL:
 *         instances.remove(instance)
 * return instances[0]
 */
#define FIRST_WITH_IRQN(index)                                                                     \
	GET_ARG_N(1, LIST_DROP_EMPTY(DT_INST_FOREACH_STATUS_OKAY_VARGS(FIRST_WITH_IRQN_INTERNAL,   \
								       DT_INST_IRQN(index))))

/*
 * Provides code for calling adc_stm32_isr for an instance if its IRQn
 * matches:
 *
 * if (irqn == device_irqn(index)):
 *     return "adc_stm32_isr(DEVICE_DT_INST_GET(index));"
 */
#define HANDLE_IRQS(index, irqn)                                                                   \
	COND_CODE_1(IS_EQ(irqn, DT_INST_IRQN(index)), (adc_stm32_isr(DEVICE_DT_INST_GET(index));), \
		    (EMPTY))

/*
 * Name of the common ISR for a given IRQn (taken from a device with a
 * given index). Example, for an ADC instance with IRQn 18, returns
 * "adc_stm32_isr_18".
 */
#define ISR_FUNC(index) UTIL_CAT(adc_stm32_isr_, DT_INST_IRQN(index))

/*
 * Macro for generating code for the common ISRs (by looping of all
 * ADC instances that share the same IRQn as that of the given device
 * by index) and the function for setting up the ISR.
 *
 * Here is where both "first" and non-"first" instances have code
 * generated for their interrupts via HANDLE_IRQS.
 */
#define GENERATE_ISR_CODE(index)                                                                   \
	static void ISR_FUNC(index)(void)                                                          \
	{                                                                                          \
		DT_INST_FOREACH_STATUS_OKAY_VARGS(HANDLE_IRQS, DT_INST_IRQN(index))                \
	}                                                                                          \
                                                                                                   \
	static void UTIL_CAT(ISR_FUNC(index), _init)(void)                                         \
	{                                                                                          \
		IRQ_CONNECT(DT_INST_IRQN(index), DT_INST_IRQ(index, priority), ISR_FUNC(index),    \
			    NULL, 0);                                                              \
		irq_enable(DT_INST_IRQN(index));                                                   \
	}

/*
 * Limit generating code to only the "first" instance:
 *
 * if (first_with_irqn(index) == index):
 *     generate_isr_code(index)
 */
#define GENERATE_ISR(index)                                                                        \
	COND_CODE_1(IS_EQ(index, FIRST_WITH_IRQN(index)), (GENERATE_ISR_CODE(index)), (EMPTY))

DT_INST_FOREACH_STATUS_OKAY(GENERATE_ISR)

/* Only "first" instances need to call the ISR setup function */
#define ADC_STM32_IRQ_FUNC(index)                                                                  \
	.irq_cfg_func = COND_CODE_1(IS_EQ(index, FIRST_WITH_IRQN(index)),                          \
				    (UTIL_CAT(ISR_FUNC(index), _init)), (NULL)),

#define ADC_DMA_CHANNEL_INIT(index, src_dev, dest_dev)

#endif /* CONFIG_ADC_STM32_DMA */

#define ADC_DMA_CHANNEL(id, src, dest)							\
	COND_CODE_1(DT_INST_DMAS_HAS_IDX(id, 0),					\
			(ADC_DMA_CHANNEL_INIT(id, src, dest)),				\
			(/* Required for other adc instances without dma */))

#define ADC_STM32_INIT(index)						\
									\
ADC_STM32_CHECK_DT_CLOCK(index);					\
									\
PINCTRL_DT_INST_DEFINE(index);						\
									\
static const struct adc_stm32_cfg adc_stm32_cfg_##index = {		\
	.base = (ADC_TypeDef *)DT_INST_REG_ADDR(index),			\
	ADC_STM32_IRQ_FUNC(index)					\
	.pclken = {.bus = DT_INST_CLOCKS_CELL_BY_NAME(index, adcx, bus),			\
		   .enr = DT_INST_CLOCKS_CELL_BY_NAME(index, adcx, bits)},			\
	COND_CODE_1(DT_INST_CLOCKS_HAS_NAME(index, adc_ker),					\
	(.pclken_ker = {.bus = DT_INST_CLOCKS_CELL_BY_NAME(index, adc_ker, bus),		\
			.enr = DT_INST_CLOCKS_CELL_BY_NAME(index, adc_ker, bits)},		\
	 .has_pclken_ker = true,),								\
	(.has_pclken_ker = false,))								\
	COND_CODE_1(DT_INST_CLOCKS_HAS_NAME(index, adc_pre),					\
	(.pclken_pre = {.bus = DT_INST_CLOCKS_CELL_BY_NAME(index, adc_pre, bus),		\
			.enr = DT_INST_CLOCKS_CELL_BY_NAME(index, adc_pre, bits)},		\
	 .has_pclken_pre = true,),								\
	(.has_pclken_pre = false,))								\
	.clk_prescaler = ADC_STM32_DT_PRESC(index),			\
	.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index),			\
	.differential_channels_used = (ANY_CHILD_NODE_IS_DIFFERENTIAL(index) > 0), \
	.sequencer_type = CONCAT(SEQUENCER_,							\
		DT_INST_STRING_UPPER_TOKEN(index, st_adc_sequencer)),				\
	.oversampler_type = CONCAT(OVERSAMPLER_,						\
		DT_INST_STRING_UPPER_TOKEN(index, st_adc_oversampler)),				\
	.internal_regulator = CONCAT(INTERNAL_REGULATOR_,					\
		DT_INST_STRING_UPPER_TOKEN(index, st_adc_internal_regulator)),			\
	.has_deep_powerdown = DT_INST_PROP(index, st_adc_has_deep_powerdown),			\
	.has_channel_preselection = DT_INST_PROP(index, st_adc_has_channel_preselection),	\
	.has_differential_support = DT_INST_PROP(index, st_adc_has_differential_support),	\
	.sampling_time_table = DT_INST_PROP(index, sampling_times),	\
	.num_sampling_time_common_channels =				\
		DT_INST_PROP_OR(index, num_sampling_time_common_channels, 0),\
	.res_table_size = DT_INST_PROP_LEN(index, resolutions),		\
	.res_table = DT_INST_PROP(index, resolutions),			\
};									\
									\
static struct adc_stm32_data adc_stm32_data_##index = {			\
	ADC_CONTEXT_INIT_TIMER(adc_stm32_data_##index, ctx),		\
	ADC_CONTEXT_INIT_LOCK(adc_stm32_data_##index, ctx),		\
	ADC_CONTEXT_INIT_SYNC(adc_stm32_data_##index, ctx),		\
	ADC_DMA_CHANNEL(index, PERIPHERAL, MEMORY)			\
};									\
									\
PM_DEVICE_DT_INST_DEFINE(index, adc_stm32_pm_action);			\
									\
DEVICE_DT_INST_DEFINE(index,						\
		    adc_stm32_init, PM_DEVICE_DT_INST_GET(index),	\
		    &adc_stm32_data_##index, &adc_stm32_cfg_##index,	\
		    POST_KERNEL, CONFIG_ADC_INIT_PRIORITY,		\
		    &api_stm32_driver_api);

DT_INST_FOREACH_STATUS_OKAY(ADC_STM32_INIT)
