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>
15 #include <linux/pm_runtime.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
|
47 SNDRV_PCM_INFO_MMAP
| SNDRV_PCM_INFO_PAUSE
,
48 .formats
= SNDRV_PCM_FMTBIT_S16_LE
| SNDRV_PCM_FMTBIT_S32_LE
,
54 .periods_max
= DFSDM_MAX_PERIODS
,
56 .period_bytes_max
= DFSDM_MAX_PERIOD_SIZE
,
57 .buffer_bytes_max
= DFSDM_MAX_PERIODS
* DFSDM_MAX_PERIOD_SIZE
60 static void stm32_adfsdm_shutdown(struct snd_pcm_substream
*substream
,
61 struct snd_soc_dai
*dai
)
63 struct stm32_adfsdm_priv
*priv
= snd_soc_dai_get_drvdata(dai
);
65 mutex_lock(&priv
->lock
);
66 if (priv
->iio_active
) {
67 iio_channel_stop_all_cb(priv
->iio_cb
);
68 priv
->iio_active
= false;
70 mutex_unlock(&priv
->lock
);
73 static int stm32_adfsdm_dai_prepare(struct snd_pcm_substream
*substream
,
74 struct snd_soc_dai
*dai
)
76 struct stm32_adfsdm_priv
*priv
= snd_soc_dai_get_drvdata(dai
);
79 mutex_lock(&priv
->lock
);
80 if (priv
->iio_active
) {
81 iio_channel_stop_all_cb(priv
->iio_cb
);
82 priv
->iio_active
= false;
85 ret
= iio_write_channel_attribute(priv
->iio_ch
,
86 substream
->runtime
->rate
, 0,
87 IIO_CHAN_INFO_SAMP_FREQ
);
89 dev_err(dai
->dev
, "%s: Failed to set %d sampling rate\n",
90 __func__
, substream
->runtime
->rate
);
94 if (!priv
->iio_active
) {
95 ret
= iio_channel_start_all_cb(priv
->iio_cb
);
97 priv
->iio_active
= true;
99 dev_err(dai
->dev
, "%s: IIO channel start failed (%d)\n",
104 mutex_unlock(&priv
->lock
);
109 static int stm32_adfsdm_set_sysclk(struct snd_soc_dai
*dai
, int clk_id
,
110 unsigned int freq
, int dir
)
112 struct stm32_adfsdm_priv
*priv
= snd_soc_dai_get_drvdata(dai
);
116 dev_dbg(dai
->dev
, "%s: Enter for freq %d\n", __func__
, freq
);
118 /* Set IIO frequency if CODEC is master as clock comes from SPI_IN */
120 snprintf(str_freq
, sizeof(str_freq
), "%u\n", freq
);
121 size
= iio_write_channel_ext_info(priv
->iio_ch
, "spi_clk_freq",
122 str_freq
, sizeof(str_freq
));
123 if (size
!= sizeof(str_freq
)) {
124 dev_err(dai
->dev
, "%s: Failed to set SPI clock\n",
131 static const struct snd_soc_dai_ops stm32_adfsdm_dai_ops
= {
132 .shutdown
= stm32_adfsdm_shutdown
,
133 .prepare
= stm32_adfsdm_dai_prepare
,
134 .set_sysclk
= stm32_adfsdm_set_sysclk
,
137 static const struct snd_soc_dai_driver stm32_adfsdm_dai
= {
141 .formats
= SNDRV_PCM_FMTBIT_S16_LE
|
142 SNDRV_PCM_FMTBIT_S32_LE
,
143 .rates
= SNDRV_PCM_RATE_CONTINUOUS
,
147 .ops
= &stm32_adfsdm_dai_ops
,
150 static const struct snd_soc_component_driver stm32_adfsdm_dai_component
= {
151 .name
= "stm32_dfsdm_audio",
152 .legacy_dai_naming
= 1,
155 static void stm32_memcpy_32to16(void *dest
, const void *src
, size_t n
)
158 u16
*d
= (u16
*)dest
, *s
= (u16
*)src
;
161 for (i
= n
>> 1; i
> 0; i
--) {
167 static int stm32_afsdm_pcm_cb(const void *data
, size_t size
, void *private)
169 struct stm32_adfsdm_priv
*priv
= private;
170 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(priv
->substream
);
171 u8
*pcm_buff
= priv
->pcm_buff
;
172 u8
*src_buff
= (u8
*)data
;
173 unsigned int old_pos
= priv
->pos
;
174 size_t buff_size
= snd_pcm_lib_buffer_bytes(priv
->substream
);
175 size_t period_size
= snd_pcm_lib_period_bytes(priv
->substream
);
176 size_t cur_size
, src_size
= size
;
177 snd_pcm_format_t format
= priv
->substream
->runtime
->format
;
179 if (format
== SNDRV_PCM_FORMAT_S16_LE
)
183 dev_dbg(rtd
->dev
, "%s: buff_add :%pK, pos = %d, size = %zu\n",
184 __func__
, &pcm_buff
[priv
->pos
], priv
->pos
, src_size
);
186 if ((priv
->pos
+ src_size
) > buff_size
) {
187 if (format
== SNDRV_PCM_FORMAT_S16_LE
)
188 stm32_memcpy_32to16(&pcm_buff
[priv
->pos
], src_buff
,
189 buff_size
- priv
->pos
);
191 memcpy(&pcm_buff
[priv
->pos
], src_buff
,
192 buff_size
- priv
->pos
);
193 cur_size
-= buff_size
- priv
->pos
;
197 if (format
== SNDRV_PCM_FORMAT_S16_LE
)
198 stm32_memcpy_32to16(&pcm_buff
[priv
->pos
],
199 &src_buff
[src_size
- cur_size
], cur_size
);
201 memcpy(&pcm_buff
[priv
->pos
], &src_buff
[src_size
- cur_size
],
204 priv
->pos
= (priv
->pos
+ cur_size
) % buff_size
;
206 if (cur_size
!= src_size
|| (old_pos
&& (old_pos
% period_size
< size
)))
207 snd_pcm_period_elapsed(priv
->substream
);
212 static int stm32_adfsdm_trigger(struct snd_soc_component
*component
,
213 struct snd_pcm_substream
*substream
, int cmd
)
215 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
216 struct stm32_adfsdm_priv
*priv
=
217 snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd
, 0));
220 case SNDRV_PCM_TRIGGER_START
:
221 case SNDRV_PCM_TRIGGER_RESUME
:
223 return stm32_dfsdm_get_buff_cb(priv
->iio_ch
->indio_dev
,
224 stm32_afsdm_pcm_cb
, priv
);
225 case SNDRV_PCM_TRIGGER_SUSPEND
:
226 case SNDRV_PCM_TRIGGER_STOP
:
227 return stm32_dfsdm_release_buff_cb(priv
->iio_ch
->indio_dev
);
233 static int stm32_adfsdm_pcm_open(struct snd_soc_component
*component
,
234 struct snd_pcm_substream
*substream
)
236 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
237 struct stm32_adfsdm_priv
*priv
= snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd
, 0));
240 ret
= snd_soc_set_runtime_hwparams(substream
, &stm32_adfsdm_pcm_hw
);
242 priv
->substream
= substream
;
247 static int stm32_adfsdm_pcm_close(struct snd_soc_component
*component
,
248 struct snd_pcm_substream
*substream
)
250 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
251 struct stm32_adfsdm_priv
*priv
=
252 snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd
, 0));
254 priv
->substream
= NULL
;
259 static snd_pcm_uframes_t
stm32_adfsdm_pcm_pointer(
260 struct snd_soc_component
*component
,
261 struct snd_pcm_substream
*substream
)
263 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
264 struct stm32_adfsdm_priv
*priv
=
265 snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd
, 0));
267 return bytes_to_frames(substream
->runtime
, priv
->pos
);
270 static int stm32_adfsdm_pcm_hw_params(struct snd_soc_component
*component
,
271 struct snd_pcm_substream
*substream
,
272 struct snd_pcm_hw_params
*params
)
274 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
275 struct stm32_adfsdm_priv
*priv
=
276 snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd
, 0));
278 priv
->pcm_buff
= substream
->runtime
->dma_area
;
280 return iio_channel_cb_set_buffer_watermark(priv
->iio_cb
,
281 params_period_size(params
));
284 static int stm32_adfsdm_pcm_new(struct snd_soc_component
*component
,
285 struct snd_soc_pcm_runtime
*rtd
)
287 struct snd_pcm
*pcm
= rtd
->pcm
;
288 struct stm32_adfsdm_priv
*priv
=
289 snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd
, 0));
290 unsigned int size
= DFSDM_MAX_PERIODS
* DFSDM_MAX_PERIOD_SIZE
;
292 snd_pcm_set_managed_buffer_all(pcm
, SNDRV_DMA_TYPE_DEV
,
293 priv
->dev
, size
, size
);
297 static int stm32_adfsdm_dummy_cb(const void *data
, void *private)
300 * This dummy callback is requested by iio_channel_get_all_cb() API,
301 * but the stm32_dfsdm_get_buff_cb() API is used instead, to optimize
307 static void stm32_adfsdm_cleanup(void *data
)
309 iio_channel_release_all_cb(data
);
312 static const struct snd_soc_component_driver stm32_adfsdm_soc_platform
= {
313 .open
= stm32_adfsdm_pcm_open
,
314 .close
= stm32_adfsdm_pcm_close
,
315 .hw_params
= stm32_adfsdm_pcm_hw_params
,
316 .trigger
= stm32_adfsdm_trigger
,
317 .pointer
= stm32_adfsdm_pcm_pointer
,
318 .pcm_construct
= stm32_adfsdm_pcm_new
,
321 static const struct of_device_id stm32_adfsdm_of_match
[] = {
322 {.compatible
= "st,stm32h7-dfsdm-dai"},
325 MODULE_DEVICE_TABLE(of
, stm32_adfsdm_of_match
);
327 static int stm32_adfsdm_probe(struct platform_device
*pdev
)
329 struct stm32_adfsdm_priv
*priv
;
330 struct snd_soc_component
*component
;
333 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
337 priv
->dev
= &pdev
->dev
;
338 priv
->dai_drv
= stm32_adfsdm_dai
;
339 mutex_init(&priv
->lock
);
341 dev_set_drvdata(&pdev
->dev
, priv
);
343 ret
= devm_snd_soc_register_component(&pdev
->dev
,
344 &stm32_adfsdm_dai_component
,
349 /* Associate iio channel */
350 priv
->iio_ch
= devm_iio_channel_get_all(&pdev
->dev
);
351 if (IS_ERR(priv
->iio_ch
))
352 return PTR_ERR(priv
->iio_ch
);
354 priv
->iio_cb
= iio_channel_get_all_cb(&pdev
->dev
, &stm32_adfsdm_dummy_cb
, NULL
);
355 if (IS_ERR(priv
->iio_cb
))
356 return PTR_ERR(priv
->iio_cb
);
358 ret
= devm_add_action_or_reset(&pdev
->dev
, stm32_adfsdm_cleanup
, priv
->iio_cb
);
360 dev_err(&pdev
->dev
, "Unable to add action\n");
364 component
= devm_kzalloc(&pdev
->dev
, sizeof(*component
), GFP_KERNEL
);
368 ret
= snd_soc_component_initialize(component
,
369 &stm32_adfsdm_soc_platform
,
373 #ifdef CONFIG_DEBUG_FS
374 component
->debugfs_prefix
= "pcm";
377 ret
= snd_soc_add_component(component
, NULL
, 0);
379 dev_err(&pdev
->dev
, "%s: Failed to register PCM platform\n",
384 pm_runtime_enable(&pdev
->dev
);
389 static void stm32_adfsdm_remove(struct platform_device
*pdev
)
391 snd_soc_unregister_component(&pdev
->dev
);
392 pm_runtime_disable(&pdev
->dev
);
395 static struct platform_driver stm32_adfsdm_driver
= {
397 .name
= STM32_ADFSDM_DRV_NAME
,
398 .of_match_table
= stm32_adfsdm_of_match
,
400 .probe
= stm32_adfsdm_probe
,
401 .remove
= stm32_adfsdm_remove
,
404 module_platform_driver(stm32_adfsdm_driver
);
406 MODULE_DESCRIPTION("stm32 DFSDM DAI driver");
407 MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>");
408 MODULE_LICENSE("GPL v2");
409 MODULE_ALIAS("platform:" STM32_ADFSDM_DRV_NAME
);