summaryrefslogtreecommitdiff
path: root/drivers/iio/adc/ad9467.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/adc/ad9467.c')
-rw-r--r--drivers/iio/adc/ad9467.c152
1 files changed, 134 insertions, 18 deletions
diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c
index 2d8f8da3671d..022888545580 100644
--- a/drivers/iio/adc/ad9467.c
+++ b/drivers/iio/adc/ad9467.c
@@ -5,29 +5,29 @@
* Copyright 2012-2020 Analog Devices Inc.
*/
+#include <linux/bitfield.h>
#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/cleanup.h>
+#include <linux/clk.h>
#include <linux/debugfs.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
+#include <linux/delay.h>
#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/spi/spi.h>
-#include <linux/seq_file.h>
#include <linux/err.h>
-#include <linux/delay.h>
#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/of.h>
-
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/units.h>
#include <linux/iio/backend.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
-#include <linux/clk.h>
-
/*
* ADI High-Speed ADC common spi interface registers
* See Application-Note AN-877:
@@ -73,6 +73,7 @@
#define AN877_ADC_OUTPUT_MODE_OFFSET_BINARY 0x0
#define AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT 0x1
#define AN877_ADC_OUTPUT_MODE_GRAY_CODE 0x2
+#define AN877_ADC_OUTPUT_MODE_MASK GENMASK(1, 0)
/* AN877_ADC_REG_OUTPUT_PHASE */
#define AN877_ADC_OUTPUT_EVEN_ODD_MODE_EN 0x20
@@ -82,11 +83,19 @@
#define AN877_ADC_DCO_DELAY_ENABLE 0x80
/*
+ * Analog Devices AD9211 10-Bit, 200/250/300 MSPS ADC
+ */
+
+#define CHIPID_AD9211 0x06
+#define AD9211_DEF_OUTPUT_MODE 0x01
+#define AD9211_REG_VREF_MASK GENMASK(4, 0)
+
+/*
* Analog Devices AD9265 16-Bit, 125/105/80 MSPS ADC
*/
#define CHIPID_AD9265 0x64
-#define AD9265_DEF_OUTPUT_MODE 0x40
+#define AD9265_DEF_OUTPUT_MODE 0x41
#define AD9265_REG_VREF_MASK 0xC0
/*
@@ -94,7 +103,7 @@
*/
#define CHIPID_AD9434 0x6A
-#define AD9434_DEF_OUTPUT_MODE 0x00
+#define AD9434_DEF_OUTPUT_MODE 0x01
#define AD9434_REG_VREF_MASK GENMASK(4, 0)
/*
@@ -102,7 +111,7 @@
*/
#define CHIPID_AD9467 0x50
-#define AD9467_DEF_OUTPUT_MODE 0x08
+#define AD9467_DEF_OUTPUT_MODE 0x09
#define AD9467_REG_VREF_MASK 0x0F
/*
@@ -110,6 +119,7 @@
*/
#define CHIPID_AD9643 0x82
+#define AD9643_DEF_OUTPUT_MODE 0x01
#define AD9643_REG_VREF_MASK 0x1F
/*
@@ -117,6 +127,7 @@
*/
#define CHIPID_AD9652 0xC1
+#define AD9652_DEF_OUTPUT_MODE 0x01
#define AD9652_REG_VREF_MASK 0xC0
/*
@@ -124,6 +135,7 @@
*/
#define CHIPID_AD9649 0x6F
+#define AD9649_DEF_OUTPUT_MODE 0x01
#define AD9649_TEST_POINTS 8
#define AD9647_MAX_TEST_POINTS 32
@@ -145,6 +157,7 @@ struct ad9467_chip_info {
unsigned int num_lanes;
unsigned int dco_en;
unsigned int test_points;
+ const int *offset_range;
/* data clock output */
bool has_dco;
bool has_dco_invert;
@@ -234,6 +247,21 @@ static int ad9467_reg_access(struct iio_dev *indio_dev, unsigned int reg,
return 0;
}
+static const int ad9434_offset_range[] = {
+ -128, 1, 127,
+};
+
+static const unsigned int ad9211_scale_table[][2] = {
+ {980, 0x10}, {1000, 0x11}, {1020, 0x12}, {1040, 0x13},
+ {1060, 0x14}, {1080, 0x15}, {1100, 0x16}, {1120, 0x17},
+ {1140, 0x18}, {1160, 0x19}, {1180, 0x1A}, {1190, 0x1B},
+ {1200, 0x1C}, {1210, 0x1D}, {1220, 0x1E}, {1230, 0x1F},
+ {1250, 0x0}, {1270, 0x1}, {1290, 0x2}, {1310, 0x3},
+ {1330, 0x4}, {1350, 0x5}, {1370, 0x6}, {1390, 0x7},
+ {1410, 0x8}, {1430, 0x9}, {1450, 0xA}, {1460, 0xB},
+ {1470, 0xC}, {1480, 0xD}, {1490, 0xE}, {1500, 0xF},
+};
+
static const unsigned int ad9265_scale_table[][2] = {
{1250, 0x00}, {1500, 0x40}, {1750, 0x80}, {2000, 0xC0},
};
@@ -297,8 +325,29 @@ static void __ad9467_get_scale(struct ad9467_state *st, int index,
}, \
}
+static const struct iio_chan_spec ad9211_channels[] = {
+ AD9467_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 0, 10, 's'),
+};
+
static const struct iio_chan_spec ad9434_channels[] = {
- AD9467_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 0, 12, 's'),
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask_shared_by_type =
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS),
+ .info_mask_shared_by_type_available =
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS),
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ },
};
static const struct iio_chan_spec ad9467_channels[] = {
@@ -367,6 +416,24 @@ static const struct ad9467_chip_info ad9434_chip_tbl = {
.default_output_mode = AD9434_DEF_OUTPUT_MODE,
.vref_mask = AD9434_REG_VREF_MASK,
.num_lanes = 6,
+ .offset_range = ad9434_offset_range,
+};
+
+static const struct ad9467_chip_info ad9211_chip_tbl = {
+ .name = "ad9211",
+ .id = CHIPID_AD9211,
+ .max_rate = 300 * HZ_PER_MHZ,
+ .scale_table = ad9211_scale_table,
+ .num_scales = ARRAY_SIZE(ad9211_scale_table),
+ .channels = ad9211_channels,
+ .num_channels = ARRAY_SIZE(ad9211_channels),
+ .test_points = AD9647_MAX_TEST_POINTS,
+ .test_mask = GENMASK(AN877_ADC_TESTMODE_ONE_ZERO_TOGGLE,
+ AN877_ADC_TESTMODE_OFF),
+ .test_mask_len = AN877_ADC_TESTMODE_ONE_ZERO_TOGGLE + 1,
+ .default_output_mode = AD9211_DEF_OUTPUT_MODE,
+ .vref_mask = AD9211_REG_VREF_MASK,
+ .has_dco = true,
};
static const struct ad9467_chip_info ad9265_chip_tbl = {
@@ -399,6 +466,7 @@ static const struct ad9467_chip_info ad9643_chip_tbl = {
.test_mask = BIT(AN877_ADC_TESTMODE_RAMP) |
GENMASK(AN877_ADC_TESTMODE_MIXED_BIT_FREQUENCY, AN877_ADC_TESTMODE_OFF),
.test_mask_len = AN877_ADC_TESTMODE_RAMP + 1,
+ .default_output_mode = AD9643_DEF_OUTPUT_MODE,
.vref_mask = AD9643_REG_VREF_MASK,
.has_dco = true,
.has_dco_invert = true,
@@ -417,6 +485,7 @@ static const struct ad9467_chip_info ad9649_chip_tbl = {
.test_mask = GENMASK(AN877_ADC_TESTMODE_MIXED_BIT_FREQUENCY,
AN877_ADC_TESTMODE_OFF),
.test_mask_len = AN877_ADC_TESTMODE_MIXED_BIT_FREQUENCY + 1,
+ .default_output_mode = AD9649_DEF_OUTPUT_MODE,
.has_dco = true,
.has_dco_invert = true,
.dco_en = AN877_ADC_DCO_DELAY_ENABLE,
@@ -434,6 +503,7 @@ static const struct ad9467_chip_info ad9652_chip_tbl = {
.test_mask = GENMASK(AN877_ADC_TESTMODE_ONE_ZERO_TOGGLE,
AN877_ADC_TESTMODE_OFF),
.test_mask_len = AN877_ADC_TESTMODE_ONE_ZERO_TOGGLE + 1,
+ .default_output_mode = AD9652_DEF_OUTPUT_MODE,
.vref_mask = AD9652_REG_VREF_MASK,
.has_dco = true,
};
@@ -499,6 +569,33 @@ static int ad9467_set_scale(struct ad9467_state *st, int val, int val2)
return -EINVAL;
}
+static int ad9467_get_offset(struct ad9467_state *st, int *val)
+{
+ int ret;
+
+ ret = ad9467_spi_read(st, AN877_ADC_REG_OFFSET);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+
+ return IIO_VAL_INT;
+}
+
+static int ad9467_set_offset(struct ad9467_state *st, int val)
+{
+ int ret;
+
+ if (val < st->info->offset_range[0] || val > st->info->offset_range[2])
+ return -EINVAL;
+
+ ret = ad9467_spi_write(st, AN877_ADC_REG_OFFSET, val);
+ if (ret < 0)
+ return ret;
+
+ return ad9467_spi_write(st, AN877_ADC_REG_TRANSFER,
+ AN877_ADC_TRANSFER_SYNC);
+}
+
static int ad9467_outputmode_set(struct ad9467_state *st, unsigned int mode)
{
int ret;
@@ -582,10 +679,14 @@ static int ad9467_backend_testmode_off(struct ad9467_state *st,
static int ad9647_calibrate_prepare(struct ad9467_state *st)
{
+ unsigned int cmode;
unsigned int c;
int ret;
- ret = ad9467_outputmode_set(st, st->info->default_output_mode);
+ cmode = st->info->default_output_mode;
+ FIELD_MODIFY(AN877_ADC_OUTPUT_MODE_MASK, &cmode,
+ AN877_ADC_OUTPUT_MODE_OFFSET_BINARY);
+ ret = ad9467_outputmode_set(st, cmode);
if (ret)
return ret;
@@ -689,7 +790,7 @@ static int ad9647_calibrate_stop(struct ad9467_state *st)
return ret;
}
- mode = st->info->default_output_mode | AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT;
+ mode = st->info->default_output_mode;
return ad9467_outputmode_set(st, mode);
}
@@ -802,6 +903,8 @@ static int ad9467_read_raw(struct iio_dev *indio_dev,
struct ad9467_state *st = iio_priv(indio_dev);
switch (m) {
+ case IIO_CHAN_INFO_CALIBBIAS:
+ return ad9467_get_offset(st, val);
case IIO_CHAN_INFO_SCALE:
return ad9467_get_scale(st, val, val2);
case IIO_CHAN_INFO_SAMP_FREQ:
@@ -836,6 +939,8 @@ static int ad9467_write_raw(struct iio_dev *indio_dev,
int ret;
switch (mask) {
+ case IIO_CHAN_INFO_CALIBBIAS:
+ return ad9467_set_offset(st, val);
case IIO_CHAN_INFO_SCALE:
return ad9467_set_scale(st, val, val2);
case IIO_CHAN_INFO_SAMP_FREQ:
@@ -874,6 +979,10 @@ static int ad9467_read_avail(struct iio_dev *indio_dev,
const struct ad9467_chip_info *info = st->info;
switch (mask) {
+ case IIO_CHAN_INFO_CALIBBIAS:
+ *type = IIO_VAL_INT;
+ *vals = info->offset_range;
+ return IIO_AVAIL_RANGE;
case IIO_CHAN_INFO_SCALE:
*vals = (const int *)st->scales;
*type = IIO_VAL_INT_PLUS_MICRO;
@@ -1077,12 +1186,17 @@ static ssize_t ad9467_chan_test_mode_write(struct file *file,
if (ret)
return ret;
- out_mode = st->info->default_output_mode | AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT;
+ out_mode = st->info->default_output_mode;
ret = ad9467_outputmode_set(st, out_mode);
if (ret)
return ret;
} else {
- ret = ad9467_outputmode_set(st, st->info->default_output_mode);
+ unsigned int cmode;
+
+ cmode = st->info->default_output_mode;
+ FIELD_MODIFY(AN877_ADC_OUTPUT_MODE_MASK, &cmode,
+ AN877_ADC_OUTPUT_MODE_OFFSET_BINARY);
+ ret = ad9467_outputmode_set(st, cmode);
if (ret)
return ret;
@@ -1264,6 +1378,7 @@ static int ad9467_probe(struct spi_device *spi)
}
static const struct of_device_id ad9467_of_match[] = {
+ { .compatible = "adi,ad9211", .data = &ad9211_chip_tbl, },
{ .compatible = "adi,ad9265", .data = &ad9265_chip_tbl, },
{ .compatible = "adi,ad9434", .data = &ad9434_chip_tbl, },
{ .compatible = "adi,ad9467", .data = &ad9467_chip_tbl, },
@@ -1275,6 +1390,7 @@ static const struct of_device_id ad9467_of_match[] = {
MODULE_DEVICE_TABLE(of, ad9467_of_match);
static const struct spi_device_id ad9467_ids[] = {
+ { "ad9211", (kernel_ulong_t)&ad9211_chip_tbl },
{ "ad9265", (kernel_ulong_t)&ad9265_chip_tbl },
{ "ad9434", (kernel_ulong_t)&ad9434_chip_tbl },
{ "ad9467", (kernel_ulong_t)&ad9467_chip_tbl },