2 * Intel Broxton-P I2S Machine Driver
4 * Copyright (C) 2014-2016, Intel Corporation. All rights reserved.
7 * Intel Skylake I2S Machine driver
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.
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.
19 #include <linux/module.h>
20 #include <linux/platform_device.h>
21 #include <sound/core.h>
22 #include <sound/pcm.h>
23 #include <sound/soc.h>
24 #include <sound/jack.h>
25 #include <sound/pcm_params.h>
26 #include "../../codecs/hdac_hdmi.h"
27 #include "../../codecs/rt298.h"
29 /* Headset jack detection DAPM pins */
30 static struct snd_soc_jack broxton_headset
;
31 static struct snd_soc_jack broxton_hdmi
[3];
34 struct list_head head
;
35 struct snd_soc_dai
*codec_dai
;
39 struct bxt_rt286_private
{
40 struct list_head hdmi_pcm_list
;
44 BXT_DPCM_AUDIO_PB
= 0,
46 BXT_DPCM_AUDIO_REF_CP
,
47 BXT_DPCM_AUDIO_DMIC_CP
,
48 BXT_DPCM_AUDIO_HDMI1_PB
,
49 BXT_DPCM_AUDIO_HDMI2_PB
,
50 BXT_DPCM_AUDIO_HDMI3_PB
,
53 static struct snd_soc_jack_pin broxton_headset_pins
[] = {
56 .mask
= SND_JACK_MICROPHONE
,
59 .pin
= "Headphone Jack",
60 .mask
= SND_JACK_HEADPHONE
,
64 static const struct snd_kcontrol_new broxton_controls
[] = {
65 SOC_DAPM_PIN_SWITCH("Speaker"),
66 SOC_DAPM_PIN_SWITCH("Headphone Jack"),
67 SOC_DAPM_PIN_SWITCH("Mic Jack"),
70 static const struct snd_soc_dapm_widget broxton_widgets
[] = {
71 SND_SOC_DAPM_HP("Headphone Jack", NULL
),
72 SND_SOC_DAPM_SPK("Speaker", NULL
),
73 SND_SOC_DAPM_MIC("Mic Jack", NULL
),
74 SND_SOC_DAPM_MIC("DMIC2", NULL
),
75 SND_SOC_DAPM_MIC("SoC DMIC", NULL
),
76 SND_SOC_DAPM_SPK("HDMI1", NULL
),
77 SND_SOC_DAPM_SPK("HDMI2", NULL
),
78 SND_SOC_DAPM_SPK("HDMI3", NULL
),
81 static const struct snd_soc_dapm_route broxton_rt298_map
[] = {
83 {"Speaker", NULL
, "SPOR"},
84 {"Speaker", NULL
, "SPOL"},
86 /* HP jack connectors - unknown if we have jack detect */
87 {"Headphone Jack", NULL
, "HPO Pin"},
90 {"MIC1", NULL
, "Mic Jack"},
93 {"DMIC1 Pin", NULL
, "DMIC2"},
94 {"DMic", NULL
, "SoC DMIC"},
96 {"HDMI1", NULL
, "hif5-0 Output"},
97 {"HDMI2", NULL
, "hif6-0 Output"},
98 {"HDMI2", NULL
, "hif7-0 Output"},
100 /* CODEC BE connections */
101 { "AIF1 Playback", NULL
, "ssp5 Tx"},
102 { "ssp5 Tx", NULL
, "codec0_out"},
103 { "ssp5 Tx", NULL
, "codec1_out"},
105 { "codec0_in", NULL
, "ssp5 Rx" },
106 { "ssp5 Rx", NULL
, "AIF1 Capture" },
108 { "dmic01_hifi", NULL
, "DMIC01 Rx" },
109 { "DMIC01 Rx", NULL
, "Capture" },
111 { "hifi3", NULL
, "iDisp3 Tx"},
112 { "iDisp3 Tx", NULL
, "iDisp3_out"},
113 { "hifi2", NULL
, "iDisp2 Tx"},
114 { "iDisp2 Tx", NULL
, "iDisp2_out"},
115 { "hifi1", NULL
, "iDisp1 Tx"},
116 { "iDisp1 Tx", NULL
, "iDisp1_out"},
119 static const struct snd_soc_dapm_route geminilake_rt298_map
[] = {
121 {"Speaker", NULL
, "SPOR"},
122 {"Speaker", NULL
, "SPOL"},
124 /* HP jack connectors - unknown if we have jack detect */
125 {"Headphone Jack", NULL
, "HPO Pin"},
128 {"MIC1", NULL
, "Mic Jack"},
131 {"DMIC1 Pin", NULL
, "DMIC2"},
132 {"DMic", NULL
, "SoC DMIC"},
134 {"HDMI1", NULL
, "hif5-0 Output"},
135 {"HDMI2", NULL
, "hif6-0 Output"},
136 {"HDMI2", NULL
, "hif7-0 Output"},
138 /* CODEC BE connections */
139 { "AIF1 Playback", NULL
, "ssp2 Tx"},
140 { "ssp2 Tx", NULL
, "codec0_out"},
141 { "ssp2 Tx", NULL
, "codec1_out"},
143 { "codec0_in", NULL
, "ssp2 Rx" },
144 { "ssp2 Rx", NULL
, "AIF1 Capture" },
146 { "dmic01_hifi", NULL
, "DMIC01 Rx" },
147 { "DMIC01 Rx", NULL
, "Capture" },
149 { "hifi3", NULL
, "iDisp3 Tx"},
150 { "iDisp3 Tx", NULL
, "iDisp3_out"},
151 { "hifi2", NULL
, "iDisp2 Tx"},
152 { "iDisp2 Tx", NULL
, "iDisp2_out"},
153 { "hifi1", NULL
, "iDisp1 Tx"},
154 { "iDisp1 Tx", NULL
, "iDisp1_out"},
157 static int broxton_rt298_fe_init(struct snd_soc_pcm_runtime
*rtd
)
159 struct snd_soc_dapm_context
*dapm
;
160 struct snd_soc_component
*component
= rtd
->cpu_dai
->component
;
162 dapm
= snd_soc_component_get_dapm(component
);
163 snd_soc_dapm_ignore_suspend(dapm
, "Reference Capture");
168 static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime
*rtd
)
170 struct snd_soc_codec
*codec
= rtd
->codec
;
173 ret
= snd_soc_card_jack_new(rtd
->card
, "Headset",
174 SND_JACK_HEADSET
| SND_JACK_BTN_0
,
176 broxton_headset_pins
, ARRAY_SIZE(broxton_headset_pins
));
181 rt298_mic_detect(codec
, &broxton_headset
);
183 snd_soc_dapm_ignore_suspend(&rtd
->card
->dapm
, "SoC DMIC");
188 static int broxton_hdmi_init(struct snd_soc_pcm_runtime
*rtd
)
190 struct bxt_rt286_private
*ctx
= snd_soc_card_get_drvdata(rtd
->card
);
191 struct snd_soc_dai
*dai
= rtd
->codec_dai
;
192 struct bxt_hdmi_pcm
*pcm
;
194 pcm
= devm_kzalloc(rtd
->card
->dev
, sizeof(*pcm
), GFP_KERNEL
);
198 pcm
->device
= BXT_DPCM_AUDIO_HDMI1_PB
+ dai
->id
;
199 pcm
->codec_dai
= dai
;
201 list_add_tail(&pcm
->head
, &ctx
->hdmi_pcm_list
);
206 static int broxton_ssp5_fixup(struct snd_soc_pcm_runtime
*rtd
,
207 struct snd_pcm_hw_params
*params
)
209 struct snd_interval
*rate
= hw_param_interval(params
,
210 SNDRV_PCM_HW_PARAM_RATE
);
211 struct snd_interval
*channels
= hw_param_interval(params
,
212 SNDRV_PCM_HW_PARAM_CHANNELS
);
213 struct snd_mask
*fmt
= hw_param_mask(params
, SNDRV_PCM_HW_PARAM_FORMAT
);
215 /* The ADSP will covert the FE rate to 48k, stereo */
216 rate
->min
= rate
->max
= 48000;
217 channels
->min
= channels
->max
= 2;
219 /* set SSP5 to 24 bit */
221 snd_mask_set(fmt
, SNDRV_PCM_FORMAT_S24_LE
);
226 static int broxton_rt298_hw_params(struct snd_pcm_substream
*substream
,
227 struct snd_pcm_hw_params
*params
)
229 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
230 struct snd_soc_dai
*codec_dai
= rtd
->codec_dai
;
233 ret
= snd_soc_dai_set_sysclk(codec_dai
, RT298_SCLK_S_PLL
,
234 19200000, SND_SOC_CLOCK_IN
);
236 dev_err(rtd
->dev
, "can't set codec sysclk configuration\n");
243 static const struct snd_soc_ops broxton_rt298_ops
= {
244 .hw_params
= broxton_rt298_hw_params
,
247 static const unsigned int rates
[] = {
251 static const struct snd_pcm_hw_constraint_list constraints_rates
= {
252 .count
= ARRAY_SIZE(rates
),
257 static int broxton_dmic_fixup(struct snd_soc_pcm_runtime
*rtd
,
258 struct snd_pcm_hw_params
*params
)
260 struct snd_interval
*channels
= hw_param_interval(params
,
261 SNDRV_PCM_HW_PARAM_CHANNELS
);
262 channels
->min
= channels
->max
= 4;
267 static const unsigned int channels_dmic
[] = {
271 static const struct snd_pcm_hw_constraint_list constraints_dmic_channels
= {
272 .count
= ARRAY_SIZE(channels_dmic
),
273 .list
= channels_dmic
,
277 static int broxton_dmic_startup(struct snd_pcm_substream
*substream
)
279 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
281 runtime
->hw
.channels_max
= 4;
282 snd_pcm_hw_constraint_list(runtime
, 0, SNDRV_PCM_HW_PARAM_CHANNELS
,
283 &constraints_dmic_channels
);
285 return snd_pcm_hw_constraint_list(substream
->runtime
, 0,
286 SNDRV_PCM_HW_PARAM_RATE
, &constraints_rates
);
289 static const struct snd_soc_ops broxton_dmic_ops
= {
290 .startup
= broxton_dmic_startup
,
293 static const unsigned int channels
[] = {
297 static const struct snd_pcm_hw_constraint_list constraints_channels
= {
298 .count
= ARRAY_SIZE(channels
),
303 static int bxt_fe_startup(struct snd_pcm_substream
*substream
)
305 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
308 * on this platform for PCM device we support:
314 runtime
->hw
.channels_max
= 2;
315 snd_pcm_hw_constraint_list(runtime
, 0, SNDRV_PCM_HW_PARAM_CHANNELS
,
316 &constraints_channels
);
318 runtime
->hw
.formats
= SNDRV_PCM_FMTBIT_S16_LE
;
319 snd_pcm_hw_constraint_msbits(runtime
, 0, 16, 16);
320 snd_pcm_hw_constraint_list(runtime
, 0,
321 SNDRV_PCM_HW_PARAM_RATE
, &constraints_rates
);
326 static const struct snd_soc_ops broxton_rt286_fe_ops
= {
327 .startup
= bxt_fe_startup
,
330 /* broxton digital audio interface glue - connects codec <--> CPU */
331 static struct snd_soc_dai_link broxton_rt298_dais
[] = {
332 /* Front End DAI links */
333 [BXT_DPCM_AUDIO_PB
] =
335 .name
= "Bxt Audio Port",
336 .stream_name
= "Audio",
337 .cpu_dai_name
= "System Pin",
338 .platform_name
= "0000:00:0e.0",
341 .codec_name
= "snd-soc-dummy",
342 .codec_dai_name
= "snd-soc-dummy-dai",
343 .init
= broxton_rt298_fe_init
,
344 .trigger
= {SND_SOC_DPCM_TRIGGER_POST
, SND_SOC_DPCM_TRIGGER_POST
},
346 .ops
= &broxton_rt286_fe_ops
,
348 [BXT_DPCM_AUDIO_CP
] =
350 .name
= "Bxt Audio Capture Port",
351 .stream_name
= "Audio Record",
352 .cpu_dai_name
= "System Pin",
353 .platform_name
= "0000:00:0e.0",
356 .codec_name
= "snd-soc-dummy",
357 .codec_dai_name
= "snd-soc-dummy-dai",
358 .trigger
= {SND_SOC_DPCM_TRIGGER_POST
, SND_SOC_DPCM_TRIGGER_POST
},
360 .ops
= &broxton_rt286_fe_ops
,
362 [BXT_DPCM_AUDIO_REF_CP
] =
364 .name
= "Bxt Audio Reference cap",
365 .stream_name
= "refcap",
366 .cpu_dai_name
= "Reference Pin",
367 .codec_name
= "snd-soc-dummy",
368 .codec_dai_name
= "snd-soc-dummy-dai",
369 .platform_name
= "0000:00:0e.0",
375 [BXT_DPCM_AUDIO_DMIC_CP
] =
377 .name
= "Bxt Audio DMIC cap",
378 .stream_name
= "dmiccap",
379 .cpu_dai_name
= "DMIC Pin",
380 .codec_name
= "snd-soc-dummy",
381 .codec_dai_name
= "snd-soc-dummy-dai",
382 .platform_name
= "0000:00:0e.0",
387 .ops
= &broxton_dmic_ops
,
389 [BXT_DPCM_AUDIO_HDMI1_PB
] =
391 .name
= "Bxt HDMI Port1",
392 .stream_name
= "Hdmi1",
393 .cpu_dai_name
= "HDMI1 Pin",
394 .codec_name
= "snd-soc-dummy",
395 .codec_dai_name
= "snd-soc-dummy-dai",
396 .platform_name
= "0000:00:0e.0",
402 [BXT_DPCM_AUDIO_HDMI2_PB
] =
404 .name
= "Bxt HDMI Port2",
405 .stream_name
= "Hdmi2",
406 .cpu_dai_name
= "HDMI2 Pin",
407 .codec_name
= "snd-soc-dummy",
408 .codec_dai_name
= "snd-soc-dummy-dai",
409 .platform_name
= "0000:00:0e.0",
415 [BXT_DPCM_AUDIO_HDMI3_PB
] =
417 .name
= "Bxt HDMI Port3",
418 .stream_name
= "Hdmi3",
419 .cpu_dai_name
= "HDMI3 Pin",
420 .codec_name
= "snd-soc-dummy",
421 .codec_dai_name
= "snd-soc-dummy-dai",
422 .platform_name
= "0000:00:0e.0",
428 /* Back End DAI links */
431 .name
= "SSP5-Codec",
433 .cpu_dai_name
= "SSP5 Pin",
434 .platform_name
= "0000:00:0e.0",
436 .codec_name
= "i2c-INT343A:00",
437 .codec_dai_name
= "rt298-aif1",
438 .init
= broxton_rt298_codec_init
,
439 .dai_fmt
= SND_SOC_DAIFMT_DSP_A
| SND_SOC_DAIFMT_NB_NF
|
440 SND_SOC_DAIFMT_CBS_CFS
,
441 .ignore_pmdown_time
= 1,
442 .be_hw_params_fixup
= broxton_ssp5_fixup
,
443 .ops
= &broxton_rt298_ops
,
450 .cpu_dai_name
= "DMIC01 Pin",
451 .codec_name
= "dmic-codec",
452 .codec_dai_name
= "dmic-hifi",
453 .platform_name
= "0000:00:0e.0",
454 .be_hw_params_fixup
= broxton_dmic_fixup
,
462 .cpu_dai_name
= "iDisp1 Pin",
463 .codec_name
= "ehdaudio0D2",
464 .codec_dai_name
= "intel-hdmi-hifi1",
465 .platform_name
= "0000:00:0e.0",
466 .init
= broxton_hdmi_init
,
473 .cpu_dai_name
= "iDisp2 Pin",
474 .codec_name
= "ehdaudio0D2",
475 .codec_dai_name
= "intel-hdmi-hifi2",
476 .platform_name
= "0000:00:0e.0",
477 .init
= broxton_hdmi_init
,
484 .cpu_dai_name
= "iDisp3 Pin",
485 .codec_name
= "ehdaudio0D2",
486 .codec_dai_name
= "intel-hdmi-hifi3",
487 .platform_name
= "0000:00:0e.0",
488 .init
= broxton_hdmi_init
,
495 static int bxt_card_late_probe(struct snd_soc_card
*card
)
497 struct bxt_rt286_private
*ctx
= snd_soc_card_get_drvdata(card
);
498 struct bxt_hdmi_pcm
*pcm
;
499 struct snd_soc_codec
*codec
= NULL
;
501 char jack_name
[NAME_SIZE
];
503 list_for_each_entry(pcm
, &ctx
->hdmi_pcm_list
, head
) {
504 codec
= pcm
->codec_dai
->codec
;
505 snprintf(jack_name
, sizeof(jack_name
),
506 "HDMI/DP, pcm=%d Jack", pcm
->device
);
507 err
= snd_soc_card_jack_new(card
, jack_name
,
508 SND_JACK_AVOUT
, &broxton_hdmi
[i
],
514 err
= hdac_hdmi_jack_init(pcm
->codec_dai
, pcm
->device
,
525 return hdac_hdmi_jack_port_init(codec
, &card
->dapm
);
529 /* broxton audio machine driver for SPT + RT298S */
530 static struct snd_soc_card broxton_rt298
= {
531 .name
= "broxton-rt298",
532 .dai_link
= broxton_rt298_dais
,
533 .num_links
= ARRAY_SIZE(broxton_rt298_dais
),
534 .controls
= broxton_controls
,
535 .num_controls
= ARRAY_SIZE(broxton_controls
),
536 .dapm_widgets
= broxton_widgets
,
537 .num_dapm_widgets
= ARRAY_SIZE(broxton_widgets
),
538 .dapm_routes
= broxton_rt298_map
,
539 .num_dapm_routes
= ARRAY_SIZE(broxton_rt298_map
),
540 .fully_routed
= true,
541 .late_probe
= bxt_card_late_probe
,
545 static struct snd_soc_card geminilake_rt298
= {
546 .name
= "geminilake-rt298",
547 .dai_link
= broxton_rt298_dais
,
548 .num_links
= ARRAY_SIZE(broxton_rt298_dais
),
549 .controls
= broxton_controls
,
550 .num_controls
= ARRAY_SIZE(broxton_controls
),
551 .dapm_widgets
= broxton_widgets
,
552 .num_dapm_widgets
= ARRAY_SIZE(broxton_widgets
),
553 .dapm_routes
= geminilake_rt298_map
,
554 .num_dapm_routes
= ARRAY_SIZE(geminilake_rt298_map
),
555 .fully_routed
= true,
556 .late_probe
= bxt_card_late_probe
,
559 static int broxton_audio_probe(struct platform_device
*pdev
)
561 struct bxt_rt286_private
*ctx
;
562 struct snd_soc_card
*card
=
563 (struct snd_soc_card
*)pdev
->id_entry
->driver_data
;
566 for (i
= 0; i
< ARRAY_SIZE(broxton_rt298_dais
); i
++) {
567 if (!strncmp(card
->dai_link
[i
].codec_name
, "i2c-INT343A:00",
569 if (!strncmp(card
->name
, "broxton-rt298",
570 PLATFORM_NAME_SIZE
)) {
571 card
->dai_link
[i
].name
= "SSP5-Codec";
572 card
->dai_link
[i
].cpu_dai_name
= "SSP5 Pin";
573 } else if (!strncmp(card
->name
, "geminilake-rt298",
574 PLATFORM_NAME_SIZE
)) {
575 card
->dai_link
[i
].name
= "SSP2-Codec";
576 card
->dai_link
[i
].cpu_dai_name
= "SSP2 Pin";
581 ctx
= devm_kzalloc(&pdev
->dev
, sizeof(*ctx
), GFP_ATOMIC
);
585 INIT_LIST_HEAD(&ctx
->hdmi_pcm_list
);
587 card
->dev
= &pdev
->dev
;
588 snd_soc_card_set_drvdata(card
, ctx
);
590 return devm_snd_soc_register_card(&pdev
->dev
, card
);
593 static const struct platform_device_id bxt_board_ids
[] = {
594 { .name
= "bxt_alc298s_i2s", .driver_data
=
595 (unsigned long)&broxton_rt298
},
596 { .name
= "glk_alc298s_i2s", .driver_data
=
597 (unsigned long)&geminilake_rt298
},
601 static struct platform_driver broxton_audio
= {
602 .probe
= broxton_audio_probe
,
604 .name
= "bxt_alc298s_i2s",
605 .pm
= &snd_soc_pm_ops
,
607 .id_table
= bxt_board_ids
,
609 module_platform_driver(broxton_audio
)
611 /* Module information */
612 MODULE_AUTHOR("Ramesh Babu <Ramesh.Babu@intel.com>");
613 MODULE_AUTHOR("Senthilnathan Veppur <senthilnathanx.veppur@intel.com>");
614 MODULE_DESCRIPTION("Intel SST Audio for Broxton");
615 MODULE_LICENSE("GPL v2");
616 MODULE_ALIAS("platform:bxt_alc298s_i2s");
617 MODULE_ALIAS("platform:glk_alc298s_i2s");