All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jonathan Cameron <jic23@kernel.org>
To: Fabrice Gasnier <fabrice.gasnier@st.com>
Cc: <robh+dt@kernel.org>, <linux@armlinux.org.uk>,
	<mark.rutland@arm.com>, <mcoquelin.stm32@gmail.com>,
	<alexandre.torgue@st.com>, <lars@metafoo.de>, <knaack.h@gmx.de>,
	<pmeerw@pmeerw.net>, <benjamin.gaignard@linaro.org>,
	<benjamin.gaignard@st.com>, <linux-iio@vger.kernel.org>,
	<devicetree@vger.kernel.org>,
	<linux-arm-kernel@lists.infradead.org>,
	<linux-kernel@vger.kernel.org>
Subject: Re: [PATCH 3/3] iio: adc: stm32: add optional min-sample-time
Date: Sun, 23 Jul 2017 12:00:22 +0100	[thread overview]
Message-ID: <20170723120022.7d06063e@kernel.org> (raw)
In-Reply-To: <1500381332-17086-4-git-send-email-fabrice.gasnier@st.com>

On Tue, 18 Jul 2017 14:35:32 +0200
Fabrice Gasnier <fabrice.gasnier@st.com> wrote:

> STM32 ADC allows each channel to be sampled with a different sampling time,
> by setting SMPR registers. Basically, value depends on local electrical
> properties. Selecting correct value for sampling time highly depends on
> analog source impedance. There is a manual that may help in this process:
> 'How to get the best ADC accuracy in STM32...'
> 
> This patch allows to configure min-sample-time via device tree, either for:
> - all channels at once:
> min-sample-time = <10000>; /* nanosecs */
> 
> - independently for each channel (must match "st,adc-channels" list):
> st,adc-channels = <0 1>;
> min-sample-time = <5000 10000>; /* nanosecs */
> 
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>

