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