1 // SPDX-License-Identifier: GPL-2.0-only 2 // Copyright(c) 2019 Intel Corporation. 3 4 /* 5 * Intel SOF Machine driver for Dialog headphone codec 6 */ 7 8 #include <linux/input.h> 9 #include <linux/module.h> 10 #include <sound/jack.h> 11 #include <sound/pcm.h> 12 #include <sound/pcm_params.h> 13 #include <linux/platform_device.h> 14 #include <sound/soc.h> 15 #include <sound/soc-acpi.h> 16 #include <sound/sof.h> 17 #include "../../codecs/da7219.h" 18 #include "sof_board_helpers.h" 19 #include "sof_maxim_common.h" 20 21 /* Driver-specific board quirks: from bit 0 to 7 */ 22 #define SOF_DA7219_GLK_BOARD BIT(0) 23 #define SOF_DA7219_CML_BOARD BIT(1) 24 #define SOF_DA7219_JSL_BOARD BIT(2) 25 #define SOF_DA7219_MCLK_EN BIT(3) 26 27 #define DIALOG_CODEC_DAI "da7219-hifi" 28 29 static int platform_clock_control(struct snd_soc_dapm_widget *w, 30 struct snd_kcontrol *k, int event) 31 { 32 struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm); 33 struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); 34 struct snd_soc_dai *codec_dai; 35 int ret = 0; 36 37 if (ctx->da7219.pll_bypass) 38 return ret; 39 40 /* PLL SRM mode */ 41 codec_dai = snd_soc_card_get_codec_dai(card, DIALOG_CODEC_DAI); 42 if (!codec_dai) { 43 dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n"); 44 return -EIO; 45 } 46 47 if (SND_SOC_DAPM_EVENT_OFF(event)) { 48 ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 49 0, 0); 50 if (ret) 51 dev_err(card->dev, "failed to stop PLL: %d\n", ret); 52 } else if (SND_SOC_DAPM_EVENT_ON(event)) { 53 dev_dbg(card->dev, "pll srm mode\n"); 54 55 ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM, 56 0, DA7219_PLL_FREQ_OUT_98304); 57 if (ret) 58 dev_err(card->dev, "failed to start PLL: %d\n", ret); 59 } 60 61 return ret; 62 } 63 64 static const struct snd_kcontrol_new controls[] = { 65 SOC_DAPM_PIN_SWITCH("Headphone Jack"), 66 SOC_DAPM_PIN_SWITCH("Headset Mic"), 67 SOC_DAPM_PIN_SWITCH("Line Out"), 68 }; 69 70 static const struct snd_soc_dapm_widget widgets[] = { 71 SND_SOC_DAPM_HP("Headphone Jack", NULL), 72 SND_SOC_DAPM_MIC("Headset Mic", NULL), 73 SND_SOC_DAPM_LINE("Line Out", NULL), 74 75 SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, 76 platform_clock_control, SND_SOC_DAPM_POST_PMD | 77 SND_SOC_DAPM_PRE_PMU), 78 }; 79 80 static const struct snd_soc_dapm_route audio_map[] = { 81 { "Headphone Jack", NULL, "HPL" }, 82 { "Headphone Jack", NULL, "HPR" }, 83 84 { "MIC", NULL, "Headset Mic" }, 85 86 { "Headphone Jack", NULL, "Platform Clock" }, 87 { "Headset Mic", NULL, "Platform Clock" }, 88 { "Line Out", NULL, "Platform Clock" }, 89 }; 90 91 static struct snd_soc_jack_pin jack_pins[] = { 92 { 93 .pin = "Headphone Jack", 94 .mask = SND_JACK_HEADPHONE, 95 }, 96 { 97 .pin = "Headset Mic", 98 .mask = SND_JACK_MICROPHONE, 99 }, 100 { 101 .pin = "Line Out", 102 .mask = SND_JACK_LINEOUT, 103 }, 104 }; 105 106 static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd) 107 { 108 struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); 109 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); 110 struct snd_soc_component *component = codec_dai->component; 111 struct snd_soc_jack *jack = &ctx->headset_jack; 112 int mclk_rate, ret; 113 114 mclk_rate = sof_dai_get_mclk(rtd); 115 if (mclk_rate <= 0) { 116 dev_err(rtd->dev, "invalid mclk freq %d\n", mclk_rate); 117 return -EINVAL; 118 } 119 120 ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, mclk_rate, 121 SND_SOC_CLOCK_IN); 122 if (ret) { 123 dev_err(rtd->dev, "fail to set sysclk, ret %d\n", ret); 124 return ret; 125 } 126 127 /* 128 * Use PLL bypass mode if MCLK is available, be sure to set the 129 * frequency of MCLK to 12.288 or 24.576MHz on topology side. 130 */ 131 if (ctx->da7219.mclk_en && 132 (mclk_rate == 12288000 || mclk_rate == 24576000)) { 133 /* PLL bypass mode */ 134 dev_dbg(rtd->dev, "pll bypass mode, mclk rate %d\n", mclk_rate); 135 136 ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0); 137 if (ret) { 138 dev_err(rtd->dev, "fail to set pll, ret %d\n", ret); 139 return ret; 140 } 141 142 ctx->da7219.pll_bypass = true; 143 } 144 145 /* 146 * Headset buttons map to the google Reference headset. 147 * These can be configured by userspace. 148 */ 149 ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", 150 SND_JACK_HEADSET | SND_JACK_BTN_0 | 151 SND_JACK_BTN_1 | SND_JACK_BTN_2 | 152 SND_JACK_BTN_3 | SND_JACK_LINEOUT, 153 jack, jack_pins, ARRAY_SIZE(jack_pins)); 154 if (ret) { 155 dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); 156 return ret; 157 } 158 159 snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); 160 snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); 161 snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); 162 snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); 163 164 ret = snd_soc_component_set_jack(component, jack, NULL); 165 if (ret) { 166 dev_err(rtd->dev, "fail to set component jack, ret %d\n", ret); 167 return ret; 168 } 169 170 return ret; 171 } 172 173 static void da7219_codec_exit(struct snd_soc_pcm_runtime *rtd) 174 { 175 struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; 176 177 snd_soc_component_set_jack(component, NULL, NULL); 178 } 179 180 static int card_late_probe(struct snd_soc_card *card) 181 { 182 struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); 183 struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); 184 int err; 185 186 if (ctx->amp_type == CODEC_MAX98373) { 187 /* Disable Left and Right Spk pin after boot */ 188 snd_soc_dapm_disable_pin(dapm, "Left Spk"); 189 snd_soc_dapm_disable_pin(dapm, "Right Spk"); 190 err = snd_soc_dapm_sync(dapm); 191 if (err < 0) 192 return err; 193 } 194 195 return sof_intel_board_card_late_probe(card); 196 } 197 198 static struct snd_soc_card card_da7219 = { 199 .name = "da7219", /* the sof- prefix is added by the core */ 200 .owner = THIS_MODULE, 201 .controls = controls, 202 .num_controls = ARRAY_SIZE(controls), 203 .dapm_widgets = widgets, 204 .num_dapm_widgets = ARRAY_SIZE(widgets), 205 .dapm_routes = audio_map, 206 .num_dapm_routes = ARRAY_SIZE(audio_map), 207 .fully_routed = true, 208 .late_probe = card_late_probe, 209 }; 210 211 static struct snd_soc_dai_link_component da7219_component[] = { 212 { 213 .name = "i2c-DLGS7219:00", 214 .dai_name = DIALOG_CODEC_DAI, 215 } 216 }; 217 218 static int 219 sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card, 220 struct sof_card_private *ctx) 221 { 222 int ret; 223 224 ret = sof_intel_board_set_dai_link(dev, card, ctx); 225 if (ret) 226 return ret; 227 228 if (!ctx->codec_link) { 229 dev_err(dev, "codec link not available"); 230 return -EINVAL; 231 } 232 233 /* codec-specific fields for headphone codec */ 234 ctx->codec_link->codecs = da7219_component; 235 ctx->codec_link->num_codecs = ARRAY_SIZE(da7219_component); 236 ctx->codec_link->init = da7219_codec_init; 237 ctx->codec_link->exit = da7219_codec_exit; 238 239 if (ctx->amp_type == CODEC_NONE) 240 return 0; 241 242 if (!ctx->amp_link) { 243 dev_err(dev, "amp link not available"); 244 return -EINVAL; 245 } 246 247 /* codec-specific fields for speaker amplifier */ 248 switch (ctx->amp_type) { 249 case CODEC_MAX98357A: 250 max_98357a_dai_link(ctx->amp_link); 251 break; 252 case CODEC_MAX98360A: 253 max_98360a_dai_link(ctx->amp_link); 254 break; 255 case CODEC_MAX98373: 256 max_98373_dai_link(dev, ctx->amp_link); 257 break; 258 case CODEC_MAX98390: 259 max_98390_dai_link(dev, ctx->amp_link); 260 break; 261 default: 262 dev_err(dev, "invalid amp type %d\n", ctx->amp_type); 263 return -EINVAL; 264 } 265 266 return 0; 267 } 268 269 #define GLK_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \ 270 SOF_LINK_CODEC, \ 271 SOF_LINK_DMIC01, \ 272 SOF_LINK_IDISP_HDMI, \ 273 SOF_LINK_NONE, \ 274 SOF_LINK_NONE, \ 275 SOF_LINK_NONE) 276 277 #define CML_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \ 278 SOF_LINK_CODEC, \ 279 SOF_LINK_DMIC01, \ 280 SOF_LINK_IDISP_HDMI, \ 281 SOF_LINK_DMIC16K, \ 282 SOF_LINK_NONE, \ 283 SOF_LINK_NONE) 284 285 #define JSL_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \ 286 SOF_LINK_CODEC, \ 287 SOF_LINK_DMIC01, \ 288 SOF_LINK_IDISP_HDMI, \ 289 SOF_LINK_DMIC16K, \ 290 SOF_LINK_NONE, \ 291 SOF_LINK_NONE) 292 293 static int audio_probe(struct platform_device *pdev) 294 { 295 struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; 296 struct sof_card_private *ctx; 297 char *card_name; 298 unsigned long board_quirk = 0; 299 int ret; 300 301 if (pdev->id_entry && pdev->id_entry->driver_data) 302 board_quirk = (unsigned long)pdev->id_entry->driver_data; 303 304 dev_dbg(&pdev->dev, "board_quirk = %lx\n", board_quirk); 305 306 /* initialize ctx with board quirk */ 307 ctx = sof_intel_board_get_ctx(&pdev->dev, board_quirk); 308 if (!ctx) 309 return -ENOMEM; 310 311 if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) 312 ctx->hdmi.idisp_codec = true; 313 314 if (board_quirk & SOF_DA7219_GLK_BOARD) { 315 /* dmic16k not support */ 316 ctx->dmic_be_num = 1; 317 318 /* overwrite the DAI link order for GLK boards */ 319 ctx->link_order_overwrite = GLK_LINK_ORDER; 320 321 /* backward-compatible with existing devices */ 322 switch (ctx->amp_type) { 323 case CODEC_MAX98357A: 324 card_name = devm_kstrdup(&pdev->dev, "glkda7219max", 325 GFP_KERNEL); 326 if (!card_name) 327 return -ENOMEM; 328 329 card_da7219.name = card_name; 330 break; 331 default: 332 break; 333 } 334 } else if (board_quirk & SOF_DA7219_CML_BOARD) { 335 /* overwrite the DAI link order for CML boards */ 336 ctx->link_order_overwrite = CML_LINK_ORDER; 337 338 /* backward-compatible with existing devices */ 339 switch (ctx->amp_type) { 340 case CODEC_MAX98357A: 341 card_name = devm_kstrdup(&pdev->dev, "cmlda7219max", 342 GFP_KERNEL); 343 if (!card_name) 344 return -ENOMEM; 345 346 card_da7219.name = card_name; 347 break; 348 case CODEC_MAX98390: 349 card_name = devm_kstrdup(&pdev->dev, 350 "cml_max98390_da7219", 351 GFP_KERNEL); 352 if (!card_name) 353 return -ENOMEM; 354 355 card_da7219.name = card_name; 356 break; 357 default: 358 break; 359 } 360 } else if (board_quirk & SOF_DA7219_JSL_BOARD) { 361 /* overwrite the DAI link order for JSL boards */ 362 ctx->link_order_overwrite = JSL_LINK_ORDER; 363 364 /* backward-compatible with existing devices */ 365 switch (ctx->amp_type) { 366 case CODEC_MAX98360A: 367 card_name = devm_kstrdup(&pdev->dev, "da7219max98360a", 368 GFP_KERNEL); 369 if (!card_name) 370 return -ENOMEM; 371 372 card_da7219.name = card_name; 373 break; 374 case CODEC_MAX98373: 375 card_name = devm_kstrdup(&pdev->dev, "da7219max", 376 GFP_KERNEL); 377 if (!card_name) 378 return -ENOMEM; 379 380 card_da7219.name = card_name; 381 break; 382 default: 383 break; 384 } 385 } 386 387 if (board_quirk & SOF_DA7219_MCLK_EN) 388 ctx->da7219.mclk_en = true; 389 390 /* update dai_link */ 391 ret = sof_card_dai_links_create(&pdev->dev, &card_da7219, ctx); 392 if (ret) 393 return ret; 394 395 /* update codec_conf */ 396 switch (ctx->amp_type) { 397 case CODEC_MAX98373: 398 max_98373_set_codec_conf(&card_da7219); 399 break; 400 case CODEC_MAX98390: 401 max_98390_set_codec_conf(&pdev->dev, &card_da7219); 402 break; 403 case CODEC_MAX98357A: 404 case CODEC_MAX98360A: 405 case CODEC_NONE: 406 /* no codec conf required */ 407 break; 408 default: 409 dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type); 410 return -EINVAL; 411 } 412 413 card_da7219.dev = &pdev->dev; 414 415 ret = snd_soc_fixup_dai_links_platform_name(&card_da7219, 416 mach->mach_params.platform); 417 if (ret) 418 return ret; 419 420 snd_soc_card_set_drvdata(&card_da7219, ctx); 421 422 return devm_snd_soc_register_card(&pdev->dev, &card_da7219); 423 } 424 425 static const struct platform_device_id board_ids[] = { 426 { 427 .name = "glk_da7219_def", 428 .driver_data = (kernel_ulong_t)(SOF_DA7219_GLK_BOARD | 429 SOF_SSP_PORT_CODEC(2) | 430 SOF_SSP_PORT_AMP(1)), 431 }, 432 { 433 .name = "cml_da7219_def", 434 .driver_data = (kernel_ulong_t)(SOF_DA7219_CML_BOARD | 435 SOF_SSP_PORT_CODEC(0) | 436 SOF_SSP_PORT_AMP(1)), 437 }, 438 { 439 .name = "jsl_da7219_def", 440 .driver_data = (kernel_ulong_t)(SOF_DA7219_JSL_BOARD | 441 SOF_SSP_PORT_CODEC(0) | 442 SOF_SSP_PORT_AMP(1)), 443 }, 444 { 445 .name = "adl_da7219_def", 446 .driver_data = (kernel_ulong_t)(SOF_DA7219_MCLK_EN | 447 SOF_SSP_PORT_CODEC(0) | 448 SOF_SSP_PORT_AMP(1) | 449 SOF_NUM_IDISP_HDMI(4) | 450 SOF_SSP_PORT_BT_OFFLOAD(2) | 451 SOF_BT_OFFLOAD_PRESENT), 452 }, 453 { 454 .name = "rpl_da7219_def", 455 .driver_data = (kernel_ulong_t)(SOF_DA7219_MCLK_EN | 456 SOF_SSP_PORT_CODEC(0) | 457 SOF_SSP_PORT_AMP(1) | 458 SOF_NUM_IDISP_HDMI(4) | 459 SOF_SSP_PORT_BT_OFFLOAD(2) | 460 SOF_BT_OFFLOAD_PRESENT), 461 }, 462 { 463 .name = "mtl_da7219_def", 464 .driver_data = (kernel_ulong_t)(SOF_DA7219_MCLK_EN | 465 SOF_SSP_PORT_CODEC(2) | 466 SOF_SSP_PORT_AMP(0) | 467 SOF_SSP_PORT_BT_OFFLOAD(1) | 468 SOF_BT_OFFLOAD_PRESENT), 469 }, 470 { } 471 }; 472 MODULE_DEVICE_TABLE(platform, board_ids); 473 474 static struct platform_driver audio = { 475 .probe = audio_probe, 476 .driver = { 477 .name = "sof_da7219", 478 .pm = &snd_soc_pm_ops, 479 }, 480 .id_table = board_ids, 481 }; 482 module_platform_driver(audio) 483 484 /* Module information */ 485 MODULE_DESCRIPTION("ASoC Intel(R) SOF Machine driver for Dialog codec"); 486 MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>"); 487 MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); 488 MODULE_LICENSE("GPL v2"); 489 MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS"); 490 MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_MAXIM_COMMON"); 491