1*4d9c6bbfSDaniel Golle // SPDX-License-Identifier: GPL-2.0 2*4d9c6bbfSDaniel Golle /* 3*4d9c6bbfSDaniel Golle * mt2701-hdmi.c -- MT2701 HDMI ALSA SoC machine driver 4*4d9c6bbfSDaniel Golle * 5*4d9c6bbfSDaniel Golle * Copyright (c) 2026 Daniel Golle <daniel@makrotopia.org> 6*4d9c6bbfSDaniel Golle * 7*4d9c6bbfSDaniel Golle * Based on mt2701-cs42448.c 8*4d9c6bbfSDaniel Golle */ 9*4d9c6bbfSDaniel Golle 10*4d9c6bbfSDaniel Golle #include <linux/module.h> 11*4d9c6bbfSDaniel Golle #include <linux/of.h> 12*4d9c6bbfSDaniel Golle #include <linux/platform_device.h> 13*4d9c6bbfSDaniel Golle #include <sound/soc.h> 14*4d9c6bbfSDaniel Golle 15*4d9c6bbfSDaniel Golle enum { 16*4d9c6bbfSDaniel Golle DAI_LINK_FE_HDMI_OUT, 17*4d9c6bbfSDaniel Golle DAI_LINK_BE_HDMI_I2S, 18*4d9c6bbfSDaniel Golle }; 19*4d9c6bbfSDaniel Golle 20*4d9c6bbfSDaniel Golle SND_SOC_DAILINK_DEFS(fe_hdmi_out, 21*4d9c6bbfSDaniel Golle DAILINK_COMP_ARRAY(COMP_CPU("PCM_HDMI")), 22*4d9c6bbfSDaniel Golle DAILINK_COMP_ARRAY(COMP_DUMMY()), 23*4d9c6bbfSDaniel Golle DAILINK_COMP_ARRAY(COMP_EMPTY())); 24*4d9c6bbfSDaniel Golle 25*4d9c6bbfSDaniel Golle SND_SOC_DAILINK_DEFS(be_hdmi_i2s, 26*4d9c6bbfSDaniel Golle DAILINK_COMP_ARRAY(COMP_CPU("HDMI I2S")), 27*4d9c6bbfSDaniel Golle DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "i2s-hifi")), 28*4d9c6bbfSDaniel Golle DAILINK_COMP_ARRAY(COMP_EMPTY())); 29*4d9c6bbfSDaniel Golle 30*4d9c6bbfSDaniel Golle static struct snd_soc_dai_link mt2701_hdmi_dai_links[] = { 31*4d9c6bbfSDaniel Golle [DAI_LINK_FE_HDMI_OUT] = { 32*4d9c6bbfSDaniel Golle .name = "HDMI Playback", 33*4d9c6bbfSDaniel Golle .stream_name = "HDMI Playback", 34*4d9c6bbfSDaniel Golle .trigger = { SND_SOC_DPCM_TRIGGER_POST, 35*4d9c6bbfSDaniel Golle SND_SOC_DPCM_TRIGGER_POST }, 36*4d9c6bbfSDaniel Golle .dynamic = 1, 37*4d9c6bbfSDaniel Golle .playback_only = 1, 38*4d9c6bbfSDaniel Golle SND_SOC_DAILINK_REG(fe_hdmi_out), 39*4d9c6bbfSDaniel Golle }, 40*4d9c6bbfSDaniel Golle [DAI_LINK_BE_HDMI_I2S] = { 41*4d9c6bbfSDaniel Golle .name = "HDMI BE", 42*4d9c6bbfSDaniel Golle .no_pcm = 1, 43*4d9c6bbfSDaniel Golle .playback_only = 1, 44*4d9c6bbfSDaniel Golle .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 45*4d9c6bbfSDaniel Golle SND_SOC_DAIFMT_CBC_CFC, 46*4d9c6bbfSDaniel Golle SND_SOC_DAILINK_REG(be_hdmi_i2s), 47*4d9c6bbfSDaniel Golle }, 48*4d9c6bbfSDaniel Golle }; 49*4d9c6bbfSDaniel Golle 50*4d9c6bbfSDaniel Golle static struct snd_soc_card mt2701_hdmi_soc_card = { 51*4d9c6bbfSDaniel Golle .name = "mt2701-hdmi", 52*4d9c6bbfSDaniel Golle .owner = THIS_MODULE, 53*4d9c6bbfSDaniel Golle .dai_link = mt2701_hdmi_dai_links, 54*4d9c6bbfSDaniel Golle .num_links = ARRAY_SIZE(mt2701_hdmi_dai_links), 55*4d9c6bbfSDaniel Golle }; 56*4d9c6bbfSDaniel Golle 57*4d9c6bbfSDaniel Golle static int mt2701_hdmi_machine_probe(struct platform_device *pdev) 58*4d9c6bbfSDaniel Golle { 59*4d9c6bbfSDaniel Golle struct snd_soc_card *card = &mt2701_hdmi_soc_card; 60*4d9c6bbfSDaniel Golle struct device *dev = &pdev->dev; 61*4d9c6bbfSDaniel Golle struct device_node *platform_node; 62*4d9c6bbfSDaniel Golle struct device_node *codec_node; 63*4d9c6bbfSDaniel Golle struct snd_soc_dai_link *dai_link; 64*4d9c6bbfSDaniel Golle int ret; 65*4d9c6bbfSDaniel Golle int i; 66*4d9c6bbfSDaniel Golle 67*4d9c6bbfSDaniel Golle platform_node = of_parse_phandle(dev->of_node, "mediatek,platform", 0); 68*4d9c6bbfSDaniel Golle if (!platform_node) 69*4d9c6bbfSDaniel Golle return dev_err_probe(dev, -EINVAL, 70*4d9c6bbfSDaniel Golle "Property 'mediatek,platform' missing\n"); 71*4d9c6bbfSDaniel Golle 72*4d9c6bbfSDaniel Golle for_each_card_prelinks(card, i, dai_link) { 73*4d9c6bbfSDaniel Golle if (dai_link->platforms->name) 74*4d9c6bbfSDaniel Golle continue; 75*4d9c6bbfSDaniel Golle dai_link->platforms->of_node = platform_node; 76*4d9c6bbfSDaniel Golle } 77*4d9c6bbfSDaniel Golle 78*4d9c6bbfSDaniel Golle codec_node = of_parse_phandle(dev->of_node, "mediatek,audio-codec", 0); 79*4d9c6bbfSDaniel Golle if (!codec_node) { 80*4d9c6bbfSDaniel Golle of_node_put(platform_node); 81*4d9c6bbfSDaniel Golle return dev_err_probe(dev, -EINVAL, 82*4d9c6bbfSDaniel Golle "Property 'mediatek,audio-codec' missing\n"); 83*4d9c6bbfSDaniel Golle } 84*4d9c6bbfSDaniel Golle mt2701_hdmi_dai_links[DAI_LINK_BE_HDMI_I2S].codecs->of_node = codec_node; 85*4d9c6bbfSDaniel Golle 86*4d9c6bbfSDaniel Golle card->dev = dev; 87*4d9c6bbfSDaniel Golle 88*4d9c6bbfSDaniel Golle ret = devm_snd_soc_register_card(dev, card); 89*4d9c6bbfSDaniel Golle 90*4d9c6bbfSDaniel Golle of_node_put(platform_node); 91*4d9c6bbfSDaniel Golle of_node_put(codec_node); 92*4d9c6bbfSDaniel Golle return ret; 93*4d9c6bbfSDaniel Golle } 94*4d9c6bbfSDaniel Golle 95*4d9c6bbfSDaniel Golle static const struct of_device_id mt2701_hdmi_machine_dt_match[] = { 96*4d9c6bbfSDaniel Golle { .compatible = "mediatek,mt2701-hdmi-audio" }, 97*4d9c6bbfSDaniel Golle { .compatible = "mediatek,mt7623n-hdmi-audio" }, 98*4d9c6bbfSDaniel Golle {} 99*4d9c6bbfSDaniel Golle }; 100*4d9c6bbfSDaniel Golle MODULE_DEVICE_TABLE(of, mt2701_hdmi_machine_dt_match); 101*4d9c6bbfSDaniel Golle 102*4d9c6bbfSDaniel Golle static struct platform_driver mt2701_hdmi_machine = { 103*4d9c6bbfSDaniel Golle .driver = { 104*4d9c6bbfSDaniel Golle .name = "mt2701-hdmi", 105*4d9c6bbfSDaniel Golle .of_match_table = mt2701_hdmi_machine_dt_match, 106*4d9c6bbfSDaniel Golle }, 107*4d9c6bbfSDaniel Golle .probe = mt2701_hdmi_machine_probe, 108*4d9c6bbfSDaniel Golle }; 109*4d9c6bbfSDaniel Golle module_platform_driver(mt2701_hdmi_machine); 110*4d9c6bbfSDaniel Golle 111*4d9c6bbfSDaniel Golle MODULE_DESCRIPTION("MT2701 HDMI ALSA SoC machine driver"); 112*4d9c6bbfSDaniel Golle MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>"); 113*4d9c6bbfSDaniel Golle MODULE_LICENSE("GPL"); 114*4d9c6bbfSDaniel Golle MODULE_ALIAS("platform:mt2701-hdmi"); 115