2016-03-22 16:08:46

by Ludovic Desroches

[permalink] [raw]
Subject: [PATCH 1/2] iio:adc:at91-sama5d2: cleanup mode register use

Do not erase previous configuration of the mode register when setting
the sampling frequency.

Signed-off-by: Ludovic Desroches <[email protected]>
---
drivers/iio/adc/at91-sama5d2_adc.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
index 5bc038f..01ba106 100644
--- a/drivers/iio/adc/at91-sama5d2_adc.c
+++ b/drivers/iio/adc/at91-sama5d2_adc.c
@@ -66,8 +66,10 @@
#define AT91_SAMA5D2_MR_PRESCAL(v) ((v) << AT91_SAMA5D2_MR_PRESCAL_OFFSET)
#define AT91_SAMA5D2_MR_PRESCAL_OFFSET 8
#define AT91_SAMA5D2_MR_PRESCAL_MAX 0xff
+#define AT91_SAMA5D2_MR_PRESCAL_MASK GENMASK(15, 8)
/* Startup Time */
#define AT91_SAMA5D2_MR_STARTUP(v) ((v) << 16)
+#define AT91_SAMA5D2_MR_STARTUP_MASK GENMASK(19, 16)
/* Analog Change */
#define AT91_SAMA5D2_MR_ANACH BIT(23)
/* Tracking Time */
@@ -226,7 +228,7 @@ static unsigned at91_adc_startup_time(unsigned startup_time_min,
static void at91_adc_setup_samp_freq(struct at91_adc_state *st, unsigned freq)
{
struct iio_dev *indio_dev = iio_priv_to_dev(st);
- unsigned f_per, prescal, startup;
+ unsigned f_per, prescal, startup, mr;

f_per = clk_get_rate(st->per_clk);
prescal = (f_per / (2 * freq)) - 1;
@@ -234,10 +236,11 @@ static void at91_adc_setup_samp_freq(struct at91_adc_state *st, unsigned freq)
startup = at91_adc_startup_time(st->soc_info.startup_time,
freq / 1000);

- at91_adc_writel(st, AT91_SAMA5D2_MR,
- AT91_SAMA5D2_MR_TRANSFER(2)
- | AT91_SAMA5D2_MR_STARTUP(startup)
- | AT91_SAMA5D2_MR_PRESCAL(prescal));
+ mr = at91_adc_readl(st, AT91_SAMA5D2_MR);
+ mr &= ~(AT91_SAMA5D2_MR_STARTUP_MASK | AT91_SAMA5D2_MR_PRESCAL_MASK);
+ mr |= AT91_SAMA5D2_MR_STARTUP(startup);
+ mr |= AT91_SAMA5D2_MR_PRESCAL(prescal);
+ at91_adc_writel(st, AT91_SAMA5D2_MR, mr);

dev_dbg(&indio_dev->dev, "freq: %u, startup: %u, prescal: %u\n",
freq, startup, prescal);
@@ -444,6 +447,8 @@ 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));

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

--
2.5.0


2016-03-22 16:09:22

by Ludovic Desroches

[permalink] [raw]
Subject: [PATCH 2/2] iio:adc:at91-sama5d2: add support for differential conversions

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

Signed-off-by: Ludovic Desroches <[email protected]>
---

This patch is based on:
iio:adc:at91-sama5d2: fix identation
iio:adc:at91-sama5d2: fix typo

drivers/iio/adc/at91-sama5d2_adc.c | 71 ++++++++++++++++++++++++++++++--------
1 file changed, 56 insertions(+), 15 deletions(-)

diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
index 01ba106..07adb10 100644
--- a/drivers/iio/adc/at91-sama5d2_adc.c
+++ b/drivers/iio/adc/at91-sama5d2_adc.c
@@ -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);

--
2.5.0

2016-03-28 14:58:42

by Jonathan Cameron

[permalink] [raw]
Subject: Re: [PATCH 2/2] iio:adc:at91-sama5d2: add support for differential conversions

On 22/03/16 16:08, Ludovic Desroches wrote:
> Add signed differential channels and update the voltage scale for
> differential conversions.
>
> Signed-off-by: Ludovic Desroches <[email protected]>
Looks good to me.

