summaryrefslogtreecommitdiffstats
path: root/drivers/iio/adc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/adc')
-rw-r--r--drivers/iio/adc/Kconfig15
-rw-r--r--drivers/iio/adc/Makefile1
-rw-r--r--drivers/iio/adc/ad4000.c4
-rw-r--r--drivers/iio/adc/ad7091r-base.c3
-rw-r--r--drivers/iio/adc/ad7192.c3
-rw-r--r--drivers/iio/adc/ad7280a.c14
-rw-r--r--drivers/iio/adc/ad7291.c2
-rw-r--r--drivers/iio/adc/ad7380.c178
-rw-r--r--drivers/iio/adc/ad7606.c797
-rw-r--r--drivers/iio/adc/ad7606.h60
-rw-r--r--drivers/iio/adc/ad7606_par.c127
-rw-r--r--drivers/iio/adc/ad7606_spi.c138
-rw-r--r--drivers/iio/adc/ad7779.c914
-rw-r--r--drivers/iio/adc/ad799x.c2
-rw-r--r--drivers/iio/adc/hi8435.c2
-rw-r--r--drivers/iio/adc/max1363.c2
-rw-r--r--drivers/iio/adc/pac1921.c7
-rw-r--r--drivers/iio/adc/pac1934.c2
-rw-r--r--drivers/iio/adc/palmas_gpadc.c2
-rw-r--r--drivers/iio/adc/ti-ads1015.c2
-rw-r--r--drivers/iio/adc/xilinx-ams.c2
-rw-r--r--drivers/iio/adc/xilinx-xadc-events.c2
-rw-r--r--drivers/iio/adc/xilinx-xadc.h2
23 files changed, 1944 insertions, 337 deletions
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 179d83aafd8a..849c90203071 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -226,9 +226,11 @@ config AD7606_IFACE_PARALLEL
tristate "Analog Devices AD7606 ADC driver with parallel interface support"
depends on HAS_IOPORT
select AD7606
+ select IIO_BACKEND
help
Say yes here to build parallel interface support for Analog Devices:
ad7605-4, ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC).
+ It also support iio_backended devices for AD7606B.
To compile this driver as a module, choose M here: the
module will be called ad7606_par.
@@ -285,6 +287,18 @@ config AD7768_1
To compile this driver as a module, choose M here: the module will be
called ad7768-1.
+config AD7779
+ tristate "Analog Devices AD7779 ADC driver"
+ depends on SPI
+ select CRC8
+ select IIO_BUFFER
+ help
+ Say yes here to build support for Analog Devices AD777X family
+ (AD7770, AD7771, AD7779) analog to digital converter (ADC).
+
+ To compile this driver as a module, choose M here: the module will be
+ called ad7779.
+
config AD7780
tristate "Analog Devices AD7780 and similar ADCs driver"
depends on SPI
@@ -1606,7 +1620,6 @@ config TWL4030_MADC
config TWL6030_GPADC
tristate "TWL6030 GPADC (General Purpose A/D Converter) Support"
depends on TWL4030_CORE
- default n
help
Say yes here if you want support for the TWL6030/TWL6032 General
Purpose A/D Converter. This will add support for battery type
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 1df8f311c183..ee19afba62b7 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_AD7606) += ad7606.o
obj-$(CONFIG_AD7625) += ad7625.o
obj-$(CONFIG_AD7766) += ad7766.o
obj-$(CONFIG_AD7768_1) += ad7768-1.o
+obj-$(CONFIG_AD7779) += ad7779.o
obj-$(CONFIG_AD7780) += ad7780.o
obj-$(CONFIG_AD7791) += ad7791.o
obj-$(CONFIG_AD7793) += ad7793.o
diff --git a/drivers/iio/adc/ad4000.c b/drivers/iio/adc/ad4000.c
index fc9c9807f89d..b3b82535f5c1 100644
--- a/drivers/iio/adc/ad4000.c
+++ b/drivers/iio/adc/ad4000.c
@@ -639,7 +639,9 @@ static int ad4000_probe(struct spi_device *spi)
indio_dev->name = chip->dev_name;
indio_dev->num_channels = 1;
- devm_mutex_init(dev, &st->lock);
+ ret = devm_mutex_init(dev, &st->lock);
+ if (ret)
+ return ret;
st->gain_milli = 1000;
if (chip->has_hardware_gain) {
diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c
index d6876259ad14..eb0a059b4b0e 100644
--- a/drivers/iio/adc/ad7091r-base.c
+++ b/drivers/iio/adc/ad7091r-base.c
@@ -150,7 +150,8 @@ static int ad7091r_read_event_config(struct iio_dev *indio_dev,
static int ad7091r_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
- enum iio_event_direction dir, int state)
+ enum iio_event_direction dir,
+ bool state)
{
struct ad7091r_state *st = iio_priv(indio_dev);
diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c
index 7042ddfdfc03..955e9eff0099 100644
--- a/drivers/iio/adc/ad7192.c
+++ b/drivers/iio/adc/ad7192.c
@@ -1394,6 +1394,9 @@ static int ad7192_probe(struct spi_device *spi)
st->int_vref_mv = ret == -ENODEV ? avdd_mv : ret / MILLI;
st->chip_info = spi_get_device_match_data(spi);
+ if (!st->chip_info)
+ return -ENODEV;
+
indio_dev->name = st->chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = st->chip_info->info;
diff --git a/drivers/iio/adc/ad7280a.c b/drivers/iio/adc/ad7280a.c
index 35aa39fe4bde..f9f32737db80 100644
--- a/drivers/iio/adc/ad7280a.c
+++ b/drivers/iio/adc/ad7280a.c
@@ -822,17 +822,15 @@ static irqreturn_t ad7280_event_handler(int irq, void *private)
if (FIELD_GET(AD7280A_TRANS_READ_CONV_CHANADDR_MSK, channels[i]) <=
AD7280A_CELL_VOLTAGE_6_REG) {
if (val >= st->cell_threshhigh) {
- u64 tmp = IIO_EVENT_CODE(IIO_VOLTAGE, 1, 0,
- IIO_EV_DIR_RISING,
- IIO_EV_TYPE_THRESH,
- 0, 0, 0);
+ u64 tmp = IIO_DIFF_EVENT_CODE(IIO_VOLTAGE, 0, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_RISING);
iio_push_event(indio_dev, tmp,
iio_get_time_ns(indio_dev));
} else if (val <= st->cell_threshlow) {
- u64 tmp = IIO_EVENT_CODE(IIO_VOLTAGE, 1, 0,
- IIO_EV_DIR_FALLING,
- IIO_EV_TYPE_THRESH,
- 0, 0, 0);
+ u64 tmp = IIO_DIFF_EVENT_CODE(IIO_VOLTAGE, 0, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_FALLING);
iio_push_event(indio_dev, tmp,
iio_get_time_ns(indio_dev));
}
diff --git a/drivers/iio/adc/ad7291.c b/drivers/iio/adc/ad7291.c
index 4c7f887adbbf..60e12faa3207 100644
--- a/drivers/iio/adc/ad7291.c
+++ b/drivers/iio/adc/ad7291.c
@@ -269,7 +269,7 @@ static int ad7291_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
- int state)
+ bool state)
{
int ret = 0;
struct ad7291_chip_info *chip = iio_priv(indio_dev);
diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c
index fb728570debe..4f32cb22f140 100644
--- a/drivers/iio/adc/ad7380.c
+++ b/drivers/iio/adc/ad7380.c
@@ -13,6 +13,8 @@
* ad7381-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7381-4.pdf
* ad7383/4-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7383-4-ad7384-4.pdf
* ad7386/7/8-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7386-4-7387-4-7388-4.pdf
+ * adaq4370-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4370-4.pdf
+ * adaq4380-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4380-4.pdf
*/
#include <linux/align.h>
@@ -22,11 +24,14 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/kernel.h>
+#include <linux/math.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
+#include <linux/units.h>
+#include <linux/util_macros.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
@@ -36,6 +41,8 @@
#define MAX_NUM_CHANNELS 8
/* 2.5V internal reference voltage */
#define AD7380_INTERNAL_REF_MV 2500
+/* 3.3V internal reference voltage for ADAQ */
+#define ADAQ4380_INTERNAL_REF_MV 3300
/* reading and writing registers is more reliable at lower than max speed */
#define AD7380_REG_WR_SPEED_HZ 10000000
@@ -77,6 +84,13 @@
#define T_CONVERT_X_NS 500 /* xth conversion start time (oversampling) */
#define T_POWERUP_US 5000 /* Power up */
+/*
+ * AD738x support several SDO lines to increase throughput, but driver currently
+ * supports only 1 SDO line (standard SPI transaction)
+ */
+#define AD7380_NUM_SDO_LINES 1
+#define AD7380_DEFAULT_GAIN_MILLI 1000
+
struct ad7380_timing_specs {
const unsigned int t_csh_ns; /* CS minimum high time */
};
@@ -86,10 +100,12 @@ struct ad7380_chip_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
unsigned int num_simult_channels;
+ bool has_hardware_gain;
bool has_mux;
const char * const *supplies;
unsigned int num_supplies;
bool external_ref_only;
+ bool adaq_internal_ref_only;
const char * const *vcm_supplies;
unsigned int num_vcm_supplies;
const unsigned long *available_scan_masks;
@@ -181,11 +197,12 @@ static const struct iio_scan_type ad7380_scan_type_16_u[] = {
},
};
-#define AD7380_CHANNEL(index, bits, diff, sign) { \
+#define _AD7380_CHANNEL(index, bits, diff, sign, gain) { \
.type = IIO_VOLTAGE, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ ((gain) ? BIT(IIO_CHAN_INFO_SCALE) : 0) | \
((diff) ? 0 : BIT(IIO_CHAN_INFO_OFFSET)), \
- .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ .info_mask_shared_by_type = ((gain) ? 0 : BIT(IIO_CHAN_INFO_SCALE)) | \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.info_mask_shared_by_type_available = \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
@@ -199,6 +216,12 @@ static const struct iio_scan_type ad7380_scan_type_16_u[] = {
.num_ext_scan_type = ARRAY_SIZE(ad7380_scan_type_##bits##_##sign), \
}
+#define AD7380_CHANNEL(index, bits, diff, sign) \
+ _AD7380_CHANNEL(index, bits, diff, sign, false)
+
+#define ADAQ4380_CHANNEL(index, bits, diff, sign) \
+ _AD7380_CHANNEL(index, bits, diff, sign, true)
+
#define DEFINE_AD7380_2_CHANNEL(name, bits, diff, sign) \
static const struct iio_chan_spec name[] = { \
AD7380_CHANNEL(0, bits, diff, sign), \
@@ -215,6 +238,15 @@ static const struct iio_chan_spec name[] = { \
IIO_CHAN_SOFT_TIMESTAMP(4), \
}
+#define DEFINE_ADAQ4380_4_CHANNEL(name, bits, diff, sign) \
+static const struct iio_chan_spec name[] = { \
+ ADAQ4380_CHANNEL(0, bits, diff, sign), \
+ ADAQ4380_CHANNEL(1, bits, diff, sign), \
+ ADAQ4380_CHANNEL(2, bits, diff, sign), \
+ ADAQ4380_CHANNEL(3, bits, diff, sign), \
+ IIO_CHAN_SOFT_TIMESTAMP(4), \
+}
+
#define DEFINE_AD7380_8_CHANNEL(name, bits, diff, sign) \
static const struct iio_chan_spec name[] = { \
AD7380_CHANNEL(0, bits, diff, sign), \
@@ -233,6 +265,7 @@ DEFINE_AD7380_2_CHANNEL(ad7380_channels, 16, 1, s);
DEFINE_AD7380_2_CHANNEL(ad7381_channels, 14, 1, s);
DEFINE_AD7380_4_CHANNEL(ad7380_4_channels, 16, 1, s);
DEFINE_AD7380_4_CHANNEL(ad7381_4_channels, 14, 1, s);
+DEFINE_ADAQ4380_4_CHANNEL(adaq4380_4_channels, 16, 1, s);
/* pseudo differential */
DEFINE_AD7380_2_CHANNEL(ad7383_channels, 16, 0, s);
DEFINE_AD7380_2_CHANNEL(ad7384_channels, 14, 0, s);
@@ -251,6 +284,10 @@ static const char * const ad7380_supplies[] = {
"vcc", "vlogic",
};
+static const char * const adaq4380_supplies[] = {
+ "ldo", "vcc", "vlogic", "vs-p", "vs-n", "refin",
+};
+
static const char * const ad7380_2_channel_vcm_supplies[] = {
"aina", "ainb",
};
@@ -341,6 +378,11 @@ static const int ad7380_oversampling_ratios[] = {
1, 2, 4, 8, 16, 32,
};
+/* Gains stored as fractions of 1000 so they can be expressed by integers. */
+static const int ad7380_gains[] = {
+ 300, 600, 1000, 1600,
+};
+
static const struct ad7380_chip_info ad7380_chip_info = {
.name = "ad7380",
.channels = ad7380_channels,
@@ -510,6 +552,32 @@ static const struct ad7380_chip_info ad7388_4_chip_info = {
.timing_specs = &ad7380_4_timing,
};
+static const struct ad7380_chip_info adaq4370_4_chip_info = {
+ .name = "adaq4370-4",
+ .channels = adaq4380_4_channels,
+ .num_channels = ARRAY_SIZE(adaq4380_4_channels),
+ .num_simult_channels = 4,
+ .supplies = adaq4380_supplies,
+ .num_supplies = ARRAY_SIZE(adaq4380_supplies),
+ .adaq_internal_ref_only = true,
+ .has_hardware_gain = true,
+ .available_scan_masks = ad7380_4_channel_scan_masks,
+ .timing_specs = &ad7380_4_timing,
+};
+
+static const struct ad7380_chip_info adaq4380_4_chip_info = {
+ .name = "adaq4380-4",
+ .channels = adaq4380_4_channels,
+ .num_channels = ARRAY_SIZE(adaq4380_4_channels),
+ .num_simult_channels = 4,
+ .supplies = adaq4380_supplies,
+ .num_supplies = ARRAY_SIZE(adaq4380_supplies),
+ .adaq_internal_ref_only = true,
+ .has_hardware_gain = true,
+ .available_scan_masks = ad7380_4_channel_scan_masks,
+ .timing_specs = &ad7380_4_timing,
+};
+
struct ad7380_state {
const struct ad7380_chip_info *chip_info;
struct spi_device *spi;
@@ -520,6 +588,7 @@ struct ad7380_state {
bool seq;
unsigned int vref_mv;
unsigned int vcm_mv[MAX_NUM_CHANNELS];
+ unsigned int gain_milli[MAX_NUM_CHANNELS];
/* xfers, message an buffer for reading sample data */
struct spi_transfer normal_xfer[2];
struct spi_message normal_msg;
@@ -649,7 +718,8 @@ static int ad7380_set_ch(struct ad7380_state *st, unsigned int ch)
if (st->oversampling_ratio > 1)
xfer.delay.value = T_CONVERT_0_NS +
- T_CONVERT_X_NS * (st->oversampling_ratio - 1);
+ T_CONVERT_X_NS * (st->oversampling_ratio - 1) *
+ st->chip_info->num_simult_channels / AD7380_NUM_SDO_LINES;
return spi_sync_transfer(st->spi, &xfer, 1);
}
@@ -672,7 +742,8 @@ static void ad7380_update_xfers(struct ad7380_state *st,
*/
if (st->oversampling_ratio > 1)
t_convert = T_CONVERT_0_NS + T_CONVERT_X_NS *
- (st->oversampling_ratio - 1);
+ (st->oversampling_ratio - 1) *
+ st->chip_info->num_simult_channels / AD7380_NUM_SDO_LINES;
if (st->seq) {
xfer[0].delay.value = xfer[1].delay.value = t_convert;
@@ -868,8 +939,15 @@ static int ad7380_read_raw(struct iio_dev *indio_dev,
* * (2 × VREF) / 2^N, for differential chips
* * VREF / 2^N, for pseudo-differential chips
* where N is the ADC resolution (i.e realbits)
+ *
+ * The gain is stored as a fraction of 1000 and, as we need to
+ * divide vref_mv by the gain, we invert the gain/1000 fraction.
*/
- *val = st->vref_mv;
+ if (st->chip_info->has_hardware_gain)
+ *val = mult_frac(st->vref_mv, MILLI,
+ st->gain_milli[chan->scan_index]);
+ else
+ *val = st->vref_mv;
*val2 = scan_type->realbits - chan->differential;
return IIO_VAL_FRACTIONAL_LOG2;
@@ -1021,17 +1099,19 @@ static int ad7380_init(struct ad7380_state *st, bool external_ref_en)
/* SPI 1-wire mode */
return regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG2,
AD7380_CONFIG2_SDO,
- FIELD_PREP(AD7380_CONFIG2_SDO, 1));
+ FIELD_PREP(AD7380_CONFIG2_SDO,
+ AD7380_NUM_SDO_LINES));
}
static int ad7380_probe(struct spi_device *spi)
{
+ struct device *dev = &spi->dev;
struct iio_dev *indio_dev;
struct ad7380_state *st;
bool external_ref_en;
int ret, i;
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
@@ -1039,21 +1119,32 @@ static int ad7380_probe(struct spi_device *spi)
st->spi = spi;
st->chip_info = spi_get_device_match_data(spi);
if (!st->chip_info)
- return dev_err_probe(&spi->dev, -EINVAL, "missing match data\n");
+ return dev_err_probe(dev, -EINVAL, "missing match data\n");
- ret = devm_regulator_bulk_get_enable(&spi->dev, st->chip_info->num_supplies,
+ ret = devm_regulator_bulk_get_enable(dev, st->chip_info->num_supplies,
st->chip_info->supplies);
if (ret)
- return dev_err_probe(&spi->dev, ret,
+ return dev_err_probe(dev, ret,
"Failed to enable power supplies\n");
fsleep(T_POWERUP_US);
- if (st->chip_info->external_ref_only) {
- ret = devm_regulator_get_enable_read_voltage(&spi->dev,
- "refin");
+ if (st->chip_info->adaq_internal_ref_only) {
+ /*
+ * ADAQ chips use fixed internal reference but still
+ * require a specific reference supply to power it.
+ * "refin" is already enabled with other power supplies
+ * in bulk_get_enable().
+ */
+
+ st->vref_mv = ADAQ4380_INTERNAL_REF_MV;
+
+ /* these chips don't have a register bit for this */
+ external_ref_en = false;
+ } else if (st->chip_info->external_ref_only) {
+ ret = devm_regulator_get_enable_read_voltage(dev, "refin");
if (ret < 0)
- return dev_err_probe(&spi->dev, ret,
+ return dev_err_probe(dev, ret,
"Failed to get refin regulator\n");
st->vref_mv = ret / 1000;
@@ -1065,10 +1156,9 @@ static int ad7380_probe(struct spi_device *spi)
* If there is no REFIO supply, then it means that we are using
* the internal reference, otherwise REFIO is reference voltage.
*/
- ret = devm_regulator_get_enable_read_voltage(&spi->dev,
- "refio");
+ ret = devm_regulator_get_enable_read_voltage(dev, "refio");
if (ret < 0 && ret != -ENODEV)
- return dev_err_probe(&spi->dev, ret,
+ return dev_err_probe(dev, ret,
"Failed to get refio regulator\n");
external_ref_en = ret != -ENODEV;
@@ -1076,7 +1166,7 @@ static int ad7380_probe(struct spi_device *spi)
}
if (st->chip_info->num_vcm_supplies > ARRAY_SIZE(st->vcm_mv))
- return dev_err_probe(&spi->dev, -EINVAL,
+ return dev_err_probe(dev, -EINVAL,
"invalid number of VCM supplies\n");
/*
@@ -1086,18 +1176,54 @@ static int ad7380_probe(struct spi_device *spi)
for (i = 0; i < st->chip_info->num_vcm_supplies; i++) {
const char *vcm = st->chip_info->vcm_supplies[i];
- ret = devm_regulator_get_enable_read_voltage(&spi->dev, vcm);
+ ret = devm_regulator_get_enable_read_voltage(dev, vcm);
if (ret < 0)
- return dev_err_probe(&spi->dev, ret,
+ return dev_err_probe(dev, ret,
"Failed to get %s regulator\n",
vcm);
st->vcm_mv[i] = ret / 1000;
}
- st->regmap = devm_regmap_init(&spi->dev, NULL, st, &ad7380_regmap_config);
+ for (i = 0; i < MAX_NUM_CHANNELS; i++)
+ st->gain_milli[i] = AD7380_DEFAULT_GAIN_MILLI;
+
+ if (st->chip_info->has_hardware_gain) {
+ device_for_each_child_node_scoped(dev, node) {
+ unsigned int channel, gain;
+ int gain_idx;
+
+ ret = fwnode_property_read_u32(node, "reg", &channel);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to read reg property\n");
+
+ if (channel >= st->chip_info->num_channels - 1)
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid channel number %i\n",
+ channel);
+
+ ret = fwnode_property_read_u32(node, "adi,gain-milli",
+ &gain);
+ if (ret && ret != -EINVAL)
+ return dev_err_probe(dev, ret,
+ "Failed to read gain for channel %i\n",
+ channel);
+ if (ret != -EINVAL) {
+ /*
+ * Match gain value from dt to one of supported
+ * gains
+ */
+ gain_idx = find_closest(gain, ad7380_gains,
+ ARRAY_SIZE(ad7380_gains));
+ st->gain_milli[channel] = ad7380_gains[gain_idx];
+ }
+ }
+ }
+
+ st->regmap = devm_regmap_init(dev, NULL, st, &ad7380_regmap_config);
if (IS_ERR(st->regmap))
- return dev_err_probe(&spi->dev, PTR_ERR(st->regmap),
+ return dev_err_probe(dev, PTR_ERR(st->regmap),
"failed to allocate register map\n");
/*
@@ -1148,7 +1274,7 @@ static int ad7380_probe(struct spi_device *spi)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->available_scan_masks = st->chip_info->available_scan_masks;
- ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
iio_pollfunc_store_time,
ad7380_trigger_handler,
&ad7380_buffer_setup_ops);
@@ -1159,7 +1285,7 @@ static int ad7380_probe(struct spi_device *spi)
if (ret)
return ret;
- return devm_iio_device_register(&spi->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct of_device_id ad7380_of_match_table[] = {
@@ -1177,6 +1303,8 @@ static const struct of_device_id ad7380_of_match_table[] = {
{ .compatible = "adi,ad7386-4", .data = &ad7386_4_chip_info },
{ .compatible = "adi,ad7387-4", .data = &ad7387_4_chip_info },
{ .compatible = "adi,ad7388-4", .data = &ad7388_4_chip_info },
+ { .compatible = "adi,adaq4370-4", .data = &adaq4370_4_chip_info },
+ { .compatible = "adi,adaq4380-4", .data = &adaq4380_4_chip_info },
{ }
};
@@ -1195,6 +1323,8 @@ static const struct spi_device_id ad7380_id_table[] = {
{ "ad7386-4", (kernel_ulong_t)&ad7386_4_chip_info },
{ "ad7387-4", (kernel_ulong_t)&ad7387_4_chip_info },
{ "ad7388-4", (kernel_ulong_t)&ad7388_4_chip_info },
+ { "adaq4370-4", (kernel_ulong_t)&adaq4370_4_chip_info },
+ { "adaq4380-4", (kernel_ulong_t)&adaq4380_4_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7380_id_table);
diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c
index 71362eafe838..8b2046baaa3e 100644
--- a/drivers/iio/adc/ad7606.c
+++ b/drivers/iio/adc/ad7606.c
@@ -13,12 +13,15 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/property.h>
+#include <linux/pwm.h>
#include <linux/regulator/consumer.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
+#include <linux/units.h>
#include <linux/util_macros.h>
+#include <linux/iio/backend.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -30,42 +33,52 @@
/*
* Scales are computed as 5000/32768 and 10000/32768 respectively,
- * so that when applied to the raw values they provide mV values
+ * so that when applied to the raw values they provide mV values.
+ * The scale arrays are kept as IIO_VAL_INT_PLUS_MICRO, so index
+ * X is the integer part and X + 1 is the fractional part.
*/
-static const unsigned int ad7606_16bit_hw_scale_avail[2] = {
- 152588, 305176
+static const unsigned int ad7606_16bit_hw_scale_avail[2][2] = {
+ { 0, 152588 }, { 0, 305176 }
};
-static const unsigned int ad7606_18bit_hw_scale_avail[2] = {
- 38147, 76294
+static const unsigned int ad7606_18bit_hw_scale_avail[2][2] = {
+ { 0, 38147 }, { 0, 76294 }
};
-static const unsigned int ad7606c_16bit_single_ended_unipolar_scale_avail[3] = {
- 76294, 152588, 190735,
+static const unsigned int ad7606c_16bit_single_ended_unipolar_scale_avail[3][2] = {
+ { 0, 76294 }, { 0, 152588 }, { 0, 190735 }
};
-static const unsigned int ad7606c_16bit_single_ended_bipolar_scale_avail[5] = {
- 76294, 152588, 190735, 305176, 381470
+static const unsigned int ad7606c_16bit_single_ended_bipolar_scale_avail[5][2] = {
+ { 0, 76294 }, { 0, 152588 }, { 0, 190735 }, { 0, 305176 }, { 0, 381470 }
};
-static const unsigned int ad7606c_16bit_differential_bipolar_scale_avail[4] = {
- 152588, 305176, 381470, 610352
+static const unsigned int ad7606c_16bit_differential_bipolar_scale_avail[4][2] = {
+ { 0, 152588 }, { 0, 305176 }, { 0, 381470 }, { 0, 610352 }
};
-static const unsigned int ad7606c_18bit_single_ended_unipolar_scale_avail[3] = {
- 19073, 38147, 47684
+static const unsigned int ad7606c_18bit_single_ended_unipolar_scale_avail[3][2] = {
+ { 0, 19073 }, { 0, 38147 }, { 0, 47684 }
};
-static const unsigned int ad7606c_18bit_single_ended_bipolar_scale_avail[5] = {
- 19073, 38147, 47684, 76294, 95367
+static const unsigned int ad7606c_18bit_single_ended_bipolar_scale_avail[5][2] = {
+ { 0, 19073 }, { 0, 38147 }, { 0, 47684 }, { 0, 76294 }, { 0, 95367 }
};
-static const unsigned int ad7606c_18bit_differential_bipolar_scale_avail[4] = {
- 38147, 76294, 95367, 152588
+static const unsigned int ad7606c_18bit_differential_bipolar_scale_avail[4][2] = {
+ { 0, 38147 }, { 0, 76294 }, { 0, 95367 }, { 0, 152588 }
};
-static const unsigned int ad7606_16bit_sw_scale_avail[3] = {
- 76293, 152588, 305176
+static const unsigned int ad7606_16bit_sw_scale_avail[3][2] = {
+ { 0, 76293 }, { 0, 152588 }, { 0, 305176 }
+};
+
+static const unsigned int ad7607_hw_scale_avail[2][2] = {
+ { 0, 610352 }, { 1, 220703 }
+};
+
+static const unsigned int ad7609_hw_scale_avail[2][2] = {
+ { 0, 152588 }, { 0, 305176 }
};
static const unsigned int ad7606_oversampling_avail[7] = {
@@ -76,6 +89,227 @@ static const unsigned int ad7616_oversampling_avail[8] = {
1, 2, 4, 8, 16, 32, 64, 128,
};
+static const struct iio_chan_spec ad7605_channels[] = {
+ IIO_CHAN_SOFT_TIMESTAMP(4),
+ AD7605_CHANNEL(0),
+ AD7605_CHANNEL(1),
+ AD7605_CHANNEL(2),
+ AD7605_CHANNEL(3),
+};
+
+static const struct iio_chan_spec ad7606_channels_16bit[] = {
+ IIO_CHAN_SOFT_TIMESTAMP(8),
+ AD7606_CHANNEL(0, 16),
+ AD7606_CHANNEL(1, 16),
+ AD7606_CHANNEL(2, 16),
+ AD7606_CHANNEL(3, 16),
+ AD7606_CHANNEL(4, 16),
+ AD7606_CHANNEL(5, 16),
+ AD7606_CHANNEL(6, 16),
+ AD7606_CHANNEL(7, 16),
+};
+
+static const struct iio_chan_spec ad7606_channels_18bit[] = {
+ IIO_CHAN_SOFT_TIMESTAMP(8),
+ AD7606_CHANNEL(0, 18),
+ AD7606_CHANNEL(1, 18),
+ AD7606_CHANNEL(2, 18),
+ AD7606_CHANNEL(3, 18),
+ AD7606_CHANNEL(4, 18),
+ AD7606_CHANNEL(5, 18),
+ AD7606_CHANNEL(6, 18),
+ AD7606_CHANNEL(7, 18),
+};
+
+static const struct iio_chan_spec ad7607_channels[] = {
+ IIO_CHAN_SOFT_TIMESTAMP(8),
+ AD7606_CHANNEL(0, 14),
+ AD7606_CHANNEL(1, 14),
+ AD7606_CHANNEL(2, 14),
+ AD7606_CHANNEL(3, 14),
+ AD7606_CHANNEL(4, 14),
+ AD7606_CHANNEL(5, 14),
+ AD7606_CHANNEL(6, 14),
+ AD7606_CHANNEL(7, 14),
+};
+
+static const struct iio_chan_spec ad7608_channels[] = {
+ IIO_CHAN_SOFT_TIMESTAMP(8),
+ AD7606_CHANNEL(0, 18),
+ AD7606_CHANNEL(1, 18),
+ AD7606_CHANNEL(2, 18),
+ AD7606_CHANNEL(3, 18),
+ AD7606_CHANNEL(4, 18),
+ AD7606_CHANNEL(5, 18),
+ AD7606_CHANNEL(6, 18),
+ AD7606_CHANNEL(7, 18),
+};
+
+/*
+ * The current assumption that this driver makes for AD7616, is that it's
+ * working in Hardware Mode with Serial, Burst and Sequencer modes activated.
+ * To activate them, following pins must be pulled high:
+ * -SER/PAR
+ * -SEQEN
+ * And following pins must be pulled low:
+ * -WR/BURST
+ * -DB4/SER1W
+ */
+static const struct iio_chan_spec ad7616_channels[] = {
+ IIO_CHAN_SOFT_TIMESTAMP(16),
+ AD7606_CHANNEL(0, 16),
+ AD7606_CHANNEL(1, 16),
+ AD7606_CHANNEL(2, 16),
+ AD7606_CHANNEL(3, 16),
+ AD7606_CHANNEL(4, 16),
+ AD7606_CHANNEL(5, 16),
+ AD7606_CHANNEL(6, 16),
+ AD7606_CHANNEL(7, 16),
+ AD7606_CHANNEL(8, 16),
+ AD7606_CHANNEL(9, 16),
+ AD7606_CHANNEL(10, 16),
+ AD7606_CHANNEL(11, 16),
+ AD7606_CHANNEL(12, 16),
+ AD7606_CHANNEL(13, 16),
+ AD7606_CHANNEL(14, 16),
+ AD7606_CHANNEL(15, 16),
+};
+
+static int ad7606c_18bit_chan_scale_setup(struct ad7606_state *st,
+ struct iio_chan_spec *chan, int ch);
+static int ad7606c_16bit_chan_scale_setup(struct ad7606_state *st,
+ struct iio_chan_spec *chan, int ch);
+static int ad7606_16bit_chan_scale_setup(struct ad7606_state *st,
+ struct iio_chan_spec *chan, int ch);
+static int ad7607_chan_scale_setup(struct ad7606_state *st,
+ struct iio_chan_spec *chan, int ch);
+static int ad7608_chan_scale_setup(struct ad7606_state *st,
+ struct iio_chan_spec *chan, int ch);
+static int ad7609_chan_scale_setup(struct ad7606_state *st,
+ struct iio_chan_spec *chan, int ch);
+
+const struct ad7606_chip_info ad7605_4_info = {
+ .channels = ad7605_channels,
+ .name = "ad7605-4",
+ .num_adc_channels = 4,
+ .num_channels = 5,
+ .scale_setup_cb = ad7606_16bit_chan_scale_setup,
+};
+EXPORT_SYMBOL_NS_GPL(ad7605_4_info, IIO_AD7606);
+
+const struct ad7606_chip_info ad7606_8_info = {
+ .channels = ad7606_channels_16bit,
+ .name = "ad7606-8",
+ .num_adc_channels = 8,
+ .num_channels = 9,
+ .oversampling_avail = ad7606_oversampling_avail,
+ .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
+ .scale_setup_cb = ad7606_16bit_chan_scale_setup,
+};
+EXPORT_SYMBOL_NS_GPL(ad7606_8_info, IIO_AD7606);
+
+const struct ad7606_chip_info ad7606_6_info = {
+ .channels = ad7606_channels_16bit,
+ .name = "ad7606-6",
+ .num_adc_channels = 6,
+ .num_channels = 7,
+ .oversampling_avail = ad7606_oversampling_avail,
+ .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
+ .scale_setup_cb = ad7606_16bit_chan_scale_setup,
+};
+EXPORT_SYMBOL_NS_GPL(ad7606_6_info, IIO_AD7606);
+
+const struct ad7606_chip_info ad7606_4_info = {
+ .channels = ad7606_channels_16bit,
+ .name = "ad7606-4",
+ .num_adc_channels = 4,
+ .num_channels = 5,
+ .oversampling_avail = ad7606_oversampling_avail,
+ .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
+ .scale_setup_cb = ad7606_16bit_chan_scale_setup,
+};
+EXPORT_SYMBOL_NS_GPL(ad7606_4_info, IIO_AD7606);
+
+const struct ad7606_chip_info ad7606b_info = {
+ .channels = ad7606_channels_16bit,
+ .max_samplerate = 800 * KILO,
+ .name = "ad7606b",
+ .num_adc_channels = 8,
+ .num_channels = 9,
+ .oversampling_avail = ad7606_oversampling_avail,
+ .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
+ .scale_setup_cb = ad7606_16bit_chan_scale_setup,
+};
+EXPORT_SYMBOL_NS_GPL(ad7606b_info, IIO_AD7606);
+
+const struct ad7606_chip_info ad7606c_16_info = {
+ .channels = ad7606_channels_16bit,
+ .name = "ad7606c16",
+ .num_adc_channels = 8,
+ .num_channels = 9,
+ .oversampling_avail = ad7606_oversampling_avail,
+ .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
+ .scale_setup_cb = ad7606c_16bit_chan_scale_setup,
+};
+EXPORT_SYMBOL_NS_GPL(ad7606c_16_info, IIO_AD7606);
+
+const struct ad7606_chip_info ad7607_info = {
+ .channels = ad7607_channels,
+ .name = "ad7607",
+ .num_adc_channels = 8,
+ .num_channels = 9,
+ .oversampling_avail = ad7606_oversampling_avail,
+ .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
+ .scale_setup_cb = ad7607_chan_scale_setup,
+};
+EXPORT_SYMBOL_NS_GPL(ad7607_info, IIO_AD7606);
+
+const struct ad7606_chip_info ad7608_info = {
+ .channels = ad7608_channels,
+ .name = "ad7608",
+ .num_adc_channels = 8,
+ .num_channels = 9,
+ .oversampling_avail = ad7606_oversampling_avail,
+ .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
+ .scale_setup_cb = ad7608_chan_scale_setup,
+};
+EXPORT_SYMBOL_NS_GPL(ad7608_info, IIO_AD7606);
+
+const struct ad7606_chip_info ad7609_info = {
+ .channels = ad7608_channels,
+ .name = "ad7609",
+ .num_adc_channels = 8,
+ .num_channels = 9,
+ .oversampling_avail = ad7606_oversampling_avail,
+ .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
+ .scale_setup_cb = ad7609_chan_scale_setup,
+};
+EXPORT_SYMBOL_NS_GPL(ad7609_info, IIO_AD7606);
+
+const struct ad7606_chip_info ad7606c_18_info = {
+ .channels = ad7606_channels_18bit,
+ .name = "ad7606c18",
+ .num_adc_channels = 8,
+ .num_channels = 9,
+ .oversampling_avail = ad7606_oversampling_avail,
+ .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
+ .scale_setup_cb = ad7606c_18bit_chan_scale_setup,
+};
+EXPORT_SYMBOL_NS_GPL(ad7606c_18_info, IIO_AD7606);
+
+const struct ad7606_chip_info ad7616_info = {
+ .channels = ad7616_channels,
+ .init_delay_ms = 15,
+ .name = "ad7616",
+ .num_adc_channels = 16,
+ .num_channels = 17,
+ .oversampling_avail = ad7616_oversampling_avail,
+ .oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail),
+ .os_req_reset = true,
+ .scale_setup_cb = ad7606_16bit_chan_scale_setup,
+};
+EXPORT_SYMBOL_NS_GPL(ad7616_info, IIO_AD7606);
+
int ad7606_reset(struct ad7606_state *st)
{
if (st->gpio_reset) {
@@ -278,6 +512,39 @@ static int ad7606c_16bit_chan_scale_setup(struct ad7606_state *st,
return 0;
}
+static int ad7607_chan_scale_setup(struct ad7606_state *st,
+ struct iio_chan_spec *chan, int ch)
+{
+ struct ad7606_chan_scale *cs = &st->chan_scales[ch];
+
+ cs->range = 0;
+ cs->scale_avail = ad7607_hw_scale_avail;
+ cs->num_scales = ARRAY_SIZE(ad7607_hw_scale_avail);
+ return 0;
+}
+
+static int ad7608_chan_scale_setup(struct ad7606_state *st,
+ struct iio_chan_spec *chan, int ch)
+{
+ struct ad7606_chan_scale *cs = &st->chan_scales[ch];
+
+ cs->range = 0;
+ cs->scale_avail = ad7606_18bit_hw_scale_avail;
+ cs->num_scales = ARRAY_SIZE(ad7606_18bit_hw_scale_avail);
+ return 0;
+}
+
+static int ad7609_chan_scale_setup(struct ad7606_state *st,
+ struct iio_chan_spec *chan, int ch)
+{
+ struct ad7606_chan_scale *cs = &st->chan_scales[ch];
+
+ cs->range = 0;
+ cs->scale_avail = ad7609_hw_scale_avail;
+ cs->num_scales = ARRAY_SIZE(ad7609_hw_scale_avail);
+ return 0;
+}
+
static int ad7606_reg_access(struct iio_dev *indio_dev,
unsigned int reg,
unsigned int writeval,
@@ -299,9 +566,83 @@ static int ad7606_reg_access(struct iio_dev *indio_dev,
}
}
+static int ad7606_pwm_set_high(struct ad7606_state *st)
+{
+ struct pwm_state cnvst_pwm_state;
+ int ret;
+
+ pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
+ cnvst_pwm_state.enabled = true;
+ cnvst_pwm_state.duty_cycle = cnvst_pwm_state.period;
+
+ ret = pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state);
+
+ return ret;
+}
+
+static int ad7606_pwm_set_low(struct ad7606_state *st)
+{
+ struct pwm_state cnvst_pwm_state;
+ int ret;
+
+ pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
+ cnvst_pwm_state.enabled = true;
+ cnvst_pwm_state.duty_cycle = 0;
+
+ ret = pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state);
+
+ return ret;
+}
+
+static int ad7606_pwm_set_swing(struct ad7606_state *st)
+{
+ struct pwm_state cnvst_pwm_state;
+
+ pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
+ cnvst_pwm_state.enabled = true;
+ cnvst_pwm_state.duty_cycle = cnvst_pwm_state.period / 2;
+
+ return pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state);
+}
+
+static bool ad7606_pwm_is_swinging(struct ad7606_state *st)
+{
+ struct pwm_state cnvst_pwm_state;
+
+ pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
+
+ return cnvst_pwm_state.duty_cycle != cnvst_pwm_state.period &&
+ cnvst_pwm_state.duty_cycle != 0;
+}
+
+static int ad7606_set_sampling_freq(struct ad7606_state *st, unsigned long freq)
+{
+ struct pwm_state cnvst_pwm_state;
+ bool is_swinging = ad7606_pwm_is_swinging(st);
+ bool is_high;
+
+ if (freq == 0)
+ return -EINVAL;
+
+ /* Retrieve the previous state. */
+ pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
+ is_high = cnvst_pwm_state.duty_cycle == cnvst_pwm_state.period;
+
+ cnvst_pwm_state.period = DIV_ROUND_UP_ULL(NSEC_PER_SEC, freq);
+ cnvst_pwm_state.polarity = PWM_POLARITY_NORMAL;
+ if (is_high)
+ cnvst_pwm_state.duty_cycle = cnvst_pwm_state.period;
+ else if (is_swinging)
+ cnvst_pwm_state.duty_cycle = cnvst_pwm_state.period / 2;
+ else
+ cnvst_pwm_state.duty_cycle = 0;
+
+ return pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state);
+}
+
static int ad7606_read_samples(struct ad7606_state *st)
{
- unsigned int num = st->chip_info->num_channels - 1;
+ unsigned int num = st->chip_info->num_adc_channels;
return st->bops->read_block(st->dev, num, &st->data);
}
@@ -333,16 +674,33 @@ static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch,
int *val)
{
struct ad7606_state *st = iio_priv(indio_dev);
- unsigned int storagebits = st->chip_info->channels[1].scan_type.storagebits;
+ unsigned int realbits = st->chip_info->channels[1].scan_type.realbits;
const struct iio_chan_spec *chan;
int ret;
- gpiod_set_value(st->gpio_convst, 1);
- ret = wait_for_completion_timeout(&st->completion,
- msecs_to_jiffies(1000));
- if (!ret) {
- ret = -ETIMEDOUT;
- goto error_ret;
+ if (st->gpio_convst) {
+ gpiod_set_value(st->gpio_convst, 1);
+ } else {
+ ret = ad7606_pwm_set_high(st);
+ if (ret < 0)
+ return ret;
+ }
+
+ /*
+ * If no backend, wait for the interruption on busy pin, otherwise just add
+ * a delay to leave time for the data to be available. For now, the latter
+ * will not happen because IIO_CHAN_INFO_RAW is not supported for the backend.
+ * TODO: Add support for reading a single value when the backend is used.
+ */
+ if (!st->back) {
+ ret = wait_for_completion_timeout(&st->completion,
+ msecs_to_jiffies(1000));
+ if (!ret) {
+ ret = -ETIMEDOUT;
+ goto error_ret;
+ }
+ } else {
+ fsleep(1);
}
ret = ad7606_read_samples(st);
@@ -351,18 +709,23 @@ static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch,
chan = &indio_dev->channels[ch + 1];
if (chan->scan_type.sign == 'u') {
- if (storagebits > 16)
+ if (realbits > 16)
*val = st->data.buf32[ch];
else
*val = st->data.buf16[ch];
} else {
- if (storagebits > 16)
- *val = sign_extend32(st->data.buf32[ch], 17);
+ if (realbits > 16)
+ *val = sign_extend32(st->data.buf32[ch], realbits - 1);
else
- *val = sign_extend32(st->data.buf16[ch], 15);
+ *val = sign_extend32(st->data.buf16[ch], realbits - 1);
}
error_ret:
+ if (!st->gpio_convst) {
+ ret = ad7606_pwm_set_low(st);
+ if (ret < 0)
+ return ret;
+ }
gpiod_set_value(st->gpio_convst, 0);
return ret;
@@ -377,6 +740,7 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
int ret, ch = 0;
struct ad7606_state *st = iio_priv(indio_dev);
struct ad7606_chan_scale *cs;
+ struct pwm_state cnvst_pwm_state;
switch (m) {
case IIO_CHAN_INFO_RAW:
@@ -391,31 +755,24 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
if (st->sw_mode_en)
ch = chan->address;
cs = &st->chan_scales[ch];
- *val = 0;
- *val2 = cs->scale_avail[cs->range];
+ *val = cs->scale_avail[cs->range][0];
+ *val2 = cs->scale_avail[cs->range][1];
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
*val = st->oversampling;
return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ /*
+ * TODO: return the real frequency intead of the requested one once
+ * pwm_get_state_hw comes upstream.
+ */
+ pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
+ *val = DIV_ROUND_CLOSEST_ULL(NSEC_PER_SEC, cnvst_pwm_state.period);
+ return IIO_VAL_INT;
}
return -EINVAL;
}
-static ssize_t ad7606_show_avail(char *buf, const unsigned int *vals,
- unsigned int n, bool micros)
-{
- size_t len = 0;
- int i;
-
- for (i = 0; i < n; i++) {
- len += scnprintf(buf + len, PAGE_SIZE - len,
- micros ? "0.%06u " : "%u ", vals[i]);
- }
- buf[len - 1] = '\n';
-
- return len;
-}
-
static ssize_t in_voltage_scale_available_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -423,8 +780,16 @@ static ssize_t in_voltage_scale_available_show(struct device *dev,
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7606_state *st = iio_priv(indio_dev);
struct ad7606_chan_scale *cs = &st->chan_scales[0];
+ const unsigned int (*vals)[2] = cs->scale_avail;
+ unsigned int i;
+ size_t len = 0;
- return ad7606_show_avail(buf, cs->scale_avail, cs->num_scales, true);
+ for (i = 0; i < cs->num_scales; i++)
+ len += scnprintf(buf + len, PAGE_SIZE - len, "%u.%06u ",
+ vals[i][0], vals[i][1]);
+ buf[len - 1] = '\n';
+
+ return len;
}
static IIO_DEVICE_ATTR_RO(in_voltage_scale_available, 0);
@@ -462,6 +827,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
long mask)
{
struct ad7606_state *st = iio_priv(indio_dev);
+ unsigned int scale_avail_uv[AD760X_MAX_SCALES];
struct ad7606_chan_scale *cs;
int i, ret, ch = 0;
@@ -472,7 +838,12 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
if (st->sw_mode_en)
ch = chan->address;
cs = &st->chan_scales[ch];
- i = find_closest(val2, cs->scale_avail, cs->num_scales);
+ for (i = 0; i < cs->num_scales; i++) {
+ scale_avail_uv[i] = cs->scale_avail[i][0] * MICRO +
+ cs->scale_avail[i][1];
+ }
+ val = (val * MICRO) + val2;
+ i = find_closest(val, scale_avail_uv, cs->num_scales);
ret = st->write_scale(indio_dev, ch, i + cs->reg_offset);
if (ret < 0)
return ret;
@@ -487,8 +858,13 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
ret = st->write_os(indio_dev, i);
if (ret < 0)
return ret;
+ st->oversampling = st->oversampling_avail[i];
return 0;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ if (val < 0 && val2 != 0)
+ return -EINVAL;
+ return ad7606_set_sampling_freq(st, val);
default:
return -EINVAL;
}
@@ -500,9 +876,15 @@ static ssize_t ad7606_oversampling_ratio_avail(struct device *dev,
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7606_state *st = iio_priv(indio_dev);
+ const unsigned int *vals = st->oversampling_avail;
+ unsigned int i;
+ size_t len = 0;
- return ad7606_show_avail(buf, st->oversampling_avail,
- st->num_os_ratios, false);
+ for (i = 0; i < st->num_os_ratios; i++)
+ len += scnprintf(buf + len, PAGE_SIZE - len, "%u ", vals[i]);
+ buf[len - 1] = '\n';
+
+ return len;
}
static IIO_DEVICE_ATTR(oversampling_ratio_available, 0444,
@@ -536,134 +918,13 @@ static const struct attribute_group ad7606_attribute_group_range = {
.attrs = ad7606_attributes_range,
};
-static const struct iio_chan_spec ad7605_channels[] = {
- IIO_CHAN_SOFT_TIMESTAMP(4),
- AD7605_CHANNEL(0),
- AD7605_CHANNEL(1),
- AD7605_CHANNEL(2),
- AD7605_CHANNEL(3),
-};
-
-static const struct iio_chan_spec ad7606_channels_16bit[] = {
- IIO_CHAN_SOFT_TIMESTAMP(8),
- AD7606_CHANNEL(0, 16),
- AD7606_CHANNEL(1, 16),
- AD7606_CHANNEL(2, 16),
- AD7606_CHANNEL(3, 16),
- AD7606_CHANNEL(4, 16),
- AD7606_CHANNEL(5, 16),
- AD7606_CHANNEL(6, 16),
- AD7606_CHANNEL(7, 16),
-};
-
-static const struct iio_chan_spec ad7606_channels_18bit[] = {
- IIO_CHAN_SOFT_TIMESTAMP(8),
- AD7606_CHANNEL(0, 18),
- AD7606_CHANNEL(1, 18),
- AD7606_CHANNEL(2, 18),
- AD7606_CHANNEL(3, 18),
- AD7606_CHANNEL(4, 18),
- AD7606_CHANNEL(5, 18),
- AD7606_CHANNEL(6, 18),
- AD7606_CHANNEL(7, 18),
-};
-
-/*
- * The current assumption that this driver makes for AD7616, is that it's
- * working in Hardware Mode with Serial, Burst and Sequencer modes activated.
- * To activate them, following pins must be pulled high:
- * -SER/PAR
- * -SEQEN
- * And following pins must be pulled low:
- * -WR/BURST
- * -DB4/SER1W
- */
-static const struct iio_chan_spec ad7616_channels[] = {
- IIO_CHAN_SOFT_TIMESTAMP(16),
- AD7606_CHANNEL(0, 16),
- AD7606_CHANNEL(1, 16),
- AD7606_CHANNEL(2, 16),
- AD7606_CHANNEL(3, 16),
- AD7606_CHANNEL(4, 16),
- AD7606_CHANNEL(5, 16),
- AD7606_CHANNEL(6, 16),
- AD7606_CHANNEL(7, 16),
- AD7606_CHANNEL(8, 16),
- AD7606_CHANNEL(9, 16),
- AD7606_CHANNEL(10, 16),
- AD7606_CHANNEL(11, 16),
- AD7606_CHANNEL(12, 16),
- AD7606_CHANNEL(13, 16),
- AD7606_CHANNEL(14, 16),
- AD7606_CHANNEL(15, 16),
-};
-
-static const struct ad7606_chip_info ad7606_chip_info_tbl[] = {
- /* More devices added in future */
- [ID_AD7605_4] = {
- .channels = ad7605_channels,
- .num_channels = 5,
- .scale_setup_cb = ad7606_16bit_chan_scale_setup,
- },
- [ID_AD7606_8] = {
- .channels = ad7606_channels_16bit,
- .num_channels = 9,
- .scale_setup_cb = ad7606_16bit_chan_scale_setup,
- .oversampling_avail = ad7606_oversampling_avail,
- .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
- },
- [ID_AD7606_6] = {
- .channels = ad7606_channels_16bit,
- .num_channels = 7,
- .scale_setup_cb = ad7606_16bit_chan_scale_setup,
- .oversampling_avail = ad7606_oversampling_avail,
- .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
- },
- [ID_AD7606_4] = {
- .channels = ad7606_channels_16bit,
- .num_channels = 5,
- .scale_setup_cb = ad7606_16bit_chan_scale_setup,
- .oversampling_avail = ad7606_oversampling_avail,
- .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
- },
- [ID_AD7606B] = {
- .channels = ad7606_channels_16bit,
- .num_channels = 9,
- .scale_setup_cb = ad7606_16bit_chan_scale_setup,
- .oversampling_avail = ad7606_oversampling_avail,
- .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
- },
- [ID_AD7606C_16] = {
- .channels = ad7606_channels_16bit,
- .num_channels = 9,
- .scale_setup_cb = ad7606c_16bit_chan_scale_setup,
- .oversampling_avail = ad7606_oversampling_avail,
- .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
- },
- [ID_AD7606C_18] = {
- .channels = ad7606_channels_18bit,
- .num_channels = 9,
- .scale_setup_cb = ad7606c_18bit_chan_scale_setup,
- .oversampling_avail = ad7606_oversampling_avail,
- .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
- },
- [ID_AD7616] = {
- .channels = ad7616_channels,
- .num_channels = 17,
- .scale_setup_cb = ad7606_16bit_chan_scale_setup,
- .oversampling_avail = ad7616_oversampling_avail,
- .oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail),
- .os_req_reset = true,
- .init_delay_ms = 15,
- },
-};
-
static int ad7606_request_gpios(struct ad7606_state *st)
{
struct device *dev = st->dev;
- st->gpio_convst = devm_gpiod_get(dev, "adi,conversion-start",
- GPIOD_OUT_LOW);
+ st->gpio_convst = devm_gpiod_get_optional(dev, "adi,conversion-start",
+ GPIOD_OUT_LOW);
+
if (IS_ERR(st->gpio_convst))
return PTR_ERR(st->gpio_convst);
@@ -705,14 +966,24 @@ static irqreturn_t ad7606_interrupt(int irq, void *dev_id)
{
struct iio_dev *indio_dev = dev_id;
struct ad7606_state *st = iio_priv(indio_dev);
+ int ret;
if (iio_buffer_enabled(indio_dev)) {
- gpiod_set_value(st->gpio_convst, 0);
+ if (st->gpio_convst) {
+ gpiod_set_value(st->gpio_convst, 0);
+ } else {
+ ret = ad7606_pwm_set_low(st);
+ if (ret < 0) {
+ dev_err(st->dev, "PWM set low failed");
+ goto done;
+ }
+ }
iio_trigger_poll_nested(st->trig);
} else {
complete(&st->completion);
}
+done:
return IRQ_HANDLED;
};
@@ -767,8 +1038,8 @@ static int ad7606_read_avail(struct iio_dev *indio_dev,
ch = chan->address;
cs = &st->chan_scales[ch];
- *vals = cs->scale_avail_show;
- *length = cs->num_scales * 2;
+ *vals = (int *)cs->scale_avail;
+ *length = cs->num_scales;
*type = IIO_VAL_INT_PLUS_MICRO;
return IIO_AVAIL_LIST;
@@ -776,14 +1047,50 @@ static int ad7606_read_avail(struct iio_dev *indio_dev,
return -EINVAL;
}
+static int ad7606_backend_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct ad7606_state *st = iio_priv(indio_dev);
+
+ return ad7606_pwm_set_swing(st);
+}
+
+static int ad7606_backend_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct ad7606_state *st = iio_priv(indio_dev);
+
+ return ad7606_pwm_set_low(st);
+}
+
+static int ad7606_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct ad7606_state *st = iio_priv(indio_dev);
+
+ /*
+ * The update scan mode is only for iio backend compatible drivers.
+ * If the specific update_scan_mode is not defined in the bus ops,
+ * just do nothing and return 0.
+ */
+ if (!st->bops->update_scan_mode)
+ return 0;
+
+ return st->bops->update_scan_mode(indio_dev, scan_mask);
+}
+
static const struct iio_buffer_setup_ops ad7606_buffer_ops = {
.postenable = &ad7606_buffer_postenable,
.predisable = &ad7606_buffer_predisable,
};
+static const struct iio_buffer_setup_ops ad7606_backend_buffer_ops = {
+ .postenable = &ad7606_backend_buffer_postenable,
+ .predisable = &ad7606_backend_buffer_predisable,
+};
+
static const struct iio_info ad7606_info_no_os_or_range = {
.read_raw = &ad7606_read_raw,
.validate_trigger = &ad7606_validate_trigger,
+ .update_scan_mode = &ad7606_update_scan_mode,
};
static const struct iio_info ad7606_info_os_and_range = {
@@ -791,6 +1098,7 @@ static const struct iio_info ad7606_info_os_and_range = {
.write_raw = &ad7606_write_raw,
.attrs = &ad7606_attribute_group_os_and_range,
.validate_trigger = &ad7606_validate_trigger,
+ .update_scan_mode = &ad7606_update_scan_mode,
};
static const struct iio_info ad7606_info_sw_mode = {
@@ -799,6 +1107,7 @@ static const struct iio_info ad7606_info_sw_mode = {
.read_avail = &ad7606_read_avail,
.debugfs_reg_access = &ad7606_reg_access,
.validate_trigger = &ad7606_validate_trigger,
+ .update_scan_mode = &ad7606_update_scan_mode,
};
static const struct iio_info ad7606_info_os = {
@@ -806,6 +1115,7 @@ static const struct iio_info ad7606_info_os = {
.write_raw = &ad7606_write_raw,
.attrs = &ad7606_attribute_group_os,
.validate_trigger = &ad7606_validate_trigger,
+ .update_scan_mode = &ad7606_update_scan_mode,
};
static const struct iio_info ad7606_info_range = {
@@ -813,13 +1123,14 @@ static const struct iio_info ad7606_info_range = {
.write_raw = &ad7606_write_raw,
.attrs = &ad7606_attribute_group_range,
.validate_trigger = &ad7606_validate_trigger,
+ .update_scan_mode = &ad7606_update_scan_mode,
};
static const struct iio_trigger_ops ad7606_trigger_ops = {
.validate_device = iio_trigger_validate_own_device,
};
-static int ad7606_sw_mode_setup(struct iio_dev *indio_dev, unsigned int id)
+static int ad7606_sw_mode_setup(struct iio_dev *indio_dev)
{
struct ad7606_state *st = iio_priv(indio_dev);
@@ -851,31 +1162,21 @@ static int ad7606_chan_scales_setup(struct iio_dev *indio_dev)
indio_dev->channels = chans;
for (ch = 0; ch < num_channels; ch++) {
- struct ad7606_chan_scale *cs;
- int i;
-
ret = st->chip_info->scale_setup_cb(st, &chans[ch + 1], ch);
if (ret)
return ret;
-
- cs = &st->chan_scales[ch];
-
- if (cs->num_scales * 2 > AD760X_MAX_SCALE_SHOW)
- return dev_err_probe(st->dev, -ERANGE,
- "Driver error: scale range too big");
-
- /* Generate a scale_avail list for showing to userspace */
- for (i = 0; i < cs->num_scales; i++) {
- cs->scale_avail_show[i * 2] = 0;
- cs->scale_avail_show[i * 2 + 1] = cs->scale_avail[i];
- }
}
return 0;
}
+static void ad7606_pwm_disable(void *data)
+{
+ pwm_disable(data);
+}
+
int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
- const char *name, unsigned int id,
+ const struct ad7606_chip_info *chip_info,
const struct ad7606_bus_ops *bops)
{
struct ad7606_state *st;
@@ -900,7 +1201,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
return dev_err_probe(dev, ret,
"Failed to enable specified AVcc supply\n");
- st->chip_info = &ad7606_chip_info_tbl[id];
+ st->chip_info = chip_info;
if (st->chip_info->oversampling_num) {
st->oversampling_avail = st->chip_info->oversampling_avail;
@@ -923,12 +1224,10 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
indio_dev->info = &ad7606_info_no_os_or_range;
}
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->name = name;
+ indio_dev->name = chip_info->name;
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
- init_completion(&st->completion);
-
ret = ad7606_reset(st);
if (ret)
dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n");
@@ -942,7 +1241,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
st->write_scale = ad7606_write_scale_hw;
st->write_os = ad7606_write_os_hw;
- ret = ad7606_sw_mode_setup(indio_dev, id);
+ ret = ad7606_sw_mode_setup(indio_dev);
if (ret)
return ret;
@@ -950,34 +1249,82 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
if (ret)
return ret;
- st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
- indio_dev->name,
- iio_device_id(indio_dev));
- if (!st->trig)
- return -ENOMEM;
+ /* If convst pin is not defined, setup PWM. */
+ if (!st->gpio_convst) {
+ st->cnvst_pwm = devm_pwm_get(dev, NULL);
+ if (IS_ERR(st->cnvst_pwm))
+ return PTR_ERR(st->cnvst_pwm);
- st->trig->ops = &ad7606_trigger_ops;
- iio_trigger_set_drvdata(st->trig, indio_dev);
- ret = devm_iio_trigger_register(dev, st->trig);
- if (ret)
- return ret;
+ /* The PWM is initialized at 1MHz to have a fast enough GPIO emulation. */
+ ret = ad7606_set_sampling_freq(st, 1 * MEGA);
+ if (ret)
+ return ret;
- indio_dev->trig = iio_trigger_get(st->trig);
+ ret = ad7606_pwm_set_low(st);
+ if (ret)
+ return ret;
- ret = devm_request_threaded_irq(dev, irq,
- NULL,
- &ad7606_interrupt,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- name, indio_dev);
- if (ret)
- return ret;
+ /*
+ * PWM is not disabled when sampling stops, but instead its duty cycle is set
+ * to 0% to be sure we have a "low" state. After we unload the driver, let's
+ * disable the PWM.
+ */
+ ret = devm_add_action_or_reset(dev, ad7606_pwm_disable,
+ st->cnvst_pwm);
+ if (ret)
+ return ret;
+ }
- ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
- &iio_pollfunc_store_time,
- &ad7606_trigger_handler,
- &ad7606_buffer_ops);
- if (ret)
- return ret;
+ if (st->bops->iio_backend_config) {
+ /*
+ * If there is a backend, the PWM should not overpass the maximum sampling
+ * frequency the chip supports.
+ */
+ ret = ad7606_set_sampling_freq(st,
+ chip_info->max_samplerate ? : 2 * KILO);
+ if (ret)
+ return ret;
+
+ ret = st->bops->iio_backend_config(dev, indio_dev);
+ if (ret)
+ return ret;
+
+ indio_dev->setup_ops = &ad7606_backend_buffer_ops;
+ } else {
+
+ /* Reserve the PWM use only for backend (force gpio_convst definition) */
+ if (!st->gpio_convst)
+ return dev_err_probe(dev, -EINVAL,
+ "No backend, connect convst to a GPIO");
+
+ init_completion(&st->completion);
+ st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
+ indio_dev->name,
+ iio_device_id(indio_dev));
+ if (!st->trig)
+ return -ENOMEM;
+
+ st->trig->ops = &ad7606_trigger_ops;
+ iio_trigger_set_drvdata(st->trig, indio_dev);
+ ret = devm_iio_trigger_register(dev, st->trig);
+ if (ret)
+ return ret;
+
+ indio_dev->trig = iio_trigger_get(st->trig);
+
+ ret = devm_request_threaded_irq(dev, irq, NULL, &ad7606_interrupt,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ chip_info->name, indio_dev);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+ &iio_pollfunc_store_time,
+ &ad7606_trigger_handler,
+ &ad7606_buffer_ops);
+ if (ret)
+ return ret;
+ }
return devm_iio_device_register(dev, indio_dev);
}
diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h
index fc05a4afa3b8..998814a92b82 100644
--- a/drivers/iio/adc/ad7606.h
+++ b/drivers/iio/adc/ad7606.h
@@ -61,6 +61,12 @@
#define AD7616_CHANNEL(num) AD7606_SW_CHANNEL(num, 16)
+#define AD7606_BI_CHANNEL(num) \
+ AD760X_CHANNEL(num, 0, \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), 16)
+
struct ad7606_state;
typedef int (*ad7606_scale_setup_cb_t)(struct ad7606_state *st,
@@ -69,7 +75,10 @@ typedef int (*ad7606_scale_setup_cb_t)(struct ad7606_state *st,
/**
* struct ad7606_chip_info - chip specific information
* @channels: channel specification
+ * @max_samplerate: maximum supported samplerate
+ * @name device name
* @num_channels: number of channels
+ * @num_adc_channels the number of channels the ADC actually inputs.
* @scale_setup_cb: callback to setup the scales for each channel
* @oversampling_avail pointer to the array which stores the available
* oversampling ratios.
@@ -80,6 +89,9 @@ typedef int (*ad7606_scale_setup_cb_t)(struct ad7606_state *st,
*/
struct ad7606_chip_info {
const struct iio_chan_spec *channels;
+ unsigned int max_samplerate;
+ const char *name;
+ unsigned int num_adc_channels;
unsigned int num_channels;
ad7606_scale_setup_cb_t scale_setup_cb;
const unsigned int *oversampling_avail;
@@ -91,8 +103,6 @@ struct ad7606_chip_info {
/**
* struct ad7606_chan_scale - channel scale configuration
* @scale_avail pointer to the array which stores the available scales
- * @scale_avail_show a duplicate of 'scale_avail' which is readily formatted
- * such that it can be read via the 'read_avail' hook
* @num_scales number of elements stored in the scale_avail array
* @range voltage range selection, selects which scale to apply
* @reg_offset offset for the register value, to be applied when
@@ -100,9 +110,7 @@ struct ad7606_chip_info {
*/
struct ad7606_chan_scale {
#define AD760X_MAX_SCALES 16
-#define AD760X_MAX_SCALE_SHOW (AD760X_MAX_SCALES * 2)
- const unsigned int *scale_avail;
- int scale_avail_show[AD760X_MAX_SCALE_SHOW];
+ const unsigned int (*scale_avail)[2];
unsigned int num_scales;
unsigned int range;
unsigned int reg_offset;
@@ -115,6 +123,7 @@ struct ad7606_chan_scale {
* @bops bus operations (SPI or parallel)
* @chan_scales scale configuration for channels
* @oversampling oversampling selection
+ * @cnvst_pwm pointer to the PWM device connected to the cnvst pin
* @base_address address from where to read data in parallel operation
* @sw_mode_en software mode enabled
* @oversampling_avail pointer to the array which stores the available
@@ -142,10 +151,12 @@ struct ad7606_state {
const struct ad7606_bus_ops *bops;
struct ad7606_chan_scale chan_scales[AD760X_MAX_CHANNELS];
unsigned int oversampling;
+ struct pwm_device *cnvst_pwm;
void __iomem *base_address;
bool sw_mode_en;
const unsigned int *oversampling_avail;
unsigned int num_os_ratios;
+ struct iio_backend *back;
int (*write_scale)(struct iio_dev *indio_dev, int ch, int val);
int (*write_os)(struct iio_dev *indio_dev, int val);
@@ -174,16 +185,21 @@ struct ad7606_state {
/**
* struct ad7606_bus_ops - driver bus operations
+ * @iio_backend_config function pointer for configuring the iio_backend for
+ * the compatibles that use it
* @read_block function pointer for reading blocks of data
* @sw_mode_config: pointer to a function which configured the device
* for software mode
* @reg_read function pointer for reading spi register
* @reg_write function pointer for writing spi register
* @write_mask function pointer for write spi register with mask
+ * @update_scan_mode function pointer for handling the calls to iio_info's update_scan
+ * mode when enabling/disabling channels.
* @rd_wr_cmd pointer to the function which calculates the spi address
*/
struct ad7606_bus_ops {
/* more methods added in future? */
+ int (*iio_backend_config)(struct device *dev, struct iio_dev *indio_dev);
int (*read_block)(struct device *dev, int num, void *data);
int (*sw_mode_config)(struct iio_dev *indio_dev);
int (*reg_read)(struct ad7606_state *st, unsigned int addr);
@@ -194,25 +210,37 @@ struct ad7606_bus_ops {
unsigned int addr,
unsigned long mask,
unsigned int val);
+ int (*update_scan_mode)(struct iio_dev *indio_dev, const unsigned long *scan_mask);
u16 (*rd_wr_cmd)(int addr, char isWriteOp);
};
+/**
+ * struct ad7606_bus_info - agregate ad7606_chip_info and ad7606_bus_ops
+ * @chip_info entry in the table of chips that describes this device
+ * @bops bus operations (SPI or parallel)
+ */
+struct ad7606_bus_info {
+ const struct ad7606_chip_info *chip_info;
+ const struct ad7606_bus_ops *bops;
+};
+
int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
- const char *name, unsigned int id,
+ const struct ad7606_chip_info *info,
const struct ad7606_bus_ops *bops);
int ad7606_reset(struct ad7606_state *st);
-enum ad7606_supported_device_ids {
- ID_AD7605_4,
- ID_AD7606_8,
- ID_AD7606_6,
- ID_AD7606_4,
- ID_AD7606B,
- ID_AD7606C_16,
- ID_AD7606C_18,
- ID_AD7616,
-};
+extern const struct ad7606_chip_info ad7605_4_info;
+extern const struct ad7606_chip_info ad7606_8_info;
+extern const struct ad7606_chip_info ad7606_6_info;
+extern const struct ad7606_chip_info ad7606_4_info;
+extern const struct ad7606_chip_info ad7606b_info;
+extern const struct ad7606_chip_info ad7606c_16_info;
+extern const struct ad7606_chip_info ad7606c_18_info;
+extern const struct ad7606_chip_info ad7607_info;
+extern const struct ad7606_chip_info ad7608_info;
+extern const struct ad7606_chip_info ad7609_info;
+extern const struct ad7606_chip_info ad7616_info;
#ifdef CONFIG_PM_SLEEP
extern const struct dev_pm_ops ad7606_pm_ops;
diff --git a/drivers/iio/adc/ad7606_par.c b/drivers/iio/adc/ad7606_par.c
index d651639c45eb..a25182a3daa7 100644
--- a/drivers/iio/adc/ad7606_par.c
+++ b/drivers/iio/adc/ad7606_par.c
@@ -2,7 +2,8 @@
/*
* AD7606 Parallel Interface ADC driver
*
- * Copyright 2011 Analog Devices Inc.
+ * Copyright 2011 - 2024 Analog Devices Inc.
+ * Copyright 2024 BayLibre SAS.
*/
#include <linux/err.h>
@@ -11,11 +12,85 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/types.h>
+#include <linux/iio/backend.h>
#include <linux/iio/iio.h>
+
#include "ad7606.h"
+static const struct iio_chan_spec ad7606b_bi_channels[] = {
+ AD7606_BI_CHANNEL(0),
+ AD7606_BI_CHANNEL(1),
+ AD7606_BI_CHANNEL(2),
+ AD7606_BI_CHANNEL(3),
+ AD7606_BI_CHANNEL(4),
+ AD7606_BI_CHANNEL(5),
+ AD7606_BI_CHANNEL(6),
+ AD7606_BI_CHANNEL(7),
+};
+
+static int ad7606_bi_update_scan_mode(struct iio_dev *indio_dev, const unsigned long *scan_mask)
+{
+ struct ad7606_state *st = iio_priv(indio_dev);
+ unsigned int c, ret;
+
+ for (c = 0; c < indio_dev->num_channels; c++) {
+ if (test_bit(c, scan_mask))
+ ret = iio_backend_chan_enable(st->back, c);
+ else
+ ret = iio_backend_chan_disable(st->back, c);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ad7606_bi_setup_iio_backend(struct device *dev, struct iio_dev *indio_dev)
+{
+ struct ad7606_state *st = iio_priv(indio_dev);
+ unsigned int ret, c;
+ struct iio_backend_data_fmt data = {
+ .sign_extend = true,
+ .enable = true,
+ };
+
+ st->back = devm_iio_backend_get(dev, NULL);
+ if (IS_ERR(st->back))
+ return PTR_ERR(st->back);
+
+ /* If the device is iio_backend powered the PWM is mandatory */
+ if (!st->cnvst_pwm)
+ return dev_err_probe(st->dev, -EINVAL,
+ "A PWM is mandatory when using backend.\n");
+
+ ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_backend_enable(dev, st->back);
+ if (ret)
+ return ret;
+
+ for (c = 0; c < indio_dev->num_channels; c++) {
+ ret = iio_backend_data_format_set(st->back, c, &data);
+ if (ret)
+ return ret;
+ }
+
+ indio_dev->channels = ad7606b_bi_channels;
+ indio_dev->num_channels = 8;
+
+ return 0;
+}
+
+static const struct ad7606_bus_ops ad7606_bi_bops = {
+ .iio_backend_config = ad7606_bi_setup_iio_backend,
+ .update_scan_mode = ad7606_bi_update_scan_mode,
+};
+
static int ad7606_par16_read_block(struct device *dev,
int count, void *buf)
{
@@ -89,12 +164,32 @@ static const struct ad7606_bus_ops ad7606_par8_bops = {
static int ad7606_par_probe(struct platform_device *pdev)
{
- const struct platform_device_id *id = platform_get_device_id(pdev);
+ const struct ad7606_chip_info *chip_info;
+ const struct platform_device_id *id;
struct resource *res;
void __iomem *addr;
resource_size_t remap_size;
int irq;
+ /*
+ * If a firmware node is available (ACPI or DT), platform_device_id is null
+ * and we must use get_match_data.
+ */
+ if (dev_fwnode(&pdev->dev)) {
+ chip_info = device_get_match_data(&pdev->dev);
+ if (device_property_present(&pdev->dev, "io-backends"))
+ /*
+ * If a backend is available ,call the core probe with backend
+ * bops, otherwise use the former bops.
+ */
+ return ad7606_probe(&pdev->dev, 0, NULL,
+ chip_info,
+ &ad7606_bi_bops);
+ } else {
+ id = platform_get_device_id(pdev);
+ chip_info = (const struct ad7606_chip_info *)id->driver_data;
+ }
+
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
@@ -105,26 +200,33 @@ static int ad7606_par_probe(struct platform_device *pdev)
remap_size = resource_size(res);
- return ad7606_probe(&pdev->dev, irq, addr,
- id->name, id->driver_data,
+ return ad7606_probe(&pdev->dev, irq, addr, chip_info,
remap_size > 1 ? &ad7606_par16_bops :
&ad7606_par8_bops);
}
static const struct platform_device_id ad7606_driver_ids[] = {
- { .name = "ad7605-4", .driver_data = ID_AD7605_4, },
- { .name = "ad7606-4", .driver_data = ID_AD7606_4, },
- { .name = "ad7606-6", .driver_data = ID_AD7606_6, },
- { .name = "ad7606-8", .driver_data = ID_AD7606_8, },
+ { .name = "ad7605-4", .driver_data = (kernel_ulong_t)&ad7605_4_info, },
+ { .name = "ad7606-4", .driver_data = (kernel_ulong_t)&ad7606_4_info, },
+ { .name = "ad7606-6", .driver_data = (kernel_ulong_t)&ad7606_6_info, },
+ { .name = "ad7606-8", .driver_data = (kernel_ulong_t)&ad7606_8_info, },
+ { .name = "ad7606b", .driver_data = (kernel_ulong_t)&ad7606b_info, },
+ { .name = "ad7607", .driver_data = (kernel_ulong_t)&ad7607_info, },
+ { .name = "ad7608", .driver_data = (kernel_ulong_t)&ad7608_info, },
+ { .name = "ad7609", .driver_data = (kernel_ulong_t)&ad7609_info, },
{ }
};
MODULE_DEVICE_TABLE(platform, ad7606_driver_ids);
static const struct of_device_id ad7606_of_match[] = {
- { .compatible = "adi,ad7605-4" },
- { .compatible = "adi,ad7606-4" },
- { .compatible = "adi,ad7606-6" },
- { .compatible = "adi,ad7606-8" },
+ { .compatible = "adi,ad7605-4", .data = &ad7605_4_info },
+ { .compatible = "adi,ad7606-4", .data = &ad7606_4_info },
+ { .compatible = "adi,ad7606-6", .data = &ad7606_6_info },
+ { .compatible = "adi,ad7606-8", .data = &ad7606_8_info },
+ { .compatible = "adi,ad7606b", .data = &ad7606b_info },
+ { .compatible = "adi,ad7607", .data = &ad7607_info },
+ { .compatible = "adi,ad7608", .data = &ad7608_info },
+ { .compatible = "adi,ad7609", .data = &ad7609_info },
{ }
};
MODULE_DEVICE_TABLE(of, ad7606_of_match);
@@ -144,3 +246,4 @@ MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(IIO_AD7606);
+MODULE_IMPORT_NS(IIO_BACKEND);
diff --git a/drivers/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c
index d12e55123888..0662300cde8d 100644
--- a/drivers/iio/adc/ad7606_spi.c
+++ b/drivers/iio/adc/ad7606_spi.c
@@ -132,6 +132,19 @@ static int ad7606_spi_read_block(struct device *dev,
return 0;
}
+static int ad7606_spi_read_block14to16(struct device *dev,
+ int count, void *buf)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct spi_transfer xfer = {
+ .bits_per_word = 14,
+ .len = count * sizeof(u16),
+ .rx_buf = buf,
+ };
+
+ return spi_sync_transfer(spi, &xfer, 1);
+}
+
static int ad7606_spi_read_block18to32(struct device *dev,
int count, void *buf)
{
@@ -325,6 +338,14 @@ static const struct ad7606_bus_ops ad7606_spi_bops = {
.read_block = ad7606_spi_read_block,
};
+static const struct ad7606_bus_ops ad7607_spi_bops = {
+ .read_block = ad7606_spi_read_block14to16,
+};
+
+static const struct ad7606_bus_ops ad7608_spi_bops = {
+ .read_block = ad7606_spi_read_block18to32,
+};
+
static const struct ad7606_bus_ops ad7616_spi_bops = {
.read_block = ad7606_spi_read_block,
.reg_read = ad7606_spi_reg_read,
@@ -334,7 +355,7 @@ static const struct ad7606_bus_ops ad7616_spi_bops = {
.sw_mode_config = ad7616_sw_mode_config,
};
-static const struct ad7606_bus_ops ad7606B_spi_bops = {
+static const struct ad7606_bus_ops ad7606b_spi_bops = {
.read_block = ad7606_spi_read_block,
.reg_read = ad7606_spi_reg_read,
.reg_write = ad7606_spi_reg_write,
@@ -352,54 +373,97 @@ static const struct ad7606_bus_ops ad7606c_18_spi_bops = {
.sw_mode_config = ad7606c_18_sw_mode_config,
};
+static const struct ad7606_bus_info ad7605_4_bus_info = {
+ .chip_info = &ad7605_4_info,
+ .bops = &ad7606_spi_bops,
+};
+
+static const struct ad7606_bus_info ad7606_8_bus_info = {
+ .chip_info = &ad7606_8_info,
+ .bops = &ad7606_spi_bops,
+};
+
+static const struct ad7606_bus_info ad7606_6_bus_info = {
+ .chip_info = &ad7606_6_info,
+ .bops = &ad7606_spi_bops,
+};
+
+static const struct ad7606_bus_info ad7606_4_bus_info = {
+ .chip_info = &ad7606_4_info,
+ .bops = &ad7606_spi_bops,
+};
+
+static const struct ad7606_bus_info ad7606b_bus_info = {
+ .chip_info = &ad7606b_info,
+ .bops = &ad7606b_spi_bops,
+};
+
+static const struct ad7606_bus_info ad7606c_16_bus_info = {
+ .chip_info = &ad7606c_16_info,
+ .bops = &ad7606b_spi_bops,
+};
+
+static const struct ad7606_bus_info ad7606c_18_bus_info = {
+ .chip_info = &ad7606c_18_info,
+ .bops = &ad7606c_18_spi_bops,
+};
+
+static const struct ad7606_bus_info ad7607_bus_info = {
+ .chip_info = &ad7607_info,
+ .bops = &ad7607_spi_bops,
+};
+
+static const struct ad7606_bus_info ad7608_bus_info = {
+ .chip_info = &ad7608_info,
+ .bops = &ad7608_spi_bops,
+};
+
+static const struct ad7606_bus_info ad7609_bus_info = {
+ .chip_info = &ad7609_info,
+ .bops = &ad7608_spi_bops,
+};
+
+static const struct ad7606_bus_info ad7616_bus_info = {
+ .chip_info = &ad7616_info,
+ .bops = &ad7616_spi_bops,
+};
+
static int ad7606_spi_probe(struct spi_device *spi)
{
- const struct spi_device_id *id = spi_get_device_id(spi);
- const struct ad7606_bus_ops *bops;
-
- switch (id->driver_data) {
- case ID_AD7616:
- bops = &ad7616_spi_bops;
- break;
- case ID_AD7606B:
- case ID_AD7606C_16:
- bops = &ad7606B_spi_bops;
- break;
- case ID_AD7606C_18:
- bops = &ad7606c_18_spi_bops;
- break;
- default:
- bops = &ad7606_spi_bops;
- break;
- }
+ const struct ad7606_bus_info *bus_info = spi_get_device_match_data(spi);
return ad7606_probe(&spi->dev, spi->irq, NULL,
- id->name, id->driver_data,
- bops);
+ bus_info->chip_info, bus_info->bops);
}
static const struct spi_device_id ad7606_id_table[] = {
- { "ad7605-4", ID_AD7605_4 },
- { "ad7606-4", ID_AD7606_4 },
- { "ad7606-6", ID_AD7606_6 },
- { "ad7606-8", ID_AD7606_8 },
- { "ad7606b", ID_AD7606B },
- { "ad7606c-16", ID_AD7606C_16 },
- { "ad7606c-18", ID_AD7606C_18 },
- { "ad7616", ID_AD7616 },
+ { "ad7605-4", (kernel_ulong_t)&ad7605_4_bus_info },
+ { "ad7606-4", (kernel_ulong_t)&ad7606_4_bus_info },
+ { "ad7606-6", (kernel_ulong_t)&ad7606_6_bus_info },
+ { "ad7606-8", (kernel_ulong_t)&ad7606_8_bus_info },
+ { "ad7606b", (kernel_ulong_t)&ad7606b_bus_info },
+ { "ad7606c-16", (kernel_ulong_t)&ad7606c_16_bus_info },
+ { "ad7606c-18", (kernel_ulong_t)&ad7606c_18_bus_info },
+ { "ad7607", (kernel_ulong_t)&ad7607_bus_info },
+ { "ad7608", (kernel_ulong_t)&ad7608_bus_info },
+ { "ad7609", (kernel_ulong_t)&ad7609_bus_info },
+ { "ad7616", (kernel_ulong_t)&ad7616_bus_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7606_id_table);
static const struct of_device_id ad7606_of_match[] = {
- { .compatible = "adi,ad7605-4" },
- { .compatible = "adi,ad7606-4" },
- { .compatible = "adi,ad7606-6" },
- { .compatible = "adi,ad7606-8" },
- { .compatible = "adi,ad7606b" },
- { .compatible = "adi,ad7606c-16" },
- { .compatible = "adi,ad7606c-18" },
- { .compatible = "adi,ad7616" },
+ { .compatible = "adi,ad7605-4", .data = &ad7605_4_bus_info },
+ { .compatible = "adi,ad7606-4", .data = &ad7606_4_bus_info },
+ { .compatible = "adi,ad7606-6", .data = &ad7606_6_bus_info },
+ { .compatible = "adi,ad7606-8", .data = &ad7606_8_bus_info },
+ { .compatible = "adi,ad7606b", .data = &ad7606b_bus_info },
+ { .compatible = "adi,ad7606c-16", .data = &ad7606c_16_bus_info },
+ { .compatible = "adi,ad7606c-18", .data = &ad7606c_18_bus_info },
+ { .compatible = "adi,ad7607", .data = &ad7607_bus_info },
+ { .compatible = "adi,ad7608", .data = &ad7608_bus_info },
+ { .compatible = "adi,ad7609", .data = &ad7609_bus_info },
+ { .compatible = "adi,ad7616", .data = &ad7616_bus_info },
{ }
};
MODULE_DEVICE_TABLE(of, ad7606_of_match);
diff --git a/drivers/iio/adc/ad7779.c b/drivers/iio/adc/ad7779.c
new file mode 100644
index 000000000000..2537dab69a35
--- /dev/null
+++ b/drivers/iio/adc/ad7779.c
@@ -0,0 +1,914 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * AD7770, AD7771, AD7779 ADC
+ *
+ * Copyright 2023-2024 Analog Devices Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitmap.h>
+#include <linux/clk.h>
+#include <linux/crc8.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/math.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+#include <linux/units.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+
+#define AD7779_SPI_READ_CMD BIT(7)
+
+#define AD7779_DISABLE_SD BIT(7)
+
+#define AD7779_REG_CH_DISABLE 0x08
+#define AD7779_REG_CH_SYNC_OFFSET(ch) (0x09 + (ch))
+#define AD7779_REG_CH_CONFIG(ch) (0x00 + (ch))
+#define AD7779_REG_GENERAL_USER_CONFIG_1 0x11
+#define AD7779_REG_GENERAL_USER_CONFIG_2 0x12
+#define AD7779_REG_GENERAL_USER_CONFIG_3 0x13
+#define AD7779_REG_DOUT_FORMAT 0x14
+#define AD7779_REG_ADC_MUX_CONFIG 0x15
+#define AD7779_REG_GPIO_CONFIG 0x17
+#define AD7779_REG_BUFFER_CONFIG_1 0x19
+#define AD7779_REG_GLOBAL_MUX_CONFIG 0x16
+#define AD7779_REG_BUFFER_CONFIG_2 0x1A
+#define AD7779_REG_GPIO_DATA 0x18
+#define AD7779_REG_CH_OFFSET_UPPER_BYTE(ch) (0x1C + (ch) * 6)
+#define AD7779_REG_CH_OFFSET_LOWER_BYTE(ch) (0x1E + (ch) * 6)
+#define AD7779_REG_CH_GAIN_UPPER_BYTE(ch) (0x1F + (ch) * 6)
+#define AD7779_REG_CH_OFFSET_MID_BYTE(ch) (0x1D + (ch) * 6)
+#define AD7779_REG_CH_GAIN_MID_BYTE(ch) (0x20 + (ch) * 6)
+#define AD7779_REG_CH_ERR_REG(ch) (0x4C + (ch))
+#define AD7779_REG_CH0_1_SAT_ERR 0x54
+#define AD7779_REG_CH_GAIN_LOWER_BYTE(ch) (0x21 + (ch) * 6)
+#define AD7779_REG_CH2_3_SAT_ERR 0x55
+#define AD7779_REG_CH4_5_SAT_ERR 0x56
+#define AD7779_REG_CH6_7_SAT_ERR 0x57
+#define AD7779_REG_CHX_ERR_REG_EN 0x58
+#define AD7779_REG_GEN_ERR_REG_1 0x59
+#define AD7779_REG_GEN_ERR_REG_1_EN 0x5A
+#define AD7779_REG_GEN_ERR_REG_2 0x5B
+#define AD7779_REG_GEN_ERR_REG_2_EN 0x5C
+#define AD7779_REG_STATUS_REG_1 0x5D
+#define AD7779_REG_STATUS_REG_2 0x5E
+#define AD7779_REG_STATUS_REG_3 0x5F
+#define AD7779_REG_SRC_N_MSB 0x60
+#define AD7779_REG_SRC_N_LSB 0x61
+#define AD7779_REG_SRC_IF_MSB 0x62
+#define AD7779_REG_SRC_IF_LSB 0x63
+#define AD7779_REG_SRC_UPDATE 0x64
+
+#define AD7779_FILTER_MSK BIT(6)
+#define AD7779_MOD_POWERMODE_MSK BIT(6)
+#define AD7779_MOD_PDB_REFOUT_MSK BIT(4)
+#define AD7779_MOD_SPI_EN_MSK BIT(4)
+#define AD7779_USRMOD_INIT_MSK GENMASK(6, 4)
+
+/* AD7779_REG_DOUT_FORMAT */
+#define AD7779_DOUT_FORMAT_MSK GENMASK(7, 6)
+#define AD7779_DOUT_HEADER_FORMAT BIT(5)
+#define AD7779_DCLK_CLK_DIV_MSK GENMASK(3, 1)
+
+#define AD7779_REFMUX_CTRL_MSK GENMASK(7, 6)
+#define AD7779_SPI_CRC_EN_MSK BIT(0)
+
+#define AD7779_MAXCLK_LOWPOWER (4096 * HZ_PER_KHZ)
+#define AD7779_NUM_CHANNELS 8
+#define AD7779_RESET_BUF_SIZE 8
+#define AD7779_CHAN_DATA_SIZE 4
+
+#define AD7779_LOWPOWER_DIV 512
+#define AD7779_HIGHPOWER_DIV 2048
+
+#define AD7779_SINC3_MAXFREQ (16 * HZ_PER_KHZ)
+#define AD7779_SINC5_MAXFREQ (128 * HZ_PER_KHZ)
+
+#define AD7779_DEFAULT_SAMPLING_FREQ (8 * HZ_PER_KHZ)
+#define AD7779_DEFAULT_SAMPLING_2LINE (4 * HZ_PER_KHZ)
+#define AD7779_DEFAULT_SAMPLING_1LINE (2 * HZ_PER_KHZ)
+
+#define AD7779_SPIMODE_MAX_SAMP_FREQ (16 * HZ_PER_KHZ)
+
+#define GAIN_REL 0x555555
+#define AD7779_FREQ_MSB_MSK GENMASK(15, 8)
+#define AD7779_FREQ_LSB_MSK GENMASK(7, 0)
+#define AD7779_UPPER GENMASK(23, 16)
+#define AD7779_MID GENMASK(15, 8)
+#define AD7779_LOWER GENMASK(7, 0)
+
+#define AD7779_REG_MSK GENMASK(6, 0)
+
+#define AD7779_CRC8_POLY 0x07
+DECLARE_CRC8_TABLE(ad7779_crc8_table);
+
+enum ad7779_filter {
+ AD7779_SINC3,
+ AD7779_SINC5,
+};
+
+enum ad7779_variant {
+ ad7770,
+ ad7771,
+ ad7779,
+};
+
+enum ad7779_power_mode {
+ AD7779_LOW_POWER,
+ AD7779_HIGH_POWER,
+};
+
+struct ad7779_chip_info {
+ const char *name;
+ struct iio_chan_spec const *channels;
+};
+
+struct ad7779_state {
+ struct spi_device *spi;
+ const struct ad7779_chip_info *chip_info;
+ struct clk *mclk;
+ struct iio_trigger *trig;
+ struct completion completion;
+ unsigned int sampling_freq;
+ enum ad7779_filter filter_enabled;
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ */
+ struct {
+ u32 chans[8];
+ aligned_s64 timestamp;
+ } data __aligned(IIO_DMA_MINALIGN);
+ u32 spidata_tx[8];
+ u8 reg_rx_buf[3];
+ u8 reg_tx_buf[3];
+ u8 reset_buf[8];
+};
+
+static const char * const ad7779_filter_type[] = {
+ [AD7779_SINC3] = "sinc3",
+ [AD7779_SINC5] = "sinc5",
+};
+
+static const char * const ad7779_power_supplies[] = {
+ "avdd1", "avdd2", "avdd4",
+};
+
+static int ad7779_spi_read(struct ad7779_state *st, u8 reg, u8 *rbuf)
+{
+ int ret;
+ u8 crc_buf[2];
+ u8 exp_crc;
+ struct spi_transfer t = {
+ .tx_buf = st->reg_tx_buf,
+ .rx_buf = st->reg_rx_buf,
+ };
+
+ st->reg_tx_buf[0] = AD7779_SPI_READ_CMD | FIELD_GET(AD7779_REG_MSK, reg);
+ st->reg_tx_buf[1] = 0;
+
+ if (reg == AD7779_REG_GEN_ERR_REG_1_EN) {
+ t.len = 2;
+ } else {
+ t.len = 3;
+ st->reg_tx_buf[2] = crc8(ad7779_crc8_table, st->reg_tx_buf,
+ t.len - 1, 0);
+ }
+
+ ret = spi_sync_transfer(st->spi, &t, 1);
+ if (ret)
+ return ret;
+
+ crc_buf[0] = AD7779_SPI_READ_CMD | FIELD_GET(AD7779_REG_MSK, reg);
+ crc_buf[1] = st->reg_rx_buf[1];
+ exp_crc = crc8(ad7779_crc8_table, crc_buf, ARRAY_SIZE(crc_buf), 0);
+ if (reg != AD7779_REG_GEN_ERR_REG_1_EN && exp_crc != st->reg_rx_buf[2]) {
+ dev_err(&st->spi->dev, "Bad CRC %x, expected %x",
+ st->reg_rx_buf[2], exp_crc);
+ return -EINVAL;
+ }
+ *rbuf = st->reg_rx_buf[1];
+
+ return 0;
+}
+
+static int ad7779_spi_write(struct ad7779_state *st, u8 reg, u8 val)
+{
+ u8 length = 3;
+
+ st->reg_tx_buf[0] = FIELD_GET(AD7779_REG_MSK, reg);
+ st->reg_tx_buf[1] = val;
+ if (reg == AD7779_REG_GEN_ERR_REG_1_EN)
+ length = 2;
+ else
+ st->reg_tx_buf[2] = crc8(ad7779_crc8_table, st->reg_tx_buf,
+ length - 1, 0);
+
+ return spi_write(st->spi, st->reg_tx_buf, length);
+}
+
+static int ad7779_spi_write_mask(struct ad7779_state *st, u8 reg, u8 mask,
+ u8 val)
+{
+ int ret;
+ u8 regval, data;
+
+ ret = ad7779_spi_read(st, reg, &data);
+ if (ret)
+ return ret;
+
+ regval = (data & ~mask) | (val & mask);
+
+ if (regval == data)
+ return 0;
+
+ return ad7779_spi_write(st, reg, regval);
+}
+
+static int ad7779_reg_access(struct iio_dev *indio_dev,
+ unsigned int reg,
+ unsigned int writeval,
+ unsigned int *readval)
+{
+ struct ad7779_state *st = iio_priv(indio_dev);
+ u8 rval;
+ int ret;
+
+ if (readval) {
+ ret = ad7779_spi_read(st, reg, &rval);
+ *readval = rval;
+ return ret;
+ }
+
+ return ad7779_spi_write(st, reg, writeval);
+}
+
+static int ad7779_set_sampling_frequency(struct ad7779_state *st,
+ unsigned int sampling_freq)
+{
+ int ret;
+ unsigned int dec;
+ unsigned int frac;
+ unsigned int div;
+ unsigned int decimal;
+ unsigned int freq_khz;
+
+ if (st->filter_enabled == AD7779_SINC3 &&
+ sampling_freq > AD7779_SINC3_MAXFREQ)
+ return -EINVAL;
+
+ if (st->filter_enabled == AD7779_SINC5 &&
+ sampling_freq > AD7779_SINC5_MAXFREQ)
+ return -EINVAL;
+
+ if (sampling_freq > AD7779_SPIMODE_MAX_SAMP_FREQ)
+ return -EINVAL;
+
+ div = AD7779_HIGHPOWER_DIV;
+
+ freq_khz = sampling_freq / HZ_PER_KHZ;
+ dec = div / freq_khz;
+ frac = div % freq_khz;
+
+ ret = ad7779_spi_write(st, AD7779_REG_SRC_N_MSB,
+ FIELD_GET(AD7779_FREQ_MSB_MSK, dec));
+ if (ret)
+ return ret;
+ ret = ad7779_spi_write(st, AD7779_REG_SRC_N_LSB,
+ FIELD_GET(AD7779_FREQ_LSB_MSK, dec));
+ if (ret)
+ return ret;
+
+ if (frac) {
+ /*
+ * In order to obtain the first three decimals of the decimation
+ * the initial number is multiplied with 10^3 prior to the
+ * division, then the original division result is subtracted and
+ * the number is divided by 10^3.
+ */
+ decimal = ((mult_frac(div, KILO, freq_khz) - dec * KILO) << 16)
+ / KILO;
+ ret = ad7779_spi_write(st, AD7779_REG_SRC_N_MSB,
+ FIELD_GET(AD7779_FREQ_MSB_MSK, decimal));
+ if (ret)
+ return ret;
+ ret = ad7779_spi_write(st, AD7779_REG_SRC_N_LSB,
+ FIELD_GET(AD7779_FREQ_LSB_MSK, decimal));
+ if (ret)
+ return ret;
+ } else {
+ ret = ad7779_spi_write(st, AD7779_REG_SRC_N_MSB,
+ FIELD_GET(AD7779_FREQ_MSB_MSK, 0x0));
+ if (ret)
+ return ret;
+ ret = ad7779_spi_write(st, AD7779_REG_SRC_N_LSB,
+ FIELD_GET(AD7779_FREQ_LSB_MSK, 0x0));
+ if (ret)
+ return ret;
+ }
+ ret = ad7779_spi_write(st, AD7779_REG_SRC_UPDATE, BIT(0));
+ if (ret)
+ return ret;
+
+ /* SRC update settling time */
+ fsleep(15);
+
+ ret = ad7779_spi_write(st, AD7779_REG_SRC_UPDATE, 0x0);
+ if (ret)
+ return ret;
+
+ /* SRC update settling time */
+ fsleep(15);
+
+ st->sampling_freq = sampling_freq;
+
+ return 0;
+}
+
+static int ad7779_get_filter(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan)
+{
+ struct ad7779_state *st = iio_priv(indio_dev);
+ u8 temp;
+ int ret;
+
+ ret = ad7779_spi_read(st, AD7779_REG_GENERAL_USER_CONFIG_2, &temp);
+ if (ret)
+ return ret;
+
+ return FIELD_GET(AD7779_FILTER_MSK, temp);
+}
+
+static int ad7779_set_filter(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ unsigned int mode)
+{
+ struct ad7779_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = ad7779_spi_write_mask(st,
+ AD7779_REG_GENERAL_USER_CONFIG_2,
+ AD7779_FILTER_MSK,
+ FIELD_PREP(AD7779_FILTER_MSK, mode));
+ if (ret)
+ return ret;
+
+ ret = ad7779_set_sampling_frequency(st, st->sampling_freq);
+ if (ret)
+ return ret;
+
+ st->filter_enabled = mode;
+
+ return 0;
+}
+
+static int ad7779_get_calibscale(struct ad7779_state *st, int channel)
+{
+ int ret;
+ u8 calibscale[3];
+
+ ret = ad7779_spi_read(st, AD7779_REG_CH_GAIN_LOWER_BYTE(channel),
+ &calibscale[0]);
+ if (ret)
+ return ret;
+
+ ret = ad7779_spi_read(st, AD7779_REG_CH_GAIN_MID_BYTE(channel),
+ &calibscale[1]);
+ if (ret)
+ return ret;
+
+ ret = ad7779_spi_read(st, AD7779_REG_CH_GAIN_UPPER_BYTE(channel),
+ &calibscale[2]);
+ if (ret)
+ return ret;
+
+ return get_unaligned_be24(calibscale);
+}
+
+static int ad7779_set_calibscale(struct ad7779_state *st, int channel, int val)
+{
+ int ret;
+ unsigned int gain;
+ u8 gain_bytes[3];
+
+ /*
+ * The gain value is relative to 0x555555, which represents a gain of 1
+ */
+ gain = DIV_ROUND_CLOSEST_ULL((u64)val * 5592405LL, MEGA);
+ put_unaligned_be24(gain, gain_bytes);
+ ret = ad7779_spi_write(st, AD7779_REG_CH_GAIN_UPPER_BYTE(channel),
+ gain_bytes[0]);
+ if (ret)
+ return ret;
+
+ ret = ad7779_spi_write(st, AD7779_REG_CH_GAIN_MID_BYTE(channel),
+ gain_bytes[1]);
+ if (ret)
+ return ret;
+
+ return ad7779_spi_write(st, AD7779_REG_CH_GAIN_LOWER_BYTE(channel),
+ gain_bytes[2]);
+}
+
+static int ad7779_get_calibbias(struct ad7779_state *st, int channel)
+{
+ int ret;
+ u8 calibbias[3];
+
+ ret = ad7779_spi_read(st, AD7779_REG_CH_OFFSET_LOWER_BYTE(channel),
+ &calibbias[0]);
+ if (ret)
+ return ret;
+
+ ret = ad7779_spi_read(st, AD7779_REG_CH_OFFSET_MID_BYTE(channel),
+ &calibbias[1]);
+ if (ret)
+ return ret;
+
+ ret = ad7779_spi_read(st, AD7779_REG_CH_OFFSET_UPPER_BYTE(channel),
+ &calibbias[2]);
+ if (ret)
+ return ret;
+
+ return get_unaligned_be24(calibbias);
+}
+
+static int ad7779_set_calibbias(struct ad7779_state *st, int channel, int val)
+{
+ int ret;
+ u8 calibbias[3];
+
+ put_unaligned_be24(val, calibbias);
+ ret = ad7779_spi_write(st, AD7779_REG_CH_OFFSET_UPPER_BYTE(channel),
+ calibbias[0]);
+ if (ret)
+ return ret;
+
+ ret = ad7779_spi_write(st, AD7779_REG_CH_OFFSET_MID_BYTE(channel),
+ calibbias[1]);
+ if (ret)
+ return ret;
+
+ return ad7779_spi_write(st, AD7779_REG_CH_OFFSET_LOWER_BYTE(channel),
+ calibbias[2]);
+}
+
+static int ad7779_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct ad7779_state *st = iio_priv(indio_dev);
+ int ret;
+
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+ switch (mask) {
+ case IIO_CHAN_INFO_CALIBSCALE:
+ ret = ad7779_get_calibscale(st, chan->channel);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ *val2 = GAIN_REL;
+ return IIO_VAL_FRACTIONAL;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ ret = ad7779_get_calibbias(st, chan->channel);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = st->sampling_freq;
+ if (*val < 0)
+ return -EINVAL;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ }
+ unreachable();
+}
+
+static int ad7779_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val, int val2,
+ long mask)
+{
+ struct ad7779_state *st = iio_priv(indio_dev);
+
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+ switch (mask) {
+ case IIO_CHAN_INFO_CALIBSCALE:
+ return ad7779_set_calibscale(st, chan->channel, val2);
+ case IIO_CHAN_INFO_CALIBBIAS:
+ return ad7779_set_calibbias(st, chan->channel, val);
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return ad7779_set_sampling_frequency(st, val);
+ default:
+ return -EINVAL;
+ }
+ }
+ unreachable();
+}
+
+static int ad7779_buffer_preenable(struct iio_dev *indio_dev)
+{
+ int ret;
+ struct ad7779_state *st = iio_priv(indio_dev);
+
+ ret = ad7779_spi_write_mask(st,
+ AD7779_REG_GENERAL_USER_CONFIG_3,
+ AD7779_MOD_SPI_EN_MSK,
+ FIELD_PREP(AD7779_MOD_SPI_EN_MSK, 1));
+ if (ret)
+ return ret;
+
+ /*
+ * DRDY output cannot be disabled at device level therefore we mask
+ * the irq at host end.
+ */
+ enable_irq(st->spi->irq);
+
+ return 0;
+}
+
+static int ad7779_buffer_postdisable(struct iio_dev *indio_dev)
+{
+ struct ad7779_state *st = iio_priv(indio_dev);
+
+ disable_irq(st->spi->irq);
+
+ return ad7779_spi_write(st, AD7779_REG_GENERAL_USER_CONFIG_3,
+ AD7779_DISABLE_SD);
+}
+
+static irqreturn_t ad7779_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ad7779_state *st = iio_priv(indio_dev);
+ int ret;
+ struct spi_transfer t = {
+ .rx_buf = st->data.chans,
+ .tx_buf = st->spidata_tx,
+ .len = AD7779_NUM_CHANNELS * AD7779_CHAN_DATA_SIZE,
+ };
+
+ st->spidata_tx[0] = AD7779_SPI_READ_CMD;
+ ret = spi_sync_transfer(st->spi, &t, 1);
+ if (ret) {
+ dev_err(&st->spi->dev, "SPI transfer error in IRQ handler");
+ goto exit_handler;
+ }
+
+ iio_push_to_buffers_with_timestamp(indio_dev, &st->data, pf->timestamp);
+
+exit_handler:
+ iio_trigger_notify_done(indio_dev->trig);
+ return IRQ_HANDLED;
+}
+
+static int ad7779_reset(struct iio_dev *indio_dev, struct gpio_desc *reset_gpio)
+{
+ struct ad7779_state *st = iio_priv(indio_dev);
+ int ret;
+ struct spi_transfer t = {
+ .tx_buf = st->reset_buf,
+ .len = 8,
+ };
+
+ if (reset_gpio) {
+ gpiod_set_value(reset_gpio, 1);
+ /* Delay for reset to occur is 225 microseconds */
+ fsleep(230);
+ ret = 0;
+ } else {
+ memset(st->reset_buf, 0xff, sizeof(st->reset_buf));
+ ret = spi_sync_transfer(st->spi, &t, 1);
+ if (ret)
+ return ret;
+ }
+
+ /* Delay for reset to occur is 225 microseconds */
+ fsleep(230);
+
+ return ret;
+}
+
+static const struct iio_info ad7779_info = {
+ .read_raw = ad7779_read_raw,
+ .write_raw = ad7779_write_raw,
+ .debugfs_reg_access = &ad7779_reg_access,
+};
+
+static const struct iio_enum ad7779_filter_enum = {
+ .items = ad7779_filter_type,
+ .num_items = ARRAY_SIZE(ad7779_filter_type),
+ .get = ad7779_get_filter,
+ .set = ad7779_set_filter,
+};
+
+static const struct iio_chan_spec_ext_info ad7779_ext_filter[] = {
+ IIO_ENUM("filter_type", IIO_SHARED_BY_ALL, &ad7779_filter_enum),
+ IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_ALL,
+ &ad7779_filter_enum),
+ { }
+};
+
+#define AD777x_CHAN_S(index, _ext_info) \
+ { \
+ .type = IIO_VOLTAGE, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_CALIBSCALE) | \
+ BIT(IIO_CHAN_INFO_CALIBBIAS), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\
+ .address = (index), \
+ .indexed = 1, \
+ .channel = (index), \
+ .scan_index = (index), \
+ .ext_info = (_ext_info), \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 24, \
+ .storagebits = 32, \
+ .endianness = IIO_BE, \
+ }, \
+ }
+
+#define AD777x_CHAN_NO_FILTER_S(index) \
+ AD777x_CHAN_S(index, NULL)
+
+#define AD777x_CHAN_FILTER_S(index) \
+ AD777x_CHAN_S(index, ad7779_ext_filter)
+static const struct iio_chan_spec ad7779_channels[] = {
+ AD777x_CHAN_NO_FILTER_S(0),
+ AD777x_CHAN_NO_FILTER_S(1),
+ AD777x_CHAN_NO_FILTER_S(2),
+ AD777x_CHAN_NO_FILTER_S(3),
+ AD777x_CHAN_NO_FILTER_S(4),
+ AD777x_CHAN_NO_FILTER_S(5),
+ AD777x_CHAN_NO_FILTER_S(6),
+ AD777x_CHAN_NO_FILTER_S(7),
+ IIO_CHAN_SOFT_TIMESTAMP(8),
+};
+
+static const struct iio_chan_spec ad7779_channels_filter[] = {
+ AD777x_CHAN_FILTER_S(0),
+ AD777x_CHAN_FILTER_S(1),
+ AD777x_CHAN_FILTER_S(2),
+ AD777x_CHAN_FILTER_S(3),
+ AD777x_CHAN_FILTER_S(4),
+ AD777x_CHAN_FILTER_S(5),
+ AD777x_CHAN_FILTER_S(6),
+ AD777x_CHAN_FILTER_S(7),
+ IIO_CHAN_SOFT_TIMESTAMP(8),
+};
+
+static const struct iio_buffer_setup_ops ad7779_buffer_setup_ops = {
+ .preenable = ad7779_buffer_preenable,
+ .postdisable = ad7779_buffer_postdisable,
+};
+
+static const struct iio_trigger_ops ad7779_trigger_ops = {
+ .validate_device = iio_trigger_validate_own_device,
+};
+
+static int ad7779_conf(struct ad7779_state *st, struct gpio_desc *start_gpio)
+{
+ int ret;
+
+ ret = ad7779_spi_write_mask(st, AD7779_REG_GEN_ERR_REG_1_EN,
+ AD7779_SPI_CRC_EN_MSK,
+ FIELD_PREP(AD7779_SPI_CRC_EN_MSK, 1));
+ if (ret)
+ return ret;
+
+ ret = ad7779_spi_write_mask(st, AD7779_REG_GENERAL_USER_CONFIG_1,
+ AD7779_USRMOD_INIT_MSK,
+ FIELD_PREP(AD7779_USRMOD_INIT_MSK, 5));
+ if (ret)
+ return ret;
+
+ ret = ad7779_spi_write_mask(st, AD7779_REG_DOUT_FORMAT,
+ AD7779_DCLK_CLK_DIV_MSK,
+ FIELD_PREP(AD7779_DCLK_CLK_DIV_MSK, 1));
+ if (ret)
+ return ret;
+
+ ret = ad7779_spi_write_mask(st, AD7779_REG_ADC_MUX_CONFIG,
+ AD7779_REFMUX_CTRL_MSK,
+ FIELD_PREP(AD7779_REFMUX_CTRL_MSK, 1));
+ if (ret)
+ return ret;
+
+ ret = ad7779_set_sampling_frequency(st, AD7779_DEFAULT_SAMPLING_FREQ);
+ if (ret)
+ return ret;
+
+ gpiod_set_value(start_gpio, 0);
+ /* Start setup time */
+ fsleep(15);
+ gpiod_set_value(start_gpio, 1);
+ /* Start setup time */
+ fsleep(15);
+ gpiod_set_value(start_gpio, 0);
+ /* Start setup time */
+ fsleep(15);
+
+ return 0;
+}
+
+static int ad7779_probe(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev;
+ struct ad7779_state *st;
+ struct gpio_desc *reset_gpio, *start_gpio;
+ struct device *dev = &spi->dev;
+ int ret = -EINVAL;
+
+ if (!spi->irq)
+ return dev_err_probe(dev, ret, "DRDY irq not present\n");
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ ret = devm_regulator_bulk_get_enable(dev,
+ ARRAY_SIZE(ad7779_power_supplies),
+ ad7779_power_supplies);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to get and enable supplies\n");
+
+ st->mclk = devm_clk_get_enabled(dev, "mclk");
+ if (IS_ERR(st->mclk))
+ return PTR_ERR(st->mclk);
+
+ reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(reset_gpio))
+ return PTR_ERR(reset_gpio);
+
+ start_gpio = devm_gpiod_get(dev, "start", GPIOD_OUT_HIGH);
+ if (IS_ERR(start_gpio))
+ return PTR_ERR(start_gpio);
+
+ crc8_populate_msb(ad7779_crc8_table, AD7779_CRC8_POLY);
+ st->spi = spi;
+
+ st->chip_info = spi_get_device_match_data(spi);
+ if (!st->chip_info)
+ return -ENODEV;
+
+ ret = ad7779_reset(indio_dev, reset_gpio);
+ if (ret)
+ return ret;
+
+ ret = ad7779_conf(st, start_gpio);
+ if (ret)
+ return ret;
+
+ indio_dev->name = st->chip_info->name;
+ indio_dev->info = &ad7779_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = st->chip_info->channels;
+ indio_dev->num_channels = ARRAY_SIZE(ad7779_channels);
+
+ st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
+ iio_device_id(indio_dev));
+ if (!st->trig)
+ return -ENOMEM;
+
+ st->trig->ops = &ad7779_trigger_ops;
+
+ iio_trigger_set_drvdata(st->trig, st);
+
+ ret = devm_request_irq(dev, spi->irq, iio_trigger_generic_data_rdy_poll,
+ IRQF_ONESHOT | IRQF_NO_AUTOEN, indio_dev->name,
+ st->trig);
+ if (ret)
+ return dev_err_probe(dev, ret, "request IRQ %d failed\n",
+ st->spi->irq);
+
+ ret = devm_iio_trigger_register(dev, st->trig);
+ if (ret)
+ return ret;
+
+ indio_dev->trig = iio_trigger_get(st->trig);
+
+ init_completion(&st->completion);
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+ &iio_pollfunc_store_time,
+ &ad7779_trigger_handler,
+ &ad7779_buffer_setup_ops);
+ if (ret)
+ return ret;
+
+ ret = ad7779_spi_write_mask(st, AD7779_REG_DOUT_FORMAT,
+ AD7779_DCLK_CLK_DIV_MSK,
+ FIELD_PREP(AD7779_DCLK_CLK_DIV_MSK, 7));
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static int ad7779_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ad7779_state *st = iio_priv(indio_dev);
+
+ return ad7779_spi_write_mask(st, AD7779_REG_GENERAL_USER_CONFIG_1,
+ AD7779_MOD_POWERMODE_MSK,
+ FIELD_PREP(AD7779_MOD_POWERMODE_MSK,
+ AD7779_LOW_POWER));
+}
+
+static int ad7779_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ad7779_state *st = iio_priv(indio_dev);
+
+ return ad7779_spi_write_mask(st, AD7779_REG_GENERAL_USER_CONFIG_1,
+ AD7779_MOD_POWERMODE_MSK,
+ FIELD_PREP(AD7779_MOD_POWERMODE_MSK,
+ AD7779_HIGH_POWER));
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(ad7779_pm_ops, ad7779_suspend, ad7779_resume);
+
+static const struct ad7779_chip_info ad7770_chip_info = {
+ .name = "ad7770",
+ .channels = ad7779_channels,
+};
+
+static const struct ad7779_chip_info ad7771_chip_info = {
+ .name = "ad7771",
+ .channels = ad7779_channels_filter,
+};
+
+static const struct ad7779_chip_info ad7779_chip_info = {
+ .name = "ad7779",
+ .channels = ad7779_channels,
+};
+
+static const struct spi_device_id ad7779_id[] = {
+ {
+ .name = "ad7770",
+ .driver_data = (kernel_ulong_t)&ad7770_chip_info,
+ },
+ {
+ .name = "ad7771",
+ .driver_data = (kernel_ulong_t)&ad7771_chip_info,
+ },
+ {
+ .name = "ad7779",
+ .driver_data = (kernel_ulong_t)&ad7779_chip_info,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ad7779_id);
+
+static const struct of_device_id ad7779_of_table[] = {
+ {
+ .compatible = "adi,ad7770",
+ .data = &ad7770_chip_info,
+ },
+ {
+ .compatible = "adi,ad7771",
+ .data = &ad7771_chip_info,
+ },
+ {
+ .compatible = "adi,ad7779",
+ .data = &ad7779_chip_info,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad7779_of_table);
+
+static struct spi_driver ad7779_driver = {
+ .driver = {
+ .name = "ad7779",
+ .pm = pm_sleep_ptr(&ad7779_pm_ops),
+ .of_match_table = ad7779_of_table,
+ },
+ .probe = ad7779_probe,
+ .id_table = ad7779_id,
+};
+module_spi_driver(ad7779_driver);
+
+MODULE_AUTHOR("Ramona Alexandra Nechita <ramona.nechita@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD7779 ADC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c
index 0f107e3fc2c8..aa44b4e2542b 100644
--- a/drivers/iio/adc/ad799x.c
+++ b/drivers/iio/adc/ad799x.c
@@ -406,7 +406,7 @@ static int ad799x_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
- int state)
+ bool state)
{
struct ad799x_state *st = iio_priv(indio_dev);
int ret;
diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c
index fb635a756440..689e34f06987 100644
--- a/drivers/iio/adc/hi8435.c
+++ b/drivers/iio/adc/hi8435.c
@@ -132,7 +132,7 @@ static int hi8435_read_event_config(struct iio_dev *idev,
static int hi8435_write_event_config(struct iio_dev *idev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
- enum iio_event_direction dir, int state)
+ enum iio_event_direction dir, bool state)
{
struct hi8435_priv *priv = iio_priv(idev);
int ret;
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c
index 8da2d8d7a9c6..9a0baea08ab6 100644
--- a/drivers/iio/adc/max1363.c
+++ b/drivers/iio/adc/max1363.c
@@ -944,7 +944,7 @@ error_ret:
static int max1363_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
- enum iio_event_direction dir, int state)
+ enum iio_event_direction dir, bool state)
{
struct max1363_state *st = iio_priv(indio_dev);
diff --git a/drivers/iio/adc/pac1921.c b/drivers/iio/adc/pac1921.c
index a96fae546bc1..b0f6727cfe38 100644
--- a/drivers/iio/adc/pac1921.c
+++ b/drivers/iio/adc/pac1921.c
@@ -699,7 +699,8 @@ static int pac1921_read_event_config(struct iio_dev *indio_dev,
static int pac1921_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
- enum iio_event_direction dir, int state)
+ enum iio_event_direction dir,
+ bool state)
{
struct pac1921_priv *priv = iio_priv(indio_dev);
u8 ovf_bit;
@@ -1170,7 +1171,9 @@ static int pac1921_probe(struct i2c_client *client)
return dev_err_probe(dev, PTR_ERR(priv->regmap),
"Cannot initialize register map\n");
- devm_mutex_init(dev, &priv->lock);
+ ret = devm_mutex_init(dev, &priv->lock);
+ if (ret)
+ return ret;
priv->dv_gain = PAC1921_DEFAULT_DV_GAIN;
priv->di_gain = PAC1921_DEFAULT_DI_GAIN;
diff --git a/drivers/iio/adc/pac1934.c b/drivers/iio/adc/pac1934.c
index 7ef249d83286..20802b7f49ea 100644
--- a/drivers/iio/adc/pac1934.c
+++ b/drivers/iio/adc/pac1934.c
@@ -1507,7 +1507,7 @@ static int pac1934_probe(struct i2c_client *client)
indio_dev->name = pac1934_chip_config[ret].name;
}
- if (acpi_match_device(dev->driver->acpi_match_table, dev))
+ if (is_acpi_device_node(dev_fwnode(dev)))
ret = pac1934_acpi_parse_channel_config(client, info);
else
/*
diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c
index 67d567ee21b4..d283ee8fb1d2 100644
--- a/drivers/iio/adc/palmas_gpadc.c
+++ b/drivers/iio/adc/palmas_gpadc.c
@@ -676,7 +676,7 @@ static int palmas_gpadc_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
- int state)
+ bool state)
{
struct palmas_gpadc *adc = iio_priv(indio_dev);
int adc_chan = chan->channel;
diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c
index 052d2124b215..47fe8e16aee4 100644
--- a/drivers/iio/adc/ti-ads1015.c
+++ b/drivers/iio/adc/ti-ads1015.c
@@ -806,7 +806,7 @@ static int ads1015_disable_event_config(struct ads1015_data *data,
static int ads1015_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
- enum iio_event_direction dir, int state)
+ enum iio_event_direction dir, bool state)
{
struct ads1015_data *data = iio_priv(indio_dev);
int ret;
diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c
index ebc583b07e0c..76dd0343f5f7 100644
--- a/drivers/iio/adc/xilinx-ams.c
+++ b/drivers/iio/adc/xilinx-ams.c
@@ -905,7 +905,7 @@ static int ams_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
- int state)
+ bool state)
{
struct ams *ams = iio_priv(indio_dev);
unsigned int alarm;
diff --git a/drivers/iio/adc/xilinx-xadc-events.c b/drivers/iio/adc/xilinx-xadc-events.c
index 90f62377c34d..c188d3dcab48 100644
--- a/drivers/iio/adc/xilinx-xadc-events.c
+++ b/drivers/iio/adc/xilinx-xadc-events.c
@@ -121,7 +121,7 @@ int xadc_read_event_config(struct iio_dev *indio_dev,
int xadc_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
- enum iio_event_direction dir, int state)
+ enum iio_event_direction dir, bool state)
{
unsigned int alarm = xadc_get_alarm_mask(chan);
struct xadc *xadc = iio_priv(indio_dev);
diff --git a/drivers/iio/adc/xilinx-xadc.h b/drivers/iio/adc/xilinx-xadc.h
index 3036f4d613ff..b4d9d4683117 100644
--- a/drivers/iio/adc/xilinx-xadc.h
+++ b/drivers/iio/adc/xilinx-xadc.h
@@ -25,7 +25,7 @@ int xadc_read_event_config(struct iio_dev *indio_dev,
enum iio_event_direction dir);
int xadc_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
- enum iio_event_direction dir, int state);
+ enum iio_event_direction dir, bool state);
int xadc_read_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, enum iio_event_info info,