Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d6511322 authored by Ludovic Desroches's avatar Ludovic Desroches Committed by Jonathan Cameron
Browse files

iio:adc:at91-sama5d2: add support for differential conversions



Add signed differential channels and update the voltage scale for
differential conversions.

Signed-off-by: default avatarLudovic Desroches <ludovic.desroches@atmel.com>
Signed-off-by: default avatarJonathan Cameron <jic23@kernel.org>
parent 94b24230
Loading
Loading
Loading
Loading
+56 −15
Original line number Diff line number Diff line
@@ -113,8 +113,11 @@
#define AT91_SAMA5D2_CWR	0x44
/* Channel Gain Register */
#define AT91_SAMA5D2_CGR	0x48

/* Channel Offset Register */
#define AT91_SAMA5D2_COR	0x4c
#define AT91_SAMA5D2_COR_DIFF_OFFSET	16

/* Channel Data Register 0 */
#define AT91_SAMA5D2_CDR0	0x50
/* Analog Control Register */
@@ -142,7 +145,7 @@
/* Version Register */
#define AT91_SAMA5D2_VERSION	0xfc

#define AT91_SAMA5D2_CHAN(num, addr)					\
#define AT91_SAMA5D2_CHAN_SINGLE(num, addr)				\
	{								\
		.type = IIO_VOLTAGE,					\
		.channel = num,						\
@@ -158,6 +161,24 @@
		.indexed = 1,						\
	}

#define AT91_SAMA5D2_CHAN_DIFF(num, num2, addr)				\
	{								\
		.type = IIO_VOLTAGE,					\
		.differential = 1,					\
		.channel = num,						\
		.channel2 = num2,					\
		.address = addr,					\
		.scan_type = {						\
			.sign = 's',					\
			.realbits = 12,					\
		},							\
		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\
		.datasheet_name = "CH"#num"-CH"#num2,			\
		.indexed = 1,						\
	}

#define at91_adc_readl(st, reg)		readl_relaxed(st->base + reg)
#define at91_adc_writel(st, reg, val)	writel_relaxed(val, st->base + reg)

@@ -187,18 +208,24 @@ struct at91_adc_state {
};

static const struct iio_chan_spec at91_adc_channels[] = {
	AT91_SAMA5D2_CHAN(0, 0x50),
	AT91_SAMA5D2_CHAN(1, 0x54),
	AT91_SAMA5D2_CHAN(2, 0x58),
	AT91_SAMA5D2_CHAN(3, 0x5c),
	AT91_SAMA5D2_CHAN(4, 0x60),
	AT91_SAMA5D2_CHAN(5, 0x64),
	AT91_SAMA5D2_CHAN(6, 0x68),
	AT91_SAMA5D2_CHAN(7, 0x6c),
	AT91_SAMA5D2_CHAN(8, 0x70),
	AT91_SAMA5D2_CHAN(9, 0x74),
	AT91_SAMA5D2_CHAN(10, 0x78),
	AT91_SAMA5D2_CHAN(11, 0x7c),
	AT91_SAMA5D2_CHAN_SINGLE(0, 0x50),
	AT91_SAMA5D2_CHAN_SINGLE(1, 0x54),
	AT91_SAMA5D2_CHAN_SINGLE(2, 0x58),
	AT91_SAMA5D2_CHAN_SINGLE(3, 0x5c),
	AT91_SAMA5D2_CHAN_SINGLE(4, 0x60),
	AT91_SAMA5D2_CHAN_SINGLE(5, 0x64),
	AT91_SAMA5D2_CHAN_SINGLE(6, 0x68),
	AT91_SAMA5D2_CHAN_SINGLE(7, 0x6c),
	AT91_SAMA5D2_CHAN_SINGLE(8, 0x70),
	AT91_SAMA5D2_CHAN_SINGLE(9, 0x74),
	AT91_SAMA5D2_CHAN_SINGLE(10, 0x78),
	AT91_SAMA5D2_CHAN_SINGLE(11, 0x7c),
	AT91_SAMA5D2_CHAN_DIFF(0, 1, 0x50),
	AT91_SAMA5D2_CHAN_DIFF(2, 3, 0x58),
	AT91_SAMA5D2_CHAN_DIFF(4, 5, 0x60),
	AT91_SAMA5D2_CHAN_DIFF(6, 7, 0x68),
	AT91_SAMA5D2_CHAN_DIFF(8, 9, 0x70),
	AT91_SAMA5D2_CHAN_DIFF(10, 11, 0x78),
};

static unsigned at91_adc_startup_time(unsigned startup_time_min,
@@ -281,6 +308,7 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev,
			     int *val, int *val2, long mask)
{
	struct at91_adc_state *st = iio_priv(indio_dev);
	u32 cor = 0;
	int ret;

	switch (mask) {
@@ -289,6 +317,11 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev,

		st->chan = chan;

		if (chan->differential)
			cor = (BIT(chan->channel) | BIT(chan->channel2)) <<
			      AT91_SAMA5D2_COR_DIFF_OFFSET;

		at91_adc_writel(st, AT91_SAMA5D2_COR, cor);
		at91_adc_writel(st, AT91_SAMA5D2_CHER, BIT(chan->channel));
		at91_adc_writel(st, AT91_SAMA5D2_IER, BIT(chan->channel));
		at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_START);
@@ -301,6 +334,8 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev,

		if (ret > 0) {
			*val = st->conversion_value;
			if (chan->scan_type.sign == 's')
				*val = sign_extend32(*val, 11);
			ret = IIO_VAL_INT;
			st->conversion_done = false;
		}
@@ -313,6 +348,8 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev,

	case IIO_CHAN_INFO_SCALE:
		*val = st->vref_uv / 1000;
		if (chan->differential)
			*val *= 2;
		*val2 = chan->scan_type.realbits;
		return IIO_VAL_FRACTIONAL_LOG2;

@@ -447,8 +484,12 @@ static int at91_adc_probe(struct platform_device *pdev)

	at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_SWRST);
	at91_adc_writel(st, AT91_SAMA5D2_IDR, 0xffffffff);
	/* Transfer field must be set to 2 according to the datasheet. */
	at91_adc_writel(st, AT91_SAMA5D2_MR, AT91_SAMA5D2_MR_TRANSFER(2));
	/*
	 * Transfer field must be set to 2 according to the datasheet and
	 * allows different analog settings for each channel.
	 */
	at91_adc_writel(st, AT91_SAMA5D2_MR,
			AT91_SAMA5D2_MR_TRANSFER(2) | AT91_SAMA5D2_MR_ANACH);

	at91_adc_setup_samp_freq(st, st->soc_info.min_sample_rate);