162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Support code for Analog Devices Sigma-Delta ADCs
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2012 Analog Devices Inc.
662306a36Sopenharmony_ci *  Author: Lars-Peter Clausen <lars@metafoo.de>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/align.h>
1062306a36Sopenharmony_ci#include <linux/interrupt.h>
1162306a36Sopenharmony_ci#include <linux/device.h>
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/slab.h>
1462306a36Sopenharmony_ci#include <linux/spi/spi.h>
1562306a36Sopenharmony_ci#include <linux/err.h>
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <linux/iio/iio.h>
1962306a36Sopenharmony_ci#include <linux/iio/sysfs.h>
2062306a36Sopenharmony_ci#include <linux/iio/buffer.h>
2162306a36Sopenharmony_ci#include <linux/iio/trigger.h>
2262306a36Sopenharmony_ci#include <linux/iio/trigger_consumer.h>
2362306a36Sopenharmony_ci#include <linux/iio/triggered_buffer.h>
2462306a36Sopenharmony_ci#include <linux/iio/adc/ad_sigma_delta.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include <asm/unaligned.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define AD_SD_COMM_CHAN_MASK	0x3
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define AD_SD_REG_COMM		0x00
3262306a36Sopenharmony_ci#define AD_SD_REG_DATA		0x03
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/**
3562306a36Sopenharmony_ci * ad_sd_set_comm() - Set communications register
3662306a36Sopenharmony_ci *
3762306a36Sopenharmony_ci * @sigma_delta: The sigma delta device
3862306a36Sopenharmony_ci * @comm: New value for the communications register
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_civoid ad_sd_set_comm(struct ad_sigma_delta *sigma_delta, uint8_t comm)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	/* Some variants use the lower two bits of the communications register
4362306a36Sopenharmony_ci	 * to select the channel */
4462306a36Sopenharmony_ci	sigma_delta->comm = comm & AD_SD_COMM_CHAN_MASK;
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(ad_sd_set_comm, IIO_AD_SIGMA_DELTA);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/**
4962306a36Sopenharmony_ci * ad_sd_write_reg() - Write a register
5062306a36Sopenharmony_ci *
5162306a36Sopenharmony_ci * @sigma_delta: The sigma delta device
5262306a36Sopenharmony_ci * @reg: Address of the register
5362306a36Sopenharmony_ci * @size: Size of the register (0-3)
5462306a36Sopenharmony_ci * @val: Value to write to the register
5562306a36Sopenharmony_ci *
5662306a36Sopenharmony_ci * Returns 0 on success, an error code otherwise.
5762306a36Sopenharmony_ci **/
5862306a36Sopenharmony_ciint ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
5962306a36Sopenharmony_ci	unsigned int size, unsigned int val)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	uint8_t *data = sigma_delta->tx_buf;
6262306a36Sopenharmony_ci	struct spi_transfer t = {
6362306a36Sopenharmony_ci		.tx_buf		= data,
6462306a36Sopenharmony_ci		.len		= size + 1,
6562306a36Sopenharmony_ci		.cs_change	= sigma_delta->keep_cs_asserted,
6662306a36Sopenharmony_ci	};
6762306a36Sopenharmony_ci	struct spi_message m;
6862306a36Sopenharmony_ci	int ret;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	data[0] = (reg << sigma_delta->info->addr_shift) | sigma_delta->comm;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	switch (size) {
7362306a36Sopenharmony_ci	case 3:
7462306a36Sopenharmony_ci		put_unaligned_be24(val, &data[1]);
7562306a36Sopenharmony_ci		break;
7662306a36Sopenharmony_ci	case 2:
7762306a36Sopenharmony_ci		put_unaligned_be16(val, &data[1]);
7862306a36Sopenharmony_ci		break;
7962306a36Sopenharmony_ci	case 1:
8062306a36Sopenharmony_ci		data[1] = val;
8162306a36Sopenharmony_ci		break;
8262306a36Sopenharmony_ci	case 0:
8362306a36Sopenharmony_ci		break;
8462306a36Sopenharmony_ci	default:
8562306a36Sopenharmony_ci		return -EINVAL;
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	spi_message_init(&m);
8962306a36Sopenharmony_ci	spi_message_add_tail(&t, &m);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	if (sigma_delta->bus_locked)
9262306a36Sopenharmony_ci		ret = spi_sync_locked(sigma_delta->spi, &m);
9362306a36Sopenharmony_ci	else
9462306a36Sopenharmony_ci		ret = spi_sync(sigma_delta->spi, &m);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	return ret;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(ad_sd_write_reg, IIO_AD_SIGMA_DELTA);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic int ad_sd_read_reg_raw(struct ad_sigma_delta *sigma_delta,
10162306a36Sopenharmony_ci	unsigned int reg, unsigned int size, uint8_t *val)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	uint8_t *data = sigma_delta->tx_buf;
10462306a36Sopenharmony_ci	int ret;
10562306a36Sopenharmony_ci	struct spi_transfer t[] = {
10662306a36Sopenharmony_ci		{
10762306a36Sopenharmony_ci			.tx_buf = data,
10862306a36Sopenharmony_ci			.len = 1,
10962306a36Sopenharmony_ci		}, {
11062306a36Sopenharmony_ci			.rx_buf = val,
11162306a36Sopenharmony_ci			.len = size,
11262306a36Sopenharmony_ci			.cs_change = sigma_delta->bus_locked,
11362306a36Sopenharmony_ci		},
11462306a36Sopenharmony_ci	};
11562306a36Sopenharmony_ci	struct spi_message m;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	spi_message_init(&m);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	if (sigma_delta->info->has_registers) {
12062306a36Sopenharmony_ci		data[0] = reg << sigma_delta->info->addr_shift;
12162306a36Sopenharmony_ci		data[0] |= sigma_delta->info->read_mask;
12262306a36Sopenharmony_ci		data[0] |= sigma_delta->comm;
12362306a36Sopenharmony_ci		spi_message_add_tail(&t[0], &m);
12462306a36Sopenharmony_ci	}
12562306a36Sopenharmony_ci	spi_message_add_tail(&t[1], &m);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	if (sigma_delta->bus_locked)
12862306a36Sopenharmony_ci		ret = spi_sync_locked(sigma_delta->spi, &m);
12962306a36Sopenharmony_ci	else
13062306a36Sopenharmony_ci		ret = spi_sync(sigma_delta->spi, &m);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	return ret;
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci/**
13662306a36Sopenharmony_ci * ad_sd_read_reg() - Read a register
13762306a36Sopenharmony_ci *
13862306a36Sopenharmony_ci * @sigma_delta: The sigma delta device
13962306a36Sopenharmony_ci * @reg: Address of the register
14062306a36Sopenharmony_ci * @size: Size of the register (1-4)
14162306a36Sopenharmony_ci * @val: Read value
14262306a36Sopenharmony_ci *
14362306a36Sopenharmony_ci * Returns 0 on success, an error code otherwise.
14462306a36Sopenharmony_ci **/
14562306a36Sopenharmony_ciint ad_sd_read_reg(struct ad_sigma_delta *sigma_delta,
14662306a36Sopenharmony_ci	unsigned int reg, unsigned int size, unsigned int *val)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	int ret;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	ret = ad_sd_read_reg_raw(sigma_delta, reg, size, sigma_delta->rx_buf);
15162306a36Sopenharmony_ci	if (ret < 0)
15262306a36Sopenharmony_ci		goto out;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	switch (size) {
15562306a36Sopenharmony_ci	case 4:
15662306a36Sopenharmony_ci		*val = get_unaligned_be32(sigma_delta->rx_buf);
15762306a36Sopenharmony_ci		break;
15862306a36Sopenharmony_ci	case 3:
15962306a36Sopenharmony_ci		*val = get_unaligned_be24(sigma_delta->rx_buf);
16062306a36Sopenharmony_ci		break;
16162306a36Sopenharmony_ci	case 2:
16262306a36Sopenharmony_ci		*val = get_unaligned_be16(sigma_delta->rx_buf);
16362306a36Sopenharmony_ci		break;
16462306a36Sopenharmony_ci	case 1:
16562306a36Sopenharmony_ci		*val = sigma_delta->rx_buf[0];
16662306a36Sopenharmony_ci		break;
16762306a36Sopenharmony_ci	default:
16862306a36Sopenharmony_ci		ret = -EINVAL;
16962306a36Sopenharmony_ci		break;
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ciout:
17362306a36Sopenharmony_ci	return ret;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(ad_sd_read_reg, IIO_AD_SIGMA_DELTA);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci/**
17862306a36Sopenharmony_ci * ad_sd_reset() - Reset the serial interface
17962306a36Sopenharmony_ci *
18062306a36Sopenharmony_ci * @sigma_delta: The sigma delta device
18162306a36Sopenharmony_ci * @reset_length: Number of SCLKs with DIN = 1
18262306a36Sopenharmony_ci *
18362306a36Sopenharmony_ci * Returns 0 on success, an error code otherwise.
18462306a36Sopenharmony_ci **/
18562306a36Sopenharmony_ciint ad_sd_reset(struct ad_sigma_delta *sigma_delta,
18662306a36Sopenharmony_ci	unsigned int reset_length)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	uint8_t *buf;
18962306a36Sopenharmony_ci	unsigned int size;
19062306a36Sopenharmony_ci	int ret;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	size = DIV_ROUND_UP(reset_length, 8);
19362306a36Sopenharmony_ci	buf = kcalloc(size, sizeof(*buf), GFP_KERNEL);
19462306a36Sopenharmony_ci	if (!buf)
19562306a36Sopenharmony_ci		return -ENOMEM;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	memset(buf, 0xff, size);
19862306a36Sopenharmony_ci	ret = spi_write(sigma_delta->spi, buf, size);
19962306a36Sopenharmony_ci	kfree(buf);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	return ret;
20262306a36Sopenharmony_ci}
20362306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(ad_sd_reset, IIO_AD_SIGMA_DELTA);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ciint ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
20662306a36Sopenharmony_ci	unsigned int mode, unsigned int channel)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	int ret;
20962306a36Sopenharmony_ci	unsigned long timeout;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	ret = ad_sigma_delta_set_channel(sigma_delta, channel);
21262306a36Sopenharmony_ci	if (ret)
21362306a36Sopenharmony_ci		return ret;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	spi_bus_lock(sigma_delta->spi->master);
21662306a36Sopenharmony_ci	sigma_delta->bus_locked = true;
21762306a36Sopenharmony_ci	sigma_delta->keep_cs_asserted = true;
21862306a36Sopenharmony_ci	reinit_completion(&sigma_delta->completion);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	ret = ad_sigma_delta_set_mode(sigma_delta, mode);
22162306a36Sopenharmony_ci	if (ret < 0)
22262306a36Sopenharmony_ci		goto out;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	sigma_delta->irq_dis = false;
22562306a36Sopenharmony_ci	enable_irq(sigma_delta->spi->irq);
22662306a36Sopenharmony_ci	timeout = wait_for_completion_timeout(&sigma_delta->completion, 2 * HZ);
22762306a36Sopenharmony_ci	if (timeout == 0) {
22862306a36Sopenharmony_ci		sigma_delta->irq_dis = true;
22962306a36Sopenharmony_ci		disable_irq_nosync(sigma_delta->spi->irq);
23062306a36Sopenharmony_ci		ret = -EIO;
23162306a36Sopenharmony_ci	} else {
23262306a36Sopenharmony_ci		ret = 0;
23362306a36Sopenharmony_ci	}
23462306a36Sopenharmony_ciout:
23562306a36Sopenharmony_ci	sigma_delta->keep_cs_asserted = false;
23662306a36Sopenharmony_ci	ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
23762306a36Sopenharmony_ci	sigma_delta->bus_locked = false;
23862306a36Sopenharmony_ci	spi_bus_unlock(sigma_delta->spi->master);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	return ret;
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(ad_sd_calibrate, IIO_AD_SIGMA_DELTA);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci/**
24562306a36Sopenharmony_ci * ad_sd_calibrate_all() - Performs channel calibration
24662306a36Sopenharmony_ci * @sigma_delta: The sigma delta device
24762306a36Sopenharmony_ci * @cb: Array of channels and calibration type to perform
24862306a36Sopenharmony_ci * @n: Number of items in cb
24962306a36Sopenharmony_ci *
25062306a36Sopenharmony_ci * Returns 0 on success, an error code otherwise.
25162306a36Sopenharmony_ci **/
25262306a36Sopenharmony_ciint ad_sd_calibrate_all(struct ad_sigma_delta *sigma_delta,
25362306a36Sopenharmony_ci	const struct ad_sd_calib_data *cb, unsigned int n)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	unsigned int i;
25662306a36Sopenharmony_ci	int ret;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	for (i = 0; i < n; i++) {
25962306a36Sopenharmony_ci		ret = ad_sd_calibrate(sigma_delta, cb[i].mode, cb[i].channel);
26062306a36Sopenharmony_ci		if (ret)
26162306a36Sopenharmony_ci			return ret;
26262306a36Sopenharmony_ci	}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	return 0;
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(ad_sd_calibrate_all, IIO_AD_SIGMA_DELTA);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci/**
26962306a36Sopenharmony_ci * ad_sigma_delta_single_conversion() - Performs a single data conversion
27062306a36Sopenharmony_ci * @indio_dev: The IIO device
27162306a36Sopenharmony_ci * @chan: The conversion is done for this channel
27262306a36Sopenharmony_ci * @val: Pointer to the location where to store the read value
27362306a36Sopenharmony_ci *
27462306a36Sopenharmony_ci * Returns: 0 on success, an error value otherwise.
27562306a36Sopenharmony_ci */
27662306a36Sopenharmony_ciint ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
27762306a36Sopenharmony_ci	const struct iio_chan_spec *chan, int *val)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
28062306a36Sopenharmony_ci	unsigned int sample, raw_sample;
28162306a36Sopenharmony_ci	unsigned int data_reg;
28262306a36Sopenharmony_ci	int ret = 0;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	ret = iio_device_claim_direct_mode(indio_dev);
28562306a36Sopenharmony_ci	if (ret)
28662306a36Sopenharmony_ci		return ret;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	ad_sigma_delta_set_channel(sigma_delta, chan->address);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	spi_bus_lock(sigma_delta->spi->master);
29162306a36Sopenharmony_ci	sigma_delta->bus_locked = true;
29262306a36Sopenharmony_ci	sigma_delta->keep_cs_asserted = true;
29362306a36Sopenharmony_ci	reinit_completion(&sigma_delta->completion);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_SINGLE);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	sigma_delta->irq_dis = false;
29862306a36Sopenharmony_ci	enable_irq(sigma_delta->spi->irq);
29962306a36Sopenharmony_ci	ret = wait_for_completion_interruptible_timeout(
30062306a36Sopenharmony_ci			&sigma_delta->completion, HZ);
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	if (ret == 0)
30362306a36Sopenharmony_ci		ret = -EIO;
30462306a36Sopenharmony_ci	if (ret < 0)
30562306a36Sopenharmony_ci		goto out;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	if (sigma_delta->info->data_reg != 0)
30862306a36Sopenharmony_ci		data_reg = sigma_delta->info->data_reg;
30962306a36Sopenharmony_ci	else
31062306a36Sopenharmony_ci		data_reg = AD_SD_REG_DATA;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	ret = ad_sd_read_reg(sigma_delta, data_reg,
31362306a36Sopenharmony_ci		DIV_ROUND_UP(chan->scan_type.realbits + chan->scan_type.shift, 8),
31462306a36Sopenharmony_ci		&raw_sample);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ciout:
31762306a36Sopenharmony_ci	if (!sigma_delta->irq_dis) {
31862306a36Sopenharmony_ci		disable_irq_nosync(sigma_delta->spi->irq);
31962306a36Sopenharmony_ci		sigma_delta->irq_dis = true;
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	sigma_delta->keep_cs_asserted = false;
32362306a36Sopenharmony_ci	ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
32462306a36Sopenharmony_ci	sigma_delta->bus_locked = false;
32562306a36Sopenharmony_ci	spi_bus_unlock(sigma_delta->spi->master);
32662306a36Sopenharmony_ci	iio_device_release_direct_mode(indio_dev);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	if (ret)
32962306a36Sopenharmony_ci		return ret;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	sample = raw_sample >> chan->scan_type.shift;
33262306a36Sopenharmony_ci	sample &= (1 << chan->scan_type.realbits) - 1;
33362306a36Sopenharmony_ci	*val = sample;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	ret = ad_sigma_delta_postprocess_sample(sigma_delta, raw_sample);
33662306a36Sopenharmony_ci	if (ret)
33762306a36Sopenharmony_ci		return ret;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	return IIO_VAL_INT;
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(ad_sigma_delta_single_conversion, IIO_AD_SIGMA_DELTA);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
34662306a36Sopenharmony_ci	unsigned int i, slot, samples_buf_size;
34762306a36Sopenharmony_ci	unsigned int channel;
34862306a36Sopenharmony_ci	uint8_t *samples_buf;
34962306a36Sopenharmony_ci	int ret;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	if (sigma_delta->num_slots == 1) {
35262306a36Sopenharmony_ci		channel = find_first_bit(indio_dev->active_scan_mask,
35362306a36Sopenharmony_ci					 indio_dev->masklength);
35462306a36Sopenharmony_ci		ret = ad_sigma_delta_set_channel(sigma_delta,
35562306a36Sopenharmony_ci						 indio_dev->channels[channel].address);
35662306a36Sopenharmony_ci		if (ret)
35762306a36Sopenharmony_ci			return ret;
35862306a36Sopenharmony_ci		slot = 1;
35962306a36Sopenharmony_ci	} else {
36062306a36Sopenharmony_ci		/*
36162306a36Sopenharmony_ci		 * At this point update_scan_mode already enabled the required channels.
36262306a36Sopenharmony_ci		 * For sigma-delta sequencer drivers with multiple slots, an update_scan_mode
36362306a36Sopenharmony_ci		 * implementation is mandatory.
36462306a36Sopenharmony_ci		 */
36562306a36Sopenharmony_ci		slot = 0;
36662306a36Sopenharmony_ci		for_each_set_bit(i, indio_dev->active_scan_mask, indio_dev->masklength) {
36762306a36Sopenharmony_ci			sigma_delta->slots[slot] = indio_dev->channels[i].address;
36862306a36Sopenharmony_ci			slot++;
36962306a36Sopenharmony_ci		}
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	sigma_delta->active_slots = slot;
37362306a36Sopenharmony_ci	sigma_delta->current_slot = 0;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	if (sigma_delta->active_slots > 1) {
37662306a36Sopenharmony_ci		ret = ad_sigma_delta_append_status(sigma_delta, true);
37762306a36Sopenharmony_ci		if (ret)
37862306a36Sopenharmony_ci			return ret;
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	samples_buf_size = ALIGN(slot * indio_dev->channels[0].scan_type.storagebits, 8);
38262306a36Sopenharmony_ci	samples_buf_size += sizeof(int64_t);
38362306a36Sopenharmony_ci	samples_buf = devm_krealloc(&sigma_delta->spi->dev, sigma_delta->samples_buf,
38462306a36Sopenharmony_ci				    samples_buf_size, GFP_KERNEL);
38562306a36Sopenharmony_ci	if (!samples_buf)
38662306a36Sopenharmony_ci		return -ENOMEM;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	sigma_delta->samples_buf = samples_buf;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	spi_bus_lock(sigma_delta->spi->master);
39162306a36Sopenharmony_ci	sigma_delta->bus_locked = true;
39262306a36Sopenharmony_ci	sigma_delta->keep_cs_asserted = true;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	ret = ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_CONTINUOUS);
39562306a36Sopenharmony_ci	if (ret)
39662306a36Sopenharmony_ci		goto err_unlock;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	sigma_delta->irq_dis = false;
39962306a36Sopenharmony_ci	enable_irq(sigma_delta->spi->irq);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	return 0;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cierr_unlock:
40462306a36Sopenharmony_ci	spi_bus_unlock(sigma_delta->spi->master);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	return ret;
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_cistatic int ad_sd_buffer_postdisable(struct iio_dev *indio_dev)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	reinit_completion(&sigma_delta->completion);
41462306a36Sopenharmony_ci	wait_for_completion_timeout(&sigma_delta->completion, HZ);
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	if (!sigma_delta->irq_dis) {
41762306a36Sopenharmony_ci		disable_irq_nosync(sigma_delta->spi->irq);
41862306a36Sopenharmony_ci		sigma_delta->irq_dis = true;
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	sigma_delta->keep_cs_asserted = false;
42262306a36Sopenharmony_ci	ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	if (sigma_delta->status_appended)
42562306a36Sopenharmony_ci		ad_sigma_delta_append_status(sigma_delta, false);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	ad_sigma_delta_disable_all(sigma_delta);
42862306a36Sopenharmony_ci	sigma_delta->bus_locked = false;
42962306a36Sopenharmony_ci	return spi_bus_unlock(sigma_delta->spi->master);
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_cistatic irqreturn_t ad_sd_trigger_handler(int irq, void *p)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	struct iio_poll_func *pf = p;
43562306a36Sopenharmony_ci	struct iio_dev *indio_dev = pf->indio_dev;
43662306a36Sopenharmony_ci	struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
43762306a36Sopenharmony_ci	uint8_t *data = sigma_delta->rx_buf;
43862306a36Sopenharmony_ci	unsigned int transfer_size;
43962306a36Sopenharmony_ci	unsigned int sample_size;
44062306a36Sopenharmony_ci	unsigned int sample_pos;
44162306a36Sopenharmony_ci	unsigned int status_pos;
44262306a36Sopenharmony_ci	unsigned int reg_size;
44362306a36Sopenharmony_ci	unsigned int data_reg;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	reg_size = indio_dev->channels[0].scan_type.realbits +
44662306a36Sopenharmony_ci			indio_dev->channels[0].scan_type.shift;
44762306a36Sopenharmony_ci	reg_size = DIV_ROUND_UP(reg_size, 8);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	if (sigma_delta->info->data_reg != 0)
45062306a36Sopenharmony_ci		data_reg = sigma_delta->info->data_reg;
45162306a36Sopenharmony_ci	else
45262306a36Sopenharmony_ci		data_reg = AD_SD_REG_DATA;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	/* Status word will be appended to the sample during transfer */
45562306a36Sopenharmony_ci	if (sigma_delta->status_appended)
45662306a36Sopenharmony_ci		transfer_size = reg_size + 1;
45762306a36Sopenharmony_ci	else
45862306a36Sopenharmony_ci		transfer_size = reg_size;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	switch (reg_size) {
46162306a36Sopenharmony_ci	case 4:
46262306a36Sopenharmony_ci	case 2:
46362306a36Sopenharmony_ci	case 1:
46462306a36Sopenharmony_ci		status_pos = reg_size;
46562306a36Sopenharmony_ci		ad_sd_read_reg_raw(sigma_delta, data_reg, transfer_size, &data[0]);
46662306a36Sopenharmony_ci		break;
46762306a36Sopenharmony_ci	case 3:
46862306a36Sopenharmony_ci		/*
46962306a36Sopenharmony_ci		 * Data array after transfer will look like (if status is appended):
47062306a36Sopenharmony_ci		 * data[] = { [0][sample][sample][sample][status] }
47162306a36Sopenharmony_ci		 * Keeping the first byte 0 shifts the status postion by 1 byte to the right.
47262306a36Sopenharmony_ci		 */
47362306a36Sopenharmony_ci		status_pos = reg_size + 1;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci		/* We store 24 bit samples in a 32 bit word. Keep the upper
47662306a36Sopenharmony_ci		 * byte set to zero. */
47762306a36Sopenharmony_ci		ad_sd_read_reg_raw(sigma_delta, data_reg, transfer_size, &data[1]);
47862306a36Sopenharmony_ci		break;
47962306a36Sopenharmony_ci	}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	/*
48262306a36Sopenharmony_ci	 * For devices sampling only one channel at
48362306a36Sopenharmony_ci	 * once, there is no need for sample number tracking.
48462306a36Sopenharmony_ci	 */
48562306a36Sopenharmony_ci	if (sigma_delta->active_slots == 1) {
48662306a36Sopenharmony_ci		iio_push_to_buffers_with_timestamp(indio_dev, data, pf->timestamp);
48762306a36Sopenharmony_ci		goto irq_handled;
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (sigma_delta->status_appended) {
49162306a36Sopenharmony_ci		u8 converted_channel;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci		converted_channel = data[status_pos] & sigma_delta->info->status_ch_mask;
49462306a36Sopenharmony_ci		if (converted_channel != sigma_delta->slots[sigma_delta->current_slot]) {
49562306a36Sopenharmony_ci			/*
49662306a36Sopenharmony_ci			 * Desync occurred during continuous sampling of multiple channels.
49762306a36Sopenharmony_ci			 * Drop this incomplete sample and start from first channel again.
49862306a36Sopenharmony_ci			 */
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci			sigma_delta->current_slot = 0;
50162306a36Sopenharmony_ci			goto irq_handled;
50262306a36Sopenharmony_ci		}
50362306a36Sopenharmony_ci	}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	sample_size = indio_dev->channels[0].scan_type.storagebits / 8;
50662306a36Sopenharmony_ci	sample_pos = sample_size * sigma_delta->current_slot;
50762306a36Sopenharmony_ci	memcpy(&sigma_delta->samples_buf[sample_pos], data, sample_size);
50862306a36Sopenharmony_ci	sigma_delta->current_slot++;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	if (sigma_delta->current_slot == sigma_delta->active_slots) {
51162306a36Sopenharmony_ci		sigma_delta->current_slot = 0;
51262306a36Sopenharmony_ci		iio_push_to_buffers_with_timestamp(indio_dev, sigma_delta->samples_buf,
51362306a36Sopenharmony_ci						   pf->timestamp);
51462306a36Sopenharmony_ci	}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ciirq_handled:
51762306a36Sopenharmony_ci	iio_trigger_notify_done(indio_dev->trig);
51862306a36Sopenharmony_ci	sigma_delta->irq_dis = false;
51962306a36Sopenharmony_ci	enable_irq(sigma_delta->spi->irq);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	return IRQ_HANDLED;
52262306a36Sopenharmony_ci}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_cistatic bool ad_sd_validate_scan_mask(struct iio_dev *indio_dev, const unsigned long *mask)
52562306a36Sopenharmony_ci{
52662306a36Sopenharmony_ci	struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	return bitmap_weight(mask, indio_dev->masklength) <= sigma_delta->num_slots;
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistatic const struct iio_buffer_setup_ops ad_sd_buffer_setup_ops = {
53262306a36Sopenharmony_ci	.postenable = &ad_sd_buffer_postenable,
53362306a36Sopenharmony_ci	.postdisable = &ad_sd_buffer_postdisable,
53462306a36Sopenharmony_ci	.validate_scan_mask = &ad_sd_validate_scan_mask,
53562306a36Sopenharmony_ci};
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_cistatic irqreturn_t ad_sd_data_rdy_trig_poll(int irq, void *private)
53862306a36Sopenharmony_ci{
53962306a36Sopenharmony_ci	struct ad_sigma_delta *sigma_delta = private;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	complete(&sigma_delta->completion);
54262306a36Sopenharmony_ci	disable_irq_nosync(irq);
54362306a36Sopenharmony_ci	sigma_delta->irq_dis = true;
54462306a36Sopenharmony_ci	iio_trigger_poll(sigma_delta->trig);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	return IRQ_HANDLED;
54762306a36Sopenharmony_ci}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci/**
55062306a36Sopenharmony_ci * ad_sd_validate_trigger() - validate_trigger callback for ad_sigma_delta devices
55162306a36Sopenharmony_ci * @indio_dev: The IIO device
55262306a36Sopenharmony_ci * @trig: The new trigger
55362306a36Sopenharmony_ci *
55462306a36Sopenharmony_ci * Returns: 0 if the 'trig' matches the trigger registered by the ad_sigma_delta
55562306a36Sopenharmony_ci * device, -EINVAL otherwise.
55662306a36Sopenharmony_ci */
55762306a36Sopenharmony_ciint ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig)
55862306a36Sopenharmony_ci{
55962306a36Sopenharmony_ci	struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	if (sigma_delta->trig != trig)
56262306a36Sopenharmony_ci		return -EINVAL;
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	return 0;
56562306a36Sopenharmony_ci}
56662306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(ad_sd_validate_trigger, IIO_AD_SIGMA_DELTA);
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_cistatic int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_dev)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
57162306a36Sopenharmony_ci	int ret;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	if (dev != &sigma_delta->spi->dev) {
57462306a36Sopenharmony_ci		dev_err(dev, "Trigger parent should be '%s', got '%s'\n",
57562306a36Sopenharmony_ci			dev_name(dev), dev_name(&sigma_delta->spi->dev));
57662306a36Sopenharmony_ci		return -EFAULT;
57762306a36Sopenharmony_ci	}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	sigma_delta->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
58062306a36Sopenharmony_ci						   iio_device_id(indio_dev));
58162306a36Sopenharmony_ci	if (sigma_delta->trig == NULL)
58262306a36Sopenharmony_ci		return -ENOMEM;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	init_completion(&sigma_delta->completion);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	sigma_delta->irq_dis = true;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	/* the IRQ core clears IRQ_DISABLE_UNLAZY flag when freeing an IRQ */
58962306a36Sopenharmony_ci	irq_set_status_flags(sigma_delta->spi->irq, IRQ_DISABLE_UNLAZY);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	ret = devm_request_irq(dev, sigma_delta->spi->irq,
59262306a36Sopenharmony_ci			       ad_sd_data_rdy_trig_poll,
59362306a36Sopenharmony_ci			       sigma_delta->info->irq_flags | IRQF_NO_AUTOEN,
59462306a36Sopenharmony_ci			       indio_dev->name,
59562306a36Sopenharmony_ci			       sigma_delta);
59662306a36Sopenharmony_ci	if (ret)
59762306a36Sopenharmony_ci		return ret;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	iio_trigger_set_drvdata(sigma_delta->trig, sigma_delta);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	ret = devm_iio_trigger_register(dev, sigma_delta->trig);
60262306a36Sopenharmony_ci	if (ret)
60362306a36Sopenharmony_ci		return ret;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	/* select default trigger */
60662306a36Sopenharmony_ci	indio_dev->trig = iio_trigger_get(sigma_delta->trig);
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	return 0;
60962306a36Sopenharmony_ci}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci/**
61262306a36Sopenharmony_ci * devm_ad_sd_setup_buffer_and_trigger() - Device-managed buffer & trigger setup
61362306a36Sopenharmony_ci * @dev: Device object to which to bind the life-time of the resources attached
61462306a36Sopenharmony_ci * @indio_dev: The IIO device
61562306a36Sopenharmony_ci */
61662306a36Sopenharmony_ciint devm_ad_sd_setup_buffer_and_trigger(struct device *dev, struct iio_dev *indio_dev)
61762306a36Sopenharmony_ci{
61862306a36Sopenharmony_ci	struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
61962306a36Sopenharmony_ci	int ret;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	sigma_delta->slots = devm_kcalloc(dev, sigma_delta->num_slots,
62262306a36Sopenharmony_ci					  sizeof(*sigma_delta->slots), GFP_KERNEL);
62362306a36Sopenharmony_ci	if (!sigma_delta->slots)
62462306a36Sopenharmony_ci		return -ENOMEM;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
62762306a36Sopenharmony_ci					      &iio_pollfunc_store_time,
62862306a36Sopenharmony_ci					      &ad_sd_trigger_handler,
62962306a36Sopenharmony_ci					      &ad_sd_buffer_setup_ops);
63062306a36Sopenharmony_ci	if (ret)
63162306a36Sopenharmony_ci		return ret;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	return devm_ad_sd_probe_trigger(dev, indio_dev);
63462306a36Sopenharmony_ci}
63562306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(devm_ad_sd_setup_buffer_and_trigger, IIO_AD_SIGMA_DELTA);
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci/**
63862306a36Sopenharmony_ci * ad_sd_init() - Initializes a ad_sigma_delta struct
63962306a36Sopenharmony_ci * @sigma_delta: The ad_sigma_delta device
64062306a36Sopenharmony_ci * @indio_dev: The IIO device which the Sigma Delta device is used for
64162306a36Sopenharmony_ci * @spi: The SPI device for the ad_sigma_delta device
64262306a36Sopenharmony_ci * @info: Device specific callbacks and options
64362306a36Sopenharmony_ci *
64462306a36Sopenharmony_ci * This function needs to be called before any other operations are performed on
64562306a36Sopenharmony_ci * the ad_sigma_delta struct.
64662306a36Sopenharmony_ci */
64762306a36Sopenharmony_ciint ad_sd_init(struct ad_sigma_delta *sigma_delta, struct iio_dev *indio_dev,
64862306a36Sopenharmony_ci	struct spi_device *spi, const struct ad_sigma_delta_info *info)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	sigma_delta->spi = spi;
65162306a36Sopenharmony_ci	sigma_delta->info = info;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	/* If the field is unset in ad_sigma_delta_info, asume there can only be 1 slot. */
65462306a36Sopenharmony_ci	if (!info->num_slots)
65562306a36Sopenharmony_ci		sigma_delta->num_slots = 1;
65662306a36Sopenharmony_ci	else
65762306a36Sopenharmony_ci		sigma_delta->num_slots = info->num_slots;
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	if (sigma_delta->num_slots > 1) {
66062306a36Sopenharmony_ci		if (!indio_dev->info->update_scan_mode) {
66162306a36Sopenharmony_ci			dev_err(&spi->dev, "iio_dev lacks update_scan_mode().\n");
66262306a36Sopenharmony_ci			return -EINVAL;
66362306a36Sopenharmony_ci		}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci		if (!info->disable_all) {
66662306a36Sopenharmony_ci			dev_err(&spi->dev, "ad_sigma_delta_info lacks disable_all().\n");
66762306a36Sopenharmony_ci			return -EINVAL;
66862306a36Sopenharmony_ci		}
66962306a36Sopenharmony_ci	}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	iio_device_set_drvdata(indio_dev, sigma_delta);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	return 0;
67462306a36Sopenharmony_ci}
67562306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(ad_sd_init, IIO_AD_SIGMA_DELTA);
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ciMODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
67862306a36Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices Sigma-Delta ADCs");
67962306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
680