diff options
author | Nuno Sa <nuno.sa@analog.com> | 2024-07-04 11:25:21 +0200 |
---|---|---|
committer | Jonathan Cameron <Jonathan.Cameron@huawei.com> | 2024-07-29 21:31:11 +0200 |
commit | 7394a155dd1215ce20fd2a562ff537929b0f86d5 (patch) | |
tree | ddb4f3460a12800b724d3f986cb231d9c8b39e80 /drivers/iio | |
parent | iio: adc: ti-tsc2046: simplify with cleanup.h (diff) | |
download | linux-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.c | 115 |
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) { |