summaryrefslogtreecommitdiffstats
path: root/drivers/iio
diff options
context:
space:
mode:
authorNuno Sa <nuno.sa@analog.com>2024-07-04 11:25:21 +0200
committerJonathan Cameron <Jonathan.Cameron@huawei.com>2024-07-29 21:31:11 +0200
commit7394a155dd1215ce20fd2a562ff537929b0f86d5 (patch)
treeddb4f3460a12800b724d3f986cb231d9c8b39e80 /drivers/iio
parentiio: adc: ti-tsc2046: simplify with cleanup.h (diff)
downloadlinux-7394a155dd1215ce20fd2a562ff537929b0f86d5.tar.xz
linux-7394a155dd1215ce20fd2a562ff537929b0f86d5.zip
iio: adc: ad9467: support multiple channels calibration
The calibration process mixes the support for calibrating multiple channels with only having one channel. Some paths do have 'num_channels' into account while others don't. As of now, the driver only supports devices with one channel so the above is not really a problem. That said, we'll add support for devices with more than one channel, hence let's properly make the calibration process to work with it. Signed-off-by: Nuno Sa <nuno.sa@analog.com> Link: https://patch.msgid.link/20240704-dev-iio-ad9467-new-devs-v1-1-f1adfee921f7@analog.com Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Diffstat (limited to 'drivers/iio')
-rw-r--r--drivers/iio/adc/ad9467.c115
1 files changed, 75 insertions, 40 deletions
diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c
index 41c1b519c573..1d8270a5bccb 100644
--- a/drivers/iio/adc/ad9467.c
+++ b/drivers/iio/adc/ad9467.c
@@ -352,6 +352,34 @@ static int ad9467_outputmode_set(struct ad9467_state *st, unsigned int mode)
AN877_ADC_TRANSFER_SYNC);
}
+static int ad9467_testmode_set(struct ad9467_state *st, unsigned int chan,
+ unsigned int test_mode)
+{
+ int ret;
+
+ if (st->info->num_channels > 1) {
+ /* so that the test mode is only applied to one channel */
+ ret = ad9467_spi_write(st, AN877_ADC_REG_CHAN_INDEX, BIT(chan));
+ if (ret)
+ return ret;
+ }
+
+ ret = ad9467_spi_write(st, AN877_ADC_REG_TEST_IO, test_mode);
+ if (ret)
+ return ret;
+
+ if (st->info->num_channels > 1) {
+ /* go to default state where all channels get write commands */
+ ret = ad9467_spi_write(st, AN877_ADC_REG_CHAN_INDEX,
+ GENMASK(st->info->num_channels - 1, 0));
+ if (ret)
+ return ret;
+ }
+
+ return ad9467_spi_write(st, AN877_ADC_REG_TRANSFER,
+ AN877_ADC_TRANSFER_SYNC);
+}
+
static int ad9647_calibrate_prepare(struct ad9467_state *st)
{
struct iio_backend_data_fmt data = {
@@ -360,32 +388,30 @@ static int ad9647_calibrate_prepare(struct ad9467_state *st)
unsigned int c;
int ret;
- ret = ad9467_spi_write(st, AN877_ADC_REG_TEST_IO,
- AN877_ADC_TESTMODE_PN9_SEQ);
- if (ret)
- return ret;
-
- ret = ad9467_spi_write(st, AN877_ADC_REG_TRANSFER,
- AN877_ADC_TRANSFER_SYNC);
- if (ret)
- return ret;
-
ret = ad9467_outputmode_set(st, st->info->default_output_mode);
if (ret)
return ret;
for (c = 0; c < st->info->num_channels; c++) {
+ ret = ad9467_testmode_set(st, c, AN877_ADC_TESTMODE_PN9_SEQ);
+ if (ret)
+ return ret;
+
ret = iio_backend_data_format_set(st->back, c, &data);
if (ret)
return ret;
- }
- ret = iio_backend_test_pattern_set(st->back, 0,
- IIO_BACKEND_ADI_PRBS_9A);
- if (ret)
- return ret;
+ ret = iio_backend_test_pattern_set(st->back, c,
+ IIO_BACKEND_ADI_PRBS_9A);
+ if (ret)
+ return ret;
+
+ ret = iio_backend_chan_enable(st->back, c);
+ if (ret)
+ return ret;
+ }
- return iio_backend_chan_enable(st->back, 0);
+ return 0;
}
static int ad9647_calibrate_polarity_set(struct ad9467_state *st,
@@ -468,38 +494,32 @@ static int ad9647_calibrate_stop(struct ad9467_state *st)
unsigned int c, mode;
int ret;
- ret = iio_backend_chan_disable(st->back, 0);
- if (ret)
- return ret;
+ for (c = 0; c < st->info->num_channels; c++) {
+ ret = iio_backend_chan_disable(st->back, c);
+ if (ret)
+ return ret;
- ret = iio_backend_test_pattern_set(st->back, 0,
- IIO_BACKEND_NO_TEST_PATTERN);
- if (ret)
- return ret;
+ ret = iio_backend_test_pattern_set(st->back, c,
+ IIO_BACKEND_NO_TEST_PATTERN);
+ if (ret)
+ return ret;
- for (c = 0; c < st->info->num_channels; c++) {
ret = iio_backend_data_format_set(st->back, c, &data);
if (ret)
return ret;
+
+ ret = ad9467_testmode_set(st, c, AN877_ADC_TESTMODE_OFF);
+ if (ret)
+ return ret;
}
mode = st->info->default_output_mode | AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT;
- ret = ad9467_outputmode_set(st, mode);
- if (ret)
- return ret;
-
- ret = ad9467_spi_write(st, AN877_ADC_REG_TEST_IO,
- AN877_ADC_TESTMODE_OFF);
- if (ret)
- return ret;
-
- return ad9467_spi_write(st, AN877_ADC_REG_TRANSFER,
- AN877_ADC_TRANSFER_SYNC);
+ return ad9467_outputmode_set(st, mode);
}
static int ad9467_calibrate(struct ad9467_state *st)
{
- unsigned int point, val, inv_val, cnt, inv_cnt = 0;
+ unsigned int point, val, inv_val, cnt, inv_cnt = 0, c;
/*
* Half of the bitmap is for the inverted signal. The number of test
* points is the same though...
@@ -526,11 +546,26 @@ retune:
if (ret)
return ret;
- ret = iio_backend_chan_status(st->back, 0, &stat);
- if (ret)
- return ret;
+ for (c = 0; c < st->info->num_channels; c++) {
+ ret = iio_backend_chan_status(st->back, c, &stat);
+ if (ret)
+ return ret;
- __assign_bit(point + invert * test_points, st->calib_map, stat);
+ /*
+ * A point is considered valid if all channels report no
+ * error. If one reports an error, then we consider the
+ * point as invalid and we can break the loop right away.
+ */
+ if (stat) {
+ dev_dbg(dev, "Invalid point(%u, inv:%u) for CH:%u\n",
+ point, invert, c);
+ break;
+ }
+
+ if (c == st->info->num_channels - 1)
+ __clear_bit(point + invert * test_points,
+ st->calib_map);
+ }
}
if (!invert) {