Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: Intel: boards: add max98390 2/4 speakers support

support 2 hw boards.
1. SSP2 connects max98390, 2 speakers.
2. SSP1 connects max98390, 2/4 speakers.

2 or 4 speakers playback
add echo reference capture
add bt offload support
add DMI_OEM_STRING for board variants
add ALC5682I-VS support

Signed-off-by: Mark Hsieh <mark_hsieh@wistron.corp-partner.google.com>
Signed-off-by: Mac Chiang <mac.chiang@intel.com>
Signed-off-by: Kieth Tzeng <keith.tzeng@quantatw.com>
Signed-off-by: Brent Lu <brent.lu@intel.com>
Acked-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20211125030453.4382-1-mac.chiang@intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Mac Chiang and committed by
Mark Brown
f316c9d9 91745b03

+291
+1
sound/soc/intel/boards/Kconfig
··· 467 467 (MFD_INTEL_LPSS || COMPILE_TEST)) ||\ 468 468 (SND_SOC_SOF_BAYTRAIL && (X86_INTEL_LPSS || COMPILE_TEST)) 469 469 select SND_SOC_MAX98373_I2C 470 + select SND_SOC_MAX98390 470 471 select SND_SOC_RT1011 471 472 select SND_SOC_RT1015 472 473 select SND_SOC_RT1015P
+180
sound/soc/intel/boards/sof_maxim_common.c
··· 5 5 #include <linux/string.h> 6 6 #include <sound/pcm.h> 7 7 #include <sound/soc.h> 8 + #include <sound/soc-acpi.h> 8 9 #include <sound/soc-dai.h> 9 10 #include <sound/soc-dapm.h> 10 11 #include <uapi/sound/asound.h> ··· 133 132 card->num_configs = ARRAY_SIZE(max_98373_codec_conf); 134 133 } 135 134 EXPORT_SYMBOL_NS(max_98373_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON); 135 + 136 + /* 137 + * Maxim MAX98390 138 + */ 139 + const struct snd_soc_dapm_route max_98390_dapm_routes[] = { 140 + /* speaker */ 141 + { "Left Spk", NULL, "Left BE_OUT" }, 142 + { "Right Spk", NULL, "Right BE_OUT" }, 143 + }; 144 + 145 + static const struct snd_kcontrol_new max_98390_tt_kcontrols[] = { 146 + SOC_DAPM_PIN_SWITCH("TL Spk"), 147 + SOC_DAPM_PIN_SWITCH("TR Spk"), 148 + }; 149 + 150 + static const struct snd_soc_dapm_widget max_98390_tt_dapm_widgets[] = { 151 + SND_SOC_DAPM_SPK("TL Spk", NULL), 152 + SND_SOC_DAPM_SPK("TR Spk", NULL), 153 + }; 154 + 155 + const struct snd_soc_dapm_route max_98390_tt_dapm_routes[] = { 156 + /* Tweeter speaker */ 157 + { "TL Spk", NULL, "Tweeter Left BE_OUT" }, 158 + { "TR Spk", NULL, "Tweeter Right BE_OUT" }, 159 + }; 160 + 161 + static struct snd_soc_codec_conf max_98390_codec_conf[] = { 162 + { 163 + .dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME), 164 + .name_prefix = "Right", 165 + }, 166 + { 167 + .dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME), 168 + .name_prefix = "Left", 169 + }, 170 + }; 171 + 172 + static struct snd_soc_codec_conf max_98390_4spk_codec_conf[] = { 173 + { 174 + .dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME), 175 + .name_prefix = "Right", 176 + }, 177 + { 178 + .dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME), 179 + .name_prefix = "Left", 180 + }, 181 + { 182 + .dlc = COMP_CODEC_CONF(MAX_98390_DEV2_NAME), 183 + .name_prefix = "Tweeter Right", 184 + }, 185 + { 186 + .dlc = COMP_CODEC_CONF(MAX_98390_DEV3_NAME), 187 + .name_prefix = "Tweeter Left", 188 + }, 189 + }; 190 + 191 + struct snd_soc_dai_link_component max_98390_components[] = { 192 + { 193 + .name = MAX_98390_DEV0_NAME, 194 + .dai_name = MAX_98390_CODEC_DAI, 195 + }, 196 + { 197 + .name = MAX_98390_DEV1_NAME, 198 + .dai_name = MAX_98390_CODEC_DAI, 199 + }, 200 + }; 201 + EXPORT_SYMBOL_NS(max_98390_components, SND_SOC_INTEL_SOF_MAXIM_COMMON); 202 + 203 + struct snd_soc_dai_link_component max_98390_4spk_components[] = { 204 + { 205 + .name = MAX_98390_DEV0_NAME, 206 + .dai_name = MAX_98390_CODEC_DAI, 207 + }, 208 + { 209 + .name = MAX_98390_DEV1_NAME, 210 + .dai_name = MAX_98390_CODEC_DAI, 211 + }, 212 + { 213 + .name = MAX_98390_DEV2_NAME, 214 + .dai_name = MAX_98390_CODEC_DAI, 215 + }, 216 + { 217 + .name = MAX_98390_DEV3_NAME, 218 + .dai_name = MAX_98390_CODEC_DAI, 219 + }, 220 + }; 221 + EXPORT_SYMBOL_NS(max_98390_4spk_components, SND_SOC_INTEL_SOF_MAXIM_COMMON); 222 + 223 + static int max_98390_hw_params(struct snd_pcm_substream *substream, 224 + struct snd_pcm_hw_params *params) 225 + { 226 + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 227 + struct snd_soc_dai *codec_dai; 228 + int i; 229 + 230 + for_each_rtd_codec_dais(rtd, i, codec_dai) { 231 + if (i >= ARRAY_SIZE(max_98390_4spk_components)) { 232 + dev_err(codec_dai->dev, "invalid codec index %d\n", i); 233 + return -ENODEV; 234 + } 235 + 236 + if (!strcmp(codec_dai->component->name, MAX_98390_DEV0_NAME)) { 237 + /* DEV0 tdm slot configuration Right */ 238 + snd_soc_dai_set_tdm_slot(codec_dai, 0x01, 3, 4, 32); 239 + } 240 + if (!strcmp(codec_dai->component->name, MAX_98390_DEV1_NAME)) { 241 + /* DEV1 tdm slot configuration Left */ 242 + snd_soc_dai_set_tdm_slot(codec_dai, 0x02, 3, 4, 32); 243 + } 244 + 245 + if (!strcmp(codec_dai->component->name, MAX_98390_DEV2_NAME)) { 246 + /* DEVi2 tdm slot configuration Tweeter Right */ 247 + snd_soc_dai_set_tdm_slot(codec_dai, 0x04, 3, 4, 32); 248 + } 249 + if (!strcmp(codec_dai->component->name, MAX_98390_DEV3_NAME)) { 250 + /* DEV3 tdm slot configuration Tweeter Left */ 251 + snd_soc_dai_set_tdm_slot(codec_dai, 0x08, 3, 4, 32); 252 + } 253 + } 254 + return 0; 255 + } 256 + 257 + int max_98390_spk_codec_init(struct snd_soc_pcm_runtime *rtd) 258 + { 259 + struct snd_soc_card *card = rtd->card; 260 + int ret; 261 + 262 + /* add regular speakers dapm route */ 263 + ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_dapm_routes, 264 + ARRAY_SIZE(max_98390_dapm_routes)); 265 + if (ret) { 266 + dev_err(rtd->dev, "unable to add Left/Right Speaker dapm, ret %d\n", ret); 267 + return ret; 268 + } 269 + 270 + /* add widgets/controls/dapm for tweeter speakers */ 271 + if (acpi_dev_present("MX98390", "3", -1)) { 272 + ret = snd_soc_dapm_new_controls(&card->dapm, max_98390_tt_dapm_widgets, 273 + ARRAY_SIZE(max_98390_tt_dapm_widgets)); 274 + 275 + if (ret) { 276 + dev_err(rtd->dev, "unable to add tweeter dapm controls, ret %d\n", ret); 277 + /* Don't need to add routes if widget addition failed */ 278 + return ret; 279 + } 280 + 281 + ret = snd_soc_add_card_controls(card, max_98390_tt_kcontrols, 282 + ARRAY_SIZE(max_98390_tt_kcontrols)); 283 + if (ret) { 284 + dev_err(rtd->dev, "unable to add tweeter card controls, ret %d\n", ret); 285 + return ret; 286 + } 287 + 288 + ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_tt_dapm_routes, 289 + ARRAY_SIZE(max_98390_tt_dapm_routes)); 290 + if (ret) 291 + dev_err(rtd->dev, 292 + "unable to add Tweeter Left/Right Speaker dapm, ret %d\n", ret); 293 + } 294 + return ret; 295 + } 296 + EXPORT_SYMBOL_NS(max_98390_spk_codec_init, SND_SOC_INTEL_SOF_MAXIM_COMMON); 297 + 298 + const struct snd_soc_ops max_98390_ops = { 299 + .hw_params = max_98390_hw_params, 300 + }; 301 + EXPORT_SYMBOL_NS(max_98390_ops, SND_SOC_INTEL_SOF_MAXIM_COMMON); 302 + 303 + void max_98390_set_codec_conf(struct snd_soc_card *card, int ch) 304 + { 305 + if (ch == ARRAY_SIZE(max_98390_4spk_codec_conf)) { 306 + card->codec_conf = max_98390_4spk_codec_conf; 307 + card->num_configs = ARRAY_SIZE(max_98390_4spk_codec_conf); 308 + } else { 309 + card->codec_conf = max_98390_codec_conf; 310 + card->num_configs = ARRAY_SIZE(max_98390_codec_conf); 311 + } 312 + } 313 + EXPORT_SYMBOL_NS(max_98390_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON); 136 314 137 315 /* 138 316 * Maxim MAX98357A/MAX98360A
+16
sound/soc/intel/boards/sof_maxim_common.h
··· 25 25 int max_98373_trigger(struct snd_pcm_substream *substream, int cmd); 26 26 27 27 /* 28 + * Maxim MAX98390 29 + */ 30 + #define MAX_98390_CODEC_DAI "max98390-aif1" 31 + #define MAX_98390_DEV0_NAME "i2c-MX98390:00" 32 + #define MAX_98390_DEV1_NAME "i2c-MX98390:01" 33 + #define MAX_98390_DEV2_NAME "i2c-MX98390:02" 34 + #define MAX_98390_DEV3_NAME "i2c-MX98390:03" 35 + 36 + extern struct snd_soc_dai_link_component max_98390_components[2]; 37 + extern struct snd_soc_dai_link_component max_98390_4spk_components[4]; 38 + extern const struct snd_soc_ops max_98390_ops; 39 + 40 + void max_98390_set_codec_conf(struct snd_soc_card *card, int ch); 41 + int max_98390_spk_codec_init(struct snd_soc_pcm_runtime *rtd); 42 + 43 + /* 28 44 * Maxim MAX98357A/MAX98360A 29 45 */ 30 46 #define MAX_98357A_CODEC_DAI "HiFi"
+72
sound/soc/intel/boards/sof_rt5682.c
··· 59 59 (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK) 60 60 #define SOF_SSP_BT_OFFLOAD_PRESENT BIT(22) 61 61 #define SOF_RT5682S_HEADPHONE_CODEC_PRESENT BIT(23) 62 + #define SOF_MAX98390_SPEAKER_AMP_PRESENT BIT(24) 63 + #define SOF_MAX98390_TWEETER_SPEAKER_PRESENT BIT(25) 64 + 62 65 63 66 /* Default: MCLK on, MCLK 19.2M, SSP0 */ 64 67 static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | ··· 181 178 SOF_MAX98373_SPEAKER_AMP_PRESENT | 182 179 SOF_RT5682_SSP_AMP(2) | 183 180 SOF_RT5682_NUM_HDMIDEV(4)), 181 + }, 182 + { 183 + .callback = sof_rt5682_quirk_cb, 184 + .matches = { 185 + DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"), 186 + DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98390_ALC5682I_I2S"), 187 + }, 188 + .driver_data = (void *)(SOF_RT5682_MCLK_EN | 189 + SOF_RT5682_SSP_CODEC(0) | 190 + SOF_SPEAKER_AMP_PRESENT | 191 + SOF_MAX98390_SPEAKER_AMP_PRESENT | 192 + SOF_RT5682_SSP_AMP(2) | 193 + SOF_RT5682_NUM_HDMIDEV(4)), 194 + }, 195 + { 196 + .callback = sof_rt5682_quirk_cb, 197 + .matches = { 198 + DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"), 199 + DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98390_ALC5682I_I2S_4SPK"), 200 + }, 201 + .driver_data = (void *)(SOF_RT5682_MCLK_EN | 202 + SOF_RT5682_SSP_CODEC(0) | 203 + SOF_SPEAKER_AMP_PRESENT | 204 + SOF_MAX98390_SPEAKER_AMP_PRESENT | 205 + SOF_MAX98390_TWEETER_SPEAKER_PRESENT | 206 + SOF_RT5682_SSP_AMP(1) | 207 + SOF_RT5682_NUM_HDMIDEV(4) | 208 + SOF_BT_OFFLOAD_SSP(2) | 209 + SOF_SSP_BT_OFFLOAD_PRESENT), 210 + 184 211 }, 185 212 {} 186 213 }; ··· 519 486 if (err < 0) 520 487 return err; 521 488 } 489 + 522 490 return hdac_hdmi_jack_port_init(component, &card->dapm); 523 491 } 524 492 ··· 818 784 } else if (sof_rt5682_quirk & 819 785 SOF_RT1011_SPEAKER_AMP_PRESENT) { 820 786 sof_rt1011_dai_link(&links[id]); 787 + } else if (sof_rt5682_quirk & 788 + SOF_MAX98390_SPEAKER_AMP_PRESENT) { 789 + if (sof_rt5682_quirk & 790 + SOF_MAX98390_TWEETER_SPEAKER_PRESENT) { 791 + links[id].codecs = max_98390_4spk_components; 792 + links[id].num_codecs = ARRAY_SIZE(max_98390_4spk_components); 793 + } else { 794 + links[id].codecs = max_98390_components; 795 + links[id].num_codecs = ARRAY_SIZE(max_98390_components); 796 + } 797 + links[id].init = max_98390_spk_codec_init; 798 + links[id].ops = &max_98390_ops; 799 + links[id].dpcm_capture = 1; 800 + 821 801 } else { 822 802 max_98357a_dai_link(&links[id]); 823 803 } ··· 916 868 if (acpi_dev_present("RTL5682", NULL, -1)) 917 869 sof_rt5682_quirk |= SOF_RT5682S_HEADPHONE_CODEC_PRESENT; 918 870 871 + /* Detect the headset codec variant to support machines in DMI quirk */ 872 + if (acpi_dev_present("RTL5682", NULL, -1)) 873 + sof_rt5682_quirk |= SOF_RT5682S_HEADPHONE_CODEC_PRESENT; 874 + 919 875 if (soc_intel_is_byt() || soc_intel_is_cht()) { 920 876 is_legacy_cpu = 1; 921 877 dmic_be_num = 0; ··· 976 924 sof_rt1011_codec_conf(&sof_audio_card_rt5682); 977 925 else if (sof_rt5682_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) 978 926 sof_rt1015p_codec_conf(&sof_audio_card_rt5682); 927 + else if (sof_rt5682_quirk & SOF_MAX98390_SPEAKER_AMP_PRESENT) { 928 + if (sof_rt5682_quirk & SOF_MAX98390_TWEETER_SPEAKER_PRESENT) 929 + max_98390_set_codec_conf(&sof_audio_card_rt5682, 930 + ARRAY_SIZE(max_98390_4spk_components)); 931 + else 932 + max_98390_set_codec_conf(&sof_audio_card_rt5682, 933 + ARRAY_SIZE(max_98390_components)); 934 + } 979 935 980 936 if (sof_rt5682_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) 981 937 sof_audio_card_rt5682.num_links++; ··· 1111 1051 SOF_RT5682_NUM_HDMIDEV(4)), 1112 1052 }, 1113 1053 { 1054 + .name = "adl_max98390_rt5682", 1055 + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | 1056 + SOF_RT5682_SSP_CODEC(0) | 1057 + SOF_SPEAKER_AMP_PRESENT | 1058 + SOF_MAX98390_SPEAKER_AMP_PRESENT | 1059 + SOF_RT5682_SSP_AMP(1) | 1060 + SOF_RT5682_NUM_HDMIDEV(4) | 1061 + SOF_BT_OFFLOAD_SSP(2) | 1062 + SOF_SSP_BT_OFFLOAD_PRESENT), 1063 + }, 1064 + { 1114 1065 .name = "adl_mx98360_rt5682", 1115 1066 .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | 1116 1067 SOF_RT5682_SSP_CODEC(0) | ··· 1151 1080 MODULE_AUTHOR("Bard Liao <bard.liao@intel.com>"); 1152 1081 MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>"); 1153 1082 MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); 1083 + MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>"); 1154 1084 MODULE_LICENSE("GPL v2"); 1155 1085 MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); 1156 1086 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);
+13
sound/soc/intel/common/soc-acpi-intel-adl-match.c
··· 379 379 .codecs = {"RTL1019"} 380 380 }; 381 381 382 + static const struct snd_soc_acpi_codecs adl_max98390_amp = { 383 + .num_codecs = 1, 384 + .codecs = {"MX98390"} 385 + }; 386 + 382 387 struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { 383 388 { 384 389 .comp_ids = &adl_rt5682_rt5682s_hp, ··· 438 433 .drv_name = "sof_nau8825", 439 434 .sof_fw_filename = "sof-adl.ri", 440 435 .sof_tplg_filename = "sof-adl-nau8825.tplg", 436 + }, 437 + { 438 + .comp_ids = &adl_rt5682_rt5682s_hp, 439 + .drv_name = "adl_max98390_rt5682", 440 + .machine_quirk = snd_soc_acpi_codec_list, 441 + .quirk_data = &adl_max98390_amp, 442 + .sof_fw_filename = "sof-adl.ri", 443 + .sof_tplg_filename = "sof-adl-max98390-rt5682.tplg", 441 444 }, 442 445 {}, 443 446 };
+9
sound/soc/sof/sof-pci-dev.c
··· 59 59 }, 60 60 .driver_data = "sof-adl-rt5682-ssp0-max98373-ssp2.tplg", 61 61 }, 62 + { 63 + .callback = sof_tplg_cb, 64 + .matches = { 65 + DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"), 66 + DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98390_ALC5682I_I2S"), 67 + }, 68 + .driver_data = "sof-adl-max98390-ssp2-rt5682-ssp0.tplg", 69 + }, 70 + 62 71 {} 63 72 }; 64 73