1 // SPDX-License-Identifier: GPL-2.0
3 * This file is part of STM32 DFSDM ASoC DAI driver
5 * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
6 * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
7 * Olivier Moysan <olivier.moysan@st.com>
10 #include <linux/clk.h>
11 #include <linux/module.h>
12 #include <linux/mutex.h>
13 #include <linux/platform_device.h>
14 #include <linux/slab.h>
16 #include <linux/iio/iio.h>
17 #include <linux/iio/consumer.h>
18 #include <linux/iio/adc/stm32-dfsdm-adc.h>
20 #include <sound/pcm.h>
21 #include <sound/soc.h>
23 #define STM32_ADFSDM_DRV_NAME "stm32-adfsdm"
25 #define DFSDM_MAX_PERIOD_SIZE (PAGE_SIZE / 2)
26 #define DFSDM_MAX_PERIODS 6
28 struct stm32_adfsdm_priv
{
29 struct snd_soc_dai_driver dai_drv
;
30 struct snd_pcm_substream
*substream
;
34 struct iio_channel
*iio_ch
;
35 struct iio_cb_buffer
*iio_cb
;
39 unsigned char *pcm_buff
;
42 struct mutex lock
; /* protect against race condition on iio state */
45 static const struct snd_pcm_hardware stm32_adfsdm_pcm_hw
= {
46 .info
= SNDRV_PCM_INFO_INTERLEAVED
| SNDRV_PCM_INFO_BLOCK_TRANSFER
|
48 .formats
= SNDRV_PCM_FMTBIT_S32_LE
,
57 .periods_max
= DFSDM_MAX_PERIODS
,
59 .period_bytes_max
= DFSDM_MAX_PERIOD_SIZE
,
60 .buffer_bytes_max
= DFSDM_MAX_PERIODS
* DFSDM_MAX_PERIOD_SIZE
63 static void stm32_adfsdm_shutdown(struct snd_pcm_substream
*substream
,
64 struct snd_soc_dai
*dai
)
66 struct stm32_adfsdm_priv
*priv
= snd_soc_dai_get_drvdata(dai
);
68 mutex_lock(&priv
->lock
);
69 if (priv
->iio_active
) {
70 iio_channel_stop_all_cb(priv
->iio_cb
);
71 priv
->iio_active
= false;
73 mutex_unlock(&priv
->lock
);
76 static int stm32_adfsdm_dai_prepare(struct snd_pcm_substream
*substream
,
77 struct snd_soc_dai
*dai
)
79 struct stm32_adfsdm_priv
*priv
= snd_soc_dai_get_drvdata(dai
);
82 mutex_lock(&priv
->lock
);
83 if (priv
->iio_active
) {
84 iio_channel_stop_all_cb(priv
->iio_cb
);
85 priv
->iio_active
= false;
88 ret
= iio_write_channel_attribute(priv
->iio_ch
,
89 substream
->runtime
->rate
, 0,
90 IIO_CHAN_INFO_SAMP_FREQ
);
92 dev_err(dai
->dev
, "%s: Failed to set %d sampling rate\n",
93 __func__
, substream
->runtime
->rate
);
97 if (!priv
->iio_active
) {
98 ret
= iio_channel_start_all_cb(priv
->iio_cb
);
100 priv
->iio_active
= true;
102 dev_err(dai
->dev
, "%s: IIO channel start failed (%d)\n",
107 mutex_unlock(&priv
->lock
);
112 static int stm32_adfsdm_set_sysclk(struct snd_soc_dai
*dai
, int clk_id
,
113 unsigned int freq
, int dir
)
115 struct stm32_adfsdm_priv
*priv
= snd_soc_dai_get_drvdata(dai
);
119 dev_dbg(dai
->dev
, "%s: Enter for freq %d\n", __func__
, freq
);
121 /* Set IIO frequency if CODEC is master as clock comes from SPI_IN */
123 snprintf(str_freq
, sizeof(str_freq
), "%d\n", freq
);
124 size
= iio_write_channel_ext_info(priv
->iio_ch
, "spi_clk_freq",
125 str_freq
, sizeof(str_freq
));
126 if (size
!= sizeof(str_freq
)) {
127 dev_err(dai
->dev
, "%s: Failed to set SPI clock\n",
134 static const struct snd_soc_dai_ops stm32_adfsdm_dai_ops
= {
135 .shutdown
= stm32_adfsdm_shutdown
,
136 .prepare
= stm32_adfsdm_dai_prepare
,
137 .set_sysclk
= stm32_adfsdm_set_sysclk
,
140 static const struct snd_soc_dai_driver stm32_adfsdm_dai
= {
144 .formats
= SNDRV_PCM_FMTBIT_S32_LE
,
145 .rates
= (SNDRV_PCM_RATE_8000
| SNDRV_PCM_RATE_16000
|
146 SNDRV_PCM_RATE_32000
),
148 .ops
= &stm32_adfsdm_dai_ops
,
151 static const struct snd_soc_component_driver stm32_adfsdm_dai_component
= {
152 .name
= "stm32_dfsdm_audio",
155 static int stm32_afsdm_pcm_cb(const void *data
, size_t size
, void *private)
157 struct stm32_adfsdm_priv
*priv
= private;
158 struct snd_soc_pcm_runtime
*rtd
= priv
->substream
->private_data
;
159 u8
*pcm_buff
= priv
->pcm_buff
;
160 u8
*src_buff
= (u8
*)data
;
161 unsigned int buff_size
= snd_pcm_lib_buffer_bytes(priv
->substream
);
162 unsigned int period_size
= snd_pcm_lib_period_bytes(priv
->substream
);
163 unsigned int old_pos
= priv
->pos
;
164 unsigned int cur_size
= size
;
166 dev_dbg(rtd
->dev
, "%s: buff_add :%pK, pos = %d, size = %zu\n",
167 __func__
, &pcm_buff
[priv
->pos
], priv
->pos
, size
);
169 if ((priv
->pos
+ size
) > buff_size
) {
170 memcpy(&pcm_buff
[priv
->pos
], src_buff
, buff_size
- priv
->pos
);
171 cur_size
-= buff_size
- priv
->pos
;
175 memcpy(&pcm_buff
[priv
->pos
], &src_buff
[size
- cur_size
], cur_size
);
176 priv
->pos
= (priv
->pos
+ cur_size
) % buff_size
;
178 if (cur_size
!= size
|| (old_pos
&& (old_pos
% period_size
< size
)))
179 snd_pcm_period_elapsed(priv
->substream
);
184 static int stm32_adfsdm_trigger(struct snd_pcm_substream
*substream
, int cmd
)
186 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
187 struct stm32_adfsdm_priv
*priv
=
188 snd_soc_dai_get_drvdata(rtd
->cpu_dai
);
191 case SNDRV_PCM_TRIGGER_START
:
192 case SNDRV_PCM_TRIGGER_RESUME
:
194 return stm32_dfsdm_get_buff_cb(priv
->iio_ch
->indio_dev
,
195 stm32_afsdm_pcm_cb
, priv
);
196 case SNDRV_PCM_TRIGGER_SUSPEND
:
197 case SNDRV_PCM_TRIGGER_STOP
:
198 return stm32_dfsdm_release_buff_cb(priv
->iio_ch
->indio_dev
);
204 static int stm32_adfsdm_pcm_open(struct snd_pcm_substream
*substream
)
206 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
207 struct stm32_adfsdm_priv
*priv
= snd_soc_dai_get_drvdata(rtd
->cpu_dai
);
210 ret
= snd_soc_set_runtime_hwparams(substream
, &stm32_adfsdm_pcm_hw
);
212 priv
->substream
= substream
;
217 static int stm32_adfsdm_pcm_close(struct snd_pcm_substream
*substream
)
219 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
220 struct stm32_adfsdm_priv
*priv
=
221 snd_soc_dai_get_drvdata(rtd
->cpu_dai
);
223 snd_pcm_lib_free_pages(substream
);
224 priv
->substream
= NULL
;
229 static snd_pcm_uframes_t
stm32_adfsdm_pcm_pointer(
230 struct snd_pcm_substream
*substream
)
232 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
233 struct stm32_adfsdm_priv
*priv
=
234 snd_soc_dai_get_drvdata(rtd
->cpu_dai
);
236 return bytes_to_frames(substream
->runtime
, priv
->pos
);
239 static int stm32_adfsdm_pcm_hw_params(struct snd_pcm_substream
*substream
,
240 struct snd_pcm_hw_params
*params
)
242 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
243 struct stm32_adfsdm_priv
*priv
=
244 snd_soc_dai_get_drvdata(rtd
->cpu_dai
);
247 ret
= snd_pcm_lib_malloc_pages(substream
, params_buffer_bytes(params
));
250 priv
->pcm_buff
= substream
->runtime
->dma_area
;
252 return iio_channel_cb_set_buffer_watermark(priv
->iio_cb
,
253 params_period_size(params
));
256 static int stm32_adfsdm_pcm_hw_free(struct snd_pcm_substream
*substream
)
258 snd_pcm_lib_free_pages(substream
);
263 static struct snd_pcm_ops stm32_adfsdm_pcm_ops
= {
264 .open
= stm32_adfsdm_pcm_open
,
265 .close
= stm32_adfsdm_pcm_close
,
266 .hw_params
= stm32_adfsdm_pcm_hw_params
,
267 .hw_free
= stm32_adfsdm_pcm_hw_free
,
268 .trigger
= stm32_adfsdm_trigger
,
269 .pointer
= stm32_adfsdm_pcm_pointer
,
272 static int stm32_adfsdm_pcm_new(struct snd_soc_pcm_runtime
*rtd
)
274 struct snd_pcm
*pcm
= rtd
->pcm
;
275 struct stm32_adfsdm_priv
*priv
=
276 snd_soc_dai_get_drvdata(rtd
->cpu_dai
);
277 unsigned int size
= DFSDM_MAX_PERIODS
* DFSDM_MAX_PERIOD_SIZE
;
279 snd_pcm_lib_preallocate_pages_for_all(pcm
, SNDRV_DMA_TYPE_DEV
,
280 priv
->dev
, size
, size
);
284 static void stm32_adfsdm_pcm_free(struct snd_pcm
*pcm
)
286 struct snd_pcm_substream
*substream
;
288 substream
= pcm
->streams
[SNDRV_PCM_STREAM_CAPTURE
].substream
;
290 snd_pcm_lib_preallocate_free_for_all(pcm
);
293 static struct snd_soc_component_driver stm32_adfsdm_soc_platform
= {
294 .ops
= &stm32_adfsdm_pcm_ops
,
295 .pcm_new
= stm32_adfsdm_pcm_new
,
296 .pcm_free
= stm32_adfsdm_pcm_free
,
299 static const struct of_device_id stm32_adfsdm_of_match
[] = {
300 {.compatible
= "st,stm32h7-dfsdm-dai"},
303 MODULE_DEVICE_TABLE(of
, stm32_adfsdm_of_match
);
305 static int stm32_adfsdm_probe(struct platform_device
*pdev
)
307 struct stm32_adfsdm_priv
*priv
;
308 struct snd_soc_component
*component
;
311 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
315 priv
->dev
= &pdev
->dev
;
316 priv
->dai_drv
= stm32_adfsdm_dai
;
317 mutex_init(&priv
->lock
);
319 dev_set_drvdata(&pdev
->dev
, priv
);
321 ret
= devm_snd_soc_register_component(&pdev
->dev
,
322 &stm32_adfsdm_dai_component
,
327 /* Associate iio channel */
328 priv
->iio_ch
= devm_iio_channel_get_all(&pdev
->dev
);
329 if (IS_ERR(priv
->iio_ch
))
330 return PTR_ERR(priv
->iio_ch
);
332 priv
->iio_cb
= iio_channel_get_all_cb(&pdev
->dev
, NULL
, NULL
);
333 if (IS_ERR(priv
->iio_cb
))
334 return PTR_ERR(priv
->iio_cb
);
336 component
= devm_kzalloc(&pdev
->dev
, sizeof(*component
), GFP_KERNEL
);
339 #ifdef CONFIG_DEBUG_FS
340 component
->debugfs_prefix
= "pcm";
343 ret
= snd_soc_add_component(&pdev
->dev
, component
,
344 &stm32_adfsdm_soc_platform
, NULL
, 0);
346 dev_err(&pdev
->dev
, "%s: Failed to register PCM platform\n",
352 static int stm32_adfsdm_remove(struct platform_device
*pdev
)
354 snd_soc_unregister_component(&pdev
->dev
);
359 static struct platform_driver stm32_adfsdm_driver
= {
361 .name
= STM32_ADFSDM_DRV_NAME
,
362 .of_match_table
= stm32_adfsdm_of_match
,
364 .probe
= stm32_adfsdm_probe
,
365 .remove
= stm32_adfsdm_remove
,
368 module_platform_driver(stm32_adfsdm_driver
);
370 MODULE_DESCRIPTION("stm32 DFSDM DAI driver");
371 MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>");
372 MODULE_LICENSE("GPL v2");
373 MODULE_ALIAS("platform:" STM32_ADFSDM_DRV_NAME
);