You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
733 lines
16 KiB
733 lines
16 KiB
/* |
|
* Copyright (c) 2024 Linumiz |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#include <zephyr/device.h> |
|
#include <zephyr/devicetree.h> |
|
#include <zephyr/drivers/adc.h> |
|
#include <zephyr/drivers/spi.h> |
|
#include <zephyr/drivers/gpio.h> |
|
#include <zephyr/logging/log.h> |
|
#include <zephyr/kernel.h> |
|
#include <zephyr/pm/device.h> |
|
#include <zephyr/sys/byteorder.h> |
|
#include <zephyr/sys/util.h> |
|
#include <zephyr/sys/util_macro.h> |
|
#include <zephyr/drivers/adc/ads131m02.h> |
|
|
|
#define ADC_CONTEXT_USES_KERNEL_TIMER |
|
#include "adc_context.h" |
|
|
|
LOG_MODULE_REGISTER(ads131m02, CONFIG_ADC_LOG_LEVEL); |
|
|
|
#define ADS131M02_DEVICE_ID 0x22 |
|
|
|
/* Device settings Registers */ |
|
#define ADS131M02_ID_REG 0x00 |
|
#define ADS131M02_STATUS_REG 0x01 |
|
|
|
/* Global settings Registers */ |
|
#define ADS131M02_MODE_REG 0x02 |
|
#define ADS131M02_CLOCK_REG 0x03 |
|
#define ADS131M02_GAIN_REG 0x04 |
|
#define ADS131M02_CFG_REG 0x06 |
|
#define ADS131M02_THRESH_MSB_REG 0x07 |
|
#define ADS131M02_THRESH_LSB_REG 0x08 |
|
|
|
/* Channel 0 settings Registers */ |
|
#define ADS131M02_CH0_CFG_REG 0x09 |
|
#define ADS131M02_CH0_OCAL_MSB_REG 0x0A |
|
#define ADS131M02_CH0_OCAL_LSB_REG 0x0B |
|
#define ADS131M02_CH0_GCAL_MSB_REG 0x0C |
|
#define ADS131M02_CH0_GCAL_LSB_REG 0x0D |
|
|
|
/* Channel 1 settings Registers */ |
|
#define ADS131M02_CH1_CFG_REG 0x0E |
|
#define ADS131M02_CH1_OCAL_MSB_REG 0x0F |
|
#define ADS131M02_CH1_OCAL_LSB_REG 0x10 |
|
#define ADS131M02_CH1_GCAL_MSB_REG 0x11 |
|
#define ADS131M02_CH1_GCAL_LSB_REG 0x12 |
|
|
|
/* Register Map CRC Registers */ |
|
#define ADS131M02_REGMAP_CRC_REG 0x3E |
|
|
|
#define ADC_CHANNEL_0 0 |
|
#define ADC_CHANNEL_1 1 |
|
#define ADS131M02_REF_INTERNAL 1200 |
|
#define ADS131M02_RESOLUTION 24 |
|
|
|
/* ADS131M02 cmds */ |
|
#define ADS131M02_NULL_CMD 0x0000 |
|
#define ADS131M02_RESET_CMD 0x0011 |
|
#define ADS131M02_STANDBY_CMD 0x0022 |
|
#define ADS131M02_WAKEUP_CMD 0x0033 |
|
#define ADS131M02_LOCK_CMD 0x0555 |
|
#define ADS131M02_UNLOCK_CMD 0x0655 |
|
#define ADS131M02_RREG_CMD 0xA000 |
|
#define ADS131M02_WREG_CMD 0x6000 |
|
|
|
#define ADS131M02_RESET_RSP 0xFF22 |
|
|
|
#define ADS131M02_GAIN0_MASK GENMASK(2, 0) |
|
#define ADS131M02_GAIN1_MASK GENMASK(6, 4) |
|
#define ADS131M02_CHANNEL0_ENABLE BIT(8) |
|
#define ADS131M02_CHANNEL1_ENABLE BIT(9) |
|
#define ADS131M02_DRDY_CH0_MASK BIT(0) |
|
#define ADS131M02_DRDY_CH1_MASK BIT(1) |
|
#define ADS131M02_OSR_256_MASK BIT(2) |
|
#define ADS131M02_OSR_512_MASK BIT(3) |
|
#define ADS131M02_OSR_1024_MASK BIT(3) | BIT(2) |
|
#define ADS131M02_OSR_2048_MASK BIT(4) |
|
#define ADS131M02_OSR_4096_MASK BIT(4) | BIT(2) |
|
#define ADS131M02_OSR_8192_MASK BIT(4) | BIT(3) |
|
#define ADS131M02_OSR_16384_MASK BIT(4) | BIT(3) | BIT(2) |
|
#define ADS131M02_GC_MODE_MASK BIT(8) |
|
#define ADS131M02_GC_DELAY_MASK GENMASK(12, 9) |
|
#define ADS131M02_PWR_HR BIT(1) | BIT(0) |
|
#define ADS131M02_PWR_LP BIT(0) |
|
|
|
#define ADS131M02_DISABLE_ADC 0x000E |
|
#define ADS131M02_RESET_DELAY 100 |
|
|
|
#define ADS131M02_GAIN_1 0 |
|
#define ADS131M02_GAIN_2 1 |
|
#define ADS131M02_GAIN_4 2 |
|
#define ADS131M02_GAIN_8 3 |
|
#define ADS131M02_GAIN_16 4 |
|
#define ADS131M02_GAIN_32 5 |
|
#define ADS131M02_GAIN_64 6 |
|
#define ADS131M02_GAIN_128 7 |
|
|
|
#define ADS131M02_GET_GAIN(channel_id, gain) \ |
|
FIELD_PREP(channel_id == 0 ? ADS131M02_GAIN0_MASK : \ |
|
ADS131M02_GAIN1_MASK, gain) |
|
|
|
enum ads131m02_data_rate { |
|
/* SPS */ |
|
ADS131M02_DR_250, |
|
ADS131M02_DR_500, |
|
ADS131M02_DR_1k, |
|
ADS131M02_DR_2k, |
|
ADS131M02_DR_4k, |
|
ADS131M02_DR_8k, |
|
ADS131M02_DR_16k, |
|
ADS131M02_DR_32k, |
|
}; |
|
|
|
struct ads131m02_config { |
|
const struct spi_dt_spec spi; |
|
const struct gpio_dt_spec gpio_drdy; |
|
}; |
|
|
|
struct ads131m02_data { |
|
struct adc_context ctx; |
|
struct k_sem acq_sem; |
|
struct k_sem drdy_sem; |
|
struct gpio_callback callback_drdy; |
|
int32_t *buffer; |
|
int32_t *buffer_ptr; |
|
}; |
|
|
|
static inline int ads131m02_transceive(const struct device *dev, |
|
uint8_t *send_buf, size_t send_buf_len, |
|
uint8_t *recv_buf, size_t recv_buf_len) |
|
{ |
|
int ret; |
|
const struct ads131m02_config *cfg = dev->config; |
|
|
|
struct spi_buf tx_buf = { |
|
.buf = send_buf, |
|
.len = send_buf_len, |
|
}; |
|
const struct spi_buf_set tx = { |
|
.buffers = &tx_buf, |
|
.count = 1 |
|
}; |
|
|
|
struct spi_buf rx_buf = { |
|
.buf = recv_buf, |
|
.len = recv_buf_len, |
|
}; |
|
const struct spi_buf_set rx = { |
|
.buffers = &rx_buf, |
|
.count = 1, |
|
}; |
|
|
|
ret = spi_transceive_dt(&cfg->spi, &tx, NULL); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
return spi_read_dt(&cfg->spi, &rx); |
|
} |
|
|
|
static int ads131m02_reg_read(const struct device *dev, uint16_t addr, |
|
uint8_t *read_buf, size_t read_buf_len) |
|
{ |
|
uint16_t temp; |
|
uint8_t tx_buf[3] = {0}; |
|
|
|
temp = (uint16_t)(ADS131M02_RREG_CMD | (addr << 7)); |
|
sys_put_be16(temp, tx_buf); |
|
|
|
return ads131m02_transceive(dev, tx_buf, sizeof(tx_buf), |
|
read_buf, read_buf_len); |
|
} |
|
|
|
static int ads131m02_reg_write(const struct device *dev, uint16_t addr, |
|
uint16_t write_data) |
|
{ |
|
uint16_t temp; |
|
uint8_t tx_buf[6] = {0}; |
|
uint8_t rx_buf[3] = {0}; |
|
|
|
temp = (uint16_t)(ADS131M02_WREG_CMD | (addr << 7)); |
|
sys_put_be16(temp, tx_buf); |
|
sys_put_be16(write_data, &tx_buf[3]); |
|
|
|
return ads131m02_transceive(dev, tx_buf, sizeof(tx_buf), |
|
rx_buf, sizeof(rx_buf)); |
|
|
|
} |
|
|
|
static inline int ads131m02_configure_gain(const struct device *dev, |
|
const struct adc_channel_cfg *channel_cfg) |
|
{ |
|
uint16_t gain_cfg; |
|
|
|
switch (channel_cfg->gain) { |
|
case ADC_GAIN_1: |
|
gain_cfg = ADS131M02_GET_GAIN(channel_cfg->channel_id, |
|
ADS131M02_GAIN_1); |
|
break; |
|
case ADC_GAIN_2: |
|
gain_cfg = ADS131M02_GET_GAIN(channel_cfg->channel_id, |
|
ADS131M02_GAIN_2); |
|
break; |
|
case ADC_GAIN_4: |
|
gain_cfg = ADS131M02_GET_GAIN(channel_cfg->channel_id, |
|
ADS131M02_GAIN_4); |
|
break; |
|
case ADC_GAIN_8: |
|
gain_cfg = ADS131M02_GET_GAIN(channel_cfg->channel_id, |
|
ADS131M02_GAIN_8); |
|
break; |
|
case ADC_GAIN_16: |
|
gain_cfg = ADS131M02_GET_GAIN(channel_cfg->channel_id, |
|
ADS131M02_GAIN_16); |
|
break; |
|
case ADC_GAIN_32: |
|
gain_cfg = ADS131M02_GET_GAIN(channel_cfg->channel_id, |
|
ADS131M02_GAIN_32); |
|
break; |
|
case ADC_GAIN_64: |
|
gain_cfg = ADS131M02_GET_GAIN(channel_cfg->channel_id, |
|
ADS131M02_GAIN_64); |
|
break; |
|
case ADC_GAIN_128: |
|
gain_cfg = ADS131M02_GET_GAIN(channel_cfg->channel_id, |
|
ADS131M02_GAIN_128); |
|
break; |
|
default: |
|
return -EINVAL; |
|
} |
|
|
|
return ads131m02_reg_write(dev, ADS131M02_GAIN_REG, gain_cfg); |
|
} |
|
|
|
static inline int ads131m02_acquistion_time(uint16_t acq_time, uint16_t *enable) |
|
{ |
|
uint16_t acq_value = ADC_ACQ_TIME_VALUE(acq_time); |
|
|
|
if (acq_time == ADC_ACQ_TIME_DEFAULT) { |
|
*enable |= ADS131M02_OSR_1024_MASK; |
|
return 0; |
|
} |
|
|
|
if (ADC_ACQ_TIME_UNIT(acq_time) != ADC_ACQ_TIME_TICKS) { |
|
return -EINVAL; |
|
} |
|
|
|
if (acq_time == ADC_ACQ_TIME_MAX) { |
|
*enable |= ADS131M02_OSR_16384_MASK; |
|
return 0; |
|
} |
|
|
|
switch (acq_value) { |
|
case ADS131M02_DR_250: |
|
*enable |= ADS131M02_OSR_16384_MASK; |
|
break; |
|
case ADS131M02_DR_500: |
|
*enable |= ADS131M02_OSR_8192_MASK; |
|
break; |
|
case ADS131M02_DR_1k: |
|
*enable |= ADS131M02_OSR_4096_MASK; |
|
break; |
|
case ADS131M02_DR_2k: |
|
*enable |= ADS131M02_OSR_2048_MASK; |
|
break; |
|
case ADS131M02_DR_4k: |
|
*enable |= ADS131M02_OSR_1024_MASK; |
|
break; |
|
case ADS131M02_DR_8k: |
|
*enable |= ADS131M02_OSR_512_MASK; |
|
break; |
|
case ADS131M02_DR_16k: |
|
*enable |= ADS131M02_OSR_256_MASK; |
|
break; |
|
default: |
|
return -EINVAL; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static int ads131m02_setup(const struct device *dev, |
|
const struct adc_channel_cfg *channel_cfg) |
|
{ |
|
int ret; |
|
uint16_t enable; |
|
uint8_t read_data[3] = {0}; |
|
|
|
ret = ads131m02_reg_read(dev, ADS131M02_CLOCK_REG, read_data, |
|
sizeof(read_data)); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
enable = sys_get_be16(read_data); |
|
switch (channel_cfg->channel_id) { |
|
case ADC_CHANNEL_0: |
|
enable |= ADS131M02_CHANNEL0_ENABLE; |
|
break; |
|
case ADC_CHANNEL_1: |
|
enable |= ADS131M02_CHANNEL1_ENABLE; |
|
break; |
|
default: |
|
return -EINVAL; |
|
} |
|
|
|
enable &= ~(ADS131M02_OSR_16384_MASK); |
|
ret = ads131m02_acquistion_time(channel_cfg->acquisition_time, &enable); |
|
if (ret < 0) { |
|
return ret; |
|
} |
|
|
|
return ads131m02_reg_write(dev, ADS131M02_CLOCK_REG, enable); |
|
} |
|
|
|
static int ads131m02_channel_setup(const struct device *dev, |
|
const struct adc_channel_cfg *channel_cfg) |
|
{ |
|
int ret; |
|
|
|
if (channel_cfg->channel_id != 0 && channel_cfg->channel_id != 1) { |
|
return -EINVAL; |
|
} |
|
|
|
if (channel_cfg->reference != ADC_REF_INTERNAL) { |
|
LOG_DBG("Unsupported Reference Voltage"); |
|
return -ENOTSUP; |
|
} |
|
|
|
if (!channel_cfg->differential) { |
|
return -EINVAL; |
|
} |
|
|
|
ret = ads131m02_configure_gain(dev, channel_cfg); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
ret = ads131m02_setup(dev, channel_cfg); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static int ads131m02_validate_buffer_size(const struct adc_sequence *sequence) |
|
{ |
|
size_t needed = sizeof(int32_t); |
|
|
|
if (sequence->options) { |
|
needed *= (1 + sequence->options->extra_samplings); |
|
} |
|
|
|
if (sequence->buffer_size < needed) { |
|
return -ENOMEM; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static int ads131m02_validate_sequence(const struct adc_sequence *sequence) |
|
{ |
|
if (sequence->resolution != ADS131M02_RESOLUTION) { |
|
return -EINVAL; |
|
} |
|
|
|
if (sequence->channels != BIT(0) && sequence->channels != BIT(1)) { |
|
LOG_ERR("invalid channel"); |
|
return -EINVAL; |
|
} |
|
|
|
if (sequence->oversampling) { |
|
return -EINVAL; |
|
} |
|
|
|
return ads131m02_validate_buffer_size(sequence); |
|
} |
|
|
|
static void adc_context_update_buffer_pointer(struct adc_context *ctx, |
|
bool repeat_sampling) |
|
{ |
|
struct ads131m02_data *data = CONTAINER_OF(ctx, struct ads131m02_data, ctx); |
|
|
|
if (repeat_sampling) { |
|
data->buffer = data->buffer_ptr; |
|
} |
|
} |
|
|
|
static void adc_context_start_sampling(struct adc_context *ctx) |
|
{ |
|
struct ads131m02_data *data = CONTAINER_OF(ctx, struct ads131m02_data, ctx); |
|
|
|
data->buffer_ptr = data->buffer; |
|
k_sem_give(&data->acq_sem); |
|
} |
|
|
|
static int ads131m02_adc_start_read(const struct device *dev, |
|
const struct adc_sequence *sequence, |
|
bool wait) |
|
{ |
|
int ret; |
|
struct ads131m02_data *data = dev->data; |
|
|
|
ret = ads131m02_validate_sequence(sequence); |
|
if (ret != 0) { |
|
LOG_ERR("sequence validation failed"); |
|
return ret; |
|
} |
|
|
|
data->buffer = sequence->buffer; |
|
adc_context_start_read(&data->ctx, sequence); |
|
if (wait) { |
|
ret = adc_context_wait_for_completion(&data->ctx); |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
static int ads131m02_wait_drdy(const struct device *dev) |
|
{ |
|
struct ads131m02_data *data = dev->data; |
|
|
|
return k_sem_take(&data->drdy_sem, |
|
ADC_CONTEXT_WAIT_FOR_COMPLETION_TIMEOUT); |
|
} |
|
|
|
static int ads131m02_read_sample(const struct device *dev, |
|
uint32_t channels, uint32_t *buffer) |
|
{ |
|
int ret; |
|
uint16_t int_status; |
|
uint8_t tx_buf[4] = {0}; |
|
uint8_t rx_buf[12] = {0}; |
|
|
|
ret = ads131m02_transceive(dev, tx_buf, sizeof(tx_buf), |
|
rx_buf, sizeof(rx_buf)); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
int_status = sys_get_be16(&rx_buf[0]); |
|
if ((int_status & ADS131M02_DRDY_CH0_MASK) && (channels & BIT(0))) { |
|
*buffer = sys_get_be24(&rx_buf[3]); |
|
} else if ((int_status & ADS131M02_DRDY_CH1_MASK) && |
|
(channels & BIT(1))) { |
|
*buffer = sys_get_be24(&rx_buf[6]); |
|
} else { |
|
LOG_INF("No ADC Data Available"); |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static int ads131m02_perform_read(const struct device *dev, |
|
const struct adc_sequence *sequence) |
|
{ |
|
int ret; |
|
struct ads131m02_data *data = dev->data; |
|
|
|
k_sem_take(&data->acq_sem, K_FOREVER); |
|
k_sem_reset(&data->drdy_sem); |
|
|
|
ret = ads131m02_wait_drdy(dev); |
|
if (ret != 0) { |
|
goto error; |
|
} |
|
|
|
ret = ads131m02_read_sample(dev, sequence->channels, data->buffer); |
|
if (ret != 0) { |
|
goto error; |
|
} |
|
|
|
data->buffer++; |
|
adc_context_on_sampling_done(&data->ctx, dev); |
|
|
|
return 0; |
|
error: |
|
adc_context_complete(&data->ctx, ret); |
|
return ret; |
|
} |
|
|
|
static int ads131m02_read(const struct device *dev, |
|
const struct adc_sequence *seq) |
|
{ |
|
int ret; |
|
struct ads131m02_data *data = dev->data; |
|
|
|
adc_context_lock(&data->ctx, false, NULL); |
|
ret = ads131m02_adc_start_read(dev, seq, false); |
|
|
|
while (ret == 0 && k_sem_take(&data->ctx.sync, K_NO_WAIT) != 0) { |
|
ret = ads131m02_perform_read(dev, seq); |
|
} |
|
|
|
adc_context_release(&data->ctx, ret); |
|
|
|
return ret; |
|
} |
|
|
|
static void ads131m02_data_ready_handler(const struct device *dev, |
|
struct gpio_callback *gpio_cb, |
|
uint32_t pins) |
|
{ |
|
ARG_UNUSED(dev); |
|
ARG_UNUSED(pins); |
|
|
|
struct ads131m02_data *data = CONTAINER_OF(gpio_cb, |
|
struct ads131m02_data, callback_drdy); |
|
|
|
k_sem_give(&data->drdy_sem); |
|
} |
|
|
|
static int ads131m02_configure_gpio(const struct device *dev) |
|
{ |
|
int ret; |
|
const struct ads131m02_config *cfg = dev->config; |
|
struct ads131m02_data *data = dev->data; |
|
|
|
ret = gpio_pin_configure_dt(&cfg->gpio_drdy, GPIO_INPUT); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
ret = gpio_pin_interrupt_configure_dt(&cfg->gpio_drdy, |
|
GPIO_INT_EDGE_TO_ACTIVE); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
gpio_init_callback(&data->callback_drdy, ads131m02_data_ready_handler, |
|
BIT(cfg->gpio_drdy.pin)); |
|
|
|
return gpio_add_callback(cfg->gpio_drdy.port, &data->callback_drdy); |
|
} |
|
|
|
static int ads131m02_device_reset(const struct device *dev) |
|
{ |
|
int ret; |
|
uint8_t tx_buf[12] = {0}; |
|
uint8_t rx_buf[3] = {0}; |
|
|
|
sys_put_be16(ADS131M02_RESET_CMD, tx_buf); |
|
ret = ads131m02_transceive(dev, tx_buf, sizeof(tx_buf), |
|
rx_buf, sizeof(rx_buf)); |
|
|
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
if (sys_get_be16(rx_buf) != ADS131M02_RESET_RSP) { |
|
return -EIO; |
|
} |
|
|
|
k_msleep(ADS131M02_RESET_DELAY); |
|
|
|
return 0; |
|
} |
|
|
|
#if defined CONFIG_PM_DEVICE |
|
static int ads131m02_pm(const struct device *dev, uint16_t cmd) |
|
{ |
|
int ret; |
|
uint8_t tx_buf[3] = {0}; |
|
uint8_t rx_buf[3] = {0}; |
|
|
|
sys_put_be16(cmd, tx_buf); |
|
ret = ads131m02_transceive(dev, tx_buf, sizeof(tx_buf), |
|
rx_buf, sizeof(rx_buf)); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
if (rx_buf[1] != cmd) { |
|
return -EIO; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static int ads131m02_pm_action(const struct device *dev, |
|
enum pm_device_action action) |
|
{ |
|
switch (action) { |
|
case PM_DEVICE_ACTION_RESUME: |
|
return ads131m02_pm(dev, ADS131M02_WAKEUP_CMD); |
|
case PM_DEVICE_ACTION_SUSPEND: |
|
return ads131m02_pm(dev, ADS131M02_STANDBY_CMD); |
|
default: |
|
return -EINVAL; |
|
} |
|
} |
|
#endif /* CONFIG_PM_DEVICE */ |
|
|
|
int ads131m02_set_adc_mode(const struct device *dev, |
|
enum ads131m02_adc_mode mode, |
|
enum ads131m02_gc_delay gc_delay) |
|
{ |
|
uint16_t temp = 0; |
|
|
|
switch (mode) { |
|
case ADS131M02_CONTINUOUS_MODE: |
|
break; |
|
case ADS131M02_GLOBAL_CHOP_MODE: |
|
temp |= ADS131M02_GC_MODE_MASK; |
|
temp |= FIELD_PREP(ADS131M02_GC_DELAY_MASK, gc_delay); |
|
break; |
|
default: |
|
return -EINVAL; |
|
} |
|
|
|
return ads131m02_reg_write(dev, ADS131M02_CFG_REG, temp); |
|
} |
|
|
|
int ads131m02_set_power_mode(const struct device *dev, |
|
enum ads131m02_adc_power_mode mode) |
|
{ |
|
int ret; |
|
uint16_t temp; |
|
uint8_t buf[3] = {0}; |
|
|
|
ret = ads131m02_reg_read(dev, ADS131M02_CLOCK_REG, buf, sizeof(buf)); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
temp = sys_get_be16(buf); |
|
temp &= ~(ADS131M02_PWR_HR); |
|
|
|
switch (mode) { |
|
case ADS131M02_VLP: |
|
break; |
|
case ADS131M02_LP: |
|
temp |= ADS131M02_PWR_LP; |
|
break; |
|
case ADS131M02_HR: |
|
temp |= ADS131M02_PWR_HR; |
|
break; |
|
default: |
|
return -EINVAL; |
|
} |
|
|
|
return ads131m02_reg_write(dev, ADS131M02_CLOCK_REG, temp); |
|
} |
|
|
|
static DEVICE_API(adc, ads131m02_api) = { |
|
.channel_setup = ads131m02_channel_setup, |
|
.read = ads131m02_read, |
|
.ref_internal = ADS131M02_REF_INTERNAL, |
|
}; |
|
|
|
static int ads131m02_init(const struct device *dev) |
|
{ |
|
int ret; |
|
uint8_t buf[3] = {0}; |
|
const struct ads131m02_config *cfg = dev->config; |
|
struct ads131m02_data *data = dev->data; |
|
|
|
if (!spi_is_ready_dt(&cfg->spi)) { |
|
LOG_ERR("ADS131M02 is not ready"); |
|
return -ENODEV; |
|
} |
|
|
|
adc_context_init(&data->ctx); |
|
k_sem_init(&data->acq_sem, 0, 1); |
|
k_sem_init(&data->drdy_sem, 0, 1); |
|
|
|
ret = ads131m02_configure_gpio(dev); |
|
if (ret != 0) { |
|
LOG_ERR("GPIO config failed %d", ret); |
|
return ret; |
|
} |
|
|
|
ret = ads131m02_reg_read(dev, ADS131M02_ID_REG, buf, sizeof(buf)); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
if (buf[0] != ADS131M02_DEVICE_ID) { |
|
LOG_ERR("Device ID mismatch %d", buf[0]); |
|
return -ENODEV; |
|
} |
|
|
|
ret = ads131m02_device_reset(dev); |
|
if (ret != 0) { |
|
LOG_WRN("Device is not reset"); |
|
} |
|
|
|
/* By default, adc is configured, so disabling it */ |
|
ret = ads131m02_reg_write(dev, ADS131M02_CLOCK_REG, |
|
ADS131M02_DISABLE_ADC); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
adc_context_unlock_unconditionally(&data->ctx); |
|
|
|
#if defined CONFIG_PM_DEVICE |
|
ret = ads131m02_pm(dev, ADS131M02_STANDBY_CMD); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
pm_device_init_suspended(dev); |
|
#endif /* CONFIG_PM_DEVICE */ |
|
|
|
LOG_INF("ADS131M02 Initialised"); |
|
|
|
return 0; |
|
} |
|
|
|
#define DT_DRV_COMPAT ti_ads131m02 |
|
|
|
#define ADC_ADS131M02_INST_DEFINE(n) \ |
|
PM_DEVICE_DT_INST_DEFINE(n, ads131m02_pm_action); \ |
|
static const struct ads131m02_config config_##n = { \ |
|
.spi = SPI_DT_SPEC_INST_GET( \ |
|
n, SPI_OP_MODE_MASTER | SPI_MODE_CPHA | \ |
|
SPI_WORD_SET(8), 0), \ |
|
.gpio_drdy = GPIO_DT_SPEC_INST_GET(n, drdy_gpios), \ |
|
}; \ |
|
static struct ads131m02_data data_##n; \ |
|
DEVICE_DT_INST_DEFINE(n, ads131m02_init, \ |
|
PM_DEVICE_DT_INST_GET(n), \ |
|
&data_##n, &config_##n, POST_KERNEL, \ |
|
CONFIG_ADC_INIT_PRIORITY, &ads131m02_api); |
|
|
|
DT_INST_FOREACH_STATUS_OKAY(ADC_ADS131M02_INST_DEFINE)
|
|
|