stm32_adfsdm.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * This file is part of STM32 DFSDM ASoC DAI driver
  4. *
  5. * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
  6. * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
  7. * Olivier Moysan <olivier.moysan@st.com>
  8. */
  9. #include <linux/clk.h>
  10. #include <linux/module.h>
  11. #include <linux/mutex.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/slab.h>
  14. #include <linux/iio/iio.h>
  15. #include <linux/iio/consumer.h>
  16. #include <linux/iio/adc/stm32-dfsdm-adc.h>
  17. #include <sound/pcm.h>
  18. #include <sound/soc.h>
  19. #define STM32_ADFSDM_DRV_NAME "stm32-adfsdm"
  20. #define DFSDM_MAX_PERIOD_SIZE (PAGE_SIZE / 2)
  21. #define DFSDM_MAX_PERIODS 6
  22. struct stm32_adfsdm_priv {
  23. struct snd_soc_dai_driver dai_drv;
  24. struct snd_pcm_substream *substream;
  25. struct device *dev;
  26. /* IIO */
  27. struct iio_channel *iio_ch;
  28. struct iio_cb_buffer *iio_cb;
  29. bool iio_active;
  30. /* PCM buffer */
  31. unsigned char *pcm_buff;
  32. unsigned int pos;
  33. struct mutex lock; /* protect against race condition on iio state */
  34. };
  35. static const struct snd_pcm_hardware stm32_adfsdm_pcm_hw = {
  36. .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
  37. SNDRV_PCM_INFO_PAUSE,
  38. .formats = SNDRV_PCM_FMTBIT_S32_LE,
  39. .rate_min = 8000,
  40. .rate_max = 32000,
  41. .channels_min = 1,
  42. .channels_max = 1,
  43. .periods_min = 2,
  44. .periods_max = DFSDM_MAX_PERIODS,
  45. .period_bytes_max = DFSDM_MAX_PERIOD_SIZE,
  46. .buffer_bytes_max = DFSDM_MAX_PERIODS * DFSDM_MAX_PERIOD_SIZE
  47. };
  48. static void stm32_adfsdm_shutdown(struct snd_pcm_substream *substream,
  49. struct snd_soc_dai *dai)
  50. {
  51. struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai);
  52. mutex_lock(&priv->lock);
  53. if (priv->iio_active) {
  54. iio_channel_stop_all_cb(priv->iio_cb);
  55. priv->iio_active = false;
  56. }
  57. mutex_unlock(&priv->lock);
  58. }
  59. static int stm32_adfsdm_dai_prepare(struct snd_pcm_substream *substream,
  60. struct snd_soc_dai *dai)
  61. {
  62. struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai);
  63. int ret;
  64. mutex_lock(&priv->lock);
  65. if (priv->iio_active) {
  66. iio_channel_stop_all_cb(priv->iio_cb);
  67. priv->iio_active = false;
  68. }
  69. ret = iio_write_channel_attribute(priv->iio_ch,
  70. substream->runtime->rate, 0,
  71. IIO_CHAN_INFO_SAMP_FREQ);
  72. if (ret < 0) {
  73. dev_err(dai->dev, "%s: Failed to set %d sampling rate\n",
  74. __func__, substream->runtime->rate);
  75. goto out;
  76. }
  77. if (!priv->iio_active) {
  78. ret = iio_channel_start_all_cb(priv->iio_cb);
  79. if (!ret)
  80. priv->iio_active = true;
  81. else
  82. dev_err(dai->dev, "%s: IIO channel start failed (%d)\n",
  83. __func__, ret);
  84. }
  85. out:
  86. mutex_unlock(&priv->lock);
  87. return ret;
  88. }
  89. static int stm32_adfsdm_set_sysclk(struct snd_soc_dai *dai, int clk_id,
  90. unsigned int freq, int dir)
  91. {
  92. struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai);
  93. ssize_t size;
  94. char str_freq[10];
  95. dev_dbg(dai->dev, "%s: Enter for freq %d\n", __func__, freq);
  96. /* Set IIO frequency if CODEC is master as clock comes from SPI_IN */
  97. snprintf(str_freq, sizeof(str_freq), "%d\n", freq);
  98. size = iio_write_channel_ext_info(priv->iio_ch, "spi_clk_freq",
  99. str_freq, sizeof(str_freq));
  100. if (size != sizeof(str_freq)) {
  101. dev_err(dai->dev, "%s: Failed to set SPI clock\n",
  102. __func__);
  103. return -EINVAL;
  104. }
  105. return 0;
  106. }
  107. static const struct snd_soc_dai_ops stm32_adfsdm_dai_ops = {
  108. .shutdown = stm32_adfsdm_shutdown,
  109. .prepare = stm32_adfsdm_dai_prepare,
  110. .set_sysclk = stm32_adfsdm_set_sysclk,
  111. };
  112. static const struct snd_soc_dai_driver stm32_adfsdm_dai = {
  113. .capture = {
  114. .channels_min = 1,
  115. .channels_max = 1,
  116. .formats = SNDRV_PCM_FMTBIT_S32_LE,
  117. .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
  118. SNDRV_PCM_RATE_32000),
  119. },
  120. .ops = &stm32_adfsdm_dai_ops,
  121. };
  122. static const struct snd_soc_component_driver stm32_adfsdm_dai_component = {
  123. .name = "stm32_dfsdm_audio",
  124. };
  125. static int stm32_afsdm_pcm_cb(const void *data, size_t size, void *private)
  126. {
  127. struct stm32_adfsdm_priv *priv = private;
  128. struct snd_soc_pcm_runtime *rtd = priv->substream->private_data;
  129. u8 *pcm_buff = priv->pcm_buff;
  130. u8 *src_buff = (u8 *)data;
  131. unsigned int buff_size = snd_pcm_lib_buffer_bytes(priv->substream);
  132. unsigned int period_size = snd_pcm_lib_period_bytes(priv->substream);
  133. unsigned int old_pos = priv->pos;
  134. unsigned int cur_size = size;
  135. dev_dbg(rtd->dev, "%s: buff_add :%pK, pos = %d, size = %zu\n",
  136. __func__, &pcm_buff[priv->pos], priv->pos, size);
  137. if ((priv->pos + size) > buff_size) {
  138. memcpy(&pcm_buff[priv->pos], src_buff, buff_size - priv->pos);
  139. cur_size -= buff_size - priv->pos;
  140. priv->pos = 0;
  141. }
  142. memcpy(&pcm_buff[priv->pos], &src_buff[size - cur_size], cur_size);
  143. priv->pos = (priv->pos + cur_size) % buff_size;
  144. if (cur_size != size || (old_pos && (old_pos % period_size < size)))
  145. snd_pcm_period_elapsed(priv->substream);
  146. return 0;
  147. }
  148. static int stm32_adfsdm_trigger(struct snd_pcm_substream *substream, int cmd)
  149. {
  150. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  151. struct stm32_adfsdm_priv *priv =
  152. snd_soc_dai_get_drvdata(rtd->cpu_dai);
  153. switch (cmd) {
  154. case SNDRV_PCM_TRIGGER_START:
  155. case SNDRV_PCM_TRIGGER_RESUME:
  156. priv->pos = 0;
  157. return stm32_dfsdm_get_buff_cb(priv->iio_ch->indio_dev,
  158. stm32_afsdm_pcm_cb, priv);
  159. case SNDRV_PCM_TRIGGER_SUSPEND:
  160. case SNDRV_PCM_TRIGGER_STOP:
  161. return stm32_dfsdm_release_buff_cb(priv->iio_ch->indio_dev);
  162. }
  163. return -EINVAL;
  164. }
  165. static int stm32_adfsdm_pcm_open(struct snd_pcm_substream *substream)
  166. {
  167. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  168. struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
  169. int ret;
  170. ret = snd_soc_set_runtime_hwparams(substream, &stm32_adfsdm_pcm_hw);
  171. if (!ret)
  172. priv->substream = substream;
  173. return ret;
  174. }
  175. static int stm32_adfsdm_pcm_close(struct snd_pcm_substream *substream)
  176. {
  177. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  178. struct stm32_adfsdm_priv *priv =
  179. snd_soc_dai_get_drvdata(rtd->cpu_dai);
  180. snd_pcm_lib_free_pages(substream);
  181. priv->substream = NULL;
  182. return 0;
  183. }
  184. static snd_pcm_uframes_t stm32_adfsdm_pcm_pointer(
  185. struct snd_pcm_substream *substream)
  186. {
  187. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  188. struct stm32_adfsdm_priv *priv =
  189. snd_soc_dai_get_drvdata(rtd->cpu_dai);
  190. return bytes_to_frames(substream->runtime, priv->pos);
  191. }
  192. static int stm32_adfsdm_pcm_hw_params(struct snd_pcm_substream *substream,
  193. struct snd_pcm_hw_params *params)
  194. {
  195. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  196. struct stm32_adfsdm_priv *priv =
  197. snd_soc_dai_get_drvdata(rtd->cpu_dai);
  198. int ret;
  199. ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
  200. if (ret < 0)
  201. return ret;
  202. priv->pcm_buff = substream->runtime->dma_area;
  203. return iio_channel_cb_set_buffer_watermark(priv->iio_cb,
  204. params_period_size(params));
  205. }
  206. static int stm32_adfsdm_pcm_hw_free(struct snd_pcm_substream *substream)
  207. {
  208. snd_pcm_lib_free_pages(substream);
  209. return 0;
  210. }
  211. static struct snd_pcm_ops stm32_adfsdm_pcm_ops = {
  212. .open = stm32_adfsdm_pcm_open,
  213. .close = stm32_adfsdm_pcm_close,
  214. .hw_params = stm32_adfsdm_pcm_hw_params,
  215. .hw_free = stm32_adfsdm_pcm_hw_free,
  216. .trigger = stm32_adfsdm_trigger,
  217. .pointer = stm32_adfsdm_pcm_pointer,
  218. };
  219. static int stm32_adfsdm_pcm_new(struct snd_soc_pcm_runtime *rtd)
  220. {
  221. struct snd_pcm *pcm = rtd->pcm;
  222. struct stm32_adfsdm_priv *priv =
  223. snd_soc_dai_get_drvdata(rtd->cpu_dai);
  224. unsigned int size = DFSDM_MAX_PERIODS * DFSDM_MAX_PERIOD_SIZE;
  225. return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
  226. priv->dev, size, size);
  227. }
  228. static void stm32_adfsdm_pcm_free(struct snd_pcm *pcm)
  229. {
  230. struct snd_pcm_substream *substream;
  231. substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
  232. if (substream)
  233. snd_pcm_lib_preallocate_free_for_all(pcm);
  234. }
  235. static struct snd_soc_component_driver stm32_adfsdm_soc_platform = {
  236. .ops = &stm32_adfsdm_pcm_ops,
  237. .pcm_new = stm32_adfsdm_pcm_new,
  238. .pcm_free = stm32_adfsdm_pcm_free,
  239. };
  240. static const struct of_device_id stm32_adfsdm_of_match[] = {
  241. {.compatible = "st,stm32h7-dfsdm-dai"},
  242. {}
  243. };
  244. MODULE_DEVICE_TABLE(of, stm32_adfsdm_of_match);
  245. static int stm32_adfsdm_probe(struct platform_device *pdev)
  246. {
  247. struct stm32_adfsdm_priv *priv;
  248. struct snd_soc_component *component;
  249. int ret;
  250. priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
  251. if (!priv)
  252. return -ENOMEM;
  253. priv->dev = &pdev->dev;
  254. priv->dai_drv = stm32_adfsdm_dai;
  255. mutex_init(&priv->lock);
  256. dev_set_drvdata(&pdev->dev, priv);
  257. ret = devm_snd_soc_register_component(&pdev->dev,
  258. &stm32_adfsdm_dai_component,
  259. &priv->dai_drv, 1);
  260. if (ret < 0)
  261. return ret;
  262. /* Associate iio channel */
  263. priv->iio_ch = devm_iio_channel_get_all(&pdev->dev);
  264. if (IS_ERR(priv->iio_ch))
  265. return PTR_ERR(priv->iio_ch);
  266. priv->iio_cb = iio_channel_get_all_cb(&pdev->dev, NULL, NULL);
  267. if (IS_ERR(priv->iio_cb))
  268. return PTR_ERR(priv->iio_cb);
  269. component = devm_kzalloc(&pdev->dev, sizeof(*component), GFP_KERNEL);
  270. if (!component)
  271. return -ENOMEM;
  272. #ifdef CONFIG_DEBUG_FS
  273. component->debugfs_prefix = "pcm";
  274. #endif
  275. ret = snd_soc_add_component(&pdev->dev, component,
  276. &stm32_adfsdm_soc_platform, NULL, 0);
  277. if (ret < 0)
  278. dev_err(&pdev->dev, "%s: Failed to register PCM platform\n",
  279. __func__);
  280. return ret;
  281. }
  282. static int stm32_adfsdm_remove(struct platform_device *pdev)
  283. {
  284. snd_soc_unregister_component(&pdev->dev);
  285. return 0;
  286. }
  287. static struct platform_driver stm32_adfsdm_driver = {
  288. .driver = {
  289. .name = STM32_ADFSDM_DRV_NAME,
  290. .of_match_table = stm32_adfsdm_of_match,
  291. },
  292. .probe = stm32_adfsdm_probe,
  293. .remove = stm32_adfsdm_remove,
  294. };
  295. module_platform_driver(stm32_adfsdm_driver);
  296. MODULE_DESCRIPTION("stm32 DFSDM DAI driver");
  297. MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>");
  298. MODULE_LICENSE("GPL v2");
  299. MODULE_ALIAS("platform:" STM32_ADFSDM_DRV_NAME);