bxt_rt298.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. /*
  2. * Intel Broxton-P I2S Machine Driver
  3. *
  4. * Copyright (C) 2014-2016, Intel Corporation. All rights reserved.
  5. *
  6. * Modified from:
  7. * Intel Skylake I2S Machine driver
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License version
  11. * 2 as published by the Free Software Foundation.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. */
  18. #include <linux/module.h>
  19. #include <linux/platform_device.h>
  20. #include <sound/core.h>
  21. #include <sound/pcm.h>
  22. #include <sound/soc.h>
  23. #include <sound/jack.h>
  24. #include <sound/pcm_params.h>
  25. #include "../../codecs/hdac_hdmi.h"
  26. #include "../../codecs/rt298.h"
  27. static struct snd_soc_jack broxton_headset;
  28. /* Headset jack detection DAPM pins */
  29. enum {
  30. BXT_DPCM_AUDIO_PB = 0,
  31. BXT_DPCM_AUDIO_CP,
  32. BXT_DPCM_AUDIO_REF_CP,
  33. BXT_DPCM_AUDIO_DMIC_CP,
  34. BXT_DPCM_AUDIO_HDMI1_PB,
  35. BXT_DPCM_AUDIO_HDMI2_PB,
  36. BXT_DPCM_AUDIO_HDMI3_PB,
  37. };
  38. static struct snd_soc_jack_pin broxton_headset_pins[] = {
  39. {
  40. .pin = "Mic Jack",
  41. .mask = SND_JACK_MICROPHONE,
  42. },
  43. {
  44. .pin = "Headphone Jack",
  45. .mask = SND_JACK_HEADPHONE,
  46. },
  47. };
  48. static const struct snd_kcontrol_new broxton_controls[] = {
  49. SOC_DAPM_PIN_SWITCH("Speaker"),
  50. SOC_DAPM_PIN_SWITCH("Headphone Jack"),
  51. SOC_DAPM_PIN_SWITCH("Mic Jack"),
  52. };
  53. static const struct snd_soc_dapm_widget broxton_widgets[] = {
  54. SND_SOC_DAPM_HP("Headphone Jack", NULL),
  55. SND_SOC_DAPM_SPK("Speaker", NULL),
  56. SND_SOC_DAPM_MIC("Mic Jack", NULL),
  57. SND_SOC_DAPM_MIC("DMIC2", NULL),
  58. SND_SOC_DAPM_MIC("SoC DMIC", NULL),
  59. SND_SOC_DAPM_SPK("HDMI1", NULL),
  60. SND_SOC_DAPM_SPK("HDMI2", NULL),
  61. SND_SOC_DAPM_SPK("HDMI3", NULL),
  62. };
  63. static const struct snd_soc_dapm_route broxton_rt298_map[] = {
  64. /* speaker */
  65. {"Speaker", NULL, "SPOR"},
  66. {"Speaker", NULL, "SPOL"},
  67. /* HP jack connectors - unknown if we have jack detect */
  68. {"Headphone Jack", NULL, "HPO Pin"},
  69. /* other jacks */
  70. {"MIC1", NULL, "Mic Jack"},
  71. /* digital mics */
  72. {"DMIC1 Pin", NULL, "DMIC2"},
  73. {"DMic", NULL, "SoC DMIC"},
  74. {"HDMI1", NULL, "hif5 Output"},
  75. {"HDMI2", NULL, "hif6 Output"},
  76. {"HDMI3", NULL, "hif7 Output"},
  77. /* CODEC BE connections */
  78. { "AIF1 Playback", NULL, "ssp5 Tx"},
  79. { "ssp5 Tx", NULL, "codec0_out"},
  80. { "ssp5 Tx", NULL, "codec1_out"},
  81. { "codec0_in", NULL, "ssp5 Rx" },
  82. { "ssp5 Rx", NULL, "AIF1 Capture" },
  83. { "dmic01_hifi", NULL, "DMIC01 Rx" },
  84. { "DMIC01 Rx", NULL, "Capture" },
  85. { "hifi3", NULL, "iDisp3 Tx"},
  86. { "iDisp3 Tx", NULL, "iDisp3_out"},
  87. { "hifi2", NULL, "iDisp2 Tx"},
  88. { "iDisp2 Tx", NULL, "iDisp2_out"},
  89. { "hifi1", NULL, "iDisp1 Tx"},
  90. { "iDisp1 Tx", NULL, "iDisp1_out"},
  91. };
  92. static int broxton_rt298_fe_init(struct snd_soc_pcm_runtime *rtd)
  93. {
  94. struct snd_soc_dapm_context *dapm;
  95. struct snd_soc_component *component = rtd->cpu_dai->component;
  96. dapm = snd_soc_component_get_dapm(component);
  97. snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
  98. return 0;
  99. }
  100. static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd)
  101. {
  102. struct snd_soc_codec *codec = rtd->codec;
  103. int ret = 0;
  104. ret = snd_soc_card_jack_new(rtd->card, "Headset",
  105. SND_JACK_HEADSET | SND_JACK_BTN_0,
  106. &broxton_headset,
  107. broxton_headset_pins, ARRAY_SIZE(broxton_headset_pins));
  108. if (ret)
  109. return ret;
  110. rt298_mic_detect(codec, &broxton_headset);
  111. snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
  112. return 0;
  113. }
  114. static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd)
  115. {
  116. struct snd_soc_dai *dai = rtd->codec_dai;
  117. return hdac_hdmi_jack_init(dai, BXT_DPCM_AUDIO_HDMI1_PB + dai->id);
  118. }
  119. static int broxton_ssp5_fixup(struct snd_soc_pcm_runtime *rtd,
  120. struct snd_pcm_hw_params *params)
  121. {
  122. struct snd_interval *rate = hw_param_interval(params,
  123. SNDRV_PCM_HW_PARAM_RATE);
  124. struct snd_interval *channels = hw_param_interval(params,
  125. SNDRV_PCM_HW_PARAM_CHANNELS);
  126. struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
  127. /* The ADSP will covert the FE rate to 48k, stereo */
  128. rate->min = rate->max = 48000;
  129. channels->min = channels->max = 2;
  130. /* set SSP5 to 24 bit */
  131. snd_mask_none(fmt);
  132. snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
  133. return 0;
  134. }
  135. static int broxton_rt298_hw_params(struct snd_pcm_substream *substream,
  136. struct snd_pcm_hw_params *params)
  137. {
  138. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  139. struct snd_soc_dai *codec_dai = rtd->codec_dai;
  140. int ret;
  141. ret = snd_soc_dai_set_sysclk(codec_dai, RT298_SCLK_S_PLL,
  142. 19200000, SND_SOC_CLOCK_IN);
  143. if (ret < 0) {
  144. dev_err(rtd->dev, "can't set codec sysclk configuration\n");
  145. return ret;
  146. }
  147. return ret;
  148. }
  149. static const struct snd_soc_ops broxton_rt298_ops = {
  150. .hw_params = broxton_rt298_hw_params,
  151. };
  152. static unsigned int rates[] = {
  153. 48000,
  154. };
  155. static struct snd_pcm_hw_constraint_list constraints_rates = {
  156. .count = ARRAY_SIZE(rates),
  157. .list = rates,
  158. .mask = 0,
  159. };
  160. static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
  161. struct snd_pcm_hw_params *params)
  162. {
  163. struct snd_interval *channels = hw_param_interval(params,
  164. SNDRV_PCM_HW_PARAM_CHANNELS);
  165. if (params_channels(params) == 2)
  166. channels->min = channels->max = 2;
  167. else
  168. channels->min = channels->max = 4;
  169. return 0;
  170. }
  171. static unsigned int channels_dmic[] = {
  172. 2, 4,
  173. };
  174. static struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
  175. .count = ARRAY_SIZE(channels_dmic),
  176. .list = channels_dmic,
  177. .mask = 0,
  178. };
  179. static int broxton_dmic_startup(struct snd_pcm_substream *substream)
  180. {
  181. struct snd_pcm_runtime *runtime = substream->runtime;
  182. runtime->hw.channels_max = 4;
  183. snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
  184. &constraints_dmic_channels);
  185. return snd_pcm_hw_constraint_list(substream->runtime, 0,
  186. SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
  187. }
  188. static const struct snd_soc_ops broxton_dmic_ops = {
  189. .startup = broxton_dmic_startup,
  190. };
  191. static unsigned int channels[] = {
  192. 2,
  193. };
  194. static struct snd_pcm_hw_constraint_list constraints_channels = {
  195. .count = ARRAY_SIZE(channels),
  196. .list = channels,
  197. .mask = 0,
  198. };
  199. static int bxt_fe_startup(struct snd_pcm_substream *substream)
  200. {
  201. struct snd_pcm_runtime *runtime = substream->runtime;
  202. /*
  203. * on this platform for PCM device we support:
  204. * 48Khz
  205. * stereo
  206. */
  207. runtime->hw.channels_max = 2;
  208. snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
  209. &constraints_channels);
  210. snd_pcm_hw_constraint_list(runtime, 0,
  211. SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
  212. return 0;
  213. }
  214. static const struct snd_soc_ops broxton_rt286_fe_ops = {
  215. .startup = bxt_fe_startup,
  216. };
  217. /* broxton digital audio interface glue - connects codec <--> CPU */
  218. static struct snd_soc_dai_link broxton_rt298_dais[] = {
  219. /* Front End DAI links */
  220. [BXT_DPCM_AUDIO_PB] =
  221. {
  222. .name = "Bxt Audio Port",
  223. .stream_name = "Audio",
  224. .cpu_dai_name = "System Pin",
  225. .platform_name = "0000:00:0e.0",
  226. .nonatomic = 1,
  227. .dynamic = 1,
  228. .codec_name = "snd-soc-dummy",
  229. .codec_dai_name = "snd-soc-dummy-dai",
  230. .init = broxton_rt298_fe_init,
  231. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  232. .dpcm_playback = 1,
  233. .ops = &broxton_rt286_fe_ops,
  234. },
  235. [BXT_DPCM_AUDIO_CP] =
  236. {
  237. .name = "Bxt Audio Capture Port",
  238. .stream_name = "Audio Record",
  239. .cpu_dai_name = "System Pin",
  240. .platform_name = "0000:00:0e.0",
  241. .nonatomic = 1,
  242. .dynamic = 1,
  243. .codec_name = "snd-soc-dummy",
  244. .codec_dai_name = "snd-soc-dummy-dai",
  245. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  246. .dpcm_capture = 1,
  247. .ops = &broxton_rt286_fe_ops,
  248. },
  249. [BXT_DPCM_AUDIO_REF_CP] =
  250. {
  251. .name = "Bxt Audio Reference cap",
  252. .stream_name = "refcap",
  253. .cpu_dai_name = "Reference Pin",
  254. .codec_name = "snd-soc-dummy",
  255. .codec_dai_name = "snd-soc-dummy-dai",
  256. .platform_name = "0000:00:0e.0",
  257. .init = NULL,
  258. .dpcm_capture = 1,
  259. .nonatomic = 1,
  260. .dynamic = 1,
  261. },
  262. [BXT_DPCM_AUDIO_DMIC_CP] =
  263. {
  264. .name = "Bxt Audio DMIC cap",
  265. .stream_name = "dmiccap",
  266. .cpu_dai_name = "DMIC Pin",
  267. .codec_name = "snd-soc-dummy",
  268. .codec_dai_name = "snd-soc-dummy-dai",
  269. .platform_name = "0000:00:0e.0",
  270. .init = NULL,
  271. .dpcm_capture = 1,
  272. .nonatomic = 1,
  273. .dynamic = 1,
  274. .ops = &broxton_dmic_ops,
  275. },
  276. [BXT_DPCM_AUDIO_HDMI1_PB] =
  277. {
  278. .name = "Bxt HDMI Port1",
  279. .stream_name = "Hdmi1",
  280. .cpu_dai_name = "HDMI1 Pin",
  281. .codec_name = "snd-soc-dummy",
  282. .codec_dai_name = "snd-soc-dummy-dai",
  283. .platform_name = "0000:00:0e.0",
  284. .dpcm_playback = 1,
  285. .init = NULL,
  286. .nonatomic = 1,
  287. .dynamic = 1,
  288. },
  289. [BXT_DPCM_AUDIO_HDMI2_PB] =
  290. {
  291. .name = "Bxt HDMI Port2",
  292. .stream_name = "Hdmi2",
  293. .cpu_dai_name = "HDMI2 Pin",
  294. .codec_name = "snd-soc-dummy",
  295. .codec_dai_name = "snd-soc-dummy-dai",
  296. .platform_name = "0000:00:0e.0",
  297. .dpcm_playback = 1,
  298. .init = NULL,
  299. .nonatomic = 1,
  300. .dynamic = 1,
  301. },
  302. [BXT_DPCM_AUDIO_HDMI3_PB] =
  303. {
  304. .name = "Bxt HDMI Port3",
  305. .stream_name = "Hdmi3",
  306. .cpu_dai_name = "HDMI3 Pin",
  307. .codec_name = "snd-soc-dummy",
  308. .codec_dai_name = "snd-soc-dummy-dai",
  309. .platform_name = "0000:00:0e.0",
  310. .dpcm_playback = 1,
  311. .init = NULL,
  312. .nonatomic = 1,
  313. .dynamic = 1,
  314. },
  315. /* Back End DAI links */
  316. {
  317. /* SSP5 - Codec */
  318. .name = "SSP5-Codec",
  319. .id = 0,
  320. .cpu_dai_name = "SSP5 Pin",
  321. .platform_name = "0000:00:0e.0",
  322. .no_pcm = 1,
  323. .codec_name = "i2c-INT343A:00",
  324. .codec_dai_name = "rt298-aif1",
  325. .init = broxton_rt298_codec_init,
  326. .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF |
  327. SND_SOC_DAIFMT_CBS_CFS,
  328. .ignore_pmdown_time = 1,
  329. .be_hw_params_fixup = broxton_ssp5_fixup,
  330. .ops = &broxton_rt298_ops,
  331. .dpcm_playback = 1,
  332. .dpcm_capture = 1,
  333. },
  334. {
  335. .name = "dmic01",
  336. .id = 1,
  337. .cpu_dai_name = "DMIC01 Pin",
  338. .codec_name = "dmic-codec",
  339. .codec_dai_name = "dmic-hifi",
  340. .platform_name = "0000:00:0e.0",
  341. .be_hw_params_fixup = broxton_dmic_fixup,
  342. .ignore_suspend = 1,
  343. .dpcm_capture = 1,
  344. .no_pcm = 1,
  345. },
  346. {
  347. .name = "iDisp1",
  348. .id = 3,
  349. .cpu_dai_name = "iDisp1 Pin",
  350. .codec_name = "ehdaudio0D2",
  351. .codec_dai_name = "intel-hdmi-hifi1",
  352. .platform_name = "0000:00:0e.0",
  353. .init = broxton_hdmi_init,
  354. .dpcm_playback = 1,
  355. .no_pcm = 1,
  356. },
  357. {
  358. .name = "iDisp2",
  359. .id = 4,
  360. .cpu_dai_name = "iDisp2 Pin",
  361. .codec_name = "ehdaudio0D2",
  362. .codec_dai_name = "intel-hdmi-hifi2",
  363. .platform_name = "0000:00:0e.0",
  364. .init = broxton_hdmi_init,
  365. .dpcm_playback = 1,
  366. .no_pcm = 1,
  367. },
  368. {
  369. .name = "iDisp3",
  370. .id = 5,
  371. .cpu_dai_name = "iDisp3 Pin",
  372. .codec_name = "ehdaudio0D2",
  373. .codec_dai_name = "intel-hdmi-hifi3",
  374. .platform_name = "0000:00:0e.0",
  375. .init = broxton_hdmi_init,
  376. .dpcm_playback = 1,
  377. .no_pcm = 1,
  378. },
  379. };
  380. /* broxton audio machine driver for SPT + RT298S */
  381. static struct snd_soc_card broxton_rt298 = {
  382. .name = "broxton-rt298",
  383. .owner = THIS_MODULE,
  384. .dai_link = broxton_rt298_dais,
  385. .num_links = ARRAY_SIZE(broxton_rt298_dais),
  386. .controls = broxton_controls,
  387. .num_controls = ARRAY_SIZE(broxton_controls),
  388. .dapm_widgets = broxton_widgets,
  389. .num_dapm_widgets = ARRAY_SIZE(broxton_widgets),
  390. .dapm_routes = broxton_rt298_map,
  391. .num_dapm_routes = ARRAY_SIZE(broxton_rt298_map),
  392. .fully_routed = true,
  393. };
  394. static int broxton_audio_probe(struct platform_device *pdev)
  395. {
  396. broxton_rt298.dev = &pdev->dev;
  397. return devm_snd_soc_register_card(&pdev->dev, &broxton_rt298);
  398. }
  399. static struct platform_driver broxton_audio = {
  400. .probe = broxton_audio_probe,
  401. .driver = {
  402. .name = "bxt_alc298s_i2s",
  403. .pm = &snd_soc_pm_ops,
  404. },
  405. };
  406. module_platform_driver(broxton_audio)
  407. /* Module information */
  408. MODULE_AUTHOR("Ramesh Babu <Ramesh.Babu@intel.com>");
  409. MODULE_AUTHOR("Senthilnathan Veppur <senthilnathanx.veppur@intel.com>");
  410. MODULE_DESCRIPTION("Intel SST Audio for Broxton");
  411. MODULE_LICENSE("GPL v2");
  412. MODULE_ALIAS("platform:bxt_alc298s_i2s");