162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2015 Prevas A/S
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/device.h>
762306a36Sopenharmony_ci#include <linux/kernel.h>
862306a36Sopenharmony_ci#include <linux/slab.h>
962306a36Sopenharmony_ci#include <linux/sysfs.h>
1062306a36Sopenharmony_ci#include <linux/spi/spi.h>
1162306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
1262306a36Sopenharmony_ci#include <linux/err.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/of.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <linux/iio/iio.h>
1762306a36Sopenharmony_ci#include <linux/iio/buffer.h>
1862306a36Sopenharmony_ci#include <linux/iio/trigger_consumer.h>
1962306a36Sopenharmony_ci#include <linux/iio/triggered_buffer.h>
2062306a36Sopenharmony_ci#include <linux/iio/sysfs.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define ADS8688_CMD_REG(x)		(x << 8)
2362306a36Sopenharmony_ci#define ADS8688_CMD_REG_NOOP		0x00
2462306a36Sopenharmony_ci#define ADS8688_CMD_REG_RST		0x85
2562306a36Sopenharmony_ci#define ADS8688_CMD_REG_MAN_CH(chan)	(0xC0 | (4 * chan))
2662306a36Sopenharmony_ci#define ADS8688_CMD_DONT_CARE_BITS	16
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define ADS8688_PROG_REG(x)		(x << 9)
2962306a36Sopenharmony_ci#define ADS8688_PROG_REG_RANGE_CH(chan)	(0x05 + chan)
3062306a36Sopenharmony_ci#define ADS8688_PROG_WR_BIT		BIT(8)
3162306a36Sopenharmony_ci#define ADS8688_PROG_DONT_CARE_BITS	8
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define ADS8688_REG_PLUSMINUS25VREF	0
3462306a36Sopenharmony_ci#define ADS8688_REG_PLUSMINUS125VREF	1
3562306a36Sopenharmony_ci#define ADS8688_REG_PLUSMINUS0625VREF	2
3662306a36Sopenharmony_ci#define ADS8688_REG_PLUS25VREF		5
3762306a36Sopenharmony_ci#define ADS8688_REG_PLUS125VREF		6
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#define ADS8688_VREF_MV			4096
4062306a36Sopenharmony_ci#define ADS8688_REALBITS		16
4162306a36Sopenharmony_ci#define ADS8688_MAX_CHANNELS		8
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/*
4462306a36Sopenharmony_ci * enum ads8688_range - ADS8688 reference voltage range
4562306a36Sopenharmony_ci * @ADS8688_PLUSMINUS25VREF: Device is configured for input range ±2.5 * VREF
4662306a36Sopenharmony_ci * @ADS8688_PLUSMINUS125VREF: Device is configured for input range ±1.25 * VREF
4762306a36Sopenharmony_ci * @ADS8688_PLUSMINUS0625VREF: Device is configured for input range ±0.625 * VREF
4862306a36Sopenharmony_ci * @ADS8688_PLUS25VREF: Device is configured for input range 0 - 2.5 * VREF
4962306a36Sopenharmony_ci * @ADS8688_PLUS125VREF: Device is configured for input range 0 - 1.25 * VREF
5062306a36Sopenharmony_ci */
5162306a36Sopenharmony_cienum ads8688_range {
5262306a36Sopenharmony_ci	ADS8688_PLUSMINUS25VREF,
5362306a36Sopenharmony_ci	ADS8688_PLUSMINUS125VREF,
5462306a36Sopenharmony_ci	ADS8688_PLUSMINUS0625VREF,
5562306a36Sopenharmony_ci	ADS8688_PLUS25VREF,
5662306a36Sopenharmony_ci	ADS8688_PLUS125VREF,
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistruct ads8688_chip_info {
6062306a36Sopenharmony_ci	const struct iio_chan_spec *channels;
6162306a36Sopenharmony_ci	unsigned int num_channels;
6262306a36Sopenharmony_ci};
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistruct ads8688_state {
6562306a36Sopenharmony_ci	struct mutex			lock;
6662306a36Sopenharmony_ci	const struct ads8688_chip_info	*chip_info;
6762306a36Sopenharmony_ci	struct spi_device		*spi;
6862306a36Sopenharmony_ci	struct regulator		*reg;
6962306a36Sopenharmony_ci	unsigned int			vref_mv;
7062306a36Sopenharmony_ci	enum ads8688_range		range[8];
7162306a36Sopenharmony_ci	union {
7262306a36Sopenharmony_ci		__be32 d32;
7362306a36Sopenharmony_ci		u8 d8[4];
7462306a36Sopenharmony_ci	} data[2] __aligned(IIO_DMA_MINALIGN);
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cienum ads8688_id {
7862306a36Sopenharmony_ci	ID_ADS8684,
7962306a36Sopenharmony_ci	ID_ADS8688,
8062306a36Sopenharmony_ci};
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistruct ads8688_ranges {
8362306a36Sopenharmony_ci	enum ads8688_range range;
8462306a36Sopenharmony_ci	unsigned int scale;
8562306a36Sopenharmony_ci	int offset;
8662306a36Sopenharmony_ci	u8 reg;
8762306a36Sopenharmony_ci};
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic const struct ads8688_ranges ads8688_range_def[5] = {
9062306a36Sopenharmony_ci	{
9162306a36Sopenharmony_ci		.range = ADS8688_PLUSMINUS25VREF,
9262306a36Sopenharmony_ci		.scale = 76295,
9362306a36Sopenharmony_ci		.offset = -(1 << (ADS8688_REALBITS - 1)),
9462306a36Sopenharmony_ci		.reg = ADS8688_REG_PLUSMINUS25VREF,
9562306a36Sopenharmony_ci	}, {
9662306a36Sopenharmony_ci		.range = ADS8688_PLUSMINUS125VREF,
9762306a36Sopenharmony_ci		.scale = 38148,
9862306a36Sopenharmony_ci		.offset = -(1 << (ADS8688_REALBITS - 1)),
9962306a36Sopenharmony_ci		.reg = ADS8688_REG_PLUSMINUS125VREF,
10062306a36Sopenharmony_ci	}, {
10162306a36Sopenharmony_ci		.range = ADS8688_PLUSMINUS0625VREF,
10262306a36Sopenharmony_ci		.scale = 19074,
10362306a36Sopenharmony_ci		.offset = -(1 << (ADS8688_REALBITS - 1)),
10462306a36Sopenharmony_ci		.reg = ADS8688_REG_PLUSMINUS0625VREF,
10562306a36Sopenharmony_ci	}, {
10662306a36Sopenharmony_ci		.range = ADS8688_PLUS25VREF,
10762306a36Sopenharmony_ci		.scale = 38148,
10862306a36Sopenharmony_ci		.offset = 0,
10962306a36Sopenharmony_ci		.reg = ADS8688_REG_PLUS25VREF,
11062306a36Sopenharmony_ci	}, {
11162306a36Sopenharmony_ci		.range = ADS8688_PLUS125VREF,
11262306a36Sopenharmony_ci		.scale = 19074,
11362306a36Sopenharmony_ci		.offset = 0,
11462306a36Sopenharmony_ci		.reg = ADS8688_REG_PLUS125VREF,
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci};
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic ssize_t ads8688_show_scales(struct device *dev,
11962306a36Sopenharmony_ci				   struct device_attribute *attr, char *buf)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	struct ads8688_state *st = iio_priv(dev_to_iio_dev(dev));
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	return sprintf(buf, "0.%09u 0.%09u 0.%09u\n",
12462306a36Sopenharmony_ci		       ads8688_range_def[0].scale * st->vref_mv,
12562306a36Sopenharmony_ci		       ads8688_range_def[1].scale * st->vref_mv,
12662306a36Sopenharmony_ci		       ads8688_range_def[2].scale * st->vref_mv);
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic ssize_t ads8688_show_offsets(struct device *dev,
13062306a36Sopenharmony_ci				    struct device_attribute *attr, char *buf)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	return sprintf(buf, "%d %d\n", ads8688_range_def[0].offset,
13362306a36Sopenharmony_ci		       ads8688_range_def[3].offset);
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic IIO_DEVICE_ATTR(in_voltage_scale_available, S_IRUGO,
13762306a36Sopenharmony_ci		       ads8688_show_scales, NULL, 0);
13862306a36Sopenharmony_cistatic IIO_DEVICE_ATTR(in_voltage_offset_available, S_IRUGO,
13962306a36Sopenharmony_ci		       ads8688_show_offsets, NULL, 0);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic struct attribute *ads8688_attributes[] = {
14262306a36Sopenharmony_ci	&iio_dev_attr_in_voltage_scale_available.dev_attr.attr,
14362306a36Sopenharmony_ci	&iio_dev_attr_in_voltage_offset_available.dev_attr.attr,
14462306a36Sopenharmony_ci	NULL,
14562306a36Sopenharmony_ci};
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic const struct attribute_group ads8688_attribute_group = {
14862306a36Sopenharmony_ci	.attrs = ads8688_attributes,
14962306a36Sopenharmony_ci};
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci#define ADS8688_CHAN(index)					\
15262306a36Sopenharmony_ci{								\
15362306a36Sopenharmony_ci	.type = IIO_VOLTAGE,					\
15462306a36Sopenharmony_ci	.indexed = 1,						\
15562306a36Sopenharmony_ci	.channel = index,					\
15662306a36Sopenharmony_ci	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW)		\
15762306a36Sopenharmony_ci			      | BIT(IIO_CHAN_INFO_SCALE)	\
15862306a36Sopenharmony_ci			      | BIT(IIO_CHAN_INFO_OFFSET),	\
15962306a36Sopenharmony_ci	.scan_index = index,					\
16062306a36Sopenharmony_ci	.scan_type = {						\
16162306a36Sopenharmony_ci		.sign = 'u',					\
16262306a36Sopenharmony_ci		.realbits = 16,					\
16362306a36Sopenharmony_ci		.storagebits = 16,				\
16462306a36Sopenharmony_ci		.endianness = IIO_BE,				\
16562306a36Sopenharmony_ci	},							\
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic const struct iio_chan_spec ads8684_channels[] = {
16962306a36Sopenharmony_ci	ADS8688_CHAN(0),
17062306a36Sopenharmony_ci	ADS8688_CHAN(1),
17162306a36Sopenharmony_ci	ADS8688_CHAN(2),
17262306a36Sopenharmony_ci	ADS8688_CHAN(3),
17362306a36Sopenharmony_ci};
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic const struct iio_chan_spec ads8688_channels[] = {
17662306a36Sopenharmony_ci	ADS8688_CHAN(0),
17762306a36Sopenharmony_ci	ADS8688_CHAN(1),
17862306a36Sopenharmony_ci	ADS8688_CHAN(2),
17962306a36Sopenharmony_ci	ADS8688_CHAN(3),
18062306a36Sopenharmony_ci	ADS8688_CHAN(4),
18162306a36Sopenharmony_ci	ADS8688_CHAN(5),
18262306a36Sopenharmony_ci	ADS8688_CHAN(6),
18362306a36Sopenharmony_ci	ADS8688_CHAN(7),
18462306a36Sopenharmony_ci};
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic int ads8688_prog_write(struct iio_dev *indio_dev, unsigned int addr,
18762306a36Sopenharmony_ci			      unsigned int val)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	struct ads8688_state *st = iio_priv(indio_dev);
19062306a36Sopenharmony_ci	u32 tmp;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	tmp = ADS8688_PROG_REG(addr) | ADS8688_PROG_WR_BIT | val;
19362306a36Sopenharmony_ci	tmp <<= ADS8688_PROG_DONT_CARE_BITS;
19462306a36Sopenharmony_ci	st->data[0].d32 = cpu_to_be32(tmp);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	return spi_write(st->spi, &st->data[0].d8[1], 3);
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic int ads8688_reset(struct iio_dev *indio_dev)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	struct ads8688_state *st = iio_priv(indio_dev);
20262306a36Sopenharmony_ci	u32 tmp;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	tmp = ADS8688_CMD_REG(ADS8688_CMD_REG_RST);
20562306a36Sopenharmony_ci	tmp <<= ADS8688_CMD_DONT_CARE_BITS;
20662306a36Sopenharmony_ci	st->data[0].d32 = cpu_to_be32(tmp);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	return spi_write(st->spi, &st->data[0].d8[0], 4);
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistatic int ads8688_read(struct iio_dev *indio_dev, unsigned int chan)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	struct ads8688_state *st = iio_priv(indio_dev);
21462306a36Sopenharmony_ci	int ret;
21562306a36Sopenharmony_ci	u32 tmp;
21662306a36Sopenharmony_ci	struct spi_transfer t[] = {
21762306a36Sopenharmony_ci		{
21862306a36Sopenharmony_ci			.tx_buf = &st->data[0].d8[0],
21962306a36Sopenharmony_ci			.len = 4,
22062306a36Sopenharmony_ci			.cs_change = 1,
22162306a36Sopenharmony_ci		}, {
22262306a36Sopenharmony_ci			.tx_buf = &st->data[1].d8[0],
22362306a36Sopenharmony_ci			.rx_buf = &st->data[1].d8[0],
22462306a36Sopenharmony_ci			.len = 4,
22562306a36Sopenharmony_ci		},
22662306a36Sopenharmony_ci	};
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	tmp = ADS8688_CMD_REG(ADS8688_CMD_REG_MAN_CH(chan));
22962306a36Sopenharmony_ci	tmp <<= ADS8688_CMD_DONT_CARE_BITS;
23062306a36Sopenharmony_ci	st->data[0].d32 = cpu_to_be32(tmp);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	tmp = ADS8688_CMD_REG(ADS8688_CMD_REG_NOOP);
23362306a36Sopenharmony_ci	tmp <<= ADS8688_CMD_DONT_CARE_BITS;
23462306a36Sopenharmony_ci	st->data[1].d32 = cpu_to_be32(tmp);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
23762306a36Sopenharmony_ci	if (ret < 0)
23862306a36Sopenharmony_ci		return ret;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	return be32_to_cpu(st->data[1].d32) & 0xffff;
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cistatic int ads8688_read_raw(struct iio_dev *indio_dev,
24462306a36Sopenharmony_ci			    struct iio_chan_spec const *chan,
24562306a36Sopenharmony_ci			    int *val, int *val2, long m)
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	int ret, offset;
24862306a36Sopenharmony_ci	unsigned long scale_mv;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	struct ads8688_state *st = iio_priv(indio_dev);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	mutex_lock(&st->lock);
25362306a36Sopenharmony_ci	switch (m) {
25462306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
25562306a36Sopenharmony_ci		ret = ads8688_read(indio_dev, chan->channel);
25662306a36Sopenharmony_ci		mutex_unlock(&st->lock);
25762306a36Sopenharmony_ci		if (ret < 0)
25862306a36Sopenharmony_ci			return ret;
25962306a36Sopenharmony_ci		*val = ret;
26062306a36Sopenharmony_ci		return IIO_VAL_INT;
26162306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
26262306a36Sopenharmony_ci		scale_mv = st->vref_mv;
26362306a36Sopenharmony_ci		scale_mv *= ads8688_range_def[st->range[chan->channel]].scale;
26462306a36Sopenharmony_ci		*val = 0;
26562306a36Sopenharmony_ci		*val2 = scale_mv;
26662306a36Sopenharmony_ci		mutex_unlock(&st->lock);
26762306a36Sopenharmony_ci		return IIO_VAL_INT_PLUS_NANO;
26862306a36Sopenharmony_ci	case IIO_CHAN_INFO_OFFSET:
26962306a36Sopenharmony_ci		offset = ads8688_range_def[st->range[chan->channel]].offset;
27062306a36Sopenharmony_ci		*val = offset;
27162306a36Sopenharmony_ci		mutex_unlock(&st->lock);
27262306a36Sopenharmony_ci		return IIO_VAL_INT;
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci	mutex_unlock(&st->lock);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	return -EINVAL;
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic int ads8688_write_reg_range(struct iio_dev *indio_dev,
28062306a36Sopenharmony_ci				   struct iio_chan_spec const *chan,
28162306a36Sopenharmony_ci				   enum ads8688_range range)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	unsigned int tmp;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	tmp = ADS8688_PROG_REG_RANGE_CH(chan->channel);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	return ads8688_prog_write(indio_dev, tmp, range);
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic int ads8688_write_raw(struct iio_dev *indio_dev,
29162306a36Sopenharmony_ci			     struct iio_chan_spec const *chan,
29262306a36Sopenharmony_ci			     int val, int val2, long mask)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	struct ads8688_state *st = iio_priv(indio_dev);
29562306a36Sopenharmony_ci	unsigned int scale = 0;
29662306a36Sopenharmony_ci	int ret = -EINVAL, i, offset = 0;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	mutex_lock(&st->lock);
29962306a36Sopenharmony_ci	switch (mask) {
30062306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
30162306a36Sopenharmony_ci		/* If the offset is 0 the ±2.5 * VREF mode is not available */
30262306a36Sopenharmony_ci		offset = ads8688_range_def[st->range[chan->channel]].offset;
30362306a36Sopenharmony_ci		if (offset == 0 && val2 == ads8688_range_def[0].scale * st->vref_mv) {
30462306a36Sopenharmony_ci			mutex_unlock(&st->lock);
30562306a36Sopenharmony_ci			return -EINVAL;
30662306a36Sopenharmony_ci		}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci		/* Lookup new mode */
30962306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(ads8688_range_def); i++)
31062306a36Sopenharmony_ci			if (val2 == ads8688_range_def[i].scale * st->vref_mv &&
31162306a36Sopenharmony_ci			    offset == ads8688_range_def[i].offset) {
31262306a36Sopenharmony_ci				ret = ads8688_write_reg_range(indio_dev, chan,
31362306a36Sopenharmony_ci					ads8688_range_def[i].reg);
31462306a36Sopenharmony_ci				break;
31562306a36Sopenharmony_ci			}
31662306a36Sopenharmony_ci		break;
31762306a36Sopenharmony_ci	case IIO_CHAN_INFO_OFFSET:
31862306a36Sopenharmony_ci		/*
31962306a36Sopenharmony_ci		 * There are only two available offsets:
32062306a36Sopenharmony_ci		 * 0 and -(1 << (ADS8688_REALBITS - 1))
32162306a36Sopenharmony_ci		 */
32262306a36Sopenharmony_ci		if (!(ads8688_range_def[0].offset == val ||
32362306a36Sopenharmony_ci		    ads8688_range_def[3].offset == val)) {
32462306a36Sopenharmony_ci			mutex_unlock(&st->lock);
32562306a36Sopenharmony_ci			return -EINVAL;
32662306a36Sopenharmony_ci		}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci		/*
32962306a36Sopenharmony_ci		 * If the device are in ±2.5 * VREF mode, it's not allowed to
33062306a36Sopenharmony_ci		 * switch to a mode where the offset is 0
33162306a36Sopenharmony_ci		 */
33262306a36Sopenharmony_ci		if (val == 0 &&
33362306a36Sopenharmony_ci		    st->range[chan->channel] == ADS8688_PLUSMINUS25VREF) {
33462306a36Sopenharmony_ci			mutex_unlock(&st->lock);
33562306a36Sopenharmony_ci			return -EINVAL;
33662306a36Sopenharmony_ci		}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci		scale = ads8688_range_def[st->range[chan->channel]].scale;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci		/* Lookup new mode */
34162306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(ads8688_range_def); i++)
34262306a36Sopenharmony_ci			if (val == ads8688_range_def[i].offset &&
34362306a36Sopenharmony_ci			    scale == ads8688_range_def[i].scale) {
34462306a36Sopenharmony_ci				ret = ads8688_write_reg_range(indio_dev, chan,
34562306a36Sopenharmony_ci					ads8688_range_def[i].reg);
34662306a36Sopenharmony_ci				break;
34762306a36Sopenharmony_ci			}
34862306a36Sopenharmony_ci		break;
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	if (!ret)
35262306a36Sopenharmony_ci		st->range[chan->channel] = ads8688_range_def[i].range;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	mutex_unlock(&st->lock);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	return ret;
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic int ads8688_write_raw_get_fmt(struct iio_dev *indio_dev,
36062306a36Sopenharmony_ci				     struct iio_chan_spec const *chan,
36162306a36Sopenharmony_ci				     long mask)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	switch (mask) {
36462306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
36562306a36Sopenharmony_ci		return IIO_VAL_INT_PLUS_NANO;
36662306a36Sopenharmony_ci	case IIO_CHAN_INFO_OFFSET:
36762306a36Sopenharmony_ci		return IIO_VAL_INT;
36862306a36Sopenharmony_ci	}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	return -EINVAL;
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistatic const struct iio_info ads8688_info = {
37462306a36Sopenharmony_ci	.read_raw = &ads8688_read_raw,
37562306a36Sopenharmony_ci	.write_raw = &ads8688_write_raw,
37662306a36Sopenharmony_ci	.write_raw_get_fmt = &ads8688_write_raw_get_fmt,
37762306a36Sopenharmony_ci	.attrs = &ads8688_attribute_group,
37862306a36Sopenharmony_ci};
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic irqreturn_t ads8688_trigger_handler(int irq, void *p)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	struct iio_poll_func *pf = p;
38362306a36Sopenharmony_ci	struct iio_dev *indio_dev = pf->indio_dev;
38462306a36Sopenharmony_ci	/* Ensure naturally aligned timestamp */
38562306a36Sopenharmony_ci	u16 buffer[ADS8688_MAX_CHANNELS + sizeof(s64)/sizeof(u16)] __aligned(8);
38662306a36Sopenharmony_ci	int i, j = 0;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	for (i = 0; i < indio_dev->masklength; i++) {
38962306a36Sopenharmony_ci		if (!test_bit(i, indio_dev->active_scan_mask))
39062306a36Sopenharmony_ci			continue;
39162306a36Sopenharmony_ci		buffer[j] = ads8688_read(indio_dev, i);
39262306a36Sopenharmony_ci		j++;
39362306a36Sopenharmony_ci	}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	iio_push_to_buffers_with_timestamp(indio_dev, buffer,
39662306a36Sopenharmony_ci			iio_get_time_ns(indio_dev));
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	iio_trigger_notify_done(indio_dev->trig);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	return IRQ_HANDLED;
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cistatic const struct ads8688_chip_info ads8688_chip_info_tbl[] = {
40462306a36Sopenharmony_ci	[ID_ADS8684] = {
40562306a36Sopenharmony_ci		.channels = ads8684_channels,
40662306a36Sopenharmony_ci		.num_channels = ARRAY_SIZE(ads8684_channels),
40762306a36Sopenharmony_ci	},
40862306a36Sopenharmony_ci	[ID_ADS8688] = {
40962306a36Sopenharmony_ci		.channels = ads8688_channels,
41062306a36Sopenharmony_ci		.num_channels = ARRAY_SIZE(ads8688_channels),
41162306a36Sopenharmony_ci	},
41262306a36Sopenharmony_ci};
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistatic int ads8688_probe(struct spi_device *spi)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	struct ads8688_state *st;
41762306a36Sopenharmony_ci	struct iio_dev *indio_dev;
41862306a36Sopenharmony_ci	int ret;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
42162306a36Sopenharmony_ci	if (indio_dev == NULL)
42262306a36Sopenharmony_ci		return -ENOMEM;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	st = iio_priv(indio_dev);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	st->reg = devm_regulator_get_optional(&spi->dev, "vref");
42762306a36Sopenharmony_ci	if (!IS_ERR(st->reg)) {
42862306a36Sopenharmony_ci		ret = regulator_enable(st->reg);
42962306a36Sopenharmony_ci		if (ret)
43062306a36Sopenharmony_ci			return ret;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci		ret = regulator_get_voltage(st->reg);
43362306a36Sopenharmony_ci		if (ret < 0)
43462306a36Sopenharmony_ci			goto err_regulator_disable;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci		st->vref_mv = ret / 1000;
43762306a36Sopenharmony_ci	} else {
43862306a36Sopenharmony_ci		/* Use internal reference */
43962306a36Sopenharmony_ci		st->vref_mv = ADS8688_VREF_MV;
44062306a36Sopenharmony_ci	}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	st->chip_info =	&ads8688_chip_info_tbl[spi_get_device_id(spi)->driver_data];
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	spi->mode = SPI_MODE_1;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	spi_set_drvdata(spi, indio_dev);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	st->spi = spi;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	indio_dev->name = spi_get_device_id(spi)->name;
45162306a36Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
45262306a36Sopenharmony_ci	indio_dev->channels = st->chip_info->channels;
45362306a36Sopenharmony_ci	indio_dev->num_channels = st->chip_info->num_channels;
45462306a36Sopenharmony_ci	indio_dev->info = &ads8688_info;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	ads8688_reset(indio_dev);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	mutex_init(&st->lock);
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	ret = iio_triggered_buffer_setup(indio_dev, NULL, ads8688_trigger_handler, NULL);
46162306a36Sopenharmony_ci	if (ret < 0) {
46262306a36Sopenharmony_ci		dev_err(&spi->dev, "iio triggered buffer setup failed\n");
46362306a36Sopenharmony_ci		goto err_regulator_disable;
46462306a36Sopenharmony_ci	}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	ret = iio_device_register(indio_dev);
46762306a36Sopenharmony_ci	if (ret)
46862306a36Sopenharmony_ci		goto err_buffer_cleanup;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	return 0;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_cierr_buffer_cleanup:
47362306a36Sopenharmony_ci	iio_triggered_buffer_cleanup(indio_dev);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cierr_regulator_disable:
47662306a36Sopenharmony_ci	if (!IS_ERR(st->reg))
47762306a36Sopenharmony_ci		regulator_disable(st->reg);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	return ret;
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_cistatic void ads8688_remove(struct spi_device *spi)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	struct iio_dev *indio_dev = spi_get_drvdata(spi);
48562306a36Sopenharmony_ci	struct ads8688_state *st = iio_priv(indio_dev);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	iio_device_unregister(indio_dev);
48862306a36Sopenharmony_ci	iio_triggered_buffer_cleanup(indio_dev);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (!IS_ERR(st->reg))
49162306a36Sopenharmony_ci		regulator_disable(st->reg);
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_cistatic const struct spi_device_id ads8688_id[] = {
49562306a36Sopenharmony_ci	{"ads8684", ID_ADS8684},
49662306a36Sopenharmony_ci	{"ads8688", ID_ADS8688},
49762306a36Sopenharmony_ci	{}
49862306a36Sopenharmony_ci};
49962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(spi, ads8688_id);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cistatic const struct of_device_id ads8688_of_match[] = {
50262306a36Sopenharmony_ci	{ .compatible = "ti,ads8684" },
50362306a36Sopenharmony_ci	{ .compatible = "ti,ads8688" },
50462306a36Sopenharmony_ci	{ }
50562306a36Sopenharmony_ci};
50662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ads8688_of_match);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_cistatic struct spi_driver ads8688_driver = {
50962306a36Sopenharmony_ci	.driver = {
51062306a36Sopenharmony_ci		.name	= "ads8688",
51162306a36Sopenharmony_ci		.of_match_table = ads8688_of_match,
51262306a36Sopenharmony_ci	},
51362306a36Sopenharmony_ci	.probe		= ads8688_probe,
51462306a36Sopenharmony_ci	.remove		= ads8688_remove,
51562306a36Sopenharmony_ci	.id_table	= ads8688_id,
51662306a36Sopenharmony_ci};
51762306a36Sopenharmony_cimodule_spi_driver(ads8688_driver);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ciMODULE_AUTHOR("Sean Nyekjaer <sean@geanix.dk>");
52062306a36Sopenharmony_ciMODULE_DESCRIPTION("Texas Instruments ADS8688 driver");
52162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
522