bytcht_nocodec.c 5.4 KB

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