xref: /openbmc/linux/drivers/iio/adc/stm32-dfsdm-adc.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1e2e6771cSArnaud Pouliquen // SPDX-License-Identifier: GPL-2.0
2e2e6771cSArnaud Pouliquen /*
3e2e6771cSArnaud Pouliquen  * This file is the ADC part of the STM32 DFSDM driver
4e2e6771cSArnaud Pouliquen  *
5e2e6771cSArnaud Pouliquen  * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
6e2e6771cSArnaud Pouliquen  * Author: Arnaud Pouliquen <arnaud.pouliquen@st.com>.
7e2e6771cSArnaud Pouliquen  */
8e2e6771cSArnaud Pouliquen 
9eca94980SArnaud Pouliquen #include <linux/dmaengine.h>
10eca94980SArnaud Pouliquen #include <linux/dma-mapping.h>
11ed582db6SFabrice Gasnier #include <linux/iio/adc/stm32-dfsdm-adc.h>
12e2e6771cSArnaud Pouliquen #include <linux/iio/buffer.h>
13e2e6771cSArnaud Pouliquen #include <linux/iio/hw-consumer.h>
14e2e6771cSArnaud Pouliquen #include <linux/iio/sysfs.h>
1511646e81SFabrice Gasnier #include <linux/iio/timer/stm32-lptim-trigger.h>
1611646e81SFabrice Gasnier #include <linux/iio/timer/stm32-timer-trigger.h>
1711646e81SFabrice Gasnier #include <linux/iio/trigger.h>
1811646e81SFabrice Gasnier #include <linux/iio/trigger_consumer.h>
1911646e81SFabrice Gasnier #include <linux/iio/triggered_buffer.h>
20ed582db6SFabrice Gasnier #include <linux/interrupt.h>
21e2e6771cSArnaud Pouliquen #include <linux/module.h>
22*1240c94cSRob Herring #include <linux/of.h>
23*1240c94cSRob Herring #include <linux/of_platform.h>
24e2e6771cSArnaud Pouliquen #include <linux/platform_device.h>
25e2e6771cSArnaud Pouliquen #include <linux/regmap.h>
26e2e6771cSArnaud Pouliquen #include <linux/slab.h>
27e2e6771cSArnaud Pouliquen 
28e2e6771cSArnaud Pouliquen #include "stm32-dfsdm.h"
29e2e6771cSArnaud Pouliquen 
30eca94980SArnaud Pouliquen #define DFSDM_DMA_BUFFER_SIZE (4 * PAGE_SIZE)
31eca94980SArnaud Pouliquen 
32e2e6771cSArnaud Pouliquen /* Conversion timeout */
33e2e6771cSArnaud Pouliquen #define DFSDM_TIMEOUT_US 100000
34e2e6771cSArnaud Pouliquen #define DFSDM_TIMEOUT (msecs_to_jiffies(DFSDM_TIMEOUT_US / 1000))
35e2e6771cSArnaud Pouliquen 
36e2e6771cSArnaud Pouliquen /* Oversampling attribute default */
37e2e6771cSArnaud Pouliquen #define DFSDM_DEFAULT_OVERSAMPLING  100
38e2e6771cSArnaud Pouliquen 
39e2e6771cSArnaud Pouliquen /* Oversampling max values */
40e2e6771cSArnaud Pouliquen #define DFSDM_MAX_INT_OVERSAMPLING 256
41e2e6771cSArnaud Pouliquen #define DFSDM_MAX_FL_OVERSAMPLING 1024
42e2e6771cSArnaud Pouliquen 
4312c8398dSOlivier Moysan /* Limit filter output resolution to 31 bits. (i.e. sample range is +/-2^30) */
4412c8398dSOlivier Moysan #define DFSDM_DATA_MAX BIT(30)
4512c8398dSOlivier Moysan /*
4612c8398dSOlivier Moysan  * Data are output as two's complement data in a 24 bit field.
4712c8398dSOlivier Moysan  * Data from filters are in the range +/-2^(n-1)
4812c8398dSOlivier Moysan  * 2^(n-1) maximum positive value cannot be coded in 2's complement n bits
4912c8398dSOlivier Moysan  * An extra bit is required to avoid wrap-around of the binary code for 2^(n-1)
5012c8398dSOlivier Moysan  * So, the resolution of samples from filter is actually limited to 23 bits
5112c8398dSOlivier Moysan  */
5212c8398dSOlivier Moysan #define DFSDM_DATA_RES 24
53e2e6771cSArnaud Pouliquen 
546f2c4a59SFabrice Gasnier /* Filter configuration */
556f2c4a59SFabrice Gasnier #define DFSDM_CR1_CFG_MASK (DFSDM_CR1_RCH_MASK | DFSDM_CR1_RCONT_MASK | \
56a6096762SFabrice Gasnier 			    DFSDM_CR1_RSYNC_MASK | DFSDM_CR1_JSYNC_MASK | \
57a6096762SFabrice Gasnier 			    DFSDM_CR1_JSCAN_MASK)
586f2c4a59SFabrice Gasnier 
59e2e6771cSArnaud Pouliquen enum sd_converter_type {
60e2e6771cSArnaud Pouliquen 	DFSDM_AUDIO,
61e2e6771cSArnaud Pouliquen 	DFSDM_IIO,
62e2e6771cSArnaud Pouliquen };
63e2e6771cSArnaud Pouliquen 
64e2e6771cSArnaud Pouliquen struct stm32_dfsdm_dev_data {
65e2e6771cSArnaud Pouliquen 	int type;
66b455d06eSFabrice Gasnier 	int (*init)(struct device *dev, struct iio_dev *indio_dev);
67e2e6771cSArnaud Pouliquen 	unsigned int num_channels;
68e2e6771cSArnaud Pouliquen 	const struct regmap_config *regmap_cfg;
69e2e6771cSArnaud Pouliquen };
70e2e6771cSArnaud Pouliquen 
71e2e6771cSArnaud Pouliquen struct stm32_dfsdm_adc {
72e2e6771cSArnaud Pouliquen 	struct stm32_dfsdm *dfsdm;
73e2e6771cSArnaud Pouliquen 	const struct stm32_dfsdm_dev_data *dev_data;
74e2e6771cSArnaud Pouliquen 	unsigned int fl_id;
75a6096762SFabrice Gasnier 	unsigned int nconv;
76a6096762SFabrice Gasnier 	unsigned long smask;
77e2e6771cSArnaud Pouliquen 
78e2e6771cSArnaud Pouliquen 	/* ADC specific */
79e2e6771cSArnaud Pouliquen 	unsigned int oversamp;
80e2e6771cSArnaud Pouliquen 	struct iio_hw_consumer *hwc;
81e2e6771cSArnaud Pouliquen 	struct completion completion;
82e2e6771cSArnaud Pouliquen 	u32 *buffer;
83e2e6771cSArnaud Pouliquen 
84eca94980SArnaud Pouliquen 	/* Audio specific */
85eca94980SArnaud Pouliquen 	unsigned int spi_freq;  /* SPI bus clock frequency */
86eca94980SArnaud Pouliquen 	unsigned int sample_freq; /* Sample frequency after filter decimation */
87eca94980SArnaud Pouliquen 	int (*cb)(const void *data, size_t size, void *cb_priv);
88eca94980SArnaud Pouliquen 	void *cb_priv;
89eca94980SArnaud Pouliquen 
90eca94980SArnaud Pouliquen 	/* DMA */
91eca94980SArnaud Pouliquen 	u8 *rx_buf;
92eca94980SArnaud Pouliquen 	unsigned int bufi; /* Buffer current position */
93eca94980SArnaud Pouliquen 	unsigned int buf_sz; /* Buffer size */
94eca94980SArnaud Pouliquen 	struct dma_chan	*dma_chan;
95eca94980SArnaud Pouliquen 	dma_addr_t dma_buf;
96e2e6771cSArnaud Pouliquen };
97e2e6771cSArnaud Pouliquen 
98e2e6771cSArnaud Pouliquen struct stm32_dfsdm_str2field {
99e2e6771cSArnaud Pouliquen 	const char	*name;
100e2e6771cSArnaud Pouliquen 	unsigned int	val;
101e2e6771cSArnaud Pouliquen };
102e2e6771cSArnaud Pouliquen 
103e2e6771cSArnaud Pouliquen /* DFSDM channel serial interface type */
104e2e6771cSArnaud Pouliquen static const struct stm32_dfsdm_str2field stm32_dfsdm_chan_type[] = {
105e2e6771cSArnaud Pouliquen 	{ "SPI_R", 0 }, /* SPI with data on rising edge */
106e2e6771cSArnaud Pouliquen 	{ "SPI_F", 1 }, /* SPI with data on falling edge */
107e2e6771cSArnaud Pouliquen 	{ "MANCH_R", 2 }, /* Manchester codec, rising edge = logic 0 */
108e2e6771cSArnaud Pouliquen 	{ "MANCH_F", 3 }, /* Manchester codec, falling edge = logic 1 */
109e2e6771cSArnaud Pouliquen 	{},
110e2e6771cSArnaud Pouliquen };
111e2e6771cSArnaud Pouliquen 
112e2e6771cSArnaud Pouliquen /* DFSDM channel clock source */
113e2e6771cSArnaud Pouliquen static const struct stm32_dfsdm_str2field stm32_dfsdm_chan_src[] = {
114e2e6771cSArnaud Pouliquen 	/* External SPI clock (CLKIN x) */
115e2e6771cSArnaud Pouliquen 	{ "CLKIN", DFSDM_CHANNEL_SPI_CLOCK_EXTERNAL },
116e2e6771cSArnaud Pouliquen 	/* Internal SPI clock (CLKOUT) */
117e2e6771cSArnaud Pouliquen 	{ "CLKOUT", DFSDM_CHANNEL_SPI_CLOCK_INTERNAL },
118e2e6771cSArnaud Pouliquen 	/* Internal SPI clock divided by 2 (falling edge) */
119e2e6771cSArnaud Pouliquen 	{ "CLKOUT_F", DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_FALLING },
120e2e6771cSArnaud Pouliquen 	/* Internal SPI clock divided by 2 (falling edge) */
121e2e6771cSArnaud Pouliquen 	{ "CLKOUT_R", DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_RISING },
122e2e6771cSArnaud Pouliquen 	{},
123e2e6771cSArnaud Pouliquen };
124e2e6771cSArnaud Pouliquen 
stm32_dfsdm_str2val(const char * str,const struct stm32_dfsdm_str2field * list)125e2e6771cSArnaud Pouliquen static int stm32_dfsdm_str2val(const char *str,
126e2e6771cSArnaud Pouliquen 			       const struct stm32_dfsdm_str2field *list)
127e2e6771cSArnaud Pouliquen {
128e2e6771cSArnaud Pouliquen 	const struct stm32_dfsdm_str2field *p = list;
129e2e6771cSArnaud Pouliquen 
130e2e6771cSArnaud Pouliquen 	for (p = list; p && p->name; p++)
131e2e6771cSArnaud Pouliquen 		if (!strcmp(p->name, str))
132e2e6771cSArnaud Pouliquen 			return p->val;
133e2e6771cSArnaud Pouliquen 
134e2e6771cSArnaud Pouliquen 	return -EINVAL;
135e2e6771cSArnaud Pouliquen }
136e2e6771cSArnaud Pouliquen 
13711646e81SFabrice Gasnier /**
13811646e81SFabrice Gasnier  * struct stm32_dfsdm_trig_info - DFSDM trigger info
13911646e81SFabrice Gasnier  * @name:		name of the trigger, corresponding to its source
14011646e81SFabrice Gasnier  * @jextsel:		trigger signal selection
14111646e81SFabrice Gasnier  */
14211646e81SFabrice Gasnier struct stm32_dfsdm_trig_info {
14311646e81SFabrice Gasnier 	const char *name;
14411646e81SFabrice Gasnier 	unsigned int jextsel;
14511646e81SFabrice Gasnier };
14611646e81SFabrice Gasnier 
14711646e81SFabrice Gasnier /* hardware injected trigger enable, edge selection */
14811646e81SFabrice Gasnier enum stm32_dfsdm_jexten {
14911646e81SFabrice Gasnier 	STM32_DFSDM_JEXTEN_DISABLED,
15011646e81SFabrice Gasnier 	STM32_DFSDM_JEXTEN_RISING_EDGE,
15111646e81SFabrice Gasnier 	STM32_DFSDM_JEXTEN_FALLING_EDGE,
15211646e81SFabrice Gasnier 	STM32_DFSDM_EXTEN_BOTH_EDGES,
15311646e81SFabrice Gasnier };
15411646e81SFabrice Gasnier 
15511646e81SFabrice Gasnier static const struct stm32_dfsdm_trig_info stm32_dfsdm_trigs[] = {
15611646e81SFabrice Gasnier 	{ TIM1_TRGO, 0 },
15711646e81SFabrice Gasnier 	{ TIM1_TRGO2, 1 },
15811646e81SFabrice Gasnier 	{ TIM8_TRGO, 2 },
15911646e81SFabrice Gasnier 	{ TIM8_TRGO2, 3 },
16011646e81SFabrice Gasnier 	{ TIM3_TRGO, 4 },
16111646e81SFabrice Gasnier 	{ TIM4_TRGO, 5 },
16211646e81SFabrice Gasnier 	{ TIM16_OC1, 6 },
16311646e81SFabrice Gasnier 	{ TIM6_TRGO, 7 },
16411646e81SFabrice Gasnier 	{ TIM7_TRGO, 8 },
16511646e81SFabrice Gasnier 	{ LPTIM1_OUT, 26 },
16611646e81SFabrice Gasnier 	{ LPTIM2_OUT, 27 },
16711646e81SFabrice Gasnier 	{ LPTIM3_OUT, 28 },
16811646e81SFabrice Gasnier 	{},
16911646e81SFabrice Gasnier };
17011646e81SFabrice Gasnier 
stm32_dfsdm_get_jextsel(struct iio_dev * indio_dev,struct iio_trigger * trig)17111646e81SFabrice Gasnier static int stm32_dfsdm_get_jextsel(struct iio_dev *indio_dev,
17211646e81SFabrice Gasnier 				   struct iio_trigger *trig)
17311646e81SFabrice Gasnier {
17411646e81SFabrice Gasnier 	int i;
17511646e81SFabrice Gasnier 
17611646e81SFabrice Gasnier 	/* lookup triggers registered by stm32 timer trigger driver */
17711646e81SFabrice Gasnier 	for (i = 0; stm32_dfsdm_trigs[i].name; i++) {
17811646e81SFabrice Gasnier 		/**
17911646e81SFabrice Gasnier 		 * Checking both stm32 timer trigger type and trig name
18011646e81SFabrice Gasnier 		 * should be safe against arbitrary trigger names.
18111646e81SFabrice Gasnier 		 */
18211646e81SFabrice Gasnier 		if ((is_stm32_timer_trigger(trig) ||
18311646e81SFabrice Gasnier 		     is_stm32_lptim_trigger(trig)) &&
18411646e81SFabrice Gasnier 		    !strcmp(stm32_dfsdm_trigs[i].name, trig->name)) {
18511646e81SFabrice Gasnier 			return stm32_dfsdm_trigs[i].jextsel;
18611646e81SFabrice Gasnier 		}
18711646e81SFabrice Gasnier 	}
18811646e81SFabrice Gasnier 
18911646e81SFabrice Gasnier 	return -EINVAL;
19011646e81SFabrice Gasnier }
19111646e81SFabrice Gasnier 
stm32_dfsdm_compute_osrs(struct stm32_dfsdm_filter * fl,unsigned int fast,unsigned int oversamp)19212c8398dSOlivier Moysan static int stm32_dfsdm_compute_osrs(struct stm32_dfsdm_filter *fl,
193e2e6771cSArnaud Pouliquen 				    unsigned int fast, unsigned int oversamp)
194e2e6771cSArnaud Pouliquen {
195e2e6771cSArnaud Pouliquen 	unsigned int i, d, fosr, iosr;
19612c8398dSOlivier Moysan 	u64 res, max;
19712c8398dSOlivier Moysan 	int bits, shift;
198e2e6771cSArnaud Pouliquen 	unsigned int m = 1;	/* multiplication factor */
199e2e6771cSArnaud Pouliquen 	unsigned int p = fl->ford;	/* filter order (ford) */
200d716204fSOlivier Moysan 	struct stm32_dfsdm_filter_osr *flo = &fl->flo[fast];
201e2e6771cSArnaud Pouliquen 
202bb142d44SMugilraj Dhavachelvan 	pr_debug("Requested oversampling: %d\n", oversamp);
203e2e6771cSArnaud Pouliquen 	/*
204e2e6771cSArnaud Pouliquen 	 * This function tries to compute filter oversampling and integrator
205e2e6771cSArnaud Pouliquen 	 * oversampling, base on oversampling ratio requested by user.
206e2e6771cSArnaud Pouliquen 	 *
207e2e6771cSArnaud Pouliquen 	 * Decimation d depends on the filter order and the oversampling ratios.
208e2e6771cSArnaud Pouliquen 	 * ford: filter order
209e2e6771cSArnaud Pouliquen 	 * fosr: filter over sampling ratio
210e2e6771cSArnaud Pouliquen 	 * iosr: integrator over sampling ratio
211e2e6771cSArnaud Pouliquen 	 */
212e2e6771cSArnaud Pouliquen 	if (fl->ford == DFSDM_FASTSINC_ORDER) {
213e2e6771cSArnaud Pouliquen 		m = 2;
214e2e6771cSArnaud Pouliquen 		p = 2;
215e2e6771cSArnaud Pouliquen 	}
216e2e6771cSArnaud Pouliquen 
217e2e6771cSArnaud Pouliquen 	/*
218e2e6771cSArnaud Pouliquen 	 * Look for filter and integrator oversampling ratios which allows
21912c8398dSOlivier Moysan 	 * to maximize data output resolution.
220e2e6771cSArnaud Pouliquen 	 */
221e2e6771cSArnaud Pouliquen 	for (fosr = 1; fosr <= DFSDM_MAX_FL_OVERSAMPLING; fosr++) {
222e2e6771cSArnaud Pouliquen 		for (iosr = 1; iosr <= DFSDM_MAX_INT_OVERSAMPLING; iosr++) {
223e2e6771cSArnaud Pouliquen 			if (fast)
224e2e6771cSArnaud Pouliquen 				d = fosr * iosr;
225e2e6771cSArnaud Pouliquen 			else if (fl->ford == DFSDM_FASTSINC_ORDER)
226e2e6771cSArnaud Pouliquen 				d = fosr * (iosr + 3) + 2;
227e2e6771cSArnaud Pouliquen 			else
228e2e6771cSArnaud Pouliquen 				d = fosr * (iosr - 1 + p) + p;
229e2e6771cSArnaud Pouliquen 
230e2e6771cSArnaud Pouliquen 			if (d > oversamp)
231e2e6771cSArnaud Pouliquen 				break;
232e2e6771cSArnaud Pouliquen 			else if (d != oversamp)
233e2e6771cSArnaud Pouliquen 				continue;
234e2e6771cSArnaud Pouliquen 			/*
235e2e6771cSArnaud Pouliquen 			 * Check resolution (limited to signed 32 bits)
236e2e6771cSArnaud Pouliquen 			 *   res <= 2^31
237e2e6771cSArnaud Pouliquen 			 * Sincx filters:
238e2e6771cSArnaud Pouliquen 			 *   res = m * fosr^p x iosr (with m=1, p=ford)
239e2e6771cSArnaud Pouliquen 			 * FastSinc filter
240e2e6771cSArnaud Pouliquen 			 *   res = m * fosr^p x iosr (with m=2, p=2)
241e2e6771cSArnaud Pouliquen 			 */
242e2e6771cSArnaud Pouliquen 			res = fosr;
243e2e6771cSArnaud Pouliquen 			for (i = p - 1; i > 0; i--) {
244e2e6771cSArnaud Pouliquen 				res = res * (u64)fosr;
24512c8398dSOlivier Moysan 				if (res > DFSDM_DATA_MAX)
246e2e6771cSArnaud Pouliquen 					break;
247e2e6771cSArnaud Pouliquen 			}
24812c8398dSOlivier Moysan 			if (res > DFSDM_DATA_MAX)
249e2e6771cSArnaud Pouliquen 				continue;
25012c8398dSOlivier Moysan 
251e2e6771cSArnaud Pouliquen 			res = res * (u64)m * (u64)iosr;
25212c8398dSOlivier Moysan 			if (res > DFSDM_DATA_MAX)
253e2e6771cSArnaud Pouliquen 				continue;
254e2e6771cSArnaud Pouliquen 
25512c8398dSOlivier Moysan 			if (res >= flo->res) {
25612c8398dSOlivier Moysan 				flo->res = res;
25712c8398dSOlivier Moysan 				flo->fosr = fosr;
25812c8398dSOlivier Moysan 				flo->iosr = iosr;
259e2e6771cSArnaud Pouliquen 
26012c8398dSOlivier Moysan 				bits = fls(flo->res);
26112c8398dSOlivier Moysan 				/* 8 LBSs in data register contain chan info */
26212c8398dSOlivier Moysan 				max = flo->res << 8;
26312c8398dSOlivier Moysan 
26412c8398dSOlivier Moysan 				/* if resolution is not a power of two */
26512c8398dSOlivier Moysan 				if (flo->res > BIT(bits - 1))
26612c8398dSOlivier Moysan 					bits++;
26712c8398dSOlivier Moysan 				else
26812c8398dSOlivier Moysan 					max--;
26912c8398dSOlivier Moysan 
27012c8398dSOlivier Moysan 				shift = DFSDM_DATA_RES - bits;
27112c8398dSOlivier Moysan 				/*
27212c8398dSOlivier Moysan 				 * Compute right/left shift
27312c8398dSOlivier Moysan 				 * Right shift is performed by hardware
27412c8398dSOlivier Moysan 				 * when transferring samples to data register.
27512c8398dSOlivier Moysan 				 * Left shift is done by software on buffer
27612c8398dSOlivier Moysan 				 */
27712c8398dSOlivier Moysan 				if (shift > 0) {
27812c8398dSOlivier Moysan 					/* Resolution is lower than 24 bits */
27912c8398dSOlivier Moysan 					flo->rshift = 0;
28012c8398dSOlivier Moysan 					flo->lshift = shift;
28112c8398dSOlivier Moysan 				} else {
28212c8398dSOlivier Moysan 					/*
28312c8398dSOlivier Moysan 					 * If resolution is 24 bits or more,
28412c8398dSOlivier Moysan 					 * max positive value may be ambiguous
28512c8398dSOlivier Moysan 					 * (equal to max negative value as sign
28612c8398dSOlivier Moysan 					 * bit is dropped).
28712c8398dSOlivier Moysan 					 * Reduce resolution to 23 bits (rshift)
28812c8398dSOlivier Moysan 					 * to keep the sign on bit 23 and treat
28912c8398dSOlivier Moysan 					 * saturation before rescaling on 24
29012c8398dSOlivier Moysan 					 * bits (lshift).
29112c8398dSOlivier Moysan 					 */
29212c8398dSOlivier Moysan 					flo->rshift = 1 - shift;
29312c8398dSOlivier Moysan 					flo->lshift = 1;
29412c8398dSOlivier Moysan 					max >>= flo->rshift;
295e2e6771cSArnaud Pouliquen 				}
29612c8398dSOlivier Moysan 				flo->max = (s32)max;
29741bceb12SOlivier Moysan 				flo->bits = bits;
298e2e6771cSArnaud Pouliquen 
299bb142d44SMugilraj Dhavachelvan 				pr_debug("fast %d, fosr %d, iosr %d, res 0x%llx/%d bits, rshift %d, lshift %d\n",
300bb142d44SMugilraj Dhavachelvan 					 fast, flo->fosr, flo->iosr,
30112c8398dSOlivier Moysan 					 flo->res, bits, flo->rshift,
30212c8398dSOlivier Moysan 					 flo->lshift);
30312c8398dSOlivier Moysan 			}
304e2e6771cSArnaud Pouliquen 		}
305e2e6771cSArnaud Pouliquen 	}
306e2e6771cSArnaud Pouliquen 
30712c8398dSOlivier Moysan 	if (!flo->res)
308e2e6771cSArnaud Pouliquen 		return -EINVAL;
309e2e6771cSArnaud Pouliquen 
310e2e6771cSArnaud Pouliquen 	return 0;
311e2e6771cSArnaud Pouliquen }
312e2e6771cSArnaud Pouliquen 
stm32_dfsdm_compute_all_osrs(struct iio_dev * indio_dev,unsigned int oversamp)313d716204fSOlivier Moysan static int stm32_dfsdm_compute_all_osrs(struct iio_dev *indio_dev,
314d716204fSOlivier Moysan 					unsigned int oversamp)
315d716204fSOlivier Moysan {
316d716204fSOlivier Moysan 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
317d716204fSOlivier Moysan 	struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id];
318d716204fSOlivier Moysan 	int ret0, ret1;
319d716204fSOlivier Moysan 
320d716204fSOlivier Moysan 	memset(&fl->flo[0], 0, sizeof(fl->flo[0]));
321d716204fSOlivier Moysan 	memset(&fl->flo[1], 0, sizeof(fl->flo[1]));
322d716204fSOlivier Moysan 
323d716204fSOlivier Moysan 	ret0 = stm32_dfsdm_compute_osrs(fl, 0, oversamp);
324d716204fSOlivier Moysan 	ret1 = stm32_dfsdm_compute_osrs(fl, 1, oversamp);
325d716204fSOlivier Moysan 	if (ret0 < 0 && ret1 < 0) {
326d716204fSOlivier Moysan 		dev_err(&indio_dev->dev,
327d716204fSOlivier Moysan 			"Filter parameters not found: errors %d/%d\n",
328d716204fSOlivier Moysan 			ret0, ret1);
329d716204fSOlivier Moysan 		return -EINVAL;
330d716204fSOlivier Moysan 	}
331d716204fSOlivier Moysan 
332d716204fSOlivier Moysan 	return 0;
333d716204fSOlivier Moysan }
334d716204fSOlivier Moysan 
stm32_dfsdm_start_channel(struct iio_dev * indio_dev)33507b6c9dcSAlexandru Ardelean static int stm32_dfsdm_start_channel(struct iio_dev *indio_dev)
336e2e6771cSArnaud Pouliquen {
33707b6c9dcSAlexandru Ardelean 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
338a6096762SFabrice Gasnier 	struct regmap *regmap = adc->dfsdm->regmap;
339a6096762SFabrice Gasnier 	const struct iio_chan_spec *chan;
340a6096762SFabrice Gasnier 	unsigned int bit;
341a6096762SFabrice Gasnier 	int ret;
342a6096762SFabrice Gasnier 
343a6096762SFabrice Gasnier 	for_each_set_bit(bit, &adc->smask, sizeof(adc->smask) * BITS_PER_BYTE) {
344a6096762SFabrice Gasnier 		chan = indio_dev->channels + bit;
345a6096762SFabrice Gasnier 		ret = regmap_update_bits(regmap, DFSDM_CHCFGR1(chan->channel),
346e2e6771cSArnaud Pouliquen 					 DFSDM_CHCFGR1_CHEN_MASK,
347e2e6771cSArnaud Pouliquen 					 DFSDM_CHCFGR1_CHEN(1));
348a6096762SFabrice Gasnier 		if (ret < 0)
349a6096762SFabrice Gasnier 			return ret;
350e2e6771cSArnaud Pouliquen 	}
351e2e6771cSArnaud Pouliquen 
352a6096762SFabrice Gasnier 	return 0;
353a6096762SFabrice Gasnier }
354a6096762SFabrice Gasnier 
stm32_dfsdm_stop_channel(struct iio_dev * indio_dev)35507b6c9dcSAlexandru Ardelean static void stm32_dfsdm_stop_channel(struct iio_dev *indio_dev)
356e2e6771cSArnaud Pouliquen {
35707b6c9dcSAlexandru Ardelean 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
358a6096762SFabrice Gasnier 	struct regmap *regmap = adc->dfsdm->regmap;
359a6096762SFabrice Gasnier 	const struct iio_chan_spec *chan;
360a6096762SFabrice Gasnier 	unsigned int bit;
361a6096762SFabrice Gasnier 
362a6096762SFabrice Gasnier 	for_each_set_bit(bit, &adc->smask, sizeof(adc->smask) * BITS_PER_BYTE) {
363a6096762SFabrice Gasnier 		chan = indio_dev->channels + bit;
364a6096762SFabrice Gasnier 		regmap_update_bits(regmap, DFSDM_CHCFGR1(chan->channel),
365a6096762SFabrice Gasnier 				   DFSDM_CHCFGR1_CHEN_MASK,
366a6096762SFabrice Gasnier 				   DFSDM_CHCFGR1_CHEN(0));
367a6096762SFabrice Gasnier 	}
368e2e6771cSArnaud Pouliquen }
369e2e6771cSArnaud Pouliquen 
stm32_dfsdm_chan_configure(struct stm32_dfsdm * dfsdm,struct stm32_dfsdm_channel * ch)370e2e6771cSArnaud Pouliquen static int stm32_dfsdm_chan_configure(struct stm32_dfsdm *dfsdm,
371e2e6771cSArnaud Pouliquen 				      struct stm32_dfsdm_channel *ch)
372e2e6771cSArnaud Pouliquen {
373e2e6771cSArnaud Pouliquen 	unsigned int id = ch->id;
374e2e6771cSArnaud Pouliquen 	struct regmap *regmap = dfsdm->regmap;
375e2e6771cSArnaud Pouliquen 	int ret;
376e2e6771cSArnaud Pouliquen 
377e2e6771cSArnaud Pouliquen 	ret = regmap_update_bits(regmap, DFSDM_CHCFGR1(id),
378e2e6771cSArnaud Pouliquen 				 DFSDM_CHCFGR1_SITP_MASK,
379e2e6771cSArnaud Pouliquen 				 DFSDM_CHCFGR1_SITP(ch->type));
380e2e6771cSArnaud Pouliquen 	if (ret < 0)
381e2e6771cSArnaud Pouliquen 		return ret;
382e2e6771cSArnaud Pouliquen 	ret = regmap_update_bits(regmap, DFSDM_CHCFGR1(id),
383e2e6771cSArnaud Pouliquen 				 DFSDM_CHCFGR1_SPICKSEL_MASK,
384e2e6771cSArnaud Pouliquen 				 DFSDM_CHCFGR1_SPICKSEL(ch->src));
385e2e6771cSArnaud Pouliquen 	if (ret < 0)
386e2e6771cSArnaud Pouliquen 		return ret;
387e2e6771cSArnaud Pouliquen 	return regmap_update_bits(regmap, DFSDM_CHCFGR1(id),
388e2e6771cSArnaud Pouliquen 				  DFSDM_CHCFGR1_CHINSEL_MASK,
389e2e6771cSArnaud Pouliquen 				  DFSDM_CHCFGR1_CHINSEL(ch->alt_si));
390e2e6771cSArnaud Pouliquen }
391e2e6771cSArnaud Pouliquen 
stm32_dfsdm_start_filter(struct stm32_dfsdm_adc * adc,unsigned int fl_id,struct iio_trigger * trig)392a6096762SFabrice Gasnier static int stm32_dfsdm_start_filter(struct stm32_dfsdm_adc *adc,
39311646e81SFabrice Gasnier 				    unsigned int fl_id,
39411646e81SFabrice Gasnier 				    struct iio_trigger *trig)
395e2e6771cSArnaud Pouliquen {
396a6096762SFabrice Gasnier 	struct stm32_dfsdm *dfsdm = adc->dfsdm;
397e2e6771cSArnaud Pouliquen 	int ret;
398e2e6771cSArnaud Pouliquen 
399e2e6771cSArnaud Pouliquen 	/* Enable filter */
400e2e6771cSArnaud Pouliquen 	ret = regmap_update_bits(dfsdm->regmap, DFSDM_CR1(fl_id),
401e2e6771cSArnaud Pouliquen 				 DFSDM_CR1_DFEN_MASK, DFSDM_CR1_DFEN(1));
402e2e6771cSArnaud Pouliquen 	if (ret < 0)
403e2e6771cSArnaud Pouliquen 		return ret;
404e2e6771cSArnaud Pouliquen 
405a6096762SFabrice Gasnier 	/* Nothing more to do for injected (scan mode/triggered) conversions */
40611646e81SFabrice Gasnier 	if (adc->nconv > 1 || trig)
407a6096762SFabrice Gasnier 		return 0;
408a6096762SFabrice Gasnier 
409a6096762SFabrice Gasnier 	/* Software start (single or continuous) regular conversion */
410e2e6771cSArnaud Pouliquen 	return regmap_update_bits(dfsdm->regmap, DFSDM_CR1(fl_id),
411e2e6771cSArnaud Pouliquen 				  DFSDM_CR1_RSWSTART_MASK,
412e2e6771cSArnaud Pouliquen 				  DFSDM_CR1_RSWSTART(1));
413e2e6771cSArnaud Pouliquen }
414e2e6771cSArnaud Pouliquen 
stm32_dfsdm_stop_filter(struct stm32_dfsdm * dfsdm,unsigned int fl_id)415c620da3aSFabrice Gasnier static void stm32_dfsdm_stop_filter(struct stm32_dfsdm *dfsdm,
416c620da3aSFabrice Gasnier 				    unsigned int fl_id)
417e2e6771cSArnaud Pouliquen {
418e2e6771cSArnaud Pouliquen 	/* Disable conversion */
419e2e6771cSArnaud Pouliquen 	regmap_update_bits(dfsdm->regmap, DFSDM_CR1(fl_id),
420e2e6771cSArnaud Pouliquen 			   DFSDM_CR1_DFEN_MASK, DFSDM_CR1_DFEN(0));
421e2e6771cSArnaud Pouliquen }
422e2e6771cSArnaud Pouliquen 
stm32_dfsdm_filter_set_trig(struct iio_dev * indio_dev,unsigned int fl_id,struct iio_trigger * trig)42307b6c9dcSAlexandru Ardelean static int stm32_dfsdm_filter_set_trig(struct iio_dev *indio_dev,
42411646e81SFabrice Gasnier 				       unsigned int fl_id,
42511646e81SFabrice Gasnier 				       struct iio_trigger *trig)
42611646e81SFabrice Gasnier {
42707b6c9dcSAlexandru Ardelean 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
42811646e81SFabrice Gasnier 	struct regmap *regmap = adc->dfsdm->regmap;
42911646e81SFabrice Gasnier 	u32 jextsel = 0, jexten = STM32_DFSDM_JEXTEN_DISABLED;
43011646e81SFabrice Gasnier 	int ret;
43111646e81SFabrice Gasnier 
43211646e81SFabrice Gasnier 	if (trig) {
43311646e81SFabrice Gasnier 		ret = stm32_dfsdm_get_jextsel(indio_dev, trig);
43411646e81SFabrice Gasnier 		if (ret < 0)
43511646e81SFabrice Gasnier 			return ret;
43611646e81SFabrice Gasnier 
43711646e81SFabrice Gasnier 		/* set trigger source and polarity (default to rising edge) */
43811646e81SFabrice Gasnier 		jextsel = ret;
43911646e81SFabrice Gasnier 		jexten = STM32_DFSDM_JEXTEN_RISING_EDGE;
44011646e81SFabrice Gasnier 	}
44111646e81SFabrice Gasnier 
44211646e81SFabrice Gasnier 	ret = regmap_update_bits(regmap, DFSDM_CR1(fl_id),
44311646e81SFabrice Gasnier 				 DFSDM_CR1_JEXTSEL_MASK | DFSDM_CR1_JEXTEN_MASK,
44411646e81SFabrice Gasnier 				 DFSDM_CR1_JEXTSEL(jextsel) |
44511646e81SFabrice Gasnier 				 DFSDM_CR1_JEXTEN(jexten));
44611646e81SFabrice Gasnier 	if (ret < 0)
44711646e81SFabrice Gasnier 		return ret;
44811646e81SFabrice Gasnier 
44911646e81SFabrice Gasnier 	return 0;
45011646e81SFabrice Gasnier }
45111646e81SFabrice Gasnier 
stm32_dfsdm_channels_configure(struct iio_dev * indio_dev,unsigned int fl_id,struct iio_trigger * trig)45207b6c9dcSAlexandru Ardelean static int stm32_dfsdm_channels_configure(struct iio_dev *indio_dev,
45312c8398dSOlivier Moysan 					  unsigned int fl_id,
45412c8398dSOlivier Moysan 					  struct iio_trigger *trig)
45512c8398dSOlivier Moysan {
45607b6c9dcSAlexandru Ardelean 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
45712c8398dSOlivier Moysan 	struct regmap *regmap = adc->dfsdm->regmap;
45812c8398dSOlivier Moysan 	struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[fl_id];
459d716204fSOlivier Moysan 	struct stm32_dfsdm_filter_osr *flo = &fl->flo[0];
46012c8398dSOlivier Moysan 	const struct iio_chan_spec *chan;
46112c8398dSOlivier Moysan 	unsigned int bit;
46212c8398dSOlivier Moysan 	int ret;
46312c8398dSOlivier Moysan 
464d716204fSOlivier Moysan 	fl->fast = 0;
465d716204fSOlivier Moysan 
466d716204fSOlivier Moysan 	/*
467d716204fSOlivier Moysan 	 * In continuous mode, use fast mode configuration,
468d716204fSOlivier Moysan 	 * if it provides a better resolution.
469d716204fSOlivier Moysan 	 */
470f8ac59f5SMiquel Raynal 	if (adc->nconv == 1 && !trig && iio_buffer_enabled(indio_dev)) {
471d716204fSOlivier Moysan 		if (fl->flo[1].res >= fl->flo[0].res) {
472d716204fSOlivier Moysan 			fl->fast = 1;
473d716204fSOlivier Moysan 			flo = &fl->flo[1];
474d716204fSOlivier Moysan 		}
475d716204fSOlivier Moysan 	}
476d716204fSOlivier Moysan 
47712c8398dSOlivier Moysan 	if (!flo->res)
47812c8398dSOlivier Moysan 		return -EINVAL;
47912c8398dSOlivier Moysan 
48041bceb12SOlivier Moysan 	dev_dbg(&indio_dev->dev, "Samples actual resolution: %d bits",
48141bceb12SOlivier Moysan 		min(flo->bits, (u32)DFSDM_DATA_RES - 1));
48241bceb12SOlivier Moysan 
48312c8398dSOlivier Moysan 	for_each_set_bit(bit, &adc->smask,
48412c8398dSOlivier Moysan 			 sizeof(adc->smask) * BITS_PER_BYTE) {
48512c8398dSOlivier Moysan 		chan = indio_dev->channels + bit;
48612c8398dSOlivier Moysan 
48712c8398dSOlivier Moysan 		ret = regmap_update_bits(regmap,
48812c8398dSOlivier Moysan 					 DFSDM_CHCFGR2(chan->channel),
48912c8398dSOlivier Moysan 					 DFSDM_CHCFGR2_DTRBS_MASK,
49012c8398dSOlivier Moysan 					 DFSDM_CHCFGR2_DTRBS(flo->rshift));
49112c8398dSOlivier Moysan 		if (ret)
49212c8398dSOlivier Moysan 			return ret;
49312c8398dSOlivier Moysan 	}
49412c8398dSOlivier Moysan 
49512c8398dSOlivier Moysan 	return 0;
49612c8398dSOlivier Moysan }
49712c8398dSOlivier Moysan 
stm32_dfsdm_filter_configure(struct iio_dev * indio_dev,unsigned int fl_id,struct iio_trigger * trig)49807b6c9dcSAlexandru Ardelean static int stm32_dfsdm_filter_configure(struct iio_dev *indio_dev,
49911646e81SFabrice Gasnier 					unsigned int fl_id,
50011646e81SFabrice Gasnier 					struct iio_trigger *trig)
501e2e6771cSArnaud Pouliquen {
50207b6c9dcSAlexandru Ardelean 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
5036f2c4a59SFabrice Gasnier 	struct regmap *regmap = adc->dfsdm->regmap;
5046f2c4a59SFabrice Gasnier 	struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[fl_id];
505d716204fSOlivier Moysan 	struct stm32_dfsdm_filter_osr *flo = &fl->flo[fl->fast];
5066f2c4a59SFabrice Gasnier 	u32 cr1;
507a6096762SFabrice Gasnier 	const struct iio_chan_spec *chan;
508a6096762SFabrice Gasnier 	unsigned int bit, jchg = 0;
509e2e6771cSArnaud Pouliquen 	int ret;
510e2e6771cSArnaud Pouliquen 
511e2e6771cSArnaud Pouliquen 	/* Average integrator oversampling */
512e2e6771cSArnaud Pouliquen 	ret = regmap_update_bits(regmap, DFSDM_FCR(fl_id), DFSDM_FCR_IOSR_MASK,
51312c8398dSOlivier Moysan 				 DFSDM_FCR_IOSR(flo->iosr - 1));
514e2e6771cSArnaud Pouliquen 	if (ret)
515e2e6771cSArnaud Pouliquen 		return ret;
516e2e6771cSArnaud Pouliquen 
517e2e6771cSArnaud Pouliquen 	/* Filter order and Oversampling */
518e2e6771cSArnaud Pouliquen 	ret = regmap_update_bits(regmap, DFSDM_FCR(fl_id), DFSDM_FCR_FOSR_MASK,
51912c8398dSOlivier Moysan 				 DFSDM_FCR_FOSR(flo->fosr - 1));
520e2e6771cSArnaud Pouliquen 	if (ret)
521e2e6771cSArnaud Pouliquen 		return ret;
522e2e6771cSArnaud Pouliquen 
523e2e6771cSArnaud Pouliquen 	ret = regmap_update_bits(regmap, DFSDM_FCR(fl_id), DFSDM_FCR_FORD_MASK,
524e2e6771cSArnaud Pouliquen 				 DFSDM_FCR_FORD(fl->ford));
525e2e6771cSArnaud Pouliquen 	if (ret)
526e2e6771cSArnaud Pouliquen 		return ret;
527e2e6771cSArnaud Pouliquen 
52807b6c9dcSAlexandru Ardelean 	ret = stm32_dfsdm_filter_set_trig(indio_dev, fl_id, trig);
52911646e81SFabrice Gasnier 	if (ret)
53011646e81SFabrice Gasnier 		return ret;
53111646e81SFabrice Gasnier 
532d716204fSOlivier Moysan 	ret = regmap_update_bits(regmap, DFSDM_CR1(fl_id),
533d716204fSOlivier Moysan 				 DFSDM_CR1_FAST_MASK,
534d716204fSOlivier Moysan 				 DFSDM_CR1_FAST(fl->fast));
535d716204fSOlivier Moysan 	if (ret)
536d716204fSOlivier Moysan 		return ret;
537d716204fSOlivier Moysan 
538a6096762SFabrice Gasnier 	/*
539a6096762SFabrice Gasnier 	 * DFSDM modes configuration W.R.T audio/iio type modes
540a6096762SFabrice Gasnier 	 * ----------------------------------------------------------------
541a6096762SFabrice Gasnier 	 * Modes         | regular |  regular     | injected | injected   |
542a6096762SFabrice Gasnier 	 *               |         |  continuous  |          | + scan     |
543a6096762SFabrice Gasnier 	 * --------------|---------|--------------|----------|------------|
544a6096762SFabrice Gasnier 	 * single conv   |    x    |              |          |            |
545a6096762SFabrice Gasnier 	 * (1 chan)      |         |              |          |            |
546a6096762SFabrice Gasnier 	 * --------------|---------|--------------|----------|------------|
547a6096762SFabrice Gasnier 	 * 1 Audio chan	 |         | sample freq  |          |            |
548a6096762SFabrice Gasnier 	 *               |         | or sync_mode |          |            |
549a6096762SFabrice Gasnier 	 * --------------|---------|--------------|----------|------------|
550a6096762SFabrice Gasnier 	 * 1 IIO chan	 |         | sample freq  | trigger  |            |
551a6096762SFabrice Gasnier 	 *               |         | or sync_mode |          |            |
552a6096762SFabrice Gasnier 	 * --------------|---------|--------------|----------|------------|
553a6096762SFabrice Gasnier 	 * 2+ IIO chans  |         |              |          | trigger or |
554a6096762SFabrice Gasnier 	 *               |         |              |          | sync_mode  |
555a6096762SFabrice Gasnier 	 * ----------------------------------------------------------------
556a6096762SFabrice Gasnier 	 */
55711646e81SFabrice Gasnier 	if (adc->nconv == 1 && !trig) {
558a6096762SFabrice Gasnier 		bit = __ffs(adc->smask);
559a6096762SFabrice Gasnier 		chan = indio_dev->channels + bit;
560e2e6771cSArnaud Pouliquen 
561a6096762SFabrice Gasnier 		/* Use regular conversion for single channel without trigger */
562a6096762SFabrice Gasnier 		cr1 = DFSDM_CR1_RCH(chan->channel);
563a6096762SFabrice Gasnier 
564a6096762SFabrice Gasnier 		/* Continuous conversions triggered by SPI clk in buffer mode */
565f8ac59f5SMiquel Raynal 		if (iio_buffer_enabled(indio_dev))
5666f2c4a59SFabrice Gasnier 			cr1 |= DFSDM_CR1_RCONT(1);
5676f2c4a59SFabrice Gasnier 
5686f2c4a59SFabrice Gasnier 		cr1 |= DFSDM_CR1_RSYNC(fl->sync_mode);
569a6096762SFabrice Gasnier 	} else {
570a6096762SFabrice Gasnier 		/* Use injected conversion for multiple channels */
571a6096762SFabrice Gasnier 		for_each_set_bit(bit, &adc->smask,
572a6096762SFabrice Gasnier 				 sizeof(adc->smask) * BITS_PER_BYTE) {
573a6096762SFabrice Gasnier 			chan = indio_dev->channels + bit;
574a6096762SFabrice Gasnier 			jchg |= BIT(chan->channel);
575a6096762SFabrice Gasnier 		}
576a6096762SFabrice Gasnier 		ret = regmap_write(regmap, DFSDM_JCHGR(fl_id), jchg);
577a6096762SFabrice Gasnier 		if (ret < 0)
578a6096762SFabrice Gasnier 			return ret;
579a6096762SFabrice Gasnier 
580a6096762SFabrice Gasnier 		/* Use scan mode for multiple channels */
58111646e81SFabrice Gasnier 		cr1 = DFSDM_CR1_JSCAN((adc->nconv > 1) ? 1 : 0);
582a6096762SFabrice Gasnier 
583a6096762SFabrice Gasnier 		/*
58411646e81SFabrice Gasnier 		 * Continuous conversions not supported in injected mode,
58511646e81SFabrice Gasnier 		 * either use:
58611646e81SFabrice Gasnier 		 * - conversions in sync with filter 0
58711646e81SFabrice Gasnier 		 * - triggered conversions
588a6096762SFabrice Gasnier 		 */
58911646e81SFabrice Gasnier 		if (!fl->sync_mode && !trig)
590a6096762SFabrice Gasnier 			return -EINVAL;
591a6096762SFabrice Gasnier 		cr1 |= DFSDM_CR1_JSYNC(fl->sync_mode);
592a6096762SFabrice Gasnier 	}
5936f2c4a59SFabrice Gasnier 
5946f2c4a59SFabrice Gasnier 	return regmap_update_bits(regmap, DFSDM_CR1(fl_id), DFSDM_CR1_CFG_MASK,
5956f2c4a59SFabrice Gasnier 				  cr1);
596e2e6771cSArnaud Pouliquen }
597e2e6771cSArnaud Pouliquen 
stm32_dfsdm_channel_parse_of(struct stm32_dfsdm * dfsdm,struct iio_dev * indio_dev,struct iio_chan_spec * ch)5989ae148f8Skbuild test robot static int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm,
599e2e6771cSArnaud Pouliquen 					struct iio_dev *indio_dev,
600e2e6771cSArnaud Pouliquen 					struct iio_chan_spec *ch)
601e2e6771cSArnaud Pouliquen {
602e2e6771cSArnaud Pouliquen 	struct stm32_dfsdm_channel *df_ch;
603e2e6771cSArnaud Pouliquen 	const char *of_str;
604e2e6771cSArnaud Pouliquen 	int chan_idx = ch->scan_index;
605e2e6771cSArnaud Pouliquen 	int ret, val;
606e2e6771cSArnaud Pouliquen 
607e2e6771cSArnaud Pouliquen 	ret = of_property_read_u32_index(indio_dev->dev.of_node,
608e2e6771cSArnaud Pouliquen 					 "st,adc-channels", chan_idx,
609e2e6771cSArnaud Pouliquen 					 &ch->channel);
610e2e6771cSArnaud Pouliquen 	if (ret < 0) {
611e2e6771cSArnaud Pouliquen 		dev_err(&indio_dev->dev,
612e2e6771cSArnaud Pouliquen 			" Error parsing 'st,adc-channels' for idx %d\n",
613e2e6771cSArnaud Pouliquen 			chan_idx);
614e2e6771cSArnaud Pouliquen 		return ret;
615e2e6771cSArnaud Pouliquen 	}
616e2e6771cSArnaud Pouliquen 	if (ch->channel >= dfsdm->num_chs) {
617e2e6771cSArnaud Pouliquen 		dev_err(&indio_dev->dev,
618e2e6771cSArnaud Pouliquen 			" Error bad channel number %d (max = %d)\n",
619e2e6771cSArnaud Pouliquen 			ch->channel, dfsdm->num_chs);
620e2e6771cSArnaud Pouliquen 		return -EINVAL;
621e2e6771cSArnaud Pouliquen 	}
622e2e6771cSArnaud Pouliquen 
623e2e6771cSArnaud Pouliquen 	ret = of_property_read_string_index(indio_dev->dev.of_node,
624e2e6771cSArnaud Pouliquen 					    "st,adc-channel-names", chan_idx,
625e2e6771cSArnaud Pouliquen 					    &ch->datasheet_name);
626e2e6771cSArnaud Pouliquen 	if (ret < 0) {
627e2e6771cSArnaud Pouliquen 		dev_err(&indio_dev->dev,
628e2e6771cSArnaud Pouliquen 			" Error parsing 'st,adc-channel-names' for idx %d\n",
629e2e6771cSArnaud Pouliquen 			chan_idx);
630e2e6771cSArnaud Pouliquen 		return ret;
631e2e6771cSArnaud Pouliquen 	}
632e2e6771cSArnaud Pouliquen 
633e2e6771cSArnaud Pouliquen 	df_ch =  &dfsdm->ch_list[ch->channel];
634e2e6771cSArnaud Pouliquen 	df_ch->id = ch->channel;
635e2e6771cSArnaud Pouliquen 
636e2e6771cSArnaud Pouliquen 	ret = of_property_read_string_index(indio_dev->dev.of_node,
637e2e6771cSArnaud Pouliquen 					    "st,adc-channel-types", chan_idx,
638e2e6771cSArnaud Pouliquen 					    &of_str);
639e2e6771cSArnaud Pouliquen 	if (!ret) {
640e2e6771cSArnaud Pouliquen 		val = stm32_dfsdm_str2val(of_str, stm32_dfsdm_chan_type);
641e2e6771cSArnaud Pouliquen 		if (val < 0)
642e2e6771cSArnaud Pouliquen 			return val;
643e2e6771cSArnaud Pouliquen 	} else {
644e2e6771cSArnaud Pouliquen 		val = 0;
645e2e6771cSArnaud Pouliquen 	}
646e2e6771cSArnaud Pouliquen 	df_ch->type = val;
647e2e6771cSArnaud Pouliquen 
648e2e6771cSArnaud Pouliquen 	ret = of_property_read_string_index(indio_dev->dev.of_node,
649e2e6771cSArnaud Pouliquen 					    "st,adc-channel-clk-src", chan_idx,
650e2e6771cSArnaud Pouliquen 					    &of_str);
651e2e6771cSArnaud Pouliquen 	if (!ret) {
652e2e6771cSArnaud Pouliquen 		val = stm32_dfsdm_str2val(of_str, stm32_dfsdm_chan_src);
653e2e6771cSArnaud Pouliquen 		if (val < 0)
654e2e6771cSArnaud Pouliquen 			return val;
655e2e6771cSArnaud Pouliquen 	} else {
656e2e6771cSArnaud Pouliquen 		val = 0;
657e2e6771cSArnaud Pouliquen 	}
658e2e6771cSArnaud Pouliquen 	df_ch->src = val;
659e2e6771cSArnaud Pouliquen 
660e2e6771cSArnaud Pouliquen 	ret = of_property_read_u32_index(indio_dev->dev.of_node,
661e2e6771cSArnaud Pouliquen 					 "st,adc-alt-channel", chan_idx,
662e2e6771cSArnaud Pouliquen 					 &df_ch->alt_si);
663e2e6771cSArnaud Pouliquen 	if (ret < 0)
664e2e6771cSArnaud Pouliquen 		df_ch->alt_si = 0;
665e2e6771cSArnaud Pouliquen 
666e2e6771cSArnaud Pouliquen 	return 0;
667e2e6771cSArnaud Pouliquen }
668e2e6771cSArnaud Pouliquen 
dfsdm_adc_audio_get_spiclk(struct iio_dev * indio_dev,uintptr_t priv,const struct iio_chan_spec * chan,char * buf)669eca94980SArnaud Pouliquen static ssize_t dfsdm_adc_audio_get_spiclk(struct iio_dev *indio_dev,
670eca94980SArnaud Pouliquen 					  uintptr_t priv,
671eca94980SArnaud Pouliquen 					  const struct iio_chan_spec *chan,
672eca94980SArnaud Pouliquen 					  char *buf)
673eca94980SArnaud Pouliquen {
674eca94980SArnaud Pouliquen 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
675eca94980SArnaud Pouliquen 
676eca94980SArnaud Pouliquen 	return snprintf(buf, PAGE_SIZE, "%d\n", adc->spi_freq);
677eca94980SArnaud Pouliquen }
678eca94980SArnaud Pouliquen 
dfsdm_adc_set_samp_freq(struct iio_dev * indio_dev,unsigned int sample_freq,unsigned int spi_freq)6799f57110dSFabrice Gasnier static int dfsdm_adc_set_samp_freq(struct iio_dev *indio_dev,
6809f57110dSFabrice Gasnier 				   unsigned int sample_freq,
6819f57110dSFabrice Gasnier 				   unsigned int spi_freq)
6829f57110dSFabrice Gasnier {
6839f57110dSFabrice Gasnier 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
6849f57110dSFabrice Gasnier 	unsigned int oversamp;
6859f57110dSFabrice Gasnier 	int ret;
6869f57110dSFabrice Gasnier 
6879f57110dSFabrice Gasnier 	oversamp = DIV_ROUND_CLOSEST(spi_freq, sample_freq);
6889f57110dSFabrice Gasnier 	if (spi_freq % sample_freq)
6899f57110dSFabrice Gasnier 		dev_dbg(&indio_dev->dev,
6909f57110dSFabrice Gasnier 			"Rate not accurate. requested (%u), actual (%u)\n",
6919f57110dSFabrice Gasnier 			sample_freq, spi_freq / oversamp);
6929f57110dSFabrice Gasnier 
693d716204fSOlivier Moysan 	ret = stm32_dfsdm_compute_all_osrs(indio_dev, oversamp);
694d716204fSOlivier Moysan 	if (ret < 0)
6959f57110dSFabrice Gasnier 		return ret;
696d716204fSOlivier Moysan 
6979f57110dSFabrice Gasnier 	adc->sample_freq = spi_freq / oversamp;
6989f57110dSFabrice Gasnier 	adc->oversamp = oversamp;
6999f57110dSFabrice Gasnier 
7009f57110dSFabrice Gasnier 	return 0;
7019f57110dSFabrice Gasnier }
7029f57110dSFabrice Gasnier 
dfsdm_adc_audio_set_spiclk(struct iio_dev * indio_dev,uintptr_t priv,const struct iio_chan_spec * chan,const char * buf,size_t len)703eca94980SArnaud Pouliquen static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev,
704eca94980SArnaud Pouliquen 					  uintptr_t priv,
705eca94980SArnaud Pouliquen 					  const struct iio_chan_spec *chan,
706eca94980SArnaud Pouliquen 					  const char *buf, size_t len)
707eca94980SArnaud Pouliquen {
708eca94980SArnaud Pouliquen 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
7090645af1bSFabrice Gasnier 	struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[chan->channel];
710eca94980SArnaud Pouliquen 	unsigned int sample_freq = adc->sample_freq;
711eca94980SArnaud Pouliquen 	unsigned int spi_freq;
712eca94980SArnaud Pouliquen 	int ret;
713eca94980SArnaud Pouliquen 
714eca94980SArnaud Pouliquen 	dev_err(&indio_dev->dev, "enter %s\n", __func__);
715eca94980SArnaud Pouliquen 	/* If DFSDM is master on SPI, SPI freq can not be updated */
716eca94980SArnaud Pouliquen 	if (ch->src != DFSDM_CHANNEL_SPI_CLOCK_EXTERNAL)
717eca94980SArnaud Pouliquen 		return -EPERM;
718eca94980SArnaud Pouliquen 
719eca94980SArnaud Pouliquen 	ret = kstrtoint(buf, 0, &spi_freq);
720eca94980SArnaud Pouliquen 	if (ret)
721eca94980SArnaud Pouliquen 		return ret;
722eca94980SArnaud Pouliquen 
723eca94980SArnaud Pouliquen 	if (!spi_freq)
724eca94980SArnaud Pouliquen 		return -EINVAL;
725eca94980SArnaud Pouliquen 
726eca94980SArnaud Pouliquen 	if (sample_freq) {
7279f57110dSFabrice Gasnier 		ret = dfsdm_adc_set_samp_freq(indio_dev, sample_freq, spi_freq);
7289f57110dSFabrice Gasnier 		if (ret < 0)
729eca94980SArnaud Pouliquen 			return ret;
730eca94980SArnaud Pouliquen 	}
731eca94980SArnaud Pouliquen 	adc->spi_freq = spi_freq;
732eca94980SArnaud Pouliquen 
733eca94980SArnaud Pouliquen 	return len;
734eca94980SArnaud Pouliquen }
735eca94980SArnaud Pouliquen 
stm32_dfsdm_start_conv(struct iio_dev * indio_dev,struct iio_trigger * trig)73607b6c9dcSAlexandru Ardelean static int stm32_dfsdm_start_conv(struct iio_dev *indio_dev,
73711646e81SFabrice Gasnier 				  struct iio_trigger *trig)
738e2e6771cSArnaud Pouliquen {
73907b6c9dcSAlexandru Ardelean 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
740e2e6771cSArnaud Pouliquen 	struct regmap *regmap = adc->dfsdm->regmap;
741e2e6771cSArnaud Pouliquen 	int ret;
742e2e6771cSArnaud Pouliquen 
74307b6c9dcSAlexandru Ardelean 	ret = stm32_dfsdm_channels_configure(indio_dev, adc->fl_id, trig);
74412c8398dSOlivier Moysan 	if (ret < 0)
74512c8398dSOlivier Moysan 		return ret;
74612c8398dSOlivier Moysan 
74707b6c9dcSAlexandru Ardelean 	ret = stm32_dfsdm_start_channel(indio_dev);
748e2e6771cSArnaud Pouliquen 	if (ret < 0)
749e2e6771cSArnaud Pouliquen 		return ret;
750e2e6771cSArnaud Pouliquen 
75107b6c9dcSAlexandru Ardelean 	ret = stm32_dfsdm_filter_configure(indio_dev, adc->fl_id, trig);
752e2e6771cSArnaud Pouliquen 	if (ret < 0)
753e2e6771cSArnaud Pouliquen 		goto stop_channels;
754e2e6771cSArnaud Pouliquen 
75511646e81SFabrice Gasnier 	ret = stm32_dfsdm_start_filter(adc, adc->fl_id, trig);
756eca94980SArnaud Pouliquen 	if (ret < 0)
7576f2c4a59SFabrice Gasnier 		goto filter_unconfigure;
758eca94980SArnaud Pouliquen 
759e2e6771cSArnaud Pouliquen 	return 0;
760e2e6771cSArnaud Pouliquen 
7616f2c4a59SFabrice Gasnier filter_unconfigure:
762e2e6771cSArnaud Pouliquen 	regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id),
7636f2c4a59SFabrice Gasnier 			   DFSDM_CR1_CFG_MASK, 0);
7646f2c4a59SFabrice Gasnier stop_channels:
76507b6c9dcSAlexandru Ardelean 	stm32_dfsdm_stop_channel(indio_dev);
766e2e6771cSArnaud Pouliquen 
767e2e6771cSArnaud Pouliquen 	return ret;
768e2e6771cSArnaud Pouliquen }
769e2e6771cSArnaud Pouliquen 
stm32_dfsdm_stop_conv(struct iio_dev * indio_dev)77007b6c9dcSAlexandru Ardelean static void stm32_dfsdm_stop_conv(struct iio_dev *indio_dev)
771e2e6771cSArnaud Pouliquen {
77207b6c9dcSAlexandru Ardelean 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
773e2e6771cSArnaud Pouliquen 	struct regmap *regmap = adc->dfsdm->regmap;
774e2e6771cSArnaud Pouliquen 
775e2e6771cSArnaud Pouliquen 	stm32_dfsdm_stop_filter(adc->dfsdm, adc->fl_id);
776e2e6771cSArnaud Pouliquen 
777e2e6771cSArnaud Pouliquen 	regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id),
7786f2c4a59SFabrice Gasnier 			   DFSDM_CR1_CFG_MASK, 0);
779e2e6771cSArnaud Pouliquen 
78007b6c9dcSAlexandru Ardelean 	stm32_dfsdm_stop_channel(indio_dev);
781e2e6771cSArnaud Pouliquen }
782e2e6771cSArnaud Pouliquen 
stm32_dfsdm_set_watermark(struct iio_dev * indio_dev,unsigned int val)783eca94980SArnaud Pouliquen static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev,
784eca94980SArnaud Pouliquen 				     unsigned int val)
785eca94980SArnaud Pouliquen {
786eca94980SArnaud Pouliquen 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
787eca94980SArnaud Pouliquen 	unsigned int watermark = DFSDM_DMA_BUFFER_SIZE / 2;
78811646e81SFabrice Gasnier 	unsigned int rx_buf_sz = DFSDM_DMA_BUFFER_SIZE;
789eca94980SArnaud Pouliquen 
790eca94980SArnaud Pouliquen 	/*
791eca94980SArnaud Pouliquen 	 * DMA cyclic transfers are used, buffer is split into two periods.
792eca94980SArnaud Pouliquen 	 * There should be :
793eca94980SArnaud Pouliquen 	 * - always one buffer (period) DMA is working on
794eca94980SArnaud Pouliquen 	 * - one buffer (period) driver pushed to ASoC side.
795eca94980SArnaud Pouliquen 	 */
796eca94980SArnaud Pouliquen 	watermark = min(watermark, val * (unsigned int)(sizeof(u32)));
79711646e81SFabrice Gasnier 	adc->buf_sz = min(rx_buf_sz, watermark * 2 * adc->nconv);
798eca94980SArnaud Pouliquen 
799eca94980SArnaud Pouliquen 	return 0;
800eca94980SArnaud Pouliquen }
801eca94980SArnaud Pouliquen 
stm32_dfsdm_adc_dma_residue(struct stm32_dfsdm_adc * adc)802eca94980SArnaud Pouliquen static unsigned int stm32_dfsdm_adc_dma_residue(struct stm32_dfsdm_adc *adc)
803eca94980SArnaud Pouliquen {
804eca94980SArnaud Pouliquen 	struct dma_tx_state state;
805eca94980SArnaud Pouliquen 	enum dma_status status;
806eca94980SArnaud Pouliquen 
807eca94980SArnaud Pouliquen 	status = dmaengine_tx_status(adc->dma_chan,
808eca94980SArnaud Pouliquen 				     adc->dma_chan->cookie,
809eca94980SArnaud Pouliquen 				     &state);
810eca94980SArnaud Pouliquen 	if (status == DMA_IN_PROGRESS) {
811eca94980SArnaud Pouliquen 		/* Residue is size in bytes from end of buffer */
812eca94980SArnaud Pouliquen 		unsigned int i = adc->buf_sz - state.residue;
813eca94980SArnaud Pouliquen 		unsigned int size;
814eca94980SArnaud Pouliquen 
815eca94980SArnaud Pouliquen 		/* Return available bytes */
816eca94980SArnaud Pouliquen 		if (i >= adc->bufi)
817eca94980SArnaud Pouliquen 			size = i - adc->bufi;
818eca94980SArnaud Pouliquen 		else
819eca94980SArnaud Pouliquen 			size = adc->buf_sz + i - adc->bufi;
820eca94980SArnaud Pouliquen 
821eca94980SArnaud Pouliquen 		return size;
822eca94980SArnaud Pouliquen 	}
823eca94980SArnaud Pouliquen 
824eca94980SArnaud Pouliquen 	return 0;
825eca94980SArnaud Pouliquen }
826eca94980SArnaud Pouliquen 
stm32_dfsdm_process_data(struct stm32_dfsdm_adc * adc,s32 * buffer)827102afde6SOlivier Moysan static inline void stm32_dfsdm_process_data(struct stm32_dfsdm_adc *adc,
828102afde6SOlivier Moysan 					    s32 *buffer)
829102afde6SOlivier Moysan {
830102afde6SOlivier Moysan 	struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id];
831d716204fSOlivier Moysan 	struct stm32_dfsdm_filter_osr *flo = &fl->flo[fl->fast];
832102afde6SOlivier Moysan 	unsigned int i = adc->nconv;
833102afde6SOlivier Moysan 	s32 *ptr = buffer;
834102afde6SOlivier Moysan 
835102afde6SOlivier Moysan 	while (i--) {
836102afde6SOlivier Moysan 		/* Mask 8 LSB that contains the channel ID */
837102afde6SOlivier Moysan 		*ptr &= 0xFFFFFF00;
838102afde6SOlivier Moysan 		/* Convert 2^(n-1) sample to 2^(n-1)-1 to avoid wrap-around */
839102afde6SOlivier Moysan 		if (*ptr > flo->max)
840102afde6SOlivier Moysan 			*ptr -= 1;
841102afde6SOlivier Moysan 		/*
842102afde6SOlivier Moysan 		 * Samples from filter are retrieved with 23 bits resolution
843102afde6SOlivier Moysan 		 * or less. Shift left to align MSB on 24 bits.
844102afde6SOlivier Moysan 		 */
845102afde6SOlivier Moysan 		*ptr <<= flo->lshift;
846102afde6SOlivier Moysan 
847102afde6SOlivier Moysan 		ptr++;
848102afde6SOlivier Moysan 	}
849102afde6SOlivier Moysan }
850102afde6SOlivier Moysan 
stm32_dfsdm_dma_buffer_done(void * data)85111646e81SFabrice Gasnier static void stm32_dfsdm_dma_buffer_done(void *data)
852eca94980SArnaud Pouliquen {
853eca94980SArnaud Pouliquen 	struct iio_dev *indio_dev = data;
854eca94980SArnaud Pouliquen 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
855eca94980SArnaud Pouliquen 	int available = stm32_dfsdm_adc_dma_residue(adc);
856eca94980SArnaud Pouliquen 	size_t old_pos;
857eca94980SArnaud Pouliquen 
858eca94980SArnaud Pouliquen 	/*
859eca94980SArnaud Pouliquen 	 * FIXME: In Kernel interface does not support cyclic DMA buffer,and
860eca94980SArnaud Pouliquen 	 * offers only an interface to push data samples per samples.
861eca94980SArnaud Pouliquen 	 * For this reason IIO buffer interface is not used and interface is
862eca94980SArnaud Pouliquen 	 * bypassed using a private callback registered by ASoC.
863eca94980SArnaud Pouliquen 	 * This should be a temporary solution waiting a cyclic DMA engine
864eca94980SArnaud Pouliquen 	 * support in IIO.
865eca94980SArnaud Pouliquen 	 */
866eca94980SArnaud Pouliquen 
867bb142d44SMugilraj Dhavachelvan 	dev_dbg(&indio_dev->dev, "pos = %d, available = %d\n",
868eca94980SArnaud Pouliquen 		adc->bufi, available);
869eca94980SArnaud Pouliquen 	old_pos = adc->bufi;
870eca94980SArnaud Pouliquen 
871eca94980SArnaud Pouliquen 	while (available >= indio_dev->scan_bytes) {
87212c8398dSOlivier Moysan 		s32 *buffer = (s32 *)&adc->rx_buf[adc->bufi];
873eca94980SArnaud Pouliquen 
874102afde6SOlivier Moysan 		stm32_dfsdm_process_data(adc, buffer);
87512c8398dSOlivier Moysan 
876eca94980SArnaud Pouliquen 		available -= indio_dev->scan_bytes;
877eca94980SArnaud Pouliquen 		adc->bufi += indio_dev->scan_bytes;
878eca94980SArnaud Pouliquen 		if (adc->bufi >= adc->buf_sz) {
879eca94980SArnaud Pouliquen 			if (adc->cb)
880eca94980SArnaud Pouliquen 				adc->cb(&adc->rx_buf[old_pos],
881eca94980SArnaud Pouliquen 					 adc->buf_sz - old_pos, adc->cb_priv);
882eca94980SArnaud Pouliquen 			adc->bufi = 0;
883eca94980SArnaud Pouliquen 			old_pos = 0;
884eca94980SArnaud Pouliquen 		}
885e19ac9d9SOlivier Moysan 		/*
886e19ac9d9SOlivier Moysan 		 * In DMA mode the trigger services of IIO are not used
887e19ac9d9SOlivier Moysan 		 * (e.g. no call to iio_trigger_poll).
888e19ac9d9SOlivier Moysan 		 * Calling irq handler associated to the hardware trigger is not
889e19ac9d9SOlivier Moysan 		 * relevant as the conversions have already been done. Data
890e19ac9d9SOlivier Moysan 		 * transfers are performed directly in DMA callback instead.
891e19ac9d9SOlivier Moysan 		 * This implementation avoids to call trigger irq handler that
892e19ac9d9SOlivier Moysan 		 * may sleep, in an atomic context (DMA irq handler context).
893e19ac9d9SOlivier Moysan 		 */
89411646e81SFabrice Gasnier 		if (adc->dev_data->type == DFSDM_IIO)
89511646e81SFabrice Gasnier 			iio_push_to_buffers(indio_dev, buffer);
896eca94980SArnaud Pouliquen 	}
897eca94980SArnaud Pouliquen 	if (adc->cb)
898eca94980SArnaud Pouliquen 		adc->cb(&adc->rx_buf[old_pos], adc->bufi - old_pos,
899eca94980SArnaud Pouliquen 			adc->cb_priv);
900eca94980SArnaud Pouliquen }
901eca94980SArnaud Pouliquen 
stm32_dfsdm_adc_dma_start(struct iio_dev * indio_dev)902eca94980SArnaud Pouliquen static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev)
903eca94980SArnaud Pouliquen {
904eca94980SArnaud Pouliquen 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
90518eaffabSOlivier Moysan 	/*
90618eaffabSOlivier Moysan 	 * The DFSDM supports half-word transfers. However, for 16 bits record,
90718eaffabSOlivier Moysan 	 * 4 bytes buswidth is kept, to avoid losing samples LSBs when left
90818eaffabSOlivier Moysan 	 * shift is required.
90918eaffabSOlivier Moysan 	 */
91074648508SFabrice Gasnier 	struct dma_slave_config config = {
911a6096762SFabrice Gasnier 		.src_addr = (dma_addr_t)adc->dfsdm->phys_base,
91274648508SFabrice Gasnier 		.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
91374648508SFabrice Gasnier 	};
914eca94980SArnaud Pouliquen 	struct dma_async_tx_descriptor *desc;
915eca94980SArnaud Pouliquen 	dma_cookie_t cookie;
916eca94980SArnaud Pouliquen 	int ret;
917eca94980SArnaud Pouliquen 
918eca94980SArnaud Pouliquen 	if (!adc->dma_chan)
919eca94980SArnaud Pouliquen 		return -EINVAL;
920eca94980SArnaud Pouliquen 
921bb142d44SMugilraj Dhavachelvan 	dev_dbg(&indio_dev->dev, "size=%d watermark=%d\n",
922eca94980SArnaud Pouliquen 		adc->buf_sz, adc->buf_sz / 2);
923eca94980SArnaud Pouliquen 
92411646e81SFabrice Gasnier 	if (adc->nconv == 1 && !indio_dev->trig)
925a6096762SFabrice Gasnier 		config.src_addr += DFSDM_RDATAR(adc->fl_id);
926a6096762SFabrice Gasnier 	else
927a6096762SFabrice Gasnier 		config.src_addr += DFSDM_JDATAR(adc->fl_id);
92874648508SFabrice Gasnier 	ret = dmaengine_slave_config(adc->dma_chan, &config);
92974648508SFabrice Gasnier 	if (ret)
93074648508SFabrice Gasnier 		return ret;
93174648508SFabrice Gasnier 
932eca94980SArnaud Pouliquen 	/* Prepare a DMA cyclic transaction */
933eca94980SArnaud Pouliquen 	desc = dmaengine_prep_dma_cyclic(adc->dma_chan,
934eca94980SArnaud Pouliquen 					 adc->dma_buf,
935eca94980SArnaud Pouliquen 					 adc->buf_sz, adc->buf_sz / 2,
936eca94980SArnaud Pouliquen 					 DMA_DEV_TO_MEM,
937eca94980SArnaud Pouliquen 					 DMA_PREP_INTERRUPT);
938eca94980SArnaud Pouliquen 	if (!desc)
939eca94980SArnaud Pouliquen 		return -EBUSY;
940eca94980SArnaud Pouliquen 
94111646e81SFabrice Gasnier 	desc->callback = stm32_dfsdm_dma_buffer_done;
942eca94980SArnaud Pouliquen 	desc->callback_param = indio_dev;
943eca94980SArnaud Pouliquen 
944eca94980SArnaud Pouliquen 	cookie = dmaengine_submit(desc);
945eca94980SArnaud Pouliquen 	ret = dma_submit_error(cookie);
946caf9c1e5SFabrice Gasnier 	if (ret)
947caf9c1e5SFabrice Gasnier 		goto err_stop_dma;
948eca94980SArnaud Pouliquen 
949eca94980SArnaud Pouliquen 	/* Issue pending DMA requests */
950eca94980SArnaud Pouliquen 	dma_async_issue_pending(adc->dma_chan);
951eca94980SArnaud Pouliquen 
95211646e81SFabrice Gasnier 	if (adc->nconv == 1 && !indio_dev->trig) {
953a6096762SFabrice Gasnier 		/* Enable regular DMA transfer*/
954a6096762SFabrice Gasnier 		ret = regmap_update_bits(adc->dfsdm->regmap,
955a6096762SFabrice Gasnier 					 DFSDM_CR1(adc->fl_id),
956a6096762SFabrice Gasnier 					 DFSDM_CR1_RDMAEN_MASK,
957a6096762SFabrice Gasnier 					 DFSDM_CR1_RDMAEN_MASK);
958a6096762SFabrice Gasnier 	} else {
959a6096762SFabrice Gasnier 		/* Enable injected DMA transfer*/
960a6096762SFabrice Gasnier 		ret = regmap_update_bits(adc->dfsdm->regmap,
961a6096762SFabrice Gasnier 					 DFSDM_CR1(adc->fl_id),
962a6096762SFabrice Gasnier 					 DFSDM_CR1_JDMAEN_MASK,
963a6096762SFabrice Gasnier 					 DFSDM_CR1_JDMAEN_MASK);
964a6096762SFabrice Gasnier 	}
965a6096762SFabrice Gasnier 
966caf9c1e5SFabrice Gasnier 	if (ret < 0)
967caf9c1e5SFabrice Gasnier 		goto err_stop_dma;
968caf9c1e5SFabrice Gasnier 
969eca94980SArnaud Pouliquen 	return 0;
970caf9c1e5SFabrice Gasnier 
971caf9c1e5SFabrice Gasnier err_stop_dma:
972caf9c1e5SFabrice Gasnier 	dmaengine_terminate_all(adc->dma_chan);
973caf9c1e5SFabrice Gasnier 
974caf9c1e5SFabrice Gasnier 	return ret;
975caf9c1e5SFabrice Gasnier }
976caf9c1e5SFabrice Gasnier 
stm32_dfsdm_adc_dma_stop(struct iio_dev * indio_dev)977caf9c1e5SFabrice Gasnier static void stm32_dfsdm_adc_dma_stop(struct iio_dev *indio_dev)
978caf9c1e5SFabrice Gasnier {
979caf9c1e5SFabrice Gasnier 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
980caf9c1e5SFabrice Gasnier 
981caf9c1e5SFabrice Gasnier 	if (!adc->dma_chan)
982caf9c1e5SFabrice Gasnier 		return;
983caf9c1e5SFabrice Gasnier 
984caf9c1e5SFabrice Gasnier 	regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR1(adc->fl_id),
985a6096762SFabrice Gasnier 			   DFSDM_CR1_RDMAEN_MASK | DFSDM_CR1_JDMAEN_MASK, 0);
986caf9c1e5SFabrice Gasnier 	dmaengine_terminate_all(adc->dma_chan);
987eca94980SArnaud Pouliquen }
988eca94980SArnaud Pouliquen 
stm32_dfsdm_update_scan_mode(struct iio_dev * indio_dev,const unsigned long * scan_mask)989a6096762SFabrice Gasnier static int stm32_dfsdm_update_scan_mode(struct iio_dev *indio_dev,
990a6096762SFabrice Gasnier 					const unsigned long *scan_mask)
991a6096762SFabrice Gasnier {
992a6096762SFabrice Gasnier 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
993a6096762SFabrice Gasnier 
994a6096762SFabrice Gasnier 	adc->nconv = bitmap_weight(scan_mask, indio_dev->masklength);
995a6096762SFabrice Gasnier 	adc->smask = *scan_mask;
996a6096762SFabrice Gasnier 
997a6096762SFabrice Gasnier 	dev_dbg(&indio_dev->dev, "nconv=%d mask=%lx\n", adc->nconv, *scan_mask);
998a6096762SFabrice Gasnier 
999a6096762SFabrice Gasnier 	return 0;
1000a6096762SFabrice Gasnier }
1001a6096762SFabrice Gasnier 
stm32_dfsdm_postenable(struct iio_dev * indio_dev)1002f11d59d8SLars-Peter Clausen static int stm32_dfsdm_postenable(struct iio_dev *indio_dev)
1003eca94980SArnaud Pouliquen {
1004eca94980SArnaud Pouliquen 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
1005eca94980SArnaud Pouliquen 	int ret;
1006eca94980SArnaud Pouliquen 
1007eca94980SArnaud Pouliquen 	/* Reset adc buffer index */
1008eca94980SArnaud Pouliquen 	adc->bufi = 0;
1009eca94980SArnaud Pouliquen 
10109491f75fSFabrice Gasnier 	if (adc->hwc) {
10119491f75fSFabrice Gasnier 		ret = iio_hw_consumer_enable(adc->hwc);
1012eca94980SArnaud Pouliquen 		if (ret < 0)
10136ec417d2SFabrice Gasnier 			return ret;
10149491f75fSFabrice Gasnier 	}
10159491f75fSFabrice Gasnier 
10169491f75fSFabrice Gasnier 	ret = stm32_dfsdm_start_dfsdm(adc->dfsdm);
10179491f75fSFabrice Gasnier 	if (ret < 0)
10189491f75fSFabrice Gasnier 		goto err_stop_hwc;
1019eca94980SArnaud Pouliquen 
1020eca94980SArnaud Pouliquen 	ret = stm32_dfsdm_adc_dma_start(indio_dev);
1021eca94980SArnaud Pouliquen 	if (ret) {
1022eca94980SArnaud Pouliquen 		dev_err(&indio_dev->dev, "Can't start DMA\n");
1023caf9c1e5SFabrice Gasnier 		goto stop_dfsdm;
1024eca94980SArnaud Pouliquen 	}
1025caf9c1e5SFabrice Gasnier 
102607b6c9dcSAlexandru Ardelean 	ret = stm32_dfsdm_start_conv(indio_dev, indio_dev->trig);
1027caf9c1e5SFabrice Gasnier 	if (ret) {
1028caf9c1e5SFabrice Gasnier 		dev_err(&indio_dev->dev, "Can't start conversion\n");
1029caf9c1e5SFabrice Gasnier 		goto err_stop_dma;
1030eca94980SArnaud Pouliquen 	}
1031eca94980SArnaud Pouliquen 
1032eca94980SArnaud Pouliquen 	return 0;
1033eca94980SArnaud Pouliquen 
1034caf9c1e5SFabrice Gasnier err_stop_dma:
1035caf9c1e5SFabrice Gasnier 	stm32_dfsdm_adc_dma_stop(indio_dev);
1036eca94980SArnaud Pouliquen stop_dfsdm:
1037eca94980SArnaud Pouliquen 	stm32_dfsdm_stop_dfsdm(adc->dfsdm);
10389491f75fSFabrice Gasnier err_stop_hwc:
10399491f75fSFabrice Gasnier 	if (adc->hwc)
10409491f75fSFabrice Gasnier 		iio_hw_consumer_disable(adc->hwc);
10416ec417d2SFabrice Gasnier 
10426ec417d2SFabrice Gasnier 	return ret;
10436ec417d2SFabrice Gasnier }
10446ec417d2SFabrice Gasnier 
stm32_dfsdm_predisable(struct iio_dev * indio_dev)1045f11d59d8SLars-Peter Clausen static int stm32_dfsdm_predisable(struct iio_dev *indio_dev)
1046eca94980SArnaud Pouliquen {
1047eca94980SArnaud Pouliquen 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
1048eca94980SArnaud Pouliquen 
104907b6c9dcSAlexandru Ardelean 	stm32_dfsdm_stop_conv(indio_dev);
1050eca94980SArnaud Pouliquen 
1051caf9c1e5SFabrice Gasnier 	stm32_dfsdm_adc_dma_stop(indio_dev);
1052caf9c1e5SFabrice Gasnier 
1053eca94980SArnaud Pouliquen 	stm32_dfsdm_stop_dfsdm(adc->dfsdm);
1054eca94980SArnaud Pouliquen 
10559491f75fSFabrice Gasnier 	if (adc->hwc)
10569491f75fSFabrice Gasnier 		iio_hw_consumer_disable(adc->hwc);
105711646e81SFabrice Gasnier 
1058eca94980SArnaud Pouliquen 	return 0;
1059eca94980SArnaud Pouliquen }
1060eca94980SArnaud Pouliquen 
1061eca94980SArnaud Pouliquen static const struct iio_buffer_setup_ops stm32_dfsdm_buffer_setup_ops = {
1062eca94980SArnaud Pouliquen 	.postenable = &stm32_dfsdm_postenable,
1063eca94980SArnaud Pouliquen 	.predisable = &stm32_dfsdm_predisable,
1064eca94980SArnaud Pouliquen };
1065eca94980SArnaud Pouliquen 
1066eca94980SArnaud Pouliquen /**
1067eca94980SArnaud Pouliquen  * stm32_dfsdm_get_buff_cb() - register a callback that will be called when
1068eca94980SArnaud Pouliquen  *                             DMA transfer period is achieved.
1069eca94980SArnaud Pouliquen  *
1070eca94980SArnaud Pouliquen  * @iio_dev: Handle to IIO device.
1071eca94980SArnaud Pouliquen  * @cb: Pointer to callback function:
1072eca94980SArnaud Pouliquen  *      - data: pointer to data buffer
1073eca94980SArnaud Pouliquen  *      - size: size in byte of the data buffer
1074eca94980SArnaud Pouliquen  *      - private: pointer to consumer private structure.
1075eca94980SArnaud Pouliquen  * @private: Pointer to consumer private structure.
1076eca94980SArnaud Pouliquen  */
stm32_dfsdm_get_buff_cb(struct iio_dev * iio_dev,int (* cb)(const void * data,size_t size,void * private),void * private)1077eca94980SArnaud Pouliquen int stm32_dfsdm_get_buff_cb(struct iio_dev *iio_dev,
1078eca94980SArnaud Pouliquen 			    int (*cb)(const void *data, size_t size,
1079eca94980SArnaud Pouliquen 				      void *private),
1080eca94980SArnaud Pouliquen 			    void *private)
1081eca94980SArnaud Pouliquen {
1082eca94980SArnaud Pouliquen 	struct stm32_dfsdm_adc *adc;
1083eca94980SArnaud Pouliquen 
1084eca94980SArnaud Pouliquen 	if (!iio_dev)
1085eca94980SArnaud Pouliquen 		return -EINVAL;
1086eca94980SArnaud Pouliquen 	adc = iio_priv(iio_dev);
1087eca94980SArnaud Pouliquen 
1088eca94980SArnaud Pouliquen 	adc->cb = cb;
1089eca94980SArnaud Pouliquen 	adc->cb_priv = private;
1090eca94980SArnaud Pouliquen 
1091eca94980SArnaud Pouliquen 	return 0;
1092eca94980SArnaud Pouliquen }
1093eca94980SArnaud Pouliquen EXPORT_SYMBOL_GPL(stm32_dfsdm_get_buff_cb);
1094eca94980SArnaud Pouliquen 
1095eca94980SArnaud Pouliquen /**
1096eca94980SArnaud Pouliquen  * stm32_dfsdm_release_buff_cb - unregister buffer callback
1097eca94980SArnaud Pouliquen  *
1098eca94980SArnaud Pouliquen  * @iio_dev: Handle to IIO device.
1099eca94980SArnaud Pouliquen  */
stm32_dfsdm_release_buff_cb(struct iio_dev * iio_dev)1100eca94980SArnaud Pouliquen int stm32_dfsdm_release_buff_cb(struct iio_dev *iio_dev)
1101eca94980SArnaud Pouliquen {
1102eca94980SArnaud Pouliquen 	struct stm32_dfsdm_adc *adc;
1103eca94980SArnaud Pouliquen 
1104eca94980SArnaud Pouliquen 	if (!iio_dev)
1105eca94980SArnaud Pouliquen 		return -EINVAL;
1106eca94980SArnaud Pouliquen 	adc = iio_priv(iio_dev);
1107eca94980SArnaud Pouliquen 
1108eca94980SArnaud Pouliquen 	adc->cb = NULL;
1109eca94980SArnaud Pouliquen 	adc->cb_priv = NULL;
1110eca94980SArnaud Pouliquen 
1111eca94980SArnaud Pouliquen 	return 0;
1112eca94980SArnaud Pouliquen }
1113eca94980SArnaud Pouliquen EXPORT_SYMBOL_GPL(stm32_dfsdm_release_buff_cb);
1114eca94980SArnaud Pouliquen 
stm32_dfsdm_single_conv(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,int * res)1115e2e6771cSArnaud Pouliquen static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev,
1116e2e6771cSArnaud Pouliquen 				   const struct iio_chan_spec *chan, int *res)
1117e2e6771cSArnaud Pouliquen {
1118e2e6771cSArnaud Pouliquen 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
1119e2e6771cSArnaud Pouliquen 	long timeout;
1120e2e6771cSArnaud Pouliquen 	int ret;
1121e2e6771cSArnaud Pouliquen 
1122e2e6771cSArnaud Pouliquen 	reinit_completion(&adc->completion);
1123e2e6771cSArnaud Pouliquen 
1124e2e6771cSArnaud Pouliquen 	adc->buffer = res;
1125e2e6771cSArnaud Pouliquen 
1126e2e6771cSArnaud Pouliquen 	ret = stm32_dfsdm_start_dfsdm(adc->dfsdm);
1127e2e6771cSArnaud Pouliquen 	if (ret < 0)
1128e2e6771cSArnaud Pouliquen 		return ret;
1129e2e6771cSArnaud Pouliquen 
1130e2e6771cSArnaud Pouliquen 	ret = regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR2(adc->fl_id),
1131e2e6771cSArnaud Pouliquen 				 DFSDM_CR2_REOCIE_MASK, DFSDM_CR2_REOCIE(1));
1132e2e6771cSArnaud Pouliquen 	if (ret < 0)
1133e2e6771cSArnaud Pouliquen 		goto stop_dfsdm;
1134e2e6771cSArnaud Pouliquen 
1135a6096762SFabrice Gasnier 	adc->nconv = 1;
1136a6096762SFabrice Gasnier 	adc->smask = BIT(chan->scan_index);
113707b6c9dcSAlexandru Ardelean 	ret = stm32_dfsdm_start_conv(indio_dev, NULL);
1138e2e6771cSArnaud Pouliquen 	if (ret < 0) {
1139e2e6771cSArnaud Pouliquen 		regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR2(adc->fl_id),
1140e2e6771cSArnaud Pouliquen 				   DFSDM_CR2_REOCIE_MASK, DFSDM_CR2_REOCIE(0));
1141e2e6771cSArnaud Pouliquen 		goto stop_dfsdm;
1142e2e6771cSArnaud Pouliquen 	}
1143e2e6771cSArnaud Pouliquen 
1144e2e6771cSArnaud Pouliquen 	timeout = wait_for_completion_interruptible_timeout(&adc->completion,
1145e2e6771cSArnaud Pouliquen 							    DFSDM_TIMEOUT);
1146e2e6771cSArnaud Pouliquen 
1147e2e6771cSArnaud Pouliquen 	/* Mask IRQ for regular conversion achievement*/
1148e2e6771cSArnaud Pouliquen 	regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR2(adc->fl_id),
1149e2e6771cSArnaud Pouliquen 			   DFSDM_CR2_REOCIE_MASK, DFSDM_CR2_REOCIE(0));
1150e2e6771cSArnaud Pouliquen 
1151e2e6771cSArnaud Pouliquen 	if (timeout == 0)
1152e2e6771cSArnaud Pouliquen 		ret = -ETIMEDOUT;
1153e2e6771cSArnaud Pouliquen 	else if (timeout < 0)
1154e2e6771cSArnaud Pouliquen 		ret = timeout;
1155e2e6771cSArnaud Pouliquen 	else
1156e2e6771cSArnaud Pouliquen 		ret = IIO_VAL_INT;
1157e2e6771cSArnaud Pouliquen 
115807b6c9dcSAlexandru Ardelean 	stm32_dfsdm_stop_conv(indio_dev);
1159e2e6771cSArnaud Pouliquen 
1160dc26935fSOlivier Moysan 	stm32_dfsdm_process_data(adc, res);
1161dc26935fSOlivier Moysan 
1162e2e6771cSArnaud Pouliquen stop_dfsdm:
1163e2e6771cSArnaud Pouliquen 	stm32_dfsdm_stop_dfsdm(adc->dfsdm);
1164e2e6771cSArnaud Pouliquen 
1165e2e6771cSArnaud Pouliquen 	return ret;
1166e2e6771cSArnaud Pouliquen }
1167e2e6771cSArnaud Pouliquen 
stm32_dfsdm_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)1168e2e6771cSArnaud Pouliquen static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev,
1169e2e6771cSArnaud Pouliquen 				 struct iio_chan_spec const *chan,
1170e2e6771cSArnaud Pouliquen 				 int val, int val2, long mask)
1171e2e6771cSArnaud Pouliquen {
1172e2e6771cSArnaud Pouliquen 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
11730645af1bSFabrice Gasnier 	struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[chan->channel];
1174d58109dcSFabrice Gasnier 	unsigned int spi_freq;
1175e2e6771cSArnaud Pouliquen 	int ret = -EINVAL;
1176e2e6771cSArnaud Pouliquen 
1177d58109dcSFabrice Gasnier 	switch (ch->src) {
1178d58109dcSFabrice Gasnier 	case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL:
1179eca94980SArnaud Pouliquen 		spi_freq = adc->dfsdm->spi_master_freq;
1180d58109dcSFabrice Gasnier 		break;
1181d58109dcSFabrice Gasnier 	case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_FALLING:
1182d58109dcSFabrice Gasnier 	case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_RISING:
1183d58109dcSFabrice Gasnier 		spi_freq = adc->dfsdm->spi_master_freq / 2;
1184d58109dcSFabrice Gasnier 		break;
1185d58109dcSFabrice Gasnier 	default:
1186d58109dcSFabrice Gasnier 		spi_freq = adc->spi_freq;
1187d58109dcSFabrice Gasnier 	}
1188eca94980SArnaud Pouliquen 
1189f81ec5bfSOlivier Moysan 	switch (mask) {
1190f81ec5bfSOlivier Moysan 	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
1191f81ec5bfSOlivier Moysan 		ret = iio_device_claim_direct_mode(indio_dev);
1192f81ec5bfSOlivier Moysan 		if (ret)
1193f81ec5bfSOlivier Moysan 			return ret;
1194f81ec5bfSOlivier Moysan 
1195f81ec5bfSOlivier Moysan 		ret = stm32_dfsdm_compute_all_osrs(indio_dev, val);
1196f81ec5bfSOlivier Moysan 		if (!ret) {
1197f81ec5bfSOlivier Moysan 			dev_dbg(&indio_dev->dev,
1198f81ec5bfSOlivier Moysan 				"Sampling rate changed from (%u) to (%u)\n",
1199f81ec5bfSOlivier Moysan 				adc->sample_freq, spi_freq / val);
1200f81ec5bfSOlivier Moysan 			adc->oversamp = val;
1201f81ec5bfSOlivier Moysan 			adc->sample_freq = spi_freq / val;
1202f81ec5bfSOlivier Moysan 		}
1203f81ec5bfSOlivier Moysan 		iio_device_release_direct_mode(indio_dev);
1204f81ec5bfSOlivier Moysan 		return ret;
1205f81ec5bfSOlivier Moysan 
1206f81ec5bfSOlivier Moysan 	case IIO_CHAN_INFO_SAMP_FREQ:
1207f81ec5bfSOlivier Moysan 		if (!val)
1208f81ec5bfSOlivier Moysan 			return -EINVAL;
1209f81ec5bfSOlivier Moysan 
1210f81ec5bfSOlivier Moysan 		ret = iio_device_claim_direct_mode(indio_dev);
1211f81ec5bfSOlivier Moysan 		if (ret)
1212f81ec5bfSOlivier Moysan 			return ret;
1213f81ec5bfSOlivier Moysan 
12149f57110dSFabrice Gasnier 		ret = dfsdm_adc_set_samp_freq(indio_dev, val, spi_freq);
121537ada026SFabrice Gasnier 		iio_device_release_direct_mode(indio_dev);
1216eca94980SArnaud Pouliquen 		return ret;
1217eca94980SArnaud Pouliquen 	}
1218eca94980SArnaud Pouliquen 
1219eca94980SArnaud Pouliquen 	return -EINVAL;
1220e2e6771cSArnaud Pouliquen }
1221e2e6771cSArnaud Pouliquen 
stm32_dfsdm_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)1222e2e6771cSArnaud Pouliquen static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev,
1223e2e6771cSArnaud Pouliquen 				struct iio_chan_spec const *chan, int *val,
1224e2e6771cSArnaud Pouliquen 				int *val2, long mask)
1225e2e6771cSArnaud Pouliquen {
1226e2e6771cSArnaud Pouliquen 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
1227e2e6771cSArnaud Pouliquen 	int ret;
1228e2e6771cSArnaud Pouliquen 
1229e2e6771cSArnaud Pouliquen 	switch (mask) {
1230e2e6771cSArnaud Pouliquen 	case IIO_CHAN_INFO_RAW:
123137ada026SFabrice Gasnier 		ret = iio_device_claim_direct_mode(indio_dev);
123237ada026SFabrice Gasnier 		if (ret)
123337ada026SFabrice Gasnier 			return ret;
1234e2e6771cSArnaud Pouliquen 		ret = iio_hw_consumer_enable(adc->hwc);
1235e2e6771cSArnaud Pouliquen 		if (ret < 0) {
1236e2e6771cSArnaud Pouliquen 			dev_err(&indio_dev->dev,
1237e2e6771cSArnaud Pouliquen 				"%s: IIO enable failed (channel %d)\n",
1238e2e6771cSArnaud Pouliquen 				__func__, chan->channel);
123937ada026SFabrice Gasnier 			iio_device_release_direct_mode(indio_dev);
1240e2e6771cSArnaud Pouliquen 			return ret;
1241e2e6771cSArnaud Pouliquen 		}
1242e2e6771cSArnaud Pouliquen 		ret = stm32_dfsdm_single_conv(indio_dev, chan, val);
1243e2e6771cSArnaud Pouliquen 		iio_hw_consumer_disable(adc->hwc);
1244e2e6771cSArnaud Pouliquen 		if (ret < 0) {
1245e2e6771cSArnaud Pouliquen 			dev_err(&indio_dev->dev,
1246e2e6771cSArnaud Pouliquen 				"%s: Conversion failed (channel %d)\n",
1247e2e6771cSArnaud Pouliquen 				__func__, chan->channel);
124837ada026SFabrice Gasnier 			iio_device_release_direct_mode(indio_dev);
1249e2e6771cSArnaud Pouliquen 			return ret;
1250e2e6771cSArnaud Pouliquen 		}
125137ada026SFabrice Gasnier 		iio_device_release_direct_mode(indio_dev);
1252e2e6771cSArnaud Pouliquen 		return IIO_VAL_INT;
1253e2e6771cSArnaud Pouliquen 
1254e2e6771cSArnaud Pouliquen 	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
1255e2e6771cSArnaud Pouliquen 		*val = adc->oversamp;
1256e2e6771cSArnaud Pouliquen 
1257e2e6771cSArnaud Pouliquen 		return IIO_VAL_INT;
1258eca94980SArnaud Pouliquen 
1259eca94980SArnaud Pouliquen 	case IIO_CHAN_INFO_SAMP_FREQ:
1260eca94980SArnaud Pouliquen 		*val = adc->sample_freq;
1261eca94980SArnaud Pouliquen 
1262eca94980SArnaud Pouliquen 		return IIO_VAL_INT;
1263e2e6771cSArnaud Pouliquen 	}
1264e2e6771cSArnaud Pouliquen 
1265e2e6771cSArnaud Pouliquen 	return -EINVAL;
1266e2e6771cSArnaud Pouliquen }
1267e2e6771cSArnaud Pouliquen 
stm32_dfsdm_validate_trigger(struct iio_dev * indio_dev,struct iio_trigger * trig)126811646e81SFabrice Gasnier static int stm32_dfsdm_validate_trigger(struct iio_dev *indio_dev,
126911646e81SFabrice Gasnier 					struct iio_trigger *trig)
127011646e81SFabrice Gasnier {
127111646e81SFabrice Gasnier 	return stm32_dfsdm_get_jextsel(indio_dev, trig) < 0 ? -EINVAL : 0;
127211646e81SFabrice Gasnier }
127311646e81SFabrice Gasnier 
1274eca94980SArnaud Pouliquen static const struct iio_info stm32_dfsdm_info_audio = {
1275eca94980SArnaud Pouliquen 	.hwfifo_set_watermark = stm32_dfsdm_set_watermark,
1276eca94980SArnaud Pouliquen 	.read_raw = stm32_dfsdm_read_raw,
1277eca94980SArnaud Pouliquen 	.write_raw = stm32_dfsdm_write_raw,
1278a6096762SFabrice Gasnier 	.update_scan_mode = stm32_dfsdm_update_scan_mode,
1279eca94980SArnaud Pouliquen };
1280eca94980SArnaud Pouliquen 
1281e2e6771cSArnaud Pouliquen static const struct iio_info stm32_dfsdm_info_adc = {
128211646e81SFabrice Gasnier 	.hwfifo_set_watermark = stm32_dfsdm_set_watermark,
1283e2e6771cSArnaud Pouliquen 	.read_raw = stm32_dfsdm_read_raw,
1284e2e6771cSArnaud Pouliquen 	.write_raw = stm32_dfsdm_write_raw,
1285a6096762SFabrice Gasnier 	.update_scan_mode = stm32_dfsdm_update_scan_mode,
128611646e81SFabrice Gasnier 	.validate_trigger = stm32_dfsdm_validate_trigger,
1287e2e6771cSArnaud Pouliquen };
1288e2e6771cSArnaud Pouliquen 
stm32_dfsdm_irq(int irq,void * arg)1289e2e6771cSArnaud Pouliquen static irqreturn_t stm32_dfsdm_irq(int irq, void *arg)
1290e2e6771cSArnaud Pouliquen {
129107b6c9dcSAlexandru Ardelean 	struct iio_dev *indio_dev = arg;
129207b6c9dcSAlexandru Ardelean 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
1293e2e6771cSArnaud Pouliquen 	struct regmap *regmap = adc->dfsdm->regmap;
1294e2e6771cSArnaud Pouliquen 	unsigned int status, int_en;
1295e2e6771cSArnaud Pouliquen 
1296e2e6771cSArnaud Pouliquen 	regmap_read(regmap, DFSDM_ISR(adc->fl_id), &status);
1297e2e6771cSArnaud Pouliquen 	regmap_read(regmap, DFSDM_CR2(adc->fl_id), &int_en);
1298e2e6771cSArnaud Pouliquen 
1299e2e6771cSArnaud Pouliquen 	if (status & DFSDM_ISR_REOCF_MASK) {
1300e2e6771cSArnaud Pouliquen 		/* Read the data register clean the IRQ status */
1301e2e6771cSArnaud Pouliquen 		regmap_read(regmap, DFSDM_RDATAR(adc->fl_id), adc->buffer);
1302e2e6771cSArnaud Pouliquen 		complete(&adc->completion);
1303e2e6771cSArnaud Pouliquen 	}
1304e2e6771cSArnaud Pouliquen 
1305e2e6771cSArnaud Pouliquen 	if (status & DFSDM_ISR_ROVRF_MASK) {
1306e2e6771cSArnaud Pouliquen 		if (int_en & DFSDM_CR2_ROVRIE_MASK)
1307e2e6771cSArnaud Pouliquen 			dev_warn(&indio_dev->dev, "Overrun detected\n");
1308e2e6771cSArnaud Pouliquen 		regmap_update_bits(regmap, DFSDM_ICR(adc->fl_id),
1309e2e6771cSArnaud Pouliquen 				   DFSDM_ICR_CLRROVRF_MASK,
1310e2e6771cSArnaud Pouliquen 				   DFSDM_ICR_CLRROVRF_MASK);
1311e2e6771cSArnaud Pouliquen 	}
1312e2e6771cSArnaud Pouliquen 
1313e2e6771cSArnaud Pouliquen 	return IRQ_HANDLED;
1314e2e6771cSArnaud Pouliquen }
1315e2e6771cSArnaud Pouliquen 
1316eca94980SArnaud Pouliquen /*
1317eca94980SArnaud Pouliquen  * Define external info for SPI Frequency and audio sampling rate that can be
1318eca94980SArnaud Pouliquen  * configured by ASoC driver through consumer.h API
1319eca94980SArnaud Pouliquen  */
1320eca94980SArnaud Pouliquen static const struct iio_chan_spec_ext_info dfsdm_adc_audio_ext_info[] = {
1321eca94980SArnaud Pouliquen 	/* spi_clk_freq : clock freq on SPI/manchester bus used by channel */
1322eca94980SArnaud Pouliquen 	{
1323eca94980SArnaud Pouliquen 		.name = "spi_clk_freq",
1324eca94980SArnaud Pouliquen 		.shared = IIO_SHARED_BY_TYPE,
1325eca94980SArnaud Pouliquen 		.read = dfsdm_adc_audio_get_spiclk,
1326eca94980SArnaud Pouliquen 		.write = dfsdm_adc_audio_set_spiclk,
1327eca94980SArnaud Pouliquen 	},
1328eca94980SArnaud Pouliquen 	{},
1329eca94980SArnaud Pouliquen };
1330eca94980SArnaud Pouliquen 
stm32_dfsdm_dma_release(struct iio_dev * indio_dev)1331eca94980SArnaud Pouliquen static void stm32_dfsdm_dma_release(struct iio_dev *indio_dev)
1332eca94980SArnaud Pouliquen {
1333eca94980SArnaud Pouliquen 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
1334eca94980SArnaud Pouliquen 
1335eca94980SArnaud Pouliquen 	if (adc->dma_chan) {
1336eca94980SArnaud Pouliquen 		dma_free_coherent(adc->dma_chan->device->dev,
1337eca94980SArnaud Pouliquen 				  DFSDM_DMA_BUFFER_SIZE,
1338eca94980SArnaud Pouliquen 				  adc->rx_buf, adc->dma_buf);
1339eca94980SArnaud Pouliquen 		dma_release_channel(adc->dma_chan);
1340eca94980SArnaud Pouliquen 	}
1341eca94980SArnaud Pouliquen }
1342eca94980SArnaud Pouliquen 
stm32_dfsdm_dma_request(struct device * dev,struct iio_dev * indio_dev)1343b455d06eSFabrice Gasnier static int stm32_dfsdm_dma_request(struct device *dev,
1344b455d06eSFabrice Gasnier 				   struct iio_dev *indio_dev)
1345eca94980SArnaud Pouliquen {
1346eca94980SArnaud Pouliquen 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
1347eca94980SArnaud Pouliquen 
1348b455d06eSFabrice Gasnier 	adc->dma_chan = dma_request_chan(dev, "rx");
1349a9ab624eSPeter Ujfalusi 	if (IS_ERR(adc->dma_chan)) {
1350a9ab624eSPeter Ujfalusi 		int ret = PTR_ERR(adc->dma_chan);
1351a9ab624eSPeter Ujfalusi 
1352a9ab624eSPeter Ujfalusi 		adc->dma_chan = NULL;
1353a9ab624eSPeter Ujfalusi 		return ret;
1354a9ab624eSPeter Ujfalusi 	}
1355eca94980SArnaud Pouliquen 
1356eca94980SArnaud Pouliquen 	adc->rx_buf = dma_alloc_coherent(adc->dma_chan->device->dev,
1357eca94980SArnaud Pouliquen 					 DFSDM_DMA_BUFFER_SIZE,
1358eca94980SArnaud Pouliquen 					 &adc->dma_buf, GFP_KERNEL);
1359eca94980SArnaud Pouliquen 	if (!adc->rx_buf) {
136074648508SFabrice Gasnier 		dma_release_channel(adc->dma_chan);
136174648508SFabrice Gasnier 		return -ENOMEM;
1362eca94980SArnaud Pouliquen 	}
1363eca94980SArnaud Pouliquen 
136411646e81SFabrice Gasnier 	indio_dev->modes |= INDIO_BUFFER_SOFTWARE;
136511646e81SFabrice Gasnier 	indio_dev->setup_ops = &stm32_dfsdm_buffer_setup_ops;
136611646e81SFabrice Gasnier 
1367eca94980SArnaud Pouliquen 	return 0;
1368eca94980SArnaud Pouliquen }
1369eca94980SArnaud Pouliquen 
stm32_dfsdm_adc_chan_init_one(struct iio_dev * indio_dev,struct iio_chan_spec * ch)1370e2e6771cSArnaud Pouliquen static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev,
1371e2e6771cSArnaud Pouliquen 					 struct iio_chan_spec *ch)
1372e2e6771cSArnaud Pouliquen {
1373e2e6771cSArnaud Pouliquen 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
1374e2e6771cSArnaud Pouliquen 	int ret;
1375e2e6771cSArnaud Pouliquen 
1376e2e6771cSArnaud Pouliquen 	ret = stm32_dfsdm_channel_parse_of(adc->dfsdm, indio_dev, ch);
1377e2e6771cSArnaud Pouliquen 	if (ret < 0)
1378e2e6771cSArnaud Pouliquen 		return ret;
1379e2e6771cSArnaud Pouliquen 
1380e2e6771cSArnaud Pouliquen 	ch->type = IIO_VOLTAGE;
1381e2e6771cSArnaud Pouliquen 	ch->indexed = 1;
1382e2e6771cSArnaud Pouliquen 
1383e2e6771cSArnaud Pouliquen 	/*
1384e2e6771cSArnaud Pouliquen 	 * IIO_CHAN_INFO_RAW: used to compute regular conversion
1385e2e6771cSArnaud Pouliquen 	 * IIO_CHAN_INFO_OVERSAMPLING_RATIO: used to set oversampling
1386e2e6771cSArnaud Pouliquen 	 */
1387e2e6771cSArnaud Pouliquen 	ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
138811646e81SFabrice Gasnier 	ch->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
138911646e81SFabrice Gasnier 					BIT(IIO_CHAN_INFO_SAMP_FREQ);
1390e2e6771cSArnaud Pouliquen 
1391eca94980SArnaud Pouliquen 	if (adc->dev_data->type == DFSDM_AUDIO) {
1392eca94980SArnaud Pouliquen 		ch->ext_info = dfsdm_adc_audio_ext_info;
1393eca94980SArnaud Pouliquen 	} else {
1394c6013bf5SOlivier Moysan 		ch->scan_type.shift = 8;
1395eca94980SArnaud Pouliquen 	}
1396c6013bf5SOlivier Moysan 	ch->scan_type.sign = 's';
1397e2e6771cSArnaud Pouliquen 	ch->scan_type.realbits = 24;
1398e2e6771cSArnaud Pouliquen 	ch->scan_type.storagebits = 32;
1399e2e6771cSArnaud Pouliquen 
1400e2e6771cSArnaud Pouliquen 	return stm32_dfsdm_chan_configure(adc->dfsdm,
1401e2e6771cSArnaud Pouliquen 					  &adc->dfsdm->ch_list[ch->channel]);
1402e2e6771cSArnaud Pouliquen }
1403e2e6771cSArnaud Pouliquen 
stm32_dfsdm_audio_init(struct device * dev,struct iio_dev * indio_dev)1404b455d06eSFabrice Gasnier static int stm32_dfsdm_audio_init(struct device *dev, struct iio_dev *indio_dev)
1405eca94980SArnaud Pouliquen {
1406eca94980SArnaud Pouliquen 	struct iio_chan_spec *ch;
1407eca94980SArnaud Pouliquen 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
1408eca94980SArnaud Pouliquen 	struct stm32_dfsdm_channel *d_ch;
1409eca94980SArnaud Pouliquen 	int ret;
1410eca94980SArnaud Pouliquen 
1411eca94980SArnaud Pouliquen 	ch = devm_kzalloc(&indio_dev->dev, sizeof(*ch), GFP_KERNEL);
1412eca94980SArnaud Pouliquen 	if (!ch)
1413eca94980SArnaud Pouliquen 		return -ENOMEM;
1414eca94980SArnaud Pouliquen 
1415eca94980SArnaud Pouliquen 	ch->scan_index = 0;
1416eca94980SArnaud Pouliquen 
1417eca94980SArnaud Pouliquen 	ret = stm32_dfsdm_adc_chan_init_one(indio_dev, ch);
1418eca94980SArnaud Pouliquen 	if (ret < 0) {
1419eca94980SArnaud Pouliquen 		dev_err(&indio_dev->dev, "Channels init failed\n");
1420eca94980SArnaud Pouliquen 		return ret;
1421eca94980SArnaud Pouliquen 	}
1422eca94980SArnaud Pouliquen 	ch->info_mask_separate = BIT(IIO_CHAN_INFO_SAMP_FREQ);
1423eca94980SArnaud Pouliquen 
14240645af1bSFabrice Gasnier 	d_ch = &adc->dfsdm->ch_list[ch->channel];
1425eca94980SArnaud Pouliquen 	if (d_ch->src != DFSDM_CHANNEL_SPI_CLOCK_EXTERNAL)
1426eca94980SArnaud Pouliquen 		adc->spi_freq = adc->dfsdm->spi_master_freq;
1427eca94980SArnaud Pouliquen 
1428eca94980SArnaud Pouliquen 	indio_dev->num_channels = 1;
1429eca94980SArnaud Pouliquen 	indio_dev->channels = ch;
1430eca94980SArnaud Pouliquen 
1431b455d06eSFabrice Gasnier 	return stm32_dfsdm_dma_request(dev, indio_dev);
1432eca94980SArnaud Pouliquen }
1433eca94980SArnaud Pouliquen 
stm32_dfsdm_adc_init(struct device * dev,struct iio_dev * indio_dev)1434b455d06eSFabrice Gasnier static int stm32_dfsdm_adc_init(struct device *dev, struct iio_dev *indio_dev)
1435e2e6771cSArnaud Pouliquen {
1436e2e6771cSArnaud Pouliquen 	struct iio_chan_spec *ch;
1437e2e6771cSArnaud Pouliquen 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
1438e2e6771cSArnaud Pouliquen 	int num_ch;
1439e2e6771cSArnaud Pouliquen 	int ret, chan_idx;
1440e2e6771cSArnaud Pouliquen 
1441e2e6771cSArnaud Pouliquen 	adc->oversamp = DFSDM_DEFAULT_OVERSAMPLING;
1442d716204fSOlivier Moysan 	ret = stm32_dfsdm_compute_all_osrs(indio_dev, adc->oversamp);
1443e2e6771cSArnaud Pouliquen 	if (ret < 0)
1444e2e6771cSArnaud Pouliquen 		return ret;
1445e2e6771cSArnaud Pouliquen 
1446e2e6771cSArnaud Pouliquen 	num_ch = of_property_count_u32_elems(indio_dev->dev.of_node,
1447e2e6771cSArnaud Pouliquen 					     "st,adc-channels");
1448e2e6771cSArnaud Pouliquen 	if (num_ch < 0 || num_ch > adc->dfsdm->num_chs) {
1449e2e6771cSArnaud Pouliquen 		dev_err(&indio_dev->dev, "Bad st,adc-channels\n");
1450e2e6771cSArnaud Pouliquen 		return num_ch < 0 ? num_ch : -EINVAL;
1451e2e6771cSArnaud Pouliquen 	}
1452e2e6771cSArnaud Pouliquen 
1453e2e6771cSArnaud Pouliquen 	/* Bind to SD modulator IIO device */
1454e2e6771cSArnaud Pouliquen 	adc->hwc = devm_iio_hw_consumer_alloc(&indio_dev->dev);
1455e2e6771cSArnaud Pouliquen 	if (IS_ERR(adc->hwc))
1456e2e6771cSArnaud Pouliquen 		return -EPROBE_DEFER;
1457e2e6771cSArnaud Pouliquen 
1458e2e6771cSArnaud Pouliquen 	ch = devm_kcalloc(&indio_dev->dev, num_ch, sizeof(*ch),
1459e2e6771cSArnaud Pouliquen 			  GFP_KERNEL);
1460e2e6771cSArnaud Pouliquen 	if (!ch)
1461e2e6771cSArnaud Pouliquen 		return -ENOMEM;
1462e2e6771cSArnaud Pouliquen 
1463e2e6771cSArnaud Pouliquen 	for (chan_idx = 0; chan_idx < num_ch; chan_idx++) {
14640645af1bSFabrice Gasnier 		ch[chan_idx].scan_index = chan_idx;
14650645af1bSFabrice Gasnier 		ret = stm32_dfsdm_adc_chan_init_one(indio_dev, &ch[chan_idx]);
1466e2e6771cSArnaud Pouliquen 		if (ret < 0) {
1467e2e6771cSArnaud Pouliquen 			dev_err(&indio_dev->dev, "Channels init failed\n");
1468e2e6771cSArnaud Pouliquen 			return ret;
1469e2e6771cSArnaud Pouliquen 		}
1470e2e6771cSArnaud Pouliquen 	}
1471e2e6771cSArnaud Pouliquen 
1472e2e6771cSArnaud Pouliquen 	indio_dev->num_channels = num_ch;
1473e2e6771cSArnaud Pouliquen 	indio_dev->channels = ch;
1474e2e6771cSArnaud Pouliquen 
1475e2e6771cSArnaud Pouliquen 	init_completion(&adc->completion);
1476e2e6771cSArnaud Pouliquen 
147711646e81SFabrice Gasnier 	/* Optionally request DMA */
1478b455d06eSFabrice Gasnier 	ret = stm32_dfsdm_dma_request(dev, indio_dev);
1479a9ab624eSPeter Ujfalusi 	if (ret) {
1480ce30eeb6SKrzysztof Kozlowski 		if (ret != -ENODEV)
1481ce30eeb6SKrzysztof Kozlowski 			return dev_err_probe(dev, ret,
1482ce30eeb6SKrzysztof Kozlowski 					     "DMA channel request failed with\n");
1483a9ab624eSPeter Ujfalusi 
1484b455d06eSFabrice Gasnier 		dev_dbg(dev, "No DMA support\n");
148511646e81SFabrice Gasnier 		return 0;
148611646e81SFabrice Gasnier 	}
148711646e81SFabrice Gasnier 
148811646e81SFabrice Gasnier 	ret = iio_triggered_buffer_setup(indio_dev,
1489e19ac9d9SOlivier Moysan 					 &iio_pollfunc_store_time, NULL,
149011646e81SFabrice Gasnier 					 &stm32_dfsdm_buffer_setup_ops);
149111646e81SFabrice Gasnier 	if (ret) {
149211646e81SFabrice Gasnier 		stm32_dfsdm_dma_release(indio_dev);
149311646e81SFabrice Gasnier 		dev_err(&indio_dev->dev, "buffer setup failed\n");
149411646e81SFabrice Gasnier 		return ret;
149511646e81SFabrice Gasnier 	}
149611646e81SFabrice Gasnier 
149711646e81SFabrice Gasnier 	/* lptimer/timer hardware triggers */
149811646e81SFabrice Gasnier 	indio_dev->modes |= INDIO_HARDWARE_TRIGGERED;
149911646e81SFabrice Gasnier 
1500e2e6771cSArnaud Pouliquen 	return 0;
1501e2e6771cSArnaud Pouliquen }
1502e2e6771cSArnaud Pouliquen 
1503e2e6771cSArnaud Pouliquen static const struct stm32_dfsdm_dev_data stm32h7_dfsdm_adc_data = {
1504e2e6771cSArnaud Pouliquen 	.type = DFSDM_IIO,
1505e2e6771cSArnaud Pouliquen 	.init = stm32_dfsdm_adc_init,
1506e2e6771cSArnaud Pouliquen };
1507e2e6771cSArnaud Pouliquen 
1508eca94980SArnaud Pouliquen static const struct stm32_dfsdm_dev_data stm32h7_dfsdm_audio_data = {
1509eca94980SArnaud Pouliquen 	.type = DFSDM_AUDIO,
1510eca94980SArnaud Pouliquen 	.init = stm32_dfsdm_audio_init,
1511eca94980SArnaud Pouliquen };
1512eca94980SArnaud Pouliquen 
1513e2e6771cSArnaud Pouliquen static const struct of_device_id stm32_dfsdm_adc_match[] = {
1514e2e6771cSArnaud Pouliquen 	{
1515e2e6771cSArnaud Pouliquen 		.compatible = "st,stm32-dfsdm-adc",
1516e2e6771cSArnaud Pouliquen 		.data = &stm32h7_dfsdm_adc_data,
1517e2e6771cSArnaud Pouliquen 	},
1518eca94980SArnaud Pouliquen 	{
1519eca94980SArnaud Pouliquen 		.compatible = "st,stm32-dfsdm-dmic",
1520eca94980SArnaud Pouliquen 		.data = &stm32h7_dfsdm_audio_data,
1521eca94980SArnaud Pouliquen 	},
1522e2e6771cSArnaud Pouliquen 	{}
1523e2e6771cSArnaud Pouliquen };
1524cc330405SOlivier Moysan MODULE_DEVICE_TABLE(of, stm32_dfsdm_adc_match);
1525e2e6771cSArnaud Pouliquen 
stm32_dfsdm_adc_probe(struct platform_device * pdev)1526e2e6771cSArnaud Pouliquen static int stm32_dfsdm_adc_probe(struct platform_device *pdev)
1527e2e6771cSArnaud Pouliquen {
1528e2e6771cSArnaud Pouliquen 	struct device *dev = &pdev->dev;
1529e2e6771cSArnaud Pouliquen 	struct stm32_dfsdm_adc *adc;
1530e2e6771cSArnaud Pouliquen 	struct device_node *np = dev->of_node;
1531e2e6771cSArnaud Pouliquen 	const struct stm32_dfsdm_dev_data *dev_data;
1532e2e6771cSArnaud Pouliquen 	struct iio_dev *iio;
1533e2e6771cSArnaud Pouliquen 	char *name;
1534e2e6771cSArnaud Pouliquen 	int ret, irq, val;
1535e2e6771cSArnaud Pouliquen 
1536abaca806SArnaud Pouliquen 	dev_data = of_device_get_match_data(dev);
1537e2e6771cSArnaud Pouliquen 	iio = devm_iio_device_alloc(dev, sizeof(*adc));
1538d5ff18bcSWei Yongjun 	if (!iio) {
1539e2e6771cSArnaud Pouliquen 		dev_err(dev, "%s: Failed to allocate IIO\n", __func__);
1540d5ff18bcSWei Yongjun 		return -ENOMEM;
1541e2e6771cSArnaud Pouliquen 	}
1542e2e6771cSArnaud Pouliquen 
1543e2e6771cSArnaud Pouliquen 	adc = iio_priv(iio);
1544e2e6771cSArnaud Pouliquen 	adc->dfsdm = dev_get_drvdata(dev->parent);
1545e2e6771cSArnaud Pouliquen 
1546e2e6771cSArnaud Pouliquen 	iio->dev.of_node = np;
154711646e81SFabrice Gasnier 	iio->modes = INDIO_DIRECT_MODE;
1548e2e6771cSArnaud Pouliquen 
154907b6c9dcSAlexandru Ardelean 	platform_set_drvdata(pdev, iio);
1550e2e6771cSArnaud Pouliquen 
1551e2e6771cSArnaud Pouliquen 	ret = of_property_read_u32(dev->of_node, "reg", &adc->fl_id);
1552dfa105b1SFabrice Gasnier 	if (ret != 0 || adc->fl_id >= adc->dfsdm->num_fls) {
1553dfa105b1SFabrice Gasnier 		dev_err(dev, "Missing or bad reg property\n");
1554e2e6771cSArnaud Pouliquen 		return -EINVAL;
1555e2e6771cSArnaud Pouliquen 	}
1556e2e6771cSArnaud Pouliquen 
1557e2e6771cSArnaud Pouliquen 	name = devm_kzalloc(dev, sizeof("dfsdm-adc0"), GFP_KERNEL);
1558e2e6771cSArnaud Pouliquen 	if (!name)
1559e2e6771cSArnaud Pouliquen 		return -ENOMEM;
1560eca94980SArnaud Pouliquen 	if (dev_data->type == DFSDM_AUDIO) {
1561eca94980SArnaud Pouliquen 		iio->info = &stm32_dfsdm_info_audio;
1562eca94980SArnaud Pouliquen 		snprintf(name, sizeof("dfsdm-pdm0"), "dfsdm-pdm%d", adc->fl_id);
1563eca94980SArnaud Pouliquen 	} else {
1564e2e6771cSArnaud Pouliquen 		iio->info = &stm32_dfsdm_info_adc;
1565e2e6771cSArnaud Pouliquen 		snprintf(name, sizeof("dfsdm-adc0"), "dfsdm-adc%d", adc->fl_id);
1566eca94980SArnaud Pouliquen 	}
1567e2e6771cSArnaud Pouliquen 	iio->name = name;
1568e2e6771cSArnaud Pouliquen 
1569e2e6771cSArnaud Pouliquen 	/*
1570e2e6771cSArnaud Pouliquen 	 * In a first step IRQs generated for channels are not treated.
1571e2e6771cSArnaud Pouliquen 	 * So IRQ associated to filter instance 0 is dedicated to the Filter 0.
1572e2e6771cSArnaud Pouliquen 	 */
1573e2e6771cSArnaud Pouliquen 	irq = platform_get_irq(pdev, 0);
15747c279229SStephen Boyd 	if (irq < 0)
15753e53ef91SFabien Dessenne 		return irq;
15763e53ef91SFabien Dessenne 
1577e2e6771cSArnaud Pouliquen 	ret = devm_request_irq(dev, irq, stm32_dfsdm_irq,
157807b6c9dcSAlexandru Ardelean 			       0, pdev->name, iio);
1579e2e6771cSArnaud Pouliquen 	if (ret < 0) {
1580e2e6771cSArnaud Pouliquen 		dev_err(dev, "Failed to request IRQ\n");
1581e2e6771cSArnaud Pouliquen 		return ret;
1582e2e6771cSArnaud Pouliquen 	}
1583e2e6771cSArnaud Pouliquen 
1584e2e6771cSArnaud Pouliquen 	ret = of_property_read_u32(dev->of_node, "st,filter-order", &val);
1585e2e6771cSArnaud Pouliquen 	if (ret < 0) {
1586e2e6771cSArnaud Pouliquen 		dev_err(dev, "Failed to set filter order\n");
1587e2e6771cSArnaud Pouliquen 		return ret;
1588e2e6771cSArnaud Pouliquen 	}
1589e2e6771cSArnaud Pouliquen 
1590e2e6771cSArnaud Pouliquen 	adc->dfsdm->fl_list[adc->fl_id].ford = val;
1591e2e6771cSArnaud Pouliquen 
1592e2e6771cSArnaud Pouliquen 	ret = of_property_read_u32(dev->of_node, "st,filter0-sync", &val);
1593e2e6771cSArnaud Pouliquen 	if (!ret)
1594e2e6771cSArnaud Pouliquen 		adc->dfsdm->fl_list[adc->fl_id].sync_mode = val;
1595e2e6771cSArnaud Pouliquen 
1596e2e6771cSArnaud Pouliquen 	adc->dev_data = dev_data;
1597b455d06eSFabrice Gasnier 	ret = dev_data->init(dev, iio);
1598e2e6771cSArnaud Pouliquen 	if (ret < 0)
1599e2e6771cSArnaud Pouliquen 		return ret;
1600e2e6771cSArnaud Pouliquen 
1601eca94980SArnaud Pouliquen 	ret = iio_device_register(iio);
1602eca94980SArnaud Pouliquen 	if (ret < 0)
1603eca94980SArnaud Pouliquen 		goto err_cleanup;
1604eca94980SArnaud Pouliquen 
1605eca94980SArnaud Pouliquen 	if (dev_data->type == DFSDM_AUDIO) {
1606eca94980SArnaud Pouliquen 		ret = of_platform_populate(np, NULL, NULL, dev);
1607eca94980SArnaud Pouliquen 		if (ret < 0) {
1608eca94980SArnaud Pouliquen 			dev_err(dev, "Failed to find an audio DAI\n");
1609eca94980SArnaud Pouliquen 			goto err_unregister;
1610eca94980SArnaud Pouliquen 		}
1611eca94980SArnaud Pouliquen 	}
1612eca94980SArnaud Pouliquen 
1613eca94980SArnaud Pouliquen 	return 0;
1614eca94980SArnaud Pouliquen 
1615eca94980SArnaud Pouliquen err_unregister:
1616eca94980SArnaud Pouliquen 	iio_device_unregister(iio);
1617eca94980SArnaud Pouliquen err_cleanup:
1618eca94980SArnaud Pouliquen 	stm32_dfsdm_dma_release(iio);
1619eca94980SArnaud Pouliquen 
1620eca94980SArnaud Pouliquen 	return ret;
1621e2e6771cSArnaud Pouliquen }
1622e2e6771cSArnaud Pouliquen 
stm32_dfsdm_adc_remove(struct platform_device * pdev)1623e2e6771cSArnaud Pouliquen static int stm32_dfsdm_adc_remove(struct platform_device *pdev)
1624e2e6771cSArnaud Pouliquen {
162507b6c9dcSAlexandru Ardelean 	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
162607b6c9dcSAlexandru Ardelean 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
1627e2e6771cSArnaud Pouliquen 
1628eca94980SArnaud Pouliquen 	if (adc->dev_data->type == DFSDM_AUDIO)
1629eca94980SArnaud Pouliquen 		of_platform_depopulate(&pdev->dev);
1630e2e6771cSArnaud Pouliquen 	iio_device_unregister(indio_dev);
1631eca94980SArnaud Pouliquen 	stm32_dfsdm_dma_release(indio_dev);
1632e2e6771cSArnaud Pouliquen 
1633e2e6771cSArnaud Pouliquen 	return 0;
1634e2e6771cSArnaud Pouliquen }
1635e2e6771cSArnaud Pouliquen 
stm32_dfsdm_adc_suspend(struct device * dev)1636ade59a7aSJonathan Cameron static int stm32_dfsdm_adc_suspend(struct device *dev)
16376ec417d2SFabrice Gasnier {
163807b6c9dcSAlexandru Ardelean 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
16396ec417d2SFabrice Gasnier 
16406ec417d2SFabrice Gasnier 	if (iio_buffer_enabled(indio_dev))
1641f11d59d8SLars-Peter Clausen 		stm32_dfsdm_predisable(indio_dev);
16426ec417d2SFabrice Gasnier 
16436ec417d2SFabrice Gasnier 	return 0;
16446ec417d2SFabrice Gasnier }
16456ec417d2SFabrice Gasnier 
stm32_dfsdm_adc_resume(struct device * dev)1646ade59a7aSJonathan Cameron static int stm32_dfsdm_adc_resume(struct device *dev)
16476ec417d2SFabrice Gasnier {
164807b6c9dcSAlexandru Ardelean 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
164907b6c9dcSAlexandru Ardelean 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
16506ec417d2SFabrice Gasnier 	const struct iio_chan_spec *chan;
16516ec417d2SFabrice Gasnier 	struct stm32_dfsdm_channel *ch;
16526ec417d2SFabrice Gasnier 	int i, ret;
16536ec417d2SFabrice Gasnier 
16546ec417d2SFabrice Gasnier 	/* restore channels configuration */
16556ec417d2SFabrice Gasnier 	for (i = 0; i < indio_dev->num_channels; i++) {
16566ec417d2SFabrice Gasnier 		chan = indio_dev->channels + i;
16576ec417d2SFabrice Gasnier 		ch = &adc->dfsdm->ch_list[chan->channel];
16586ec417d2SFabrice Gasnier 		ret = stm32_dfsdm_chan_configure(adc->dfsdm, ch);
16596ec417d2SFabrice Gasnier 		if (ret)
16606ec417d2SFabrice Gasnier 			return ret;
16616ec417d2SFabrice Gasnier 	}
16626ec417d2SFabrice Gasnier 
16636ec417d2SFabrice Gasnier 	if (iio_buffer_enabled(indio_dev))
1664f11d59d8SLars-Peter Clausen 		stm32_dfsdm_postenable(indio_dev);
16656ec417d2SFabrice Gasnier 
16666ec417d2SFabrice Gasnier 	return 0;
16676ec417d2SFabrice Gasnier }
16686ec417d2SFabrice Gasnier 
1669ade59a7aSJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(stm32_dfsdm_adc_pm_ops,
1670ade59a7aSJonathan Cameron 				stm32_dfsdm_adc_suspend,
1671ade59a7aSJonathan Cameron 				stm32_dfsdm_adc_resume);
16726ec417d2SFabrice Gasnier 
1673e2e6771cSArnaud Pouliquen static struct platform_driver stm32_dfsdm_adc_driver = {
1674e2e6771cSArnaud Pouliquen 	.driver = {
1675e2e6771cSArnaud Pouliquen 		.name = "stm32-dfsdm-adc",
1676e2e6771cSArnaud Pouliquen 		.of_match_table = stm32_dfsdm_adc_match,
1677ade59a7aSJonathan Cameron 		.pm = pm_sleep_ptr(&stm32_dfsdm_adc_pm_ops),
1678e2e6771cSArnaud Pouliquen 	},
1679e2e6771cSArnaud Pouliquen 	.probe = stm32_dfsdm_adc_probe,
1680e2e6771cSArnaud Pouliquen 	.remove = stm32_dfsdm_adc_remove,
1681e2e6771cSArnaud Pouliquen };
1682e2e6771cSArnaud Pouliquen module_platform_driver(stm32_dfsdm_adc_driver);
1683e2e6771cSArnaud Pouliquen 
1684e2e6771cSArnaud Pouliquen MODULE_DESCRIPTION("STM32 sigma delta ADC");
1685e2e6771cSArnaud Pouliquen MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>");
1686e2e6771cSArnaud Pouliquen MODULE_LICENSE("GPL v2");
1687