blob: fe731c2db63cce932c132d3ccd519f74b716af6a [file] [log] [blame]
/*
* Copyright (c) 2025 Silicon Laboratories Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT silabs_iadc
#include <zephyr/drivers/adc.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/clock_control/clock_control_silabs.h>
#include <zephyr/drivers/dma.h>
#include <zephyr/drivers/dma/dma_silabs_ldma.h>
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/logging/log.h>
#include <zephyr/pm/device.h>
#include <sl_hal_iadc.h>
LOG_MODULE_REGISTER(iadc, CONFIG_ADC_LOG_LEVEL);
#define ADC_CONTEXT_USES_KERNEL_TIMER
#include "adc_context.h"
/* Comptibility section for IADC IP version*/
#if (_IADC_IPVERSION_RESETVALUE == 0x00000000UL)
#define IADC_NO_DIGAVG 1
#define _IADC_CFG_DIGAVG_AVG1 -1
#define _IADC_CFG_DIGAVG_AVG2 -1
#define _IADC_CFG_DIGAVG_AVG4 -1
#define _IADC_CFG_DIGAVG_AVG8 -1
#define _IADC_CFG_DIGAVG_AVG16 -1
#define IADC_NO_EXTENDED_ALIGN 1
#define _IADC_SCANFIFOCFG_ALIGNMENT_RIGHT16 -1
#define _IADC_SCANFIFOCFG_ALIGNMENT_RIGHT20 -1
#define _IADC_SCANFIFOCFG_ALIGNMENT_LEFT16 -1
#define _IADC_SCANFIFOCFG_ALIGNMENT_LEFT20 -1
#define IADC_EXPLICIT_NEG_PIN 1
#endif
#define IADC_PORT_MASK 0xF0
#define IADC_PIN_MASK 0x0F
struct iadc_dma_channel {
const struct device *dma_dev;
struct dma_block_config blk_cfg;
struct dma_config dma_cfg;
int dma_channel;
bool enabled;
};
struct iadc_chan_conf {
sl_hal_iadc_analog_gain_t gain;
sl_hal_iadc_voltage_reference_t reference;
sl_hal_iadc_positive_port_input_t pos_port;
uint8_t pos_pin;
sl_hal_iadc_negative_port_input_t neg_port;
uint8_t neg_pin;
uint8_t iadc_conf_id;
bool initialized;
};
struct iadc_data {
const struct device *dev;
struct adc_context ctx;
struct iadc_chan_conf chan_conf[SL_HAL_IADC_CHANNEL_ID_MAX];
struct iadc_dma_channel dma;
uint8_t adc_config_count; /* Number of ADC configs created (max 2) */
uint32_t clock_rate;
uint32_t channels;
uint16_t active_channels;
uint8_t alignment;
uint8_t oversampling;
uint8_t digital_averaging;
size_t data_size;
uint8_t *buffer;
};
struct iadc_config {
sl_hal_iadc_config_t config;
IADC_TypeDef *base;
const struct pinctrl_dev_config *pcfg;
const struct device *clock_dev;
struct silabs_clock_control_cmu_config clock_cfg;
void (*irq_cfg_func)(void);
};
static int iadc_find_or_create_adc_config(struct iadc_data *data, sl_hal_iadc_init_t *init,
const struct iadc_chan_conf *chan_conf)
{
int iadc_conf_id;
/* Check if we can reuse existing ADC configs */
for (int i = 0; i < data->adc_config_count; i++) {
if (chan_conf->gain == init->configs[i].analog_gain &&
chan_conf->reference == init->configs[i].reference) {
return i;
}
}
if (data->adc_config_count >= ARRAY_SIZE(init->configs)) {
LOG_ERR("Maximum of 2 different ADC configs supported");
return -EINVAL;
}
iadc_conf_id = data->adc_config_count;
init->configs[iadc_conf_id].analog_gain = chan_conf->gain;
init->configs[iadc_conf_id].reference = chan_conf->reference;
data->adc_config_count++;
return iadc_conf_id;
}
static void iadc_configure_scan_table_entry(sl_hal_iadc_scan_table_entry_t *entry,
const struct iadc_chan_conf *chan_conf)
{
*entry = (sl_hal_iadc_scan_table_entry_t){
.positive_port = chan_conf->pos_port,
.positive_pin = chan_conf->pos_pin,
.negative_port = chan_conf->neg_port,
.negative_pin = chan_conf->neg_pin,
.config_id = chan_conf->iadc_conf_id,
.include_in_scan = true,
};
}
#ifdef CONFIG_ADC_SILABS_IADC_DMA
static int iadc_dma_init(const struct device *dev)
{
const struct iadc_config *config = dev->config;
struct iadc_data *data = dev->data;
struct iadc_dma_channel *dma = &data->dma;
if (!dma->dma_dev) {
return 0;
}
if (!device_is_ready(dma->dma_dev)) {
LOG_ERR("DMA device not ready");
return -ENODEV;
}
dma->dma_channel = dma_request_channel(dma->dma_dev, NULL);
if (dma->dma_channel < 0) {
LOG_ERR("Failed to request DMA channel");
return -ENODEV;
}
memset(&dma->blk_cfg, 0, sizeof(dma->blk_cfg));
dma->blk_cfg.source_address = (uintptr_t)&(config->base)->SCANFIFODATA;
dma->blk_cfg.source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE;
dma->blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_INCREMENT;
dma->dma_cfg.complete_callback_en = 1;
dma->dma_cfg.channel_priority = 3;
dma->dma_cfg.channel_direction = PERIPHERAL_TO_MEMORY;
dma->dma_cfg.head_block = &dma->blk_cfg;
dma->dma_cfg.user_data = data;
return 0;
}
static int iadc_dma_start(const struct device *dev)
{
struct iadc_data *data = dev->data;
struct iadc_dma_channel *dma = &data->dma;
int ret;
if (!dma->dma_dev) {
return -ENODEV;
}
if (dma->enabled) {
return -EBUSY;
}
ret = dma_config(dma->dma_dev, dma->dma_channel, &dma->dma_cfg);
if (ret) {
LOG_ERR("DMA config error: %d", ret);
return ret;
}
dma->enabled = true;
ret = dma_start(dma->dma_dev, dma->dma_channel);
if (ret) {
LOG_ERR("DMA start error: %d", ret);
dma->enabled = false;
return ret;
}
return 0;
}
static void iadc_dma_stop(const struct device *dev)
{
struct iadc_data *data = dev->data;
struct iadc_dma_channel *dma = &data->dma;
if (!dma->enabled) {
return;
}
dma_stop(dma->dma_dev, dma->dma_channel);
dma->enabled = false;
}
static void iadc_dma_cb(const struct device *dma_dev, void *user_data, uint32_t channel, int status)
{
struct iadc_data *data = user_data;
const struct device *dev = data->dev;
if (status < 0) {
LOG_ERR("DMA transfer error: %d", status);
adc_context_complete(&data->ctx, status);
return;
}
iadc_dma_stop(dev);
adc_context_on_sampling_done(&data->ctx, dev);
}
#endif /* CONFIG_ADC_SILABS_IADC_DMA */
/* Oversampling and resolution are common for both ADC configs
* because they are not configurable per channel inside a ADC
* sequence and are common for a sequence.
*/
static int iadc_set_config(const struct device *dev)
{
const struct iadc_config *config = dev->config;
IADC_TypeDef *iadc = config->base;
struct iadc_data *data = dev->data;
sl_hal_iadc_scan_table_t scan_table = {};
sl_hal_iadc_init_t adc_init_config = {
.configs[0].analog_gain = _IADC_CFG_ANALOGGAIN_ANAGAIN1,
.configs[1].analog_gain = _IADC_CFG_ANALOGGAIN_ANAGAIN1,
.configs[0].vref = SL_HAL_IADC_DEFAULT_VREF,
.configs[1].vref = SL_HAL_IADC_DEFAULT_VREF,
.configs[0].osr_high_speed = data->oversampling,
.configs[1].osr_high_speed = data->oversampling,
#ifndef IADC_NO_DIGAVG
.configs[0].dig_avg = data->digital_averaging,
.configs[1].dig_avg = data->digital_averaging,
#endif
};
sl_hal_iadc_init_scan_t scan_init = {
.data_valid_level = _IADC_SCANFIFOCFG_DVL_VALID4,
.alignment = data->alignment,
};
struct iadc_chan_conf *chan_conf;
uint32_t channels;
int res;
if (data->dma.dma_dev) {
scan_init.data_valid_level = _IADC_SCANFIFOCFG_DVL_VALID1;
/* Only needed to wake up DMA if EM is 2/3 */
scan_init.fifo_dma_wakeup = true;
}
data->adc_config_count = 0;
if (data->dma.dma_dev) {
if (data->alignment == _IADC_SCANFIFOCFG_ALIGNMENT_RIGHT20) {
data->dma.dma_cfg.source_data_size = 4;
data->dma.dma_cfg.dest_data_size = 4;
data->dma.dma_cfg.source_burst_length = 4;
data->dma.dma_cfg.dest_burst_length = 4;
} else {
data->dma.dma_cfg.source_data_size = 2;
data->dma.dma_cfg.dest_data_size = 2;
data->dma.dma_cfg.source_burst_length = 2;
data->dma.dma_cfg.dest_burst_length = 2;
}
}
channels = data->channels;
/*
* Process each channel configuration and set up ADC scan sequence.
* The IADC hardware supports only 2 different ADC configurations
* (gain + reference combinations + oversampling), so we need to map
* multiple channel configs to these 2 available ADC configs.
*/
ARRAY_FOR_EACH(data->chan_conf, i) {
chan_conf = &data->chan_conf[i];
if (!chan_conf->initialized || (i != find_lsb_set(channels) - 1)) {
continue;
}
res = iadc_find_or_create_adc_config(data, &adc_init_config, chan_conf);
if (res < 0) {
LOG_DBG("IADC: too many different ADC configurations");
return res;
}
chan_conf->iadc_conf_id = res;
iadc_configure_scan_table_entry(&scan_table.entries[i], chan_conf);
channels &= ~BIT(i);
}
sl_hal_iadc_init(iadc, &adc_init_config, data->clock_rate);
sl_hal_iadc_init_scan(iadc, &scan_init, &scan_table);
sl_hal_iadc_set_scan_mask_multiple_entries(iadc, &scan_table);
return 0;
}
static int iadc_check_buffer_size(const struct adc_sequence *sequence, uint16_t active_channels,
size_t data_size)
{
size_t needed_buffer_size = active_channels * data_size;
if (sequence->options) {
needed_buffer_size *= (1 + sequence->options->extra_samplings);
}
if (sequence->buffer_size < needed_buffer_size) {
LOG_DBG("Provided buffer is too small (%u/%u)", sequence->buffer_size,
needed_buffer_size);
return -ENOMEM;
}
return 0;
}
/*
* Goal of this function is to have concensius between wanted resolution, oversampling,
* the IADC Alignment Table, analog oversampling and digital averaging.
*
* Formulas:
* Output Resolution = 11 + log2(OversamplingRatio × DigitalAveraging)
* +------------+-------------+---------------+---------------+-------------+
* | Alignment | Oversample | Digital Avg | Num Samples | Output Res |
* | Setting | Ratio | | Averaged | |
* +------------+-------------+---------------+---------------+-------------+
* | 16-bit | 2x | 1x | 2 | 12 bits |
* | 16-bit | 8x | 2x | 16 | 15 bits |
* | 20-bit | 2x | 1x | 2 | 12 bits |
* | 20-bit | 16x | 4x | 64 | 17 bits |
* +------------+-------------+---------------+---------------+-------------+
*/
static int iadc_check_oversampling_and_resolution(const struct adc_sequence *sequence,
struct iadc_data *data)
{
int res = sequence->resolution;
int ospl;
const static struct oversampling_table {
uint8_t analog_oversampling;
uint8_t digital_averaging;
} ospl_table[] = {
[0] = { _IADC_CFG_OSRHS_HISPD2, _IADC_CFG_DIGAVG_AVG1 }, /* 2x oversampling */
[1] = { _IADC_CFG_OSRHS_HISPD2, _IADC_CFG_DIGAVG_AVG1 }, /* 2x oversampling */
[2] = { _IADC_CFG_OSRHS_HISPD4, _IADC_CFG_DIGAVG_AVG1 }, /* 4x oversampling */
[3] = { _IADC_CFG_OSRHS_HISPD8, _IADC_CFG_DIGAVG_AVG1 }, /* 8x oversampling */
[4] = { _IADC_CFG_OSRHS_HISPD16, _IADC_CFG_DIGAVG_AVG1 }, /* 16x oversampling */
[5] = { _IADC_CFG_OSRHS_HISPD32, _IADC_CFG_DIGAVG_AVG1 }, /* 32x oversampling */
[6] = { _IADC_CFG_OSRHS_HISPD64, _IADC_CFG_DIGAVG_AVG1 }, /* 64x oversampling */
[7] = { _IADC_CFG_OSRHS_HISPD64, _IADC_CFG_DIGAVG_AVG2 }, /* 128x oversampling */
[8] = { _IADC_CFG_OSRHS_HISPD64, _IADC_CFG_DIGAVG_AVG4 }, /* 256x oversampling */
[9] = { _IADC_CFG_OSRHS_HISPD64, _IADC_CFG_DIGAVG_AVG8 }, /* 512x oversampling */
[10] = { _IADC_CFG_OSRHS_HISPD64, _IADC_CFG_DIGAVG_AVG16 }, /* 1024x oversampling */
};
if (!sequence->oversampling) {
ospl = 1;
} else {
ospl = sequence->oversampling;
}
if (ospl > ARRAY_SIZE(ospl_table) - 1) {
LOG_ERR("Unsupported oversampling %d", sequence->oversampling);
return -EINVAL;
}
if (ospl > 6 && IS_ENABLED(IADC_NO_DIGAVG)) {
LOG_ERR("Unsupported oversampling %d", ospl);
return -EINVAL;
}
if (res > 12 && IS_ENABLED(IADC_NO_EXTENDED_ALIGN)) {
LOG_ERR("Unsupported resolution %d", res);
return -EINVAL;
}
switch (res) {
case 12:
data->alignment = _IADC_SCANFIFOCFG_ALIGNMENT_RIGHT12;
break;
case 16:
data->alignment = _IADC_SCANFIFOCFG_ALIGNMENT_RIGHT16;
break;
case 20:
data->alignment = _IADC_SCANFIFOCFG_ALIGNMENT_RIGHT20;
break;
default:
LOG_ERR("Unsupported resolution %d", res);
return -EINVAL;
}
data->oversampling = ospl_table[ospl].analog_oversampling;
data->digital_averaging = ospl_table[ospl].digital_averaging;
return 0;
}
static int start_read(const struct device *dev, const struct adc_sequence *sequence)
{
struct iadc_data *data = dev->data;
uint32_t channels;
uint16_t channel_count;
uint16_t index;
int res;
if (sequence->channels == 0) {
LOG_DBG("No channel requested");
return -EINVAL;
}
res = iadc_check_oversampling_and_resolution(sequence, data);
if (res < 0) {
return res;
}
if (data->alignment == _IADC_SCANFIFOCFG_ALIGNMENT_RIGHT20) {
data->data_size = sizeof(uint32_t);
} else {
data->data_size = sizeof(uint16_t);
}
if (sequence->calibrate) {
/* TODO: Implement runtime calibration */
LOG_DBG("Hardware have hardcoded calibration value but runtime calibration is not "
"supported");
}
channels = sequence->channels;
channel_count = 0;
while (channels) {
index = find_lsb_set(channels) - 1;
if (index >= SL_HAL_IADC_CHANNEL_ID_MAX) {
LOG_DBG("Requested channel index not available: %d", index);
return -EINVAL;
}
if (!data->chan_conf[index].initialized) {
LOG_DBG("Channel not initialized");
return -EINVAL;
}
channel_count++;
channels &= ~BIT(index);
}
res = iadc_check_buffer_size(sequence, channel_count, data->data_size);
if (res < 0) {
return res;
}
data->buffer = sequence->buffer;
data->active_channels = channel_count;
if (data->dma.dma_dev) {
data->dma.blk_cfg.dest_address = (uintptr_t)data->buffer;
data->dma.blk_cfg.block_size = channel_count * data->data_size;
}
data->channels = sequence->channels;
res = iadc_set_config(data->dev);
if (res < 0) {
return res;
}
adc_context_start_read(&data->ctx, sequence);
res = adc_context_wait_for_completion(&data->ctx);
return res;
}
static void iadc_start_scan(const struct device *dev)
{
const struct iadc_config *config = dev->config;
__maybe_unused struct iadc_data *data = dev->data;
IADC_TypeDef *iadc = (IADC_TypeDef *)config->base;
#ifdef CONFIG_ADC_SILABS_IADC_DMA
if (data->dma.dma_dev) {
data->dma.blk_cfg.dest_address = (uintptr_t)data->buffer;
iadc_dma_start(dev);
} else {
sl_hal_iadc_enable_interrupts(iadc, IADC_IEN_SCANTABLEDONE);
}
#else
sl_hal_iadc_enable_interrupts(iadc, IADC_IEN_SCANTABLEDONE);
#endif
sl_hal_iadc_start_scan(iadc);
}
static void adc_context_start_sampling(struct adc_context *ctx)
{
struct iadc_data *data = CONTAINER_OF(ctx, struct iadc_data, ctx);
iadc_start_scan(data->dev);
}
static void adc_context_update_buffer_pointer(struct adc_context *ctx, bool repeat_sampling)
{
struct iadc_data *data = CONTAINER_OF(ctx, struct iadc_data, ctx);
if (!repeat_sampling) {
data->buffer += data->active_channels * data->data_size;
}
}
static void iadc_isr(void *arg)
{
const struct device *dev = (const struct device *)arg;
const struct iadc_config *config = dev->config;
struct iadc_data *data = dev->data;
uint8_t *sample_ptr = data->buffer;
IADC_TypeDef *iadc = config->base;
sl_hal_iadc_result_t sample;
uint32_t flags, err;
flags = sl_hal_iadc_get_pending_interrupts(iadc);
sl_hal_iadc_clear_interrupts(iadc, flags);
err = flags & (IADC_IF_PORTALLOCERR | IADC_IF_POLARITYERR | IADC_IF_EM23ABORTERROR |
IADC_IF_SCANFIFOOF | IADC_IF_SCANFIFOUF);
if (flags & IADC_IF_SCANTABLEDONE) {
while (sl_hal_iadc_get_scan_fifo_cnt(iadc) > 0) {
sample = sl_hal_iadc_pull_scan_fifo_result(iadc);
memcpy(sample_ptr, &sample.data, data->data_size);
sample_ptr += data->data_size;
}
adc_context_on_sampling_done(&data->ctx, dev);
}
if (err) {
LOG_ERR("IADC error, flags=%08x", err);
adc_context_complete(&data->ctx, -EIO);
}
}
static int iadc_read(const struct device *dev, const struct adc_sequence *sequence)
{
struct iadc_data *data = dev->data;
int error;
adc_context_lock(&data->ctx, false, NULL);
error = start_read(dev, sequence);
adc_context_release(&data->ctx, error);
return error;
}
#ifdef CONFIG_ADC_ASYNC
static int iadc_read_async(const struct device *dev, const struct adc_sequence *sequence,
struct k_poll_signal *async)
{
struct iadc_data *data = dev->data;
int error;
adc_context_lock(&data->ctx, true, async);
error = start_read(dev, sequence);
adc_context_release(&data->ctx, error);
return error;
}
#endif
static int iadc_channel_setup(const struct device *dev, const struct adc_channel_cfg *channel_cfg)
{
struct iadc_data *data = dev->data;
struct iadc_chan_conf *chan_conf = NULL;
if (channel_cfg->channel_id < SL_HAL_IADC_CHANNEL_ID_MAX) {
chan_conf = &data->chan_conf[channel_cfg->channel_id];
} else {
LOG_DBG("Requested channel index not available: %d", channel_cfg->channel_id);
return -EINVAL;
}
if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) {
LOG_ERR("Selected ADC acquisition time is not valid");
return -EINVAL;
}
chan_conf->initialized = false;
chan_conf->pos_port = (channel_cfg->input_positive & IADC_PORT_MASK) >> 4;
chan_conf->pos_pin = channel_cfg->input_positive & IADC_PIN_MASK;
if (channel_cfg->differential) {
chan_conf->neg_port = (channel_cfg->input_negative & IADC_PORT_MASK) >> 4;
chan_conf->neg_pin = channel_cfg->input_negative & IADC_PIN_MASK;
} else {
chan_conf->neg_port = _IADC_SCAN_PORTNEG_GND;
if (chan_conf->pos_port == _IADC_SCAN_PORTPOS_SUPPLY &&
IS_ENABLED(IADC_EXPLICIT_NEG_PIN)) {
chan_conf->neg_pin = 1;
}
}
switch (channel_cfg->gain) {
case ADC_GAIN_1_2:
chan_conf->gain = _IADC_CFG_ANALOGGAIN_ANAGAIN0P5;
break;
case ADC_GAIN_1:
chan_conf->gain = _IADC_CFG_ANALOGGAIN_ANAGAIN1;
break;
case ADC_GAIN_2:
chan_conf->gain = _IADC_CFG_ANALOGGAIN_ANAGAIN2;
break;
case ADC_GAIN_3:
chan_conf->gain = _IADC_CFG_ANALOGGAIN_ANAGAIN3;
break;
case ADC_GAIN_4:
chan_conf->gain = _IADC_CFG_ANALOGGAIN_ANAGAIN4;
break;
default:
LOG_ERR("unsupported channel gain '%d'", channel_cfg->gain);
return -EINVAL;
}
/* Setup reference */
switch (channel_cfg->reference) {
case ADC_REF_VDD_1:
chan_conf->reference = _IADC_CFG_REFSEL_VDDX;
break;
case ADC_REF_INTERNAL:
chan_conf->reference = _IADC_CFG_REFSEL_VBGR;
break;
case ADC_REF_EXTERNAL0:
chan_conf->reference = _IADC_CFG_REFSEL_VREF;
break;
default:
LOG_ERR("unsupported channel reference type '%d'", channel_cfg->reference);
return -EINVAL;
}
chan_conf->initialized = true;
LOG_DBG("Channel setup succeeded!");
return 0;
}
static int iadc_pm_action(const struct device *dev, enum pm_device_action action)
{
const struct iadc_config *config = dev->config;
int err;
if (action == PM_DEVICE_ACTION_RESUME) {
err = clock_control_on(config->clock_dev,
(clock_control_subsys_t)&config->clock_cfg);
if (err < 0 && err != -EALREADY) {
return err;
}
err = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
if (err < 0 && err != -ENOENT) {
return err;
}
} else if (IS_ENABLED(CONFIG_PM_DEVICE) && (action == PM_DEVICE_ACTION_SUSPEND)) {
err = clock_control_off(config->clock_dev,
(clock_control_subsys_t)&config->clock_cfg);
if (err < 0) {
return err;
}
err = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP);
if (err < 0 && err != -ENOENT) {
return err;
}
} else {
return -ENOTSUP;
}
return 0;
}
static int iadc_init(const struct device *dev)
{
const struct iadc_config *config = dev->config;
struct iadc_data *data = dev->data;
int ret;
data->dev = dev;
ret = clock_control_on(config->clock_dev, (clock_control_subsys_t)&config->clock_cfg);
if (ret < 0 && ret != -EALREADY) {
return ret;
}
ret = clock_control_get_rate(config->clock_dev, (clock_control_subsys_t)&config->clock_cfg,
&data->clock_rate);
if (ret < 0) {
return ret;
}
#ifdef CONFIG_ADC_SILABS_IADC_DMA
ret = iadc_dma_init(dev);
if (ret < 0) {
data->dma.dma_dev = NULL;
}
#endif
config->irq_cfg_func();
adc_context_unlock_unconditionally(&data->ctx);
return pm_device_driver_init(dev, iadc_pm_action);
}
static DEVICE_API(adc, iadc_api) = {
.channel_setup = iadc_channel_setup,
.read = iadc_read,
#ifdef CONFIG_ADC_ASYNC
.read_async = iadc_read_async,
#endif
.ref_internal = SL_HAL_IADC_DEFAULT_VREF,
};
#ifdef CONFIG_ADC_SILABS_IADC_DMA
#define IADC_DMA_CHANNEL_INIT(n) \
.dma.dma_dev = DEVICE_DT_GET(DT_INST_DMAS_CTLR(n)), \
.dma.dma_cfg.dma_slot = SILABS_LDMA_REQSEL_TO_SLOT(DT_INST_DMAS_CELL_BY_IDX(n, 0, slot)), \
.dma.dma_cfg.dma_callback = iadc_dma_cb,
#define IADC_DMA_CHANNEL(n) \
COND_CODE_1(DT_INST_NODE_HAS_PROP(n, dmas), (IADC_DMA_CHANNEL_INIT(n)), ())
#else
#define IADC_DMA_CHANNEL(n)
#endif
#define IADC_INIT(n) \
PINCTRL_DT_INST_DEFINE(n); \
PM_DEVICE_DT_INST_DEFINE(n, iadc_pm_action); \
\
static void iadc_config_func_##n(void); \
\
const static struct iadc_config iadc_config_##n = { \
.base = (IADC_TypeDef *)DT_INST_REG_ADDR(n), \
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \
.clock_cfg = SILABS_DT_INST_CLOCK_CFG(n), \
.irq_cfg_func = iadc_config_func_##n, \
}; \
\
static struct iadc_data iadc_data_##n = { \
ADC_CONTEXT_INIT_TIMER(iadc_data_##n, ctx), \
ADC_CONTEXT_INIT_LOCK(iadc_data_##n, ctx), \
ADC_CONTEXT_INIT_SYNC(iadc_data_##n, ctx), \
IADC_DMA_CHANNEL(n) \
}; \
\
static void iadc_config_func_##n(void) \
{ \
IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), iadc_isr, \
DEVICE_DT_INST_GET(n), 0); \
irq_enable(DT_INST_IRQN(n)); \
}; \
DEVICE_DT_INST_DEFINE(n, &iadc_init, PM_DEVICE_DT_INST_GET(n), &iadc_data_##n, \
&iadc_config_##n, POST_KERNEL, CONFIG_ADC_INIT_PRIORITY, &iadc_api);
DT_INST_FOREACH_STATUS_OKAY(IADC_INIT)