0001
0002
0003
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
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
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
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
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
0503
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
0542
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
0562
0563
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
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
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
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
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
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
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
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
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");