1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * mt8173-max98090.c -- MT8173 MAX98090 ALSA SoC machine driver 4 * 5 * Copyright (c) 2015 MediaTek Inc. 6 * Author: Koro Chen <koro.chen@mediatek.com> 7 */ 8 9 #include <linux/module.h> 10 #include <sound/soc.h> 11 #include <sound/jack.h> 12 #include "../../codecs/max98090.h" 13 14 static struct snd_soc_jack mt8173_max98090_jack; 15 16 static struct snd_soc_jack_pin mt8173_max98090_jack_pins[] = { 17 { 18 .pin = "Headphone", 19 .mask = SND_JACK_HEADPHONE, 20 }, 21 { 22 .pin = "Headset Mic", 23 .mask = SND_JACK_MICROPHONE, 24 }, 25 }; 26 27 static const struct snd_soc_dapm_widget mt8173_max98090_widgets[] = { 28 SND_SOC_DAPM_SPK("Speaker", NULL), 29 SND_SOC_DAPM_MIC("Int Mic", NULL), 30 SND_SOC_DAPM_HP("Headphone", NULL), 31 SND_SOC_DAPM_MIC("Headset Mic", NULL), 32 }; 33 34 static const struct snd_soc_dapm_route mt8173_max98090_routes[] = { 35 {"Speaker", NULL, "SPKL"}, 36 {"Speaker", NULL, "SPKR"}, 37 {"DMICL", NULL, "Int Mic"}, 38 {"Headphone", NULL, "HPL"}, 39 {"Headphone", NULL, "HPR"}, 40 {"Headset Mic", NULL, "MICBIAS"}, 41 {"IN34", NULL, "Headset Mic"}, 42 }; 43 44 static const struct snd_kcontrol_new mt8173_max98090_controls[] = { 45 SOC_DAPM_PIN_SWITCH("Speaker"), 46 SOC_DAPM_PIN_SWITCH("Int Mic"), 47 SOC_DAPM_PIN_SWITCH("Headphone"), 48 SOC_DAPM_PIN_SWITCH("Headset Mic"), 49 }; 50 51 static int mt8173_max98090_hw_params(struct snd_pcm_substream *substream, 52 struct snd_pcm_hw_params *params) 53 { 54 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 55 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); 56 57 return snd_soc_dai_set_sysclk(codec_dai, 0, params_rate(params) * 256, 58 SND_SOC_CLOCK_IN); 59 } 60 61 static const struct snd_soc_ops mt8173_max98090_ops = { 62 .hw_params = mt8173_max98090_hw_params, 63 }; 64 65 static int mt8173_max98090_init(struct snd_soc_pcm_runtime *runtime) 66 { 67 int ret; 68 struct snd_soc_card *card = runtime->card; 69 struct snd_soc_component *component = snd_soc_rtd_to_codec(runtime, 0)->component; 70 71 /* enable jack detection */ 72 ret = snd_soc_card_jack_new_pins(card, "Headphone", SND_JACK_HEADSET, 73 &mt8173_max98090_jack, 74 mt8173_max98090_jack_pins, 75 ARRAY_SIZE(mt8173_max98090_jack_pins)); 76 if (ret) { 77 dev_err(card->dev, "Can't create a new Jack %d\n", ret); 78 return ret; 79 } 80 81 return max98090_mic_detect(component, &mt8173_max98090_jack); 82 } 83 84 SND_SOC_DAILINK_DEFS(playback, 85 DAILINK_COMP_ARRAY(COMP_CPU("DL1")), 86 DAILINK_COMP_ARRAY(COMP_DUMMY()), 87 DAILINK_COMP_ARRAY(COMP_EMPTY())); 88 89 SND_SOC_DAILINK_DEFS(capture, 90 DAILINK_COMP_ARRAY(COMP_CPU("VUL")), 91 DAILINK_COMP_ARRAY(COMP_DUMMY()), 92 DAILINK_COMP_ARRAY(COMP_EMPTY())); 93 94 SND_SOC_DAILINK_DEFS(hifi, 95 DAILINK_COMP_ARRAY(COMP_CPU("I2S")), 96 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")), 97 DAILINK_COMP_ARRAY(COMP_EMPTY())); 98 99 /* Digital audio interface glue - connects codec <---> CPU */ 100 static struct snd_soc_dai_link mt8173_max98090_dais[] = { 101 /* Front End DAI links */ 102 { 103 .name = "MAX98090 Playback", 104 .stream_name = "MAX98090 Playback", 105 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, 106 .dynamic = 1, 107 .dpcm_playback = 1, 108 SND_SOC_DAILINK_REG(playback), 109 }, 110 { 111 .name = "MAX98090 Capture", 112 .stream_name = "MAX98090 Capture", 113 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, 114 .dynamic = 1, 115 .dpcm_capture = 1, 116 SND_SOC_DAILINK_REG(capture), 117 }, 118 /* Back End DAI links */ 119 { 120 .name = "Codec", 121 .no_pcm = 1, 122 .init = mt8173_max98090_init, 123 .ops = &mt8173_max98090_ops, 124 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 125 SND_SOC_DAIFMT_CBS_CFS, 126 .dpcm_playback = 1, 127 .dpcm_capture = 1, 128 SND_SOC_DAILINK_REG(hifi), 129 }, 130 }; 131 132 static struct snd_soc_card mt8173_max98090_card = { 133 .name = "mt8173-max98090", 134 .owner = THIS_MODULE, 135 .dai_link = mt8173_max98090_dais, 136 .num_links = ARRAY_SIZE(mt8173_max98090_dais), 137 .controls = mt8173_max98090_controls, 138 .num_controls = ARRAY_SIZE(mt8173_max98090_controls), 139 .dapm_widgets = mt8173_max98090_widgets, 140 .num_dapm_widgets = ARRAY_SIZE(mt8173_max98090_widgets), 141 .dapm_routes = mt8173_max98090_routes, 142 .num_dapm_routes = ARRAY_SIZE(mt8173_max98090_routes), 143 }; 144 145 static int mt8173_max98090_dev_probe(struct platform_device *pdev) 146 { 147 struct snd_soc_card *card = &mt8173_max98090_card; 148 struct device_node *codec_node, *platform_node; 149 struct snd_soc_dai_link *dai_link; 150 int ret, i; 151 152 platform_node = of_parse_phandle(pdev->dev.of_node, 153 "mediatek,platform", 0); 154 if (!platform_node) { 155 dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); 156 return -EINVAL; 157 } 158 for_each_card_prelinks(card, i, dai_link) { 159 if (dai_link->platforms->name) 160 continue; 161 dai_link->platforms->of_node = platform_node; 162 } 163 164 codec_node = of_parse_phandle(pdev->dev.of_node, 165 "mediatek,audio-codec", 0); 166 if (!codec_node) { 167 dev_err(&pdev->dev, 168 "Property 'audio-codec' missing or invalid\n"); 169 ret = -EINVAL; 170 goto put_platform_node; 171 } 172 for_each_card_prelinks(card, i, dai_link) { 173 if (dai_link->codecs->name) 174 continue; 175 dai_link->codecs->of_node = codec_node; 176 } 177 card->dev = &pdev->dev; 178 179 ret = devm_snd_soc_register_card(&pdev->dev, card); 180 181 of_node_put(codec_node); 182 183 put_platform_node: 184 of_node_put(platform_node); 185 return ret; 186 } 187 188 static const struct of_device_id mt8173_max98090_dt_match[] = { 189 { .compatible = "mediatek,mt8173-max98090", }, 190 { } 191 }; 192 MODULE_DEVICE_TABLE(of, mt8173_max98090_dt_match); 193 194 static struct platform_driver mt8173_max98090_driver = { 195 .driver = { 196 .name = "mt8173-max98090", 197 .of_match_table = mt8173_max98090_dt_match, 198 .pm = &snd_soc_pm_ops, 199 }, 200 .probe = mt8173_max98090_dev_probe, 201 }; 202 203 module_platform_driver(mt8173_max98090_driver); 204 205 /* Module information */ 206 MODULE_DESCRIPTION("MT8173 MAX98090 ALSA SoC machine driver"); 207 MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>"); 208 MODULE_LICENSE("GPL v2"); 209 MODULE_ALIAS("platform:mt8173-max98090"); 210 211