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 .playback_only = 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 .capture_only = 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 SND_SOC_DAILINK_REG(hifi), 127 }, 128 }; 129 130 static struct snd_soc_card mt8173_max98090_card = { 131 .name = "mt8173-max98090", 132 .owner = THIS_MODULE, 133 .dai_link = mt8173_max98090_dais, 134 .num_links = ARRAY_SIZE(mt8173_max98090_dais), 135 .controls = mt8173_max98090_controls, 136 .num_controls = ARRAY_SIZE(mt8173_max98090_controls), 137 .dapm_widgets = mt8173_max98090_widgets, 138 .num_dapm_widgets = ARRAY_SIZE(mt8173_max98090_widgets), 139 .dapm_routes = mt8173_max98090_routes, 140 .num_dapm_routes = ARRAY_SIZE(mt8173_max98090_routes), 141 }; 142 143 static int mt8173_max98090_dev_probe(struct platform_device *pdev) 144 { 145 struct snd_soc_card *card = &mt8173_max98090_card; 146 struct device_node *codec_node, *platform_node; 147 struct snd_soc_dai_link *dai_link; 148 int ret, i; 149 150 platform_node = of_parse_phandle(pdev->dev.of_node, 151 "mediatek,platform", 0); 152 if (!platform_node) { 153 dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); 154 return -EINVAL; 155 } 156 for_each_card_prelinks(card, i, dai_link) { 157 if (dai_link->platforms->name) 158 continue; 159 dai_link->platforms->of_node = platform_node; 160 } 161 162 codec_node = of_parse_phandle(pdev->dev.of_node, 163 "mediatek,audio-codec", 0); 164 if (!codec_node) { 165 dev_err(&pdev->dev, 166 "Property 'audio-codec' missing or invalid\n"); 167 ret = -EINVAL; 168 goto put_platform_node; 169 } 170 for_each_card_prelinks(card, i, dai_link) { 171 if (dai_link->codecs->name) 172 continue; 173 dai_link->codecs->of_node = codec_node; 174 } 175 card->dev = &pdev->dev; 176 177 ret = devm_snd_soc_register_card(&pdev->dev, card); 178 179 of_node_put(codec_node); 180 181 put_platform_node: 182 of_node_put(platform_node); 183 return ret; 184 } 185 186 static const struct of_device_id mt8173_max98090_dt_match[] = { 187 { .compatible = "mediatek,mt8173-max98090", }, 188 { } 189 }; 190 MODULE_DEVICE_TABLE(of, mt8173_max98090_dt_match); 191 192 static struct platform_driver mt8173_max98090_driver = { 193 .driver = { 194 .name = "mt8173-max98090", 195 .of_match_table = mt8173_max98090_dt_match, 196 .pm = &snd_soc_pm_ops, 197 }, 198 .probe = mt8173_max98090_dev_probe, 199 }; 200 201 module_platform_driver(mt8173_max98090_driver); 202 203 /* Module information */ 204 MODULE_DESCRIPTION("MT8173 MAX98090 ALSA SoC machine driver"); 205 MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>"); 206 MODULE_LICENSE("GPL v2"); 207 MODULE_ALIAS("platform:mt8173-max98090"); 208 209