| /* |
| * Copyright (c) 2025 Analog Devices, Inc. |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #define DT_DRV_COMPAT adi_ad7124_adc |
| |
| #include <zephyr/device.h> |
| #include <zephyr/devicetree.h> |
| #include <zephyr/drivers/adc.h> |
| #include <zephyr/drivers/spi.h> |
| #include <zephyr/logging/log.h> |
| #include <zephyr/kernel.h> |
| #include <zephyr/sys/byteorder.h> |
| #include <zephyr/sys/util.h> |
| #include <zephyr/sys/crc.h> |
| |
| LOG_MODULE_REGISTER(adc_ad7124, CONFIG_ADC_LOG_LEVEL); |
| |
| #define ADC_CONTEXT_USES_KERNEL_TIMER |
| #include "adc_context.h" |
| |
| #define AD7124_MAX_RETURNED_DATA_SIZE 6 |
| #define AD7124_ADC_VREF_MV 2500U |
| #define AD7124_RESOLUTION 24 |
| #define AD7124_SPI_RDY_POLL_CNT 10000 |
| |
| /* Maximum number of channels */ |
| #define AD7124_MAX_CHANNELS 16 |
| /* Total Number of Setups */ |
| #define AD7124_MAX_SETUPS 8 |
| |
| /* AD7124-4 Standard Device ID */ |
| #define AD7124_4_STD_ID 0x04 |
| /* AD7124-4 B Grade Device ID */ |
| #define AD7124_4_B_GRADE_ID 0x06 |
| /* Device ID for the re-designed die in the AD7124-4 standard part and B-grade */ |
| #define AD7124_4_NEW_ID 0x07 |
| |
| /* AD7124-8 Standard Device ID */ |
| #define AD7124_8_STD_ID 0x14 |
| /* AD7124-8 B and W Grade Device ID */ |
| #define AD7124_8_B_W_GRADE_ID 0x16 |
| /* Device ID for the re-designed die in the AD7124-8 standard part, B-grade and W-grade */ |
| #define AD7124_8_NEW_ID 0x17 |
| |
| /* ODR */ |
| #define ADC_ODR_DEFAULT_VALUE 0xA /* 10SPS */ |
| #define ADC_ODR_MIN_VALUE 0xA /* 10SPS */ |
| #define ADC_ODR_LOW_POWER_MAX 0x960 /* 2400SPS */ |
| #define ADC_ODR_MID_POWER_MAX 0x12C0 /* 4800SPS */ |
| #define ADC_ODR_HIGH_POWER_MAX 0x4B00 /* 19200SPS */ |
| |
| #define ADC_ODR_SEL_BITS_MAX 0x7FF |
| #define ADC_ODR_SEL_BITS_MIN 0x1 |
| |
| /* AD7124 registers */ |
| #define AD7124_STATUS 0x00 |
| #define AD7124_ADC_CONTROL 0x01 |
| #define AD7124_DATA 0x02 |
| #define AD7124_ID 0x05 |
| #define AD7124_ERROR 0x06 |
| #define AD7124_ERROR_EN 0x07 |
| #define AD7124_CHANNEL(x) (0x09 + (x)) |
| #define AD7124_CONFIG(x) (0x19 + (x)) |
| #define AD7124_FILTER(x) (0x21 + (x)) |
| |
| /* Configuration Registers 0-7 bits */ |
| #define AD7124_CFG_REG_BIPOLAR BIT(11) |
| #define AD7124_CFG_REG_REF_BUFP BIT(8) |
| #define AD7124_CFG_REG_REF_BUFM BIT(7) |
| #define AD7124_CFG_REG_AIN_BUFP BIT(6) |
| #define AD7124_CFG_REG_AINN_BUFM BIT(5) |
| |
| #define AD7124_REF_BUF_MSK GENMASK(8, 7) |
| #define AD7124_AIN_BUF_MSK GENMASK(6, 5) |
| #define AD7124_SETUP_CONF_REG_REF_SEL_MSK GENMASK(4, 3) |
| #define AD7124_SETUP_CONF_PGA_MSK GENMASK(2, 0) |
| #define AD7124_ALL_BUF_MSK GENMASK(8, 0) |
| |
| #define AD7124_SETUP_CONFIGURATION_MASK (AD7124_CFG_REG_BIPOLAR | AD7124_ALL_BUF_MSK) |
| |
| /* ADC_Control Register bits */ |
| #define AD7124_ADC_CTRL_REG_DATA_STATUS BIT(10) |
| #define AD7124_ADC_CTRL_REG_REF_EN BIT(8) |
| |
| /* CRC */ |
| #define AD7124_CRC8_POLYNOMIAL_REPRESENTATION 0x07 /* x8 + x2 + x + 1 */ |
| |
| /* Communication Register bits */ |
| #define AD7124_COMM_REG_WEN (0 << 7) |
| #define AD7124_COMM_REG_WR (0 << 6) |
| #define AD7124_COMM_REG_RD BIT(6) |
| #define AD7124_COMM_REG_RA(x) ((x) & 0x3F) |
| |
| /* Filter register bits */ |
| #define AD7124_FILTER_CONF_REG_FILTER_MSK GENMASK(23, 21) |
| #define AD7124_FILTER_FS_MSK GENMASK(10, 0) |
| |
| /* Channel register bits */ |
| #define AD7124_CH_MAP_REG_CH_ENABLE BIT(15) |
| #define AD7124_CHMAP_REG_SETUP_SEL_MSK GENMASK(14, 12) |
| #define AD7124_CHMAP_REG_AINPOS_MSK GENMASK(9, 5) |
| #define AD7124_CHMAP_REG_AINNEG_MSK GENMASK(4, 0) |
| |
| /* Status register bits */ |
| #define AD7124_STATUS_REG_RDY BIT(7) |
| #define AD7124_STATUS_REG_POR_FLAG BIT(4) |
| #define AD7124_STATUS_REG_CH_ACTIVE(x) ((x) & 0xF) |
| |
| /* Error_En register bits */ |
| #define AD7124_ERREN_REG_SPI_IGNORE_ERR_EN BIT(6) |
| #define AD7124_ERREN_REG_SPI_CRC_ERR_EN BIT(2) |
| |
| /* ADC control register bits */ |
| #define AD7124_POWER_MODE_MSK GENMASK(7, 6) |
| #define AD7124_ADC_CTRL_REG_MODE_MSK GENMASK(5, 2) |
| |
| /* Error register bits */ |
| #define AD7124_ERR_REG_SPI_IGNORE_ERR BIT(6) |
| |
| enum ad7124_register_lengths { |
| AD7124_STATUS_REG_LEN = 1, |
| AD7124_ADC_CONTROL_REG_LEN = 2, |
| AD7124_DATA_REG_LEN = 3, |
| AD7124_ID_REG_LEN = 1, |
| AD7124_ERROR_REG_LEN = 3, |
| AD7124_ERROR_EN_REG_LEN = 3, |
| AD7124_CHANNEL_REG_LEN = 2, |
| AD7124_CONFIG_REG_LEN = 2, |
| AD7124_FILTER_REG_LEN = 3, |
| }; |
| |
| enum ad7124_mode { |
| AD7124_CONTINUOUS, |
| AD7124_SINGLE, |
| AD7124_STANDBY, |
| AD7124_POWER_DOWN, |
| AD7124_IDLE, |
| AD7124_IN_ZERO_SCALE_OFF, |
| AD7124_IN_FULL_SCALE_GAIN, |
| AD7124_SYS_ZERO_SCALE_OFF, |
| AD7124_SYS_ZERO_SCALE_GAIN, |
| }; |
| |
| enum ad7124_power_mode { |
| AD7124_LOW_POWER_MODE, |
| AD7124_MID_POWER_MODE, |
| AD7124_HIGH_POWER_MODE |
| }; |
| |
| enum adc_ad7124_master_clk_freq_hz { |
| AD7124_LOW_POWER_CLK = 76800, |
| AD7124_MID_POWER_CLK = 153600, |
| AD7124_HIGH_POWER_CLK = 614400, |
| }; |
| |
| enum ad7124_device_type { |
| ID_AD7124_4, |
| ID_AD7124_8 |
| }; |
| |
| struct ad7124_control_status { |
| uint16_t value; |
| bool is_read; |
| }; |
| |
| enum ad7124_reference_source { |
| /* External Reference REFIN1+/-*/ |
| EXTERNAL_REFIN1, |
| /* External Reference REFIN2+/-*/ |
| EXTERNAL_REFIN2, |
| /* Internal 2.5V Reference */ |
| INTERNAL_REF, |
| /* AVDD - AVSS */ |
| AVDD_AVSS, |
| }; |
| |
| enum ad7124_gain { |
| AD7124_GAIN_1, |
| AD7124_GAIN_2, |
| AD7124_GAIN_4, |
| AD7124_GAIN_8, |
| AD7124_GAIN_16, |
| AD7124_GAIN_32, |
| AD7124_GAIN_64, |
| AD7124_GAIN_128 |
| }; |
| |
| enum ad7124_filter_type { |
| AD7124_FILTER_SINC4, |
| AD7124_FILTER_SINC3 = 2U, |
| }; |
| |
| struct ad7124_config_props { |
| enum ad7124_reference_source refsel; |
| enum ad7124_gain pga_bits; |
| enum ad7124_filter_type filter_type; |
| uint16_t odr_sel_bits; |
| bool bipolar; |
| bool inbuf_enable; |
| bool refbuf_enable; |
| }; |
| |
| struct ad7124_channel_config { |
| struct ad7124_config_props props; |
| uint8_t cfg_slot; |
| bool live_cfg; |
| }; |
| |
| struct adc_ad7124_config { |
| struct spi_dt_spec bus; |
| uint16_t filter_type_mask; |
| uint16_t bipolar_mask; |
| uint16_t inbuf_enable_mask; |
| uint16_t refbuf_enable_mask; |
| enum ad7124_mode adc_mode; |
| enum ad7124_power_mode power_mode; |
| enum ad7124_device_type active_device; |
| uint8_t resolution; |
| bool ref_en; |
| }; |
| |
| struct adc_ad7124_data { |
| const struct device *dev; |
| struct adc_context ctx; |
| struct ad7124_control_status adc_control_status; |
| struct ad7124_channel_config channel_setup_cfg[AD7124_MAX_CHANNELS]; |
| uint8_t setup_cfg_slots; |
| struct k_sem acquire_signal; |
| uint16_t channels; |
| uint32_t *buffer; |
| uint32_t *repeat_buffer; |
| bool crc_enable; |
| bool spi_ready; |
| #if CONFIG_ADC_ASYNC |
| struct k_thread thread; |
| |
| K_KERNEL_STACK_MEMBER(stack, CONFIG_ADI_AD7124_ADC_ACQUISITION_THREAD_STACK_SIZE); |
| #endif /* CONFIG_ADC_ASYNC */ |
| }; |
| |
| static int adc_ad7124_read_reg(const struct device *dev, uint32_t reg, |
| enum ad7124_register_lengths len, uint32_t *val); |
| |
| static void adc_context_update_buffer_pointer(struct adc_context *ctx, bool repeat_sampling) |
| { |
| struct adc_ad7124_data *data = CONTAINER_OF(ctx, struct adc_ad7124_data, ctx); |
| |
| if (repeat_sampling) { |
| data->buffer = data->repeat_buffer; |
| } |
| } |
| |
| static void adc_context_start_sampling(struct adc_context *ctx) |
| { |
| struct adc_ad7124_data *data = CONTAINER_OF(ctx, struct adc_ad7124_data, ctx); |
| |
| data->repeat_buffer = data->buffer; |
| k_sem_give(&data->acquire_signal); |
| } |
| |
| static int adc_ad7124_acq_time_to_odr(const struct device *dev, uint16_t acq_time, uint16_t *odr) |
| { |
| const struct adc_ad7124_config *config = dev->config; |
| uint16_t acquisition_time_value = ADC_ACQ_TIME_VALUE(acq_time); |
| uint16_t acquisition_time_unit = ADC_ACQ_TIME_UNIT(acq_time); |
| |
| /* The AD7124 uses samples per seconds units with the lowest being 10SPS |
| * regardless of the selected power mode and with acquisition_time only |
| * having 14b for time, this will not fit within here for microsecond units. |
| * Use Tick units and allow the user to specify the ODR directly. |
| */ |
| |
| if (acq_time == ADC_ACQ_TIME_DEFAULT) { |
| *odr = ADC_ODR_DEFAULT_VALUE; |
| return 0; |
| } |
| |
| if (acquisition_time_unit != ADC_ACQ_TIME_TICKS) { |
| LOG_ERR("%s: invalid acquisition time %i", dev->name, acquisition_time_value); |
| return -EINVAL; |
| } |
| |
| if (acquisition_time_value < ADC_ODR_MIN_VALUE) { |
| LOG_ERR("%s: invalid acquisition time %i", dev->name, acquisition_time_value); |
| return -EINVAL; |
| } else if (config->power_mode == AD7124_HIGH_POWER_MODE && |
| acquisition_time_value > ADC_ODR_HIGH_POWER_MAX) { |
| LOG_ERR("%s: invalid acquisition time %i", dev->name, acquisition_time_value); |
| return -EINVAL; |
| } else if (config->power_mode == AD7124_MID_POWER_MODE && |
| acquisition_time_value > ADC_ODR_MID_POWER_MAX) { |
| LOG_ERR("%s: invalid acquisition time %i", dev->name, acquisition_time_value); |
| return -EINVAL; |
| } else if (config->power_mode == AD7124_LOW_POWER_MODE && |
| acquisition_time_value > ADC_ODR_LOW_POWER_MAX) { |
| LOG_ERR("%s: invalid acquisition time %i", dev->name, acquisition_time_value); |
| return -EINVAL; |
| } |
| |
| *odr = acquisition_time_value; |
| |
| return 0; |
| } |
| |
| static uint16_t adc_ad7124_odr_to_fs(const struct device *dev, int16_t odr) |
| { |
| const struct adc_ad7124_config *config = dev->config; |
| uint16_t odr_sel_bits; |
| uint32_t master_clk_freq; |
| |
| switch (config->power_mode) { |
| case AD7124_HIGH_POWER_MODE: |
| master_clk_freq = AD7124_HIGH_POWER_CLK; |
| break; |
| case AD7124_MID_POWER_MODE: |
| master_clk_freq = AD7124_MID_POWER_CLK; |
| break; |
| case AD7124_LOW_POWER_MODE: |
| master_clk_freq = AD7124_LOW_POWER_CLK; |
| break; |
| default: |
| LOG_ERR("Invalid power mode (%u)", config->power_mode); |
| return -EINVAL; |
| } |
| |
| odr_sel_bits = DIV_ROUND_CLOSEST(master_clk_freq, odr * 32); |
| |
| if (odr_sel_bits < ADC_ODR_SEL_BITS_MIN) { |
| odr_sel_bits = ADC_ODR_SEL_BITS_MIN; |
| } else if (odr_sel_bits > ADC_ODR_SEL_BITS_MAX) { |
| odr_sel_bits = ADC_ODR_SEL_BITS_MAX; |
| } |
| |
| return odr_sel_bits; |
| } |
| |
| static int adc_ad7124_create_new_cfg(const struct device *dev, const struct adc_channel_cfg *cfg, |
| struct ad7124_channel_config *new_cfg) |
| { |
| const struct adc_ad7124_config *config = dev->config; |
| uint16_t odr; |
| enum ad7124_reference_source ref_source; |
| enum ad7124_gain gain; |
| int ret; |
| |
| if (cfg->channel_id >= AD7124_MAX_CHANNELS) { |
| LOG_ERR("Invalid channel (%u)", cfg->channel_id); |
| return -EINVAL; |
| } |
| |
| switch (cfg->reference) { |
| case ADC_REF_INTERNAL: |
| ref_source = INTERNAL_REF; |
| break; |
| case ADC_REF_EXTERNAL0: |
| ref_source = EXTERNAL_REFIN1; |
| break; |
| case ADC_REF_EXTERNAL1: |
| ref_source = EXTERNAL_REFIN2; |
| break; |
| case ADC_REF_VDD_1: |
| ref_source = AVDD_AVSS; |
| break; |
| default: |
| LOG_ERR("Invalid reference source (%u)", cfg->reference); |
| return -EINVAL; |
| } |
| |
| new_cfg->props.refsel = ref_source; |
| |
| switch (cfg->gain) { |
| case ADC_GAIN_1: |
| gain = AD7124_GAIN_1; |
| break; |
| case ADC_GAIN_2: |
| gain = AD7124_GAIN_2; |
| break; |
| case ADC_GAIN_4: |
| gain = AD7124_GAIN_4; |
| break; |
| case ADC_GAIN_8: |
| gain = AD7124_GAIN_8; |
| break; |
| case ADC_GAIN_16: |
| gain = AD7124_GAIN_16; |
| break; |
| case ADC_GAIN_32: |
| gain = AD7124_GAIN_32; |
| break; |
| case ADC_GAIN_64: |
| gain = AD7124_GAIN_64; |
| break; |
| case ADC_GAIN_128: |
| gain = AD7124_GAIN_128; |
| break; |
| default: |
| LOG_ERR("Invalid gain value (%u)", cfg->gain); |
| return -EINVAL; |
| } |
| |
| new_cfg->props.pga_bits = gain; |
| |
| ret = adc_ad7124_acq_time_to_odr(dev, cfg->acquisition_time, &odr); |
| if (ret) { |
| return ret; |
| } |
| |
| if (config->filter_type_mask & BIT(cfg->channel_id)) { |
| new_cfg->props.filter_type = AD7124_FILTER_SINC3; |
| } else { |
| new_cfg->props.filter_type = AD7124_FILTER_SINC4; |
| } |
| |
| new_cfg->props.odr_sel_bits = adc_ad7124_odr_to_fs(dev, odr); |
| new_cfg->props.bipolar = config->bipolar_mask & BIT(cfg->channel_id); |
| new_cfg->props.inbuf_enable = config->inbuf_enable_mask & BIT(cfg->channel_id); |
| new_cfg->props.refbuf_enable = config->refbuf_enable_mask & BIT(cfg->channel_id); |
| |
| return 0; |
| } |
| |
| static int adc_ad7124_find_new_slot(const struct device *dev) |
| { |
| struct adc_ad7124_data *data = dev->data; |
| uint8_t slot = data->setup_cfg_slots; |
| |
| int cnt = 0; |
| |
| while (slot) { |
| if ((slot & 0x1) == 0) { |
| return cnt; |
| } |
| slot >>= 1; |
| cnt++; |
| } |
| |
| if (cnt == AD7124_MAX_SETUPS) { |
| return -1; |
| } |
| |
| return cnt; |
| } |
| |
| static int adc_ad7124_find_similar_configuration(const struct device *dev, |
| const struct ad7124_channel_config *cfg, |
| int channel_id) |
| { |
| struct adc_ad7124_data *data = dev->data; |
| int similar_channel_index = -1; |
| |
| for (int i = 0; i < AD7124_MAX_CHANNELS; i++) { |
| if (!data->channel_setup_cfg[i].live_cfg && i == channel_id) { |
| continue; |
| } |
| |
| if (memcmp(&cfg->props, &data->channel_setup_cfg[i].props, |
| sizeof(struct ad7124_config_props)) == 0) { |
| similar_channel_index = i; |
| break; |
| } |
| } |
| |
| return similar_channel_index; |
| } |
| |
| static int adc_ad7124_wait_for_spi_ready(const struct device *dev) |
| { |
| int ret = 0; |
| uint32_t read_val = 0; |
| bool ready = false; |
| uint16_t spi_ready_try_count = AD7124_SPI_RDY_POLL_CNT; |
| |
| while (!ready && --spi_ready_try_count) { |
| ret = adc_ad7124_read_reg(dev, AD7124_ERROR, AD7124_ERROR_REG_LEN, &read_val); |
| if (ret) { |
| return ret; |
| } |
| |
| ready = (read_val & AD7124_ERR_REG_SPI_IGNORE_ERR) == 0; |
| } |
| |
| if (!spi_ready_try_count) { |
| return -ETIMEDOUT; |
| } |
| |
| return 0; |
| } |
| |
| static int adc_ad7124_read_reg(const struct device *dev, uint32_t reg, |
| enum ad7124_register_lengths len, uint32_t *val) |
| { |
| const struct adc_ad7124_config *config = dev->config; |
| struct adc_ad7124_data *data = dev->data; |
| const struct spi_dt_spec *spec = &config->bus; |
| |
| int ret; |
| uint32_t cntrl_value = 0; |
| uint8_t add_status_length = 0; |
| uint8_t buffer_tx[AD7124_MAX_RETURNED_DATA_SIZE] = {0}; |
| uint8_t buffer_rx[ARRAY_SIZE(buffer_tx)]; |
| uint8_t crc_check; |
| |
| if (reg != AD7124_ERROR && data->spi_ready) { |
| ret = adc_ad7124_wait_for_spi_ready(dev); |
| if (ret) { |
| return ret; |
| } |
| } |
| |
| if (reg == AD7124_DATA) { |
| |
| if (data->adc_control_status.is_read) { |
| cntrl_value = data->adc_control_status.value; |
| } else { |
| ret = adc_ad7124_read_reg(dev, AD7124_ADC_CONTROL, |
| AD7124_ADC_CONTROL_REG_LEN, &cntrl_value); |
| if (ret) { |
| return ret; |
| } |
| } |
| |
| if (cntrl_value & AD7124_ADC_CTRL_REG_DATA_STATUS) { |
| add_status_length = 1; |
| } |
| } |
| |
| struct spi_buf tx_buf[] = {{ |
| .buf = buffer_tx, |
| .len = 1, |
| }}; |
| struct spi_buf rx_buf[] = {{ |
| .buf = buffer_rx, |
| .len = ((data->crc_enable) ? len + 1 : len) + 1 + add_status_length, |
| }}; |
| const struct spi_buf_set tx = {.buffers = tx_buf, .count = ARRAY_SIZE(tx_buf)}; |
| const struct spi_buf_set rx = {.buffers = rx_buf, .count = ARRAY_SIZE(rx_buf)}; |
| |
| buffer_tx[0] = AD7124_COMM_REG_WEN | AD7124_COMM_REG_RD | AD7124_COMM_REG_RA(reg); |
| |
| ret = spi_transceive_dt(spec, &tx, &rx); |
| if (ret) { |
| return ret; |
| } |
| |
| if (data->crc_enable) { |
| buffer_rx[0] = AD7124_COMM_REG_WEN | AD7124_COMM_REG_RD | AD7124_COMM_REG_RA(reg); |
| |
| crc_check = crc8(buffer_rx, len + 2 + add_status_length, |
| AD7124_CRC8_POLYNOMIAL_REPRESENTATION, 0, false); |
| if (crc_check) { |
| return -EBADMSG; |
| } |
| } |
| |
| switch (len) { |
| case 1: |
| *val = buffer_rx[1]; |
| break; |
| case 2: |
| *val = sys_get_be16(&buffer_rx[1]); |
| break; |
| case 3: |
| *val = sys_get_be24(&buffer_rx[1]); |
| break; |
| default: |
| return -EINVAL; |
| } |
| |
| if (reg == AD7124_ADC_CONTROL) { |
| data->adc_control_status.value = *val; |
| data->adc_control_status.is_read = true; |
| } |
| |
| return 0; |
| } |
| |
| static int adc_ad7124_write_reg(const struct device *dev, uint32_t reg, |
| enum ad7124_register_lengths len, uint32_t val) |
| { |
| const struct adc_ad7124_config *config = dev->config; |
| struct adc_ad7124_data *data = dev->data; |
| const struct spi_dt_spec *spec = &config->bus; |
| |
| int ret; |
| uint8_t buffer_tx[AD7124_MAX_RETURNED_DATA_SIZE] = {0}; |
| uint8_t crc; |
| |
| if (data->spi_ready) { |
| ret = adc_ad7124_wait_for_spi_ready(dev); |
| if (ret) { |
| return ret; |
| } |
| } |
| |
| buffer_tx[0] = AD7124_COMM_REG_WEN | AD7124_COMM_REG_WR | AD7124_COMM_REG_RA(reg); |
| |
| switch (len) { |
| case 1: |
| buffer_tx[1] = val; |
| break; |
| case 2: |
| sys_put_be16(val, &buffer_tx[1]); |
| break; |
| case 3: |
| sys_put_be24(val, &buffer_tx[1]); |
| break; |
| default: |
| return -EINVAL; |
| } |
| |
| if (data->crc_enable) { |
| crc = crc8(buffer_tx, len + 1, AD7124_CRC8_POLYNOMIAL_REPRESENTATION, 0, false); |
| buffer_tx[len + 1] = crc; |
| } |
| |
| struct spi_buf tx_buf[] = {{ |
| .buf = buffer_tx, |
| .len = ((data->crc_enable) ? len + 1 : len) + 1, |
| }}; |
| |
| const struct spi_buf_set tx = {.buffers = tx_buf, .count = ARRAY_SIZE(tx_buf)}; |
| |
| ret = spi_transceive_dt(spec, &tx, NULL); |
| if (ret) { |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| static int adc_ad7124_reg_write_msk(const struct device *dev, uint32_t reg, |
| enum ad7124_register_lengths len, uint32_t data, uint32_t mask) |
| { |
| int ret; |
| uint32_t reg_data; |
| |
| ret = adc_ad7124_read_reg(dev, reg, len, ®_data); |
| if (ret) { |
| return ret; |
| } |
| |
| reg_data &= ~mask; |
| reg_data |= data; |
| |
| ret = adc_ad7124_write_reg(dev, reg, len, reg_data); |
| if (ret) { |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| static int adc_ad7124_setup_cfg(const struct device *dev, const struct ad7124_channel_config *cfg) |
| { |
| const struct adc_ad7124_config *config = dev->config; |
| int ret; |
| int configuration_setup = 0; |
| int configuration_mask = 0; |
| int ref_internal = 0; |
| |
| if (cfg->props.bipolar) { |
| configuration_setup |= AD7124_CFG_REG_BIPOLAR; |
| } |
| |
| if (cfg->props.inbuf_enable) { |
| configuration_setup |= AD7124_CFG_REG_AIN_BUFP | AD7124_CFG_REG_AINN_BUFM; |
| } |
| |
| if (cfg->props.refbuf_enable) { |
| configuration_setup |= AD7124_CFG_REG_REF_BUFP | AD7124_CFG_REG_REF_BUFM; |
| } |
| |
| configuration_setup |= FIELD_PREP(AD7124_SETUP_CONF_REG_REF_SEL_MSK, cfg->props.refsel); |
| configuration_setup |= FIELD_PREP(AD7124_SETUP_CONF_PGA_MSK, cfg->props.pga_bits); |
| configuration_mask |= AD7124_SETUP_CONFIGURATION_MASK; |
| |
| ret = adc_ad7124_reg_write_msk(dev, AD7124_CONFIG(cfg->cfg_slot), AD7124_CONFIG_REG_LEN, |
| configuration_setup, configuration_mask); |
| if (ret) { |
| return ret; |
| } |
| |
| if (config->ref_en) { |
| ref_internal = AD7124_ADC_CTRL_REG_REF_EN; |
| } |
| |
| if (cfg->props.refsel == INTERNAL_REF) { |
| ret = adc_ad7124_reg_write_msk(dev, AD7124_ADC_CONTROL, AD7124_ADC_CONTROL_REG_LEN, |
| ref_internal, AD7124_ADC_CTRL_REG_REF_EN); |
| if (ret) { |
| return ret; |
| } |
| } |
| |
| return 0; |
| } |
| |
| static int adc_ad7124_filter_cfg(const struct device *dev, const struct ad7124_channel_config *cfg) |
| { |
| int filter_setup = 0; |
| int filter_mask = 0; |
| int ret; |
| |
| filter_setup = FIELD_PREP(AD7124_FILTER_CONF_REG_FILTER_MSK, cfg->props.filter_type) | |
| FIELD_PREP(AD7124_FILTER_FS_MSK, cfg->props.odr_sel_bits); |
| filter_mask = AD7124_FILTER_CONF_REG_FILTER_MSK | AD7124_FILTER_FS_MSK; |
| |
| /* Set filter type and odr*/ |
| ret = adc_ad7124_reg_write_msk(dev, AD7124_FILTER(cfg->cfg_slot), AD7124_FILTER_REG_LEN, |
| filter_setup, filter_mask); |
| if (ret) { |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| static int adc_ad7124_connect_analog_input(const struct device *dev, uint8_t chn_num, uint8_t ainp, |
| uint8_t ainm) |
| { |
| int ret; |
| |
| ret = adc_ad7124_reg_write_msk(dev, AD7124_CHANNEL(chn_num), AD7124_CHANNEL_REG_LEN, |
| FIELD_PREP(AD7124_CHMAP_REG_AINPOS_MSK, ainp), |
| AD7124_CHMAP_REG_AINPOS_MSK); |
| if (ret) { |
| return ret; |
| } |
| |
| ret = adc_ad7124_reg_write_msk(dev, AD7124_CHANNEL(chn_num), AD7124_CHANNEL_REG_LEN, |
| FIELD_PREP(AD7124_CHMAP_REG_AINNEG_MSK, ainm), |
| AD7124_CHMAP_REG_AINNEG_MSK); |
| if (ret) { |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| static int adc_ad7124_set_channel_status(const struct device *dev, uint8_t chn_num, |
| bool channel_status) |
| { |
| int ret; |
| uint16_t status; |
| |
| if (channel_status) { |
| status = AD7124_CH_MAP_REG_CH_ENABLE; |
| } else { |
| status = 0x0U; |
| } |
| |
| ret = adc_ad7124_reg_write_msk(dev, AD7124_CHANNEL(chn_num), AD7124_CHANNEL_REG_LEN, status, |
| AD7124_CH_MAP_REG_CH_ENABLE); |
| if (ret) { |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| static int adc_ad7124_channel_cfg(const struct device *dev, const struct adc_channel_cfg *cfg) |
| { |
| struct adc_ad7124_data *data = dev->data; |
| int ret; |
| |
| ret = adc_ad7124_connect_analog_input(dev, cfg->channel_id, cfg->input_positive, |
| cfg->input_negative); |
| if (ret) { |
| return ret; |
| } |
| |
| /* Assign setup */ |
| ret = adc_ad7124_reg_write_msk( |
| dev, AD7124_CHANNEL(cfg->channel_id), AD7124_CHANNEL_REG_LEN, |
| FIELD_PREP(AD7124_CHMAP_REG_SETUP_SEL_MSK, |
| data->channel_setup_cfg[cfg->channel_id].cfg_slot), |
| AD7124_CHMAP_REG_SETUP_SEL_MSK); |
| if (ret) { |
| return ret; |
| } |
| |
| ret = adc_ad7124_set_channel_status(dev, cfg->channel_id, true); |
| if (ret) { |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| static int adc_ad7124_channel_setup(const struct device *dev, const struct adc_channel_cfg *cfg) |
| { |
| struct adc_ad7124_data *data = dev->data; |
| struct ad7124_channel_config new_cfg; |
| int new_slot; |
| int ret; |
| int similar_channel_index; |
| |
| data->channel_setup_cfg[cfg->channel_id].live_cfg = false; |
| |
| ret = adc_ad7124_create_new_cfg(dev, cfg, &new_cfg); |
| if (ret) { |
| return ret; |
| } |
| |
| /* AD7124 supports only 8 different configurations for 16 channels*/ |
| new_slot = adc_ad7124_find_new_slot(dev); |
| |
| if (new_slot == -1) { |
| similar_channel_index = |
| adc_ad7124_find_similar_configuration(dev, &new_cfg, cfg->channel_id); |
| if (similar_channel_index == -1) { |
| return -EINVAL; |
| } |
| new_cfg.cfg_slot = data->channel_setup_cfg[similar_channel_index].cfg_slot; |
| } else { |
| new_cfg.cfg_slot = new_slot; |
| WRITE_BIT(data->setup_cfg_slots, new_slot, true); |
| } |
| |
| new_cfg.live_cfg = true; |
| |
| memcpy(&data->channel_setup_cfg[cfg->channel_id], &new_cfg, |
| sizeof(struct ad7124_channel_config)); |
| |
| /* Setup the channel configuration */ |
| ret = adc_ad7124_setup_cfg(dev, &data->channel_setup_cfg[cfg->channel_id]); |
| if (ret) { |
| LOG_ERR("Error setting up configuration"); |
| return ret; |
| } |
| |
| /* Setup the filter configuration */ |
| ret = adc_ad7124_filter_cfg(dev, &data->channel_setup_cfg[cfg->channel_id]); |
| if (ret) { |
| LOG_ERR("Error setting up filter"); |
| return ret; |
| } |
| |
| /* Setup the channel */ |
| ret = adc_ad7124_channel_cfg(dev, cfg); |
| if (ret) { |
| LOG_ERR("Error setting up channel"); |
| return ret; |
| } |
| |
| WRITE_BIT(data->channels, cfg->channel_id, true); |
| |
| return 0; |
| } |
| |
| int adc_ad7124_wait_to_power_up(const struct device *dev) |
| { |
| int ret = 0; |
| uint32_t read_val = 0; |
| bool powered_on = false; |
| uint16_t spi_ready_try_count = AD7124_SPI_RDY_POLL_CNT; |
| |
| while (!powered_on && --spi_ready_try_count) { |
| |
| ret = adc_ad7124_read_reg(dev, AD7124_STATUS, AD7124_STATUS_REG_LEN, &read_val); |
| if (ret) { |
| return ret; |
| } |
| |
| powered_on = (read_val & AD7124_STATUS_REG_POR_FLAG) == 0; |
| } |
| |
| if (!spi_ready_try_count) { |
| return -ETIMEDOUT; |
| } |
| |
| return 0; |
| } |
| |
| int adc_ad7124_reset(const struct device *dev) |
| { |
| const struct adc_ad7124_config *config = dev->config; |
| const struct spi_dt_spec *spec = &config->bus; |
| |
| int ret; |
| uint8_t buffer_tx[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; |
| |
| struct spi_buf tx_buf[] = {{ |
| .buf = buffer_tx, |
| .len = ARRAY_SIZE(buffer_tx), |
| }}; |
| |
| const struct spi_buf_set tx = {.buffers = tx_buf, .count = ARRAY_SIZE(tx_buf)}; |
| |
| ret = spi_transceive_dt(spec, &tx, NULL); |
| if (ret) { |
| return ret; |
| } |
| |
| ret = adc_ad7124_wait_to_power_up(dev); |
| if (ret) { |
| return ret; |
| } |
| |
| return ret; |
| } |
| |
| static int adc_ad7124_update_crc(const struct device *dev) |
| { |
| struct adc_ad7124_data *data = dev->data; |
| |
| int ret = 0; |
| uint32_t reg_temp = 0; |
| |
| ret = adc_ad7124_read_reg(dev, AD7124_ERROR_EN, AD7124_ERROR_EN_REG_LEN, ®_temp); |
| if (ret) { |
| return ret; |
| } |
| |
| if (reg_temp & AD7124_ERREN_REG_SPI_CRC_ERR_EN) { |
| data->crc_enable = true; |
| } else { |
| data->crc_enable = false; |
| } |
| |
| return 0; |
| } |
| |
| static int adc_ad7124_update_spi_check_ready(const struct device *dev) |
| { |
| struct adc_ad7124_data *data = dev->data; |
| |
| int ret = 0; |
| uint32_t reg_temp = 0; |
| |
| ret = adc_ad7124_read_reg(dev, AD7124_ERROR_EN, AD7124_ERROR_EN_REG_LEN, ®_temp); |
| if (ret) { |
| return ret; |
| } |
| |
| if (reg_temp & AD7124_ERREN_REG_SPI_IGNORE_ERR_EN) { |
| data->spi_ready = true; |
| } else { |
| data->spi_ready = false; |
| } |
| |
| return 0; |
| } |
| |
| static int adc_ad7124_check_chip_id(const struct device *dev) |
| { |
| const struct adc_ad7124_config *config = dev->config; |
| uint32_t reg_temp = 0; |
| int ret; |
| |
| ret = adc_ad7124_read_reg(dev, AD7124_ID, AD7124_ID_REG_LEN, ®_temp); |
| if (ret) { |
| return ret; |
| } |
| |
| if (config->active_device == ID_AD7124_4) { |
| switch (reg_temp) { |
| case AD7124_4_STD_ID: |
| case AD7124_4_B_GRADE_ID: |
| case AD7124_4_NEW_ID: |
| break; |
| |
| default: |
| return -ENODEV; |
| } |
| } else if (config->active_device == ID_AD7124_8) { |
| switch (reg_temp) { |
| case AD7124_8_STD_ID: |
| case AD7124_8_B_W_GRADE_ID: |
| case AD7124_8_NEW_ID: |
| break; |
| |
| default: |
| return -ENODEV; |
| } |
| } else { |
| return -ENODEV; |
| } |
| |
| return 0; |
| } |
| |
| static int adc_ad7124_set_adc_mode(const struct device *dev, enum ad7124_mode adc_mode) |
| { |
| int ret; |
| |
| ret = adc_ad7124_reg_write_msk(dev, AD7124_ADC_CONTROL, AD7124_ADC_CONTROL_REG_LEN, |
| FIELD_PREP(AD7124_ADC_CTRL_REG_MODE_MSK, adc_mode), |
| AD7124_ADC_CTRL_REG_MODE_MSK); |
| if (ret) { |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| static int adc_ad7124_set_power_mode(const struct device *dev, enum ad7124_power_mode power_mode) |
| { |
| int ret; |
| |
| ret = adc_ad7124_reg_write_msk(dev, AD7124_ADC_CONTROL, AD7124_ADC_CONTROL_REG_LEN, |
| FIELD_PREP(AD7124_POWER_MODE_MSK, power_mode), |
| AD7124_POWER_MODE_MSK); |
| if (ret) { |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| static int adc_ad7124_setup(const struct device *dev) |
| { |
| const struct adc_ad7124_config *config = dev->config; |
| int ret; |
| |
| /* Reset the device interface */ |
| ret = adc_ad7124_reset(dev); |
| if (ret) { |
| return ret; |
| } |
| |
| /* Get CRC State */ |
| ret = adc_ad7124_update_crc(dev); |
| if (ret) { |
| return ret; |
| } |
| |
| ret = adc_ad7124_update_spi_check_ready(dev); |
| if (ret) { |
| return ret; |
| } |
| |
| /* Check the device ID */ |
| ret = adc_ad7124_check_chip_id(dev); |
| if (ret) { |
| return ret; |
| } |
| |
| /* Disable channel 0 */ |
| ret = adc_ad7124_set_channel_status(dev, 0, false); |
| if (ret) { |
| return ret; |
| } |
| |
| ret = adc_ad7124_set_adc_mode(dev, config->adc_mode); |
| if (ret) { |
| return ret; |
| } |
| |
| ret = adc_ad7124_set_power_mode(dev, config->power_mode); |
| if (ret) { |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| static int adc_ad7124_wait_for_conv_ready(const struct device *dev) |
| { |
| int ret = 0; |
| uint32_t read_val = 0; |
| bool ready = false; |
| uint16_t spi_ready_try_count = AD7124_SPI_RDY_POLL_CNT; |
| |
| while (!ready && --spi_ready_try_count) { |
| |
| ret = adc_ad7124_read_reg(dev, AD7124_STATUS, AD7124_STATUS_REG_LEN, &read_val); |
| if (ret) { |
| return ret; |
| } |
| |
| ready = (read_val & AD7124_STATUS_REG_RDY) == 0; |
| } |
| |
| if (!spi_ready_try_count) { |
| return -ETIMEDOUT; |
| } |
| |
| return 0; |
| } |
| |
| static bool get_next_ch_idx(uint16_t ch_mask, uint16_t last_idx, uint16_t *new_idx) |
| { |
| last_idx++; |
| if (last_idx >= AD7124_MAX_CHANNELS) { |
| return 0; |
| } |
| ch_mask >>= last_idx; |
| if (!ch_mask) { |
| *new_idx = -1; |
| return 0; |
| } |
| while (!(ch_mask & 1)) { |
| last_idx++; |
| ch_mask >>= 1; |
| } |
| *new_idx = last_idx; |
| |
| return 1; |
| } |
| |
| static int adc_ad7124_get_read_chan_id(const struct device *dev, uint16_t *chan_id) |
| { |
| int ret; |
| uint32_t reg_temp; |
| |
| ret = adc_ad7124_read_reg(dev, AD7124_STATUS, AD7124_STATUS_REG_LEN, ®_temp); |
| if (ret) { |
| return ret; |
| } |
| |
| *chan_id = reg_temp & AD7124_STATUS_REG_CH_ACTIVE(0xF); |
| |
| return 0; |
| } |
| |
| static int adc_ad7124_perform_read(const struct device *dev) |
| { |
| int ret; |
| struct adc_ad7124_data *data = dev->data; |
| uint16_t ch_idx = -1; |
| uint16_t prev_ch_idx = -1; |
| uint16_t adc_ch_id = 0; |
| bool status; |
| |
| k_sem_take(&data->acquire_signal, K_FOREVER); |
| |
| do { |
| prev_ch_idx = ch_idx; |
| |
| status = get_next_ch_idx(data->ctx.sequence.channels, ch_idx, &ch_idx); |
| if (!status) { |
| break; |
| } |
| |
| ret = adc_ad7124_wait_for_conv_ready(dev); |
| if (ret) { |
| LOG_ERR("waiting for conversion ready failed"); |
| adc_context_complete(&data->ctx, ret); |
| return ret; |
| } |
| |
| ret = adc_ad7124_read_reg(dev, AD7124_DATA, AD7124_DATA_REG_LEN, data->buffer); |
| if (ret) { |
| LOG_ERR("reading sample failed"); |
| adc_context_complete(&data->ctx, ret); |
| return ret; |
| } |
| |
| ret = adc_ad7124_get_read_chan_id(dev, &adc_ch_id); |
| if (ret) { |
| LOG_ERR("reading channel id failed"); |
| adc_context_complete(&data->ctx, ret); |
| return ret; |
| } |
| |
| if (ch_idx == adc_ch_id) { |
| data->buffer++; |
| } else { |
| ch_idx = prev_ch_idx; |
| } |
| |
| } while (true); |
| |
| adc_context_on_sampling_done(&data->ctx, dev); |
| |
| return ret; |
| } |
| |
| static int adc_ad7124_validate_sequence(const struct device *dev, |
| const struct adc_sequence *sequence) |
| { |
| const struct adc_ad7124_config *config = dev->config; |
| struct adc_ad7124_data *data = dev->data; |
| const size_t channel_maximum = 8 * sizeof(sequence->channels); |
| uint32_t num_requested_channels; |
| size_t necessary; |
| |
| if (sequence->resolution != config->resolution) { |
| LOG_ERR("invalid resolution"); |
| return -EINVAL; |
| } |
| |
| if (!sequence->channels) { |
| LOG_ERR("no channel selected"); |
| return -EINVAL; |
| } |
| |
| if (sequence->oversampling) { |
| LOG_ERR("oversampling is not supported"); |
| return -EINVAL; |
| } |
| |
| num_requested_channels = POPCOUNT(sequence->channels); |
| necessary = num_requested_channels * sizeof(int32_t); |
| |
| if (sequence->options) { |
| necessary *= (1 + sequence->options->extra_samplings); |
| } |
| |
| if (sequence->buffer_size < necessary) { |
| LOG_ERR("buffer size %u is too small, need %u", sequence->buffer_size, necessary); |
| return -ENOMEM; |
| } |
| |
| for (size_t i = 0; i < channel_maximum; ++i) { |
| if ((BIT(i) & sequence->channels) == 0) { |
| continue; |
| } |
| |
| if ((BIT(i) & sequence->channels) && !(BIT(i) & data->channels)) { |
| LOG_ERR("Channel-%d not enabled", i); |
| return -EINVAL; |
| } |
| |
| if (i >= AD7124_MAX_CHANNELS) { |
| LOG_ERR("invalid channel selection"); |
| return -EINVAL; |
| } |
| } |
| |
| return 0; |
| } |
| |
| static int adc_ad7124_start_read(const struct device *dev, const struct adc_sequence *sequence, |
| bool wait) |
| { |
| int result; |
| struct adc_ad7124_data *data = dev->data; |
| |
| result = adc_ad7124_validate_sequence(dev, sequence); |
| if (result != 0) { |
| LOG_ERR("sequence validation failed"); |
| return result; |
| } |
| |
| data->buffer = sequence->buffer; |
| |
| adc_context_start_read(&data->ctx, sequence); |
| |
| if (wait) { |
| result = adc_context_wait_for_completion(&data->ctx); |
| } |
| |
| return result; |
| } |
| |
| #if CONFIG_ADC_ASYNC |
| static int adc_ad7124_read_async(const struct device *dev, const struct adc_sequence *sequence, |
| struct k_poll_signal *async) |
| { |
| int status; |
| struct adc_ad7124_data *data = dev->data; |
| |
| adc_context_lock(&data->ctx, true, async); |
| status = adc_ad7124_start_read(dev, sequence, true); |
| adc_context_release(&data->ctx, status); |
| |
| return status; |
| } |
| |
| static int adc_ad7124_read(const struct device *dev, const struct adc_sequence *sequence) |
| { |
| int status; |
| struct adc_ad7124_data *data = dev->data; |
| |
| adc_context_lock(&data->ctx, false, NULL); |
| status = adc_ad7124_start_read(dev, sequence, true); |
| adc_context_release(&data->ctx, status); |
| |
| return status; |
| } |
| |
| #else |
| static int adc_ad7124_read(const struct device *dev, const struct adc_sequence *sequence) |
| { |
| int status; |
| struct adc_ad7124_data *data = dev->data; |
| |
| adc_context_lock(&data->ctx, false, NULL); |
| |
| status = adc_ad7124_start_read(dev, sequence, false); |
| |
| while (status == 0 && k_sem_take(&data->ctx.sync, K_NO_WAIT) != 0) { |
| status = adc_ad7124_perform_read(dev); |
| } |
| |
| adc_context_release(&data->ctx, status); |
| |
| return status; |
| } |
| #endif |
| |
| #if CONFIG_ADC_ASYNC |
| static void adc_ad7124_acquisition_thread(void *p1, void *p2, void *p3) |
| { |
| ARG_UNUSED(p2); |
| ARG_UNUSED(p3); |
| |
| const struct device *dev = p1; |
| |
| while (true) { |
| adc_ad7124_perform_read(dev); |
| } |
| } |
| #endif /* CONFIG_ADC_ASYNC */ |
| |
| static int adc_ad7124_init(const struct device *dev) |
| { |
| const struct adc_ad7124_config *config = dev->config; |
| struct adc_ad7124_data *data = dev->data; |
| int ret; |
| |
| data->dev = dev; |
| |
| k_sem_init(&data->acquire_signal, 0, 1); |
| |
| if (!spi_is_ready_dt(&config->bus)) { |
| LOG_ERR("spi bus %s not ready", config->bus.bus->name); |
| return -ENODEV; |
| } |
| |
| ret = adc_ad7124_setup(dev); |
| if (ret) { |
| return ret; |
| } |
| |
| #if CONFIG_ADC_ASYNC |
| k_tid_t tid = k_thread_create( |
| &data->thread, data->stack, CONFIG_ADI_AD7124_ADC_ACQUISITION_THREAD_STACK_SIZE, |
| adc_ad7124_acquisition_thread, (void *)dev, NULL, NULL, |
| CONFIG_ADI_AD7124_ADC_ACQUISITION_THREAD_INIT_PRIO, 0, K_NO_WAIT); |
| k_thread_name_set(tid, "adc_ad7124"); |
| #endif /* CONFIG_ADC_ASYNC */ |
| |
| adc_context_unlock_unconditionally(&data->ctx); |
| |
| return 0; |
| } |
| |
| static DEVICE_API(adc, adc_ad7124_api) = { |
| .channel_setup = adc_ad7124_channel_setup, |
| .read = adc_ad7124_read, |
| #ifdef CONFIG_ADC_ASYNC |
| .read_async = adc_ad7124_read_async, |
| #endif |
| .ref_internal = AD7124_ADC_VREF_MV, |
| }; |
| |
| #define ADC_AD7124_INST_DEFINE(inst) \ |
| static const struct adc_ad7124_config adc_ad7124_config##inst = { \ |
| .bus = SPI_DT_SPEC_INST_GET( \ |
| inst, \ |
| SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_WORD_SET(8), 0), \ |
| .resolution = AD7124_RESOLUTION, \ |
| .filter_type_mask = DT_INST_PROP(inst, filter_type_mask), \ |
| .bipolar_mask = DT_INST_PROP(inst, bipolar_mask), \ |
| .inbuf_enable_mask = DT_INST_PROP(inst, inbuf_enable_mask), \ |
| .refbuf_enable_mask = DT_INST_PROP(inst, refbuf_enable_mask), \ |
| .adc_mode = DT_INST_PROP(inst, adc_mode), \ |
| .power_mode = DT_INST_PROP(inst, power_mode), \ |
| .active_device = DT_INST_PROP(inst, active_device), \ |
| .ref_en = DT_INST_PROP(inst, reference_enable), \ |
| }; \ |
| static struct adc_ad7124_data adc_ad7124_data##inst = { \ |
| ADC_CONTEXT_INIT_LOCK(adc_ad7124_data##inst, ctx), \ |
| ADC_CONTEXT_INIT_TIMER(adc_ad7124_data##inst, ctx), \ |
| ADC_CONTEXT_INIT_SYNC(adc_ad7124_data##inst, ctx), \ |
| }; \ |
| DEVICE_DT_INST_DEFINE(inst, adc_ad7124_init, NULL, &adc_ad7124_data##inst, \ |
| &adc_ad7124_config##inst, POST_KERNEL, CONFIG_ADC_INIT_PRIORITY, \ |
| &adc_ad7124_api); |
| |
| DT_INST_FOREACH_STATUS_OKAY(ADC_AD7124_INST_DEFINE) |