sof_ssp_amp.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. //
  3. // Copyright(c) 2022 Intel Corporation
  4. /*
  5. * sof_ssp_amp.c - ASoc Machine driver for Intel platforms
  6. * with RT1308/CS35L41 codec.
  7. */
  8. #include <linux/acpi.h>
  9. #include <linux/delay.h>
  10. #include <linux/dmi.h>
  11. #include <linux/module.h>
  12. #include <linux/platform_device.h>
  13. #include <sound/core.h>
  14. #include <sound/jack.h>
  15. #include <sound/pcm.h>
  16. #include <sound/pcm_params.h>
  17. #include <sound/sof.h>
  18. #include "sof_board_helpers.h"
  19. #include "sof_realtek_common.h"
  20. #include "sof_cirrus_common.h"
  21. /* Driver-specific board quirks: from bit 0 to 7 */
  22. #define SOF_HDMI_PLAYBACK_PRESENT BIT(0)
  23. /* Default: SSP2 */
  24. static unsigned long sof_ssp_amp_quirk = SOF_SSP_PORT_AMP(2);
  25. static const struct dmi_system_id chromebook_platforms[] = {
  26. {
  27. .ident = "Google Chromebooks",
  28. .matches = {
  29. DMI_MATCH(DMI_SYS_VENDOR, "Google"),
  30. }
  31. },
  32. {},
  33. };
  34. static int sof_card_late_probe(struct snd_soc_card *card)
  35. {
  36. return sof_intel_board_card_late_probe(card);
  37. }
  38. static struct snd_soc_card sof_ssp_amp_card = {
  39. .name = "ssp_amp",
  40. .owner = THIS_MODULE,
  41. .fully_routed = true,
  42. .late_probe = sof_card_late_probe,
  43. };
  44. /* BE ID defined in sof-tgl-rt1308-hdmi-ssp.m4 */
  45. #define HDMI_IN_BE_ID 0
  46. #define SPK_BE_ID 2
  47. #define DMIC01_BE_ID 3
  48. #define INTEL_HDMI_BE_ID 5
  49. /* extra BE links to support no-hdmi-in boards */
  50. #define DMIC16K_BE_ID 4
  51. #define BT_OFFLOAD_BE_ID 8
  52. #define SSP_AMP_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_HDMI_IN, \
  53. SOF_LINK_AMP, \
  54. SOF_LINK_DMIC01, \
  55. SOF_LINK_DMIC16K, \
  56. SOF_LINK_IDISP_HDMI, \
  57. SOF_LINK_BT_OFFLOAD, \
  58. SOF_LINK_NONE)
  59. #define SSP_AMP_LINK_IDS SOF_LINK_ORDER(HDMI_IN_BE_ID, \
  60. SPK_BE_ID, \
  61. DMIC01_BE_ID, \
  62. DMIC16K_BE_ID, \
  63. INTEL_HDMI_BE_ID, \
  64. BT_OFFLOAD_BE_ID, \
  65. 0)
  66. static int
  67. sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card,
  68. struct sof_card_private *ctx)
  69. {
  70. int ret;
  71. ret = sof_intel_board_set_dai_link(dev, card, ctx);
  72. if (ret)
  73. return ret;
  74. if (ctx->amp_type == CODEC_NONE)
  75. return 0;
  76. if (!ctx->amp_link) {
  77. dev_err(dev, "amp link not available");
  78. return -EINVAL;
  79. }
  80. /* codec-specific fields for speaker amplifier */
  81. switch (ctx->amp_type) {
  82. case CODEC_CS35L41:
  83. cs35l41_set_dai_link(ctx->amp_link);
  84. break;
  85. case CODEC_RT1308:
  86. sof_rt1308_dai_link(ctx->amp_link);
  87. break;
  88. default:
  89. dev_err(dev, "invalid amp type %d\n", ctx->amp_type);
  90. return -EINVAL;
  91. }
  92. return 0;
  93. }
  94. static int sof_ssp_amp_probe(struct platform_device *pdev)
  95. {
  96. struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
  97. struct sof_card_private *ctx;
  98. int ret;
  99. if (pdev->id_entry && pdev->id_entry->driver_data)
  100. sof_ssp_amp_quirk = (unsigned long)pdev->id_entry->driver_data;
  101. dev_dbg(&pdev->dev, "sof_ssp_amp_quirk = %lx\n", sof_ssp_amp_quirk);
  102. /* initialize ctx with board quirk */
  103. ctx = sof_intel_board_get_ctx(&pdev->dev, sof_ssp_amp_quirk);
  104. if (!ctx)
  105. return -ENOMEM;
  106. if (!dmi_check_system(chromebook_platforms) &&
  107. (mach->mach_params.dmic_num == 0))
  108. ctx->dmic_be_num = 0;
  109. if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) {
  110. if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
  111. ctx->hdmi.idisp_codec = true;
  112. } else {
  113. ctx->hdmi_num = 0;
  114. }
  115. ctx->link_order_overwrite = SSP_AMP_LINK_ORDER;
  116. if (ctx->ssp_mask_hdmi_in) {
  117. /* the topology supports HDMI-IN uses fixed BE ID for DAI links */
  118. ctx->link_id_overwrite = SSP_AMP_LINK_IDS;
  119. }
  120. /* update dai_link */
  121. ret = sof_card_dai_links_create(&pdev->dev, &sof_ssp_amp_card, ctx);
  122. if (ret)
  123. return ret;
  124. /* update codec_conf */
  125. switch (ctx->amp_type) {
  126. case CODEC_CS35L41:
  127. cs35l41_set_codec_conf(&sof_ssp_amp_card);
  128. break;
  129. case CODEC_RT1308:
  130. case CODEC_NONE:
  131. /* no codec conf required */
  132. break;
  133. default:
  134. dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type);
  135. return -EINVAL;
  136. }
  137. sof_ssp_amp_card.dev = &pdev->dev;
  138. /* set platform name for each dailink */
  139. ret = snd_soc_fixup_dai_links_platform_name(&sof_ssp_amp_card,
  140. mach->mach_params.platform);
  141. if (ret)
  142. return ret;
  143. snd_soc_card_set_drvdata(&sof_ssp_amp_card, ctx);
  144. return devm_snd_soc_register_card(&pdev->dev, &sof_ssp_amp_card);
  145. }
  146. static const struct platform_device_id board_ids[] = {
  147. {
  148. .name = "sof_ssp_amp",
  149. },
  150. {
  151. .name = "tgl_rt1308_hdmi_ssp",
  152. .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_AMP(2) |
  153. SOF_SSP_MASK_HDMI_CAPTURE(0x22)),
  154. /* SSP 1 and SSP 5 are used for HDMI IN */
  155. },
  156. {
  157. .name = "adl_cs35l41",
  158. .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_AMP(1) |
  159. SOF_NUM_IDISP_HDMI(4) |
  160. SOF_HDMI_PLAYBACK_PRESENT |
  161. SOF_SSP_PORT_BT_OFFLOAD(2) |
  162. SOF_BT_OFFLOAD_PRESENT),
  163. },
  164. {
  165. .name = "adl_lt6911_hdmi_ssp",
  166. .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) |
  167. /* SSP 0 and SSP 2 are used for HDMI IN */
  168. SOF_HDMI_PLAYBACK_PRESENT),
  169. },
  170. {
  171. .name = "rpl_lt6911_hdmi_ssp",
  172. .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) |
  173. /* SSP 0 and SSP 2 are used for HDMI IN */
  174. SOF_HDMI_PLAYBACK_PRESENT),
  175. },
  176. {
  177. .name = "mtl_lt6911_hdmi_ssp",
  178. .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) |
  179. /* SSP 0 and SSP 2 are used for HDMI IN */
  180. SOF_HDMI_PLAYBACK_PRESENT),
  181. },
  182. {
  183. .name = "arl_lt6911_hdmi_ssp",
  184. .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) |
  185. /* SSP 0 and SSP 2 are used for HDMI IN */
  186. SOF_HDMI_PLAYBACK_PRESENT),
  187. },
  188. { }
  189. };
  190. MODULE_DEVICE_TABLE(platform, board_ids);
  191. static struct platform_driver sof_ssp_amp_driver = {
  192. .probe = sof_ssp_amp_probe,
  193. .driver = {
  194. .name = "sof_ssp_amp",
  195. .pm = &snd_soc_pm_ops,
  196. },
  197. .id_table = board_ids,
  198. };
  199. module_platform_driver(sof_ssp_amp_driver);
  200. MODULE_DESCRIPTION("ASoC Intel(R) SOF Amplifier Machine driver");
  201. MODULE_AUTHOR("Balamurugan C <balamurugan.c@intel.com>");
  202. MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
  203. MODULE_LICENSE("GPL");
  204. MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS);
  205. MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON);
  206. MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_CIRRUS_COMMON);