xref: /openbmc/linux/drivers/iio/adc/ad7266.c (revision f91ca89e924eb287915522664a31afc71a49c05b)
1fda8d26eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
28ec4cf53SLars-Peter Clausen /*
38ec4cf53SLars-Peter Clausen  * AD7266/65 SPI ADC driver
48ec4cf53SLars-Peter Clausen  *
58ec4cf53SLars-Peter Clausen  * Copyright 2012 Analog Devices Inc.
68ec4cf53SLars-Peter Clausen  */
78ec4cf53SLars-Peter Clausen 
88ec4cf53SLars-Peter Clausen #include <linux/device.h>
98ec4cf53SLars-Peter Clausen #include <linux/kernel.h>
108ec4cf53SLars-Peter Clausen #include <linux/slab.h>
118ec4cf53SLars-Peter Clausen #include <linux/spi/spi.h>
128ec4cf53SLars-Peter Clausen #include <linux/regulator/consumer.h>
138ec4cf53SLars-Peter Clausen #include <linux/err.h>
145750ebabSLinus Walleij #include <linux/gpio/consumer.h>
158ec4cf53SLars-Peter Clausen #include <linux/module.h>
168ec4cf53SLars-Peter Clausen 
178ec4cf53SLars-Peter Clausen #include <linux/interrupt.h>
188ec4cf53SLars-Peter Clausen 
198ec4cf53SLars-Peter Clausen #include <linux/iio/iio.h>
208ec4cf53SLars-Peter Clausen #include <linux/iio/buffer.h>
218ec4cf53SLars-Peter Clausen #include <linux/iio/trigger_consumer.h>
228ec4cf53SLars-Peter Clausen #include <linux/iio/triggered_buffer.h>
238ec4cf53SLars-Peter Clausen 
248ec4cf53SLars-Peter Clausen #include <linux/platform_data/ad7266.h>
258ec4cf53SLars-Peter Clausen 
268ec4cf53SLars-Peter Clausen struct ad7266_state {
278ec4cf53SLars-Peter Clausen 	struct spi_device	*spi;
288ec4cf53SLars-Peter Clausen 	struct regulator	*reg;
292ebc39c0SLars-Peter Clausen 	unsigned long		vref_mv;
308ec4cf53SLars-Peter Clausen 
318ec4cf53SLars-Peter Clausen 	struct spi_transfer	single_xfer[3];
328ec4cf53SLars-Peter Clausen 	struct spi_message	single_msg;
338ec4cf53SLars-Peter Clausen 
348ec4cf53SLars-Peter Clausen 	enum ad7266_range	range;
358ec4cf53SLars-Peter Clausen 	enum ad7266_mode	mode;
368ec4cf53SLars-Peter Clausen 	bool			fixed_addr;
375750ebabSLinus Walleij 	struct gpio_desc	*gpios[3];
388ec4cf53SLars-Peter Clausen 
398ec4cf53SLars-Peter Clausen 	/*
40b990cdfeSJonathan Cameron 	 * DMA (thus cache coherency maintenance) may require the
418ec4cf53SLars-Peter Clausen 	 * transfer buffers to live in their own cache lines.
428ec4cf53SLars-Peter Clausen 	 * The buffer needs to be large enough to hold two samples (4 bytes) and
438ec4cf53SLars-Peter Clausen 	 * the naturally aligned timestamp (8 bytes).
448ec4cf53SLars-Peter Clausen 	 */
4554e018daSLars-Peter Clausen 	struct {
4654e018daSLars-Peter Clausen 		__be16 sample[2];
4754e018daSLars-Peter Clausen 		s64 timestamp;
48b990cdfeSJonathan Cameron 	} data __aligned(IIO_DMA_MINALIGN);
498ec4cf53SLars-Peter Clausen };
508ec4cf53SLars-Peter Clausen 
ad7266_wakeup(struct ad7266_state * st)518ec4cf53SLars-Peter Clausen static int ad7266_wakeup(struct ad7266_state *st)
528ec4cf53SLars-Peter Clausen {
538ec4cf53SLars-Peter Clausen 	/* Any read with >= 2 bytes will wake the device */
5454e018daSLars-Peter Clausen 	return spi_read(st->spi, &st->data.sample[0], 2);
558ec4cf53SLars-Peter Clausen }
568ec4cf53SLars-Peter Clausen 
ad7266_powerdown(struct ad7266_state * st)578ec4cf53SLars-Peter Clausen static int ad7266_powerdown(struct ad7266_state *st)
588ec4cf53SLars-Peter Clausen {
598ec4cf53SLars-Peter Clausen 	/* Any read with < 2 bytes will powerdown the device */
6054e018daSLars-Peter Clausen 	return spi_read(st->spi, &st->data.sample[0], 1);
618ec4cf53SLars-Peter Clausen }
628ec4cf53SLars-Peter Clausen 
ad7266_preenable(struct iio_dev * indio_dev)638ec4cf53SLars-Peter Clausen static int ad7266_preenable(struct iio_dev *indio_dev)
648ec4cf53SLars-Peter Clausen {
658ec4cf53SLars-Peter Clausen 	struct ad7266_state *st = iio_priv(indio_dev);
6606e1b542SLars-Peter Clausen 	return ad7266_wakeup(st);
678ec4cf53SLars-Peter Clausen }
688ec4cf53SLars-Peter Clausen 
ad7266_postdisable(struct iio_dev * indio_dev)698ec4cf53SLars-Peter Clausen static int ad7266_postdisable(struct iio_dev *indio_dev)
708ec4cf53SLars-Peter Clausen {
718ec4cf53SLars-Peter Clausen 	struct ad7266_state *st = iio_priv(indio_dev);
728ec4cf53SLars-Peter Clausen 	return ad7266_powerdown(st);
738ec4cf53SLars-Peter Clausen }
748ec4cf53SLars-Peter Clausen 
758ec4cf53SLars-Peter Clausen static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = {
768ec4cf53SLars-Peter Clausen 	.preenable = &ad7266_preenable,
778ec4cf53SLars-Peter Clausen 	.postdisable = &ad7266_postdisable,
788ec4cf53SLars-Peter Clausen };
798ec4cf53SLars-Peter Clausen 
ad7266_trigger_handler(int irq,void * p)808ec4cf53SLars-Peter Clausen static irqreturn_t ad7266_trigger_handler(int irq, void *p)
818ec4cf53SLars-Peter Clausen {
828ec4cf53SLars-Peter Clausen 	struct iio_poll_func *pf = p;
838ec4cf53SLars-Peter Clausen 	struct iio_dev *indio_dev = pf->indio_dev;
848ec4cf53SLars-Peter Clausen 	struct ad7266_state *st = iio_priv(indio_dev);
858ec4cf53SLars-Peter Clausen 	int ret;
868ec4cf53SLars-Peter Clausen 
8754e018daSLars-Peter Clausen 	ret = spi_read(st->spi, st->data.sample, 4);
888ec4cf53SLars-Peter Clausen 	if (ret == 0) {
8954e018daSLars-Peter Clausen 		iio_push_to_buffers_with_timestamp(indio_dev, &st->data,
90fce8abfdSLars-Peter Clausen 			    pf->timestamp);
918ec4cf53SLars-Peter Clausen 	}
928ec4cf53SLars-Peter Clausen 
938ec4cf53SLars-Peter Clausen 	iio_trigger_notify_done(indio_dev->trig);
948ec4cf53SLars-Peter Clausen 
958ec4cf53SLars-Peter Clausen 	return IRQ_HANDLED;
968ec4cf53SLars-Peter Clausen }
978ec4cf53SLars-Peter Clausen 
ad7266_select_input(struct ad7266_state * st,unsigned int nr)988ec4cf53SLars-Peter Clausen static void ad7266_select_input(struct ad7266_state *st, unsigned int nr)
998ec4cf53SLars-Peter Clausen {
1008ec4cf53SLars-Peter Clausen 	unsigned int i;
1018ec4cf53SLars-Peter Clausen 
1028ec4cf53SLars-Peter Clausen 	if (st->fixed_addr)
1038ec4cf53SLars-Peter Clausen 		return;
1048ec4cf53SLars-Peter Clausen 
1058ec4cf53SLars-Peter Clausen 	switch (st->mode) {
1068ec4cf53SLars-Peter Clausen 	case AD7266_MODE_SINGLE_ENDED:
1078ec4cf53SLars-Peter Clausen 		nr >>= 1;
1088ec4cf53SLars-Peter Clausen 		break;
1098ec4cf53SLars-Peter Clausen 	case AD7266_MODE_PSEUDO_DIFF:
1108ec4cf53SLars-Peter Clausen 		nr |= 1;
1118ec4cf53SLars-Peter Clausen 		break;
1128ec4cf53SLars-Peter Clausen 	case AD7266_MODE_DIFF:
1138ec4cf53SLars-Peter Clausen 		nr &= ~1;
1148ec4cf53SLars-Peter Clausen 		break;
1158ec4cf53SLars-Peter Clausen 	}
1168ec4cf53SLars-Peter Clausen 
1178ec4cf53SLars-Peter Clausen 	for (i = 0; i < 3; ++i)
1185750ebabSLinus Walleij 		gpiod_set_value(st->gpios[i], (bool)(nr & BIT(i)));
1198ec4cf53SLars-Peter Clausen }
1208ec4cf53SLars-Peter Clausen 
ad7266_update_scan_mode(struct iio_dev * indio_dev,const unsigned long * scan_mask)1218ec4cf53SLars-Peter Clausen static int ad7266_update_scan_mode(struct iio_dev *indio_dev,
1228ec4cf53SLars-Peter Clausen 	const unsigned long *scan_mask)
1238ec4cf53SLars-Peter Clausen {
1248ec4cf53SLars-Peter Clausen 	struct ad7266_state *st = iio_priv(indio_dev);
1258ec4cf53SLars-Peter Clausen 	unsigned int nr = find_first_bit(scan_mask, indio_dev->masklength);
1268ec4cf53SLars-Peter Clausen 
1278ec4cf53SLars-Peter Clausen 	ad7266_select_input(st, nr);
1288ec4cf53SLars-Peter Clausen 
1298ec4cf53SLars-Peter Clausen 	return 0;
1308ec4cf53SLars-Peter Clausen }
1318ec4cf53SLars-Peter Clausen 
ad7266_read_single(struct ad7266_state * st,int * val,unsigned int address)1328ec4cf53SLars-Peter Clausen static int ad7266_read_single(struct ad7266_state *st, int *val,
1338ec4cf53SLars-Peter Clausen 	unsigned int address)
1348ec4cf53SLars-Peter Clausen {
1358ec4cf53SLars-Peter Clausen 	int ret;
1368ec4cf53SLars-Peter Clausen 
1378ec4cf53SLars-Peter Clausen 	ad7266_select_input(st, address);
1388ec4cf53SLars-Peter Clausen 
1398ec4cf53SLars-Peter Clausen 	ret = spi_sync(st->spi, &st->single_msg);
14054e018daSLars-Peter Clausen 	*val = be16_to_cpu(st->data.sample[address % 2]);
1418ec4cf53SLars-Peter Clausen 
1428ec4cf53SLars-Peter Clausen 	return ret;
1438ec4cf53SLars-Peter Clausen }
1448ec4cf53SLars-Peter Clausen 
ad7266_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long m)1458ec4cf53SLars-Peter Clausen static int ad7266_read_raw(struct iio_dev *indio_dev,
1468ec4cf53SLars-Peter Clausen 	struct iio_chan_spec const *chan, int *val, int *val2, long m)
1478ec4cf53SLars-Peter Clausen {
1488ec4cf53SLars-Peter Clausen 	struct ad7266_state *st = iio_priv(indio_dev);
1492ebc39c0SLars-Peter Clausen 	unsigned long scale_mv;
1508ec4cf53SLars-Peter Clausen 	int ret;
1518ec4cf53SLars-Peter Clausen 
1528ec4cf53SLars-Peter Clausen 	switch (m) {
1538ec4cf53SLars-Peter Clausen 	case IIO_CHAN_INFO_RAW:
154c70df20eSAlison Schofield 		ret = iio_device_claim_direct_mode(indio_dev);
1558ec4cf53SLars-Peter Clausen 		if (ret)
1568ec4cf53SLars-Peter Clausen 			return ret;
157c70df20eSAlison Schofield 		ret = ad7266_read_single(st, val, chan->address);
158c70df20eSAlison Schofield 		iio_device_release_direct_mode(indio_dev);
1598ec4cf53SLars-Peter Clausen 
160*1ce8be84SFernando Yang 		if (ret < 0)
161*1ce8be84SFernando Yang 			return ret;
1628ec4cf53SLars-Peter Clausen 		*val = (*val >> 2) & 0xfff;
1638ec4cf53SLars-Peter Clausen 		if (chan->scan_type.sign == 's')
1644e9f4c12SGwendal Grignou 			*val = sign_extend32(*val,
1654e9f4c12SGwendal Grignou 					     chan->scan_type.realbits - 1);
1668ec4cf53SLars-Peter Clausen 
1678ec4cf53SLars-Peter Clausen 		return IIO_VAL_INT;
1688ec4cf53SLars-Peter Clausen 	case IIO_CHAN_INFO_SCALE:
1692ebc39c0SLars-Peter Clausen 		scale_mv = st->vref_mv;
1708ec4cf53SLars-Peter Clausen 		if (st->mode == AD7266_MODE_DIFF)
1712ebc39c0SLars-Peter Clausen 			scale_mv *= 2;
1728ec4cf53SLars-Peter Clausen 		if (st->range == AD7266_RANGE_2VREF)
1732ebc39c0SLars-Peter Clausen 			scale_mv *= 2;
1748ec4cf53SLars-Peter Clausen 
1752ebc39c0SLars-Peter Clausen 		*val = scale_mv;
1762ebc39c0SLars-Peter Clausen 		*val2 = chan->scan_type.realbits;
1772ebc39c0SLars-Peter Clausen 		return IIO_VAL_FRACTIONAL_LOG2;
1788ec4cf53SLars-Peter Clausen 	case IIO_CHAN_INFO_OFFSET:
1798ec4cf53SLars-Peter Clausen 		if (st->range == AD7266_RANGE_2VREF &&
1808ec4cf53SLars-Peter Clausen 			st->mode != AD7266_MODE_DIFF)
1818ec4cf53SLars-Peter Clausen 			*val = 2048;
1828ec4cf53SLars-Peter Clausen 		else
1838ec4cf53SLars-Peter Clausen 			*val = 0;
1848ec4cf53SLars-Peter Clausen 		return IIO_VAL_INT;
1858ec4cf53SLars-Peter Clausen 	}
1868ec4cf53SLars-Peter Clausen 	return -EINVAL;
1878ec4cf53SLars-Peter Clausen }
1888ec4cf53SLars-Peter Clausen 
1898ec4cf53SLars-Peter Clausen #define AD7266_CHAN(_chan, _sign) {			\
1908ec4cf53SLars-Peter Clausen 	.type = IIO_VOLTAGE,				\
1918ec4cf53SLars-Peter Clausen 	.indexed = 1,					\
1928ec4cf53SLars-Peter Clausen 	.channel = (_chan),				\
1938ec4cf53SLars-Peter Clausen 	.address = (_chan),				\
1943234ac7eSJonathan Cameron 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),	\
1953234ac7eSJonathan Cameron 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
1963234ac7eSJonathan Cameron 		| BIT(IIO_CHAN_INFO_OFFSET),			\
1978ec4cf53SLars-Peter Clausen 	.scan_index = (_chan),				\
1988ec4cf53SLars-Peter Clausen 	.scan_type = {					\
1998ec4cf53SLars-Peter Clausen 		.sign = (_sign),			\
2008ec4cf53SLars-Peter Clausen 		.realbits = 12,				\
2018ec4cf53SLars-Peter Clausen 		.storagebits = 16,			\
2028ec4cf53SLars-Peter Clausen 		.shift = 2,				\
2038ec4cf53SLars-Peter Clausen 		.endianness = IIO_BE,			\
2048ec4cf53SLars-Peter Clausen 	},						\
2058ec4cf53SLars-Peter Clausen }
2068ec4cf53SLars-Peter Clausen 
2078ec4cf53SLars-Peter Clausen #define AD7266_DECLARE_SINGLE_ENDED_CHANNELS(_name, _sign) \
2088ec4cf53SLars-Peter Clausen const struct iio_chan_spec ad7266_channels_##_name[] = { \
2098ec4cf53SLars-Peter Clausen 	AD7266_CHAN(0, (_sign)), \
2108ec4cf53SLars-Peter Clausen 	AD7266_CHAN(1, (_sign)), \
2118ec4cf53SLars-Peter Clausen 	AD7266_CHAN(2, (_sign)), \
2128ec4cf53SLars-Peter Clausen 	AD7266_CHAN(3, (_sign)), \
2138ec4cf53SLars-Peter Clausen 	AD7266_CHAN(4, (_sign)), \
2148ec4cf53SLars-Peter Clausen 	AD7266_CHAN(5, (_sign)), \
2158ec4cf53SLars-Peter Clausen 	AD7266_CHAN(6, (_sign)), \
2168ec4cf53SLars-Peter Clausen 	AD7266_CHAN(7, (_sign)), \
2178ec4cf53SLars-Peter Clausen 	AD7266_CHAN(8, (_sign)), \
2188ec4cf53SLars-Peter Clausen 	AD7266_CHAN(9, (_sign)), \
2198ec4cf53SLars-Peter Clausen 	AD7266_CHAN(10, (_sign)), \
2208ec4cf53SLars-Peter Clausen 	AD7266_CHAN(11, (_sign)), \
2218ec4cf53SLars-Peter Clausen 	IIO_CHAN_SOFT_TIMESTAMP(13), \
2228ec4cf53SLars-Peter Clausen }
2238ec4cf53SLars-Peter Clausen 
2248ec4cf53SLars-Peter Clausen #define AD7266_DECLARE_SINGLE_ENDED_CHANNELS_FIXED(_name, _sign) \
2258ec4cf53SLars-Peter Clausen const struct iio_chan_spec ad7266_channels_##_name##_fixed[] = { \
2268ec4cf53SLars-Peter Clausen 	AD7266_CHAN(0, (_sign)), \
2278ec4cf53SLars-Peter Clausen 	AD7266_CHAN(1, (_sign)), \
2288ec4cf53SLars-Peter Clausen 	IIO_CHAN_SOFT_TIMESTAMP(2), \
2298ec4cf53SLars-Peter Clausen }
2308ec4cf53SLars-Peter Clausen 
2318ec4cf53SLars-Peter Clausen static AD7266_DECLARE_SINGLE_ENDED_CHANNELS(u, 'u');
2328ec4cf53SLars-Peter Clausen static AD7266_DECLARE_SINGLE_ENDED_CHANNELS(s, 's');
2338ec4cf53SLars-Peter Clausen static AD7266_DECLARE_SINGLE_ENDED_CHANNELS_FIXED(u, 'u');
2348ec4cf53SLars-Peter Clausen static AD7266_DECLARE_SINGLE_ENDED_CHANNELS_FIXED(s, 's');
2358ec4cf53SLars-Peter Clausen 
2368ec4cf53SLars-Peter Clausen #define AD7266_CHAN_DIFF(_chan, _sign) {			\
2378ec4cf53SLars-Peter Clausen 	.type = IIO_VOLTAGE,				\
2388ec4cf53SLars-Peter Clausen 	.indexed = 1,					\
2398ec4cf53SLars-Peter Clausen 	.channel = (_chan) * 2,				\
2408ec4cf53SLars-Peter Clausen 	.channel2 = (_chan) * 2 + 1,			\
2418ec4cf53SLars-Peter Clausen 	.address = (_chan),				\
2423234ac7eSJonathan Cameron 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),	\
2433234ac7eSJonathan Cameron 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE)	\
2443234ac7eSJonathan Cameron 		| BIT(IIO_CHAN_INFO_OFFSET),			\
2458ec4cf53SLars-Peter Clausen 	.scan_index = (_chan),				\
2468ec4cf53SLars-Peter Clausen 	.scan_type = {					\
2478ec4cf53SLars-Peter Clausen 		.sign = _sign,			\
2488ec4cf53SLars-Peter Clausen 		.realbits = 12,				\
2498ec4cf53SLars-Peter Clausen 		.storagebits = 16,			\
2508ec4cf53SLars-Peter Clausen 		.shift = 2,				\
2518ec4cf53SLars-Peter Clausen 		.endianness = IIO_BE,			\
2528ec4cf53SLars-Peter Clausen 	},						\
2538ec4cf53SLars-Peter Clausen 	.differential = 1,				\
2548ec4cf53SLars-Peter Clausen }
2558ec4cf53SLars-Peter Clausen 
2568ec4cf53SLars-Peter Clausen #define AD7266_DECLARE_DIFF_CHANNELS(_name, _sign) \
2578ec4cf53SLars-Peter Clausen const struct iio_chan_spec ad7266_channels_diff_##_name[] = { \
2588ec4cf53SLars-Peter Clausen 	AD7266_CHAN_DIFF(0, (_sign)), \
2598ec4cf53SLars-Peter Clausen 	AD7266_CHAN_DIFF(1, (_sign)), \
2608ec4cf53SLars-Peter Clausen 	AD7266_CHAN_DIFF(2, (_sign)), \
2618ec4cf53SLars-Peter Clausen 	AD7266_CHAN_DIFF(3, (_sign)), \
2628ec4cf53SLars-Peter Clausen 	AD7266_CHAN_DIFF(4, (_sign)), \
2638ec4cf53SLars-Peter Clausen 	AD7266_CHAN_DIFF(5, (_sign)), \
2648ec4cf53SLars-Peter Clausen 	IIO_CHAN_SOFT_TIMESTAMP(6), \
2658ec4cf53SLars-Peter Clausen }
2668ec4cf53SLars-Peter Clausen 
2678ec4cf53SLars-Peter Clausen static AD7266_DECLARE_DIFF_CHANNELS(s, 's');
2688ec4cf53SLars-Peter Clausen static AD7266_DECLARE_DIFF_CHANNELS(u, 'u');
2698ec4cf53SLars-Peter Clausen 
2708ec4cf53SLars-Peter Clausen #define AD7266_DECLARE_DIFF_CHANNELS_FIXED(_name, _sign) \
2718ec4cf53SLars-Peter Clausen const struct iio_chan_spec ad7266_channels_diff_fixed_##_name[] = { \
2728ec4cf53SLars-Peter Clausen 	AD7266_CHAN_DIFF(0, (_sign)), \
2738ec4cf53SLars-Peter Clausen 	AD7266_CHAN_DIFF(1, (_sign)), \
2748ec4cf53SLars-Peter Clausen 	IIO_CHAN_SOFT_TIMESTAMP(2), \
2758ec4cf53SLars-Peter Clausen }
2768ec4cf53SLars-Peter Clausen 
2778ec4cf53SLars-Peter Clausen static AD7266_DECLARE_DIFF_CHANNELS_FIXED(s, 's');
2788ec4cf53SLars-Peter Clausen static AD7266_DECLARE_DIFF_CHANNELS_FIXED(u, 'u');
2798ec4cf53SLars-Peter Clausen 
2808ec4cf53SLars-Peter Clausen static const struct iio_info ad7266_info = {
2818ec4cf53SLars-Peter Clausen 	.read_raw = &ad7266_read_raw,
2828ec4cf53SLars-Peter Clausen 	.update_scan_mode = &ad7266_update_scan_mode,
2838ec4cf53SLars-Peter Clausen };
2848ec4cf53SLars-Peter Clausen 
2852bdb3afcSPeter Meerwald static const unsigned long ad7266_available_scan_masks[] = {
2868ec4cf53SLars-Peter Clausen 	0x003,
2878ec4cf53SLars-Peter Clausen 	0x00c,
2888ec4cf53SLars-Peter Clausen 	0x030,
2898ec4cf53SLars-Peter Clausen 	0x0c0,
2908ec4cf53SLars-Peter Clausen 	0x300,
2918ec4cf53SLars-Peter Clausen 	0xc00,
2928ec4cf53SLars-Peter Clausen 	0x000,
2938ec4cf53SLars-Peter Clausen };
2948ec4cf53SLars-Peter Clausen 
2952bdb3afcSPeter Meerwald static const unsigned long ad7266_available_scan_masks_diff[] = {
2968ec4cf53SLars-Peter Clausen 	0x003,
2978ec4cf53SLars-Peter Clausen 	0x00c,
2988ec4cf53SLars-Peter Clausen 	0x030,
2998ec4cf53SLars-Peter Clausen 	0x000,
3008ec4cf53SLars-Peter Clausen };
3018ec4cf53SLars-Peter Clausen 
3022bdb3afcSPeter Meerwald static const unsigned long ad7266_available_scan_masks_fixed[] = {
3038ec4cf53SLars-Peter Clausen 	0x003,
3048ec4cf53SLars-Peter Clausen 	0x000,
3058ec4cf53SLars-Peter Clausen };
3068ec4cf53SLars-Peter Clausen 
3078ec4cf53SLars-Peter Clausen struct ad7266_chan_info {
3088ec4cf53SLars-Peter Clausen 	const struct iio_chan_spec *channels;
3098ec4cf53SLars-Peter Clausen 	unsigned int num_channels;
3102bdb3afcSPeter Meerwald 	const unsigned long *scan_masks;
3118ec4cf53SLars-Peter Clausen };
3128ec4cf53SLars-Peter Clausen 
3138ec4cf53SLars-Peter Clausen #define AD7266_CHAN_INFO_INDEX(_differential, _signed, _fixed) \
3148ec4cf53SLars-Peter Clausen 	(((_differential) << 2) | ((_signed) << 1) | ((_fixed) << 0))
3158ec4cf53SLars-Peter Clausen 
3168ec4cf53SLars-Peter Clausen static const struct ad7266_chan_info ad7266_chan_infos[] = {
3178ec4cf53SLars-Peter Clausen 	[AD7266_CHAN_INFO_INDEX(0, 0, 0)] = {
3188ec4cf53SLars-Peter Clausen 		.channels = ad7266_channels_u,
3198ec4cf53SLars-Peter Clausen 		.num_channels = ARRAY_SIZE(ad7266_channels_u),
3208ec4cf53SLars-Peter Clausen 		.scan_masks = ad7266_available_scan_masks,
3218ec4cf53SLars-Peter Clausen 	},
3228ec4cf53SLars-Peter Clausen 	[AD7266_CHAN_INFO_INDEX(0, 0, 1)] = {
3238ec4cf53SLars-Peter Clausen 		.channels = ad7266_channels_u_fixed,
3248ec4cf53SLars-Peter Clausen 		.num_channels = ARRAY_SIZE(ad7266_channels_u_fixed),
3258ec4cf53SLars-Peter Clausen 		.scan_masks = ad7266_available_scan_masks_fixed,
3268ec4cf53SLars-Peter Clausen 	},
3278ec4cf53SLars-Peter Clausen 	[AD7266_CHAN_INFO_INDEX(0, 1, 0)] = {
3288ec4cf53SLars-Peter Clausen 		.channels = ad7266_channels_s,
3298ec4cf53SLars-Peter Clausen 		.num_channels = ARRAY_SIZE(ad7266_channels_s),
3308ec4cf53SLars-Peter Clausen 		.scan_masks = ad7266_available_scan_masks,
3318ec4cf53SLars-Peter Clausen 	},
3328ec4cf53SLars-Peter Clausen 	[AD7266_CHAN_INFO_INDEX(0, 1, 1)] = {
3338ec4cf53SLars-Peter Clausen 		.channels = ad7266_channels_s_fixed,
3348ec4cf53SLars-Peter Clausen 		.num_channels = ARRAY_SIZE(ad7266_channels_s_fixed),
3358ec4cf53SLars-Peter Clausen 		.scan_masks = ad7266_available_scan_masks_fixed,
3368ec4cf53SLars-Peter Clausen 	},
3378ec4cf53SLars-Peter Clausen 	[AD7266_CHAN_INFO_INDEX(1, 0, 0)] = {
3388ec4cf53SLars-Peter Clausen 		.channels = ad7266_channels_diff_u,
3398ec4cf53SLars-Peter Clausen 		.num_channels = ARRAY_SIZE(ad7266_channels_diff_u),
3408ec4cf53SLars-Peter Clausen 		.scan_masks = ad7266_available_scan_masks_diff,
3418ec4cf53SLars-Peter Clausen 	},
3428ec4cf53SLars-Peter Clausen 	[AD7266_CHAN_INFO_INDEX(1, 0, 1)] = {
3438ec4cf53SLars-Peter Clausen 		.channels = ad7266_channels_diff_fixed_u,
3448ec4cf53SLars-Peter Clausen 		.num_channels = ARRAY_SIZE(ad7266_channels_diff_fixed_u),
3458ec4cf53SLars-Peter Clausen 		.scan_masks = ad7266_available_scan_masks_fixed,
3468ec4cf53SLars-Peter Clausen 	},
3478ec4cf53SLars-Peter Clausen 	[AD7266_CHAN_INFO_INDEX(1, 1, 0)] = {
3488ec4cf53SLars-Peter Clausen 		.channels = ad7266_channels_diff_s,
3498ec4cf53SLars-Peter Clausen 		.num_channels = ARRAY_SIZE(ad7266_channels_diff_s),
3508ec4cf53SLars-Peter Clausen 		.scan_masks = ad7266_available_scan_masks_diff,
3518ec4cf53SLars-Peter Clausen 	},
3528ec4cf53SLars-Peter Clausen 	[AD7266_CHAN_INFO_INDEX(1, 1, 1)] = {
3538ec4cf53SLars-Peter Clausen 		.channels = ad7266_channels_diff_fixed_s,
3548ec4cf53SLars-Peter Clausen 		.num_channels = ARRAY_SIZE(ad7266_channels_diff_fixed_s),
3558ec4cf53SLars-Peter Clausen 		.scan_masks = ad7266_available_scan_masks_fixed,
3568ec4cf53SLars-Peter Clausen 	},
3578ec4cf53SLars-Peter Clausen };
3588ec4cf53SLars-Peter Clausen 
ad7266_init_channels(struct iio_dev * indio_dev)359fc52692cSGreg Kroah-Hartman static void ad7266_init_channels(struct iio_dev *indio_dev)
3608ec4cf53SLars-Peter Clausen {
3618ec4cf53SLars-Peter Clausen 	struct ad7266_state *st = iio_priv(indio_dev);
3628ec4cf53SLars-Peter Clausen 	bool is_differential, is_signed;
3638ec4cf53SLars-Peter Clausen 	const struct ad7266_chan_info *chan_info;
3648ec4cf53SLars-Peter Clausen 	int i;
3658ec4cf53SLars-Peter Clausen 
3668ec4cf53SLars-Peter Clausen 	is_differential = st->mode != AD7266_MODE_SINGLE_ENDED;
3678ec4cf53SLars-Peter Clausen 	is_signed = (st->range == AD7266_RANGE_2VREF) |
3688ec4cf53SLars-Peter Clausen 		    (st->mode == AD7266_MODE_DIFF);
3698ec4cf53SLars-Peter Clausen 
3708ec4cf53SLars-Peter Clausen 	i = AD7266_CHAN_INFO_INDEX(is_differential, is_signed, st->fixed_addr);
3718ec4cf53SLars-Peter Clausen 	chan_info = &ad7266_chan_infos[i];
3728ec4cf53SLars-Peter Clausen 
3738ec4cf53SLars-Peter Clausen 	indio_dev->channels = chan_info->channels;
3748ec4cf53SLars-Peter Clausen 	indio_dev->num_channels = chan_info->num_channels;
3758ec4cf53SLars-Peter Clausen 	indio_dev->available_scan_masks = chan_info->scan_masks;
3768ec4cf53SLars-Peter Clausen 	indio_dev->masklength = chan_info->num_channels - 1;
3778ec4cf53SLars-Peter Clausen }
3788ec4cf53SLars-Peter Clausen 
3798ec4cf53SLars-Peter Clausen static const char * const ad7266_gpio_labels[] = {
3805750ebabSLinus Walleij 	"ad0", "ad1", "ad2",
3818ec4cf53SLars-Peter Clausen };
3828ec4cf53SLars-Peter Clausen 
ad7266_reg_disable(void * reg)383aac6834dSMaíra Canal static void ad7266_reg_disable(void *reg)
384aac6834dSMaíra Canal {
385aac6834dSMaíra Canal 	regulator_disable(reg);
386aac6834dSMaíra Canal }
387aac6834dSMaíra Canal 
ad7266_probe(struct spi_device * spi)388fc52692cSGreg Kroah-Hartman static int ad7266_probe(struct spi_device *spi)
3898ec4cf53SLars-Peter Clausen {
3908ec4cf53SLars-Peter Clausen 	struct ad7266_platform_data *pdata = spi->dev.platform_data;
3918ec4cf53SLars-Peter Clausen 	struct iio_dev *indio_dev;
3928ec4cf53SLars-Peter Clausen 	struct ad7266_state *st;
3938ec4cf53SLars-Peter Clausen 	unsigned int i;
3948ec4cf53SLars-Peter Clausen 	int ret;
3958ec4cf53SLars-Peter Clausen 
396ded4fef9SSachin Kamat 	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
3978ec4cf53SLars-Peter Clausen 	if (indio_dev == NULL)
3988ec4cf53SLars-Peter Clausen 		return -ENOMEM;
3998ec4cf53SLars-Peter Clausen 
4008ec4cf53SLars-Peter Clausen 	st = iio_priv(indio_dev);
4018ec4cf53SLars-Peter Clausen 
402e5511c81SMark Brown 	st->reg = devm_regulator_get_optional(&spi->dev, "vref");
4036b7f4e25SMark Brown 	if (!IS_ERR(st->reg)) {
4048ec4cf53SLars-Peter Clausen 		ret = regulator_enable(st->reg);
4058ec4cf53SLars-Peter Clausen 		if (ret)
406ded4fef9SSachin Kamat 			return ret;
4078ec4cf53SLars-Peter Clausen 
408aac6834dSMaíra Canal 		ret = devm_add_action_or_reset(&spi->dev, ad7266_reg_disable, st->reg);
409aac6834dSMaíra Canal 		if (ret)
410aac6834dSMaíra Canal 			return ret;
411aac6834dSMaíra Canal 
41236ce0c1cSAxel Lin 		ret = regulator_get_voltage(st->reg);
41336ce0c1cSAxel Lin 		if (ret < 0)
414aac6834dSMaíra Canal 			return ret;
41536ce0c1cSAxel Lin 
4162ebc39c0SLars-Peter Clausen 		st->vref_mv = ret / 1000;
4178ec4cf53SLars-Peter Clausen 	} else {
41868b356ebSMark Brown 		/* Any other error indicates that the regulator does exist */
41968b356ebSMark Brown 		if (PTR_ERR(st->reg) != -ENODEV)
42068b356ebSMark Brown 			return PTR_ERR(st->reg);
4218ec4cf53SLars-Peter Clausen 		/* Use internal reference */
4222ebc39c0SLars-Peter Clausen 		st->vref_mv = 2500;
4238ec4cf53SLars-Peter Clausen 	}
4248ec4cf53SLars-Peter Clausen 
4258ec4cf53SLars-Peter Clausen 	if (pdata) {
4268ec4cf53SLars-Peter Clausen 		st->fixed_addr = pdata->fixed_addr;
4278ec4cf53SLars-Peter Clausen 		st->mode = pdata->mode;
4288ec4cf53SLars-Peter Clausen 		st->range = pdata->range;
4298ec4cf53SLars-Peter Clausen 
4308ec4cf53SLars-Peter Clausen 		if (!st->fixed_addr) {
4318ec4cf53SLars-Peter Clausen 			for (i = 0; i < ARRAY_SIZE(st->gpios); ++i) {
4325750ebabSLinus Walleij 				st->gpios[i] = devm_gpiod_get(&spi->dev,
4335750ebabSLinus Walleij 						      ad7266_gpio_labels[i],
4345750ebabSLinus Walleij 						      GPIOD_OUT_LOW);
4355750ebabSLinus Walleij 				if (IS_ERR(st->gpios[i])) {
4365750ebabSLinus Walleij 					ret = PTR_ERR(st->gpios[i]);
437aac6834dSMaíra Canal 					return ret;
4388ec4cf53SLars-Peter Clausen 				}
4395750ebabSLinus Walleij 			}
4405750ebabSLinus Walleij 		}
4418ec4cf53SLars-Peter Clausen 	} else {
4428ec4cf53SLars-Peter Clausen 		st->fixed_addr = true;
4438ec4cf53SLars-Peter Clausen 		st->range = AD7266_RANGE_VREF;
4448ec4cf53SLars-Peter Clausen 		st->mode = AD7266_MODE_DIFF;
4458ec4cf53SLars-Peter Clausen 	}
4468ec4cf53SLars-Peter Clausen 
4478ec4cf53SLars-Peter Clausen 	st->spi = spi;
4488ec4cf53SLars-Peter Clausen 
4498ec4cf53SLars-Peter Clausen 	indio_dev->name = spi_get_device_id(spi)->name;
4508ec4cf53SLars-Peter Clausen 	indio_dev->modes = INDIO_DIRECT_MODE;
4518ec4cf53SLars-Peter Clausen 	indio_dev->info = &ad7266_info;
4528ec4cf53SLars-Peter Clausen 
4538ec4cf53SLars-Peter Clausen 	ad7266_init_channels(indio_dev);
4548ec4cf53SLars-Peter Clausen 
4558ec4cf53SLars-Peter Clausen 	/* wakeup */
45654e018daSLars-Peter Clausen 	st->single_xfer[0].rx_buf = &st->data.sample[0];
4578ec4cf53SLars-Peter Clausen 	st->single_xfer[0].len = 2;
4588ec4cf53SLars-Peter Clausen 	st->single_xfer[0].cs_change = 1;
4598ec4cf53SLars-Peter Clausen 	/* conversion */
46054e018daSLars-Peter Clausen 	st->single_xfer[1].rx_buf = st->data.sample;
4618ec4cf53SLars-Peter Clausen 	st->single_xfer[1].len = 4;
4628ec4cf53SLars-Peter Clausen 	st->single_xfer[1].cs_change = 1;
4638ec4cf53SLars-Peter Clausen 	/* powerdown */
46454e018daSLars-Peter Clausen 	st->single_xfer[2].tx_buf = &st->data.sample[0];
4658ec4cf53SLars-Peter Clausen 	st->single_xfer[2].len = 1;
4668ec4cf53SLars-Peter Clausen 
4678ec4cf53SLars-Peter Clausen 	spi_message_init(&st->single_msg);
4688ec4cf53SLars-Peter Clausen 	spi_message_add_tail(&st->single_xfer[0], &st->single_msg);
4698ec4cf53SLars-Peter Clausen 	spi_message_add_tail(&st->single_xfer[1], &st->single_msg);
4708ec4cf53SLars-Peter Clausen 	spi_message_add_tail(&st->single_xfer[2], &st->single_msg);
4718ec4cf53SLars-Peter Clausen 
472aac6834dSMaíra Canal 	ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, &iio_pollfunc_store_time,
4738ec4cf53SLars-Peter Clausen 		&ad7266_trigger_handler, &iio_triggered_buffer_setup_ops);
4748ec4cf53SLars-Peter Clausen 	if (ret)
4758ec4cf53SLars-Peter Clausen 		return ret;
4768ec4cf53SLars-Peter Clausen 
477aac6834dSMaíra Canal 	return devm_iio_device_register(&spi->dev, indio_dev);
4788ec4cf53SLars-Peter Clausen }
4798ec4cf53SLars-Peter Clausen 
4808ec4cf53SLars-Peter Clausen static const struct spi_device_id ad7266_id[] = {
4818ec4cf53SLars-Peter Clausen 	{"ad7265", 0},
4828ec4cf53SLars-Peter Clausen 	{"ad7266", 0},
4838ec4cf53SLars-Peter Clausen 	{ }
4848ec4cf53SLars-Peter Clausen };
4858ec4cf53SLars-Peter Clausen MODULE_DEVICE_TABLE(spi, ad7266_id);
4868ec4cf53SLars-Peter Clausen 
4878ec4cf53SLars-Peter Clausen static struct spi_driver ad7266_driver = {
4888ec4cf53SLars-Peter Clausen 	.driver = {
4898ec4cf53SLars-Peter Clausen 		.name	= "ad7266",
4908ec4cf53SLars-Peter Clausen 	},
4918ec4cf53SLars-Peter Clausen 	.probe		= ad7266_probe,
4928ec4cf53SLars-Peter Clausen 	.id_table	= ad7266_id,
4938ec4cf53SLars-Peter Clausen };
4948ec4cf53SLars-Peter Clausen module_spi_driver(ad7266_driver);
4958ec4cf53SLars-Peter Clausen 
4968ec4cf53SLars-Peter Clausen MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
4978ec4cf53SLars-Peter Clausen MODULE_DESCRIPTION("Analog Devices AD7266/65 ADC");
4988ec4cf53SLars-Peter Clausen MODULE_LICENSE("GPL v2");
499