bxt_da7219_max98357a.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. /*
  2. * Intel Broxton-P I2S Machine Driver
  3. *
  4. * Copyright (C) 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/jack.h>
  22. #include <sound/pcm.h>
  23. #include <sound/pcm_params.h>
  24. #include <sound/soc.h>
  25. #include "../../codecs/hdac_hdmi.h"
  26. #include "../../codecs/da7219.h"
  27. #include "../../codecs/da7219-aad.h"
  28. #define BXT_DIALOG_CODEC_DAI "da7219-hifi"
  29. #define BXT_MAXIM_CODEC_DAI "HiFi"
  30. #define DUAL_CHANNEL 2
  31. static struct snd_soc_jack broxton_headset;
  32. enum {
  33. BXT_DPCM_AUDIO_PB = 0,
  34. BXT_DPCM_AUDIO_CP,
  35. BXT_DPCM_AUDIO_REF_CP,
  36. BXT_DPCM_AUDIO_DMIC_CP,
  37. BXT_DPCM_AUDIO_HDMI1_PB,
  38. BXT_DPCM_AUDIO_HDMI2_PB,
  39. BXT_DPCM_AUDIO_HDMI3_PB,
  40. };
  41. static const struct snd_kcontrol_new broxton_controls[] = {
  42. SOC_DAPM_PIN_SWITCH("Headphone Jack"),
  43. SOC_DAPM_PIN_SWITCH("Headset Mic"),
  44. SOC_DAPM_PIN_SWITCH("Spk"),
  45. };
  46. static const struct snd_soc_dapm_widget broxton_widgets[] = {
  47. SND_SOC_DAPM_HP("Headphone Jack", NULL),
  48. SND_SOC_DAPM_MIC("Headset Mic", NULL),
  49. SND_SOC_DAPM_SPK("Spk", NULL),
  50. SND_SOC_DAPM_MIC("SoC DMIC", NULL),
  51. SND_SOC_DAPM_SPK("HDMI1", NULL),
  52. SND_SOC_DAPM_SPK("HDMI2", NULL),
  53. SND_SOC_DAPM_SPK("HDMI3", NULL),
  54. };
  55. static const struct snd_soc_dapm_route broxton_map[] = {
  56. /* HP jack connectors - unknown if we have jack detection */
  57. {"Headphone Jack", NULL, "HPL"},
  58. {"Headphone Jack", NULL, "HPR"},
  59. /* speaker */
  60. {"Spk", NULL, "Speaker"},
  61. /* other jacks */
  62. {"MIC", NULL, "Headset Mic"},
  63. /* digital mics */
  64. {"DMic", NULL, "SoC DMIC"},
  65. /* CODEC BE connections */
  66. {"HiFi Playback", NULL, "ssp5 Tx"},
  67. {"ssp5 Tx", NULL, "codec0_out"},
  68. {"Playback", NULL, "ssp1 Tx"},
  69. {"ssp1 Tx", NULL, "codec1_out"},
  70. {"codec0_in", NULL, "ssp1 Rx"},
  71. {"ssp1 Rx", NULL, "Capture"},
  72. {"HDMI1", NULL, "hif5 Output"},
  73. {"HDMI2", NULL, "hif6 Output"},
  74. {"HDMI3", NULL, "hif7 Output"},
  75. {"hifi3", NULL, "iDisp3 Tx"},
  76. {"iDisp3 Tx", NULL, "iDisp3_out"},
  77. {"hifi2", NULL, "iDisp2 Tx"},
  78. {"iDisp2 Tx", NULL, "iDisp2_out"},
  79. {"hifi1", NULL, "iDisp1 Tx"},
  80. {"iDisp1 Tx", NULL, "iDisp1_out"},
  81. /* DMIC */
  82. {"dmic01_hifi", NULL, "DMIC01 Rx"},
  83. {"DMIC01 Rx", NULL, "DMIC AIF"},
  84. };
  85. static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
  86. struct snd_pcm_hw_params *params)
  87. {
  88. struct snd_interval *rate = hw_param_interval(params,
  89. SNDRV_PCM_HW_PARAM_RATE);
  90. struct snd_interval *channels = hw_param_interval(params,
  91. SNDRV_PCM_HW_PARAM_CHANNELS);
  92. struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
  93. /* The ADSP will convert the FE rate to 48k, stereo */
  94. rate->min = rate->max = 48000;
  95. channels->min = channels->max = DUAL_CHANNEL;
  96. /* set SSP to 24 bit */
  97. snd_mask_none(fmt);
  98. snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
  99. return 0;
  100. }
  101. static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
  102. {
  103. int ret;
  104. struct snd_soc_codec *codec = rtd->codec;
  105. /*
  106. * Headset buttons map to the google Reference headset.
  107. * These can be configured by userspace.
  108. */
  109. ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
  110. SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
  111. SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
  112. &broxton_headset, NULL, 0);
  113. if (ret) {
  114. dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
  115. return ret;
  116. }
  117. da7219_aad_jack_det(codec, &broxton_headset);
  118. snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
  119. return ret;
  120. }
  121. static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd)
  122. {
  123. struct snd_soc_dai *dai = rtd->codec_dai;
  124. return hdac_hdmi_jack_init(dai, BXT_DPCM_AUDIO_HDMI1_PB + dai->id);
  125. }
  126. static int broxton_da7219_fe_init(struct snd_soc_pcm_runtime *rtd)
  127. {
  128. struct snd_soc_dapm_context *dapm;
  129. struct snd_soc_component *component = rtd->cpu_dai->component;
  130. dapm = snd_soc_component_get_dapm(component);
  131. snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
  132. return 0;
  133. }
  134. static unsigned int rates[] = {
  135. 48000,
  136. };
  137. static struct snd_pcm_hw_constraint_list constraints_rates = {
  138. .count = ARRAY_SIZE(rates),
  139. .list = rates,
  140. .mask = 0,
  141. };
  142. static unsigned int channels[] = {
  143. DUAL_CHANNEL,
  144. };
  145. static struct snd_pcm_hw_constraint_list constraints_channels = {
  146. .count = ARRAY_SIZE(channels),
  147. .list = channels,
  148. .mask = 0,
  149. };
  150. static int bxt_fe_startup(struct snd_pcm_substream *substream)
  151. {
  152. struct snd_pcm_runtime *runtime = substream->runtime;
  153. /*
  154. * On this platform for PCM device we support,
  155. * 48Khz
  156. * stereo
  157. * 16 bit audio
  158. */
  159. runtime->hw.channels_max = DUAL_CHANNEL;
  160. snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
  161. &constraints_channels);
  162. runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
  163. snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
  164. snd_pcm_hw_constraint_list(runtime, 0,
  165. SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
  166. return 0;
  167. }
  168. static const struct snd_soc_ops broxton_da7219_fe_ops = {
  169. .startup = bxt_fe_startup,
  170. };
  171. static int broxton_da7219_hw_params(struct snd_pcm_substream *substream,
  172. struct snd_pcm_hw_params *params)
  173. {
  174. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  175. struct snd_soc_dai *codec_dai = rtd->codec_dai;
  176. int ret;
  177. ret = snd_soc_dai_set_sysclk(codec_dai,
  178. DA7219_CLKSRC_MCLK, 19200000, SND_SOC_CLOCK_IN);
  179. if (ret < 0)
  180. dev_err(codec_dai->dev, "can't set codec sysclk configuration\n");
  181. ret = snd_soc_dai_set_pll(codec_dai, 0,
  182. DA7219_SYSCLK_PLL_SRM, 0, DA7219_PLL_FREQ_OUT_98304);
  183. if (ret < 0) {
  184. dev_err(codec_dai->dev, "failed to start PLL: %d\n", ret);
  185. return -EIO;
  186. }
  187. return ret;
  188. }
  189. static int broxton_da7219_hw_free(struct snd_pcm_substream *substream)
  190. {
  191. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  192. struct snd_soc_dai *codec_dai = rtd->codec_dai;
  193. int ret;
  194. ret = snd_soc_dai_set_pll(codec_dai, 0,
  195. DA7219_SYSCLK_MCLK, 0, 0);
  196. if (ret < 0) {
  197. dev_err(codec_dai->dev, "failed to stop PLL: %d\n", ret);
  198. return -EIO;
  199. }
  200. return ret;
  201. }
  202. static struct snd_soc_ops broxton_da7219_ops = {
  203. .hw_params = broxton_da7219_hw_params,
  204. .hw_free = broxton_da7219_hw_free,
  205. };
  206. static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
  207. struct snd_pcm_hw_params *params)
  208. {
  209. struct snd_interval *channels = hw_param_interval(params,
  210. SNDRV_PCM_HW_PARAM_CHANNELS);
  211. channels->min = channels->max = DUAL_CHANNEL;
  212. return 0;
  213. }
  214. static int broxton_dmic_startup(struct snd_pcm_substream *substream)
  215. {
  216. struct snd_pcm_runtime *runtime = substream->runtime;
  217. runtime->hw.channels_max = DUAL_CHANNEL;
  218. snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
  219. &constraints_channels);
  220. return snd_pcm_hw_constraint_list(substream->runtime, 0,
  221. SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
  222. }
  223. static const struct snd_soc_ops broxton_dmic_ops = {
  224. .startup = broxton_dmic_startup,
  225. };
  226. static const unsigned int rates_16000[] = {
  227. 16000,
  228. };
  229. static const struct snd_pcm_hw_constraint_list constraints_16000 = {
  230. .count = ARRAY_SIZE(rates_16000),
  231. .list = rates_16000,
  232. };
  233. static int broxton_refcap_startup(struct snd_pcm_substream *substream)
  234. {
  235. return snd_pcm_hw_constraint_list(substream->runtime, 0,
  236. SNDRV_PCM_HW_PARAM_RATE,
  237. &constraints_16000);
  238. };
  239. static struct snd_soc_ops broxton_refcap_ops = {
  240. .startup = broxton_refcap_startup,
  241. };
  242. /* broxton digital audio interface glue - connects codec <--> CPU */
  243. static struct snd_soc_dai_link broxton_dais[] = {
  244. /* Front End DAI links */
  245. [BXT_DPCM_AUDIO_PB] =
  246. {
  247. .name = "Bxt Audio Port",
  248. .stream_name = "Audio",
  249. .cpu_dai_name = "System Pin",
  250. .platform_name = "0000:00:0e.0",
  251. .dynamic = 1,
  252. .codec_name = "snd-soc-dummy",
  253. .codec_dai_name = "snd-soc-dummy-dai",
  254. .nonatomic = 1,
  255. .init = broxton_da7219_fe_init,
  256. .trigger = {
  257. SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  258. .dpcm_playback = 1,
  259. .ops = &broxton_da7219_fe_ops,
  260. },
  261. [BXT_DPCM_AUDIO_CP] =
  262. {
  263. .name = "Bxt Audio Capture Port",
  264. .stream_name = "Audio Record",
  265. .cpu_dai_name = "System Pin",
  266. .platform_name = "0000:00:0e.0",
  267. .dynamic = 1,
  268. .codec_name = "snd-soc-dummy",
  269. .codec_dai_name = "snd-soc-dummy-dai",
  270. .nonatomic = 1,
  271. .trigger = {
  272. SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  273. .dpcm_capture = 1,
  274. .ops = &broxton_da7219_fe_ops,
  275. },
  276. [BXT_DPCM_AUDIO_REF_CP] =
  277. {
  278. .name = "Bxt Audio Reference cap",
  279. .stream_name = "Refcap",
  280. .cpu_dai_name = "Reference Pin",
  281. .codec_name = "snd-soc-dummy",
  282. .codec_dai_name = "snd-soc-dummy-dai",
  283. .platform_name = "0000:00:0e.0",
  284. .init = NULL,
  285. .dpcm_capture = 1,
  286. .ignore_suspend = 1,
  287. .nonatomic = 1,
  288. .dynamic = 1,
  289. .ops = &broxton_refcap_ops,
  290. },
  291. [BXT_DPCM_AUDIO_DMIC_CP]
  292. {
  293. .name = "Bxt Audio DMIC cap",
  294. .stream_name = "dmiccap",
  295. .cpu_dai_name = "DMIC Pin",
  296. .codec_name = "snd-soc-dummy",
  297. .codec_dai_name = "snd-soc-dummy-dai",
  298. .platform_name = "0000:00:0e.0",
  299. .init = NULL,
  300. .dpcm_capture = 1,
  301. .nonatomic = 1,
  302. .dynamic = 1,
  303. .ops = &broxton_dmic_ops,
  304. },
  305. [BXT_DPCM_AUDIO_HDMI1_PB] =
  306. {
  307. .name = "Bxt HDMI Port1",
  308. .stream_name = "Hdmi1",
  309. .cpu_dai_name = "HDMI1 Pin",
  310. .codec_name = "snd-soc-dummy",
  311. .codec_dai_name = "snd-soc-dummy-dai",
  312. .platform_name = "0000:00:0e.0",
  313. .dpcm_playback = 1,
  314. .init = NULL,
  315. .nonatomic = 1,
  316. .dynamic = 1,
  317. },
  318. [BXT_DPCM_AUDIO_HDMI2_PB] =
  319. {
  320. .name = "Bxt HDMI Port2",
  321. .stream_name = "Hdmi2",
  322. .cpu_dai_name = "HDMI2 Pin",
  323. .codec_name = "snd-soc-dummy",
  324. .codec_dai_name = "snd-soc-dummy-dai",
  325. .platform_name = "0000:00:0e.0",
  326. .dpcm_playback = 1,
  327. .init = NULL,
  328. .nonatomic = 1,
  329. .dynamic = 1,
  330. },
  331. [BXT_DPCM_AUDIO_HDMI3_PB] =
  332. {
  333. .name = "Bxt HDMI Port3",
  334. .stream_name = "Hdmi3",
  335. .cpu_dai_name = "HDMI3 Pin",
  336. .codec_name = "snd-soc-dummy",
  337. .codec_dai_name = "snd-soc-dummy-dai",
  338. .platform_name = "0000:00:0e.0",
  339. .dpcm_playback = 1,
  340. .init = NULL,
  341. .nonatomic = 1,
  342. .dynamic = 1,
  343. },
  344. /* Back End DAI links */
  345. {
  346. /* SSP5 - Codec */
  347. .name = "SSP5-Codec",
  348. .id = 0,
  349. .cpu_dai_name = "SSP5 Pin",
  350. .platform_name = "0000:00:0e.0",
  351. .no_pcm = 1,
  352. .codec_name = "MX98357A:00",
  353. .codec_dai_name = BXT_MAXIM_CODEC_DAI,
  354. .dai_fmt = SND_SOC_DAIFMT_I2S |
  355. SND_SOC_DAIFMT_NB_NF |
  356. SND_SOC_DAIFMT_CBS_CFS,
  357. .ignore_pmdown_time = 1,
  358. .be_hw_params_fixup = broxton_ssp_fixup,
  359. .dpcm_playback = 1,
  360. },
  361. {
  362. /* SSP1 - Codec */
  363. .name = "SSP1-Codec",
  364. .id = 1,
  365. .cpu_dai_name = "SSP1 Pin",
  366. .platform_name = "0000:00:0e.0",
  367. .no_pcm = 1,
  368. .codec_name = "i2c-DLGS7219:00",
  369. .codec_dai_name = BXT_DIALOG_CODEC_DAI,
  370. .init = broxton_da7219_codec_init,
  371. .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
  372. SND_SOC_DAIFMT_CBS_CFS,
  373. .ignore_pmdown_time = 1,
  374. .be_hw_params_fixup = broxton_ssp_fixup,
  375. .ops = &broxton_da7219_ops,
  376. .dpcm_playback = 1,
  377. .dpcm_capture = 1,
  378. },
  379. {
  380. .name = "dmic01",
  381. .id = 2,
  382. .cpu_dai_name = "DMIC01 Pin",
  383. .codec_name = "dmic-codec",
  384. .codec_dai_name = "dmic-hifi",
  385. .platform_name = "0000:00:0e.0",
  386. .ignore_suspend = 1,
  387. .be_hw_params_fixup = broxton_dmic_fixup,
  388. .dpcm_capture = 1,
  389. .no_pcm = 1,
  390. },
  391. {
  392. .name = "iDisp1",
  393. .id = 3,
  394. .cpu_dai_name = "iDisp1 Pin",
  395. .codec_name = "ehdaudio0D2",
  396. .codec_dai_name = "intel-hdmi-hifi1",
  397. .platform_name = "0000:00:0e.0",
  398. .init = broxton_hdmi_init,
  399. .dpcm_playback = 1,
  400. .no_pcm = 1,
  401. },
  402. {
  403. .name = "iDisp2",
  404. .id = 4,
  405. .cpu_dai_name = "iDisp2 Pin",
  406. .codec_name = "ehdaudio0D2",
  407. .codec_dai_name = "intel-hdmi-hifi2",
  408. .platform_name = "0000:00:0e.0",
  409. .init = broxton_hdmi_init,
  410. .dpcm_playback = 1,
  411. .no_pcm = 1,
  412. },
  413. {
  414. .name = "iDisp3",
  415. .id = 5,
  416. .cpu_dai_name = "iDisp3 Pin",
  417. .codec_name = "ehdaudio0D2",
  418. .codec_dai_name = "intel-hdmi-hifi3",
  419. .platform_name = "0000:00:0e.0",
  420. .init = broxton_hdmi_init,
  421. .dpcm_playback = 1,
  422. .no_pcm = 1,
  423. },
  424. };
  425. /* broxton audio machine driver for SPT + da7219 */
  426. static struct snd_soc_card broxton_audio_card = {
  427. .name = "bxtda7219max",
  428. .owner = THIS_MODULE,
  429. .dai_link = broxton_dais,
  430. .num_links = ARRAY_SIZE(broxton_dais),
  431. .controls = broxton_controls,
  432. .num_controls = ARRAY_SIZE(broxton_controls),
  433. .dapm_widgets = broxton_widgets,
  434. .num_dapm_widgets = ARRAY_SIZE(broxton_widgets),
  435. .dapm_routes = broxton_map,
  436. .num_dapm_routes = ARRAY_SIZE(broxton_map),
  437. .fully_routed = true,
  438. };
  439. static int broxton_audio_probe(struct platform_device *pdev)
  440. {
  441. broxton_audio_card.dev = &pdev->dev;
  442. return devm_snd_soc_register_card(&pdev->dev, &broxton_audio_card);
  443. }
  444. static struct platform_driver broxton_audio = {
  445. .probe = broxton_audio_probe,
  446. .driver = {
  447. .name = "bxt_da7219_max98357a_i2s",
  448. .pm = &snd_soc_pm_ops,
  449. },
  450. };
  451. module_platform_driver(broxton_audio)
  452. /* Module information */
  453. MODULE_DESCRIPTION("Audio Machine driver-DA7219 & MAX98357A in I2S mode");
  454. MODULE_AUTHOR("Sathyanarayana Nujella <sathyanarayana.nujella@intel.com>");
  455. MODULE_AUTHOR("Rohit Ainapure <rohit.m.ainapure@intel.com>");
  456. MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
  457. MODULE_AUTHOR("Conrad Cooke <conrad.cooke@intel.com>");
  458. MODULE_LICENSE("GPL v2");
  459. MODULE_ALIAS("platform:bxt_da7219_max98357a_i2s");