On question inline which may well just be down to me missing what
happens when you query index element 2 from a 1 element device tree
array.
> ---
>  drivers/iio/adc/stm32-adc.c | 134 ++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 130 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
> index 5bfcc1f..e6f6b5e 100644
> --- a/drivers/iio/adc/stm32-adc.c
> +++ b/drivers/iio/adc/stm32-adc.c
> @@ -83,6 +83,8 @@
>  #define STM32H7_ADC_IER			0x04
>  #define STM32H7_ADC_CR			0x08
>  #define STM32H7_ADC_CFGR		0x0C
> +#define STM32H7_ADC_SMPR1		0x14
> +#define STM32H7_ADC_SMPR2		0x18
>  #define STM32H7_ADC_PCSEL		0x1C
>  #define STM32H7_ADC_SQR1		0x30
>  #define STM32H7_ADC_SQR2		0x34
> @@ -151,6 +153,7 @@ enum stm32h7_adc_dmngt {
>  #define STM32H7_BOOST_CLKRATE		20000000UL
>  
>  #define STM32_ADC_MAX_SQ		16	/* SQ1..SQ16 */
> +#define STM32_ADC_MAX_SMP		7	/* SMPx range is [0..7] */
>  #define STM32_ADC_TIMEOUT_US		100000
>  #define STM32_ADC_TIMEOUT	(msecs_to_jiffies(STM32_ADC_TIMEOUT_US / 1000))
>  
> @@ -227,6 +230,8 @@ struct stm32_adc_regs {
>   * @exten:		trigger control register & bitfield
>   * @extsel:		trigger selection register & bitfield
>   * @res:		resolution selection register & bitfield
> + * @smpr:		smpr1 & smpr2 registers offset array
> + * @smp_bits:		smpr1 & smpr2 index and bitfields
>   */
>  struct stm32_adc_regspec {
>  	const u32 dr;
> @@ -236,6 +241,8 @@ struct stm32_adc_regspec {
>  	const struct stm32_adc_regs exten;
>  	const struct stm32_adc_regs extsel;
>  	const struct stm32_adc_regs res;
> +	const u32 smpr[2];
> +	const struct stm32_adc_regs *smp_bits;
>  };
>  
>  struct stm32_adc;
> @@ -251,6 +258,7 @@ struct stm32_adc_regspec {
>   * @start_conv:		routine to start conversions
>   * @stop_conv:		routine to stop conversions
>   * @unprepare:		optional unprepare routine (disable, power-down)
> + * @smp_cycles:		programmable sampling time (ADC clock cycles)
>   */
>  struct stm32_adc_cfg {
>  	const struct stm32_adc_regspec	*regs;
> @@ -262,6 +270,7 @@ struct stm32_adc_cfg {
>  	void (*start_conv)(struct stm32_adc *, bool dma);
>  	void (*stop_conv)(struct stm32_adc *);
>  	void (*unprepare)(struct stm32_adc *);
> +	const unsigned int *smp_cycles;
>  };
>  
>  /**
> @@ -283,6 +292,7 @@ struct stm32_adc_cfg {
>   * @rx_dma_buf:		dma rx buffer bus address
>   * @rx_buf_sz:		dma rx buffer size
>   * @pcsel		bitmask to preselect channels on some devices
> + * @smpr_val:		sampling time settings (e.g. smpr1 / smpr2)
>   * @cal:		optional calibration data on some devices
>   */
>  struct stm32_adc {
> @@ -303,6 +313,7 @@ struct stm32_adc {
>  	dma_addr_t		rx_dma_buf;
>  	unsigned int		rx_buf_sz;
>  	u32			pcsel;
> +	u32			smpr_val[2];
>  	struct stm32_adc_calib	cal;
>  };
>  
> @@ -431,6 +442,39 @@ struct stm32_adc_info {
>  	{}, /* sentinel */
>  };
>  
> +/**
> + * stm32f4_smp_bits[] - describe sampling time register index & bit fields
> + * Sorted so it can be indexed by channel number.
> + */
> +static const struct stm32_adc_regs stm32f4_smp_bits[] = {
> +	/* STM32F4_ADC_SMPR2: smpr[] index, mask, shift for SMP0 to SMP9 */
> +	{ 1, GENMASK(2, 0), 0 },
> +	{ 1, GENMASK(5, 3), 3 },
> +	{ 1, GENMASK(8, 6), 6 },
> +	{ 1, GENMASK(11, 9), 9 },
> +	{ 1, GENMASK(14, 12), 12 },
> +	{ 1, GENMASK(17, 15), 15 },
> +	{ 1, GENMASK(20, 18), 18 },
> +	{ 1, GENMASK(23, 21), 21 },
> +	{ 1, GENMASK(26, 24), 24 },
> +	{ 1, GENMASK(29, 27), 27 },
> +	/* STM32F4_ADC_SMPR1, smpr[] index, mask, shift for SMP10 to SMP18 */
> +	{ 0, GENMASK(2, 0), 0 },
> +	{ 0, GENMASK(5, 3), 3 },
> +	{ 0, GENMASK(8, 6), 6 },
> +	{ 0, GENMASK(11, 9), 9 },
> +	{ 0, GENMASK(14, 12), 12 },
> +	{ 0, GENMASK(17, 15), 15 },
> +	{ 0, GENMASK(20, 18), 18 },
> +	{ 0, GENMASK(23, 21), 21 },
> +	{ 0, GENMASK(26, 24), 24 },
> +};
> +
> +/* STM32F4 programmable sampling time (ADC clock cycles) */
> +static const unsigned int stm32f4_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = {
> +	3, 15, 28, 56, 84, 112, 144, 480,
> +};
> +
>  static const struct stm32_adc_regspec stm32f4_adc_regspec = {
>  	.dr = STM32F4_ADC_DR,
>  	.ier_eoc = { STM32F4_ADC_CR1, STM32F4_EOCIE },
> @@ -440,6 +484,8 @@ struct stm32_adc_info {
>  	.extsel = { STM32F4_ADC_CR2, STM32F4_EXTSEL_MASK,
>  		    STM32F4_EXTSEL_SHIFT },
>  	.res = { STM32F4_ADC_CR1, STM32F4_RES_MASK, STM32F4_RES_SHIFT },
> +	.smpr = { STM32F4_ADC_SMPR1, STM32F4_ADC_SMPR2 },
> +	.smp_bits = stm32f4_smp_bits,
>  };
>  
>  static const struct stm32_adc_regs stm32h7_sq[STM32_ADC_MAX_SQ + 1] = {
> @@ -483,6 +529,40 @@ struct stm32_adc_info {
>  	{},
>  };
>  
> +/**
> + * stm32h7_smp_bits - describe sampling time register index & bit fields
> + * Sorted so it can be indexed by channel number.
> + */
> +static const struct stm32_adc_regs stm32h7_smp_bits[] = {
> +	/* STM32H7_ADC_SMPR1, smpr[] index, mask, shift for SMP0 to SMP9 */
> +	{ 0, GENMASK(2, 0), 0 },
> +	{ 0, GENMASK(5, 3), 3 },
> +	{ 0, GENMASK(8, 6), 6 },
> +	{ 0, GENMASK(11, 9), 9 },
> +	{ 0, GENMASK(14, 12), 12 },
> +	{ 0, GENMASK(17, 15), 15 },
> +	{ 0, GENMASK(20, 18), 18 },
> +	{ 0, GENMASK(23, 21), 21 },
> +	{ 0, GENMASK(26, 24), 24 },
> +	{ 0, GENMASK(29, 27), 27 },
> +	/* STM32H7_ADC_SMPR2, smpr[] index, mask, shift for SMP10 to SMP19 */
> +	{ 1, GENMASK(2, 0), 0 },
> +	{ 1, GENMASK(5, 3), 3 },
> +	{ 1, GENMASK(8, 6), 6 },
> +	{ 1, GENMASK(11, 9), 9 },
> +	{ 1, GENMASK(14, 12), 12 },
> +	{ 1, GENMASK(17, 15), 15 },
> +	{ 1, GENMASK(20, 18), 18 },
> +	{ 1, GENMASK(23, 21), 21 },
> +	{ 1, GENMASK(26, 24), 24 },
> +	{ 1, GENMASK(29, 27), 27 },
> +};
> +
> +/* STM32H7 programmable sampling time (ADC clock cycles, rounded down) */
> +static const unsigned int stm32h7_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = {
> +	1, 2, 8, 16, 32, 64, 387, 810,
> +};
> +
>  static const struct stm32_adc_regspec stm32h7_adc_regspec = {
>  	.dr = STM32H7_ADC_DR,
>  	.ier_eoc = { STM32H7_ADC_IER, STM32H7_EOCIE },
> @@ -492,6 +572,8 @@ struct stm32_adc_info {
>  	.extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK,
>  		    STM32H7_EXTSEL_SHIFT },
>  	.res = { STM32H7_ADC_CFGR, STM32H7_RES_MASK, STM32H7_RES_SHIFT },
> +	.smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 },
> +	.smp_bits = stm32h7_smp_bits,
>  };
>  
>  /**
> @@ -933,6 +1015,7 @@ static void stm32h7_adc_unprepare(struct stm32_adc *adc)
>   * @scan_mask: channels to be converted
>   *
>   * Conversion sequence :
> + * Apply sampling time settings for all channels.
>   * Configure ADC scan sequence based on selected channels in scan_mask.
>   * Add channels to SQR registers, from scan_mask LSB to MSB, then
>   * program sequence len.
> @@ -946,6 +1029,10 @@ static int stm32_adc_conf_scan_seq(struct iio_dev *indio_dev,
>  	u32 val, bit;
>  	int i = 0;
>  
> +	/* Apply sampling time settings */
> +	stm32_adc_writel(adc, adc->cfg->regs->smpr[0], adc->smpr_val[0]);
> +	stm32_adc_writel(adc, adc->cfg->regs->smpr[1], adc->smpr_val[1]);
> +
>  	for_each_set_bit(bit, scan_mask, indio_dev->masklength) {
>  		chan = indio_dev->channels + bit;
>  		/*
> @@ -1079,6 +1166,7 @@ static int stm32_adc_get_trig_pol(struct iio_dev *indio_dev,
>   * @res: conversion result
>   *
>   * The function performs a single conversion on a given channel:
> + * - Apply sampling time settings
>   * - Program sequencer with one channel (e.g. in SQ1 with len = 1)
>   * - Use SW trigger
>   * - Start conversion, then wait for interrupt completion.
> @@ -1103,6 +1191,10 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev,
>  			return ret;
>  	}
>  
> +	/* Apply sampling time settings */
> +	stm32_adc_writel(adc, regs->smpr[0], adc->smpr_val[0]);
> +	stm32_adc_writel(adc, regs->smpr[1], adc->smpr_val[1]);
> +
>  	/* Program chan number in regular sequence (SQ1) */
>  	val = stm32_adc_readl(adc, regs->sqr[1].reg);
>  	val &= ~regs->sqr[1].mask;
> @@ -1507,10 +1599,28 @@ static int stm32_adc_of_get_resolution(struct iio_dev *indio_dev)
>  	return 0;
>  }
>  
> +static void stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns)
> +{
> +	const struct stm32_adc_regs *smpr = &adc->cfg->regs->smp_bits[channel];
> +	u32 period_ns, shift = smpr->shift, mask = smpr->mask;
> +	unsigned int smp, r = smpr->reg;
> +
> +	/* Determine sampling time (ADC clock cycles) */
> +	period_ns = NSEC_PER_SEC / adc->common->rate;
> +	for (smp = 0; smp <= STM32_ADC_MAX_SMP; smp++)
> +		if ((period_ns * adc->cfg->smp_cycles[smp]) >= smp_ns)
> +			break;
> +	if (smp > STM32_ADC_MAX_SMP)
> +		smp = STM32_ADC_MAX_SMP;
> +
> +	/* pre-build sampling time registers (e.g. smpr1, smpr2) */
> +	adc->smpr_val[r] = (adc->smpr_val[r] & ~mask) | (smp << shift);
> +}
> +
>  static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
>  				    struct iio_chan_spec *chan,
>  				    const struct stm32_adc_chan_spec *channel,
> -				    int scan_index)
> +				    int scan_index, u32 smp)
>  {
>  	struct stm32_adc *adc = iio_priv(indio_dev);
>  
> @@ -1526,6 +1636,9 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
>  	chan->scan_type.storagebits = 16;
>  	chan->ext_info = stm32_adc_ext_info;
>  
> +	/* Prepare sampling time settings */
> +	stm32_adc_smpr_init(adc, chan->channel, smp);
> +
>  	/* pre-build selected channels mask */
>  	adc->pcsel |= BIT(chan->channel);
>  }
> @@ -1538,8 +1651,8 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
>  	struct property *prop;
>  	const __be32 *cur;
>  	struct iio_chan_spec *channels;
> -	int scan_index = 0, num_channels;
> -	u32 val;
> +	int scan_index = 0, num_channels, ret;
> +	u32 val, smp = 0;
>  
>  	num_channels = of_property_count_u32_elems(node, "st,adc-channels");
>  	if (num_channels < 0 ||
> @@ -1548,6 +1661,13 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
>  		return num_channels < 0 ? num_channels : -EINVAL;
>  	}
>  
> +	/* Optional sample time is provided either for each, or all channels */
> +	ret = of_property_count_u32_elems(node, "min-sample-time");
> +	if (ret > 1 && ret != num_channels) {
> +		dev_err(&indio_dev->dev, "Invalid min-sample-time\n");
> +		return -EINVAL;
> +	}
> +
>  	channels = devm_kcalloc(&indio_dev->dev, num_channels,
>  				sizeof(struct iio_chan_spec), GFP_KERNEL);
>  	if (!channels)
> @@ -1558,9 +1678,13 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
>  			dev_err(&indio_dev->dev, "Invalid channel %d\n", val);
>  			return -EINVAL;
>  		}
> +
> +		of_property_read_u32_index(node, "min-sample-time", scan_index,
> +					   &smp);
> +
I might be missing something, but doesn't this fail for the single shared
value case?
>  		stm32_adc_chan_init_one(indio_dev, &channels[scan_index],
>  					&adc_info->channels[val],
> -					scan_index);
> +					scan_index, smp);
>  		scan_index++;
>  	}
>  
> @@ -1755,6 +1879,7 @@ static int stm32_adc_remove(struct platform_device *pdev)
>  	.clk_required = true,
>  	.start_conv = stm32f4_adc_start_conv,
>  	.stop_conv = stm32f4_adc_stop_conv,
> +	.smp_cycles = stm32f4_adc_smp_cycles,
>  };
>  
>  static const struct stm32_adc_cfg stm32h7_adc_cfg = {
> @@ -1766,6 +1891,7 @@ static int stm32_adc_remove(struct platform_device *pdev)
>  	.stop_conv = stm32h7_adc_stop_conv,
>  	.prepare = stm32h7_adc_prepare,
>  	.unprepare = stm32h7_adc_unprepare,
> +	.smp_cycles = stm32h7_adc_smp_cycles,
>  };
>  
>  static const struct of_device_id stm32_adc_of_match[] = {


WARNING: multiple messages have this Message-ID (diff)
From: jic23@kernel.org (Jonathan Cameron)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 3/3] iio: adc: stm32: add optional min-sample-time
Date: Sun, 23 Jul 2017 12:00:22 +0100	[thread overview]
Message-ID: <20170723120022.7d06063e@kernel.org> (raw)
In-Reply-To: <1500381332-17086-4-git-send-email-fabrice.gasnier@st.com>

