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