zephyr/drivers/adc/adc_esp32.c
Pieter De Gendt 8442b6a83f drivers: adc: Place API into iterable section
Move all adc driver api structs into an iterable section, this allows us
to verify if an api pointer is located in compatible linker section.

Signed-off-by: Pieter De Gendt <pieter.degendt@basalte.be>
2024-11-29 14:50:40 +01:00

754 lines
21 KiB
C

/*
* Copyright (c) 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT espressif_esp32_adc
#include <errno.h>
#include <hal/adc_hal.h>
#include <hal/adc_types.h>
#include <soc/adc_periph.h>
#include <esp_adc_cal.h>
#include <esp_clk_tree.h>
#include <esp_private/periph_ctrl.h>
#include <esp_private/sar_periph_ctrl.h>
#include <esp_private/adc_share_hw_ctrl.h>
#if defined(CONFIG_ADC_ESP32_DMA)
#if !SOC_GDMA_SUPPORTED
#error "SoCs without GDMA peripheral are not supported!"
#endif
#include <zephyr/drivers/dma.h>
#include <zephyr/drivers/dma/dma_esp32.h>
#endif
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/adc.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(adc_esp32, CONFIG_ADC_LOG_LEVEL);
#define ADC_RESOLUTION_MIN SOC_ADC_DIGI_MIN_BITWIDTH
#define ADC_RESOLUTION_MAX SOC_ADC_DIGI_MAX_BITWIDTH
#if CONFIG_SOC_SERIES_ESP32
#define ADC_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_VREF
/* Due to significant measurement discrepancy in higher voltage range, we
* clip the value instead of yet another correction. The IDF implementation
* for ESP32-S2 is doing it, so we copy that approach in Zephyr driver
*/
#define ADC_CLIP_MVOLT_12DB 2550
#elif CONFIG_SOC_SERIES_ESP32S3
#define ADC_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP_FIT
#else
#define ADC_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP
#endif
/* Validate if resolution in bits is within allowed values */
#define VALID_RESOLUTION(r) ((r) >= ADC_RESOLUTION_MIN && (r) <= ADC_RESOLUTION_MAX)
#define INVALID_RESOLUTION(r) (!VALID_RESOLUTION(r))
/* Default internal reference voltage */
#define ADC_ESP32_DEFAULT_VREF_INTERNAL (1100)
#define ADC_DMA_BUFFER_SIZE DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED
struct adc_esp32_conf {
adc_unit_t unit;
uint8_t channel_count;
#if defined(CONFIG_ADC_ESP32_DMA)
const struct device *gpio_port;
const struct device *dma_dev;
uint8_t dma_channel;
#endif /* defined(CONFIG_ADC_ESP32_DMA) */
};
struct adc_esp32_data {
adc_atten_t attenuation[SOC_ADC_MAX_CHANNEL_NUM];
uint8_t resolution[SOC_ADC_MAX_CHANNEL_NUM];
esp_adc_cal_characteristics_t chars[SOC_ADC_MAX_CHANNEL_NUM];
uint16_t meas_ref_internal;
uint16_t *buffer;
bool calibrate;
#if defined(CONFIG_ADC_ESP32_DMA)
adc_hal_dma_ctx_t adc_hal_dma_ctx;
uint8_t *dma_buffer;
struct k_sem dma_conv_wait_lock;
#endif /* defined(CONFIG_ADC_ESP32_DMA) */
};
/* Convert zephyr,gain property to the ESP32 attenuation */
static inline int gain_to_atten(enum adc_gain gain, adc_atten_t *atten)
{
switch (gain) {
case ADC_GAIN_1:
*atten = ADC_ATTEN_DB_0;
break;
case ADC_GAIN_4_5:
*atten = ADC_ATTEN_DB_2_5;
break;
case ADC_GAIN_1_2:
*atten = ADC_ATTEN_DB_6;
break;
case ADC_GAIN_1_4:
*atten = ADC_ATTEN_DB_12;
break;
default:
return -ENOTSUP;
}
return 0;
}
#if !defined(CONFIG_ADC_ESP32_DMA)
/* Convert voltage by inverted attenuation to support zephyr gain values */
static void atten_to_gain(adc_atten_t atten, uint32_t *val_mv)
{
if (!val_mv) {
return;
}
switch (atten) {
case ADC_ATTEN_DB_2_5:
*val_mv = (*val_mv * 4) / 5; /* 1/ADC_GAIN_4_5 */
break;
case ADC_ATTEN_DB_6:
*val_mv = *val_mv >> 1; /* 1/ADC_GAIN_1_2 */
break;
case ADC_ATTEN_DB_12:
*val_mv = *val_mv / 4; /* 1/ADC_GAIN_1_4 */
break;
case ADC_ATTEN_DB_0: /* 1/ADC_GAIN_1 */
default:
break;
}
}
#endif /* !defined(CONFIG_ADC_ESP32_DMA) */
static void adc_hw_calibration(adc_unit_t unit)
{
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
adc_hal_calibration_init(unit);
for (int j = 0; j < SOC_ADC_ATTEN_NUM; j++) {
adc_calc_hw_calibration_code(unit, j);
#if SOC_ADC_CALIB_CHAN_COMPENS_SUPPORTED
/* Load the channel compensation from efuse */
for (int k = 0; k < SOC_ADC_CHANNEL_NUM(unit); k++) {
adc_load_hw_calibration_chan_compens(unit, k, j);
}
#endif /* SOC_ADC_CALIB_CHAN_COMPENS_SUPPORTED */
}
#endif /* SOC_ADC_CALIBRATION_V1_SUPPORTED */
}
static bool adc_calibration_init(const struct device *dev)
{
switch (esp_adc_cal_check_efuse(ADC_CALI_SCHEME)) {
case ESP_ERR_NOT_SUPPORTED:
LOG_WRN("Skip software calibration - Not supported!");
break;
case ESP_ERR_INVALID_VERSION:
LOG_WRN("Skip software calibration - Invalid version!");
break;
case ESP_OK:
LOG_DBG("Software calibration possible");
return true;
default:
LOG_ERR("Invalid arg");
break;
}
return false;
}
#if defined(CONFIG_ADC_ESP32_DMA)
static void IRAM_ATTR adc_esp32_dma_conv_done(const struct device *dma_dev, void *user_data,
uint32_t channel, int status)
{
ARG_UNUSED(dma_dev);
ARG_UNUSED(status);
const struct device *dev = user_data;
struct adc_esp32_data *data = dev->data;
k_sem_give(&data->dma_conv_wait_lock);
}
static int adc_esp32_dma_start(const struct device *dev, uint8_t *buf, size_t len)
{
const struct adc_esp32_conf *conf = dev->config;
struct adc_esp32_data *data = dev->data;
int err = 0;
struct dma_config dma_cfg = {0};
struct dma_status dma_status = {0};
struct dma_block_config dma_blk = {0};
err = dma_get_status(conf->dma_dev, conf->dma_channel, &dma_status);
if (err) {
LOG_ERR("Unable to get dma channel[%u] status (%d)",
(unsigned int)conf->dma_channel, err);
return -EINVAL;
}
if (dma_status.busy) {
LOG_ERR("dma channel[%u] is busy!", (unsigned int)conf->dma_channel);
return -EBUSY;
}
unsigned int key = irq_lock();
dma_cfg.channel_direction = PERIPHERAL_TO_MEMORY;
dma_cfg.dma_callback = adc_esp32_dma_conv_done;
dma_cfg.user_data = (void *)dev;
dma_cfg.dma_slot = ESP_GDMA_TRIG_PERIPH_ADC0;
dma_cfg.block_count = 1;
dma_cfg.head_block = &dma_blk;
dma_blk.block_size = len;
dma_blk.dest_address = (uint32_t)buf;
err = dma_config(conf->dma_dev, conf->dma_channel, &dma_cfg);
if (err) {
LOG_ERR("Error configuring dma (%d)", err);
goto unlock;
}
err = dma_start(conf->dma_dev, conf->dma_channel);
if (err) {
LOG_ERR("Error starting dma (%d)", err);
goto unlock;
}
unlock:
irq_unlock(key);
return err;
}
static int adc_esp32_dma_stop(const struct device *dev)
{
const struct adc_esp32_conf *conf = dev->config;
unsigned int key = irq_lock();
int err = 0;
err = dma_stop(conf->dma_dev, conf->dma_channel);
if (err) {
LOG_ERR("Error stopping dma (%d)", err);
}
irq_unlock(key);
return err;
}
static int adc_esp32_fill_digi_pattern(const struct device *dev, const struct adc_sequence *seq,
void *pattern_config, uint32_t *pattern_len, uint32_t *unit_attenuation)
{
const struct adc_esp32_conf *conf = dev->config;
struct adc_esp32_data *data = dev->data;
adc_digi_pattern_config_t *adc_digi_pattern_config =
(adc_digi_pattern_config_t *)pattern_config;
const uint32_t unit_atten_uninit = 999;
uint32_t channel_mask = 1, channels_copy = seq->channels;
*pattern_len = 0;
*unit_attenuation = unit_atten_uninit;
for (uint8_t channel_id = 0; channel_id < conf->channel_count; channel_id++) {
if (channels_copy & channel_mask) {
if (*unit_attenuation == unit_atten_uninit) {
*unit_attenuation = data->attenuation[channel_id];
} else if (*unit_attenuation != data->attenuation[channel_id]) {
LOG_ERR("Channel[%u] attenuation different of unit[%u] attenuation",
(unsigned int)channel_id, (unsigned int)conf->unit);
return -EINVAL;
}
adc_digi_pattern_config->atten = data->attenuation[channel_id];
adc_digi_pattern_config->channel = channel_id;
adc_digi_pattern_config->unit = conf->unit;
adc_digi_pattern_config->bit_width = seq->resolution;
adc_digi_pattern_config++;
*pattern_len += 1;
if (*pattern_len > SOC_ADC_PATT_LEN_MAX) {
LOG_ERR("Max pattern len is %d", SOC_ADC_PATT_LEN_MAX);
return -EINVAL;
}
channels_copy &= ~channel_mask;
if (!channels_copy) {
break;
}
}
channel_mask <<= 1;
}
return 0;
}
static void adc_esp32_digi_start(const struct device *dev, void *pattern_config,
uint32_t pattern_len, uint32_t number_of_samplings,
uint32_t sample_freq_hz, uint32_t unit_attenuation)
{
const struct adc_esp32_conf *conf = dev->config;
struct adc_esp32_data *data = dev->data;
sar_periph_ctrl_adc_continuous_power_acquire();
adc_lock_acquire(conf->unit);
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
adc_set_hw_calibration_code(conf->unit, unit_attenuation);
#endif /* SOC_ADC_CALIBRATION_V1_SUPPORTED */
#if SOC_ADC_ARBITER_SUPPORTED
if (conf->unit == ADC_UNIT_2) {
adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT();
adc_hal_arbiter_config(&config);
}
#endif /* SOC_ADC_ARBITER_SUPPORTED */
adc_hal_digi_ctrlr_cfg_t adc_hal_digi_ctrlr_cfg;
soc_module_clk_t clk_src = ADC_DIGI_CLK_SRC_DEFAULT;
uint32_t clk_src_freq_hz = 0;
esp_clk_tree_src_get_freq_hz(clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED,
&clk_src_freq_hz);
adc_hal_digi_ctrlr_cfg.conv_mode =
(conf->unit == ADC_UNIT_1)?ADC_CONV_SINGLE_UNIT_1:ADC_CONV_SINGLE_UNIT_2;
adc_hal_digi_ctrlr_cfg.clk_src = clk_src;
adc_hal_digi_ctrlr_cfg.clk_src_freq_hz = clk_src_freq_hz;
adc_hal_digi_ctrlr_cfg.sample_freq_hz = sample_freq_hz;
adc_hal_digi_ctrlr_cfg.adc_pattern = (adc_digi_pattern_config_t *)pattern_config;
adc_hal_digi_ctrlr_cfg.adc_pattern_len = pattern_len;
uint32_t number_of_adc_digi_samples = number_of_samplings * pattern_len;
adc_hal_dma_config_t adc_hal_dma_config = {
.dev = (void *)GDMA_LL_GET_HW(0),
.eof_desc_num = 1,
.eof_step = 1,
.dma_chan = conf->dma_channel,
.eof_num = number_of_adc_digi_samples,
};
adc_hal_dma_ctx_config(&data->adc_hal_dma_ctx, &adc_hal_dma_config);
adc_hal_set_controller(conf->unit, ADC_HAL_CONTINUOUS_READ_MODE);
adc_hal_digi_init(&data->adc_hal_dma_ctx);
adc_hal_digi_controller_config(&data->adc_hal_dma_ctx, &adc_hal_digi_ctrlr_cfg);
adc_hal_digi_start(&data->adc_hal_dma_ctx, data->dma_buffer);
}
static void adc_esp32_digi_stop(const struct device *dev)
{
const struct adc_esp32_conf *conf = dev->config;
struct adc_esp32_data *data = dev->data;
adc_hal_digi_dis_intr(&data->adc_hal_dma_ctx, ADC_HAL_DMA_INTR_MASK);
adc_hal_digi_clr_intr(&data->adc_hal_dma_ctx, ADC_HAL_DMA_INTR_MASK);
adc_hal_digi_stop(&data->adc_hal_dma_ctx);
adc_hal_digi_deinit(&data->adc_hal_dma_ctx);
adc_lock_release(conf->unit);
sar_periph_ctrl_adc_continuous_power_release();
}
static void adc_esp32_fill_seq_buffer(const void *seq_buffer, const void *dma_buffer,
uint32_t number_of_samples)
{
uint16_t *sample = (uint16_t *)seq_buffer;
adc_digi_output_data_t *digi_data = (adc_digi_output_data_t *)dma_buffer;
for (uint32_t k = 0; k < number_of_samples; k++) {
*sample++ = (uint16_t)(digi_data++)->type2.data;
}
}
static int adc_esp32_wait_for_dma_conv_done(const struct device *dev)
{
struct adc_esp32_data *data = dev->data;
int err = 0;
err = k_sem_take(&data->dma_conv_wait_lock, K_FOREVER);
if (err) {
LOG_ERR("Error taking dma_conv_wait_lock (%d)", err);
}
return err;
}
#endif /* defined(CONFIG_ADC_ESP32_DMA) */
static int adc_esp32_read(const struct device *dev, const struct adc_sequence *seq)
{
const struct adc_esp32_conf *conf = dev->config;
struct adc_esp32_data *data = dev->data;
int reading;
uint32_t cal, cal_mv;
uint8_t channel_id = find_lsb_set(seq->channels) - 1;
if (seq->buffer_size < 2) {
LOG_ERR("Sequence buffer space too low '%d'", seq->buffer_size);
return -ENOMEM;
}
#if !defined(CONFIG_ADC_ESP32_DMA)
if (seq->channels > BIT(channel_id)) {
LOG_ERR("Multi-channel readings not supported");
return -ENOTSUP;
}
#endif /* !defined(CONFIG_ADC_ESP32_DMA) */
if (seq->options) {
if (seq->options->extra_samplings) {
LOG_ERR("Extra samplings not supported");
return -ENOTSUP;
}
#if !defined(CONFIG_ADC_ESP32_DMA)
if (seq->options->interval_us) {
LOG_ERR("Interval between samplings not supported");
return -ENOTSUP;
}
#endif /* !defined(CONFIG_ADC_ESP32_DMA) */
}
if (INVALID_RESOLUTION(seq->resolution)) {
LOG_ERR("unsupported resolution (%d)", seq->resolution);
return -ENOTSUP;
}
if (seq->calibrate) {
/* TODO: Does this mean actual Vref measurement on selected GPIO ?*/
LOG_ERR("calibration is not supported");
return -ENOTSUP;
}
data->resolution[channel_id] = seq->resolution;
#if CONFIG_SOC_SERIES_ESP32C3
/* NOTE: nothing to set on ESP32C3 SoC */
if (conf->unit == ADC_UNIT_1) {
adc1_config_width(ADC_WIDTH_BIT_DEFAULT);
}
#else
adc_set_data_width(conf->unit, data->resolution[channel_id]);
#endif /* CONFIG_SOC_SERIES_ESP32C3 */
#if !defined(CONFIG_ADC_ESP32_DMA)
/* Read raw value */
if (conf->unit == ADC_UNIT_1) {
reading = adc1_get_raw(channel_id);
}
if (conf->unit == ADC_UNIT_2) {
if (adc2_get_raw(channel_id, ADC_WIDTH_BIT_DEFAULT, &reading)) {
LOG_ERR("Conversion timeout on '%s' channel %d", dev->name, channel_id);
return -ETIMEDOUT;
}
}
/* Calibration scheme is available */
if (data->calibrate) {
data->chars[channel_id].bit_width = data->resolution[channel_id];
/* Get corrected voltage output */
cal = cal_mv = esp_adc_cal_raw_to_voltage(reading, &data->chars[channel_id]);
#if CONFIG_SOC_SERIES_ESP32
if (data->attenuation[channel_id] == ADC_ATTEN_DB_12) {
if (cal > ADC_CLIP_MVOLT_12DB) {
cal = ADC_CLIP_MVOLT_12DB;
}
}
#endif /* CONFIG_SOC_SERIES_ESP32 */
/* Fit according to selected attenuation */
atten_to_gain(data->attenuation[channel_id], &cal);
if (data->meas_ref_internal > 0) {
cal = (cal << data->resolution[channel_id]) / data->meas_ref_internal;
}
} else {
LOG_DBG("Using uncalibrated values!");
/* Uncalibrated raw value */
cal = reading;
}
/* Store result */
data->buffer = (uint16_t *) seq->buffer;
data->buffer[0] = cal;
#else /* !defined(CONFIG_ADC_ESP32_DMA) */
int err = 0;
uint32_t adc_pattern_len, unit_attenuation;
adc_digi_pattern_config_t adc_digi_pattern_config[SOC_ADC_MAX_CHANNEL_NUM];
err = adc_esp32_fill_digi_pattern(dev, seq, &adc_digi_pattern_config,
&adc_pattern_len, &unit_attenuation);
if (err || adc_pattern_len == 0) {
return -EINVAL;
}
const struct adc_sequence_options *options = seq->options;
uint32_t sample_freq_hz = SOC_ADC_SAMPLE_FREQ_THRES_HIGH,
number_of_samplings = 1;
if (options != NULL) {
number_of_samplings = seq->buffer_size / (adc_pattern_len * sizeof(uint16_t));
if (options->interval_us) {
sample_freq_hz = MHZ(1) / options->interval_us;
}
}
if (!number_of_samplings) {
LOG_ERR("buffer_size insufficient to store at least one set of samples!");
return -EINVAL;
}
if (sample_freq_hz < SOC_ADC_SAMPLE_FREQ_THRES_LOW ||
sample_freq_hz > SOC_ADC_SAMPLE_FREQ_THRES_HIGH) {
LOG_ERR("ADC sampling frequency out of range: %uHz", sample_freq_hz);
return -EINVAL;
}
uint32_t number_of_adc_samples = number_of_samplings * adc_pattern_len;
uint32_t number_of_adc_dma_data_bytes =
number_of_adc_samples * SOC_ADC_DIGI_DATA_BYTES_PER_CONV;
if (number_of_adc_dma_data_bytes > ADC_DMA_BUFFER_SIZE) {
LOG_ERR("dma buffer size insufficient to store a complete sequence!");
return -EINVAL;
}
err = adc_esp32_dma_start(dev, data->dma_buffer, number_of_adc_dma_data_bytes);
if (err) {
return err;
}
adc_esp32_digi_start(dev, &adc_digi_pattern_config, adc_pattern_len, number_of_samplings,
sample_freq_hz, unit_attenuation);
err = adc_esp32_wait_for_dma_conv_done(dev);
if (err) {
return err;
}
adc_esp32_digi_stop(dev);
err = adc_esp32_dma_stop(dev);
if (err) {
return err;
}
adc_esp32_fill_seq_buffer(seq->buffer, data->dma_buffer, number_of_adc_samples);
#endif /* !defined(CONFIG_ADC_ESP32_DMA) */
return 0;
}
#ifdef CONFIG_ADC_ASYNC
static int adc_esp32_read_async(const struct device *dev,
const struct adc_sequence *sequence,
struct k_poll_signal *async)
{
(void)(dev);
(void)(sequence);
(void)(async);
return -ENOTSUP;
}
#endif /* CONFIG_ADC_ASYNC */
static int adc_esp32_channel_setup(const struct device *dev, const struct adc_channel_cfg *cfg)
{
const struct adc_esp32_conf *conf = (const struct adc_esp32_conf *)dev->config;
struct adc_esp32_data *data = (struct adc_esp32_data *) dev->data;
if (cfg->channel_id >= conf->channel_count) {
LOG_ERR("Unsupported channel id '%d'", cfg->channel_id);
return -ENOTSUP;
}
if (cfg->reference != ADC_REF_INTERNAL) {
LOG_ERR("Unsupported channel reference '%d'", cfg->reference);
return -ENOTSUP;
}
if (cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) {
LOG_ERR("Unsupported acquisition_time '%d'", cfg->acquisition_time);
return -ENOTSUP;
}
if (cfg->differential) {
LOG_ERR("Differential channels are not supported");
return -ENOTSUP;
}
if (gain_to_atten(cfg->gain, &data->attenuation[cfg->channel_id])) {
LOG_ERR("Unsupported gain value '%d'", cfg->gain);
return -ENOTSUP;
}
/* Prepare channel */
if (conf->unit == ADC_UNIT_1) {
adc1_config_channel_atten(cfg->channel_id, data->attenuation[cfg->channel_id]);
}
if (conf->unit == ADC_UNIT_2) {
adc2_config_channel_atten(cfg->channel_id, data->attenuation[cfg->channel_id]);
}
if (data->calibrate) {
esp_adc_cal_value_t cal = esp_adc_cal_characterize(conf->unit,
data->attenuation[cfg->channel_id],
data->resolution[cfg->channel_id],
data->meas_ref_internal,
&data->chars[cfg->channel_id]);
if (cal >= ESP_ADC_CAL_VAL_NOT_SUPPORTED) {
LOG_ERR("Calibration error or not supported");
return -EIO;
}
LOG_DBG("Using ADC calibration method %d", cal);
}
#if defined(CONFIG_ADC_ESP32_DMA)
if (!SOC_ADC_DIG_SUPPORTED_UNIT(conf->unit)) {
LOG_ERR("ADC2 dma mode is no longer supported, please use ADC1!");
return -EINVAL;
}
int io_num = adc_channel_io_map[conf->unit][cfg->channel_id];
if (io_num < 0) {
LOG_ERR("Channel %u not supported!", cfg->channel_id);
return -ENOTSUP;
}
struct gpio_dt_spec gpio = {
.port = conf->gpio_port,
.dt_flags = 0,
.pin = io_num,
};
int err = gpio_pin_configure_dt(&gpio, GPIO_DISCONNECTED);
if (err) {
LOG_ERR("Error disconnecting io (%d)", io_num);
return err;
}
#endif /* defined(CONFIG_ADC_ESP32_DMA) */
return 0;
}
static int adc_esp32_init(const struct device *dev)
{
struct adc_esp32_data *data = (struct adc_esp32_data *) dev->data;
const struct adc_esp32_conf *conf = (struct adc_esp32_conf *) dev->config;
adc_hw_calibration(conf->unit);
#if CONFIG_SOC_SERIES_ESP32S2 || CONFIG_SOC_SERIES_ESP32C3
if (conf->unit == ADC_UNIT_2) {
adc2_init_code_calibration();
}
#endif /* CONFIG_SOC_SERIES_ESP32S2 || CONFIG_SOC_SERIES_ESP32C3 */
#if defined(CONFIG_ADC_ESP32_DMA)
if (!device_is_ready(conf->gpio_port)) {
LOG_ERR("gpio0 port not ready");
return -ENODEV;
}
if (k_sem_init(&data->dma_conv_wait_lock, 0, 1)) {
LOG_ERR("dma_conv_wait_lock initialization failed!");
return -EINVAL;
}
data->adc_hal_dma_ctx.rx_desc = k_aligned_alloc(sizeof(uint32_t),
sizeof(dma_descriptor_t));
if (!data->adc_hal_dma_ctx.rx_desc) {
LOG_ERR("rx_desc allocation failed!");
return -ENOMEM;
}
LOG_DBG("rx_desc = 0x%08X", (unsigned int)data->adc_hal_dma_ctx.rx_desc);
data->dma_buffer = k_aligned_alloc(sizeof(uint32_t), ADC_DMA_BUFFER_SIZE);
if (!data->dma_buffer) {
LOG_ERR("dma buffer allocation failed!");
k_free(data->adc_hal_dma_ctx.rx_desc);
return -ENOMEM;
}
LOG_DBG("data->dma_buffer = 0x%08X", (unsigned int)data->dma_buffer);
#endif /* defined(CONFIG_ADC_ESP32_DMA) */
for (uint8_t i = 0; i < ARRAY_SIZE(data->resolution); i++) {
data->resolution[i] = ADC_RESOLUTION_MAX;
}
for (uint8_t i = 0; i < ARRAY_SIZE(data->attenuation); i++) {
data->attenuation[i] = ADC_ATTEN_DB_0;
}
/* Default reference voltage. This could be calibrated externaly */
data->meas_ref_internal = ADC_ESP32_DEFAULT_VREF_INTERNAL;
/* Check if calibration is possible */
data->calibrate = adc_calibration_init(dev);
return 0;
}
static DEVICE_API(adc, api_esp32_driver_api) = {
.channel_setup = adc_esp32_channel_setup,
.read = adc_esp32_read,
#ifdef CONFIG_ADC_ASYNC
.read_async = adc_esp32_read_async,
#endif /* CONFIG_ADC_ASYNC */
.ref_internal = ADC_ESP32_DEFAULT_VREF_INTERNAL,
};
#if defined(CONFIG_ADC_ESP32_DMA)
#define ADC_ESP32_CONF_GPIO_PORT_INIT .gpio_port = DEVICE_DT_GET(DT_NODELABEL(gpio0)),
#define ADC_ESP32_CONF_DMA_INIT(n) .dma_dev = COND_CODE_1(DT_INST_NODE_HAS_PROP(n, dmas), \
(DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_IDX(n, 0))), \
(NULL)), \
.dma_channel = COND_CODE_1(DT_INST_NODE_HAS_PROP(n, dmas), \
(DT_INST_DMAS_CELL_BY_IDX(n, 0, channel)), \
(0xff)),
#else
#define ADC_ESP32_CONF_GPIO_PORT_INIT
#define ADC_ESP32_CONF_DMA_INIT(inst)
#endif /* defined(CONFIG_ADC_ESP32_DMA) */
#define ESP32_ADC_INIT(inst) \
\
static const struct adc_esp32_conf adc_esp32_conf_##inst = { \
.unit = DT_PROP(DT_DRV_INST(inst), unit) - 1, \
.channel_count = DT_PROP(DT_DRV_INST(inst), channel_count), \
ADC_ESP32_CONF_GPIO_PORT_INIT \
ADC_ESP32_CONF_DMA_INIT(inst) \
}; \
\
static struct adc_esp32_data adc_esp32_data_##inst = { \
}; \
\
DEVICE_DT_INST_DEFINE(inst, &adc_esp32_init, NULL, \
&adc_esp32_data_##inst, \
&adc_esp32_conf_##inst, \
POST_KERNEL, \
CONFIG_ADC_INIT_PRIORITY, \
&api_esp32_driver_api);
DT_INST_FOREACH_STATUS_OKAY(ESP32_ADC_INIT)