Applied to the togreg branch of iio.git - initially pushed out as testing
etc etc.

Jonathan
> ---
>
> This patch is based on:
> iio:adc:at91-sama5d2: fix identation
> iio:adc:at91-sama5d2: fix typo
>
> drivers/iio/adc/at91-sama5d2_adc.c | 71 ++++++++++++++++++++++++++++++--------
> 1 file changed, 56 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
> index 01ba106..07adb10 100644
> --- a/drivers/iio/adc/at91-sama5d2_adc.c
> +++ b/drivers/iio/adc/at91-sama5d2_adc.c
> @@ -113,8 +113,11 @@
> #define AT91_SAMA5D2_CWR 0x44
> /* Channel Gain Register */
> #define AT91_SAMA5D2_CGR 0x48
> +
Ever so slight gripe here as this is unconnected to this patch so should have
been in a trivial additional patch...
> /* 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);
>
>

2016-03-28 14:59:13

by Jonathan Cameron

[permalink] [raw]
Subject: Re: [PATCH 1/2] iio:adc:at91-sama5d2: cleanup mode register use

On 22/03/16 16:08, Ludovic Desroches wrote:
> Do not erase previous configuration of the mode register when setting
> the sampling frequency.
>
> Signed-off-by: Ludovic Desroches <[email protected]>
Applied.
> ---
> drivers/iio/adc/at91-sama5d2_adc.c | 15 ++++++++++-----
> 1 file changed, 10 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
> index 5bc038f..01ba106 100644
> --- a/drivers/iio/adc/at91-sama5d2_adc.c
> +++ b/drivers/iio/adc/at91-sama5d2_adc.c
> @@ -66,8 +66,10 @@
> #define AT91_SAMA5D2_MR_PRESCAL(v) ((v) << AT91_SAMA5D2_MR_PRESCAL_OFFSET)
> #define AT91_SAMA5D2_MR_PRESCAL_OFFSET 8
> #define AT91_SAMA5D2_MR_PRESCAL_MAX 0xff
> +#define AT91_SAMA5D2_MR_PRESCAL_MASK GENMASK(15, 8)
> /* Startup Time */
> #define AT91_SAMA5D2_MR_STARTUP(v) ((v) << 16)
> +#define AT91_SAMA5D2_MR_STARTUP_MASK GENMASK(19, 16)
> /* Analog Change */
> #define AT91_SAMA5D2_MR_ANACH BIT(23)
> /* Tracking Time */
> @@ -226,7 +228,7 @@ static unsigned at91_adc_startup_time(unsigned startup_time_min,
> static void at91_adc_setup_samp_freq(struct at91_adc_state *st, unsigned freq)
> {
> struct iio_dev *indio_dev = iio_priv_to_dev(st);
> - unsigned f_per, prescal, startup;
> + unsigned f_per, prescal, startup, mr;
>
> f_per = clk_get_rate(st->per_clk);
> prescal = (f_per / (2 * freq)) - 1;
> @@ -234,10 +236,11 @@ static void at91_adc_setup_samp_freq(struct at91_adc_state *st, unsigned freq)
> startup = at91_adc_startup_time(st->soc_info.startup_time,
> freq / 1000);
>
> - at91_adc_writel(st, AT91_SAMA5D2_MR,
> - AT91_SAMA5D2_MR_TRANSFER(2)
> - | AT91_SAMA5D2_MR_STARTUP(startup)
> - | AT91_SAMA5D2_MR_PRESCAL(prescal));
> + mr = at91_adc_readl(st, AT91_SAMA5D2_MR);
> + mr &= ~(AT91_SAMA5D2_MR_STARTUP_MASK | AT91_SAMA5D2_MR_PRESCAL_MASK);
> + mr |= AT91_SAMA5D2_MR_STARTUP(startup);
> + mr |= AT91_SAMA5D2_MR_PRESCAL(prescal);
> + at91_adc_writel(st, AT91_SAMA5D2_MR, mr);
>
> dev_dbg(&indio_dev->dev, "freq: %u, startup: %u, prescal: %u\n",
> freq, startup, prescal);
> @@ -444,6 +447,8 @@ 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));
>
> at91_adc_setup_samp_freq(st, st->soc_info.min_sample_rate);
>
>