bytcht_nocodec.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * bytcht_nocodec.c - ASoc Machine driver for MinnowBoard Max and Up
  4. * to make I2S signals observable on the Low-Speed connector. Audio codec
  5. * is not managed by ASoC/DAPM
  6. *
  7. * Copyright (C) 2015-2017 Intel Corp
  8. *
  9. * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  10. *
  11. * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  12. */
  13. #include <linux/module.h>
  14. #include <sound/pcm.h>
  15. #include <sound/pcm_params.h>
  16. #include <sound/soc.h>
  17. #include "../atom/sst-atom-controls.h"
  18. static const struct snd_soc_dapm_widget widgets[] = {
  19. SND_SOC_DAPM_MIC("Mic", NULL),
  20. SND_SOC_DAPM_SPK("Speaker", NULL),
  21. };
  22. static const struct snd_kcontrol_new controls[] = {
  23. SOC_DAPM_PIN_SWITCH("Mic"),
  24. SOC_DAPM_PIN_SWITCH("Speaker"),
  25. };
  26. static const struct snd_soc_dapm_route audio_map[] = {
  27. {"ssp2 Tx", NULL, "codec_out0"},
  28. {"ssp2 Tx", NULL, "codec_out1"},
  29. {"codec_in0", NULL, "ssp2 Rx"},
  30. {"codec_in1", NULL, "ssp2 Rx"},
  31. {"ssp2 Rx", NULL, "Mic"},
  32. {"Speaker", NULL, "ssp2 Tx"},
  33. };
  34. static int codec_fixup(struct snd_soc_pcm_runtime *rtd,
  35. struct snd_pcm_hw_params *params)
  36. {
  37. struct snd_interval *rate = hw_param_interval(params,
  38. SNDRV_PCM_HW_PARAM_RATE);
  39. struct snd_interval *channels = hw_param_interval(params,
  40. SNDRV_PCM_HW_PARAM_CHANNELS);
  41. int ret;
  42. /* The DSP will convert the FE rate to 48k, stereo, 24bits */
  43. rate->min = rate->max = 48000;
  44. channels->min = channels->max = 2;
  45. /* set SSP2 to 24-bit */
  46. params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
  47. /*
  48. * Default mode for SSP configuration is TDM 4 slot, override config
  49. * with explicit setting to I2S 2ch 24-bit. The word length is set with
  50. * dai_set_tdm_slot() since there is no other API exposed
  51. */
  52. ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
  53. SND_SOC_DAIFMT_I2S |
  54. SND_SOC_DAIFMT_NB_NF |
  55. SND_SOC_DAIFMT_BP_FP);
  56. if (ret < 0) {
  57. dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
  58. return ret;
  59. }
  60. ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 24);
  61. if (ret < 0) {
  62. dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
  63. return ret;
  64. }
  65. return 0;
  66. }
  67. static const unsigned int rates_48000[] = {
  68. 48000,
  69. };
  70. static const struct snd_pcm_hw_constraint_list constraints_48000 = {
  71. .count = ARRAY_SIZE(rates_48000),
  72. .list = rates_48000,
  73. };
  74. static int aif1_startup(struct snd_pcm_substream *substream)
  75. {
  76. return snd_pcm_hw_constraint_list(substream->runtime, 0,
  77. SNDRV_PCM_HW_PARAM_RATE,
  78. &constraints_48000);
  79. }
  80. static const struct snd_soc_ops aif1_ops = {
  81. .startup = aif1_startup,
  82. };
  83. SND_SOC_DAILINK_DEF(dummy,
  84. DAILINK_COMP_ARRAY(COMP_DUMMY()));
  85. SND_SOC_DAILINK_DEF(media,
  86. DAILINK_COMP_ARRAY(COMP_CPU("media-cpu-dai")));
  87. SND_SOC_DAILINK_DEF(deepbuffer,
  88. DAILINK_COMP_ARRAY(COMP_CPU("deepbuffer-cpu-dai")));
  89. SND_SOC_DAILINK_DEF(ssp2_port,
  90. DAILINK_COMP_ARRAY(COMP_CPU("ssp2-port")));
  91. SND_SOC_DAILINK_DEF(platform,
  92. DAILINK_COMP_ARRAY(COMP_PLATFORM("sst-mfld-platform")));
  93. static struct snd_soc_dai_link dais[] = {
  94. [MERR_DPCM_AUDIO] = {
  95. .name = "Audio Port",
  96. .stream_name = "Audio",
  97. .ignore_suspend = 1,
  98. .nonatomic = true,
  99. .dynamic = 1,
  100. .dpcm_playback = 1,
  101. .dpcm_capture = 1,
  102. .ops = &aif1_ops,
  103. SND_SOC_DAILINK_REG(media, dummy, platform),
  104. },
  105. [MERR_DPCM_DEEP_BUFFER] = {
  106. .name = "Deep-Buffer Audio Port",
  107. .stream_name = "Deep-Buffer Audio",
  108. .ignore_suspend = 1,
  109. .nonatomic = true,
  110. .dynamic = 1,
  111. .dpcm_playback = 1,
  112. .ops = &aif1_ops,
  113. SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
  114. },
  115. /* CODEC<->CODEC link */
  116. /* back ends */
  117. {
  118. .name = "SSP2-LowSpeed Connector",
  119. .id = 0,
  120. .no_pcm = 1,
  121. .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
  122. | SND_SOC_DAIFMT_CBC_CFC,
  123. .be_hw_params_fixup = codec_fixup,
  124. .ignore_suspend = 1,
  125. .dpcm_playback = 1,
  126. .dpcm_capture = 1,
  127. SND_SOC_DAILINK_REG(ssp2_port, dummy, platform),
  128. },
  129. };
  130. /* SoC card */
  131. static struct snd_soc_card bytcht_nocodec_card = {
  132. .name = "bytcht-nocodec",
  133. .owner = THIS_MODULE,
  134. .dai_link = dais,
  135. .num_links = ARRAY_SIZE(dais),
  136. .dapm_widgets = widgets,
  137. .num_dapm_widgets = ARRAY_SIZE(widgets),
  138. .dapm_routes = audio_map,
  139. .num_dapm_routes = ARRAY_SIZE(audio_map),
  140. .controls = controls,
  141. .num_controls = ARRAY_SIZE(controls),
  142. .fully_routed = true,
  143. };
  144. static int snd_bytcht_nocodec_mc_probe(struct platform_device *pdev)
  145. {
  146. int ret_val = 0;
  147. /* register the soc card */
  148. bytcht_nocodec_card.dev = &pdev->dev;
  149. ret_val = devm_snd_soc_register_card(&pdev->dev, &bytcht_nocodec_card);
  150. if (ret_val) {
  151. dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n",
  152. ret_val);
  153. return ret_val;
  154. }
  155. platform_set_drvdata(pdev, &bytcht_nocodec_card);
  156. return ret_val;
  157. }
  158. static struct platform_driver snd_bytcht_nocodec_mc_driver = {
  159. .driver = {
  160. .name = "bytcht_nocodec",
  161. },
  162. .probe = snd_bytcht_nocodec_mc_probe,
  163. };
  164. module_platform_driver(snd_bytcht_nocodec_mc_driver);
  165. MODULE_DESCRIPTION("ASoC Intel(R) Baytrail/Cherrytrail Nocodec Machine driver");
  166. MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>");
  167. MODULE_LICENSE("GPL v2");
  168. MODULE_ALIAS("platform:bytcht_nocodec");