brintos

brintos / linux-shallow public Read only

0
0
Text · 27.0 KiB · 775ce43 Raw
1024 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * tegra_asoc_machine.c - Universal ASoC machine driver for NVIDIA Tegra boards.4 */5 6#include <linux/clk.h>7#include <linux/export.h>8#include <linux/gpio/consumer.h>9#include <linux/module.h>10#include <linux/of.h>11#include <linux/platform_device.h>12#include <linux/slab.h>13 14#include <sound/core.h>15#include <sound/jack.h>16#include <sound/pcm.h>17#include <sound/pcm_params.h>18#include <sound/soc.h>19 20#include "tegra_asoc_machine.h"21 22/* Headphones Jack */23 24static struct snd_soc_jack tegra_machine_hp_jack;25 26static struct snd_soc_jack_pin tegra_machine_hp_jack_pins[] = {27	{ .pin = "Headphone",  .mask = SND_JACK_HEADPHONE },28	{ .pin = "Headphones", .mask = SND_JACK_HEADPHONE },29};30 31static struct snd_soc_jack_gpio tegra_machine_hp_jack_gpio = {32	.name = "Headphones detection",33	.report = SND_JACK_HEADPHONE,34	.debounce_time = 150,35};36 37/* Headset Jack */38 39static struct snd_soc_jack tegra_machine_headset_jack;40 41static struct snd_soc_jack_pin tegra_machine_headset_jack_pins[] = {42	{ .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE },43	{ .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE },44};45 46static struct snd_soc_jack_gpio tegra_machine_headset_jack_gpio = {47	.name = "Headset detection",48	.report = SND_JACK_HEADSET,49	.debounce_time = 150,50};51 52/* Mic Jack */53static int coupled_mic_hp_check(void *data)54{55	struct tegra_machine *machine = (struct tegra_machine *)data;56 57	/* Detect mic insertion only if 3.5 jack is in */58	if (gpiod_get_value_cansleep(machine->gpiod_hp_det) &&59	    gpiod_get_value_cansleep(machine->gpiod_mic_det))60		return SND_JACK_MICROPHONE;61 62	return 0;63}64 65static struct snd_soc_jack tegra_machine_mic_jack;66 67static struct snd_soc_jack_pin tegra_machine_mic_jack_pins[] = {68	{ .pin = "Mic Jack",    .mask = SND_JACK_MICROPHONE },69	{ .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE },70};71 72static struct snd_soc_jack_gpio tegra_machine_mic_jack_gpio = {73	.name = "Mic detection",74	.report = SND_JACK_MICROPHONE,75	.debounce_time = 150,76};77 78static int tegra_machine_event(struct snd_soc_dapm_widget *w,79			       struct snd_kcontrol *k, int event)80{81	struct snd_soc_dapm_context *dapm = w->dapm;82	struct tegra_machine *machine = snd_soc_card_get_drvdata(dapm->card);83 84	if (!snd_soc_dapm_widget_name_cmp(w, "Int Spk") ||85	    !snd_soc_dapm_widget_name_cmp(w, "Speakers"))86		gpiod_set_value_cansleep(machine->gpiod_spkr_en,87					 SND_SOC_DAPM_EVENT_ON(event));88 89	if (!snd_soc_dapm_widget_name_cmp(w, "Mic Jack") ||90	    !snd_soc_dapm_widget_name_cmp(w, "Headset Mic"))91		gpiod_set_value_cansleep(machine->gpiod_ext_mic_en,92					 SND_SOC_DAPM_EVENT_ON(event));93 94	if (!snd_soc_dapm_widget_name_cmp(w, "Int Mic") ||95	    !snd_soc_dapm_widget_name_cmp(w, "Internal Mic 2"))96		gpiod_set_value_cansleep(machine->gpiod_int_mic_en,97					 SND_SOC_DAPM_EVENT_ON(event));98 99	if (!snd_soc_dapm_widget_name_cmp(w, "Headphone") ||100	    !snd_soc_dapm_widget_name_cmp(w, "Headphone Jack"))101		gpiod_set_value_cansleep(machine->gpiod_hp_mute,102					 !SND_SOC_DAPM_EVENT_ON(event));103 104	return 0;105}106 107static const struct snd_soc_dapm_widget tegra_machine_dapm_widgets[] = {108	SND_SOC_DAPM_HP("Headphone Jack", tegra_machine_event),109	SND_SOC_DAPM_HP("Headphone", tegra_machine_event),110	SND_SOC_DAPM_HP("Headset Stereophone", NULL),111	SND_SOC_DAPM_HP("Headphones", NULL),112	SND_SOC_DAPM_SPK("Speakers", tegra_machine_event),113	SND_SOC_DAPM_SPK("Int Spk", tegra_machine_event),114	SND_SOC_DAPM_SPK("Earpiece", NULL),115	SND_SOC_DAPM_MIC("Int Mic", tegra_machine_event),116	SND_SOC_DAPM_MIC("Mic Jack", tegra_machine_event),117	SND_SOC_DAPM_MIC("Internal Mic 1", NULL),118	SND_SOC_DAPM_MIC("Internal Mic 2", tegra_machine_event),119	SND_SOC_DAPM_MIC("Headset Mic", tegra_machine_event),120	SND_SOC_DAPM_MIC("Digital Mic", NULL),121	SND_SOC_DAPM_MIC("Mic", NULL),122	SND_SOC_DAPM_LINE("Line In Jack", NULL),123	SND_SOC_DAPM_LINE("Line In", NULL),124	SND_SOC_DAPM_LINE("LineIn", NULL),125};126 127static const struct snd_kcontrol_new tegra_machine_controls[] = {128	SOC_DAPM_PIN_SWITCH("Speakers"),129	SOC_DAPM_PIN_SWITCH("Int Spk"),130	SOC_DAPM_PIN_SWITCH("Earpiece"),131	SOC_DAPM_PIN_SWITCH("Int Mic"),132	SOC_DAPM_PIN_SWITCH("Headset Mic"),133	SOC_DAPM_PIN_SWITCH("Internal Mic 1"),134	SOC_DAPM_PIN_SWITCH("Internal Mic 2"),135	SOC_DAPM_PIN_SWITCH("Headphones"),136	SOC_DAPM_PIN_SWITCH("Mic Jack"),137};138 139int tegra_asoc_machine_init(struct snd_soc_pcm_runtime *rtd)140{141	struct snd_soc_card *card = rtd->card;142	struct tegra_machine *machine = snd_soc_card_get_drvdata(card);143	const char *jack_name;144	int err;145 146	if (machine->gpiod_hp_det && machine->asoc->add_hp_jack) {147		if (machine->asoc->hp_jack_name)148			jack_name = machine->asoc->hp_jack_name;149		else150			jack_name = "Headphones Jack";151 152		err = snd_soc_card_jack_new_pins(card, jack_name,153						 SND_JACK_HEADPHONE,154						 &tegra_machine_hp_jack,155						 tegra_machine_hp_jack_pins,156						 ARRAY_SIZE(tegra_machine_hp_jack_pins));157		if (err) {158			dev_err(rtd->dev,159				"Headphones Jack creation failed: %d\n", err);160			return err;161		}162 163		tegra_machine_hp_jack_gpio.desc = machine->gpiod_hp_det;164 165		err = snd_soc_jack_add_gpios(&tegra_machine_hp_jack, 1,166					     &tegra_machine_hp_jack_gpio);167		if (err)168			dev_err(rtd->dev, "HP GPIOs not added: %d\n", err);169	}170 171	if (machine->gpiod_hp_det && machine->asoc->add_headset_jack) {172		err = snd_soc_card_jack_new_pins(card, "Headset Jack",173						 SND_JACK_HEADSET,174						 &tegra_machine_headset_jack,175						 tegra_machine_headset_jack_pins,176						 ARRAY_SIZE(tegra_machine_headset_jack_pins));177		if (err) {178			dev_err(rtd->dev,179				"Headset Jack creation failed: %d\n", err);180			return err;181		}182 183		tegra_machine_headset_jack_gpio.desc = machine->gpiod_hp_det;184 185		err = snd_soc_jack_add_gpios(&tegra_machine_headset_jack, 1,186					     &tegra_machine_headset_jack_gpio);187		if (err)188			dev_err(rtd->dev, "Headset GPIOs not added: %d\n", err);189	}190 191	if (machine->gpiod_mic_det && machine->asoc->add_mic_jack) {192		err = snd_soc_card_jack_new_pins(rtd->card, "Mic Jack",193						 SND_JACK_MICROPHONE,194						 &tegra_machine_mic_jack,195						 tegra_machine_mic_jack_pins,196						 ARRAY_SIZE(tegra_machine_mic_jack_pins));197		if (err) {198			dev_err(rtd->dev, "Mic Jack creation failed: %d\n", err);199			return err;200		}201 202		tegra_machine_mic_jack_gpio.data = machine;203		tegra_machine_mic_jack_gpio.desc = machine->gpiod_mic_det;204 205		if (of_property_read_bool(card->dev->of_node,206					  "nvidia,coupled-mic-hp-det")) {207			tegra_machine_mic_jack_gpio.desc = machine->gpiod_hp_det;208			tegra_machine_mic_jack_gpio.jack_status_check = coupled_mic_hp_check;209		}210 211		err = snd_soc_jack_add_gpios(&tegra_machine_mic_jack, 1,212					     &tegra_machine_mic_jack_gpio);213		if (err)214			dev_err(rtd->dev, "Mic GPIOs not added: %d\n", err);215	}216 217	return 0;218}219EXPORT_SYMBOL_GPL(tegra_asoc_machine_init);220 221static unsigned int tegra_machine_mclk_rate_128(unsigned int srate)222{223	return 128 * srate;224}225 226static unsigned int tegra_machine_mclk_rate_256(unsigned int srate)227{228	return 256 * srate;229}230 231static unsigned int tegra_machine_mclk_rate_512(unsigned int srate)232{233	return 512 * srate;234}235 236static unsigned int tegra_machine_mclk_rate_12mhz(unsigned int srate)237{238	unsigned int mclk;239 240	switch (srate) {241	case 8000:242	case 16000:243	case 24000:244	case 32000:245	case 48000:246	case 64000:247	case 96000:248		mclk = 12288000;249		break;250	case 11025:251	case 22050:252	case 44100:253	case 88200:254		mclk = 11289600;255		break;256	default:257		mclk = 12000000;258		break;259	}260 261	return mclk;262}263 264static unsigned int tegra_machine_mclk_rate_6mhz(unsigned int srate)265{266	unsigned int mclk;267 268	switch (srate) {269	case 8000:270	case 16000:271	case 64000:272		mclk = 8192000;273		break;274	case 11025:275	case 22050:276	case 88200:277		mclk = 11289600;278		break;279	case 96000:280		mclk = 12288000;281		break;282	default:283		mclk = 256 * srate;284		break;285	}286 287	return mclk;288}289 290static int tegra_machine_hw_params(struct snd_pcm_substream *substream,291				   struct snd_pcm_hw_params *params)292{293	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);294	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);295	struct snd_soc_card *card = rtd->card;296	struct tegra_machine *machine = snd_soc_card_get_drvdata(card);297	unsigned int srate = params_rate(params);298	unsigned int mclk = machine->asoc->mclk_rate(srate);299	unsigned int clk_id = machine->asoc->mclk_id;300	unsigned int new_baseclock;301	int err;302 303	switch (srate) {304	case 11025:305	case 22050:306	case 44100:307	case 88200:308		if (of_machine_is_compatible("nvidia,tegra20"))309			new_baseclock = 56448000;310		else if (of_machine_is_compatible("nvidia,tegra30"))311			new_baseclock = 564480000;312		else313			new_baseclock = 282240000;314		break;315	case 8000:316	case 16000:317	case 32000:318	case 48000:319	case 64000:320	case 96000:321		if (of_machine_is_compatible("nvidia,tegra20"))322			new_baseclock = 73728000;323		else if (of_machine_is_compatible("nvidia,tegra30"))324			new_baseclock = 552960000;325		else326			new_baseclock = 368640000;327		break;328	default:329		dev_err(card->dev, "Invalid sound rate: %u\n", srate);330		return -EINVAL;331	}332 333	if (new_baseclock != machine->set_baseclock ||334	    mclk != machine->set_mclk) {335		machine->set_baseclock = 0;336		machine->set_mclk = 0;337 338		clk_disable_unprepare(machine->clk_cdev1);339 340		err = clk_set_rate(machine->clk_pll_a, new_baseclock);341		if (err) {342			dev_err(card->dev, "Can't set pll_a rate: %d\n", err);343			return err;344		}345 346		err = clk_set_rate(machine->clk_pll_a_out0, mclk);347		if (err) {348			dev_err(card->dev, "Can't set pll_a_out0 rate: %d\n", err);349			return err;350		}351 352		/* Don't set cdev1/extern1 rate; it's locked to pll_a_out0 */353 354		err = clk_prepare_enable(machine->clk_cdev1);355		if (err) {356			dev_err(card->dev, "Can't enable cdev1: %d\n", err);357			return err;358		}359 360		machine->set_baseclock = new_baseclock;361		machine->set_mclk = mclk;362	}363 364	err = snd_soc_dai_set_sysclk(codec_dai, clk_id, mclk, SND_SOC_CLOCK_IN);365	if (err < 0) {366		dev_err(card->dev, "codec_dai clock not set: %d\n", err);367		return err;368	}369 370	return 0;371}372 373static const struct snd_soc_ops tegra_machine_snd_ops = {374	.hw_params = tegra_machine_hw_params,375};376 377static void tegra_machine_node_release(void *of_node)378{379	of_node_put(of_node);380}381 382static struct device_node *383tegra_machine_parse_phandle(struct device *dev, const char *name)384{385	struct device_node *np;386	int err;387 388	np = of_parse_phandle(dev->of_node, name, 0);389	if (!np) {390		dev_err(dev, "Property '%s' missing or invalid\n", name);391		return ERR_PTR(-EINVAL);392	}393 394	err = devm_add_action_or_reset(dev, tegra_machine_node_release, np);395	if (err)396		return ERR_PTR(err);397 398	return np;399}400 401static void tegra_machine_unregister_codec(void *pdev)402{403	platform_device_unregister(pdev);404}405 406static int tegra_machine_register_codec(struct device *dev, const char *name)407{408	struct platform_device *pdev;409	int err;410 411	if (!name)412		return 0;413 414	pdev = platform_device_register_simple(name, -1, NULL, 0);415	if (IS_ERR(pdev))416		return PTR_ERR(pdev);417 418	err = devm_add_action_or_reset(dev, tegra_machine_unregister_codec,419				       pdev);420	if (err)421		return err;422 423	return 0;424}425 426int tegra_asoc_machine_probe(struct platform_device *pdev)427{428	struct device_node *np_codec, *np_i2s, *np_ac97;429	const struct tegra_asoc_data *asoc;430	struct device *dev = &pdev->dev;431	struct tegra_machine *machine;432	struct snd_soc_card *card;433	struct gpio_desc *gpiod;434	int err;435 436	machine = devm_kzalloc(dev, sizeof(*machine), GFP_KERNEL);437	if (!machine)438		return -ENOMEM;439 440	asoc = of_device_get_match_data(dev);441	card = asoc->card;442	card->dev = dev;443 444	machine->asoc = asoc;445	machine->mic_jack = &tegra_machine_mic_jack;446	machine->hp_jack_gpio = &tegra_machine_hp_jack_gpio;447	snd_soc_card_set_drvdata(card, machine);448 449	gpiod = devm_gpiod_get_optional(dev, "nvidia,hp-mute", GPIOD_OUT_HIGH);450	machine->gpiod_hp_mute = gpiod;451	if (IS_ERR(gpiod))452		return PTR_ERR(gpiod);453 454	gpiod = devm_gpiod_get_optional(dev, "nvidia,hp-det", GPIOD_IN);455	machine->gpiod_hp_det = gpiod;456	if (IS_ERR(gpiod))457		return PTR_ERR(gpiod);458 459	gpiod = devm_gpiod_get_optional(dev, "nvidia,mic-det", GPIOD_IN);460	machine->gpiod_mic_det = gpiod;461	if (IS_ERR(gpiod))462		return PTR_ERR(gpiod);463 464	gpiod = devm_gpiod_get_optional(dev, "nvidia,spkr-en", GPIOD_OUT_LOW);465	machine->gpiod_spkr_en = gpiod;466	if (IS_ERR(gpiod))467		return PTR_ERR(gpiod);468 469	gpiod = devm_gpiod_get_optional(dev, "nvidia,int-mic-en", GPIOD_OUT_LOW);470	machine->gpiod_int_mic_en = gpiod;471	if (IS_ERR(gpiod))472		return PTR_ERR(gpiod);473 474	gpiod = devm_gpiod_get_optional(dev, "nvidia,ext-mic-en", GPIOD_OUT_LOW);475	machine->gpiod_ext_mic_en = gpiod;476	if (IS_ERR(gpiod))477		return PTR_ERR(gpiod);478 479	err = snd_soc_of_parse_card_name(card, "nvidia,model");480	if (err)481		return err;482 483	if (!card->dapm_routes) {484		err = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");485		if (err)486			return err;487	}488 489	if (asoc->set_ac97) {490		err = tegra_machine_register_codec(dev, asoc->codec_dev_name);491		if (err)492			return err;493 494		np_ac97 = tegra_machine_parse_phandle(dev, "nvidia,ac97-controller");495		if (IS_ERR(np_ac97))496			return PTR_ERR(np_ac97);497 498		card->dai_link->cpus->of_node = np_ac97;499		card->dai_link->platforms->of_node = np_ac97;500	} else {501		np_codec = tegra_machine_parse_phandle(dev, "nvidia,audio-codec");502		if (IS_ERR(np_codec))503			return PTR_ERR(np_codec);504 505		np_i2s = tegra_machine_parse_phandle(dev, "nvidia,i2s-controller");506		if (IS_ERR(np_i2s))507			return PTR_ERR(np_i2s);508 509		card->dai_link->cpus->of_node = np_i2s;510		card->dai_link->codecs->of_node = np_codec;511		card->dai_link->platforms->of_node = np_i2s;512	}513 514	if (asoc->add_common_controls) {515		card->controls = tegra_machine_controls;516		card->num_controls = ARRAY_SIZE(tegra_machine_controls);517	}518 519	if (asoc->add_common_dapm_widgets) {520		card->dapm_widgets = tegra_machine_dapm_widgets;521		card->num_dapm_widgets = ARRAY_SIZE(tegra_machine_dapm_widgets);522	}523 524	if (asoc->add_common_snd_ops)525		card->dai_link->ops = &tegra_machine_snd_ops;526 527	if (!card->owner)528		card->owner = THIS_MODULE;529	if (!card->driver_name)530		card->driver_name = "tegra";531 532	machine->clk_pll_a = devm_clk_get(dev, "pll_a");533	if (IS_ERR(machine->clk_pll_a)) {534		dev_err(dev, "Can't retrieve clk pll_a\n");535		return PTR_ERR(machine->clk_pll_a);536	}537 538	machine->clk_pll_a_out0 = devm_clk_get(dev, "pll_a_out0");539	if (IS_ERR(machine->clk_pll_a_out0)) {540		dev_err(dev, "Can't retrieve clk pll_a_out0\n");541		return PTR_ERR(machine->clk_pll_a_out0);542	}543 544	machine->clk_cdev1 = devm_clk_get(dev, "mclk");545	if (IS_ERR(machine->clk_cdev1)) {546		dev_err(dev, "Can't retrieve clk cdev1\n");547		return PTR_ERR(machine->clk_cdev1);548	}549 550	/*551	 * If clock parents are not set in DT, configure here to use clk_out_1552	 * as mclk and extern1 as parent for Tegra30 and higher.553	 */554	if (!of_property_present(dev->of_node, "assigned-clock-parents") &&555	    !of_machine_is_compatible("nvidia,tegra20")) {556		struct clk *clk_out_1, *clk_extern1;557 558		dev_warn(dev, "Configuring clocks for a legacy device-tree\n");559		dev_warn(dev, "Please update DT to use assigned-clock-parents\n");560 561		clk_extern1 = devm_clk_get(dev, "extern1");562		if (IS_ERR(clk_extern1)) {563			dev_err(dev, "Can't retrieve clk extern1\n");564			return PTR_ERR(clk_extern1);565		}566 567		err = clk_set_parent(clk_extern1, machine->clk_pll_a_out0);568		if (err < 0) {569			dev_err(dev, "Set parent failed for clk extern1\n");570			return err;571		}572 573		clk_out_1 = devm_clk_get(dev, "pmc_clk_out_1");574		if (IS_ERR(clk_out_1)) {575			dev_err(dev, "Can't retrieve pmc_clk_out_1\n");576			return PTR_ERR(clk_out_1);577		}578 579		err = clk_set_parent(clk_out_1, clk_extern1);580		if (err < 0) {581			dev_err(dev, "Set parent failed for pmc_clk_out_1\n");582			return err;583		}584 585		machine->clk_cdev1 = clk_out_1;586	}587 588	if (asoc->set_ac97) {589		/*590		 * AC97 rate is fixed at 24.576MHz and is used for both the591		 * host controller and the external codec592		 */593		err = clk_set_rate(machine->clk_pll_a, 73728000);594		if (err) {595			dev_err(dev, "Can't set pll_a rate: %d\n", err);596			return err;597		}598 599		err = clk_set_rate(machine->clk_pll_a_out0, 24576000);600		if (err) {601			dev_err(dev, "Can't set pll_a_out0 rate: %d\n", err);602			return err;603		}604 605		machine->set_baseclock = 73728000;606		machine->set_mclk = 24576000;607	}608 609	/*610	 * FIXME: There is some unknown dependency between audio MCLK disable611	 * and suspend-resume functionality on Tegra30, although audio MCLK is612	 * only needed for audio.613	 */614	err = clk_prepare_enable(machine->clk_cdev1);615	if (err) {616		dev_err(dev, "Can't enable cdev1: %d\n", err);617		return err;618	}619 620	err = devm_snd_soc_register_card(dev, card);621	if (err)622		return err;623 624	return 0;625}626EXPORT_SYMBOL_GPL(tegra_asoc_machine_probe);627 628/* WM8753 machine */629 630SND_SOC_DAILINK_DEFS(wm8753_hifi,631	DAILINK_COMP_ARRAY(COMP_EMPTY()),632	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8753-hifi")),633	DAILINK_COMP_ARRAY(COMP_EMPTY()));634 635static struct snd_soc_dai_link tegra_wm8753_dai = {636	.name = "WM8753",637	.stream_name = "WM8753 PCM",638	.dai_fmt = SND_SOC_DAIFMT_I2S |639		   SND_SOC_DAIFMT_NB_NF |640		   SND_SOC_DAIFMT_CBS_CFS,641	SND_SOC_DAILINK_REG(wm8753_hifi),642};643 644static struct snd_soc_card snd_soc_tegra_wm8753 = {645	.components = "codec:wm8753",646	.dai_link = &tegra_wm8753_dai,647	.num_links = 1,648	.fully_routed = true,649};650 651static const struct tegra_asoc_data tegra_wm8753_data = {652	.mclk_rate = tegra_machine_mclk_rate_12mhz,653	.card = &snd_soc_tegra_wm8753,654	.add_common_dapm_widgets = true,655	.add_common_snd_ops = true,656};657 658/* WM9712 machine */659 660static int tegra_wm9712_init(struct snd_soc_pcm_runtime *rtd)661{662	return snd_soc_dapm_force_enable_pin(&rtd->card->dapm, "Mic Bias");663}664 665SND_SOC_DAILINK_DEFS(wm9712_hifi,666	DAILINK_COMP_ARRAY(COMP_EMPTY()),667	DAILINK_COMP_ARRAY(COMP_CODEC("wm9712-codec", "wm9712-hifi")),668	DAILINK_COMP_ARRAY(COMP_EMPTY()));669 670static struct snd_soc_dai_link tegra_wm9712_dai = {671	.name = "AC97 HiFi",672	.stream_name = "AC97 HiFi",673	.init = tegra_wm9712_init,674	SND_SOC_DAILINK_REG(wm9712_hifi),675};676 677static struct snd_soc_card snd_soc_tegra_wm9712 = {678	.components = "codec:wm9712",679	.dai_link = &tegra_wm9712_dai,680	.num_links = 1,681	.fully_routed = true,682};683 684static const struct tegra_asoc_data tegra_wm9712_data = {685	.card = &snd_soc_tegra_wm9712,686	.add_common_dapm_widgets = true,687	.codec_dev_name = "wm9712-codec",688	.set_ac97 = true,689};690 691/* MAX98090 machine */692 693SND_SOC_DAILINK_DEFS(max98090_hifi,694	DAILINK_COMP_ARRAY(COMP_EMPTY()),695	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")),696	DAILINK_COMP_ARRAY(COMP_EMPTY()));697 698static struct snd_soc_dai_link tegra_max98090_dai = {699	.name = "max98090",700	.stream_name = "max98090 PCM",701	.init = tegra_asoc_machine_init,702	.dai_fmt = SND_SOC_DAIFMT_I2S |703		   SND_SOC_DAIFMT_NB_NF |704		   SND_SOC_DAIFMT_CBS_CFS,705	SND_SOC_DAILINK_REG(max98090_hifi),706};707 708static struct snd_soc_card snd_soc_tegra_max98090 = {709	.components = "codec:max98090",710	.dai_link = &tegra_max98090_dai,711	.num_links = 1,712	.fully_routed = true,713};714 715static const struct tegra_asoc_data tegra_max98090_data = {716	.mclk_rate = tegra_machine_mclk_rate_12mhz,717	.card = &snd_soc_tegra_max98090,718	.hp_jack_name = "Headphones",719	.add_common_dapm_widgets = true,720	.add_common_controls = true,721	.add_common_snd_ops = true,722	.add_mic_jack = true,723	.add_hp_jack = true,724};725 726/* MAX98088 machine */727 728SND_SOC_DAILINK_DEFS(max98088_hifi,729	DAILINK_COMP_ARRAY(COMP_EMPTY()),730	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")),731	DAILINK_COMP_ARRAY(COMP_EMPTY()));732 733static struct snd_soc_dai_link tegra_max98088_dai = {734	.name = "MAX98088",735	.stream_name = "MAX98088 PCM",736	.init = tegra_asoc_machine_init,737	.dai_fmt = SND_SOC_DAIFMT_I2S |738		   SND_SOC_DAIFMT_NB_NF |739		   SND_SOC_DAIFMT_CBS_CFS,740	SND_SOC_DAILINK_REG(max98088_hifi),741};742 743static struct snd_soc_card snd_soc_tegra_max98088 = {744	.components = "codec:max98088",745	.dai_link = &tegra_max98088_dai,746	.num_links = 1,747	.fully_routed = true,748};749 750static const struct tegra_asoc_data tegra_max98088_data = {751	.mclk_rate = tegra_machine_mclk_rate_12mhz,752	.card = &snd_soc_tegra_max98088,753	.add_common_dapm_widgets = true,754	.add_common_controls = true,755	.add_common_snd_ops = true,756	.add_mic_jack = true,757	.add_hp_jack = true,758};759 760/* SGTL5000 machine */761 762SND_SOC_DAILINK_DEFS(sgtl5000_hifi,763	DAILINK_COMP_ARRAY(COMP_EMPTY()),764	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "sgtl5000")),765	DAILINK_COMP_ARRAY(COMP_EMPTY()));766 767static struct snd_soc_dai_link tegra_sgtl5000_dai = {768	.name = "sgtl5000",769	.stream_name = "HiFi",770	.dai_fmt = SND_SOC_DAIFMT_I2S |771		   SND_SOC_DAIFMT_NB_NF |772		   SND_SOC_DAIFMT_CBS_CFS,773	SND_SOC_DAILINK_REG(sgtl5000_hifi),774};775 776static struct snd_soc_card snd_soc_tegra_sgtl5000 = {777	.components = "codec:sgtl5000",778	.dai_link = &tegra_sgtl5000_dai,779	.num_links = 1,780	.fully_routed = true,781};782 783static const struct tegra_asoc_data tegra_sgtl5000_data = {784	.mclk_rate = tegra_machine_mclk_rate_12mhz,785	.card = &snd_soc_tegra_sgtl5000,786	.add_common_dapm_widgets = true,787	.add_common_snd_ops = true,788};789 790/* TLV320AIC23 machine */791 792static const struct snd_soc_dapm_widget trimslice_dapm_widgets[] = {793	SND_SOC_DAPM_HP("Line Out", NULL),794	SND_SOC_DAPM_LINE("Line In", NULL),795};796 797static const struct snd_soc_dapm_route trimslice_audio_map[] = {798	{"Line Out", NULL, "LOUT"},799	{"Line Out", NULL, "ROUT"},800 801	{"LLINEIN", NULL, "Line In"},802	{"RLINEIN", NULL, "Line In"},803};804 805SND_SOC_DAILINK_DEFS(tlv320aic23_hifi,806	DAILINK_COMP_ARRAY(COMP_EMPTY()),807	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "tlv320aic23-hifi")),808	DAILINK_COMP_ARRAY(COMP_EMPTY()));809 810static struct snd_soc_dai_link tegra_tlv320aic23_dai = {811	.name = "TLV320AIC23",812	.stream_name = "AIC23",813	.dai_fmt = SND_SOC_DAIFMT_I2S |814		   SND_SOC_DAIFMT_NB_NF |815		   SND_SOC_DAIFMT_CBS_CFS,816	SND_SOC_DAILINK_REG(tlv320aic23_hifi),817};818 819static struct snd_soc_card snd_soc_tegra_trimslice = {820	.name = "tegra-trimslice",821	.components = "codec:tlv320aic23",822	.dai_link = &tegra_tlv320aic23_dai,823	.num_links = 1,824	.dapm_widgets = trimslice_dapm_widgets,825	.num_dapm_widgets = ARRAY_SIZE(trimslice_dapm_widgets),826	.dapm_routes = trimslice_audio_map,827	.num_dapm_routes = ARRAY_SIZE(trimslice_audio_map),828	.fully_routed = true,829};830 831static const struct tegra_asoc_data tegra_trimslice_data = {832	.mclk_rate = tegra_machine_mclk_rate_128,833	.card = &snd_soc_tegra_trimslice,834	.add_common_snd_ops = true,835};836 837/* RT5677 machine */838 839static int tegra_rt5677_init(struct snd_soc_pcm_runtime *rtd)840{841	struct snd_soc_card *card = rtd->card;842	int err;843 844	err = tegra_asoc_machine_init(rtd);845	if (err)846		return err;847 848	snd_soc_dapm_force_enable_pin(&card->dapm, "MICBIAS1");849 850	return 0;851}852 853SND_SOC_DAILINK_DEFS(rt5677_aif1,854	DAILINK_COMP_ARRAY(COMP_EMPTY()),855	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5677-aif1")),856	DAILINK_COMP_ARRAY(COMP_EMPTY()));857 858static struct snd_soc_dai_link tegra_rt5677_dai = {859	.name = "RT5677",860	.stream_name = "RT5677 PCM",861	.init = tegra_rt5677_init,862	.dai_fmt = SND_SOC_DAIFMT_I2S |863		   SND_SOC_DAIFMT_NB_NF |864		   SND_SOC_DAIFMT_CBS_CFS,865	SND_SOC_DAILINK_REG(rt5677_aif1),866};867 868static struct snd_soc_card snd_soc_tegra_rt5677 = {869	.components = "codec:rt5677",870	.dai_link = &tegra_rt5677_dai,871	.num_links = 1,872	.fully_routed = true,873};874 875static const struct tegra_asoc_data tegra_rt5677_data = {876	.mclk_rate = tegra_machine_mclk_rate_256,877	.card = &snd_soc_tegra_rt5677,878	.add_common_dapm_widgets = true,879	.add_common_controls = true,880	.add_common_snd_ops = true,881	.add_mic_jack = true,882	.add_hp_jack = true,883};884 885/* RT5640 machine */886 887SND_SOC_DAILINK_DEFS(rt5640_aif1,888	DAILINK_COMP_ARRAY(COMP_EMPTY()),889	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5640-aif1")),890	DAILINK_COMP_ARRAY(COMP_EMPTY()));891 892static struct snd_soc_dai_link tegra_rt5640_dai = {893	.name = "RT5640",894	.stream_name = "RT5640 PCM",895	.init = tegra_asoc_machine_init,896	.dai_fmt = SND_SOC_DAIFMT_I2S |897		   SND_SOC_DAIFMT_NB_NF |898		   SND_SOC_DAIFMT_CBS_CFS,899	SND_SOC_DAILINK_REG(rt5640_aif1),900};901 902static struct snd_soc_card snd_soc_tegra_rt5640 = {903	.components = "codec:rt5640",904	.dai_link = &tegra_rt5640_dai,905	.num_links = 1,906	.fully_routed = true,907};908 909static const struct tegra_asoc_data tegra_rt5640_data = {910	.mclk_rate = tegra_machine_mclk_rate_256,911	.card = &snd_soc_tegra_rt5640,912	.add_common_dapm_widgets = true,913	.add_common_controls = true,914	.add_common_snd_ops = true,915	.add_hp_jack = true,916};917 918/* RT5632 machine */919 920SND_SOC_DAILINK_DEFS(rt5632_hifi,921	DAILINK_COMP_ARRAY(COMP_EMPTY()),922	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "alc5632-hifi")),923	DAILINK_COMP_ARRAY(COMP_EMPTY()));924 925static struct snd_soc_dai_link tegra_rt5632_dai = {926	.name = "ALC5632",927	.stream_name = "ALC5632 PCM",928	.init = tegra_rt5677_init,929	.dai_fmt = SND_SOC_DAIFMT_I2S |930		   SND_SOC_DAIFMT_NB_NF |931		   SND_SOC_DAIFMT_CBS_CFS,932	SND_SOC_DAILINK_REG(rt5632_hifi),933};934 935static struct snd_soc_card snd_soc_tegra_rt5632 = {936	.components = "codec:rt5632",937	.dai_link = &tegra_rt5632_dai,938	.num_links = 1,939	.fully_routed = true,940};941 942static const struct tegra_asoc_data tegra_rt5632_data = {943	.mclk_rate = tegra_machine_mclk_rate_512,944	.card = &snd_soc_tegra_rt5632,945	.add_common_dapm_widgets = true,946	.add_common_controls = true,947	.add_common_snd_ops = true,948	.add_headset_jack = true,949};950 951/* RT5631 machine */952 953SND_SOC_DAILINK_DEFS(rt5631_hifi,954	DAILINK_COMP_ARRAY(COMP_EMPTY()),955	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5631-hifi")),956	DAILINK_COMP_ARRAY(COMP_EMPTY()));957 958static struct snd_soc_dai_link tegra_rt5631_dai = {959	.name = "RT5631",960	.stream_name = "RT5631 PCM",961	.init = tegra_asoc_machine_init,962	.dai_fmt = SND_SOC_DAIFMT_I2S |963		   SND_SOC_DAIFMT_NB_NF |964		   SND_SOC_DAIFMT_CBS_CFS,965	SND_SOC_DAILINK_REG(rt5631_hifi),966};967 968static struct snd_soc_card snd_soc_tegra_rt5631 = {969	.components = "codec:rt5631",970	.dai_link = &tegra_rt5631_dai,971	.num_links = 1,972	.fully_routed = true,973};974 975static const struct tegra_asoc_data tegra_rt5631_data = {976	.mclk_rate = tegra_machine_mclk_rate_6mhz,977	.card = &snd_soc_tegra_rt5631,978	.add_common_dapm_widgets = true,979	.add_common_controls = true,980	.add_common_snd_ops = true,981	.add_mic_jack = true,982	.add_hp_jack = true,983};984 985static const struct of_device_id tegra_machine_of_match[] = {986	{ .compatible = "nvidia,tegra-audio-trimslice", .data = &tegra_trimslice_data },987	{ .compatible = "nvidia,tegra-audio-max98090", .data = &tegra_max98090_data },988	{ .compatible = "nvidia,tegra-audio-max98088", .data = &tegra_max98088_data },989	{ .compatible = "nvidia,tegra-audio-max98089", .data = &tegra_max98088_data },990	{ .compatible = "nvidia,tegra-audio-sgtl5000", .data = &tegra_sgtl5000_data },991	{ .compatible = "nvidia,tegra-audio-wm9712", .data = &tegra_wm9712_data },992	{ .compatible = "nvidia,tegra-audio-wm8753", .data = &tegra_wm8753_data },993	{ .compatible = "nvidia,tegra-audio-rt5677", .data = &tegra_rt5677_data },994	{ .compatible = "nvidia,tegra-audio-rt5640", .data = &tegra_rt5640_data },995	{ .compatible = "nvidia,tegra-audio-alc5632", .data = &tegra_rt5632_data },996	{ .compatible = "nvidia,tegra-audio-rt5631", .data = &tegra_rt5631_data },997	{},998};999MODULE_DEVICE_TABLE(of, tegra_machine_of_match);1000 1001static struct platform_driver tegra_asoc_machine_driver = {1002	.driver = {1003		.name = "tegra-audio",1004		.of_match_table = tegra_machine_of_match,1005		.pm = &snd_soc_pm_ops,1006	},1007	.probe = tegra_asoc_machine_probe,1008};1009module_platform_driver(tegra_asoc_machine_driver);1010 1011MODULE_AUTHOR("Anatol Pomozov <anatol@google.com>");1012MODULE_AUTHOR("Andrey Danin <danindrey@mail.ru>");1013MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>");1014MODULE_AUTHOR("Ion Agorria <ion@agorria.com>");1015MODULE_AUTHOR("Leon Romanovsky <leon@leon.nu>");1016MODULE_AUTHOR("Lucas Stach <dev@lynxeye.de>");1017MODULE_AUTHOR("Marc Dietrich <marvin24@gmx.de>");1018MODULE_AUTHOR("Marcel Ziswiler <marcel@ziswiler.com>");1019MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");1020MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");1021MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>");1022MODULE_DESCRIPTION("Tegra machine ASoC driver");1023MODULE_LICENSE("GPL");1024