hsw_rt5640.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Sound card driver for Intel Haswell Lynx Point with Realtek 5640
  4. *
  5. * Copyright (C) 2013, Intel Corporation. All rights reserved.
  6. */
  7. #include <linux/module.h>
  8. #include <linux/platform_device.h>
  9. #include <sound/core.h>
  10. #include <sound/pcm.h>
  11. #include <sound/pcm_params.h>
  12. #include <sound/soc.h>
  13. #include <sound/soc-acpi.h>
  14. #include "../../codecs/rt5640.h"
  15. static const struct snd_soc_dapm_widget card_widgets[] = {
  16. SND_SOC_DAPM_HP("Headphones", NULL),
  17. SND_SOC_DAPM_MIC("Mic", NULL),
  18. };
  19. static const struct snd_soc_dapm_route card_routes[] = {
  20. {"Headphones", NULL, "HPOR"},
  21. {"Headphones", NULL, "HPOL"},
  22. {"IN2P", NULL, "Mic"},
  23. /* CODEC BE connections */
  24. {"SSP0 CODEC IN", NULL, "AIF1 Capture"},
  25. {"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
  26. };
  27. static int codec_link_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
  28. struct snd_pcm_hw_params *params)
  29. {
  30. struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
  31. struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
  32. /* The ADSP will convert the FE rate to 48k, stereo. */
  33. rate->min = rate->max = 48000;
  34. channels->min = channels->max = 2;
  35. /* Set SSP0 to 16 bit. */
  36. params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
  37. return 0;
  38. }
  39. static int codec_link_hw_params(struct snd_pcm_substream *substream,
  40. struct snd_pcm_hw_params *params)
  41. {
  42. struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
  43. struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
  44. int ret;
  45. ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_MCLK, 12288000, SND_SOC_CLOCK_IN);
  46. if (ret < 0) {
  47. dev_err(rtd->dev, "set codec sysclk failed: %d\n", ret);
  48. return ret;
  49. }
  50. /* Set correct codec filter for DAI format and clock config. */
  51. snd_soc_component_update_bits(codec_dai->component, 0x83, 0xffff, 0x8000);
  52. return ret;
  53. }
  54. static const struct snd_soc_ops codec_link_ops = {
  55. .hw_params = codec_link_hw_params,
  56. };
  57. SND_SOC_DAILINK_DEF(system, DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
  58. SND_SOC_DAILINK_DEF(offload0, DAILINK_COMP_ARRAY(COMP_CPU("Offload0 Pin")));
  59. SND_SOC_DAILINK_DEF(offload1, DAILINK_COMP_ARRAY(COMP_CPU("Offload1 Pin")));
  60. SND_SOC_DAILINK_DEF(loopback, DAILINK_COMP_ARRAY(COMP_CPU("Loopback Pin")));
  61. SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));
  62. SND_SOC_DAILINK_DEF(codec, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT33CA:00", "rt5640-aif1")));
  63. SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio")));
  64. SND_SOC_DAILINK_DEF(ssp0_port, DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
  65. static struct snd_soc_dai_link card_dai_links[] = {
  66. /* Front End DAI links */
  67. {
  68. .name = "System",
  69. .stream_name = "System Playback/Capture",
  70. .nonatomic = 1,
  71. .dynamic = 1,
  72. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  73. .dpcm_playback = 1,
  74. .dpcm_capture = 1,
  75. SND_SOC_DAILINK_REG(system, dummy, platform),
  76. },
  77. {
  78. .name = "Offload0",
  79. .stream_name = "Offload0 Playback",
  80. .nonatomic = 1,
  81. .dynamic = 1,
  82. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  83. .dpcm_playback = 1,
  84. SND_SOC_DAILINK_REG(offload0, dummy, platform),
  85. },
  86. {
  87. .name = "Offload1",
  88. .stream_name = "Offload1 Playback",
  89. .nonatomic = 1,
  90. .dynamic = 1,
  91. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  92. .dpcm_playback = 1,
  93. SND_SOC_DAILINK_REG(offload1, dummy, platform),
  94. },
  95. {
  96. .name = "Loopback",
  97. .stream_name = "Loopback",
  98. .nonatomic = 1,
  99. .dynamic = 1,
  100. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  101. .dpcm_capture = 1,
  102. SND_SOC_DAILINK_REG(loopback, dummy, platform),
  103. },
  104. /* Back End DAI links */
  105. {
  106. /* SSP0 - Codec */
  107. .name = "Codec",
  108. .id = 0,
  109. .nonatomic = 1,
  110. .no_pcm = 1,
  111. .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC,
  112. .ignore_pmdown_time = 1,
  113. .be_hw_params_fixup = codec_link_hw_params_fixup,
  114. .ops = &codec_link_ops,
  115. .dpcm_playback = 1,
  116. .dpcm_capture = 1,
  117. SND_SOC_DAILINK_REG(ssp0_port, codec, platform),
  118. },
  119. };
  120. static struct snd_soc_card hsw_rt5640_card = {
  121. .name = "haswell-rt5640",
  122. .owner = THIS_MODULE,
  123. .dai_link = card_dai_links,
  124. .num_links = ARRAY_SIZE(card_dai_links),
  125. .dapm_widgets = card_widgets,
  126. .num_dapm_widgets = ARRAY_SIZE(card_widgets),
  127. .dapm_routes = card_routes,
  128. .num_dapm_routes = ARRAY_SIZE(card_routes),
  129. .fully_routed = true,
  130. };
  131. static int hsw_rt5640_probe(struct platform_device *pdev)
  132. {
  133. struct snd_soc_acpi_mach *mach;
  134. struct device *dev = &pdev->dev;
  135. int ret;
  136. hsw_rt5640_card.dev = dev;
  137. mach = dev_get_platdata(dev);
  138. ret = snd_soc_fixup_dai_links_platform_name(&hsw_rt5640_card, mach->mach_params.platform);
  139. if (ret)
  140. return ret;
  141. return devm_snd_soc_register_card(dev, &hsw_rt5640_card);
  142. }
  143. static struct platform_driver hsw_rt5640_driver = {
  144. .probe = hsw_rt5640_probe,
  145. .driver = {
  146. .name = "hsw_rt5640",
  147. .pm = &snd_soc_pm_ops,
  148. },
  149. };
  150. module_platform_driver(hsw_rt5640_driver)
  151. MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
  152. MODULE_DESCRIPTION("Sound card driver for Intel Haswell Lynx Point with Realtek 5640");
  153. MODULE_LICENSE("GPL");
  154. MODULE_ALIAS("platform:hsw_rt5640");