1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * MediaTek MT8365 Sound Card driver 4 * 5 * Copyright (c) 2024 MediaTek Inc. 6 * Authors: Nicolas Belin <nbelin@baylibre.com> 7 */ 8 9 #include <linux/array_size.h> 10 #include <linux/dev_printk.h> 11 #include <linux/err.h> 12 #include <linux/mod_devicetable.h> 13 #include <linux/module.h> 14 #include <linux/pinctrl/consumer.h> 15 #include <linux/platform_device.h> 16 #include <linux/types.h> 17 18 #include <sound/soc.h> 19 #include <sound/pcm_params.h> 20 21 #include "mt8365-afe-common.h" 22 #include "../common/mtk-soc-card.h" 23 #include "../common/mtk-soundcard-driver.h" 24 25 enum pinctrl_pin_state { 26 PIN_STATE_DEFAULT, 27 PIN_STATE_DMIC, 28 PIN_STATE_MISO_OFF, 29 PIN_STATE_MISO_ON, 30 PIN_STATE_MOSI_OFF, 31 PIN_STATE_MOSI_ON, 32 PIN_STATE_MAX 33 }; 34 35 static const char * const mt8365_mt6357_pin_str[PIN_STATE_MAX] = { 36 "default", 37 "dmic", 38 "miso_off", 39 "miso_on", 40 "mosi_off", 41 "mosi_on", 42 }; 43 44 struct mt8365_mt6357_priv { 45 struct pinctrl *pinctrl; 46 struct pinctrl_state *pin_states[PIN_STATE_MAX]; 47 }; 48 49 enum { 50 /* FE */ 51 DAI_LINK_DL1_PLAYBACK = 0, 52 DAI_LINK_DL2_PLAYBACK, 53 DAI_LINK_AWB_CAPTURE, 54 DAI_LINK_VUL_CAPTURE, 55 /* BE */ 56 DAI_LINK_2ND_I2S_INTF, 57 DAI_LINK_DMIC, 58 DAI_LINK_INT_ADDA, 59 DAI_LINK_NUM 60 }; 61 62 static const struct snd_soc_dapm_widget mt8365_mt6357_widgets[] = { 63 SND_SOC_DAPM_OUTPUT("HDMI Out"), 64 }; 65 66 static const struct snd_soc_dapm_route mt8365_mt6357_routes[] = { 67 {"HDMI Out", NULL, "2ND I2S Playback"}, 68 {"DMIC In", NULL, "MICBIAS0"}, 69 }; 70 71 static int mt8365_mt6357_int_adda_startup(struct snd_pcm_substream *substream) 72 { 73 struct snd_soc_pcm_runtime *rtd = substream->private_data; 74 struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(rtd->card); 75 int ret = 0; 76 77 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 78 if (IS_ERR(priv->pin_states[PIN_STATE_MOSI_ON])) 79 return ret; 80 81 ret = pinctrl_select_state(priv->pinctrl, 82 priv->pin_states[PIN_STATE_MOSI_ON]); 83 if (ret) 84 dev_err(rtd->card->dev, "%s failed to select state %d\n", 85 __func__, ret); 86 } 87 88 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 89 if (IS_ERR(priv->pin_states[PIN_STATE_MISO_ON])) 90 return ret; 91 92 ret = pinctrl_select_state(priv->pinctrl, 93 priv->pin_states[PIN_STATE_MISO_ON]); 94 if (ret) 95 dev_err(rtd->card->dev, "%s failed to select state %d\n", 96 __func__, ret); 97 } 98 99 return 0; 100 } 101 102 static void mt8365_mt6357_int_adda_shutdown(struct snd_pcm_substream *substream) 103 { 104 struct snd_soc_pcm_runtime *rtd = substream->private_data; 105 struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(rtd->card); 106 int ret = 0; 107 108 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 109 if (IS_ERR(priv->pin_states[PIN_STATE_MOSI_OFF])) 110 return; 111 112 ret = pinctrl_select_state(priv->pinctrl, 113 priv->pin_states[PIN_STATE_MOSI_OFF]); 114 if (ret) 115 dev_err(rtd->card->dev, "%s failed to select state %d\n", 116 __func__, ret); 117 } 118 119 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 120 if (IS_ERR(priv->pin_states[PIN_STATE_MISO_OFF])) 121 return; 122 123 ret = pinctrl_select_state(priv->pinctrl, 124 priv->pin_states[PIN_STATE_MISO_OFF]); 125 if (ret) 126 dev_err(rtd->card->dev, "%s failed to select state %d\n", 127 __func__, ret); 128 } 129 } 130 131 static const struct snd_soc_ops mt8365_mt6357_int_adda_ops = { 132 .startup = mt8365_mt6357_int_adda_startup, 133 .shutdown = mt8365_mt6357_int_adda_shutdown, 134 }; 135 136 SND_SOC_DAILINK_DEFS(playback1, 137 DAILINK_COMP_ARRAY(COMP_CPU("DL1")), 138 DAILINK_COMP_ARRAY(COMP_DUMMY()), 139 DAILINK_COMP_ARRAY(COMP_EMPTY())); 140 SND_SOC_DAILINK_DEFS(playback2, 141 DAILINK_COMP_ARRAY(COMP_CPU("DL2")), 142 DAILINK_COMP_ARRAY(COMP_DUMMY()), 143 DAILINK_COMP_ARRAY(COMP_EMPTY())); 144 SND_SOC_DAILINK_DEFS(awb_capture, 145 DAILINK_COMP_ARRAY(COMP_CPU("AWB")), 146 DAILINK_COMP_ARRAY(COMP_DUMMY()), 147 DAILINK_COMP_ARRAY(COMP_EMPTY())); 148 SND_SOC_DAILINK_DEFS(vul, 149 DAILINK_COMP_ARRAY(COMP_CPU("VUL")), 150 DAILINK_COMP_ARRAY(COMP_DUMMY()), 151 DAILINK_COMP_ARRAY(COMP_EMPTY())); 152 153 SND_SOC_DAILINK_DEFS(i2s3, 154 DAILINK_COMP_ARRAY(COMP_CPU("2ND I2S")), 155 DAILINK_COMP_ARRAY(COMP_DUMMY()), 156 DAILINK_COMP_ARRAY(COMP_EMPTY())); 157 SND_SOC_DAILINK_DEFS(dmic, 158 DAILINK_COMP_ARRAY(COMP_CPU("DMIC")), 159 DAILINK_COMP_ARRAY(COMP_DUMMY()), 160 DAILINK_COMP_ARRAY(COMP_EMPTY())); 161 SND_SOC_DAILINK_DEFS(primary_codec, 162 DAILINK_COMP_ARRAY(COMP_CPU("INT ADDA")), 163 DAILINK_COMP_ARRAY(COMP_CODEC("mt6357-sound", "mt6357-snd-codec-aif1")), 164 DAILINK_COMP_ARRAY(COMP_EMPTY())); 165 166 /* Digital audio interface glue - connects codec <---> CPU */ 167 static struct snd_soc_dai_link mt8365_mt6357_dais[] = { 168 /* Front End DAI links */ 169 [DAI_LINK_DL1_PLAYBACK] = { 170 .name = "DL1_FE", 171 .stream_name = "MultiMedia1_PLayback", 172 .id = DAI_LINK_DL1_PLAYBACK, 173 .trigger = { 174 SND_SOC_DPCM_TRIGGER_POST, 175 SND_SOC_DPCM_TRIGGER_POST 176 }, 177 .dynamic = 1, 178 .playback_only = 1, 179 .dpcm_merged_rate = 1, 180 SND_SOC_DAILINK_REG(playback1), 181 }, 182 [DAI_LINK_DL2_PLAYBACK] = { 183 .name = "DL2_FE", 184 .stream_name = "MultiMedia2_PLayback", 185 .id = DAI_LINK_DL2_PLAYBACK, 186 .trigger = { 187 SND_SOC_DPCM_TRIGGER_POST, 188 SND_SOC_DPCM_TRIGGER_POST 189 }, 190 .dynamic = 1, 191 .playback_only = 1, 192 .dpcm_merged_rate = 1, 193 SND_SOC_DAILINK_REG(playback2), 194 }, 195 [DAI_LINK_AWB_CAPTURE] = { 196 .name = "AWB_FE", 197 .stream_name = "DL1_AWB_Record", 198 .id = DAI_LINK_AWB_CAPTURE, 199 .trigger = { 200 SND_SOC_DPCM_TRIGGER_POST, 201 SND_SOC_DPCM_TRIGGER_POST 202 }, 203 .dynamic = 1, 204 .capture_only = 1, 205 .dpcm_merged_rate = 1, 206 SND_SOC_DAILINK_REG(awb_capture), 207 }, 208 [DAI_LINK_VUL_CAPTURE] = { 209 .name = "VUL_FE", 210 .stream_name = "MultiMedia1_Capture", 211 .id = DAI_LINK_VUL_CAPTURE, 212 .trigger = { 213 SND_SOC_DPCM_TRIGGER_POST, 214 SND_SOC_DPCM_TRIGGER_POST 215 }, 216 .dynamic = 1, 217 .capture_only = 1, 218 .dpcm_merged_rate = 1, 219 SND_SOC_DAILINK_REG(vul), 220 }, 221 /* Back End DAI links */ 222 [DAI_LINK_2ND_I2S_INTF] = { 223 .name = "I2S_OUT_BE", 224 .no_pcm = 1, 225 .id = DAI_LINK_2ND_I2S_INTF, 226 .dai_fmt = SND_SOC_DAIFMT_I2S | 227 SND_SOC_DAIFMT_NB_NF | 228 SND_SOC_DAIFMT_CBC_CFC, 229 SND_SOC_DAILINK_REG(i2s3), 230 }, 231 [DAI_LINK_DMIC] = { 232 .name = "DMIC_BE", 233 .no_pcm = 1, 234 .id = DAI_LINK_DMIC, 235 .capture_only = 1, 236 SND_SOC_DAILINK_REG(dmic), 237 }, 238 [DAI_LINK_INT_ADDA] = { 239 .name = "MTK_Codec", 240 .no_pcm = 1, 241 .id = DAI_LINK_INT_ADDA, 242 .ops = &mt8365_mt6357_int_adda_ops, 243 SND_SOC_DAILINK_REG(primary_codec), 244 }, 245 }; 246 247 static int mt8365_mt6357_gpio_probe(struct snd_soc_card *card) 248 { 249 struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(card); 250 int ret, i; 251 252 priv->pinctrl = devm_pinctrl_get(card->dev); 253 if (IS_ERR(priv->pinctrl)) { 254 ret = PTR_ERR(priv->pinctrl); 255 return dev_err_probe(card->dev, ret, 256 "Failed to get pinctrl\n"); 257 } 258 259 for (i = PIN_STATE_DEFAULT ; i < PIN_STATE_MAX ; i++) { 260 priv->pin_states[i] = pinctrl_lookup_state(priv->pinctrl, 261 mt8365_mt6357_pin_str[i]); 262 if (IS_ERR(priv->pin_states[i])) { 263 dev_info(card->dev, "No pin state for %s\n", 264 mt8365_mt6357_pin_str[i]); 265 } else { 266 ret = pinctrl_select_state(priv->pinctrl, 267 priv->pin_states[i]); 268 if (ret) { 269 dev_err_probe(card->dev, ret, 270 "Failed to select pin state %s\n", 271 mt8365_mt6357_pin_str[i]); 272 return ret; 273 } 274 } 275 } 276 return 0; 277 } 278 279 static struct snd_soc_card mt8365_mt6357_soc_card = { 280 .name = "mt8365-evk", 281 .owner = THIS_MODULE, 282 .dai_link = mt8365_mt6357_dais, 283 .num_links = ARRAY_SIZE(mt8365_mt6357_dais), 284 .dapm_widgets = mt8365_mt6357_widgets, 285 .num_dapm_widgets = ARRAY_SIZE(mt8365_mt6357_widgets), 286 .dapm_routes = mt8365_mt6357_routes, 287 .num_dapm_routes = ARRAY_SIZE(mt8365_mt6357_routes), 288 }; 289 290 static int mt8365_mt6357_dev_probe(struct mtk_soc_card_data *soc_card_data, bool legacy) 291 { 292 struct mtk_platform_card_data *card_data = soc_card_data->card_data; 293 struct snd_soc_card *card = card_data->card; 294 struct device *dev = card->dev; 295 struct mt8365_mt6357_priv *mach_priv; 296 int ret; 297 298 card->dev = dev; 299 ret = parse_dai_link_info(card); 300 if (ret) 301 goto err; 302 303 mach_priv = devm_kzalloc(dev, sizeof(*mach_priv), 304 GFP_KERNEL); 305 if (!mach_priv) 306 return -ENOMEM; 307 soc_card_data->mach_priv = mach_priv; 308 snd_soc_card_set_drvdata(card, soc_card_data); 309 mt8365_mt6357_gpio_probe(card); 310 return 0; 311 312 err: 313 clean_card_reference(card); 314 return ret; 315 } 316 317 static const struct mtk_soundcard_pdata mt8365_mt6357_card = { 318 .card_name = "mt8365-mt6357", 319 .card_data = &(struct mtk_platform_card_data) { 320 .card = &mt8365_mt6357_soc_card, 321 }, 322 .soc_probe = mt8365_mt6357_dev_probe 323 }; 324 325 static const struct of_device_id mt8365_mt6357_dt_match[] = { 326 { .compatible = "mediatek,mt8365-mt6357", .data = &mt8365_mt6357_card }, 327 { /* sentinel */ } 328 }; 329 MODULE_DEVICE_TABLE(of, mt8365_mt6357_dt_match); 330 331 static struct platform_driver mt8365_mt6357_driver = { 332 .driver = { 333 .name = "mt8365_mt6357", 334 .of_match_table = mt8365_mt6357_dt_match, 335 .pm = &snd_soc_pm_ops, 336 }, 337 .probe = mtk_soundcard_common_probe, 338 }; 339 340 module_platform_driver(mt8365_mt6357_driver); 341 342 /* Module information */ 343 MODULE_DESCRIPTION("MT8365 EVK SoC machine driver"); 344 MODULE_AUTHOR("Nicolas Belin <nbelin@baylibre.com>"); 345 MODULE_LICENSE("GPL"); 346 MODULE_ALIAS("platform: mt8365_mt6357"); 347