Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ASoC: mediatek: mt7986: add machine driver with wm8960

Add support for mt7986 board with wm8960.

Signed-off-by: Maso Huang <maso.huang@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Link: https://lore.kernel.org/r/20230817101338.18782-5-maso.huang@mediatek.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Maso Huang and committed by
Mark Brown
9873277f 8d0d4884

+207
+10
sound/soc/mediatek/Kconfig
··· 64 64 Select Y if you have such device. 65 65 If unsure select "N". 66 66 67 + config SND_SOC_MT7986_WM8960 68 + tristate "ASoc Audio driver for MT7986 with WM8960 codec" 69 + depends on SND_SOC_MT7986 && I2C 70 + select SND_SOC_WM8960 71 + help 72 + This adds support for ASoC machine driver for MediaTek MT7986 73 + boards with the WM8960 codecs. 74 + Select Y if you have such device. 75 + If unsure select "N". 76 + 67 77 config SND_SOC_MT8173 68 78 tristate "ASoC support for Mediatek MT8173 chip" 69 79 depends on ARCH_MEDIATEK
+1
sound/soc/mediatek/mt7986/Makefile
··· 6 6 mt7986-dai-etdm.o 7 7 8 8 obj-$(CONFIG_SND_SOC_MT7986) += snd-soc-mt7986-afe.o 9 + obj-$(CONFIG_SND_SOC_MT7986_WM8960) += mt7986-wm8960.o
+196
sound/soc/mediatek/mt7986/mt7986-wm8960.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * mt7986-wm8960.c -- MT7986-WM8960 ALSA SoC machine driver 4 + * 5 + * Copyright (c) 2023 MediaTek Inc. 6 + * Authors: Vic Wu <vic.wu@mediatek.com> 7 + * Maso Huang <maso.huang@mediatek.com> 8 + */ 9 + 10 + #include <linux/module.h> 11 + #include <sound/soc.h> 12 + 13 + #include "mt7986-afe-common.h" 14 + 15 + struct mt7986_wm8960_priv { 16 + struct device_node *platform_node; 17 + struct device_node *codec_node; 18 + }; 19 + 20 + static const struct snd_soc_dapm_widget mt7986_wm8960_widgets[] = { 21 + SND_SOC_DAPM_HP("Headphone", NULL), 22 + SND_SOC_DAPM_MIC("AMIC", NULL), 23 + }; 24 + 25 + static const struct snd_kcontrol_new mt7986_wm8960_controls[] = { 26 + SOC_DAPM_PIN_SWITCH("Headphone"), 27 + SOC_DAPM_PIN_SWITCH("AMIC"), 28 + }; 29 + 30 + SND_SOC_DAILINK_DEFS(playback, 31 + DAILINK_COMP_ARRAY(COMP_CPU("DL1")), 32 + DAILINK_COMP_ARRAY(COMP_DUMMY()), 33 + DAILINK_COMP_ARRAY(COMP_EMPTY())); 34 + 35 + SND_SOC_DAILINK_DEFS(capture, 36 + DAILINK_COMP_ARRAY(COMP_CPU("UL1")), 37 + DAILINK_COMP_ARRAY(COMP_DUMMY()), 38 + DAILINK_COMP_ARRAY(COMP_EMPTY())); 39 + 40 + SND_SOC_DAILINK_DEFS(codec, 41 + DAILINK_COMP_ARRAY(COMP_CPU("ETDM")), 42 + DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8960-hifi")), 43 + DAILINK_COMP_ARRAY(COMP_EMPTY())); 44 + 45 + static struct snd_soc_dai_link mt7986_wm8960_dai_links[] = { 46 + /* FE */ 47 + { 48 + .name = "wm8960-playback", 49 + .stream_name = "wm8960-playback", 50 + .trigger = {SND_SOC_DPCM_TRIGGER_POST, 51 + SND_SOC_DPCM_TRIGGER_POST}, 52 + .dynamic = 1, 53 + .dpcm_playback = 1, 54 + SND_SOC_DAILINK_REG(playback), 55 + }, 56 + { 57 + .name = "wm8960-capture", 58 + .stream_name = "wm8960-capture", 59 + .trigger = {SND_SOC_DPCM_TRIGGER_POST, 60 + SND_SOC_DPCM_TRIGGER_POST}, 61 + .dynamic = 1, 62 + .dpcm_capture = 1, 63 + SND_SOC_DAILINK_REG(capture), 64 + }, 65 + /* BE */ 66 + { 67 + .name = "wm8960-codec", 68 + .no_pcm = 1, 69 + .dai_fmt = SND_SOC_DAIFMT_I2S | 70 + SND_SOC_DAIFMT_NB_NF | 71 + SND_SOC_DAIFMT_CBS_CFS | 72 + SND_SOC_DAIFMT_GATED, 73 + .dpcm_playback = 1, 74 + .dpcm_capture = 1, 75 + SND_SOC_DAILINK_REG(codec), 76 + }, 77 + }; 78 + 79 + static struct snd_soc_card mt7986_wm8960_card = { 80 + .name = "mt7986-wm8960", 81 + .owner = THIS_MODULE, 82 + .dai_link = mt7986_wm8960_dai_links, 83 + .num_links = ARRAY_SIZE(mt7986_wm8960_dai_links), 84 + .controls = mt7986_wm8960_controls, 85 + .num_controls = ARRAY_SIZE(mt7986_wm8960_controls), 86 + .dapm_widgets = mt7986_wm8960_widgets, 87 + .num_dapm_widgets = ARRAY_SIZE(mt7986_wm8960_widgets), 88 + }; 89 + 90 + static int mt7986_wm8960_machine_probe(struct platform_device *pdev) 91 + { 92 + struct snd_soc_card *card = &mt7986_wm8960_card; 93 + struct snd_soc_dai_link *dai_link; 94 + struct device_node *platform, *codec; 95 + struct mt7986_wm8960_priv *priv; 96 + int ret, i; 97 + 98 + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 99 + if (!priv) 100 + return -ENOMEM; 101 + 102 + platform = of_get_child_by_name(pdev->dev.of_node, "platform"); 103 + 104 + if (platform) { 105 + priv->platform_node = of_parse_phandle(platform, "sound-dai", 0); 106 + of_node_put(platform); 107 + 108 + if (!priv->platform_node) { 109 + dev_err(&pdev->dev, "Failed to parse platform/sound-dai property\n"); 110 + return -EINVAL; 111 + } 112 + } else { 113 + dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); 114 + return -EINVAL; 115 + } 116 + 117 + for_each_card_prelinks(card, i, dai_link) { 118 + if (dai_link->platforms->name) 119 + continue; 120 + dai_link->platforms->of_node = priv->platform_node; 121 + } 122 + 123 + card->dev = &pdev->dev; 124 + 125 + codec = of_get_child_by_name(pdev->dev.of_node, "codec"); 126 + 127 + if (codec) { 128 + priv->codec_node = of_parse_phandle(codec, "sound-dai", 0); 129 + of_node_put(codec); 130 + 131 + if (!priv->codec_node) { 132 + of_node_put(priv->platform_node); 133 + dev_err(&pdev->dev, "Failed to parse codec/sound-dai property\n"); 134 + return -EINVAL; 135 + } 136 + } else { 137 + of_node_put(priv->platform_node); 138 + dev_err(&pdev->dev, "Property 'codec' missing or invalid\n"); 139 + return -EINVAL; 140 + } 141 + 142 + for_each_card_prelinks(card, i, dai_link) { 143 + if (dai_link->codecs->name) 144 + continue; 145 + dai_link->codecs->of_node = priv->codec_node; 146 + } 147 + 148 + ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); 149 + if (ret) { 150 + dev_err(&pdev->dev, "Failed to parse audio-routing: %d\n", ret); 151 + goto err_of_node_put; 152 + } 153 + 154 + ret = devm_snd_soc_register_card(&pdev->dev, card); 155 + if (ret) { 156 + dev_err(&pdev->dev, "%s snd_soc_register_card fail: %d\n", __func__, ret); 157 + goto err_of_node_put; 158 + } 159 + 160 + err_of_node_put: 161 + of_node_put(priv->codec_node); 162 + of_node_put(priv->platform_node); 163 + return ret; 164 + } 165 + 166 + static void mt7986_wm8960_machine_remove(struct platform_device *pdev) 167 + { 168 + struct snd_soc_card *card = platform_get_drvdata(pdev); 169 + struct mt7986_wm8960_priv *priv = snd_soc_card_get_drvdata(card); 170 + 171 + of_node_put(priv->codec_node); 172 + of_node_put(priv->platform_node); 173 + } 174 + 175 + static const struct of_device_id mt7986_wm8960_machine_dt_match[] = { 176 + {.compatible = "mediatek,mt7986-wm8960-sound"}, 177 + { /* sentinel */ } 178 + }; 179 + MODULE_DEVICE_TABLE(of, mt7986_wm8960_machine_dt_match); 180 + 181 + static struct platform_driver mt7986_wm8960_machine = { 182 + .driver = { 183 + .name = "mt7986-wm8960", 184 + .of_match_table = mt7986_wm8960_machine_dt_match, 185 + }, 186 + .probe = mt7986_wm8960_machine_probe, 187 + .remove_new = mt7986_wm8960_machine_remove, 188 + }; 189 + 190 + module_platform_driver(mt7986_wm8960_machine); 191 + 192 + /* Module information */ 193 + MODULE_DESCRIPTION("MT7986 WM8960 ALSA SoC machine driver"); 194 + MODULE_AUTHOR("Vic Wu <vic.wu@mediatek.com>"); 195 + MODULE_LICENSE("GPL"); 196 + MODULE_ALIAS("mt7986 wm8960 soc card");