mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 18:21:24 +02:00
iio: adc: ad4130: add new supported parts
Add support for AD4129-4/8, AD4130-4, and AD4131-4/8 variants. The AD4129 series supports the same FIFO interface as the AD4130 but with reduced resolution (16-bit). The AD4131 series lacks FIFO support, so triggered buffer functionality is introduced. The 4-channel variants feature fewer analog inputs, GPIOs, and sparse pin mappings for VBIAS, analog inputs, and excitation currents. The driver now handles these differences with chip-specific configurations, including pin mappings and GPIO counts. Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com> Signed-off-by: Jonathan Santos <Jonathan.Santos@analog.com> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
This commit is contained in:
parent
71c1a1b376
commit
ec98c3b501
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/cleanup.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
|
|
@ -21,6 +22,7 @@
|
|||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
#include <asm/div64.h>
|
||||
|
|
@ -30,6 +32,9 @@
|
|||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/kfifo_buf.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
#define AD4130_NAME "ad4130"
|
||||
|
||||
|
|
@ -40,6 +45,7 @@
|
|||
#define AD4130_ADC_CONTROL_REG 0x01
|
||||
#define AD4130_ADC_CONTROL_BIPOLAR_MASK BIT(14)
|
||||
#define AD4130_ADC_CONTROL_INT_REF_VAL_MASK BIT(13)
|
||||
#define AD4130_ADC_CONTROL_CONT_READ_MASK BIT(11)
|
||||
#define AD4130_INT_REF_2_5V 2500000
|
||||
#define AD4130_INT_REF_1_25V 1250000
|
||||
#define AD4130_ADC_CONTROL_CSB_EN_MASK BIT(9)
|
||||
|
|
@ -54,7 +60,9 @@
|
|||
#define AD4130_IO_CONTROL_REG 0x03
|
||||
#define AD4130_IO_CONTROL_INT_PIN_SEL_MASK GENMASK(9, 8)
|
||||
#define AD4130_IO_CONTROL_GPIO_DATA_MASK GENMASK(7, 4)
|
||||
#define AD4130_4_IO_CONTROL_GPIO_DATA_MASK GENMASK(7, 6)
|
||||
#define AD4130_IO_CONTROL_GPIO_CTRL_MASK GENMASK(3, 0)
|
||||
#define AD4130_4_IO_CONTROL_GPIO_CTRL_MASK GENMASK(3, 2)
|
||||
|
||||
#define AD4130_VBIAS_REG 0x04
|
||||
|
||||
|
|
@ -125,6 +133,28 @@
|
|||
|
||||
#define AD4130_INVALID_SLOT -1
|
||||
|
||||
static const unsigned int ad4129_reg_size[] = {
|
||||
[AD4130_STATUS_REG] = 1,
|
||||
[AD4130_ADC_CONTROL_REG] = 2,
|
||||
[AD4130_DATA_REG] = 2,
|
||||
[AD4130_IO_CONTROL_REG] = 2,
|
||||
[AD4130_VBIAS_REG] = 2,
|
||||
[AD4130_ID_REG] = 1,
|
||||
[AD4130_ERROR_REG] = 2,
|
||||
[AD4130_ERROR_EN_REG] = 2,
|
||||
[AD4130_MCLK_COUNT_REG] = 1,
|
||||
[AD4130_CHANNEL_X_REG(0) ... AD4130_CHANNEL_X_REG(AD4130_MAX_CHANNELS - 1)] = 3,
|
||||
[AD4130_CONFIG_X_REG(0) ... AD4130_CONFIG_X_REG(AD4130_MAX_SETUPS - 1)] = 2,
|
||||
[AD4130_FILTER_X_REG(0) ... AD4130_FILTER_X_REG(AD4130_MAX_SETUPS - 1)] = 3,
|
||||
[AD4130_OFFSET_X_REG(0) ... AD4130_OFFSET_X_REG(AD4130_MAX_SETUPS - 1)] = 2,
|
||||
[AD4130_GAIN_X_REG(0) ... AD4130_GAIN_X_REG(AD4130_MAX_SETUPS - 1)] = 2,
|
||||
[AD4130_MISC_REG] = 2,
|
||||
[AD4130_FIFO_CONTROL_REG] = 3,
|
||||
[AD4130_FIFO_STATUS_REG] = 1,
|
||||
[AD4130_FIFO_THRESHOLD_REG] = 3,
|
||||
[AD4130_FIFO_DATA_REG] = 2,
|
||||
};
|
||||
|
||||
static const unsigned int ad4130_reg_size[] = {
|
||||
[AD4130_STATUS_REG] = 1,
|
||||
[AD4130_ADC_CONTROL_REG] = 2,
|
||||
|
|
@ -147,6 +177,24 @@ static const unsigned int ad4130_reg_size[] = {
|
|||
[AD4130_FIFO_DATA_REG] = 3,
|
||||
};
|
||||
|
||||
static const unsigned int ad4131_reg_size[] = {
|
||||
[AD4130_STATUS_REG] = 1,
|
||||
[AD4130_ADC_CONTROL_REG] = 2,
|
||||
[AD4130_DATA_REG] = 2,
|
||||
[AD4130_IO_CONTROL_REG] = 2,
|
||||
[AD4130_VBIAS_REG] = 2,
|
||||
[AD4130_ID_REG] = 1,
|
||||
[AD4130_ERROR_REG] = 2,
|
||||
[AD4130_ERROR_EN_REG] = 2,
|
||||
[AD4130_MCLK_COUNT_REG] = 1,
|
||||
[AD4130_CHANNEL_X_REG(0) ... AD4130_CHANNEL_X_REG(AD4130_MAX_CHANNELS - 1)] = 3,
|
||||
[AD4130_CONFIG_X_REG(0) ... AD4130_CONFIG_X_REG(AD4130_MAX_SETUPS - 1)] = 2,
|
||||
[AD4130_FILTER_X_REG(0) ... AD4130_FILTER_X_REG(AD4130_MAX_SETUPS - 1)] = 3,
|
||||
[AD4130_OFFSET_X_REG(0) ... AD4130_OFFSET_X_REG(AD4130_MAX_SETUPS - 1)] = 2,
|
||||
[AD4130_GAIN_X_REG(0) ... AD4130_GAIN_X_REG(AD4130_MAX_SETUPS - 1)] = 2,
|
||||
[AD4130_MISC_REG] = 2,
|
||||
};
|
||||
|
||||
enum ad4130_int_ref_val {
|
||||
AD4130_INT_REF_VAL_2_5V,
|
||||
AD4130_INT_REF_VAL_1_25V,
|
||||
|
|
@ -224,12 +272,26 @@ enum ad4130_pin_function {
|
|||
AD4130_PIN_FN_VBIAS = BIT(3),
|
||||
};
|
||||
|
||||
/* Pin mapping for AIN0..AIN7, VBIAS_0..VBIAS_7 */
|
||||
static const u8 ad4130_4_pin_map[] = {
|
||||
0x00, 0x01, 0x04, 0x05, 0x0A, 0x0B, 0x0E, 0x0F, /* 0 - 7 */
|
||||
};
|
||||
|
||||
/* Pin mapping for AIN0..AIN15, VBIAS_0..VBIAS_15 */
|
||||
static const u8 ad4130_8_pin_map[] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0 - 7 */
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 8 - 15 */
|
||||
};
|
||||
|
||||
struct ad4130_chip_info {
|
||||
const char *name;
|
||||
unsigned int max_analog_pins;
|
||||
unsigned int num_gpios;
|
||||
const struct iio_info *info;
|
||||
const unsigned int *reg_size;
|
||||
const unsigned int reg_size_length;
|
||||
const u8 *pin_map;
|
||||
bool has_fifo;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -303,6 +365,7 @@ struct ad4130_state {
|
|||
u32 mclk_sel;
|
||||
bool int_ref_en;
|
||||
bool bipolar;
|
||||
bool buffer_wait_for_irq;
|
||||
|
||||
unsigned int num_enabled_channels;
|
||||
unsigned int effective_watermark;
|
||||
|
|
@ -310,6 +373,7 @@ struct ad4130_state {
|
|||
|
||||
struct spi_message fifo_msg;
|
||||
struct spi_transfer fifo_xfer[2];
|
||||
struct iio_trigger *trig;
|
||||
|
||||
/*
|
||||
* DMA (thus cache coherency maintenance) requires any transfer
|
||||
|
|
@ -321,9 +385,13 @@ struct ad4130_state {
|
|||
u8 reg_write_tx_buf[4];
|
||||
u8 reg_read_tx_buf[1];
|
||||
u8 reg_read_rx_buf[3];
|
||||
u8 fifo_tx_buf[2];
|
||||
u8 fifo_rx_buf[AD4130_FIFO_SIZE *
|
||||
AD4130_FIFO_MAX_SAMPLE_SIZE];
|
||||
union {
|
||||
struct {
|
||||
u8 fifo_tx_buf[2];
|
||||
u8 fifo_rx_buf[AD4130_FIFO_SIZE * AD4130_FIFO_MAX_SAMPLE_SIZE];
|
||||
};
|
||||
IIO_DECLARE_BUFFER_WITH_TS(u32, scan_channels, AD4130_MAX_CHANNELS);
|
||||
};
|
||||
};
|
||||
|
||||
static const char * const ad4130_int_pin_names[] = {
|
||||
|
|
@ -514,7 +582,8 @@ static int ad4130_gpio_init_valid_mask(struct gpio_chip *gc,
|
|||
|
||||
/*
|
||||
* Output-only GPIO functionality is available on pins AIN2 through
|
||||
* AIN5. If these pins are used for anything else, do not expose them.
|
||||
* AIN5 for some parts and AIN2 through AIN3 for others. If these pins
|
||||
* are used for anything else, do not expose them.
|
||||
*/
|
||||
for (i = 0; i < ngpios; i++) {
|
||||
unsigned int pin = i + AD4130_AIN2_P1;
|
||||
|
|
@ -535,8 +604,14 @@ static int ad4130_gpio_set(struct gpio_chip *gc, unsigned int offset,
|
|||
int value)
|
||||
{
|
||||
struct ad4130_state *st = gpiochip_get_data(gc);
|
||||
unsigned int mask = FIELD_PREP(AD4130_IO_CONTROL_GPIO_DATA_MASK,
|
||||
BIT(offset));
|
||||
unsigned int mask;
|
||||
|
||||
if (st->chip_info->num_gpios == AD4130_MAX_GPIOS)
|
||||
mask = FIELD_PREP(AD4130_IO_CONTROL_GPIO_DATA_MASK,
|
||||
BIT(offset));
|
||||
else
|
||||
mask = FIELD_PREP(AD4130_4_IO_CONTROL_GPIO_DATA_MASK,
|
||||
BIT(offset));
|
||||
|
||||
return regmap_update_bits(st->regmap, AD4130_IO_CONTROL_REG, mask,
|
||||
value ? mask : 0);
|
||||
|
|
@ -597,10 +672,43 @@ static irqreturn_t ad4130_irq_handler(int irq, void *private)
|
|||
struct iio_dev *indio_dev = private;
|
||||
struct ad4130_state *st = iio_priv(indio_dev);
|
||||
|
||||
if (iio_buffer_enabled(indio_dev))
|
||||
ad4130_push_fifo_data(indio_dev);
|
||||
else
|
||||
if (iio_buffer_enabled(indio_dev)) {
|
||||
if (st->chip_info->has_fifo)
|
||||
ad4130_push_fifo_data(indio_dev);
|
||||
else if (st->buffer_wait_for_irq)
|
||||
complete(&st->completion);
|
||||
else
|
||||
iio_trigger_poll(st->trig);
|
||||
} else {
|
||||
complete(&st->completion);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t ad4130_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct ad4130_state *st = iio_priv(indio_dev);
|
||||
unsigned int data_reg_size = ad4130_data_reg_size(st);
|
||||
struct spi_transfer xfer = { };
|
||||
unsigned int num_en_chn;
|
||||
int ret;
|
||||
|
||||
num_en_chn = bitmap_weight(indio_dev->active_scan_mask,
|
||||
iio_get_masklength(indio_dev));
|
||||
xfer.rx_buf = st->scan_channels;
|
||||
xfer.len = data_reg_size * num_en_chn;
|
||||
ret = spi_sync_transfer(st->spi, &xfer, 1);
|
||||
if (ret < 0)
|
||||
goto err_out;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, &st->scan_channels,
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
err_out:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
|
@ -1300,12 +1408,77 @@ static const struct iio_info ad4130_info = {
|
|||
.debugfs_reg_access = ad4130_reg_access,
|
||||
};
|
||||
|
||||
static const struct ad4130_chip_info ad4130_8_chip_info = {
|
||||
.name = "ad4130-8",
|
||||
static const struct iio_info ad4131_info = {
|
||||
.read_raw = ad4130_read_raw,
|
||||
.read_avail = ad4130_read_avail,
|
||||
.write_raw_get_fmt = ad4130_write_raw_get_fmt,
|
||||
.write_raw = ad4130_write_raw,
|
||||
.update_scan_mode = ad4130_update_scan_mode,
|
||||
.debugfs_reg_access = ad4130_reg_access,
|
||||
};
|
||||
|
||||
static const struct ad4130_chip_info ad4129_4_chip_info = {
|
||||
.name = "ad4129-4",
|
||||
.max_analog_pins = 8,
|
||||
.num_gpios = 2,
|
||||
.info = &ad4130_info,
|
||||
.reg_size = ad4129_reg_size,
|
||||
.reg_size_length = ARRAY_SIZE(ad4129_reg_size),
|
||||
.has_fifo = true,
|
||||
.pin_map = ad4130_4_pin_map,
|
||||
};
|
||||
|
||||
static const struct ad4130_chip_info ad4129_8_chip_info = {
|
||||
.name = "ad4129-8",
|
||||
.max_analog_pins = 16,
|
||||
.num_gpios = 4,
|
||||
.info = &ad4130_info,
|
||||
.reg_size = ad4129_reg_size,
|
||||
.reg_size_length = ARRAY_SIZE(ad4129_reg_size),
|
||||
.has_fifo = true,
|
||||
.pin_map = ad4130_8_pin_map,
|
||||
};
|
||||
|
||||
static const struct ad4130_chip_info ad4130_4_chip_info = {
|
||||
.name = "ad4130-4",
|
||||
.max_analog_pins = 16,
|
||||
.num_gpios = 2,
|
||||
.info = &ad4130_info,
|
||||
.reg_size = ad4130_reg_size,
|
||||
.reg_size_length = ARRAY_SIZE(ad4130_reg_size),
|
||||
.has_fifo = true,
|
||||
.pin_map = ad4130_4_pin_map,
|
||||
};
|
||||
|
||||
static const struct ad4130_chip_info ad4130_8_chip_info = {
|
||||
.name = "ad4130-8",
|
||||
.max_analog_pins = 16,
|
||||
.num_gpios = 4,
|
||||
.info = &ad4130_info,
|
||||
.reg_size = ad4130_reg_size,
|
||||
.reg_size_length = ARRAY_SIZE(ad4130_reg_size),
|
||||
.has_fifo = true,
|
||||
.pin_map = ad4130_8_pin_map,
|
||||
};
|
||||
|
||||
static const struct ad4130_chip_info ad4131_4_chip_info = {
|
||||
.name = "ad4131-4",
|
||||
.max_analog_pins = 8,
|
||||
.num_gpios = 2,
|
||||
.info = &ad4131_info,
|
||||
.reg_size = ad4131_reg_size,
|
||||
.reg_size_length = ARRAY_SIZE(ad4131_reg_size),
|
||||
.pin_map = ad4130_4_pin_map,
|
||||
};
|
||||
|
||||
static const struct ad4130_chip_info ad4131_8_chip_info = {
|
||||
.name = "ad4131-8",
|
||||
.max_analog_pins = 16,
|
||||
.num_gpios = 4,
|
||||
.info = &ad4131_info,
|
||||
.reg_size = ad4131_reg_size,
|
||||
.reg_size_length = ARRAY_SIZE(ad4131_reg_size),
|
||||
.pin_map = ad4130_8_pin_map,
|
||||
};
|
||||
|
||||
static int ad4130_buffer_postenable(struct iio_dev *indio_dev)
|
||||
|
|
@ -1315,44 +1488,89 @@ static int ad4130_buffer_postenable(struct iio_dev *indio_dev)
|
|||
|
||||
guard(mutex)(&st->lock);
|
||||
|
||||
ret = ad4130_set_watermark_interrupt_en(st, true);
|
||||
if (st->chip_info->has_fifo) {
|
||||
ret = ad4130_set_watermark_interrupt_en(st, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = irq_set_irq_type(st->spi->irq, st->inv_irq_trigger);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_WM);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ad4130_set_mode(st, AD4130_MODE_CONTINUOUS);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = irq_set_irq_type(st->spi->irq, st->inv_irq_trigger);
|
||||
if (ret)
|
||||
return ret;
|
||||
/*
|
||||
* When using triggered buffer, Entering continuous read mode must
|
||||
* be the last command sent. No configuration changes are allowed until
|
||||
* exiting this mode.
|
||||
*/
|
||||
if (!st->chip_info->has_fifo) {
|
||||
ret = regmap_update_bits(st->regmap, AD4130_ADC_CONTROL_REG,
|
||||
AD4130_ADC_CONTROL_CONT_READ_MASK,
|
||||
FIELD_PREP(AD4130_ADC_CONTROL_CONT_READ_MASK, 1));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_WM);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ad4130_set_mode(st, AD4130_MODE_CONTINUOUS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad4130_buffer_predisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad4130_state *st = iio_priv(indio_dev);
|
||||
unsigned int i;
|
||||
u32 temp;
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
|
||||
if (!st->chip_info->has_fifo) {
|
||||
temp = 0x42;
|
||||
reinit_completion(&st->completion);
|
||||
|
||||
/*
|
||||
* In continuous read mode, when all samples are read, the data
|
||||
* ready signal returns high until the next conversion result is
|
||||
* ready. To exit this mode, the command must be sent when data
|
||||
* ready is low. In order to ensure that condition, wait for the
|
||||
* next interrupt (when the new conversion is finished), allowing
|
||||
* data ready to return low before sending the exit command.
|
||||
*/
|
||||
st->buffer_wait_for_irq = true;
|
||||
if (!wait_for_completion_timeout(&st->completion, msecs_to_jiffies(1000)))
|
||||
dev_warn(&st->spi->dev, "Conversion timed out\n");
|
||||
st->buffer_wait_for_irq = false;
|
||||
|
||||
/* Perform a read data command to exit continuous read mode (0x42) */
|
||||
ret = spi_write(st->spi, &temp, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ad4130_set_mode(st, AD4130_MODE_IDLE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = irq_set_irq_type(st->spi->irq, st->irq_trigger);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (st->chip_info->has_fifo) {
|
||||
ret = irq_set_irq_type(st->spi->irq, st->irq_trigger);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_DISABLED);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_DISABLED);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ad4130_set_watermark_interrupt_en(st, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = ad4130_set_watermark_interrupt_en(st, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* update_scan_mode() is not called in the disable path, disable all
|
||||
|
|
@ -1427,6 +1645,34 @@ static const struct iio_dev_attr *ad4130_fifo_attributes[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static const struct iio_trigger_ops ad4130_trigger_ops = {
|
||||
.validate_device = iio_trigger_validate_own_device,
|
||||
};
|
||||
|
||||
static int ad4130_triggered_buffer_setup(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad4130_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
st->trig = devm_iio_trigger_alloc(indio_dev->dev.parent, "%s-dev%d",
|
||||
indio_dev->name, iio_device_id(indio_dev));
|
||||
if (!st->trig)
|
||||
return -ENOMEM;
|
||||
|
||||
st->trig->ops = &ad4130_trigger_ops;
|
||||
iio_trigger_set_drvdata(st->trig, indio_dev);
|
||||
ret = devm_iio_trigger_register(indio_dev->dev.parent, st->trig);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
indio_dev->trig = iio_trigger_get(st->trig);
|
||||
|
||||
return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev,
|
||||
&iio_pollfunc_store_time,
|
||||
&ad4130_trigger_handler,
|
||||
&ad4130_buffer_ops);
|
||||
}
|
||||
|
||||
static int _ad4130_find_table_index(const unsigned int *tbl, size_t len,
|
||||
unsigned int val)
|
||||
{
|
||||
|
|
@ -1513,6 +1759,17 @@ static int ad4130_parse_fw_setup(struct ad4130_state *st,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int ad4130_translate_pin(struct ad4130_state *st,
|
||||
unsigned int logical_pin)
|
||||
{
|
||||
/* For analog input pins, use the chip-specific pin mapping */
|
||||
if (logical_pin < st->chip_info->max_analog_pins)
|
||||
return st->chip_info->pin_map[logical_pin];
|
||||
|
||||
/* For internal channels, pass through unchanged */
|
||||
return logical_pin;
|
||||
}
|
||||
|
||||
static int ad4130_validate_diff_channel(struct ad4130_state *st, u32 pin)
|
||||
{
|
||||
struct device *dev = &st->spi->dev;
|
||||
|
|
@ -1931,9 +2188,14 @@ static int ad4130_setup(struct iio_dev *indio_dev)
|
|||
* function of P2 takes priority over the GPIO out function.
|
||||
*/
|
||||
val = 0;
|
||||
for (i = 0; i < AD4130_MAX_GPIOS; i++)
|
||||
if (st->pins_fn[i + AD4130_AIN2_P1] == AD4130_PIN_FN_NONE)
|
||||
val |= FIELD_PREP(AD4130_IO_CONTROL_GPIO_CTRL_MASK, BIT(i));
|
||||
for (i = 0; i < st->chip_info->num_gpios; i++) {
|
||||
if (st->pins_fn[i + AD4130_AIN2_P1] == AD4130_PIN_FN_NONE) {
|
||||
if (st->chip_info->num_gpios == 2)
|
||||
val |= FIELD_PREP(AD4130_4_IO_CONTROL_GPIO_CTRL_MASK, BIT(i));
|
||||
else
|
||||
val |= FIELD_PREP(AD4130_IO_CONTROL_GPIO_CTRL_MASK, BIT(i));
|
||||
}
|
||||
}
|
||||
|
||||
val |= FIELD_PREP(AD4130_IO_CONTROL_INT_PIN_SEL_MASK, st->int_pin_sel);
|
||||
|
||||
|
|
@ -1943,21 +2205,23 @@ static int ad4130_setup(struct iio_dev *indio_dev)
|
|||
|
||||
val = 0;
|
||||
for (i = 0; i < st->num_vbias_pins; i++)
|
||||
val |= BIT(st->vbias_pins[i]);
|
||||
val |= BIT(ad4130_translate_pin(st, st->vbias_pins[i]));
|
||||
|
||||
ret = regmap_write(st->regmap, AD4130_VBIAS_REG, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_clear_bits(st->regmap, AD4130_FIFO_CONTROL_REG,
|
||||
AD4130_FIFO_CONTROL_HEADER_MASK);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (st->chip_info->has_fifo) {
|
||||
ret = regmap_clear_bits(st->regmap, AD4130_FIFO_CONTROL_REG,
|
||||
AD4130_FIFO_CONTROL_HEADER_MASK);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* FIFO watermark interrupt starts out as enabled, disable it. */
|
||||
ret = ad4130_set_watermark_interrupt_en(st, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* FIFO watermark interrupt starts out as enabled, disable it. */
|
||||
ret = ad4130_set_watermark_interrupt_en(st, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Setup channels. */
|
||||
for (i = 0; i < indio_dev->num_channels; i++) {
|
||||
|
|
@ -1965,10 +2229,14 @@ static int ad4130_setup(struct iio_dev *indio_dev)
|
|||
struct iio_chan_spec *chan = &st->chans[i];
|
||||
unsigned int val;
|
||||
|
||||
val = FIELD_PREP(AD4130_CHANNEL_AINP_MASK, chan->channel) |
|
||||
FIELD_PREP(AD4130_CHANNEL_AINM_MASK, chan->channel2) |
|
||||
FIELD_PREP(AD4130_CHANNEL_IOUT1_MASK, chan_info->iout0) |
|
||||
FIELD_PREP(AD4130_CHANNEL_IOUT2_MASK, chan_info->iout1);
|
||||
val = FIELD_PREP(AD4130_CHANNEL_AINP_MASK,
|
||||
ad4130_translate_pin(st, chan->channel)) |
|
||||
FIELD_PREP(AD4130_CHANNEL_AINM_MASK,
|
||||
ad4130_translate_pin(st, chan->channel2)) |
|
||||
FIELD_PREP(AD4130_CHANNEL_IOUT1_MASK,
|
||||
ad4130_translate_pin(st, chan_info->iout0)) |
|
||||
FIELD_PREP(AD4130_CHANNEL_IOUT2_MASK,
|
||||
ad4130_translate_pin(st, chan_info->iout1));
|
||||
|
||||
ret = regmap_write(st->regmap, AD4130_CHANNEL_X_REG(i), val);
|
||||
if (ret)
|
||||
|
|
@ -2018,17 +2286,19 @@ static int ad4130_probe(struct spi_device *spi)
|
|||
mutex_init(&st->lock);
|
||||
st->spi = spi;
|
||||
|
||||
/*
|
||||
* Xfer: [ XFR1 ] [ XFR2 ]
|
||||
* Master: 0x7D N ......................
|
||||
* Slave: ...... DATA1 DATA2 ... DATAN
|
||||
*/
|
||||
st->fifo_tx_buf[0] = AD4130_COMMS_READ_MASK | AD4130_FIFO_DATA_REG;
|
||||
st->fifo_xfer[0].tx_buf = st->fifo_tx_buf;
|
||||
st->fifo_xfer[0].len = sizeof(st->fifo_tx_buf);
|
||||
st->fifo_xfer[1].rx_buf = st->fifo_rx_buf;
|
||||
spi_message_init_with_transfers(&st->fifo_msg, st->fifo_xfer,
|
||||
ARRAY_SIZE(st->fifo_xfer));
|
||||
if (st->chip_info->has_fifo) {
|
||||
/*
|
||||
* Xfer: [ XFR1 ] [ XFR2 ]
|
||||
* Master: 0x7D N ......................
|
||||
* Slave: ...... DATA1 DATA2 ... DATAN
|
||||
*/
|
||||
st->fifo_tx_buf[0] = AD4130_COMMS_READ_MASK | AD4130_FIFO_DATA_REG;
|
||||
st->fifo_xfer[0].tx_buf = st->fifo_tx_buf;
|
||||
st->fifo_xfer[0].len = sizeof(st->fifo_tx_buf);
|
||||
st->fifo_xfer[1].rx_buf = st->fifo_rx_buf;
|
||||
spi_message_init_with_transfers(&st->fifo_msg, st->fifo_xfer,
|
||||
ARRAY_SIZE(st->fifo_xfer));
|
||||
}
|
||||
|
||||
indio_dev->name = st->chip_info->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
|
@ -2077,7 +2347,7 @@ static int ad4130_probe(struct spi_device *spi)
|
|||
st->gc.owner = THIS_MODULE;
|
||||
st->gc.label = st->chip_info->name;
|
||||
st->gc.base = -1;
|
||||
st->gc.ngpio = AD4130_MAX_GPIOS;
|
||||
st->gc.ngpio = st->chip_info->num_gpios;
|
||||
st->gc.parent = dev;
|
||||
st->gc.can_sleep = true;
|
||||
st->gc.init_valid_mask = ad4130_gpio_init_valid_mask;
|
||||
|
|
@ -2088,9 +2358,12 @@ static int ad4130_probe(struct spi_device *spi)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev,
|
||||
&ad4130_buffer_ops,
|
||||
ad4130_fifo_attributes);
|
||||
if (st->chip_info->has_fifo)
|
||||
ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev,
|
||||
&ad4130_buffer_ops,
|
||||
ad4130_fifo_attributes);
|
||||
else
|
||||
ret = ad4130_triggered_buffer_setup(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -2100,37 +2373,64 @@ static int ad4130_probe(struct spi_device *spi)
|
|||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to request irq\n");
|
||||
|
||||
/*
|
||||
* When the chip enters FIFO mode, IRQ polarity is inverted.
|
||||
* When the chip exits FIFO mode, IRQ polarity returns to normal.
|
||||
* See datasheet pages: 65, FIFO Watermark Interrupt section,
|
||||
* and 71, Bit Descriptions for STATUS Register, RDYB.
|
||||
* Cache the normal and inverted IRQ triggers to set them when
|
||||
* entering and exiting FIFO mode.
|
||||
*/
|
||||
st->irq_trigger = irq_get_trigger_type(spi->irq);
|
||||
if (st->irq_trigger & IRQF_TRIGGER_RISING)
|
||||
st->inv_irq_trigger = IRQF_TRIGGER_FALLING;
|
||||
else if (st->irq_trigger & IRQF_TRIGGER_FALLING)
|
||||
st->inv_irq_trigger = IRQF_TRIGGER_RISING;
|
||||
else
|
||||
return dev_err_probe(dev, -EINVAL, "Invalid irq flags: %u\n",
|
||||
st->irq_trigger);
|
||||
if (st->chip_info->has_fifo) {
|
||||
/*
|
||||
* When the chip enters FIFO mode, IRQ polarity is inverted.
|
||||
* When the chip exits FIFO mode, IRQ polarity returns to normal.
|
||||
* See datasheet pages: 65, FIFO Watermark Interrupt section,
|
||||
* and 71, Bit Descriptions for STATUS Register, RDYB.
|
||||
* Cache the normal and inverted IRQ triggers to set them when
|
||||
* entering and exiting FIFO mode.
|
||||
*/
|
||||
st->irq_trigger = irq_get_trigger_type(spi->irq);
|
||||
if (st->irq_trigger & IRQF_TRIGGER_RISING)
|
||||
st->inv_irq_trigger = IRQF_TRIGGER_FALLING;
|
||||
else if (st->irq_trigger & IRQF_TRIGGER_FALLING)
|
||||
st->inv_irq_trigger = IRQF_TRIGGER_RISING;
|
||||
else
|
||||
return dev_err_probe(dev, -EINVAL, "Invalid irq flags: %u\n",
|
||||
st->irq_trigger);
|
||||
}
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id ad4130_of_match[] = {
|
||||
{
|
||||
.compatible = "adi,ad4129-4",
|
||||
.data = &ad4129_4_chip_info
|
||||
},
|
||||
{
|
||||
.compatible = "adi,ad4129-8",
|
||||
.data = &ad4129_8_chip_info
|
||||
},
|
||||
{
|
||||
.compatible = "adi,ad4130-4",
|
||||
.data = &ad4130_4_chip_info
|
||||
},
|
||||
{
|
||||
.compatible = "adi,ad4130",
|
||||
.data = &ad4130_8_chip_info
|
||||
},
|
||||
{
|
||||
.compatible = "adi,ad4131-4",
|
||||
.data = &ad4131_4_chip_info
|
||||
},
|
||||
{
|
||||
.compatible = "adi,ad4131-8",
|
||||
.data = &ad4131_8_chip_info
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad4130_of_match);
|
||||
|
||||
static const struct spi_device_id ad4130_id_table[] = {
|
||||
{ "ad4129-4", (kernel_ulong_t)&ad4129_4_chip_info },
|
||||
{ "ad4129-8", (kernel_ulong_t)&ad4129_8_chip_info },
|
||||
{ "ad4130-4", (kernel_ulong_t)&ad4130_4_chip_info },
|
||||
{ "ad4130", (kernel_ulong_t)&ad4130_8_chip_info },
|
||||
{ "ad4131-4", (kernel_ulong_t)&ad4131_4_chip_info },
|
||||
{ "ad4131-8", (kernel_ulong_t)&ad4131_8_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad4130_id_table);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user