sof-of-dev.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
  2. //
  3. // Copyright 2019 NXP
  4. //
  5. // Author: Daniel Baluta <daniel.baluta@nxp.com>
  6. //
  7. #include <linux/firmware.h>
  8. #include <linux/module.h>
  9. #include <linux/pm_runtime.h>
  10. #include <sound/sof.h>
  11. #include "ops.h"
  12. extern struct snd_sof_dsp_ops sof_imx8_ops;
  13. extern struct snd_sof_dsp_ops sof_imx8x_ops;
  14. extern struct snd_sof_dsp_ops sof_imx8m_ops;
  15. /* platform specific devices */
  16. #if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8)
  17. static struct sof_dev_desc sof_of_imx8qxp_desc = {
  18. .default_fw_path = "imx/sof",
  19. .default_tplg_path = "imx/sof-tplg",
  20. .default_fw_filename = "sof-imx8x.ri",
  21. .nocodec_tplg_filename = "sof-imx8-nocodec.tplg",
  22. .ops = &sof_imx8x_ops,
  23. };
  24. static struct sof_dev_desc sof_of_imx8qm_desc = {
  25. .default_fw_path = "imx/sof",
  26. .default_tplg_path = "imx/sof-tplg",
  27. .default_fw_filename = "sof-imx8.ri",
  28. .nocodec_tplg_filename = "sof-imx8-nocodec.tplg",
  29. .ops = &sof_imx8_ops,
  30. };
  31. #endif
  32. #if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8M)
  33. static struct sof_dev_desc sof_of_imx8mp_desc = {
  34. .default_fw_path = "imx/sof",
  35. .default_tplg_path = "imx/sof-tplg",
  36. .default_fw_filename = "sof-imx8m.ri",
  37. .nocodec_tplg_filename = "sof-imx8-nocodec.tplg",
  38. .ops = &sof_imx8m_ops,
  39. };
  40. #endif
  41. static const struct dev_pm_ops sof_of_pm = {
  42. .prepare = snd_sof_prepare,
  43. .complete = snd_sof_complete,
  44. SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume)
  45. SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume,
  46. NULL)
  47. };
  48. static void sof_of_probe_complete(struct device *dev)
  49. {
  50. /* allow runtime_pm */
  51. pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS);
  52. pm_runtime_use_autosuspend(dev);
  53. pm_runtime_set_active(dev);
  54. pm_runtime_enable(dev);
  55. pm_runtime_mark_last_busy(dev);
  56. pm_runtime_put_autosuspend(dev);
  57. }
  58. static int sof_of_probe(struct platform_device *pdev)
  59. {
  60. struct device *dev = &pdev->dev;
  61. const struct sof_dev_desc *desc;
  62. struct snd_sof_pdata *sof_pdata;
  63. const struct snd_sof_dsp_ops *ops;
  64. int ret;
  65. dev_info(&pdev->dev, "DT DSP detected");
  66. sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL);
  67. if (!sof_pdata)
  68. return -ENOMEM;
  69. desc = device_get_match_data(dev);
  70. if (!desc)
  71. return -ENODEV;
  72. /* get ops for platform */
  73. ops = desc->ops;
  74. if (!ops) {
  75. dev_err(dev, "error: no matching DT descriptor ops\n");
  76. return -ENODEV;
  77. }
  78. sof_pdata->desc = desc;
  79. sof_pdata->dev = &pdev->dev;
  80. sof_pdata->fw_filename = desc->default_fw_filename;
  81. /* TODO: read alternate fw and tplg filenames from DT */
  82. sof_pdata->fw_filename_prefix = sof_pdata->desc->default_fw_path;
  83. sof_pdata->tplg_filename_prefix = sof_pdata->desc->default_tplg_path;
  84. #if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)
  85. /* set callback to enable runtime_pm */
  86. sof_pdata->sof_probe_complete = sof_of_probe_complete;
  87. #endif
  88. /* call sof helper for DSP hardware probe */
  89. ret = snd_sof_device_probe(dev, sof_pdata);
  90. if (ret) {
  91. dev_err(dev, "error: failed to probe DSP hardware\n");
  92. return ret;
  93. }
  94. #if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)
  95. sof_of_probe_complete(dev);
  96. #endif
  97. return ret;
  98. }
  99. static int sof_of_remove(struct platform_device *pdev)
  100. {
  101. pm_runtime_disable(&pdev->dev);
  102. /* call sof helper for DSP hardware remove */
  103. snd_sof_device_remove(&pdev->dev);
  104. return 0;
  105. }
  106. static const struct of_device_id sof_of_ids[] = {
  107. #if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8)
  108. { .compatible = "fsl,imx8qxp-dsp", .data = &sof_of_imx8qxp_desc},
  109. { .compatible = "fsl,imx8qm-dsp", .data = &sof_of_imx8qm_desc},
  110. #endif
  111. #if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8M)
  112. { .compatible = "fsl,imx8mp-dsp", .data = &sof_of_imx8mp_desc},
  113. #endif
  114. { }
  115. };
  116. MODULE_DEVICE_TABLE(of, sof_of_ids);
  117. /* DT driver definition */
  118. static struct platform_driver snd_sof_of_driver = {
  119. .probe = sof_of_probe,
  120. .remove = sof_of_remove,
  121. .driver = {
  122. .name = "sof-audio-of",
  123. .pm = &sof_of_pm,
  124. .of_match_table = sof_of_ids,
  125. },
  126. };
  127. module_platform_driver(snd_sof_of_driver);
  128. MODULE_LICENSE("Dual BSD/GPL");