Commit 7394a155 authored by Nuno Sa's avatar Nuno Sa Committed by Jonathan Cameron
Browse files

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: default avatarNuno Sa <nuno.sa@analog.com>
Link: https://patch.msgid.link/20240704-dev-iio-ad9467-new-devs-v1-1-f1adfee921f7@analog.com


Signed-off-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
parent 1de9c3c7
Loading
Loading
Loading
Loading
+75 −40
Original line number Diff line number Diff line
@@ -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);
	ret = ad9467_outputmode_set(st, st->info->default_output_mode);
	if (ret)
		return ret;

	ret = ad9467_spi_write(st, AN877_ADC_REG_TRANSFER,
			       AN877_ADC_TRANSFER_SYNC);
	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 = ad9467_outputmode_set(st, st->info->default_output_mode);
		ret = iio_backend_data_format_set(st->back, c, &data);
		if (ret)
			return ret;

	for (c = 0; c < st->info->num_channels; c++) {
		ret = iio_backend_data_format_set(st->back, c, &data);
		ret = iio_backend_test_pattern_set(st->back, c,
						   IIO_BACKEND_ADI_PRBS_9A);
		if (ret)
			return ret;
	}

	ret = iio_backend_test_pattern_set(st->back, 0,
					   IIO_BACKEND_ADI_PRBS_9A);
		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);
	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,
		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;
	}

	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);
		ret = ad9467_testmode_set(st, c, AN877_ADC_TESTMODE_OFF);
		if (ret)
			return ret;
	}

	return ad9467_spi_write(st, AN877_ADC_REG_TRANSFER,
			       AN877_ADC_TRANSFER_SYNC);
	mode = st->info->default_output_mode | AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT;
	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 @@ static int ad9467_calibrate(struct ad9467_state *st)
		if (ret)
			return ret;

		ret = iio_backend_chan_status(st->back, 0, &stat);
		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) {