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/platform_device.h>
13 #include <linux/slab.h>
15 #include <linux/iio/iio.h>
16 #include <linux/iio/consumer.h>
17 #include <linux/iio/adc/stm32-dfsdm-adc.h>
19 #include <sound/pcm.h>
20 #include <sound/soc.h>
22 #define STM32_ADFSDM_DRV_NAME "stm32-adfsdm"
24 #define DFSDM_MAX_PERIOD_SIZE (PAGE_SIZE / 2)
25 #define DFSDM_MAX_PERIODS 6
27 struct stm32_adfsdm_priv
{
28 struct snd_soc_dai_driver dai_drv
;
29 struct snd_pcm_substream
*substream
;
33 struct iio_channel
*iio_ch
;
34 struct iio_cb_buffer
*iio_cb
;
38 unsigned char *pcm_buff
;
42 static const struct snd_pcm_hardware stm32_adfsdm_pcm_hw
= {
43 .info
= SNDRV_PCM_INFO_INTERLEAVED
| SNDRV_PCM_INFO_BLOCK_TRANSFER
|
45 .formats
= 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 if (priv
->iio_active
) {
66 iio_channel_stop_all_cb(priv
->iio_cb
);
67 priv
->iio_active
= false;
71 static int stm32_adfsdm_dai_prepare(struct snd_pcm_substream
*substream
,
72 struct snd_soc_dai
*dai
)
74 struct stm32_adfsdm_priv
*priv
= snd_soc_dai_get_drvdata(dai
);
77 ret
= iio_write_channel_attribute(priv
->iio_ch
,
78 substream
->runtime
->rate
, 0,
79 IIO_CHAN_INFO_SAMP_FREQ
);
81 dev_err(dai
->dev
, "%s: Failed to set %d sampling rate\n",
82 __func__
, substream
->runtime
->rate
);
86 if (!priv
->iio_active
) {
87 ret
= iio_channel_start_all_cb(priv
->iio_cb
);
89 priv
->iio_active
= true;
91 dev_err(dai
->dev
, "%s: IIO channel start failed (%d)\n",
98 static int stm32_adfsdm_set_sysclk(struct snd_soc_dai
*dai
, int clk_id
,
99 unsigned int freq
, int dir
)
101 struct stm32_adfsdm_priv
*priv
= snd_soc_dai_get_drvdata(dai
);
105 dev_dbg(dai
->dev
, "%s: Enter for freq %d\n", __func__
, freq
);
107 /* Set IIO frequency if CODEC is master as clock comes from SPI_IN */
109 snprintf(str_freq
, sizeof(str_freq
), "%d\n", freq
);
110 size
= iio_write_channel_ext_info(priv
->iio_ch
, "spi_clk_freq",
111 str_freq
, sizeof(str_freq
));
112 if (size
!= sizeof(str_freq
)) {
113 dev_err(dai
->dev
, "%s: Failed to set SPI clock\n",
120 static const struct snd_soc_dai_ops stm32_adfsdm_dai_ops
= {
121 .shutdown
= stm32_adfsdm_shutdown
,
122 .prepare
= stm32_adfsdm_dai_prepare
,
123 .set_sysclk
= stm32_adfsdm_set_sysclk
,
126 static const struct snd_soc_dai_driver stm32_adfsdm_dai
= {
130 .formats
= SNDRV_PCM_FMTBIT_S32_LE
,
131 .rates
= (SNDRV_PCM_RATE_8000
| SNDRV_PCM_RATE_16000
|
132 SNDRV_PCM_RATE_32000
),
134 .ops
= &stm32_adfsdm_dai_ops
,
137 static const struct snd_soc_component_driver stm32_adfsdm_dai_component
= {
138 .name
= "stm32_dfsdm_audio",
141 static int stm32_afsdm_pcm_cb(const void *data
, size_t size
, void *private)
143 struct stm32_adfsdm_priv
*priv
= private;
144 struct snd_soc_pcm_runtime
*rtd
= priv
->substream
->private_data
;
145 u8
*pcm_buff
= priv
->pcm_buff
;
146 u8
*src_buff
= (u8
*)data
;
147 unsigned int buff_size
= snd_pcm_lib_buffer_bytes(priv
->substream
);
148 unsigned int period_size
= snd_pcm_lib_period_bytes(priv
->substream
);
149 unsigned int old_pos
= priv
->pos
;
150 unsigned int cur_size
= size
;
152 dev_dbg(rtd
->dev
, "%s: buff_add :%p, pos = %d, size = %zu\n",
153 __func__
, &pcm_buff
[priv
->pos
], priv
->pos
, size
);
155 if ((priv
->pos
+ size
) > buff_size
) {
156 memcpy(&pcm_buff
[priv
->pos
], src_buff
, buff_size
- priv
->pos
);
157 cur_size
-= buff_size
- priv
->pos
;
161 memcpy(&pcm_buff
[priv
->pos
], &src_buff
[size
- cur_size
], cur_size
);
162 priv
->pos
= (priv
->pos
+ cur_size
) % buff_size
;
164 if (cur_size
!= size
|| (old_pos
&& (old_pos
% period_size
< size
)))
165 snd_pcm_period_elapsed(priv
->substream
);
170 static int stm32_adfsdm_trigger(struct snd_pcm_substream
*substream
, int cmd
)
172 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
173 struct stm32_adfsdm_priv
*priv
=
174 snd_soc_dai_get_drvdata(rtd
->cpu_dai
);
177 case SNDRV_PCM_TRIGGER_START
:
178 case SNDRV_PCM_TRIGGER_RESUME
:
180 return stm32_dfsdm_get_buff_cb(priv
->iio_ch
->indio_dev
,
181 stm32_afsdm_pcm_cb
, priv
);
182 case SNDRV_PCM_TRIGGER_SUSPEND
:
183 case SNDRV_PCM_TRIGGER_STOP
:
184 return stm32_dfsdm_release_buff_cb(priv
->iio_ch
->indio_dev
);
190 static int stm32_adfsdm_pcm_open(struct snd_pcm_substream
*substream
)
192 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
193 struct stm32_adfsdm_priv
*priv
= snd_soc_dai_get_drvdata(rtd
->cpu_dai
);
196 ret
= snd_soc_set_runtime_hwparams(substream
, &stm32_adfsdm_pcm_hw
);
198 priv
->substream
= substream
;
203 static int stm32_adfsdm_pcm_close(struct snd_pcm_substream
*substream
)
205 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
206 struct stm32_adfsdm_priv
*priv
=
207 snd_soc_dai_get_drvdata(rtd
->cpu_dai
);
209 snd_pcm_lib_free_pages(substream
);
210 priv
->substream
= NULL
;
215 static snd_pcm_uframes_t
stm32_adfsdm_pcm_pointer(
216 struct snd_pcm_substream
*substream
)
218 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
219 struct stm32_adfsdm_priv
*priv
=
220 snd_soc_dai_get_drvdata(rtd
->cpu_dai
);
222 return bytes_to_frames(substream
->runtime
, priv
->pos
);
225 static int stm32_adfsdm_pcm_hw_params(struct snd_pcm_substream
*substream
,
226 struct snd_pcm_hw_params
*params
)
228 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
229 struct stm32_adfsdm_priv
*priv
=
230 snd_soc_dai_get_drvdata(rtd
->cpu_dai
);
233 ret
= snd_pcm_lib_malloc_pages(substream
, params_buffer_bytes(params
));
236 priv
->pcm_buff
= substream
->runtime
->dma_area
;
238 return iio_channel_cb_set_buffer_watermark(priv
->iio_cb
,
239 params_period_size(params
));
242 static int stm32_adfsdm_pcm_hw_free(struct snd_pcm_substream
*substream
)
244 snd_pcm_lib_free_pages(substream
);
249 static struct snd_pcm_ops stm32_adfsdm_pcm_ops
= {
250 .open
= stm32_adfsdm_pcm_open
,
251 .close
= stm32_adfsdm_pcm_close
,
252 .hw_params
= stm32_adfsdm_pcm_hw_params
,
253 .hw_free
= stm32_adfsdm_pcm_hw_free
,
254 .trigger
= stm32_adfsdm_trigger
,
255 .pointer
= stm32_adfsdm_pcm_pointer
,
258 static int stm32_adfsdm_pcm_new(struct snd_soc_pcm_runtime
*rtd
)
260 struct snd_pcm
*pcm
= rtd
->pcm
;
261 struct stm32_adfsdm_priv
*priv
=
262 snd_soc_dai_get_drvdata(rtd
->cpu_dai
);
263 unsigned int size
= DFSDM_MAX_PERIODS
* DFSDM_MAX_PERIOD_SIZE
;
265 return snd_pcm_lib_preallocate_pages_for_all(pcm
, SNDRV_DMA_TYPE_DEV
,
266 priv
->dev
, size
, size
);
269 static void stm32_adfsdm_pcm_free(struct snd_pcm
*pcm
)
271 struct snd_pcm_substream
*substream
;
272 struct snd_soc_pcm_runtime
*rtd
;
273 struct stm32_adfsdm_priv
*priv
;
275 substream
= pcm
->streams
[SNDRV_PCM_STREAM_CAPTURE
].substream
;
277 rtd
= substream
->private_data
;
278 priv
= snd_soc_dai_get_drvdata(rtd
->cpu_dai
);
280 snd_pcm_lib_preallocate_free_for_all(pcm
);
284 static struct snd_soc_platform_driver stm32_adfsdm_soc_platform
= {
285 .ops
= &stm32_adfsdm_pcm_ops
,
286 .pcm_new
= stm32_adfsdm_pcm_new
,
287 .pcm_free
= stm32_adfsdm_pcm_free
,
290 static const struct of_device_id stm32_adfsdm_of_match
[] = {
291 {.compatible
= "st,stm32h7-dfsdm-dai"},
294 MODULE_DEVICE_TABLE(of
, stm32_adfsdm_of_match
);
296 static int stm32_adfsdm_probe(struct platform_device
*pdev
)
298 struct stm32_adfsdm_priv
*priv
;
301 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
305 priv
->dev
= &pdev
->dev
;
306 priv
->dai_drv
= stm32_adfsdm_dai
;
308 dev_set_drvdata(&pdev
->dev
, priv
);
310 ret
= devm_snd_soc_register_component(&pdev
->dev
,
311 &stm32_adfsdm_dai_component
,
316 /* Associate iio channel */
317 priv
->iio_ch
= devm_iio_channel_get_all(&pdev
->dev
);
318 if (IS_ERR(priv
->iio_ch
))
319 return PTR_ERR(priv
->iio_ch
);
321 priv
->iio_cb
= iio_channel_get_all_cb(&pdev
->dev
, NULL
, NULL
);
322 if (IS_ERR(priv
->iio_cb
))
323 return PTR_ERR(priv
->iio_cb
);
325 ret
= devm_snd_soc_register_platform(&pdev
->dev
,
326 &stm32_adfsdm_soc_platform
);
328 dev_err(&pdev
->dev
, "%s: Failed to register PCM platform\n",
334 static struct platform_driver stm32_adfsdm_driver
= {
336 .name
= STM32_ADFSDM_DRV_NAME
,
337 .of_match_table
= stm32_adfsdm_of_match
,
339 .probe
= stm32_adfsdm_probe
,
342 module_platform_driver(stm32_adfsdm_driver
);
344 MODULE_DESCRIPTION("stm32 DFSDM DAI driver");
345 MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>");
346 MODULE_LICENSE("GPL v2");
347 MODULE_ALIAS("platform:" STM32_ADFSDM_DRV_NAME
);