On Tue, 18 Jul 2017 14:35:32 +0200
Fabrice Gasnier <fabrice.gasnier@st.com> wrote:

> STM32 ADC allows each channel to be sampled with a different sampling time,
> by setting SMPR registers. Basically, value depends on local electrical
> properties. Selecting correct value for sampling time highly depends on
> analog source impedance. There is a manual that may help in this process:
> 'How to get the best ADC accuracy in STM32...'
> 
> This patch allows to configure min-sample-time via device tree, either for:
> - all channels at once:
> min-sample-time = <10000>; /* nanosecs */
> 
> - independently for each channel (must match "st,adc-channels" list):
> st,adc-channels = <0 1>;
> min-sample-time = <5000 10000>; /* nanosecs */
> 
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>

On question inline which may well just be down to me missing what
happens when you query index element 2 from a 1 element device tree
array.
> ---
>  drivers/iio/adc/stm32-adc.c | 134 ++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 130 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
> index 5bfcc1f..e6f6b5e 100644
> --- a/drivers/iio/adc/stm32-adc.c
> +++ b/drivers/iio/adc/stm32-adc.c
> @@ -83,6 +83,8 @@
>  #define STM32H7_ADC_IER			0x04
>  #define STM32H7_ADC_CR			0x08
>  #define STM32H7_ADC_CFGR		0x0C
> +#define STM32H7_ADC_SMPR1		0x14
> +#define STM32H7_ADC_SMPR2		0x18
>  #define STM32H7_ADC_PCSEL		0x1C
>  #define STM32H7_ADC_SQR1		0x30
>  #define STM32H7_ADC_SQR2		0x34
> @@ -151,6 +153,7 @@ enum stm32h7_adc_dmngt {
>  #define STM32H7_BOOST_CLKRATE		20000000UL
>  
>  #define STM32_ADC_MAX_SQ		16	/* SQ1..SQ16 */
> +#define STM32_ADC_MAX_SMP		7	/* SMPx range is [0..7] */
>  #define STM32_ADC_TIMEOUT_US		100000
>  #define STM32_ADC_TIMEOUT	(msecs_to_jiffies(STM32_ADC_TIMEOUT_US / 1000))
>  
> @@ -227,6 +230,8 @@ struct stm32_adc_regs {
>   * @exten:		trigger control register & bitfield
>   * @extsel:		trigger selection register & bitfield
>   * @res:		resolution selection register & bitfield
> + * @smpr:		smpr1 & smpr2 registers offset array
> + * @smp_bits:		smpr1 & smpr2 index and bitfields
>   */
>  struct stm32_adc_regspec {
>  	const u32 dr;
> @@ -236,6 +241,8 @@ struct stm32_adc_regspec {
>  	const struct stm32_adc_regs exten;
>  	const struct stm32_adc_regs extsel;
>  	const struct stm32_adc_regs res;
> +	const u32 smpr[2];
> +	const struct stm32_adc_regs *smp_bits;
>  };
>  
>  struct stm32_adc;
> @@ -251,6 +258,7 @@ struct stm32_adc_regspec {
>   * @start_conv:		routine to start conversions
>   * @stop_conv:		routine to stop conversions
>   * @unprepare:		optional unprepare routine (disable, power-down)
> + * @smp_cycles:		programmable sampling time (ADC clock cycles)
>   */
>  struct stm32_adc_cfg {
>  	const struct stm32_adc_regspec	*regs;
> @@ -262,6 +270,7 @@ struct stm32_adc_cfg {
>  	void (*start_conv)(struct stm32_adc *, bool dma);
>  	void (*stop_conv)(struct stm32_adc *);
>  	void (*unprepare)(struct stm32_adc *);
> +	const unsigned int *smp_cycles;
>  };
>  
>  /**
> @@ -283,6 +292,7 @@ struct stm32_adc_cfg {
>   * @rx_dma_buf:		dma rx buffer bus address
>   * @rx_buf_sz:		dma rx buffer size
>   * @pcsel		bitmask to preselect channels on some devices
> + * @smpr_val:		sampling time settings (e.g. smpr1 / smpr2)
>   * @cal:		optional calibration data on some devices
>   */
>  struct stm32_adc {
> @@ -303,6 +313,7 @@ struct stm32_adc {
>  	dma_addr_t		rx_dma_buf;
>  	unsigned int		rx_buf_sz;
>  	u32			pcsel;
> +	u32			smpr_val[2];
>  	struct stm32_adc_calib	cal;
>  };
>  
> @@ -431,6 +442,39 @@ struct stm32_adc_info {
>  	{}, /* sentinel */
>  };
>  
> +/**
> + * stm32f4_smp_bits[] - describe sampling time register index & bit fields
> + * Sorted so it can be indexed by channel number.
> + */
> +static const struct stm32_adc_regs stm32f4_smp_bits[] = {
> +	/* STM32F4_ADC_SMPR2: smpr[] index, mask, shift for SMP0 to SMP9 */
> +	{ 1, GENMASK(2, 0), 0 },
> +	{ 1, GENMASK(5, 3), 3 },
> +	{ 1, GENMASK(8, 6), 6 },
> +	{ 1, GENMASK(11, 9), 9 },
> +	{ 1, GENMASK(14, 12), 12 },
> +	{ 1, GENMASK(17, 15), 15 },
> +	{ 1, GENMASK(20, 18), 18 },
> +	{ 1, GENMASK(23, 21), 21 },
> +	{ 1, GENMASK(26, 24), 24 },
> +	{ 1, GENMASK(29, 27), 27 },
> +	/* STM32F4_ADC_SMPR1, smpr[] index, mask, shift for SMP10 to SMP18 */
> +	{ 0, GENMASK(2, 0), 0 },
> +	{ 0, GENMASK(5, 3), 3 },
> +	{ 0, GENMASK(8, 6), 6 },
> +	{ 0, GENMASK(11, 9), 9 },
> +	{ 0, GENMASK(14, 12), 12 },
> +	{ 0, GENMASK(17, 15), 15 },
> +	{ 0, GENMASK(20, 18), 18 },
> +	{ 0, GENMASK(23, 21), 21 },
> +	{ 0, GENMASK(26, 24), 24 },
> +};
> +
> +/* STM32F4 programmable sampling time (ADC clock cycles) */
> +static const unsigned int stm32f4_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = {
> +	3, 15, 28, 56, 84, 112, 144, 480,
> +};
> +
>  static const struct stm32_adc_regspec stm32f4_adc_regspec = {
>  	.dr = STM32F4_ADC_DR,
>  	.ier_eoc = { STM32F4_ADC_CR1, STM32F4_EOCIE },
> @@ -440,6 +484,8 @@ struct stm32_adc_info {
>  	.extsel = { STM32F4_ADC_CR2, STM32F4_EXTSEL_MASK,
>  		    STM32F4_EXTSEL_SHIFT },
>  	.res = { STM32F4_ADC_CR1, STM32F4_RES_MASK, STM32F4_RES_SHIFT },
> +	.smpr = { STM32F4_ADC_SMPR1, STM32F4_ADC_SMPR2 },
> +	.smp_bits = stm32f4_smp_bits,
>  };
>  
>  static const struct stm32_adc_regs stm32h7_sq[STM32_ADC_MAX_SQ + 1] = {
> @@ -483,6 +529,40 @@ struct stm32_adc_info {
>  	{},
>  };
>  
> +/**
> + * stm32h7_smp_bits - describe sampling time register index & bit fields
> + * Sorted so it can be indexed by channel number.
> + */
> +static const struct stm32_adc_regs stm32h7_smp_bits[] = {
> +	/* STM32H7_ADC_SMPR1, smpr[] index, mask, shift for SMP0 to SMP9 */
> +	{ 0, GENMASK(2, 0), 0 },
> +	{ 0, GENMASK(5, 3), 3 },
> +	{ 0, GENMASK(8, 6), 6 },
> +	{ 0, GENMASK(11, 9), 9 },
> +	{ 0, GENMASK(14, 12), 12 },
> +	{ 0, GENMASK(17, 15), 15 },
> +	{ 0, GENMASK(20, 18), 18 },
> +	{ 0, GENMASK(23, 21), 21 },
> +	{ 0, GENMASK(26, 24), 24 },
> +	{ 0, GENMASK(29, 27), 27 },
> +	/* STM32H7_ADC_SMPR2, smpr[] index, mask, shift for SMP10 to SMP19 */
> +	{ 1, GENMASK(2, 0), 0 },
> +	{ 1, GENMASK(5, 3), 3 },
> +	{ 1, GENMASK(8, 6), 6 },
> +	{ 1, GENMASK(11, 9), 9 },
> +	{ 1, GENMASK(14, 12), 12 },
> +	{ 1, GENMASK(17, 15), 15 },
> +	{ 1, GENMASK(20, 18), 18 },
> +	{ 1, GENMASK(23, 21), 21 },
> +	{ 1, GENMASK(26, 24), 24 },
> +	{ 1, GENMASK(29, 27), 27 },
> +};
> +
> +/* STM32H7 programmable sampling time (ADC clock cycles, rounded down) */
> +static const unsigned int stm32h7_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = {
> +	1, 2, 8, 16, 32, 64, 387, 810,
> +};
> +
>  static const struct stm32_adc_regspec stm32h7_adc_regspec = {
>  	.dr = STM32H7_ADC_DR,
>  	.ier_eoc = { STM32H7_ADC_IER, STM32H7_EOCIE },
> @@ -492,6 +572,8 @@ struct stm32_adc_info {
>  	.extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK,
>  		    STM32H7_EXTSEL_SHIFT },
>  	.res = { STM32H7_ADC_CFGR, STM32H7_RES_MASK, STM32H7_RES_SHIFT },
> +	.smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 },
> +	.smp_bits = stm32h7_smp_bits,
>  };
>  
>  /**
> @@ -933,6 +1015,7 @@ static void stm32h7_adc_unprepare(struct stm32_adc *adc)
>   * @scan_mask: channels to be converted
>   *
>   * Conversion sequence :
> + * Apply sampling time settings for all channels.
>   * Configure ADC scan sequence based on selected channels in scan_mask.
>   * Add channels to SQR registers, from scan_mask LSB to MSB, then
>   * program sequence len.
> @@ -946,6 +1029,10 @@ static int stm32_adc_conf_scan_seq(struct iio_dev *indio_dev,
>  	u32 val, bit;
>  	int i = 0;
>  
> +	/* Apply sampling time settings */
> +	stm32_adc_writel(adc, adc->cfg->regs->smpr[0], adc->smpr_val[0]);
> +	stm32_adc_writel(adc, adc->cfg->regs->smpr[1], adc->smpr_val[1]);
> +
>  	for_each_set_bit(bit, scan_mask, indio_dev->masklength) {
>  		chan = indio_dev->channels + bit;
>  		/*
> @@ -1079,6 +1166,7 @@ static int stm32_adc_get_trig_pol(struct iio_dev *indio_dev,
>   * @res: conversion result
>   *
>   * The function performs a single conversion on a given channel:
> + * - Apply sampling time settings
>   * - Program sequencer with one channel (e.g. in SQ1 with len = 1)
>   * - Use SW trigger
>   * - Start conversion, then wait for interrupt completion.
> @@ -1103,6 +1191,10 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev,
>  			return ret;
>  	}
>  
> +	/* Apply sampling time settings */
> +	stm32_adc_writel(adc, regs->smpr[0], adc->smpr_val[0]);
> +	stm32_adc_writel(adc, regs->smpr[1], adc->smpr_val[1]);
> +
>  	/* Program chan number in regular sequence (SQ1) */
>  	val = stm32_adc_readl(adc, regs->sqr[1].reg);
>  	val &= ~regs->sqr[1].mask;
> @@ -1507,10 +1599,28 @@ static int stm32_adc_of_get_resolution(struct iio_dev *indio_dev)
>  	return 0;
>  }
>  
> +static void stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns)
> +{
> +	const struct stm32_adc_regs *smpr = &adc->cfg->regs->smp_bits[channel];
> +	u32 period_ns, shift = smpr->shift, mask = smpr->mask;
> +	unsigned int smp, r = smpr->reg;
> +
> +	/* Determine sampling time (ADC clock cycles) */
> +	period_ns = NSEC_PER_SEC / adc->common->rate;
> +	for (smp = 0; smp <= STM32_ADC_MAX_SMP; smp++)
> +		if ((period_ns * adc->cfg->smp_cycles[smp]) >= smp_ns)
> +			break;
> +	if (smp > STM32_ADC_MAX_SMP)
> +		smp = STM32_ADC_MAX_SMP;
> +
> +	/* pre-build sampling time registers (e.g. smpr1, smpr2) */
> +	adc->smpr_val[r] = (adc->smpr_val[r] & ~mask) | (smp << shift);
> +}
> +
>  static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
>  				    struct iio_chan_spec *chan,
>  				    const struct stm32_adc_chan_spec *channel,
> -				    int scan_index)
> +				    int scan_index, u32 smp)
>  {
>  	struct stm32_adc *adc = iio_priv(indio_dev);
>  
> @@ -1526,6 +1636,9 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
>  	chan->scan_type.storagebits = 16;
>  	chan->ext_info = stm32_adc_ext_info;
>  
> +	/* Prepare sampling time settings */
> +	stm32_adc_smpr_init(adc, chan->channel, smp);
> +
>  	/* pre-build selected channels mask */
>  	adc->pcsel |= BIT(chan->channel);
>  }
> @@ -1538,8 +1651,8 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
>  	struct property *prop;
>  	const __be32 *cur;
>  	struct iio_chan_spec *channels;
> -	int scan_index = 0, num_channels;
> -	u32 val;
> +	int scan_index = 0, num_channels, ret;
> +	u32 val, smp = 0;
>  
>  	num_channels = of_property_count_u32_elems(node, "st,adc-channels");
>  	if (num_channels < 0 ||
> @@ -1548,6 +1661,13 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
>  		return num_channels < 0 ? num_channels : -EINVAL;
>  	}
>  
> +	/* Optional sample time is provided either for each, or all channels */
> +	ret = of_property_count_u32_elems(node, "min-sample-time");
> +	if (ret > 1 && ret != num_channels) {
> +		dev_err(&indio_dev->dev, "Invalid min-sample-time\n");
> +		return -EINVAL;
> +	}
> +
>  	channels = devm_kcalloc(&indio_dev->dev, num_channels,
>  				sizeof(struct iio_chan_spec), GFP_KERNEL);
>  	if (!channels)
> @@ -1558,9 +1678,13 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
>  			dev_err(&indio_dev->dev, "Invalid channel %d\n", val);
>  			return -EINVAL;
>  		}
> +
> +		of_property_read_u32_index(node, "min-sample-time", scan_index,
> +					   &smp);
> +
I might be missing something, but doesn't this fail for the single shared
value case?
>  		stm32_adc_chan_init_one(indio_dev, &channels[scan_index],
>  					&adc_info->channels[val],
> -					scan_index);
> +					scan_index, smp);
>  		scan_index++;
>  	}
>  
> @@ -1755,6 +1879,7 @@ static int stm32_adc_remove(struct platform_device *pdev)
>  	.clk_required = true,
>  	.start_conv = stm32f4_adc_start_conv,
>  	.stop_conv = stm32f4_adc_stop_conv,
> +	.smp_cycles = stm32f4_adc_smp_cycles,
>  };
>  
>  static const struct stm32_adc_cfg stm32h7_adc_cfg = {
> @@ -1766,6 +1891,7 @@ static int stm32_adc_remove(struct platform_device *pdev)
>  	.stop_conv = stm32h7_adc_stop_conv,
>  	.prepare = stm32h7_adc_prepare,
>  	.unprepare = stm32h7_adc_unprepare,
> +	.smp_cycles = stm32h7_adc_smp_cycles,
>  };
>  
>  static const struct of_device_id stm32_adc_of_match[] = {

WARNING: multiple messages have this Message-ID (diff)
From: Jonathan Cameron <jic23@kernel.org>
To: Fabrice Gasnier <fabrice.gasnier@st.com>
Cc: robh+dt@kernel.org, linux@armlinux.org.uk, mark.rutland@arm.com,
	mcoquelin.stm32@gmail.com, alexandre.torgue@st.com,
	lars@metafoo.de, knaack.h@gmx.de, pmeerw@pmeerw.net,
	benjamin.gaignard@linaro.org, benjamin.gaignard@st.com,
	linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH 3/3] iio: adc: stm32: add optional min-sample-time
