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