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 channels->min = channels->max = 4; 216 217 return 0; 218 } 219 220 static unsigned int channels_dmic[] = { 221 2, 4, 222 }; 223 224 static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { 225 .count = ARRAY_SIZE(channels_dmic), 226 .list = channels_dmic, 227 .mask = 0, 228 }; 229 230 static int skylake_dmic_startup(struct snd_pcm_substream *substream) 231 { 232 struct snd_pcm_runtime *runtime = substream->runtime; 233 234 runtime->hw.channels_max = 4; 235 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 236 &constraints_dmic_channels); 237 238 return snd_pcm_hw_constraint_list(substream->runtime, 0, 239 SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); 240 } 241 242 static struct snd_soc_ops skylake_dmic_ops = { 243 .startup = skylake_dmic_startup, 244 }; 245 246 /* skylake digital audio interface glue - connects codec <--> CPU */ 247 static struct snd_soc_dai_link skylake_rt286_dais[] = { 248 /* Front End DAI links */ 249 { 250 .name = "Skl Audio Port", 251 .stream_name = "Audio", 252 .cpu_dai_name = "System Pin", 253 .platform_name = "0000:00:1f.3", 254 .nonatomic = 1, 255 .dynamic = 1, 256 .codec_name = "snd-soc-dummy", 257 .codec_dai_name = "snd-soc-dummy-dai", 258 .init = skylake_rt286_fe_init, 259 .trigger = { 260 SND_SOC_DPCM_TRIGGER_POST, 261 SND_SOC_DPCM_TRIGGER_POST 262 }, 263 .dpcm_playback = 1, 264 .ops = &skylake_rt286_fe_ops, 265 }, 266 { 267 .name = "Skl Audio Capture Port", 268 .stream_name = "Audio Record", 269 .cpu_dai_name = "System Pin", 270 .platform_name = "0000:00:1f.3", 271 .nonatomic = 1, 272 .dynamic = 1, 273 .codec_name = "snd-soc-dummy", 274 .codec_dai_name = "snd-soc-dummy-dai", 275 .trigger = { 276 SND_SOC_DPCM_TRIGGER_POST, 277 SND_SOC_DPCM_TRIGGER_POST 278 }, 279 .dpcm_capture = 1, 280 .ops = &skylake_rt286_fe_ops, 281 }, 282 { 283 .name = "Skl Audio Reference cap", 284 .stream_name = "refcap", 285 .cpu_dai_name = "Reference Pin", 286 .codec_name = "snd-soc-dummy", 287 .codec_dai_name = "snd-soc-dummy-dai", 288 .platform_name = "0000:00:1f.3", 289 .init = NULL, 290 .dpcm_capture = 1, 291 .ignore_suspend = 1, 292 .nonatomic = 1, 293 .dynamic = 1, 294 }, 295 { 296 .name = "Skl Audio DMIC cap", 297 .stream_name = "dmiccap", 298 .cpu_dai_name = "DMIC Pin", 299 .codec_name = "snd-soc-dummy", 300 .codec_dai_name = "snd-soc-dummy-dai", 301 .platform_name = "0000:00:1f.3", 302 .init = NULL, 303 .dpcm_capture = 1, 304 .nonatomic = 1, 305 .dynamic = 1, 306 .ops = &skylake_dmic_ops, 307 }, 308 309 /* Back End DAI links */ 310 { 311 /* SSP0 - Codec */ 312 .name = "SSP0-Codec", 313 .be_id = 0, 314 .cpu_dai_name = "SSP0 Pin", 315 .platform_name = "0000:00:1f.3", 316 .no_pcm = 1, 317 .codec_name = "i2c-INT343A:00", 318 .codec_dai_name = "rt286-aif1", 319 .init = skylake_rt286_codec_init, 320 .dai_fmt = SND_SOC_DAIFMT_I2S | 321 SND_SOC_DAIFMT_NB_NF | 322 SND_SOC_DAIFMT_CBS_CFS, 323 .ignore_pmdown_time = 1, 324 .be_hw_params_fixup = skylake_ssp0_fixup, 325 .ops = &skylake_rt286_ops, 326 .dpcm_playback = 1, 327 .dpcm_capture = 1, 328 }, 329 { 330 .name = "dmic01", 331 .be_id = 1, 332 .cpu_dai_name = "DMIC01 Pin", 333 .codec_name = "dmic-codec", 334 .codec_dai_name = "dmic-hifi", 335 .platform_name = "0000:00:1f.3", 336 .be_hw_params_fixup = skylake_dmic_fixup, 337 .ignore_suspend = 1, 338 .dpcm_capture = 1, 339 .no_pcm = 1, 340 }, 341 }; 342 343 /* skylake audio machine driver for SPT + RT286S */ 344 static struct snd_soc_card skylake_rt286 = { 345 .name = "skylake-rt286", 346 .owner = THIS_MODULE, 347 .dai_link = skylake_rt286_dais, 348 .num_links = ARRAY_SIZE(skylake_rt286_dais), 349 .controls = skylake_controls, 350 .num_controls = ARRAY_SIZE(skylake_controls), 351 .dapm_widgets = skylake_widgets, 352 .num_dapm_widgets = ARRAY_SIZE(skylake_widgets), 353 .dapm_routes = skylake_rt286_map, 354 .num_dapm_routes = ARRAY_SIZE(skylake_rt286_map), 355 .fully_routed = true, 356 }; 357 358 static int skylake_audio_probe(struct platform_device *pdev) 359 { 360 skylake_rt286.dev = &pdev->dev; 361 362 return devm_snd_soc_register_card(&pdev->dev, &skylake_rt286); 363 } 364 365 static struct platform_driver skylake_audio = { 366 .probe = skylake_audio_probe, 367 .driver = { 368 .name = "skl_alc286s_i2s", 369 .pm = &snd_soc_pm_ops, 370 }, 371 }; 372 373 module_platform_driver(skylake_audio) 374 375 /* Module information */ 376 MODULE_AUTHOR("Omair Mohammed Abdullah <omair.m.abdullah@intel.com>"); 377 MODULE_DESCRIPTION("Intel SST Audio for Skylake"); 378 MODULE_LICENSE("GPL v2"); 379 MODULE_ALIAS("platform:skl_alc286s_i2s"); 380