fsl_rpmsg.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. // SPDX-License-Identifier: GPL-2.0+
  2. // Copyright 2018-2021 NXP
  3. #include <linux/clk.h>
  4. #include <linux/clk-provider.h>
  5. #include <linux/delay.h>
  6. #include <linux/dmaengine.h>
  7. #include <linux/module.h>
  8. #include <linux/of_device.h>
  9. #include <linux/of_address.h>
  10. #include <linux/pm_runtime.h>
  11. #include <linux/rpmsg.h>
  12. #include <linux/slab.h>
  13. #include <sound/core.h>
  14. #include <sound/dmaengine_pcm.h>
  15. #include <sound/pcm_params.h>
  16. #include "fsl_rpmsg.h"
  17. #include "imx-pcm.h"
  18. #define FSL_RPMSG_RATES (SNDRV_PCM_RATE_8000 | \
  19. SNDRV_PCM_RATE_16000 | \
  20. SNDRV_PCM_RATE_48000)
  21. #define FSL_RPMSG_FORMATS SNDRV_PCM_FMTBIT_S16_LE
  22. /* 192kHz/32bit/2ch/60s size is 0x574e00 */
  23. #define LPA_LARGE_BUFFER_SIZE (0x6000000)
  24. static const unsigned int fsl_rpmsg_rates[] = {
  25. 8000, 11025, 16000, 22050, 44100,
  26. 32000, 48000, 96000, 88200, 176400, 192000,
  27. 352800, 384000, 705600, 768000, 1411200, 2822400,
  28. };
  29. static const struct snd_pcm_hw_constraint_list fsl_rpmsg_rate_constraints = {
  30. .count = ARRAY_SIZE(fsl_rpmsg_rates),
  31. .list = fsl_rpmsg_rates,
  32. };
  33. static int fsl_rpmsg_hw_params(struct snd_pcm_substream *substream,
  34. struct snd_pcm_hw_params *params,
  35. struct snd_soc_dai *dai)
  36. {
  37. struct fsl_rpmsg *rpmsg = snd_soc_dai_get_drvdata(dai);
  38. struct clk *p = rpmsg->mclk, *pll = NULL, *npll = NULL;
  39. u64 rate = params_rate(params);
  40. int ret = 0;
  41. /* Get current pll parent */
  42. while (p && rpmsg->pll8k && rpmsg->pll11k) {
  43. struct clk *pp = clk_get_parent(p);
  44. if (clk_is_match(pp, rpmsg->pll8k) ||
  45. clk_is_match(pp, rpmsg->pll11k)) {
  46. pll = pp;
  47. break;
  48. }
  49. p = pp;
  50. }
  51. /* Switch to another pll parent if needed. */
  52. if (pll) {
  53. npll = (do_div(rate, 8000) ? rpmsg->pll11k : rpmsg->pll8k);
  54. if (!clk_is_match(pll, npll)) {
  55. ret = clk_set_parent(p, npll);
  56. if (ret < 0)
  57. dev_warn(dai->dev, "failed to set parent %s: %d\n",
  58. __clk_get_name(npll), ret);
  59. }
  60. }
  61. if (!(rpmsg->mclk_streams & BIT(substream->stream))) {
  62. ret = clk_prepare_enable(rpmsg->mclk);
  63. if (ret) {
  64. dev_err(dai->dev, "failed to enable mclk: %d\n", ret);
  65. return ret;
  66. }
  67. rpmsg->mclk_streams |= BIT(substream->stream);
  68. }
  69. return ret;
  70. }
  71. static int fsl_rpmsg_hw_free(struct snd_pcm_substream *substream,
  72. struct snd_soc_dai *dai)
  73. {
  74. struct fsl_rpmsg *rpmsg = snd_soc_dai_get_drvdata(dai);
  75. if (rpmsg->mclk_streams & BIT(substream->stream)) {
  76. clk_disable_unprepare(rpmsg->mclk);
  77. rpmsg->mclk_streams &= ~BIT(substream->stream);
  78. }
  79. return 0;
  80. }
  81. static int fsl_rpmsg_startup(struct snd_pcm_substream *substream,
  82. struct snd_soc_dai *cpu_dai)
  83. {
  84. int ret;
  85. ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
  86. SNDRV_PCM_HW_PARAM_RATE,
  87. &fsl_rpmsg_rate_constraints);
  88. return ret;
  89. }
  90. static const struct snd_soc_dai_ops fsl_rpmsg_dai_ops = {
  91. .startup = fsl_rpmsg_startup,
  92. .hw_params = fsl_rpmsg_hw_params,
  93. .hw_free = fsl_rpmsg_hw_free,
  94. };
  95. static struct snd_soc_dai_driver fsl_rpmsg_dai = {
  96. .playback = {
  97. .stream_name = "CPU-Playback",
  98. .channels_min = 2,
  99. .channels_max = 2,
  100. .rates = SNDRV_PCM_RATE_KNOT,
  101. .formats = FSL_RPMSG_FORMATS,
  102. },
  103. .capture = {
  104. .stream_name = "CPU-Capture",
  105. .channels_min = 2,
  106. .channels_max = 2,
  107. .rates = SNDRV_PCM_RATE_KNOT,
  108. .formats = FSL_RPMSG_FORMATS,
  109. },
  110. .symmetric_rate = 1,
  111. .symmetric_channels = 1,
  112. .symmetric_sample_bits = 1,
  113. .ops = &fsl_rpmsg_dai_ops,
  114. };
  115. static const struct snd_soc_component_driver fsl_component = {
  116. .name = "fsl-rpmsg",
  117. .legacy_dai_naming = 1,
  118. };
  119. static const struct fsl_rpmsg_soc_data imx7ulp_data = {
  120. .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
  121. SNDRV_PCM_RATE_48000,
  122. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  123. };
  124. static const struct fsl_rpmsg_soc_data imx8mm_data = {
  125. .rates = SNDRV_PCM_RATE_KNOT,
  126. .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
  127. SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_DSD_U8 |
  128. SNDRV_PCM_FMTBIT_DSD_U16_LE | SNDRV_PCM_FMTBIT_DSD_U32_LE,
  129. };
  130. static const struct fsl_rpmsg_soc_data imx8mn_data = {
  131. .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
  132. SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
  133. SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
  134. SNDRV_PCM_RATE_192000,
  135. .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
  136. SNDRV_PCM_FMTBIT_S32_LE,
  137. };
  138. static const struct fsl_rpmsg_soc_data imx8mp_data = {
  139. .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
  140. SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
  141. SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
  142. SNDRV_PCM_RATE_192000,
  143. .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
  144. SNDRV_PCM_FMTBIT_S32_LE,
  145. };
  146. static const struct of_device_id fsl_rpmsg_ids[] = {
  147. { .compatible = "fsl,imx7ulp-rpmsg-audio", .data = &imx7ulp_data},
  148. { .compatible = "fsl,imx8mm-rpmsg-audio", .data = &imx8mm_data},
  149. { .compatible = "fsl,imx8mn-rpmsg-audio", .data = &imx8mn_data},
  150. { .compatible = "fsl,imx8mp-rpmsg-audio", .data = &imx8mp_data},
  151. { .compatible = "fsl,imx8ulp-rpmsg-audio", .data = &imx7ulp_data},
  152. { /* sentinel */ }
  153. };
  154. MODULE_DEVICE_TABLE(of, fsl_rpmsg_ids);
  155. static int fsl_rpmsg_probe(struct platform_device *pdev)
  156. {
  157. struct device_node *np = pdev->dev.of_node;
  158. struct fsl_rpmsg *rpmsg;
  159. int ret;
  160. rpmsg = devm_kzalloc(&pdev->dev, sizeof(struct fsl_rpmsg), GFP_KERNEL);
  161. if (!rpmsg)
  162. return -ENOMEM;
  163. rpmsg->soc_data = of_device_get_match_data(&pdev->dev);
  164. fsl_rpmsg_dai.playback.rates = rpmsg->soc_data->rates;
  165. fsl_rpmsg_dai.capture.rates = rpmsg->soc_data->rates;
  166. fsl_rpmsg_dai.playback.formats = rpmsg->soc_data->formats;
  167. fsl_rpmsg_dai.capture.formats = rpmsg->soc_data->formats;
  168. if (of_property_read_bool(np, "fsl,enable-lpa")) {
  169. rpmsg->enable_lpa = 1;
  170. rpmsg->buffer_size = LPA_LARGE_BUFFER_SIZE;
  171. } else {
  172. rpmsg->buffer_size = IMX_DEFAULT_DMABUF_SIZE;
  173. }
  174. /* Get the optional clocks */
  175. rpmsg->ipg = devm_clk_get_optional(&pdev->dev, "ipg");
  176. if (IS_ERR(rpmsg->ipg))
  177. return PTR_ERR(rpmsg->ipg);
  178. rpmsg->mclk = devm_clk_get_optional(&pdev->dev, "mclk");
  179. if (IS_ERR(rpmsg->mclk))
  180. return PTR_ERR(rpmsg->mclk);
  181. rpmsg->dma = devm_clk_get_optional(&pdev->dev, "dma");
  182. if (IS_ERR(rpmsg->dma))
  183. return PTR_ERR(rpmsg->dma);
  184. rpmsg->pll8k = devm_clk_get_optional(&pdev->dev, "pll8k");
  185. if (IS_ERR(rpmsg->pll8k))
  186. return PTR_ERR(rpmsg->pll8k);
  187. rpmsg->pll11k = devm_clk_get_optional(&pdev->dev, "pll11k");
  188. if (IS_ERR(rpmsg->pll11k))
  189. return PTR_ERR(rpmsg->pll11k);
  190. platform_set_drvdata(pdev, rpmsg);
  191. pm_runtime_enable(&pdev->dev);
  192. ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
  193. &fsl_rpmsg_dai, 1);
  194. if (ret)
  195. return ret;
  196. rpmsg->card_pdev = platform_device_register_data(&pdev->dev,
  197. "imx-audio-rpmsg",
  198. PLATFORM_DEVID_NONE,
  199. NULL,
  200. 0);
  201. if (IS_ERR(rpmsg->card_pdev)) {
  202. dev_err(&pdev->dev, "failed to register rpmsg card\n");
  203. ret = PTR_ERR(rpmsg->card_pdev);
  204. return ret;
  205. }
  206. return 0;
  207. }
  208. static int fsl_rpmsg_remove(struct platform_device *pdev)
  209. {
  210. struct fsl_rpmsg *rpmsg = platform_get_drvdata(pdev);
  211. if (rpmsg->card_pdev)
  212. platform_device_unregister(rpmsg->card_pdev);
  213. return 0;
  214. }
  215. #ifdef CONFIG_PM
  216. static int fsl_rpmsg_runtime_resume(struct device *dev)
  217. {
  218. struct fsl_rpmsg *rpmsg = dev_get_drvdata(dev);
  219. int ret;
  220. ret = clk_prepare_enable(rpmsg->ipg);
  221. if (ret) {
  222. dev_err(dev, "failed to enable ipg clock: %d\n", ret);
  223. goto ipg_err;
  224. }
  225. ret = clk_prepare_enable(rpmsg->dma);
  226. if (ret) {
  227. dev_err(dev, "Failed to enable dma clock %d\n", ret);
  228. goto dma_err;
  229. }
  230. return 0;
  231. dma_err:
  232. clk_disable_unprepare(rpmsg->ipg);
  233. ipg_err:
  234. return ret;
  235. }
  236. static int fsl_rpmsg_runtime_suspend(struct device *dev)
  237. {
  238. struct fsl_rpmsg *rpmsg = dev_get_drvdata(dev);
  239. clk_disable_unprepare(rpmsg->dma);
  240. clk_disable_unprepare(rpmsg->ipg);
  241. return 0;
  242. }
  243. #endif
  244. static const struct dev_pm_ops fsl_rpmsg_pm_ops = {
  245. SET_RUNTIME_PM_OPS(fsl_rpmsg_runtime_suspend,
  246. fsl_rpmsg_runtime_resume,
  247. NULL)
  248. };
  249. static struct platform_driver fsl_rpmsg_driver = {
  250. .probe = fsl_rpmsg_probe,
  251. .remove = fsl_rpmsg_remove,
  252. .driver = {
  253. .name = "fsl_rpmsg",
  254. .pm = &fsl_rpmsg_pm_ops,
  255. .of_match_table = fsl_rpmsg_ids,
  256. },
  257. };
  258. module_platform_driver(fsl_rpmsg_driver);
  259. MODULE_DESCRIPTION("Freescale SoC Audio PRMSG CPU Interface");
  260. MODULE_AUTHOR("Shengjiu Wang <[email protected]>");
  261. MODULE_ALIAS("platform:fsl_rpmsg");
  262. MODULE_LICENSE("GPL");