Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * tegra_asoc_machine.c - Universal ASoC machine driver for NVIDIA Tegra boards.
0004  */
0005 
0006 #include <linux/clk.h>
0007 #include <linux/export.h>
0008 #include <linux/gpio/consumer.h>
0009 #include <linux/module.h>
0010 #include <linux/of.h>
0011 #include <linux/of_device.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/slab.h>
0014 
0015 #include <sound/core.h>
0016 #include <sound/jack.h>
0017 #include <sound/pcm.h>
0018 #include <sound/pcm_params.h>
0019 #include <sound/soc.h>
0020 
0021 #include "tegra_asoc_machine.h"
0022 
0023 /* Headphones Jack */
0024 
0025 static struct snd_soc_jack tegra_machine_hp_jack;
0026 
0027 static struct snd_soc_jack_pin tegra_machine_hp_jack_pins[] = {
0028     { .pin = "Headphone",  .mask = SND_JACK_HEADPHONE },
0029     { .pin = "Headphones", .mask = SND_JACK_HEADPHONE },
0030 };
0031 
0032 static struct snd_soc_jack_gpio tegra_machine_hp_jack_gpio = {
0033     .name = "Headphones detection",
0034     .report = SND_JACK_HEADPHONE,
0035     .debounce_time = 150,
0036 };
0037 
0038 /* Headset Jack */
0039 
0040 static struct snd_soc_jack tegra_machine_headset_jack;
0041 
0042 static struct snd_soc_jack_pin tegra_machine_headset_jack_pins[] = {
0043     { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE },
0044     { .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE },
0045 };
0046 
0047 static struct snd_soc_jack_gpio tegra_machine_headset_jack_gpio = {
0048     .name = "Headset detection",
0049     .report = SND_JACK_HEADSET,
0050     .debounce_time = 150,
0051 };
0052 
0053 /* Mic Jack */
0054 
0055 static struct snd_soc_jack tegra_machine_mic_jack;
0056 
0057 static struct snd_soc_jack_pin tegra_machine_mic_jack_pins[] = {
0058     { .pin = "Mic Jack",    .mask = SND_JACK_MICROPHONE },
0059     { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE },
0060 };
0061 
0062 static struct snd_soc_jack_gpio tegra_machine_mic_jack_gpio = {
0063     .name = "Mic detection",
0064     .report = SND_JACK_MICROPHONE,
0065     .debounce_time = 150,
0066 };
0067 
0068 static int tegra_machine_event(struct snd_soc_dapm_widget *w,
0069                    struct snd_kcontrol *k, int event)
0070 {
0071     struct snd_soc_dapm_context *dapm = w->dapm;
0072     struct tegra_machine *machine = snd_soc_card_get_drvdata(dapm->card);
0073 
0074     if (!strcmp(w->name, "Int Spk") || !strcmp(w->name, "Speakers"))
0075         gpiod_set_value_cansleep(machine->gpiod_spkr_en,
0076                      SND_SOC_DAPM_EVENT_ON(event));
0077 
0078     if (!strcmp(w->name, "Mic Jack"))
0079         gpiod_set_value_cansleep(machine->gpiod_ext_mic_en,
0080                      SND_SOC_DAPM_EVENT_ON(event));
0081 
0082     if (!strcmp(w->name, "Int Mic"))
0083         gpiod_set_value_cansleep(machine->gpiod_int_mic_en,
0084                      SND_SOC_DAPM_EVENT_ON(event));
0085 
0086     if (!strcmp(w->name, "Headphone") || !strcmp(w->name, "Headphone Jack"))
0087         gpiod_set_value_cansleep(machine->gpiod_hp_mute,
0088                      !SND_SOC_DAPM_EVENT_ON(event));
0089 
0090     return 0;
0091 }
0092 
0093 static const struct snd_soc_dapm_widget tegra_machine_dapm_widgets[] = {
0094     SND_SOC_DAPM_HP("Headphone Jack", tegra_machine_event),
0095     SND_SOC_DAPM_HP("Headphone", tegra_machine_event),
0096     SND_SOC_DAPM_HP("Headset Stereophone", NULL),
0097     SND_SOC_DAPM_HP("Headphones", NULL),
0098     SND_SOC_DAPM_SPK("Speakers", tegra_machine_event),
0099     SND_SOC_DAPM_SPK("Int Spk", tegra_machine_event),
0100     SND_SOC_DAPM_MIC("Int Mic", tegra_machine_event),
0101     SND_SOC_DAPM_MIC("Mic Jack", tegra_machine_event),
0102     SND_SOC_DAPM_MIC("Internal Mic 1", NULL),
0103     SND_SOC_DAPM_MIC("Internal Mic 2", NULL),
0104     SND_SOC_DAPM_MIC("Headset Mic", NULL),
0105     SND_SOC_DAPM_MIC("Digital Mic", NULL),
0106     SND_SOC_DAPM_MIC("Mic", NULL),
0107     SND_SOC_DAPM_LINE("Line In Jack", NULL),
0108     SND_SOC_DAPM_LINE("Line In", NULL),
0109     SND_SOC_DAPM_LINE("LineIn", NULL),
0110 };
0111 
0112 static const struct snd_kcontrol_new tegra_machine_controls[] = {
0113     SOC_DAPM_PIN_SWITCH("Speakers"),
0114     SOC_DAPM_PIN_SWITCH("Int Spk"),
0115     SOC_DAPM_PIN_SWITCH("Int Mic"),
0116     SOC_DAPM_PIN_SWITCH("Headset Mic"),
0117     SOC_DAPM_PIN_SWITCH("Internal Mic 1"),
0118     SOC_DAPM_PIN_SWITCH("Internal Mic 2"),
0119     SOC_DAPM_PIN_SWITCH("Headphones"),
0120     SOC_DAPM_PIN_SWITCH("Mic Jack"),
0121 };
0122 
0123 int tegra_asoc_machine_init(struct snd_soc_pcm_runtime *rtd)
0124 {
0125     struct snd_soc_card *card = rtd->card;
0126     struct tegra_machine *machine = snd_soc_card_get_drvdata(card);
0127     const char *jack_name;
0128     int err;
0129 
0130     if (machine->gpiod_hp_det && machine->asoc->add_hp_jack) {
0131         if (machine->asoc->hp_jack_name)
0132             jack_name = machine->asoc->hp_jack_name;
0133         else
0134             jack_name = "Headphones Jack";
0135 
0136         err = snd_soc_card_jack_new_pins(card, jack_name,
0137                          SND_JACK_HEADPHONE,
0138                          &tegra_machine_hp_jack,
0139                          tegra_machine_hp_jack_pins,
0140                          ARRAY_SIZE(tegra_machine_hp_jack_pins));
0141         if (err) {
0142             dev_err(rtd->dev,
0143                 "Headphones Jack creation failed: %d\n", err);
0144             return err;
0145         }
0146 
0147         tegra_machine_hp_jack_gpio.desc = machine->gpiod_hp_det;
0148 
0149         err = snd_soc_jack_add_gpios(&tegra_machine_hp_jack, 1,
0150                          &tegra_machine_hp_jack_gpio);
0151         if (err)
0152             dev_err(rtd->dev, "HP GPIOs not added: %d\n", err);
0153     }
0154 
0155     if (machine->gpiod_hp_det && machine->asoc->add_headset_jack) {
0156         err = snd_soc_card_jack_new_pins(card, "Headset Jack",
0157                          SND_JACK_HEADSET,
0158                          &tegra_machine_headset_jack,
0159                          tegra_machine_headset_jack_pins,
0160                          ARRAY_SIZE(tegra_machine_headset_jack_pins));
0161         if (err) {
0162             dev_err(rtd->dev,
0163                 "Headset Jack creation failed: %d\n", err);
0164             return err;
0165         }
0166 
0167         tegra_machine_headset_jack_gpio.desc = machine->gpiod_hp_det;
0168 
0169         err = snd_soc_jack_add_gpios(&tegra_machine_headset_jack, 1,
0170                          &tegra_machine_headset_jack_gpio);
0171         if (err)
0172             dev_err(rtd->dev, "Headset GPIOs not added: %d\n", err);
0173     }
0174 
0175     if (machine->gpiod_mic_det && machine->asoc->add_mic_jack) {
0176         err = snd_soc_card_jack_new_pins(rtd->card, "Mic Jack",
0177                          SND_JACK_MICROPHONE,
0178                          &tegra_machine_mic_jack,
0179                          tegra_machine_mic_jack_pins,
0180                          ARRAY_SIZE(tegra_machine_mic_jack_pins));
0181         if (err) {
0182             dev_err(rtd->dev, "Mic Jack creation failed: %d\n", err);
0183             return err;
0184         }
0185 
0186         tegra_machine_mic_jack_gpio.desc = machine->gpiod_mic_det;
0187 
0188         err = snd_soc_jack_add_gpios(&tegra_machine_mic_jack, 1,
0189                          &tegra_machine_mic_jack_gpio);
0190         if (err)
0191             dev_err(rtd->dev, "Mic GPIOs not added: %d\n", err);
0192     }
0193 
0194     return 0;
0195 }
0196 EXPORT_SYMBOL_GPL(tegra_asoc_machine_init);
0197 
0198 static unsigned int tegra_machine_mclk_rate_128(unsigned int srate)
0199 {
0200     return 128 * srate;
0201 }
0202 
0203 static unsigned int tegra_machine_mclk_rate_256(unsigned int srate)
0204 {
0205     return 256 * srate;
0206 }
0207 
0208 static unsigned int tegra_machine_mclk_rate_512(unsigned int srate)
0209 {
0210     return 512 * srate;
0211 }
0212 
0213 static unsigned int tegra_machine_mclk_rate_12mhz(unsigned int srate)
0214 {
0215     unsigned int mclk;
0216 
0217     switch (srate) {
0218     case 8000:
0219     case 16000:
0220     case 24000:
0221     case 32000:
0222     case 48000:
0223     case 64000:
0224     case 96000:
0225         mclk = 12288000;
0226         break;
0227     case 11025:
0228     case 22050:
0229     case 44100:
0230     case 88200:
0231         mclk = 11289600;
0232         break;
0233     default:
0234         mclk = 12000000;
0235         break;
0236     }
0237 
0238     return mclk;
0239 }
0240 
0241 static int tegra_machine_hw_params(struct snd_pcm_substream *substream,
0242                    struct snd_pcm_hw_params *params)
0243 {
0244     struct snd_soc_pcm_runtime *rtd = substream->private_data;
0245     struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
0246     struct snd_soc_card *card = rtd->card;
0247     struct tegra_machine *machine = snd_soc_card_get_drvdata(card);
0248     unsigned int srate = params_rate(params);
0249     unsigned int mclk = machine->asoc->mclk_rate(srate);
0250     unsigned int clk_id = machine->asoc->mclk_id;
0251     unsigned int new_baseclock;
0252     int err;
0253 
0254     switch (srate) {
0255     case 11025:
0256     case 22050:
0257     case 44100:
0258     case 88200:
0259         if (of_machine_is_compatible("nvidia,tegra20"))
0260             new_baseclock = 56448000;
0261         else if (of_machine_is_compatible("nvidia,tegra30"))
0262             new_baseclock = 564480000;
0263         else
0264             new_baseclock = 282240000;
0265         break;
0266     case 8000:
0267     case 16000:
0268     case 32000:
0269     case 48000:
0270     case 64000:
0271     case 96000:
0272         if (of_machine_is_compatible("nvidia,tegra20"))
0273             new_baseclock = 73728000;
0274         else if (of_machine_is_compatible("nvidia,tegra30"))
0275             new_baseclock = 552960000;
0276         else
0277             new_baseclock = 368640000;
0278         break;
0279     default:
0280         dev_err(card->dev, "Invalid sound rate: %u\n", srate);
0281         return -EINVAL;
0282     }
0283 
0284     if (new_baseclock != machine->set_baseclock ||
0285         mclk != machine->set_mclk) {
0286         machine->set_baseclock = 0;
0287         machine->set_mclk = 0;
0288 
0289         clk_disable_unprepare(machine->clk_cdev1);
0290 
0291         err = clk_set_rate(machine->clk_pll_a, new_baseclock);
0292         if (err) {
0293             dev_err(card->dev, "Can't set pll_a rate: %d\n", err);
0294             return err;
0295         }
0296 
0297         err = clk_set_rate(machine->clk_pll_a_out0, mclk);
0298         if (err) {
0299             dev_err(card->dev, "Can't set pll_a_out0 rate: %d\n", err);
0300             return err;
0301         }
0302 
0303         /* Don't set cdev1/extern1 rate; it's locked to pll_a_out0 */
0304 
0305         err = clk_prepare_enable(machine->clk_cdev1);
0306         if (err) {
0307             dev_err(card->dev, "Can't enable cdev1: %d\n", err);
0308             return err;
0309         }
0310 
0311         machine->set_baseclock = new_baseclock;
0312         machine->set_mclk = mclk;
0313     }
0314 
0315     err = snd_soc_dai_set_sysclk(codec_dai, clk_id, mclk, SND_SOC_CLOCK_IN);
0316     if (err < 0) {
0317         dev_err(card->dev, "codec_dai clock not set: %d\n", err);
0318         return err;
0319     }
0320 
0321     return 0;
0322 }
0323 
0324 static const struct snd_soc_ops tegra_machine_snd_ops = {
0325     .hw_params = tegra_machine_hw_params,
0326 };
0327 
0328 static void tegra_machine_node_release(void *of_node)
0329 {
0330     of_node_put(of_node);
0331 }
0332 
0333 static struct device_node *
0334 tegra_machine_parse_phandle(struct device *dev, const char *name)
0335 {
0336     struct device_node *np;
0337     int err;
0338 
0339     np = of_parse_phandle(dev->of_node, name, 0);
0340     if (!np) {
0341         dev_err(dev, "Property '%s' missing or invalid\n", name);
0342         return ERR_PTR(-EINVAL);
0343     }
0344 
0345     err = devm_add_action_or_reset(dev, tegra_machine_node_release, np);
0346     if (err)
0347         return ERR_PTR(err);
0348 
0349     return np;
0350 }
0351 
0352 static void tegra_machine_unregister_codec(void *pdev)
0353 {
0354     platform_device_unregister(pdev);
0355 }
0356 
0357 static int tegra_machine_register_codec(struct device *dev, const char *name)
0358 {
0359     struct platform_device *pdev;
0360     int err;
0361 
0362     if (!name)
0363         return 0;
0364 
0365     pdev = platform_device_register_simple(name, -1, NULL, 0);
0366     if (IS_ERR(pdev))
0367         return PTR_ERR(pdev);
0368 
0369     err = devm_add_action_or_reset(dev, tegra_machine_unregister_codec,
0370                        pdev);
0371     if (err)
0372         return err;
0373 
0374     return 0;
0375 }
0376 
0377 int tegra_asoc_machine_probe(struct platform_device *pdev)
0378 {
0379     struct device_node *np_codec, *np_i2s, *np_ac97;
0380     const struct tegra_asoc_data *asoc;
0381     struct device *dev = &pdev->dev;
0382     struct tegra_machine *machine;
0383     struct snd_soc_card *card;
0384     struct gpio_desc *gpiod;
0385     int err;
0386 
0387     machine = devm_kzalloc(dev, sizeof(*machine), GFP_KERNEL);
0388     if (!machine)
0389         return -ENOMEM;
0390 
0391     asoc = of_device_get_match_data(dev);
0392     card = asoc->card;
0393     card->dev = dev;
0394 
0395     machine->asoc = asoc;
0396     machine->mic_jack = &tegra_machine_mic_jack;
0397     machine->hp_jack_gpio = &tegra_machine_hp_jack_gpio;
0398     snd_soc_card_set_drvdata(card, machine);
0399 
0400     gpiod = devm_gpiod_get_optional(dev, "nvidia,hp-mute", GPIOD_OUT_HIGH);
0401     machine->gpiod_hp_mute = gpiod;
0402     if (IS_ERR(gpiod))
0403         return PTR_ERR(gpiod);
0404 
0405     gpiod = devm_gpiod_get_optional(dev, "nvidia,hp-det", GPIOD_IN);
0406     machine->gpiod_hp_det = gpiod;
0407     if (IS_ERR(gpiod))
0408         return PTR_ERR(gpiod);
0409 
0410     gpiod = devm_gpiod_get_optional(dev, "nvidia,mic-det", GPIOD_IN);
0411     machine->gpiod_mic_det = gpiod;
0412     if (IS_ERR(gpiod))
0413         return PTR_ERR(gpiod);
0414 
0415     gpiod = devm_gpiod_get_optional(dev, "nvidia,spkr-en", GPIOD_OUT_LOW);
0416     machine->gpiod_spkr_en = gpiod;
0417     if (IS_ERR(gpiod))
0418         return PTR_ERR(gpiod);
0419 
0420     gpiod = devm_gpiod_get_optional(dev, "nvidia,int-mic-en", GPIOD_OUT_LOW);
0421     machine->gpiod_int_mic_en = gpiod;
0422     if (IS_ERR(gpiod))
0423         return PTR_ERR(gpiod);
0424 
0425     gpiod = devm_gpiod_get_optional(dev, "nvidia,ext-mic-en", GPIOD_OUT_LOW);
0426     machine->gpiod_ext_mic_en = gpiod;
0427     if (IS_ERR(gpiod))
0428         return PTR_ERR(gpiod);
0429 
0430     err = snd_soc_of_parse_card_name(card, "nvidia,model");
0431     if (err)
0432         return err;
0433 
0434     if (!card->dapm_routes) {
0435         err = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
0436         if (err)
0437             return err;
0438     }
0439 
0440     if (asoc->set_ac97) {
0441         err = tegra_machine_register_codec(dev, asoc->codec_dev_name);
0442         if (err)
0443             return err;
0444 
0445         np_ac97 = tegra_machine_parse_phandle(dev, "nvidia,ac97-controller");
0446         if (IS_ERR(np_ac97))
0447             return PTR_ERR(np_ac97);
0448 
0449         card->dai_link->cpus->of_node = np_ac97;
0450         card->dai_link->platforms->of_node = np_ac97;
0451     } else {
0452         np_codec = tegra_machine_parse_phandle(dev, "nvidia,audio-codec");
0453         if (IS_ERR(np_codec))
0454             return PTR_ERR(np_codec);
0455 
0456         np_i2s = tegra_machine_parse_phandle(dev, "nvidia,i2s-controller");
0457         if (IS_ERR(np_i2s))
0458             return PTR_ERR(np_i2s);
0459 
0460         card->dai_link->cpus->of_node = np_i2s;
0461         card->dai_link->codecs->of_node = np_codec;
0462         card->dai_link->platforms->of_node = np_i2s;
0463     }
0464 
0465     if (asoc->add_common_controls) {
0466         card->controls = tegra_machine_controls;
0467         card->num_controls = ARRAY_SIZE(tegra_machine_controls);
0468     }
0469 
0470     if (asoc->add_common_dapm_widgets) {
0471         card->dapm_widgets = tegra_machine_dapm_widgets;
0472         card->num_dapm_widgets = ARRAY_SIZE(tegra_machine_dapm_widgets);
0473     }
0474 
0475     if (asoc->add_common_snd_ops)
0476         card->dai_link->ops = &tegra_machine_snd_ops;
0477 
0478     if (!card->owner)
0479         card->owner = THIS_MODULE;
0480     if (!card->driver_name)
0481         card->driver_name = "tegra";
0482 
0483     machine->clk_pll_a = devm_clk_get(dev, "pll_a");
0484     if (IS_ERR(machine->clk_pll_a)) {
0485         dev_err(dev, "Can't retrieve clk pll_a\n");
0486         return PTR_ERR(machine->clk_pll_a);
0487     }
0488 
0489     machine->clk_pll_a_out0 = devm_clk_get(dev, "pll_a_out0");
0490     if (IS_ERR(machine->clk_pll_a_out0)) {
0491         dev_err(dev, "Can't retrieve clk pll_a_out0\n");
0492         return PTR_ERR(machine->clk_pll_a_out0);
0493     }
0494 
0495     machine->clk_cdev1 = devm_clk_get(dev, "mclk");
0496     if (IS_ERR(machine->clk_cdev1)) {
0497         dev_err(dev, "Can't retrieve clk cdev1\n");
0498         return PTR_ERR(machine->clk_cdev1);
0499     }
0500 
0501     /*
0502      * If clock parents are not set in DT, configure here to use clk_out_1
0503      * as mclk and extern1 as parent for Tegra30 and higher.
0504      */
0505     if (!of_find_property(dev->of_node, "assigned-clock-parents", NULL) &&
0506         !of_machine_is_compatible("nvidia,tegra20")) {
0507         struct clk *clk_out_1, *clk_extern1;
0508 
0509         dev_warn(dev, "Configuring clocks for a legacy device-tree\n");
0510         dev_warn(dev, "Please update DT to use assigned-clock-parents\n");
0511 
0512         clk_extern1 = devm_clk_get(dev, "extern1");
0513         if (IS_ERR(clk_extern1)) {
0514             dev_err(dev, "Can't retrieve clk extern1\n");
0515             return PTR_ERR(clk_extern1);
0516         }
0517 
0518         err = clk_set_parent(clk_extern1, machine->clk_pll_a_out0);
0519         if (err < 0) {
0520             dev_err(dev, "Set parent failed for clk extern1\n");
0521             return err;
0522         }
0523 
0524         clk_out_1 = devm_clk_get(dev, "pmc_clk_out_1");
0525         if (IS_ERR(clk_out_1)) {
0526             dev_err(dev, "Can't retrieve pmc_clk_out_1\n");
0527             return PTR_ERR(clk_out_1);
0528         }
0529 
0530         err = clk_set_parent(clk_out_1, clk_extern1);
0531         if (err < 0) {
0532             dev_err(dev, "Set parent failed for pmc_clk_out_1\n");
0533             return err;
0534         }
0535 
0536         machine->clk_cdev1 = clk_out_1;
0537     }
0538 
0539     if (asoc->set_ac97) {
0540         /*
0541          * AC97 rate is fixed at 24.576MHz and is used for both the
0542          * host controller and the external codec
0543          */
0544         err = clk_set_rate(machine->clk_pll_a, 73728000);
0545         if (err) {
0546             dev_err(dev, "Can't set pll_a rate: %d\n", err);
0547             return err;
0548         }
0549 
0550         err = clk_set_rate(machine->clk_pll_a_out0, 24576000);
0551         if (err) {
0552             dev_err(dev, "Can't set pll_a_out0 rate: %d\n", err);
0553             return err;
0554         }
0555 
0556         machine->set_baseclock = 73728000;
0557         machine->set_mclk = 24576000;
0558     }
0559 
0560     /*
0561      * FIXME: There is some unknown dependency between audio MCLK disable
0562      * and suspend-resume functionality on Tegra30, although audio MCLK is
0563      * only needed for audio.
0564      */
0565     err = clk_prepare_enable(machine->clk_cdev1);
0566     if (err) {
0567         dev_err(dev, "Can't enable cdev1: %d\n", err);
0568         return err;
0569     }
0570 
0571     err = devm_snd_soc_register_card(dev, card);
0572     if (err)
0573         return err;
0574 
0575     return 0;
0576 }
0577 EXPORT_SYMBOL_GPL(tegra_asoc_machine_probe);
0578 
0579 /* WM8753 machine */
0580 
0581 SND_SOC_DAILINK_DEFS(wm8753_hifi,
0582     DAILINK_COMP_ARRAY(COMP_EMPTY()),
0583     DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8753-hifi")),
0584     DAILINK_COMP_ARRAY(COMP_EMPTY()));
0585 
0586 static struct snd_soc_dai_link tegra_wm8753_dai = {
0587     .name = "WM8753",
0588     .stream_name = "WM8753 PCM",
0589     .dai_fmt = SND_SOC_DAIFMT_I2S |
0590            SND_SOC_DAIFMT_NB_NF |
0591            SND_SOC_DAIFMT_CBS_CFS,
0592     SND_SOC_DAILINK_REG(wm8753_hifi),
0593 };
0594 
0595 static struct snd_soc_card snd_soc_tegra_wm8753 = {
0596     .components = "codec:wm8753",
0597     .dai_link = &tegra_wm8753_dai,
0598     .num_links = 1,
0599     .fully_routed = true,
0600 };
0601 
0602 static const struct tegra_asoc_data tegra_wm8753_data = {
0603     .mclk_rate = tegra_machine_mclk_rate_12mhz,
0604     .card = &snd_soc_tegra_wm8753,
0605     .add_common_dapm_widgets = true,
0606     .add_common_snd_ops = true,
0607 };
0608 
0609 /* WM9712 machine */
0610 
0611 static int tegra_wm9712_init(struct snd_soc_pcm_runtime *rtd)
0612 {
0613     return snd_soc_dapm_force_enable_pin(&rtd->card->dapm, "Mic Bias");
0614 }
0615 
0616 SND_SOC_DAILINK_DEFS(wm9712_hifi,
0617     DAILINK_COMP_ARRAY(COMP_EMPTY()),
0618     DAILINK_COMP_ARRAY(COMP_CODEC("wm9712-codec", "wm9712-hifi")),
0619     DAILINK_COMP_ARRAY(COMP_EMPTY()));
0620 
0621 static struct snd_soc_dai_link tegra_wm9712_dai = {
0622     .name = "AC97 HiFi",
0623     .stream_name = "AC97 HiFi",
0624     .init = tegra_wm9712_init,
0625     SND_SOC_DAILINK_REG(wm9712_hifi),
0626 };
0627 
0628 static struct snd_soc_card snd_soc_tegra_wm9712 = {
0629     .components = "codec:wm9712",
0630     .dai_link = &tegra_wm9712_dai,
0631     .num_links = 1,
0632     .fully_routed = true,
0633 };
0634 
0635 static const struct tegra_asoc_data tegra_wm9712_data = {
0636     .card = &snd_soc_tegra_wm9712,
0637     .add_common_dapm_widgets = true,
0638     .codec_dev_name = "wm9712-codec",
0639     .set_ac97 = true,
0640 };
0641 
0642 /* MAX98090 machine */
0643 
0644 SND_SOC_DAILINK_DEFS(max98090_hifi,
0645     DAILINK_COMP_ARRAY(COMP_EMPTY()),
0646     DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")),
0647     DAILINK_COMP_ARRAY(COMP_EMPTY()));
0648 
0649 static struct snd_soc_dai_link tegra_max98090_dai = {
0650     .name = "max98090",
0651     .stream_name = "max98090 PCM",
0652     .init = tegra_asoc_machine_init,
0653     .dai_fmt = SND_SOC_DAIFMT_I2S |
0654            SND_SOC_DAIFMT_NB_NF |
0655            SND_SOC_DAIFMT_CBS_CFS,
0656     SND_SOC_DAILINK_REG(max98090_hifi),
0657 };
0658 
0659 static struct snd_soc_card snd_soc_tegra_max98090 = {
0660     .components = "codec:max98090",
0661     .dai_link = &tegra_max98090_dai,
0662     .num_links = 1,
0663     .fully_routed = true,
0664 };
0665 
0666 static const struct tegra_asoc_data tegra_max98090_data = {
0667     .mclk_rate = tegra_machine_mclk_rate_12mhz,
0668     .card = &snd_soc_tegra_max98090,
0669     .hp_jack_name = "Headphones",
0670     .add_common_dapm_widgets = true,
0671     .add_common_controls = true,
0672     .add_common_snd_ops = true,
0673     .add_mic_jack = true,
0674     .add_hp_jack = true,
0675 };
0676 
0677 /* SGTL5000 machine */
0678 
0679 SND_SOC_DAILINK_DEFS(sgtl5000_hifi,
0680     DAILINK_COMP_ARRAY(COMP_EMPTY()),
0681     DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "sgtl5000")),
0682     DAILINK_COMP_ARRAY(COMP_EMPTY()));
0683 
0684 static struct snd_soc_dai_link tegra_sgtl5000_dai = {
0685     .name = "sgtl5000",
0686     .stream_name = "HiFi",
0687     .dai_fmt = SND_SOC_DAIFMT_I2S |
0688            SND_SOC_DAIFMT_NB_NF |
0689            SND_SOC_DAIFMT_CBS_CFS,
0690     SND_SOC_DAILINK_REG(sgtl5000_hifi),
0691 };
0692 
0693 static struct snd_soc_card snd_soc_tegra_sgtl5000 = {
0694     .components = "codec:sgtl5000",
0695     .dai_link = &tegra_sgtl5000_dai,
0696     .num_links = 1,
0697     .fully_routed = true,
0698 };
0699 
0700 static const struct tegra_asoc_data tegra_sgtl5000_data = {
0701     .mclk_rate = tegra_machine_mclk_rate_12mhz,
0702     .card = &snd_soc_tegra_sgtl5000,
0703     .add_common_dapm_widgets = true,
0704     .add_common_snd_ops = true,
0705 };
0706 
0707 /* TLV320AIC23 machine */
0708 
0709 static const struct snd_soc_dapm_widget trimslice_dapm_widgets[] = {
0710     SND_SOC_DAPM_HP("Line Out", NULL),
0711     SND_SOC_DAPM_LINE("Line In", NULL),
0712 };
0713 
0714 static const struct snd_soc_dapm_route trimslice_audio_map[] = {
0715     {"Line Out", NULL, "LOUT"},
0716     {"Line Out", NULL, "ROUT"},
0717 
0718     {"LLINEIN", NULL, "Line In"},
0719     {"RLINEIN", NULL, "Line In"},
0720 };
0721 
0722 SND_SOC_DAILINK_DEFS(tlv320aic23_hifi,
0723     DAILINK_COMP_ARRAY(COMP_EMPTY()),
0724     DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "tlv320aic23-hifi")),
0725     DAILINK_COMP_ARRAY(COMP_EMPTY()));
0726 
0727 static struct snd_soc_dai_link tegra_tlv320aic23_dai = {
0728     .name = "TLV320AIC23",
0729     .stream_name = "AIC23",
0730     .dai_fmt = SND_SOC_DAIFMT_I2S |
0731            SND_SOC_DAIFMT_NB_NF |
0732            SND_SOC_DAIFMT_CBS_CFS,
0733     SND_SOC_DAILINK_REG(tlv320aic23_hifi),
0734 };
0735 
0736 static struct snd_soc_card snd_soc_tegra_trimslice = {
0737     .name = "tegra-trimslice",
0738     .components = "codec:tlv320aic23",
0739     .dai_link = &tegra_tlv320aic23_dai,
0740     .num_links = 1,
0741     .dapm_widgets = trimslice_dapm_widgets,
0742     .num_dapm_widgets = ARRAY_SIZE(trimslice_dapm_widgets),
0743     .dapm_routes = trimslice_audio_map,
0744     .num_dapm_routes = ARRAY_SIZE(trimslice_audio_map),
0745     .fully_routed = true,
0746 };
0747 
0748 static const struct tegra_asoc_data tegra_trimslice_data = {
0749     .mclk_rate = tegra_machine_mclk_rate_128,
0750     .card = &snd_soc_tegra_trimslice,
0751     .add_common_snd_ops = true,
0752 };
0753 
0754 /* RT5677 machine */
0755 
0756 static int tegra_rt5677_init(struct snd_soc_pcm_runtime *rtd)
0757 {
0758     struct snd_soc_card *card = rtd->card;
0759     int err;
0760 
0761     err = tegra_asoc_machine_init(rtd);
0762     if (err)
0763         return err;
0764 
0765     snd_soc_dapm_force_enable_pin(&card->dapm, "MICBIAS1");
0766 
0767     return 0;
0768 }
0769 
0770 SND_SOC_DAILINK_DEFS(rt5677_aif1,
0771     DAILINK_COMP_ARRAY(COMP_EMPTY()),
0772     DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5677-aif1")),
0773     DAILINK_COMP_ARRAY(COMP_EMPTY()));
0774 
0775 static struct snd_soc_dai_link tegra_rt5677_dai = {
0776     .name = "RT5677",
0777     .stream_name = "RT5677 PCM",
0778     .init = tegra_rt5677_init,
0779     .dai_fmt = SND_SOC_DAIFMT_I2S |
0780            SND_SOC_DAIFMT_NB_NF |
0781            SND_SOC_DAIFMT_CBS_CFS,
0782     SND_SOC_DAILINK_REG(rt5677_aif1),
0783 };
0784 
0785 static struct snd_soc_card snd_soc_tegra_rt5677 = {
0786     .components = "codec:rt5677",
0787     .dai_link = &tegra_rt5677_dai,
0788     .num_links = 1,
0789     .fully_routed = true,
0790 };
0791 
0792 static const struct tegra_asoc_data tegra_rt5677_data = {
0793     .mclk_rate = tegra_machine_mclk_rate_256,
0794     .card = &snd_soc_tegra_rt5677,
0795     .add_common_dapm_widgets = true,
0796     .add_common_controls = true,
0797     .add_common_snd_ops = true,
0798     .add_mic_jack = true,
0799     .add_hp_jack = true,
0800 };
0801 
0802 /* RT5640 machine */
0803 
0804 SND_SOC_DAILINK_DEFS(rt5640_aif1,
0805     DAILINK_COMP_ARRAY(COMP_EMPTY()),
0806     DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5640-aif1")),
0807     DAILINK_COMP_ARRAY(COMP_EMPTY()));
0808 
0809 static struct snd_soc_dai_link tegra_rt5640_dai = {
0810     .name = "RT5640",
0811     .stream_name = "RT5640 PCM",
0812     .init = tegra_asoc_machine_init,
0813     .dai_fmt = SND_SOC_DAIFMT_I2S |
0814            SND_SOC_DAIFMT_NB_NF |
0815            SND_SOC_DAIFMT_CBS_CFS,
0816     SND_SOC_DAILINK_REG(rt5640_aif1),
0817 };
0818 
0819 static struct snd_soc_card snd_soc_tegra_rt5640 = {
0820     .components = "codec:rt5640",
0821     .dai_link = &tegra_rt5640_dai,
0822     .num_links = 1,
0823     .fully_routed = true,
0824 };
0825 
0826 static const struct tegra_asoc_data tegra_rt5640_data = {
0827     .mclk_rate = tegra_machine_mclk_rate_256,
0828     .card = &snd_soc_tegra_rt5640,
0829     .add_common_dapm_widgets = true,
0830     .add_common_controls = true,
0831     .add_common_snd_ops = true,
0832     .add_hp_jack = true,
0833 };
0834 
0835 /* RT5632 machine */
0836 
0837 SND_SOC_DAILINK_DEFS(rt5632_hifi,
0838     DAILINK_COMP_ARRAY(COMP_EMPTY()),
0839     DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "alc5632-hifi")),
0840     DAILINK_COMP_ARRAY(COMP_EMPTY()));
0841 
0842 static struct snd_soc_dai_link tegra_rt5632_dai = {
0843     .name = "ALC5632",
0844     .stream_name = "ALC5632 PCM",
0845     .init = tegra_rt5677_init,
0846     .dai_fmt = SND_SOC_DAIFMT_I2S |
0847            SND_SOC_DAIFMT_NB_NF |
0848            SND_SOC_DAIFMT_CBS_CFS,
0849     SND_SOC_DAILINK_REG(rt5632_hifi),
0850 };
0851 
0852 static struct snd_soc_card snd_soc_tegra_rt5632 = {
0853     .components = "codec:rt5632",
0854     .dai_link = &tegra_rt5632_dai,
0855     .num_links = 1,
0856     .fully_routed = true,
0857 };
0858 
0859 static const struct tegra_asoc_data tegra_rt5632_data = {
0860     .mclk_rate = tegra_machine_mclk_rate_512,
0861     .card = &snd_soc_tegra_rt5632,
0862     .add_common_dapm_widgets = true,
0863     .add_common_controls = true,
0864     .add_common_snd_ops = true,
0865     .add_headset_jack = true,
0866 };
0867 
0868 static const struct of_device_id tegra_machine_of_match[] = {
0869     { .compatible = "nvidia,tegra-audio-trimslice", .data = &tegra_trimslice_data },
0870     { .compatible = "nvidia,tegra-audio-max98090", .data = &tegra_max98090_data },
0871     { .compatible = "nvidia,tegra-audio-sgtl5000", .data = &tegra_sgtl5000_data },
0872     { .compatible = "nvidia,tegra-audio-wm9712", .data = &tegra_wm9712_data },
0873     { .compatible = "nvidia,tegra-audio-wm8753", .data = &tegra_wm8753_data },
0874     { .compatible = "nvidia,tegra-audio-rt5677", .data = &tegra_rt5677_data },
0875     { .compatible = "nvidia,tegra-audio-rt5640", .data = &tegra_rt5640_data },
0876     { .compatible = "nvidia,tegra-audio-alc5632", .data = &tegra_rt5632_data },
0877     {},
0878 };
0879 MODULE_DEVICE_TABLE(of, tegra_machine_of_match);
0880 
0881 static struct platform_driver tegra_asoc_machine_driver = {
0882     .driver = {
0883         .name = "tegra-audio",
0884         .of_match_table = tegra_machine_of_match,
0885         .pm = &snd_soc_pm_ops,
0886     },
0887     .probe = tegra_asoc_machine_probe,
0888 };
0889 module_platform_driver(tegra_asoc_machine_driver);
0890 
0891 MODULE_AUTHOR("Anatol Pomozov <anatol@google.com>");
0892 MODULE_AUTHOR("Andrey Danin <danindrey@mail.ru>");
0893 MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>");
0894 MODULE_AUTHOR("Ion Agorria <ion@agorria.com>");
0895 MODULE_AUTHOR("Leon Romanovsky <leon@leon.nu>");
0896 MODULE_AUTHOR("Lucas Stach <dev@lynxeye.de>");
0897 MODULE_AUTHOR("Marc Dietrich <marvin24@gmx.de>");
0898 MODULE_AUTHOR("Marcel Ziswiler <marcel@ziswiler.com>");
0899 MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
0900 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
0901 MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>");
0902 MODULE_DESCRIPTION("Tegra machine ASoC driver");
0903 MODULE_LICENSE("GPL");