1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // Copyright(c) 2020 Intel Corporation. All rights reserved. 4 #include <linux/module.h> 5 #include <linux/string.h> 6 #include <sound/pcm.h> 7 #include <sound/pcm_params.h> 8 #include <sound/soc.h> 9 #include <sound/soc-acpi.h> 10 #include <sound/soc-dai.h> 11 #include <sound/soc-dapm.h> 12 #include <uapi/sound/asound.h> 13 #include "sof_maxim_common.h" 14 15 /* helper function to get the number of specific codec */ 16 static unsigned int get_num_codecs(const char *hid) 17 { 18 struct acpi_device *adev; 19 unsigned int dev_num = 0; 20 21 for_each_acpi_dev_match(adev, hid, NULL, -1) 22 dev_num++; 23 24 return dev_num; 25 } 26 27 #define MAX_98373_PIN_NAME 16 28 29 const struct snd_soc_dapm_route max_98373_dapm_routes[] = { 30 /* speaker */ 31 { "Left Spk", NULL, "Left BE_OUT" }, 32 { "Right Spk", NULL, "Right BE_OUT" }, 33 }; 34 EXPORT_SYMBOL_NS(max_98373_dapm_routes, SND_SOC_INTEL_SOF_MAXIM_COMMON); 35 36 static struct snd_soc_codec_conf max_98373_codec_conf[] = { 37 { 38 .dlc = COMP_CODEC_CONF(MAX_98373_DEV0_NAME), 39 .name_prefix = "Right", 40 }, 41 { 42 .dlc = COMP_CODEC_CONF(MAX_98373_DEV1_NAME), 43 .name_prefix = "Left", 44 }, 45 }; 46 47 struct snd_soc_dai_link_component max_98373_components[] = { 48 { /* For Right */ 49 .name = MAX_98373_DEV0_NAME, 50 .dai_name = MAX_98373_CODEC_DAI, 51 }, 52 { /* For Left */ 53 .name = MAX_98373_DEV1_NAME, 54 .dai_name = MAX_98373_CODEC_DAI, 55 }, 56 }; 57 EXPORT_SYMBOL_NS(max_98373_components, SND_SOC_INTEL_SOF_MAXIM_COMMON); 58 59 static int max_98373_hw_params(struct snd_pcm_substream *substream, 60 struct snd_pcm_hw_params *params) 61 { 62 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 63 struct snd_soc_dai *codec_dai; 64 int ret = 0; 65 int j; 66 67 for_each_rtd_codec_dais(rtd, j, codec_dai) { 68 if (!strcmp(codec_dai->component->name, MAX_98373_DEV0_NAME)) { 69 /* DEV0 tdm slot configuration */ 70 ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x03, 3, 8, 32); 71 } else if (!strcmp(codec_dai->component->name, MAX_98373_DEV1_NAME)) { 72 /* DEV1 tdm slot configuration */ 73 ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0C, 3, 8, 32); 74 } 75 if (ret < 0) { 76 dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n", 77 ret); 78 return ret; 79 } 80 } 81 return 0; 82 } 83 84 int max_98373_trigger(struct snd_pcm_substream *substream, int cmd) 85 { 86 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 87 struct snd_soc_dai *codec_dai; 88 struct snd_soc_dai *cpu_dai; 89 int j; 90 int ret = 0; 91 92 /* set spk pin by playback only */ 93 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 94 return 0; 95 96 cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); 97 for_each_rtd_codec_dais(rtd, j, codec_dai) { 98 struct snd_soc_dapm_context *dapm = 99 snd_soc_component_get_dapm(cpu_dai->component); 100 char pin_name[MAX_98373_PIN_NAME]; 101 102 snprintf(pin_name, ARRAY_SIZE(pin_name), "%s Spk", 103 codec_dai->component->name_prefix); 104 105 switch (cmd) { 106 case SNDRV_PCM_TRIGGER_START: 107 case SNDRV_PCM_TRIGGER_RESUME: 108 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 109 ret = snd_soc_dapm_enable_pin(dapm, pin_name); 110 if (!ret) 111 snd_soc_dapm_sync(dapm); 112 break; 113 case SNDRV_PCM_TRIGGER_STOP: 114 case SNDRV_PCM_TRIGGER_SUSPEND: 115 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 116 ret = snd_soc_dapm_disable_pin(dapm, pin_name); 117 if (!ret) 118 snd_soc_dapm_sync(dapm); 119 break; 120 default: 121 break; 122 } 123 } 124 125 return ret; 126 } 127 EXPORT_SYMBOL_NS(max_98373_trigger, SND_SOC_INTEL_SOF_MAXIM_COMMON); 128 129 struct snd_soc_ops max_98373_ops = { 130 .hw_params = max_98373_hw_params, 131 .trigger = max_98373_trigger, 132 }; 133 EXPORT_SYMBOL_NS(max_98373_ops, SND_SOC_INTEL_SOF_MAXIM_COMMON); 134 135 int max_98373_spk_codec_init(struct snd_soc_pcm_runtime *rtd) 136 { 137 struct snd_soc_card *card = rtd->card; 138 int ret; 139 140 ret = snd_soc_dapm_add_routes(&card->dapm, max_98373_dapm_routes, 141 ARRAY_SIZE(max_98373_dapm_routes)); 142 if (ret) 143 dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); 144 return ret; 145 } 146 EXPORT_SYMBOL_NS(max_98373_spk_codec_init, SND_SOC_INTEL_SOF_MAXIM_COMMON); 147 148 void max_98373_set_codec_conf(struct snd_soc_card *card) 149 { 150 card->codec_conf = max_98373_codec_conf; 151 card->num_configs = ARRAY_SIZE(max_98373_codec_conf); 152 } 153 EXPORT_SYMBOL_NS(max_98373_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON); 154 155 /* 156 * Maxim MAX98390 157 */ 158 static const struct snd_soc_dapm_route max_98390_dapm_routes[] = { 159 /* speaker */ 160 { "Left Spk", NULL, "Left BE_OUT" }, 161 { "Right Spk", NULL, "Right BE_OUT" }, 162 }; 163 164 static const struct snd_kcontrol_new max_98390_tt_kcontrols[] = { 165 SOC_DAPM_PIN_SWITCH("TL Spk"), 166 SOC_DAPM_PIN_SWITCH("TR Spk"), 167 }; 168 169 static const struct snd_soc_dapm_widget max_98390_tt_dapm_widgets[] = { 170 SND_SOC_DAPM_SPK("TL Spk", NULL), 171 SND_SOC_DAPM_SPK("TR Spk", NULL), 172 }; 173 174 static const struct snd_soc_dapm_route max_98390_tt_dapm_routes[] = { 175 /* Tweeter speaker */ 176 { "TL Spk", NULL, "Tweeter Left BE_OUT" }, 177 { "TR Spk", NULL, "Tweeter Right BE_OUT" }, 178 }; 179 180 static struct snd_soc_codec_conf max_98390_codec_conf[] = { 181 { 182 .dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME), 183 .name_prefix = "Right", 184 }, 185 { 186 .dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME), 187 .name_prefix = "Left", 188 }, 189 { 190 .dlc = COMP_CODEC_CONF(MAX_98390_DEV2_NAME), 191 .name_prefix = "Tweeter Right", 192 }, 193 { 194 .dlc = COMP_CODEC_CONF(MAX_98390_DEV3_NAME), 195 .name_prefix = "Tweeter Left", 196 }, 197 }; 198 199 static struct snd_soc_dai_link_component max_98390_components[] = { 200 { 201 .name = MAX_98390_DEV0_NAME, 202 .dai_name = MAX_98390_CODEC_DAI, 203 }, 204 { 205 .name = MAX_98390_DEV1_NAME, 206 .dai_name = MAX_98390_CODEC_DAI, 207 }, 208 { 209 .name = MAX_98390_DEV2_NAME, 210 .dai_name = MAX_98390_CODEC_DAI, 211 }, 212 { 213 .name = MAX_98390_DEV3_NAME, 214 .dai_name = MAX_98390_CODEC_DAI, 215 }, 216 }; 217 218 static const struct { 219 unsigned int tx; 220 unsigned int rx; 221 } max_98390_tdm_mask[] = { 222 {.tx = 0x01, .rx = 0x3}, 223 {.tx = 0x02, .rx = 0x3}, 224 {.tx = 0x04, .rx = 0x3}, 225 {.tx = 0x08, .rx = 0x3}, 226 }; 227 228 static int max_98390_hw_params(struct snd_pcm_substream *substream, 229 struct snd_pcm_hw_params *params) 230 { 231 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 232 struct snd_soc_dai *codec_dai; 233 int i, ret; 234 235 for_each_rtd_codec_dais(rtd, i, codec_dai) { 236 if (i >= ARRAY_SIZE(max_98390_tdm_mask)) { 237 dev_err(codec_dai->dev, "invalid codec index %d\n", i); 238 return -ENODEV; 239 } 240 241 ret = snd_soc_dai_set_tdm_slot(codec_dai, max_98390_tdm_mask[i].tx, 242 max_98390_tdm_mask[i].rx, 4, 243 params_width(params)); 244 if (ret < 0) { 245 dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n", 246 ret); 247 return ret; 248 } 249 } 250 return 0; 251 } 252 253 static int max_98390_init(struct snd_soc_pcm_runtime *rtd) 254 { 255 struct snd_soc_card *card = rtd->card; 256 unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID); 257 int ret; 258 259 switch (num_codecs) { 260 case 4: 261 /* add widgets/controls/dapm for tweeter speakers */ 262 ret = snd_soc_dapm_new_controls(&card->dapm, max_98390_tt_dapm_widgets, 263 ARRAY_SIZE(max_98390_tt_dapm_widgets)); 264 if (ret) { 265 dev_err(rtd->dev, "unable to add tweeter dapm widgets, ret %d\n", 266 ret); 267 /* Don't need to add routes if widget addition failed */ 268 return ret; 269 } 270 271 ret = snd_soc_add_card_controls(card, max_98390_tt_kcontrols, 272 ARRAY_SIZE(max_98390_tt_kcontrols)); 273 if (ret) { 274 dev_err(rtd->dev, "unable to add tweeter controls, ret %d\n", 275 ret); 276 return ret; 277 } 278 279 ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_tt_dapm_routes, 280 ARRAY_SIZE(max_98390_tt_dapm_routes)); 281 if (ret) { 282 dev_err(rtd->dev, "unable to add tweeter dapm routes, ret %d\n", 283 ret); 284 return ret; 285 } 286 287 fallthrough; 288 case 2: 289 /* add regular speakers dapm route */ 290 ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_dapm_routes, 291 ARRAY_SIZE(max_98390_dapm_routes)); 292 if (ret) { 293 dev_err(rtd->dev, "unable to add dapm routes, ret %d\n", 294 ret); 295 return ret; 296 } 297 break; 298 default: 299 dev_err(rtd->dev, "invalid codec number %d\n", num_codecs); 300 return -EINVAL; 301 } 302 303 return ret; 304 } 305 306 static const struct snd_soc_ops max_98390_ops = { 307 .hw_params = max_98390_hw_params, 308 }; 309 310 void max_98390_dai_link(struct device *dev, struct snd_soc_dai_link *link) 311 { 312 unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID); 313 314 link->codecs = max_98390_components; 315 316 switch (num_codecs) { 317 case 2: 318 case 4: 319 link->num_codecs = num_codecs; 320 break; 321 default: 322 dev_err(dev, "invalid codec number %d for %s\n", num_codecs, 323 MAX_98390_ACPI_HID); 324 break; 325 } 326 327 link->init = max_98390_init; 328 link->ops = &max_98390_ops; 329 } 330 EXPORT_SYMBOL_NS(max_98390_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON); 331 332 void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card) 333 { 334 unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID); 335 336 card->codec_conf = max_98390_codec_conf; 337 338 switch (num_codecs) { 339 case 2: 340 case 4: 341 card->num_configs = num_codecs; 342 break; 343 default: 344 dev_err(dev, "invalid codec number %d for %s\n", num_codecs, 345 MAX_98390_ACPI_HID); 346 break; 347 } 348 } 349 EXPORT_SYMBOL_NS(max_98390_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON); 350 351 /* 352 * Maxim MAX98357A/MAX98360A 353 */ 354 static const struct snd_kcontrol_new max_98357a_kcontrols[] = { 355 SOC_DAPM_PIN_SWITCH("Spk"), 356 }; 357 358 static const struct snd_soc_dapm_widget max_98357a_dapm_widgets[] = { 359 SND_SOC_DAPM_SPK("Spk", NULL), 360 }; 361 362 static const struct snd_soc_dapm_route max_98357a_dapm_routes[] = { 363 /* speaker */ 364 {"Spk", NULL, "Speaker"}, 365 }; 366 367 static struct snd_soc_dai_link_component max_98357a_components[] = { 368 { 369 .name = MAX_98357A_DEV0_NAME, 370 .dai_name = MAX_98357A_CODEC_DAI, 371 } 372 }; 373 374 static struct snd_soc_dai_link_component max_98360a_components[] = { 375 { 376 .name = MAX_98360A_DEV0_NAME, 377 .dai_name = MAX_98357A_CODEC_DAI, 378 } 379 }; 380 381 static int max_98357a_init(struct snd_soc_pcm_runtime *rtd) 382 { 383 struct snd_soc_card *card = rtd->card; 384 int ret; 385 386 ret = snd_soc_dapm_new_controls(&card->dapm, max_98357a_dapm_widgets, 387 ARRAY_SIZE(max_98357a_dapm_widgets)); 388 if (ret) { 389 dev_err(rtd->dev, "unable to add dapm controls, ret %d\n", ret); 390 /* Don't need to add routes if widget addition failed */ 391 return ret; 392 } 393 394 ret = snd_soc_add_card_controls(card, max_98357a_kcontrols, 395 ARRAY_SIZE(max_98357a_kcontrols)); 396 if (ret) { 397 dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); 398 return ret; 399 } 400 401 ret = snd_soc_dapm_add_routes(&card->dapm, max_98357a_dapm_routes, 402 ARRAY_SIZE(max_98357a_dapm_routes)); 403 404 if (ret) 405 dev_err(rtd->dev, "unable to add dapm routes, ret %d\n", ret); 406 407 return ret; 408 } 409 410 void max_98357a_dai_link(struct snd_soc_dai_link *link) 411 { 412 link->codecs = max_98357a_components; 413 link->num_codecs = ARRAY_SIZE(max_98357a_components); 414 link->init = max_98357a_init; 415 } 416 EXPORT_SYMBOL_NS(max_98357a_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON); 417 418 void max_98360a_dai_link(struct snd_soc_dai_link *link) 419 { 420 link->codecs = max_98360a_components; 421 link->num_codecs = ARRAY_SIZE(max_98360a_components); 422 link->init = max_98357a_init; 423 } 424 EXPORT_SYMBOL_NS(max_98360a_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON); 425 426 MODULE_DESCRIPTION("ASoC Intel SOF Maxim helpers"); 427 MODULE_LICENSE("GPL"); 428