Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * mt8173-max98090.c  --  MT8173 MAX98090 ALSA SoC machine driver
0004  *
0005  * Copyright (c) 2015 MediaTek Inc.
0006  * Author: Koro Chen <koro.chen@mediatek.com>
0007  */
0008 
0009 #include <linux/module.h>
0010 #include <sound/soc.h>
0011 #include <sound/jack.h>
0012 #include <linux/gpio.h>
0013 #include "../../codecs/max98090.h"
0014 
0015 static struct snd_soc_jack mt8173_max98090_jack;
0016 
0017 static struct snd_soc_jack_pin mt8173_max98090_jack_pins[] = {
0018     {
0019         .pin    = "Headphone",
0020         .mask   = SND_JACK_HEADPHONE,
0021     },
0022     {
0023         .pin    = "Headset Mic",
0024         .mask   = SND_JACK_MICROPHONE,
0025     },
0026 };
0027 
0028 static const struct snd_soc_dapm_widget mt8173_max98090_widgets[] = {
0029     SND_SOC_DAPM_SPK("Speaker", NULL),
0030     SND_SOC_DAPM_MIC("Int Mic", NULL),
0031     SND_SOC_DAPM_HP("Headphone", NULL),
0032     SND_SOC_DAPM_MIC("Headset Mic", NULL),
0033 };
0034 
0035 static const struct snd_soc_dapm_route mt8173_max98090_routes[] = {
0036     {"Speaker", NULL, "SPKL"},
0037     {"Speaker", NULL, "SPKR"},
0038     {"DMICL", NULL, "Int Mic"},
0039     {"Headphone", NULL, "HPL"},
0040     {"Headphone", NULL, "HPR"},
0041     {"Headset Mic", NULL, "MICBIAS"},
0042     {"IN34", NULL, "Headset Mic"},
0043 };
0044 
0045 static const struct snd_kcontrol_new mt8173_max98090_controls[] = {
0046     SOC_DAPM_PIN_SWITCH("Speaker"),
0047     SOC_DAPM_PIN_SWITCH("Int Mic"),
0048     SOC_DAPM_PIN_SWITCH("Headphone"),
0049     SOC_DAPM_PIN_SWITCH("Headset Mic"),
0050 };
0051 
0052 static int mt8173_max98090_hw_params(struct snd_pcm_substream *substream,
0053                      struct snd_pcm_hw_params *params)
0054 {
0055     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0056     struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
0057 
0058     return snd_soc_dai_set_sysclk(codec_dai, 0, params_rate(params) * 256,
0059                       SND_SOC_CLOCK_IN);
0060 }
0061 
0062 static const struct snd_soc_ops mt8173_max98090_ops = {
0063     .hw_params = mt8173_max98090_hw_params,
0064 };
0065 
0066 static int mt8173_max98090_init(struct snd_soc_pcm_runtime *runtime)
0067 {
0068     int ret;
0069     struct snd_soc_card *card = runtime->card;
0070     struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
0071 
0072     /* enable jack detection */
0073     ret = snd_soc_card_jack_new_pins(card, "Headphone", SND_JACK_HEADPHONE,
0074                      &mt8173_max98090_jack,
0075                      mt8173_max98090_jack_pins,
0076                      ARRAY_SIZE(mt8173_max98090_jack_pins));
0077     if (ret) {
0078         dev_err(card->dev, "Can't create a new Jack %d\n", ret);
0079         return ret;
0080     }
0081 
0082     return max98090_mic_detect(component, &mt8173_max98090_jack);
0083 }
0084 
0085 SND_SOC_DAILINK_DEFS(playback,
0086     DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
0087     DAILINK_COMP_ARRAY(COMP_DUMMY()),
0088     DAILINK_COMP_ARRAY(COMP_EMPTY()));
0089 
0090 SND_SOC_DAILINK_DEFS(capture,
0091     DAILINK_COMP_ARRAY(COMP_CPU("VUL")),
0092     DAILINK_COMP_ARRAY(COMP_DUMMY()),
0093     DAILINK_COMP_ARRAY(COMP_EMPTY()));
0094 
0095 SND_SOC_DAILINK_DEFS(hifi,
0096     DAILINK_COMP_ARRAY(COMP_CPU("I2S")),
0097     DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")),
0098     DAILINK_COMP_ARRAY(COMP_EMPTY()));
0099 
0100 /* Digital audio interface glue - connects codec <---> CPU */
0101 static struct snd_soc_dai_link mt8173_max98090_dais[] = {
0102     /* Front End DAI links */
0103     {
0104         .name = "MAX98090 Playback",
0105         .stream_name = "MAX98090 Playback",
0106         .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
0107         .dynamic = 1,
0108         .dpcm_playback = 1,
0109         SND_SOC_DAILINK_REG(playback),
0110     },
0111     {
0112         .name = "MAX98090 Capture",
0113         .stream_name = "MAX98090 Capture",
0114         .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
0115         .dynamic = 1,
0116         .dpcm_capture = 1,
0117         SND_SOC_DAILINK_REG(capture),
0118     },
0119     /* Back End DAI links */
0120     {
0121         .name = "Codec",
0122         .no_pcm = 1,
0123         .init = mt8173_max98090_init,
0124         .ops = &mt8173_max98090_ops,
0125         .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
0126                SND_SOC_DAIFMT_CBS_CFS,
0127         .dpcm_playback = 1,
0128         .dpcm_capture = 1,
0129         SND_SOC_DAILINK_REG(hifi),
0130     },
0131 };
0132 
0133 static struct snd_soc_card mt8173_max98090_card = {
0134     .name = "mt8173-max98090",
0135     .owner = THIS_MODULE,
0136     .dai_link = mt8173_max98090_dais,
0137     .num_links = ARRAY_SIZE(mt8173_max98090_dais),
0138     .controls = mt8173_max98090_controls,
0139     .num_controls = ARRAY_SIZE(mt8173_max98090_controls),
0140     .dapm_widgets = mt8173_max98090_widgets,
0141     .num_dapm_widgets = ARRAY_SIZE(mt8173_max98090_widgets),
0142     .dapm_routes = mt8173_max98090_routes,
0143     .num_dapm_routes = ARRAY_SIZE(mt8173_max98090_routes),
0144 };
0145 
0146 static int mt8173_max98090_dev_probe(struct platform_device *pdev)
0147 {
0148     struct snd_soc_card *card = &mt8173_max98090_card;
0149     struct device_node *codec_node, *platform_node;
0150     struct snd_soc_dai_link *dai_link;
0151     int ret, i;
0152 
0153     platform_node = of_parse_phandle(pdev->dev.of_node,
0154                      "mediatek,platform", 0);
0155     if (!platform_node) {
0156         dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
0157         return -EINVAL;
0158     }
0159     for_each_card_prelinks(card, i, dai_link) {
0160         if (dai_link->platforms->name)
0161             continue;
0162         dai_link->platforms->of_node = platform_node;
0163     }
0164 
0165     codec_node = of_parse_phandle(pdev->dev.of_node,
0166                       "mediatek,audio-codec", 0);
0167     if (!codec_node) {
0168         dev_err(&pdev->dev,
0169             "Property 'audio-codec' missing or invalid\n");
0170         ret = -EINVAL;
0171         goto put_platform_node;
0172     }
0173     for_each_card_prelinks(card, i, dai_link) {
0174         if (dai_link->codecs->name)
0175             continue;
0176         dai_link->codecs->of_node = codec_node;
0177     }
0178     card->dev = &pdev->dev;
0179 
0180     ret = devm_snd_soc_register_card(&pdev->dev, card);
0181 
0182     of_node_put(codec_node);
0183 
0184 put_platform_node:
0185     of_node_put(platform_node);
0186     return ret;
0187 }
0188 
0189 static const struct of_device_id mt8173_max98090_dt_match[] = {
0190     { .compatible = "mediatek,mt8173-max98090", },
0191     { }
0192 };
0193 MODULE_DEVICE_TABLE(of, mt8173_max98090_dt_match);
0194 
0195 static struct platform_driver mt8173_max98090_driver = {
0196     .driver = {
0197            .name = "mt8173-max98090",
0198            .of_match_table = mt8173_max98090_dt_match,
0199            .pm = &snd_soc_pm_ops,
0200     },
0201     .probe = mt8173_max98090_dev_probe,
0202 };
0203 
0204 module_platform_driver(mt8173_max98090_driver);
0205 
0206 /* Module information */
0207 MODULE_DESCRIPTION("MT8173 MAX98090 ALSA SoC machine driver");
0208 MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>");
0209 MODULE_LICENSE("GPL v2");
0210 MODULE_ALIAS("platform:mt8173-max98090");
0211