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 30 static struct snd_soc_jack skylake_headset; 31 /* Headset jack detection DAPM pins */ 32 static struct snd_soc_jack_pin skylake_headset_pins[] = { 33 { 34 .pin = "Mic Jack", 35 .mask = SND_JACK_MICROPHONE, 36 }, 37 { 38 .pin = "Headphone Jack", 39 .mask = SND_JACK_HEADPHONE, 40 }, 41 }; 42 43 static const struct snd_kcontrol_new skylake_controls[] = { 44 SOC_DAPM_PIN_SWITCH("Speaker"), 45 SOC_DAPM_PIN_SWITCH("Headphone Jack"), 46 SOC_DAPM_PIN_SWITCH("Mic Jack"), 47 }; 48 49 static const struct snd_soc_dapm_widget skylake_widgets[] = { 50 SND_SOC_DAPM_HP("Headphone Jack", NULL), 51 SND_SOC_DAPM_SPK("Speaker", NULL), 52 SND_SOC_DAPM_MIC("Mic Jack", NULL), 53 SND_SOC_DAPM_MIC("DMIC2", NULL), 54 SND_SOC_DAPM_MIC("SoC DMIC", NULL), 55 SND_SOC_DAPM_SINK("WoV Sink"), 56 }; 57 58 static const struct snd_soc_dapm_route skylake_rt286_map[] = { 59 /* speaker */ 60 {"Speaker", NULL, "SPOR"}, 61 {"Speaker", NULL, "SPOL"}, 62 63 /* HP jack connectors - unknown if we have jack deteck */ 64 {"Headphone Jack", NULL, "HPO Pin"}, 65 66 /* other jacks */ 67 {"MIC1", NULL, "Mic Jack"}, 68 69 /* digital mics */ 70 {"DMIC1 Pin", NULL, "DMIC2"}, 71 {"DMic", NULL, "SoC DMIC"}, 72 73 {"WoV Sink", NULL, "hwd_in sink"}, 74 75 /* CODEC BE connections */ 76 { "AIF1 Playback", NULL, "ssp0 Tx"}, 77 { "ssp0 Tx", NULL, "codec0_out"}, 78 { "ssp0 Tx", NULL, "codec1_out"}, 79 80 { "codec0_in", NULL, "ssp0 Rx" }, 81 { "codec1_in", NULL, "ssp0 Rx" }, 82 { "ssp0 Rx", NULL, "AIF1 Capture" }, 83 84 { "dmic01_hifi", NULL, "DMIC01 Rx" }, 85 { "DMIC01 Rx", NULL, "DMIC AIF" }, 86 87 { "hif1", NULL, "iDisp Tx"}, 88 { "iDisp Tx", NULL, "iDisp_out"}, 89 90 }; 91 92 static int skylake_rt286_fe_init(struct snd_soc_pcm_runtime *rtd) 93 { 94 struct snd_soc_dapm_context *dapm; 95 struct snd_soc_component *component = rtd->cpu_dai->component; 96 97 dapm = snd_soc_component_get_dapm(component); 98 snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); 99 100 return 0; 101 } 102 103 static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd) 104 { 105 struct snd_soc_codec *codec = rtd->codec; 106 int ret; 107 108 ret = snd_soc_card_jack_new(rtd->card, "Headset", 109 SND_JACK_HEADSET | SND_JACK_BTN_0, 110 &skylake_headset, 111 skylake_headset_pins, ARRAY_SIZE(skylake_headset_pins)); 112 113 if (ret) 114 return ret; 115 116 rt286_mic_detect(codec, &skylake_headset); 117 118 snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); 119 snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink"); 120 121 return 0; 122 } 123 124 static unsigned int rates[] = { 125 48000, 126 }; 127 128 static struct snd_pcm_hw_constraint_list constraints_rates = { 129 .count = ARRAY_SIZE(rates), 130 .list = rates, 131 .mask = 0, 132 }; 133 134 static unsigned int channels[] = { 135 2, 136 }; 137 138 static struct snd_pcm_hw_constraint_list constraints_channels = { 139 .count = ARRAY_SIZE(channels), 140 .list = channels, 141 .mask = 0, 142 }; 143 144 static int skl_fe_startup(struct snd_pcm_substream *substream) 145 { 146 struct snd_pcm_runtime *runtime = substream->runtime; 147 148 /* 149 * on this platform for PCM device we support, 150 * 48Khz 151 * stereo 152 * 16 bit audio 153 */ 154 155 runtime->hw.channels_max = 2; 156 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 157 &constraints_channels); 158 159 runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; 160 snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); 161 162 snd_pcm_hw_constraint_list(runtime, 0, 163 SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); 164 165 return 0; 166 } 167 168 static const struct snd_soc_ops skylake_rt286_fe_ops = { 169 .startup = skl_fe_startup, 170 }; 171 172 static int skylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, 173 struct snd_pcm_hw_params *params) 174 { 175 struct snd_interval *rate = hw_param_interval(params, 176 SNDRV_PCM_HW_PARAM_RATE); 177 struct snd_interval *channels = hw_param_interval(params, 178 SNDRV_PCM_HW_PARAM_CHANNELS); 179 struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 180 181 /* The output is 48KHz, stereo, 16bits */ 182 rate->min = rate->max = 48000; 183 channels->min = channels->max = 2; 184 185 /* set SSP0 to 24 bit */ 186 snd_mask_none(fmt); 187 snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); 188 return 0; 189 } 190 191 static int skylake_rt286_hw_params(struct snd_pcm_substream *substream, 192 struct snd_pcm_hw_params *params) 193 { 194 struct snd_soc_pcm_runtime *rtd = substream->private_data; 195 struct snd_soc_dai *codec_dai = rtd->codec_dai; 196 int ret; 197 198 ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000, 199 SND_SOC_CLOCK_IN); 200 if (ret < 0) 201 dev_err(rtd->dev, "set codec sysclk failed: %d\n", ret); 202 203 return ret; 204 } 205 206 static struct snd_soc_ops skylake_rt286_ops = { 207 .hw_params = skylake_rt286_hw_params, 208 }; 209 210 static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, 211 struct snd_pcm_hw_params *params) 212 { 213 struct snd_interval *channels = hw_param_interval(params, 214 SNDRV_PCM_HW_PARAM_CHANNELS); 215 if (params_channels(params) == 2) 216 channels->min = channels->max = 2; 217 else 218 channels->min = channels->max = 4; 219 220 return 0; 221 } 222 223 static unsigned int channels_dmic[] = { 224 2, 4, 225 }; 226 227 static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { 228 .count = ARRAY_SIZE(channels_dmic), 229 .list = channels_dmic, 230 .mask = 0, 231 }; 232 233 static int skylake_dmic_startup(struct snd_pcm_substream *substream) 234 { 235 struct snd_pcm_runtime *runtime = substream->runtime; 236 237 runtime->hw.channels_max = 4; 238 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 239 &constraints_dmic_channels); 240 241 return snd_pcm_hw_constraint_list(substream->runtime, 0, 242 SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); 243 } 244 245 static struct snd_soc_ops skylake_dmic_ops = { 246 .startup = skylake_dmic_startup, 247 }; 248 249 /* skylake digital audio interface glue - connects codec <--> CPU */ 250 static struct snd_soc_dai_link skylake_rt286_dais[] = { 251 /* Front End DAI links */ 252 { 253 .name = "Skl Audio Port", 254 .stream_name = "Audio", 255 .cpu_dai_name = "System Pin", 256 .platform_name = "0000:00:1f.3", 257 .nonatomic = 1, 258 .dynamic = 1, 259 .codec_name = "snd-soc-dummy", 260 .codec_dai_name = "snd-soc-dummy-dai", 261 .init = skylake_rt286_fe_init, 262 .trigger = { 263 SND_SOC_DPCM_TRIGGER_POST, 264 SND_SOC_DPCM_TRIGGER_POST 265 }, 266 .dpcm_playback = 1, 267 .ops = &skylake_rt286_fe_ops, 268 }, 269 { 270 .name = "Skl Audio Capture Port", 271 .stream_name = "Audio Record", 272 .cpu_dai_name = "System Pin", 273 .platform_name = "0000:00:1f.3", 274 .nonatomic = 1, 275 .dynamic = 1, 276 .codec_name = "snd-soc-dummy", 277 .codec_dai_name = "snd-soc-dummy-dai", 278 .trigger = { 279 SND_SOC_DPCM_TRIGGER_POST, 280 SND_SOC_DPCM_TRIGGER_POST 281 }, 282 .dpcm_capture = 1, 283 .ops = &skylake_rt286_fe_ops, 284 }, 285 { 286 .name = "Skl Audio Reference cap", 287 .stream_name = "refcap", 288 .cpu_dai_name = "Reference Pin", 289 .codec_name = "snd-soc-dummy", 290 .codec_dai_name = "snd-soc-dummy-dai", 291 .platform_name = "0000:00:1f.3", 292 .init = NULL, 293 .dpcm_capture = 1, 294 .ignore_suspend = 1, 295 .nonatomic = 1, 296 .dynamic = 1, 297 }, 298 { 299 .name = "Skl Audio DMIC cap", 300 .stream_name = "dmiccap", 301 .cpu_dai_name = "DMIC Pin", 302 .codec_name = "snd-soc-dummy", 303 .codec_dai_name = "snd-soc-dummy-dai", 304 .platform_name = "0000:00:1f.3", 305 .init = NULL, 306 .dpcm_capture = 1, 307 .nonatomic = 1, 308 .dynamic = 1, 309 .ops = &skylake_dmic_ops, 310 }, 311 312 /* Back End DAI links */ 313 { 314 /* SSP0 - Codec */ 315 .name = "SSP0-Codec", 316 .be_id = 0, 317 .cpu_dai_name = "SSP0 Pin", 318 .platform_name = "0000:00:1f.3", 319 .no_pcm = 1, 320 .codec_name = "i2c-INT343A:00", 321 .codec_dai_name = "rt286-aif1", 322 .init = skylake_rt286_codec_init, 323 .dai_fmt = SND_SOC_DAIFMT_I2S | 324 SND_SOC_DAIFMT_NB_NF | 325 SND_SOC_DAIFMT_CBS_CFS, 326 .ignore_pmdown_time = 1, 327 .be_hw_params_fixup = skylake_ssp0_fixup, 328 .ops = &skylake_rt286_ops, 329 .dpcm_playback = 1, 330 .dpcm_capture = 1, 331 }, 332 { 333 .name = "dmic01", 334 .be_id = 1, 335 .cpu_dai_name = "DMIC01 Pin", 336 .codec_name = "dmic-codec", 337 .codec_dai_name = "dmic-hifi", 338 .platform_name = "0000:00:1f.3", 339 .be_hw_params_fixup = skylake_dmic_fixup, 340 .ignore_suspend = 1, 341 .dpcm_capture = 1, 342 .no_pcm = 1, 343 }, 344 }; 345 346 /* skylake audio machine driver for SPT + RT286S */ 347 static struct snd_soc_card skylake_rt286 = { 348 .name = "skylake-rt286", 349 .owner = THIS_MODULE, 350 .dai_link = skylake_rt286_dais, 351 .num_links = ARRAY_SIZE(skylake_rt286_dais), 352 .controls = skylake_controls, 353 .num_controls = ARRAY_SIZE(skylake_controls), 354 .dapm_widgets = skylake_widgets, 355 .num_dapm_widgets = ARRAY_SIZE(skylake_widgets), 356 .dapm_routes = skylake_rt286_map, 357 .num_dapm_routes = ARRAY_SIZE(skylake_rt286_map), 358 .fully_routed = true, 359 }; 360 361 static int skylake_audio_probe(struct platform_device *pdev) 362 { 363 skylake_rt286.dev = &pdev->dev; 364 365 return devm_snd_soc_register_card(&pdev->dev, &skylake_rt286); 366 } 367 368 static struct platform_driver skylake_audio = { 369 .probe = skylake_audio_probe, 370 .driver = { 371 .name = "skl_alc286s_i2s", 372 .pm = &snd_soc_pm_ops, 373 }, 374 }; 375 376 module_platform_driver(skylake_audio) 377 378 /* Module information */ 379 MODULE_AUTHOR("Omair Mohammed Abdullah <omair.m.abdullah@intel.com>"); 380 MODULE_DESCRIPTION("Intel SST Audio for Skylake"); 381 MODULE_LICENSE("GPL v2"); 382 MODULE_ALIAS("platform:skl_alc286s_i2s"); 383