1 // SPDX-License-Identifier: GPL-2.0 2 // 3 // mt8183-da7219-max98357.c 4 // -- MT8183-DA7219-MAX98357 ALSA SoC machine driver 5 // 6 // Copyright (c) 2018 MediaTek Inc. 7 // Author: Shunli Wang <shunli.wang@mediatek.com> 8 9 #include <linux/module.h> 10 #include <sound/pcm_params.h> 11 #include <sound/soc.h> 12 #include <sound/jack.h> 13 #include <linux/pinctrl/consumer.h> 14 15 #include "mt8183-afe-common.h" 16 #include "../../codecs/da7219-aad.h" 17 #include "../../codecs/da7219.h" 18 19 static struct snd_soc_jack headset_jack; 20 21 /* Headset jack detection DAPM pins */ 22 static struct snd_soc_jack_pin headset_jack_pins[] = { 23 { 24 .pin = "Headphone", 25 .mask = SND_JACK_HEADPHONE, 26 }, 27 { 28 .pin = "Headset Mic", 29 .mask = SND_JACK_MICROPHONE, 30 }, 31 }; 32 33 static struct snd_soc_dai_link_component 34 mt8183_da7219_max98357_external_codecs[] = { 35 { 36 .name = "max98357a", 37 .dai_name = "HiFi", 38 }, 39 { 40 .name = "da7219.5-001a", 41 .dai_name = "da7219-hifi", 42 }, 43 }; 44 45 static int mt8183_mt6358_i2s_hw_params(struct snd_pcm_substream *substream, 46 struct snd_pcm_hw_params *params) 47 { 48 struct snd_soc_pcm_runtime *rtd = substream->private_data; 49 unsigned int rate = params_rate(params); 50 unsigned int mclk_fs_ratio = 128; 51 unsigned int mclk_fs = rate * mclk_fs_ratio; 52 53 return snd_soc_dai_set_sysclk(rtd->cpu_dai, 54 0, mclk_fs, SND_SOC_CLOCK_OUT); 55 } 56 57 static const struct snd_soc_ops mt8183_mt6358_i2s_ops = { 58 .hw_params = mt8183_mt6358_i2s_hw_params, 59 }; 60 61 static int mt8183_da7219_i2s_hw_params(struct snd_pcm_substream *substream, 62 struct snd_pcm_hw_params *params) 63 { 64 struct snd_soc_pcm_runtime *rtd = substream->private_data; 65 unsigned int rate = params_rate(params); 66 unsigned int mclk_fs_ratio = 256; 67 unsigned int mclk_fs = rate * mclk_fs_ratio; 68 unsigned int freq; 69 int ret = 0, j; 70 71 ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, 0, 72 mclk_fs, SND_SOC_CLOCK_OUT); 73 if (ret < 0) 74 dev_err(rtd->dev, "failed to set cpu dai sysclk\n"); 75 76 for (j = 0; j < rtd->num_codecs; j++) { 77 struct snd_soc_dai *codec_dai = rtd->codec_dais[j]; 78 79 if (!strcmp(codec_dai->component->name, "da7219.5-001a")) { 80 ret = snd_soc_dai_set_sysclk(codec_dai, 81 DA7219_CLKSRC_MCLK, 82 mclk_fs, 83 SND_SOC_CLOCK_IN); 84 if (ret < 0) 85 dev_err(rtd->dev, "failed to set sysclk\n"); 86 87 if ((rate % 8000) == 0) 88 freq = DA7219_PLL_FREQ_OUT_98304; 89 else 90 freq = DA7219_PLL_FREQ_OUT_90316; 91 92 ret = snd_soc_dai_set_pll(codec_dai, 0, 93 DA7219_SYSCLK_PLL_SRM, 94 0, freq); 95 if (ret) 96 dev_err(rtd->dev, "failed to start PLL: %d\n", 97 ret); 98 } 99 } 100 101 return ret; 102 } 103 104 static int mt8183_da7219_hw_free(struct snd_pcm_substream *substream) 105 { 106 struct snd_soc_pcm_runtime *rtd = substream->private_data; 107 int ret = 0, j; 108 109 for (j = 0; j < rtd->num_codecs; j++) { 110 struct snd_soc_dai *codec_dai = rtd->codec_dais[j]; 111 112 if (!strcmp(codec_dai->component->name, "da7219.5-001a")) { 113 ret = snd_soc_dai_set_pll(codec_dai, 114 0, DA7219_SYSCLK_MCLK, 0, 0); 115 if (ret < 0) { 116 dev_err(rtd->dev, "failed to stop PLL: %d\n", 117 ret); 118 break; 119 } 120 } 121 } 122 123 return ret; 124 } 125 126 static const struct snd_soc_ops mt8183_da7219_i2s_ops = { 127 .hw_params = mt8183_da7219_i2s_hw_params, 128 .hw_free = mt8183_da7219_hw_free, 129 }; 130 131 static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, 132 struct snd_pcm_hw_params *params) 133 { 134 /* fix BE i2s format to 32bit, clean param mask first */ 135 snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), 136 0, SNDRV_PCM_FORMAT_LAST); 137 138 params_set_format(params, SNDRV_PCM_FORMAT_S32_LE); 139 140 return 0; 141 } 142 143 static const struct snd_soc_dapm_widget 144 mt8183_da7219_max98357_dapm_widgets[] = { 145 SND_SOC_DAPM_OUTPUT("IT6505_8CH"), 146 }; 147 148 static const struct snd_soc_dapm_route mt8183_da7219_max98357_dapm_routes[] = { 149 {"IT6505_8CH", NULL, "TDM"}, 150 }; 151 152 static struct snd_soc_dai_link mt8183_da7219_max98357_dai_links[] = { 153 /* FE */ 154 { 155 .name = "Playback_1", 156 .stream_name = "Playback_1", 157 .cpu_dai_name = "DL1", 158 .codec_name = "snd-soc-dummy", 159 .codec_dai_name = "snd-soc-dummy-dai", 160 .trigger = {SND_SOC_DPCM_TRIGGER_PRE, 161 SND_SOC_DPCM_TRIGGER_PRE}, 162 .dynamic = 1, 163 .dpcm_playback = 1, 164 }, 165 { 166 .name = "Playback_2", 167 .stream_name = "Playback_2", 168 .cpu_dai_name = "DL2", 169 .codec_name = "snd-soc-dummy", 170 .codec_dai_name = "snd-soc-dummy-dai", 171 .trigger = {SND_SOC_DPCM_TRIGGER_PRE, 172 SND_SOC_DPCM_TRIGGER_PRE}, 173 .dynamic = 1, 174 .dpcm_playback = 1, 175 }, 176 { 177 .name = "Playback_3", 178 .stream_name = "Playback_3", 179 .cpu_dai_name = "DL3", 180 .codec_name = "snd-soc-dummy", 181 .codec_dai_name = "snd-soc-dummy-dai", 182 .trigger = {SND_SOC_DPCM_TRIGGER_PRE, 183 SND_SOC_DPCM_TRIGGER_PRE}, 184 .dynamic = 1, 185 .dpcm_playback = 1, 186 }, 187 { 188 .name = "Capture_1", 189 .stream_name = "Capture_1", 190 .cpu_dai_name = "UL1", 191 .codec_name = "snd-soc-dummy", 192 .codec_dai_name = "snd-soc-dummy-dai", 193 .trigger = {SND_SOC_DPCM_TRIGGER_PRE, 194 SND_SOC_DPCM_TRIGGER_PRE}, 195 .dynamic = 1, 196 .dpcm_capture = 1, 197 }, 198 { 199 .name = "Capture_2", 200 .stream_name = "Capture_2", 201 .cpu_dai_name = "UL2", 202 .codec_name = "snd-soc-dummy", 203 .codec_dai_name = "snd-soc-dummy-dai", 204 .trigger = {SND_SOC_DPCM_TRIGGER_PRE, 205 SND_SOC_DPCM_TRIGGER_PRE}, 206 .dynamic = 1, 207 .dpcm_capture = 1, 208 }, 209 { 210 .name = "Capture_3", 211 .stream_name = "Capture_3", 212 .cpu_dai_name = "UL3", 213 .codec_name = "snd-soc-dummy", 214 .codec_dai_name = "snd-soc-dummy-dai", 215 .trigger = {SND_SOC_DPCM_TRIGGER_PRE, 216 SND_SOC_DPCM_TRIGGER_PRE}, 217 .dynamic = 1, 218 .dpcm_capture = 1, 219 }, 220 { 221 .name = "Capture_Mono_1", 222 .stream_name = "Capture_Mono_1", 223 .cpu_dai_name = "UL_MONO_1", 224 .codec_name = "snd-soc-dummy", 225 .codec_dai_name = "snd-soc-dummy-dai", 226 .trigger = {SND_SOC_DPCM_TRIGGER_PRE, 227 SND_SOC_DPCM_TRIGGER_PRE}, 228 .dynamic = 1, 229 .dpcm_capture = 1, 230 }, 231 { 232 .name = "Playback_HDMI", 233 .stream_name = "Playback_HDMI", 234 .cpu_dai_name = "HDMI", 235 .codec_name = "snd-soc-dummy", 236 .codec_dai_name = "snd-soc-dummy-dai", 237 .trigger = {SND_SOC_DPCM_TRIGGER_PRE, 238 SND_SOC_DPCM_TRIGGER_PRE}, 239 .dynamic = 1, 240 .dpcm_playback = 1, 241 }, 242 /* BE */ 243 { 244 .name = "Primary Codec", 245 .cpu_dai_name = "ADDA", 246 .codec_dai_name = "mt6358-snd-codec-aif1", 247 .codec_name = "mt6358-sound", 248 .no_pcm = 1, 249 .dpcm_playback = 1, 250 .dpcm_capture = 1, 251 .ignore_suspend = 1, 252 }, 253 { 254 .name = "PCM 1", 255 .cpu_dai_name = "PCM 1", 256 .codec_name = "snd-soc-dummy", 257 .codec_dai_name = "snd-soc-dummy-dai", 258 .no_pcm = 1, 259 .dpcm_playback = 1, 260 .dpcm_capture = 1, 261 .ignore_suspend = 1, 262 }, 263 { 264 .name = "PCM 2", 265 .cpu_dai_name = "PCM 2", 266 .codec_name = "snd-soc-dummy", 267 .codec_dai_name = "snd-soc-dummy-dai", 268 .no_pcm = 1, 269 .dpcm_playback = 1, 270 .dpcm_capture = 1, 271 .ignore_suspend = 1, 272 }, 273 { 274 .name = "I2S0", 275 .cpu_dai_name = "I2S0", 276 .codec_dai_name = "bt-sco-pcm", 277 .codec_name = "bt-sco", 278 .no_pcm = 1, 279 .dpcm_capture = 1, 280 .ignore_suspend = 1, 281 .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, 282 .ops = &mt8183_mt6358_i2s_ops, 283 }, 284 { 285 .name = "I2S1", 286 .cpu_dai_name = "I2S1", 287 .codec_dai_name = "snd-soc-dummy-dai", 288 .codec_name = "snd-soc-dummy", 289 .no_pcm = 1, 290 .dpcm_playback = 1, 291 .ignore_suspend = 1, 292 .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, 293 .ops = &mt8183_mt6358_i2s_ops, 294 }, 295 { 296 .name = "I2S2", 297 .cpu_dai_name = "I2S2", 298 .codec_dai_name = "da7219-hifi", 299 .codec_name = "da7219.5-001a", 300 .no_pcm = 1, 301 .dpcm_capture = 1, 302 .ignore_suspend = 1, 303 .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, 304 .ops = &mt8183_da7219_i2s_ops, 305 }, 306 { 307 .name = "I2S3", 308 .cpu_dai_name = "I2S3", 309 .codecs = mt8183_da7219_max98357_external_codecs, 310 .num_codecs = 311 ARRAY_SIZE(mt8183_da7219_max98357_external_codecs), 312 .no_pcm = 1, 313 .dpcm_playback = 1, 314 .ignore_suspend = 1, 315 .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, 316 .ops = &mt8183_da7219_i2s_ops, 317 }, 318 { 319 .name = "I2S5", 320 .cpu_dai_name = "I2S5", 321 .codec_dai_name = "bt-sco-pcm", 322 .codec_name = "bt-sco", 323 .no_pcm = 1, 324 .dpcm_playback = 1, 325 .ignore_suspend = 1, 326 .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, 327 .ops = &mt8183_mt6358_i2s_ops, 328 }, 329 { 330 .name = "TDM", 331 .cpu_dai_name = "TDM", 332 .codec_name = "snd-soc-dummy", 333 .codec_dai_name = "snd-soc-dummy-dai", 334 .no_pcm = 1, 335 .dpcm_playback = 1, 336 .ignore_suspend = 1, 337 }, 338 }; 339 340 static int 341 mt8183_da7219_max98357_headset_init(struct snd_soc_component *component); 342 343 static struct snd_soc_aux_dev mt8183_da7219_max98357_headset_dev = { 344 .name = "Headset Chip", 345 .init = mt8183_da7219_max98357_headset_init, 346 }; 347 348 static struct snd_soc_codec_conf mt6358_codec_conf[] = { 349 { 350 .dev_name = "mt6358-sound", 351 .name_prefix = "Mt6358", 352 }, 353 }; 354 355 static struct snd_soc_card mt8183_da7219_max98357_card = { 356 .name = "mt8183_da7219_max98357", 357 .owner = THIS_MODULE, 358 .dai_link = mt8183_da7219_max98357_dai_links, 359 .num_links = ARRAY_SIZE(mt8183_da7219_max98357_dai_links), 360 .aux_dev = &mt8183_da7219_max98357_headset_dev, 361 .num_aux_devs = 1, 362 .codec_conf = mt6358_codec_conf, 363 .num_configs = ARRAY_SIZE(mt6358_codec_conf), 364 }; 365 366 static int 367 mt8183_da7219_max98357_headset_init(struct snd_soc_component *component) 368 { 369 int ret; 370 371 /* Enable Headset and 4 Buttons Jack detection */ 372 ret = snd_soc_card_jack_new(&mt8183_da7219_max98357_card, 373 "Headset Jack", 374 SND_JACK_HEADSET | 375 SND_JACK_BTN_0 | SND_JACK_BTN_1 | 376 SND_JACK_BTN_2 | SND_JACK_BTN_3, 377 &headset_jack, 378 headset_jack_pins, 379 ARRAY_SIZE(headset_jack_pins)); 380 if (ret) 381 return ret; 382 383 da7219_aad_jack_det(component, &headset_jack); 384 385 return ret; 386 } 387 388 static int mt8183_da7219_max98357_dev_probe(struct platform_device *pdev) 389 { 390 struct snd_soc_card *card = &mt8183_da7219_max98357_card; 391 struct device_node *platform_node; 392 struct snd_soc_dai_link *dai_link; 393 struct pinctrl *default_pins; 394 int ret, i; 395 396 card->dev = &pdev->dev; 397 398 platform_node = of_parse_phandle(pdev->dev.of_node, 399 "mediatek,platform", 0); 400 if (!platform_node) { 401 dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); 402 return -EINVAL; 403 } 404 405 for_each_card_prelinks(card, i, dai_link) { 406 /* In the alsa soc-core, the "platform" will be 407 * allocated by devm_kzalloc if null. 408 * There is a special case that registerring 409 * sound card is failed at the first time, but 410 * the "platform" will not null when probe is trying 411 * again. It's not expected normally. 412 */ 413 dai_link->platforms = NULL; 414 415 if (dai_link->platform_name) 416 continue; 417 dai_link->platform_of_node = platform_node; 418 } 419 420 mt8183_da7219_max98357_headset_dev.codec_of_node = 421 of_parse_phandle(pdev->dev.of_node, 422 "mediatek,headset-codec", 0); 423 if (!mt8183_da7219_max98357_headset_dev.codec_of_node) { 424 dev_err(&pdev->dev, 425 "Property 'mediatek,headset-codec' missing/invalid\n"); 426 return -EINVAL; 427 } 428 429 ret = devm_snd_soc_register_card(&pdev->dev, card); 430 if (ret) { 431 dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", 432 __func__, ret); 433 return ret; 434 } 435 436 default_pins = 437 devm_pinctrl_get_select(&pdev->dev, PINCTRL_STATE_DEFAULT); 438 if (IS_ERR(default_pins)) { 439 dev_err(&pdev->dev, "%s set pins failed\n", 440 __func__); 441 return PTR_ERR(default_pins); 442 } 443 444 return ret; 445 } 446 447 #ifdef CONFIG_OF 448 static const struct of_device_id mt8183_da7219_max98357_dt_match[] = { 449 {.compatible = "mediatek,mt8183_da7219_max98357",}, 450 {} 451 }; 452 #endif 453 454 static struct platform_driver mt8183_da7219_max98357_driver = { 455 .driver = { 456 .name = "mt8183_da7219_max98357", 457 #ifdef CONFIG_OF 458 .of_match_table = mt8183_da7219_max98357_dt_match, 459 #endif 460 }, 461 .probe = mt8183_da7219_max98357_dev_probe, 462 }; 463 464 module_platform_driver(mt8183_da7219_max98357_driver); 465 466 /* Module information */ 467 MODULE_DESCRIPTION("MT8183-DA7219-MAX98357 ALSA SoC machine driver"); 468 MODULE_AUTHOR("Shunli Wang <shunli.wang@mediatek.com>"); 469 MODULE_LICENSE("GPL v2"); 470 MODULE_ALIAS("mt8183_da7219_max98357 soc card"); 471 472