Date: Sun, 23 Jul 2017 12:00:22 +0100	[thread overview]
Message-ID: <20170723120022.7d06063e@kernel.org> (raw)
In-Reply-To: <1500381332-17086-4-git-send-email-fabrice.gasnier@st.com>

On Tue, 18 Jul 2017 14:35:32 +0200
Fabrice Gasnier <fabrice.gasnier@st.com> wrote:

> STM32 ADC allows each channel to be sampled with a different sampling time,
> by setting SMPR registers. Basically, value depends on local electrical
> properties. Selecting correct value for sampling time highly depends on
> analog source impedance. There is a manual that may help in this process:
> 'How to get the best ADC accuracy in STM32...'
> 
> This patch allows to configure min-sample-time via device tree, either for:
> - all channels at once:
> min-sample-time = <10000>; /* nanosecs */
> 
> - independently for each channel (must match "st,adc-channels" list):
> st,adc-channels = <0 1>;
> min-sample-time = <5000 10000>; /* nanosecs */
> 
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>

On question inline which may well just be down to me missing what
happens when you query index element 2 from a 1 element device tree
array.
> ---
>  drivers/iio/adc/stm32-adc.c | 134 ++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 130 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
> index 5bfcc1f..e6f6b5e 100644
> --- a/drivers/iio/adc/stm32-adc.c
> +++ b/drivers/iio/adc/stm32-adc.c
> @@ -83,6 +83,8 @@
>  #define STM32H7_ADC_IER			0x04
>  #define STM32H7_ADC_CR			0x08
>  #define STM32H7_ADC_CFGR		0x0C
> +#define STM32H7_ADC_SMPR1		0x14
> +#define STM32H7_ADC_SMPR2		0x18
>  #define STM32H7_ADC_PCSEL		0x1C
>  #define STM32H7_ADC_SQR1		0x30
>  #define STM32H7_ADC_SQR2		0x34
> @@ -151,6 +153,7 @@ enum stm32h7_adc_dmngt {
>  #define STM32H7_BOOST_CLKRATE		20000000UL
>  
>  #define STM32_ADC_MAX_SQ		16	/* SQ1..SQ16 */
> +#define STM32_ADC_MAX_SMP		7	/* SMPx range is [0..7] */
>  #define STM32_ADC_TIMEOUT_US		100000
>  #define STM32_ADC_TIMEOUT	(msecs_to_jiffies(STM32_ADC_TIMEOUT_US / 1000))
>  
> @@ -227,6 +230,8 @@ struct stm32_adc_regs {
>   * @exten:		trigger control register & bitfield
>   * @extsel:		trigger selection register & bitfield
>   * @res:		resolution selection register & bitfield
> + * @smpr:		smpr1 & smpr2 registers offset array
> + * @smp_bits:		smpr1 & smpr2 index and bitfields
>   */
>  struct stm32_adc_regspec {
>  	const u32 dr;
> @@ -236,6 +241,8 @@ struct stm32_adc_regspec {
>  	const struct stm32_adc_regs exten;
>  	const struct stm32_adc_regs extsel;
>  	const struct stm32_adc_regs res;
> +	const u32 smpr[2];
> +	const struct stm32_adc_regs *smp_bits;
>  };
>  
>  struct stm32_adc;
> @@ -251,6 +258,7 @@ struct stm32_adc_regspec {
>   * @start_conv:		routine to start conversions
>   * @stop_conv:		routine to stop conversions
>   * @unprepare:		optional unprepare routine (disable, power-down)
> + * @smp_cycles:		programmable sampling time (ADC clock cycles)
>   */
>  struct stm32_adc_cfg {
>  	const struct stm32_adc_regspec	*regs;
> @@ -262,6 +270,7 @@ struct stm32_adc_cfg {
>  	void (*start_conv)(struct stm32_adc *, bool dma);
>  	void (*stop_conv)(struct stm32_adc *);
>  	void (*unprepare)(struct stm32_adc *);
> +	const unsigned int *smp_cycles;
>  };
>  
>  /**
> @@ -283,6 +292,7 @@ struct stm32_adc_cfg {
>   * @rx_dma_buf:		dma rx buffer bus address
>   * @rx_buf_sz:		dma rx buffer size
>   * @pcsel		bitmask to preselect channels on some devices
> + * @smpr_val:		sampling time settings (e.g. smpr1 / smpr2)
>   * @cal:		optional calibration data on some devices
>   */
>  struct stm32_adc {
> @@ -303,6 +313,7 @@ struct stm32_adc {
>  	dma_addr_t		rx_dma_buf;
>  	unsigned int		rx_buf_sz;
>  	u32			pcsel;
> +	u32			smpr_val[2];
>  	struct stm32_adc_calib	cal;
>  };
>  
> @@ -431,6 +442,39 @@ struct stm32_adc_info {
>  	{}, /* sentinel */
>  };
>  
> +/**
> + * stm32f4_smp_bits[] - describe sampling time register index & bit fields
> + * Sorted so it can be indexed by channel number.
> + */
> +static const struct stm32_adc_regs stm32f4_smp_bits[] = {
> +	/* STM32F4_ADC_SMPR2: smpr[] index, mask, shift for SMP0 to SMP9 */
> +	{ 1, GENMASK(2, 0), 0 },
> +	{ 1, GENMASK(5, 3), 3 },
> +	{ 1, GENMASK(8, 6), 6 },
> +	{ 1, GENMASK(11, 9), 9 },
> +	{ 1, GENMASK(14, 12), 12 },
> +	{ 1, GENMASK(17, 15), 15 },
> +	{ 1, GENMASK(20, 18), 18 },
> +	{ 1, GENMASK(23, 21), 21 },
> +	{ 1, GENMASK(26, 24), 24 },
> +	{ 1, GENMASK(29, 27), 27 },
> +	/* STM32F4_ADC_SMPR1, smpr[] index, mask, shift for SMP10 to SMP18 */
> +	{ 0, GENMASK(2, 0), 0 },
> +	{ 0, GENMASK(5, 3), 3 },
> +	{ 0, GENMASK(8, 6), 6 },
> +	{ 0, GENMASK(11, 9), 9 },
> +	{ 0, GENMASK(14, 12), 12 },
> +	{ 0, GENMASK(17, 15), 15 },
> +	{ 0, GENMASK(20, 18), 18 },
> +	{ 0, GENMASK(23, 21), 21 },
> +	{ 0, GENMASK(26, 24), 24 },
> +};
> +
> +/* STM32F4 programmable sampling time (ADC clock cycles) */
> +static const unsigned int stm32f4_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = {
> +	3, 15, 28, 56, 84, 112, 144, 480,
> +};
> +
>  static const struct stm32_adc_regspec stm32f4_adc_regspec = {
>  	.dr = STM32F4_ADC_DR,
>  	.ier_eoc = { STM32F4_ADC_CR1, STM32F4_EOCIE },
> @@ -440,6 +484,8 @@ struct stm32_adc_info {
>  	.extsel = { STM32F4_ADC_CR2, STM32F4_EXTSEL_MASK,
>  		    STM32F4_EXTSEL_SHIFT },
>  	.res = { STM32F4_ADC_CR1, STM32F4_RES_MASK, STM32F4_RES_SHIFT },
> +	.smpr = { STM32F4_ADC_SMPR1, STM32F4_ADC_SMPR2 },
> +	.smp_bits = stm32f4_smp_bits,
>  };
>  
>  static const struct stm32_adc_regs stm32h7_sq[STM32_ADC_MAX_SQ + 1] = {
> @@ -483,6 +529,40 @@ struct stm32_adc_info {
>  	{},
>  };
>  
> +/**
> + * stm32h7_smp_bits - describe sampling time register index & bit fields
> + * Sorted so it can be indexed by channel number.
> + */
> +static const struct stm32_adc_regs stm32h7_smp_bits[] = {
> +	/* STM32H7_ADC_SMPR1, smpr[] index, mask, shift for SMP0 to SMP9 */
> +	{ 0, GENMASK(2, 0), 0 },
> +	{ 0, GENMASK(5, 3), 3 },
> +	{ 0, GENMASK(8, 6), 6 },
> +	{ 0, GENMASK(11, 9), 9 },
> +	{ 0, GENMASK(14, 12), 12 },
> +	{ 0, GENMASK(17, 15), 15 },
> +	{ 0, GENMASK(20, 18), 18 },
> +	{ 0, GENMASK(23, 21), 21 },
> +	{ 0, GENMASK(26, 24), 24 },
> +	{ 0, GENMASK(29, 27), 27 },
> +	/* STM32H7_ADC_SMPR2, smpr[] index, mask, shift for SMP10 to SMP19 */
> +	{ 1, GENMASK(2, 0), 0 },
> +	{ 1, GENMASK(5, 3), 3 },
> +	{ 1, GENMASK(8, 6), 6 },
> +	{ 1, GENMASK(11, 9), 9 },
> +	{ 1, GENMASK(14, 12), 12 },
> +	{ 1, GENMASK(17, 15), 15 },
> +	{ 1, GENMASK(20, 18), 18 },
> +	{ 1, GENMASK(23, 21), 21 },
> +	{ 1, GENMASK(26, 24), 24 },
> +	{ 1, GENMASK(29, 27), 27 },
> +};
> +
> +/* STM32H7 programmable sampling time (ADC clock cycles, rounded down) */
> +static const unsigned int stm32h7_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = {
> +	1, 2, 8, 16, 32, 64, 387, 810,
> +};
> +
>  static const struct stm32_adc_regspec stm32h7_adc_regspec = {
>  	.dr = STM32H7_ADC_DR,
>  	.ier_eoc = { STM32H7_ADC_IER, STM32H7_EOCIE },
> @@ -492,6 +572,8 @@ struct stm32_adc_info {
>  	.extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK,
>  		    STM32H7_EXTSEL_SHIFT },
>  	.res = { STM32H7_ADC_CFGR, STM32H7_RES_MASK, STM32H7_RES_SHIFT },
> +	.smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 },
> +	.smp_bits = stm32h7_smp_bits,
>  };
>  
>  /**
> @@ -933,6 +1015,7 @@ static void stm32h7_adc_unprepare(struct stm32_adc *adc)
>   * @scan_mask: channels to be converted
>   *
>   * Conversion sequence :
> + * Apply sampling time settings for all channels.
>   * Configure ADC scan sequence based on selected channels in scan_mask.
>   * Add channels to SQR registers, from scan_mask LSB to MSB, then
>   * program sequence len.
> @@ -946,6 +1029,10 @@ static int stm32_adc_conf_scan_seq(struct iio_dev *indio_dev,
>  	u32 val, bit;
>  	int i = 0;
>  
> +	/* Apply sampling time settings */
> +	stm32_adc_writel(adc, adc->cfg->regs->smpr[0], adc->smpr_val[0]);
> +	stm32_adc_writel(adc, adc->cfg->regs->smpr[1], adc->smpr_val[1]);
> +
>  	for_each_set_bit(bit, scan_mask, indio_dev->masklength) {
>  		chan = indio_dev->channels + bit;
>  		/*
> @@ -1079,6 +1166,7 @@ static int stm32_adc_get_trig_pol(struct iio_dev *indio_dev,
>   * @res: conversion result
>   *
>   * The function performs a single conversion on a given channel:
> + * - Apply sampling time settings
>   * - Program sequencer with one channel (e.g. in SQ1 with len = 1)
>   * - Use SW trigger
>   * - Start conversion, then wait for interrupt completion.
> @@ -1103,6 +1191,10 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev,
>  			return ret;
>  	}
>  
> +	/* Apply sampling time settings */
> +	stm32_adc_writel(adc, regs->smpr[0], adc->smpr_val[0]);
> +	stm32_adc_writel(adc, regs->smpr[1], adc->smpr_val[1]);
> +
>  	/* Program chan number in regular sequence (SQ1) */
>  	val = stm32_adc_readl(adc, regs->sqr[1].reg);
>  	val &= ~regs->sqr[1].mask;
> @@ -1507,10 +1599,28 @@ static int stm32_adc_of_get_resolution(struct iio_dev *indio_dev)
>  	return 0;
>  }
>  
> +static void stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns)
> +{
> +	const struct stm32_adc_regs *smpr = &adc->cfg->regs->smp_bits[channel];
> +	u32 period_ns, shift = smpr->shift, mask = smpr->mask;
> +	unsigned int smp, r = smpr->reg;
> +
> +	/* Determine sampling time (ADC clock cycles) */
> +	period_ns = NSEC_PER_SEC / adc->common->rate;
> +	for (smp = 0; smp <= STM32_ADC_MAX_SMP; smp++)
> +		if ((period_ns * adc->cfg->smp_cycles[smp]) >= smp_ns)
> +			break;
> +	if (smp > STM32_ADC_MAX_SMP)
> +		smp = STM32_ADC_MAX_SMP;
> +
> +	/* pre-build sampling time registers (e.g. smpr1, smpr2) */
> +	adc->smpr_val[r] = (adc->smpr_val[r] & ~mask) | (smp << shift);
> +}
> +
>  static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
>  				    struct iio_chan_spec *chan,
>  				    const struct stm32_adc_chan_spec *channel,
> -				    int scan_index)
> +				    int scan_index, u32 smp)
>  {
>  	struct stm32_adc *adc = iio_priv(indio_dev);
>  
> @@ -1526,6 +1636,9 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
>  	chan->scan_type.storagebits = 16;
>  	chan->ext_info = stm32_adc_ext_info;
>  
> +	/* Prepare sampling time settings */
> +	stm32_adc_smpr_init(adc, chan->channel, smp);
> +
>  	/* pre-build selected channels mask */
>  	adc->pcsel |= BIT(chan->channel);
>  }
> @@ -1538,8 +1651,8 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
>  	struct property *prop;
>  	const __be32 *cur;
>  	struct iio_chan_spec *channels;
> -	int scan_index = 0, num_channels;
> -	u32 val;
> +	int scan_index = 0, num_channels, ret;
> +	u32 val, smp = 0;
>  
>  	num_channels = of_property_count_u32_elems(node, "st,adc-channels");
>  	if (num_channels < 0 ||
> @@ -1548,6 +1661,13 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
>  		return num_channels < 0 ? num_channels : -EINVAL;
>  	}
>  
> +	/* Optional sample time is provided either for each, or all channels */
> +	ret = of_property_count_u32_elems(node, "min-sample-time");
> +	if (ret > 1 && ret != num_channels) {
> +		dev_err(&indio_dev->dev, "Invalid min-sample-time\n");
> +		return -EINVAL;
> +	}
> +
>  	channels = devm_kcalloc(&indio_dev->dev, num_channels,
>  				sizeof(struct iio_chan_spec), GFP_KERNEL);
>  	if (!channels)
> @@ -1558,9 +1678,13 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
>  			dev_err(&indio_dev->dev, "Invalid channel %d\n", val);
>  			return -EINVAL;
>  		}
> +
> +		of_property_read_u32_index(node, "min-sample-time", scan_index,
> +					   &smp);
> +
I might be missing something, but doesn't this fail for the single shared
value case?
>  		stm32_adc_chan_init_one(indio_dev, &channels[scan_index],
>  					&adc_info->channels[val],
> -					scan_index);
> +					scan_index, smp);
>  		scan_index++;
>  	}
>  
> @@ -1755,6 +1879,7 @@ static int stm32_adc_remove(struct platform_device *pdev)
>  	.clk_required = true,
>  	.start_conv = stm32f4_adc_start_conv,
>  	.stop_conv = stm32f4_adc_stop_conv,
> +	.smp_cycles = stm32f4_adc_smp_cycles,
>  };
>  
>  static const struct stm32_adc_cfg stm32h7_adc_cfg = {
> @@ -1766,6 +1891,7 @@ static int stm32_adc_remove(struct platform_device *pdev)
>  	.stop_conv = stm32h7_adc_stop_conv,
>  	.prepare = stm32h7_adc_prepare,
>  	.unprepare = stm32h7_adc_unprepare,
> +	.smp_cycles = stm32h7_adc_smp_cycles,
>  };
>  
>  static const struct of_device_id stm32_adc_of_match[] = {

  reply	other threads:[~2017-07-23 11:00 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-07-18 12:35 [PATCH 0/3] Allow to tune sampling time on STM32 ADC Fabrice Gasnier
2017-07-18 12:35 ` Fabrice Gasnier
2017-07-18 12:35 ` Fabrice Gasnier
2017-07-18 12:35 ` [PATCH 1/3] iio: adc: stm32: fix common clock rate Fabrice Gasnier
2017-07-18 12:35   ` Fabrice Gasnier
2017-07-18 12:35   ` Fabrice Gasnier
2017-07-23 10:51   ` Jonathan Cameron
2017-07-23 10:51     ` Jonathan Cameron
2017-07-23 10:51     ` Jonathan Cameron
2017-07-24  7:43     ` Fabrice Gasnier
2017-07-24  7:43       ` Fabrice Gasnier
2017-07-24  7:43       ` Fabrice Gasnier
2017-07-24 15:03       ` Jonathan Cameron
2017-07-24 15:03         ` Jonathan Cameron
2017-07-24 15:03         ` Jonathan Cameron
2017-07-18 12:35 ` [PATCH 2/3] dt-bindings: iio: adc: stm32: add optional min-sample-time Fabrice Gasnier
2017-07-18 12:35   ` Fabrice Gasnier
2017-07-18 12:35   ` Fabrice Gasnier
2017-07-23 10:53   ` Jonathan Cameron
2017-07-23 10:53     ` Jonathan Cameron
2017-07-23 10:53     ` Jonathan Cameron
2017-07-24  7:55     ` Fabrice Gasnier
2017-07-24  7:55       ` Fabrice Gasnier
2017-07-24  7:55       ` Fabrice Gasnier
2017-07-24 15:04       ` Jonathan Cameron
2017-07-24 15:04         ` Jonathan Cameron
2017-07-24 15:04         ` Jonathan Cameron
2017-07-18 12:35 ` [PATCH 3/3] " Fabrice Gasnier
2017-07-18 12:35   ` Fabrice Gasnier
2017-07-18 12:35   ` Fabrice Gasnier
2017-07-23 11:00   ` Jonathan Cameron [this message]
2017-07-23 11:00     ` Jonathan Cameron
2017-07-23 11:00     ` Jonathan Cameron
2017-07-24  8:16     ` Fabrice Gasnier
2017-07-24  8:16       ` Fabrice Gasnier
2017-07-24  8:16       ` Fabrice Gasnier
2017-07-24 15:06       ` Jonathan Cameron
2017-07-24 15:06         ` Jonathan Cameron
2017-07-24 15:06         ` Jonathan Cameron

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170723120022.7d06063e@kernel.org \
    --to=jic23@kernel.org \
    --cc=alexandre.torgue@st.com \
    --cc=benjamin.gaignard@linaro.org \
    --cc=benjamin.gaignard@st.com \
    --cc=devicetree@vger.kernel.org \
    --cc=fabrice.gasnier@st.com \
    --cc=knaack.h@gmx.de \
    --cc=lars@metafoo.de \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@armlinux.org.uk \
    --cc=mark.rutland@arm.com \
    --cc=mcoquelin.stm32@gmail.com \
    --cc=pmeerw@pmeerw.net \
    --cc=robh+dt@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.