bxt_da7219_max98357a.c 13 KB

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