1*cc8f70f5SDmitry Osipenko // SPDX-License-Identifier: GPL-2.0-only 2*cc8f70f5SDmitry Osipenko /* 3*cc8f70f5SDmitry Osipenko * tegra_asoc_machine.c - Universal ASoC machine driver for NVIDIA Tegra boards. 4*cc8f70f5SDmitry Osipenko */ 5*cc8f70f5SDmitry Osipenko 6*cc8f70f5SDmitry Osipenko #include <linux/export.h> 7*cc8f70f5SDmitry Osipenko #include <linux/gpio/consumer.h> 8*cc8f70f5SDmitry Osipenko #include <linux/module.h> 9*cc8f70f5SDmitry Osipenko #include <linux/of.h> 10*cc8f70f5SDmitry Osipenko #include <linux/of_device.h> 11*cc8f70f5SDmitry Osipenko #include <linux/platform_device.h> 12*cc8f70f5SDmitry Osipenko #include <linux/slab.h> 13*cc8f70f5SDmitry Osipenko 14*cc8f70f5SDmitry Osipenko #include <sound/core.h> 15*cc8f70f5SDmitry Osipenko #include <sound/jack.h> 16*cc8f70f5SDmitry Osipenko #include <sound/pcm.h> 17*cc8f70f5SDmitry Osipenko #include <sound/pcm_params.h> 18*cc8f70f5SDmitry Osipenko #include <sound/soc.h> 19*cc8f70f5SDmitry Osipenko 20*cc8f70f5SDmitry Osipenko #include "tegra_asoc_machine.h" 21*cc8f70f5SDmitry Osipenko 22*cc8f70f5SDmitry Osipenko /* Headphones Jack */ 23*cc8f70f5SDmitry Osipenko 24*cc8f70f5SDmitry Osipenko static struct snd_soc_jack tegra_machine_hp_jack; 25*cc8f70f5SDmitry Osipenko 26*cc8f70f5SDmitry Osipenko static struct snd_soc_jack_pin tegra_machine_hp_jack_pins[] = { 27*cc8f70f5SDmitry Osipenko { .pin = "Headphone", .mask = SND_JACK_HEADPHONE }, 28*cc8f70f5SDmitry Osipenko { .pin = "Headphones", .mask = SND_JACK_HEADPHONE }, 29*cc8f70f5SDmitry Osipenko }; 30*cc8f70f5SDmitry Osipenko 31*cc8f70f5SDmitry Osipenko static struct snd_soc_jack_gpio tegra_machine_hp_jack_gpio = { 32*cc8f70f5SDmitry Osipenko .name = "Headphones detection", 33*cc8f70f5SDmitry Osipenko .report = SND_JACK_HEADPHONE, 34*cc8f70f5SDmitry Osipenko .debounce_time = 150, 35*cc8f70f5SDmitry Osipenko }; 36*cc8f70f5SDmitry Osipenko 37*cc8f70f5SDmitry Osipenko /* Headset Jack */ 38*cc8f70f5SDmitry Osipenko 39*cc8f70f5SDmitry Osipenko static struct snd_soc_jack tegra_machine_headset_jack; 40*cc8f70f5SDmitry Osipenko 41*cc8f70f5SDmitry Osipenko static struct snd_soc_jack_pin tegra_machine_headset_jack_pins[] = { 42*cc8f70f5SDmitry Osipenko { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE }, 43*cc8f70f5SDmitry Osipenko { .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE }, 44*cc8f70f5SDmitry Osipenko }; 45*cc8f70f5SDmitry Osipenko 46*cc8f70f5SDmitry Osipenko static struct snd_soc_jack_gpio tegra_machine_headset_jack_gpio = { 47*cc8f70f5SDmitry Osipenko .name = "Headset detection", 48*cc8f70f5SDmitry Osipenko .report = SND_JACK_HEADSET, 49*cc8f70f5SDmitry Osipenko .debounce_time = 150, 50*cc8f70f5SDmitry Osipenko }; 51*cc8f70f5SDmitry Osipenko 52*cc8f70f5SDmitry Osipenko /* Mic Jack */ 53*cc8f70f5SDmitry Osipenko 54*cc8f70f5SDmitry Osipenko static struct snd_soc_jack tegra_machine_mic_jack; 55*cc8f70f5SDmitry Osipenko 56*cc8f70f5SDmitry Osipenko static struct snd_soc_jack_pin tegra_machine_mic_jack_pins[] = { 57*cc8f70f5SDmitry Osipenko { .pin = "Mic Jack", .mask = SND_JACK_MICROPHONE }, 58*cc8f70f5SDmitry Osipenko { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE }, 59*cc8f70f5SDmitry Osipenko }; 60*cc8f70f5SDmitry Osipenko 61*cc8f70f5SDmitry Osipenko static struct snd_soc_jack_gpio tegra_machine_mic_jack_gpio = { 62*cc8f70f5SDmitry Osipenko .name = "Mic detection", 63*cc8f70f5SDmitry Osipenko .report = SND_JACK_MICROPHONE, 64*cc8f70f5SDmitry Osipenko .debounce_time = 150, 65*cc8f70f5SDmitry Osipenko }; 66*cc8f70f5SDmitry Osipenko 67*cc8f70f5SDmitry Osipenko static int tegra_machine_event(struct snd_soc_dapm_widget *w, 68*cc8f70f5SDmitry Osipenko struct snd_kcontrol *k, int event) 69*cc8f70f5SDmitry Osipenko { 70*cc8f70f5SDmitry Osipenko struct snd_soc_dapm_context *dapm = w->dapm; 71*cc8f70f5SDmitry Osipenko struct tegra_machine *machine = snd_soc_card_get_drvdata(dapm->card); 72*cc8f70f5SDmitry Osipenko 73*cc8f70f5SDmitry Osipenko if (!strcmp(w->name, "Int Spk") || !strcmp(w->name, "Speakers")) 74*cc8f70f5SDmitry Osipenko gpiod_set_value_cansleep(machine->gpiod_spkr_en, 75*cc8f70f5SDmitry Osipenko SND_SOC_DAPM_EVENT_ON(event)); 76*cc8f70f5SDmitry Osipenko 77*cc8f70f5SDmitry Osipenko if (!strcmp(w->name, "Mic Jack")) 78*cc8f70f5SDmitry Osipenko gpiod_set_value_cansleep(machine->gpiod_ext_mic_en, 79*cc8f70f5SDmitry Osipenko SND_SOC_DAPM_EVENT_ON(event)); 80*cc8f70f5SDmitry Osipenko 81*cc8f70f5SDmitry Osipenko if (!strcmp(w->name, "Int Mic")) 82*cc8f70f5SDmitry Osipenko gpiod_set_value_cansleep(machine->gpiod_int_mic_en, 83*cc8f70f5SDmitry Osipenko SND_SOC_DAPM_EVENT_ON(event)); 84*cc8f70f5SDmitry Osipenko 85*cc8f70f5SDmitry Osipenko if (!strcmp(w->name, "Headphone") || !strcmp(w->name, "Headphone Jack")) 86*cc8f70f5SDmitry Osipenko gpiod_set_value_cansleep(machine->gpiod_hp_mute, 87*cc8f70f5SDmitry Osipenko !SND_SOC_DAPM_EVENT_ON(event)); 88*cc8f70f5SDmitry Osipenko 89*cc8f70f5SDmitry Osipenko return 0; 90*cc8f70f5SDmitry Osipenko } 91*cc8f70f5SDmitry Osipenko 92*cc8f70f5SDmitry Osipenko static const struct snd_soc_dapm_widget tegra_machine_dapm_widgets[] = { 93*cc8f70f5SDmitry Osipenko SND_SOC_DAPM_HP("Headphone Jack", tegra_machine_event), 94*cc8f70f5SDmitry Osipenko SND_SOC_DAPM_HP("Headphone", tegra_machine_event), 95*cc8f70f5SDmitry Osipenko SND_SOC_DAPM_HP("Headset Stereophone", NULL), 96*cc8f70f5SDmitry Osipenko SND_SOC_DAPM_HP("Headphones", NULL), 97*cc8f70f5SDmitry Osipenko SND_SOC_DAPM_SPK("Speakers", tegra_machine_event), 98*cc8f70f5SDmitry Osipenko SND_SOC_DAPM_SPK("Int Spk", tegra_machine_event), 99*cc8f70f5SDmitry Osipenko SND_SOC_DAPM_MIC("Int Mic", tegra_machine_event), 100*cc8f70f5SDmitry Osipenko SND_SOC_DAPM_MIC("Mic Jack", tegra_machine_event), 101*cc8f70f5SDmitry Osipenko SND_SOC_DAPM_MIC("Internal Mic 1", NULL), 102*cc8f70f5SDmitry Osipenko SND_SOC_DAPM_MIC("Internal Mic 2", NULL), 103*cc8f70f5SDmitry Osipenko SND_SOC_DAPM_MIC("Headset Mic", NULL), 104*cc8f70f5SDmitry Osipenko SND_SOC_DAPM_MIC("Digital Mic", NULL), 105*cc8f70f5SDmitry Osipenko SND_SOC_DAPM_MIC("Mic", NULL), 106*cc8f70f5SDmitry Osipenko SND_SOC_DAPM_LINE("Line In Jack", NULL), 107*cc8f70f5SDmitry Osipenko SND_SOC_DAPM_LINE("Line In", NULL), 108*cc8f70f5SDmitry Osipenko SND_SOC_DAPM_LINE("LineIn", NULL), 109*cc8f70f5SDmitry Osipenko }; 110*cc8f70f5SDmitry Osipenko 111*cc8f70f5SDmitry Osipenko static const struct snd_kcontrol_new tegra_machine_controls[] = { 112*cc8f70f5SDmitry Osipenko SOC_DAPM_PIN_SWITCH("Speakers"), 113*cc8f70f5SDmitry Osipenko SOC_DAPM_PIN_SWITCH("Int Spk"), 114*cc8f70f5SDmitry Osipenko SOC_DAPM_PIN_SWITCH("Int Mic"), 115*cc8f70f5SDmitry Osipenko SOC_DAPM_PIN_SWITCH("Headset Mic"), 116*cc8f70f5SDmitry Osipenko SOC_DAPM_PIN_SWITCH("Internal Mic 1"), 117*cc8f70f5SDmitry Osipenko SOC_DAPM_PIN_SWITCH("Internal Mic 2"), 118*cc8f70f5SDmitry Osipenko }; 119*cc8f70f5SDmitry Osipenko 120*cc8f70f5SDmitry Osipenko int tegra_asoc_machine_init(struct snd_soc_pcm_runtime *rtd) 121*cc8f70f5SDmitry Osipenko { 122*cc8f70f5SDmitry Osipenko struct snd_soc_card *card = rtd->card; 123*cc8f70f5SDmitry Osipenko struct tegra_machine *machine = snd_soc_card_get_drvdata(card); 124*cc8f70f5SDmitry Osipenko int err; 125*cc8f70f5SDmitry Osipenko 126*cc8f70f5SDmitry Osipenko if (machine->gpiod_hp_det && machine->asoc->add_hp_jack) { 127*cc8f70f5SDmitry Osipenko err = snd_soc_card_jack_new(card, "Headphones Jack", 128*cc8f70f5SDmitry Osipenko SND_JACK_HEADPHONE, 129*cc8f70f5SDmitry Osipenko &tegra_machine_hp_jack, 130*cc8f70f5SDmitry Osipenko tegra_machine_hp_jack_pins, 131*cc8f70f5SDmitry Osipenko ARRAY_SIZE(tegra_machine_hp_jack_pins)); 132*cc8f70f5SDmitry Osipenko if (err) { 133*cc8f70f5SDmitry Osipenko dev_err(rtd->dev, 134*cc8f70f5SDmitry Osipenko "Headphones Jack creation failed: %d\n", err); 135*cc8f70f5SDmitry Osipenko return err; 136*cc8f70f5SDmitry Osipenko } 137*cc8f70f5SDmitry Osipenko 138*cc8f70f5SDmitry Osipenko tegra_machine_hp_jack_gpio.desc = machine->gpiod_hp_det; 139*cc8f70f5SDmitry Osipenko 140*cc8f70f5SDmitry Osipenko err = snd_soc_jack_add_gpios(&tegra_machine_hp_jack, 1, 141*cc8f70f5SDmitry Osipenko &tegra_machine_hp_jack_gpio); 142*cc8f70f5SDmitry Osipenko if (err) 143*cc8f70f5SDmitry Osipenko dev_err(rtd->dev, "HP GPIOs not added: %d\n", err); 144*cc8f70f5SDmitry Osipenko } 145*cc8f70f5SDmitry Osipenko 146*cc8f70f5SDmitry Osipenko if (machine->gpiod_hp_det && machine->asoc->add_headset_jack) { 147*cc8f70f5SDmitry Osipenko err = snd_soc_card_jack_new(card, "Headset Jack", 148*cc8f70f5SDmitry Osipenko SND_JACK_HEADSET, 149*cc8f70f5SDmitry Osipenko &tegra_machine_headset_jack, 150*cc8f70f5SDmitry Osipenko tegra_machine_headset_jack_pins, 151*cc8f70f5SDmitry Osipenko ARRAY_SIZE(tegra_machine_headset_jack_pins)); 152*cc8f70f5SDmitry Osipenko if (err) { 153*cc8f70f5SDmitry Osipenko dev_err(rtd->dev, 154*cc8f70f5SDmitry Osipenko "Headset Jack creation failed: %d\n", err); 155*cc8f70f5SDmitry Osipenko return err; 156*cc8f70f5SDmitry Osipenko } 157*cc8f70f5SDmitry Osipenko 158*cc8f70f5SDmitry Osipenko tegra_machine_headset_jack_gpio.desc = machine->gpiod_hp_det; 159*cc8f70f5SDmitry Osipenko 160*cc8f70f5SDmitry Osipenko err = snd_soc_jack_add_gpios(&tegra_machine_headset_jack, 1, 161*cc8f70f5SDmitry Osipenko &tegra_machine_headset_jack_gpio); 162*cc8f70f5SDmitry Osipenko if (err) 163*cc8f70f5SDmitry Osipenko dev_err(rtd->dev, "Headset GPIOs not added: %d\n", err); 164*cc8f70f5SDmitry Osipenko } 165*cc8f70f5SDmitry Osipenko 166*cc8f70f5SDmitry Osipenko if (machine->gpiod_mic_det && machine->asoc->add_mic_jack) { 167*cc8f70f5SDmitry Osipenko err = snd_soc_card_jack_new(rtd->card, "Mic Jack", 168*cc8f70f5SDmitry Osipenko SND_JACK_MICROPHONE, 169*cc8f70f5SDmitry Osipenko &tegra_machine_mic_jack, 170*cc8f70f5SDmitry Osipenko tegra_machine_mic_jack_pins, 171*cc8f70f5SDmitry Osipenko ARRAY_SIZE(tegra_machine_mic_jack_pins)); 172*cc8f70f5SDmitry Osipenko if (err) { 173*cc8f70f5SDmitry Osipenko dev_err(rtd->dev, "Mic Jack creation failed: %d\n", err); 174*cc8f70f5SDmitry Osipenko return err; 175*cc8f70f5SDmitry Osipenko } 176*cc8f70f5SDmitry Osipenko 177*cc8f70f5SDmitry Osipenko tegra_machine_mic_jack_gpio.desc = machine->gpiod_mic_det; 178*cc8f70f5SDmitry Osipenko 179*cc8f70f5SDmitry Osipenko err = snd_soc_jack_add_gpios(&tegra_machine_mic_jack, 1, 180*cc8f70f5SDmitry Osipenko &tegra_machine_mic_jack_gpio); 181*cc8f70f5SDmitry Osipenko if (err) 182*cc8f70f5SDmitry Osipenko dev_err(rtd->dev, "Mic GPIOs not added: %d\n", err); 183*cc8f70f5SDmitry Osipenko } 184*cc8f70f5SDmitry Osipenko 185*cc8f70f5SDmitry Osipenko return 0; 186*cc8f70f5SDmitry Osipenko } 187*cc8f70f5SDmitry Osipenko EXPORT_SYMBOL_GPL(tegra_asoc_machine_init); 188*cc8f70f5SDmitry Osipenko 189*cc8f70f5SDmitry Osipenko static unsigned int tegra_machine_mclk_rate_128(unsigned int srate) 190*cc8f70f5SDmitry Osipenko { 191*cc8f70f5SDmitry Osipenko return 128 * srate; 192*cc8f70f5SDmitry Osipenko } 193*cc8f70f5SDmitry Osipenko 194*cc8f70f5SDmitry Osipenko static unsigned int tegra_machine_mclk_rate_256(unsigned int srate) 195*cc8f70f5SDmitry Osipenko { 196*cc8f70f5SDmitry Osipenko return 256 * srate; 197*cc8f70f5SDmitry Osipenko } 198*cc8f70f5SDmitry Osipenko 199*cc8f70f5SDmitry Osipenko static unsigned int tegra_machine_mclk_rate_512(unsigned int srate) 200*cc8f70f5SDmitry Osipenko { 201*cc8f70f5SDmitry Osipenko return 512 * srate; 202*cc8f70f5SDmitry Osipenko } 203*cc8f70f5SDmitry Osipenko 204*cc8f70f5SDmitry Osipenko static unsigned int tegra_machine_mclk_rate_12mhz(unsigned int srate) 205*cc8f70f5SDmitry Osipenko { 206*cc8f70f5SDmitry Osipenko unsigned int mclk; 207*cc8f70f5SDmitry Osipenko 208*cc8f70f5SDmitry Osipenko switch (srate) { 209*cc8f70f5SDmitry Osipenko case 8000: 210*cc8f70f5SDmitry Osipenko case 16000: 211*cc8f70f5SDmitry Osipenko case 24000: 212*cc8f70f5SDmitry Osipenko case 32000: 213*cc8f70f5SDmitry Osipenko case 48000: 214*cc8f70f5SDmitry Osipenko case 64000: 215*cc8f70f5SDmitry Osipenko case 96000: 216*cc8f70f5SDmitry Osipenko mclk = 12288000; 217*cc8f70f5SDmitry Osipenko break; 218*cc8f70f5SDmitry Osipenko case 11025: 219*cc8f70f5SDmitry Osipenko case 22050: 220*cc8f70f5SDmitry Osipenko case 44100: 221*cc8f70f5SDmitry Osipenko case 88200: 222*cc8f70f5SDmitry Osipenko mclk = 11289600; 223*cc8f70f5SDmitry Osipenko break; 224*cc8f70f5SDmitry Osipenko default: 225*cc8f70f5SDmitry Osipenko mclk = 12000000; 226*cc8f70f5SDmitry Osipenko break; 227*cc8f70f5SDmitry Osipenko } 228*cc8f70f5SDmitry Osipenko 229*cc8f70f5SDmitry Osipenko return mclk; 230*cc8f70f5SDmitry Osipenko } 231*cc8f70f5SDmitry Osipenko 232*cc8f70f5SDmitry Osipenko static int tegra_machine_hw_params(struct snd_pcm_substream *substream, 233*cc8f70f5SDmitry Osipenko struct snd_pcm_hw_params *params) 234*cc8f70f5SDmitry Osipenko { 235*cc8f70f5SDmitry Osipenko struct snd_soc_pcm_runtime *rtd = substream->private_data; 236*cc8f70f5SDmitry Osipenko struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 237*cc8f70f5SDmitry Osipenko struct snd_soc_card *card = rtd->card; 238*cc8f70f5SDmitry Osipenko struct tegra_machine *machine = snd_soc_card_get_drvdata(card); 239*cc8f70f5SDmitry Osipenko unsigned int srate = params_rate(params); 240*cc8f70f5SDmitry Osipenko unsigned int mclk = machine->asoc->mclk_rate(srate); 241*cc8f70f5SDmitry Osipenko unsigned int clk_id = machine->asoc->mclk_id; 242*cc8f70f5SDmitry Osipenko int err; 243*cc8f70f5SDmitry Osipenko 244*cc8f70f5SDmitry Osipenko err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); 245*cc8f70f5SDmitry Osipenko if (err < 0) { 246*cc8f70f5SDmitry Osipenko dev_err(card->dev, "Can't configure clocks: %d\n", err); 247*cc8f70f5SDmitry Osipenko return err; 248*cc8f70f5SDmitry Osipenko } 249*cc8f70f5SDmitry Osipenko 250*cc8f70f5SDmitry Osipenko err = snd_soc_dai_set_sysclk(codec_dai, clk_id, mclk, SND_SOC_CLOCK_IN); 251*cc8f70f5SDmitry Osipenko if (err < 0) { 252*cc8f70f5SDmitry Osipenko dev_err(card->dev, "codec_dai clock not set: %d\n", err); 253*cc8f70f5SDmitry Osipenko return err; 254*cc8f70f5SDmitry Osipenko } 255*cc8f70f5SDmitry Osipenko 256*cc8f70f5SDmitry Osipenko return 0; 257*cc8f70f5SDmitry Osipenko } 258*cc8f70f5SDmitry Osipenko 259*cc8f70f5SDmitry Osipenko static struct snd_soc_ops tegra_machine_snd_ops = { 260*cc8f70f5SDmitry Osipenko .hw_params = tegra_machine_hw_params, 261*cc8f70f5SDmitry Osipenko }; 262*cc8f70f5SDmitry Osipenko 263*cc8f70f5SDmitry Osipenko static void tegra_machine_node_release(void *of_node) 264*cc8f70f5SDmitry Osipenko { 265*cc8f70f5SDmitry Osipenko of_node_put(of_node); 266*cc8f70f5SDmitry Osipenko } 267*cc8f70f5SDmitry Osipenko 268*cc8f70f5SDmitry Osipenko static struct device_node * 269*cc8f70f5SDmitry Osipenko tegra_machine_parse_phandle(struct device *dev, const char *name) 270*cc8f70f5SDmitry Osipenko { 271*cc8f70f5SDmitry Osipenko struct device_node *np; 272*cc8f70f5SDmitry Osipenko int err; 273*cc8f70f5SDmitry Osipenko 274*cc8f70f5SDmitry Osipenko np = of_parse_phandle(dev->of_node, name, 0); 275*cc8f70f5SDmitry Osipenko if (!np) { 276*cc8f70f5SDmitry Osipenko dev_err(dev, "Property '%s' missing or invalid\n", name); 277*cc8f70f5SDmitry Osipenko return ERR_PTR(-EINVAL); 278*cc8f70f5SDmitry Osipenko } 279*cc8f70f5SDmitry Osipenko 280*cc8f70f5SDmitry Osipenko err = devm_add_action_or_reset(dev, tegra_machine_node_release, np); 281*cc8f70f5SDmitry Osipenko if (err) 282*cc8f70f5SDmitry Osipenko return ERR_PTR(err); 283*cc8f70f5SDmitry Osipenko 284*cc8f70f5SDmitry Osipenko return np; 285*cc8f70f5SDmitry Osipenko } 286*cc8f70f5SDmitry Osipenko 287*cc8f70f5SDmitry Osipenko int tegra_asoc_machine_probe(struct platform_device *pdev) 288*cc8f70f5SDmitry Osipenko { 289*cc8f70f5SDmitry Osipenko struct device_node *np_codec, *np_i2s; 290*cc8f70f5SDmitry Osipenko const struct tegra_asoc_data *asoc; 291*cc8f70f5SDmitry Osipenko struct device *dev = &pdev->dev; 292*cc8f70f5SDmitry Osipenko struct tegra_machine *machine; 293*cc8f70f5SDmitry Osipenko struct snd_soc_card *card; 294*cc8f70f5SDmitry Osipenko struct gpio_desc *gpiod; 295*cc8f70f5SDmitry Osipenko int err; 296*cc8f70f5SDmitry Osipenko 297*cc8f70f5SDmitry Osipenko machine = devm_kzalloc(dev, sizeof(*machine), GFP_KERNEL); 298*cc8f70f5SDmitry Osipenko if (!machine) 299*cc8f70f5SDmitry Osipenko return -ENOMEM; 300*cc8f70f5SDmitry Osipenko 301*cc8f70f5SDmitry Osipenko asoc = of_device_get_match_data(dev); 302*cc8f70f5SDmitry Osipenko card = asoc->card; 303*cc8f70f5SDmitry Osipenko card->dev = dev; 304*cc8f70f5SDmitry Osipenko 305*cc8f70f5SDmitry Osipenko machine->asoc = asoc; 306*cc8f70f5SDmitry Osipenko machine->mic_jack = &tegra_machine_mic_jack; 307*cc8f70f5SDmitry Osipenko machine->hp_jack_gpio = &tegra_machine_hp_jack_gpio; 308*cc8f70f5SDmitry Osipenko snd_soc_card_set_drvdata(card, machine); 309*cc8f70f5SDmitry Osipenko 310*cc8f70f5SDmitry Osipenko gpiod = devm_gpiod_get_optional(dev, "nvidia,hp-mute", GPIOD_OUT_HIGH); 311*cc8f70f5SDmitry Osipenko machine->gpiod_hp_mute = gpiod; 312*cc8f70f5SDmitry Osipenko if (IS_ERR(gpiod)) 313*cc8f70f5SDmitry Osipenko return PTR_ERR(gpiod); 314*cc8f70f5SDmitry Osipenko 315*cc8f70f5SDmitry Osipenko gpiod = devm_gpiod_get_optional(dev, "nvidia,hp-det", GPIOD_IN); 316*cc8f70f5SDmitry Osipenko machine->gpiod_hp_det = gpiod; 317*cc8f70f5SDmitry Osipenko if (IS_ERR(gpiod)) 318*cc8f70f5SDmitry Osipenko return PTR_ERR(gpiod); 319*cc8f70f5SDmitry Osipenko 320*cc8f70f5SDmitry Osipenko gpiod = devm_gpiod_get_optional(dev, "nvidia,mic-det", GPIOD_IN); 321*cc8f70f5SDmitry Osipenko machine->gpiod_mic_det = gpiod; 322*cc8f70f5SDmitry Osipenko if (IS_ERR(gpiod)) 323*cc8f70f5SDmitry Osipenko return PTR_ERR(gpiod); 324*cc8f70f5SDmitry Osipenko 325*cc8f70f5SDmitry Osipenko gpiod = devm_gpiod_get_optional(dev, "nvidia,spkr-en", GPIOD_OUT_LOW); 326*cc8f70f5SDmitry Osipenko machine->gpiod_spkr_en = gpiod; 327*cc8f70f5SDmitry Osipenko if (IS_ERR(gpiod)) 328*cc8f70f5SDmitry Osipenko return PTR_ERR(gpiod); 329*cc8f70f5SDmitry Osipenko 330*cc8f70f5SDmitry Osipenko gpiod = devm_gpiod_get_optional(dev, "nvidia,int-mic-en", GPIOD_OUT_LOW); 331*cc8f70f5SDmitry Osipenko machine->gpiod_int_mic_en = gpiod; 332*cc8f70f5SDmitry Osipenko if (IS_ERR(gpiod)) 333*cc8f70f5SDmitry Osipenko return PTR_ERR(gpiod); 334*cc8f70f5SDmitry Osipenko 335*cc8f70f5SDmitry Osipenko gpiod = devm_gpiod_get_optional(dev, "nvidia,ext-mic-en", GPIOD_OUT_LOW); 336*cc8f70f5SDmitry Osipenko machine->gpiod_ext_mic_en = gpiod; 337*cc8f70f5SDmitry Osipenko if (IS_ERR(gpiod)) 338*cc8f70f5SDmitry Osipenko return PTR_ERR(gpiod); 339*cc8f70f5SDmitry Osipenko 340*cc8f70f5SDmitry Osipenko err = snd_soc_of_parse_card_name(card, "nvidia,model"); 341*cc8f70f5SDmitry Osipenko if (err) 342*cc8f70f5SDmitry Osipenko return err; 343*cc8f70f5SDmitry Osipenko 344*cc8f70f5SDmitry Osipenko if (!card->dapm_routes) { 345*cc8f70f5SDmitry Osipenko err = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing"); 346*cc8f70f5SDmitry Osipenko if (err) 347*cc8f70f5SDmitry Osipenko return err; 348*cc8f70f5SDmitry Osipenko } 349*cc8f70f5SDmitry Osipenko 350*cc8f70f5SDmitry Osipenko np_codec = tegra_machine_parse_phandle(dev, "nvidia,audio-codec"); 351*cc8f70f5SDmitry Osipenko if (IS_ERR(np_codec)) 352*cc8f70f5SDmitry Osipenko return PTR_ERR(np_codec); 353*cc8f70f5SDmitry Osipenko 354*cc8f70f5SDmitry Osipenko np_i2s = tegra_machine_parse_phandle(dev, "nvidia,i2s-controller"); 355*cc8f70f5SDmitry Osipenko if (!np_i2s) 356*cc8f70f5SDmitry Osipenko return PTR_ERR(np_i2s); 357*cc8f70f5SDmitry Osipenko 358*cc8f70f5SDmitry Osipenko card->dai_link->cpus->of_node = np_i2s; 359*cc8f70f5SDmitry Osipenko card->dai_link->codecs->of_node = np_codec; 360*cc8f70f5SDmitry Osipenko card->dai_link->platforms->of_node = np_i2s; 361*cc8f70f5SDmitry Osipenko 362*cc8f70f5SDmitry Osipenko if (asoc->add_common_controls) { 363*cc8f70f5SDmitry Osipenko card->controls = tegra_machine_controls; 364*cc8f70f5SDmitry Osipenko card->num_controls = ARRAY_SIZE(tegra_machine_controls); 365*cc8f70f5SDmitry Osipenko } 366*cc8f70f5SDmitry Osipenko 367*cc8f70f5SDmitry Osipenko if (asoc->add_common_dapm_widgets) { 368*cc8f70f5SDmitry Osipenko card->dapm_widgets = tegra_machine_dapm_widgets; 369*cc8f70f5SDmitry Osipenko card->num_dapm_widgets = ARRAY_SIZE(tegra_machine_dapm_widgets); 370*cc8f70f5SDmitry Osipenko } 371*cc8f70f5SDmitry Osipenko 372*cc8f70f5SDmitry Osipenko if (asoc->add_common_snd_ops) 373*cc8f70f5SDmitry Osipenko card->dai_link->ops = &tegra_machine_snd_ops; 374*cc8f70f5SDmitry Osipenko 375*cc8f70f5SDmitry Osipenko if (!card->owner) 376*cc8f70f5SDmitry Osipenko card->owner = THIS_MODULE; 377*cc8f70f5SDmitry Osipenko if (!card->driver_name) 378*cc8f70f5SDmitry Osipenko card->driver_name = "tegra"; 379*cc8f70f5SDmitry Osipenko 380*cc8f70f5SDmitry Osipenko err = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); 381*cc8f70f5SDmitry Osipenko if (err) 382*cc8f70f5SDmitry Osipenko return err; 383*cc8f70f5SDmitry Osipenko 384*cc8f70f5SDmitry Osipenko if (asoc->set_ac97) { 385*cc8f70f5SDmitry Osipenko err = tegra_asoc_utils_set_ac97_rate(&machine->util_data); 386*cc8f70f5SDmitry Osipenko if (err) 387*cc8f70f5SDmitry Osipenko return err; 388*cc8f70f5SDmitry Osipenko } 389*cc8f70f5SDmitry Osipenko 390*cc8f70f5SDmitry Osipenko err = devm_snd_soc_register_card(dev, card); 391*cc8f70f5SDmitry Osipenko if (err) 392*cc8f70f5SDmitry Osipenko return err; 393*cc8f70f5SDmitry Osipenko 394*cc8f70f5SDmitry Osipenko return 0; 395*cc8f70f5SDmitry Osipenko } 396*cc8f70f5SDmitry Osipenko EXPORT_SYMBOL_GPL(tegra_asoc_machine_probe); 397*cc8f70f5SDmitry Osipenko 398*cc8f70f5SDmitry Osipenko /* WM8753 machine */ 399*cc8f70f5SDmitry Osipenko 400*cc8f70f5SDmitry Osipenko SND_SOC_DAILINK_DEFS(wm8753_hifi, 401*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_EMPTY()), 402*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8753-hifi")), 403*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_EMPTY())); 404*cc8f70f5SDmitry Osipenko 405*cc8f70f5SDmitry Osipenko static struct snd_soc_dai_link tegra_wm8753_dai = { 406*cc8f70f5SDmitry Osipenko .name = "WM8753", 407*cc8f70f5SDmitry Osipenko .stream_name = "WM8753 PCM", 408*cc8f70f5SDmitry Osipenko .dai_fmt = SND_SOC_DAIFMT_I2S | 409*cc8f70f5SDmitry Osipenko SND_SOC_DAIFMT_NB_NF | 410*cc8f70f5SDmitry Osipenko SND_SOC_DAIFMT_CBS_CFS, 411*cc8f70f5SDmitry Osipenko SND_SOC_DAILINK_REG(wm8753_hifi), 412*cc8f70f5SDmitry Osipenko }; 413*cc8f70f5SDmitry Osipenko 414*cc8f70f5SDmitry Osipenko static struct snd_soc_card snd_soc_tegra_wm8753 = { 415*cc8f70f5SDmitry Osipenko .dai_link = &tegra_wm8753_dai, 416*cc8f70f5SDmitry Osipenko .num_links = 1, 417*cc8f70f5SDmitry Osipenko .fully_routed = true, 418*cc8f70f5SDmitry Osipenko }; 419*cc8f70f5SDmitry Osipenko 420*cc8f70f5SDmitry Osipenko static const struct tegra_asoc_data tegra_wm8753_data = { 421*cc8f70f5SDmitry Osipenko .mclk_rate = tegra_machine_mclk_rate_12mhz, 422*cc8f70f5SDmitry Osipenko .card = &snd_soc_tegra_wm8753, 423*cc8f70f5SDmitry Osipenko .add_common_dapm_widgets = true, 424*cc8f70f5SDmitry Osipenko .add_common_snd_ops = true, 425*cc8f70f5SDmitry Osipenko }; 426*cc8f70f5SDmitry Osipenko 427*cc8f70f5SDmitry Osipenko /* WM9712 machine */ 428*cc8f70f5SDmitry Osipenko 429*cc8f70f5SDmitry Osipenko static int tegra_wm9712_init(struct snd_soc_pcm_runtime *rtd) 430*cc8f70f5SDmitry Osipenko { 431*cc8f70f5SDmitry Osipenko return snd_soc_dapm_force_enable_pin(&rtd->card->dapm, "Mic Bias"); 432*cc8f70f5SDmitry Osipenko } 433*cc8f70f5SDmitry Osipenko 434*cc8f70f5SDmitry Osipenko SND_SOC_DAILINK_DEFS(wm9712_hifi, 435*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_EMPTY()), 436*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_CODEC("wm9712-codec", "wm9712-hifi")), 437*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_EMPTY())); 438*cc8f70f5SDmitry Osipenko 439*cc8f70f5SDmitry Osipenko static struct snd_soc_dai_link tegra_wm9712_dai = { 440*cc8f70f5SDmitry Osipenko .name = "AC97 HiFi", 441*cc8f70f5SDmitry Osipenko .stream_name = "AC97 HiFi", 442*cc8f70f5SDmitry Osipenko .init = tegra_wm9712_init, 443*cc8f70f5SDmitry Osipenko SND_SOC_DAILINK_REG(wm9712_hifi), 444*cc8f70f5SDmitry Osipenko }; 445*cc8f70f5SDmitry Osipenko 446*cc8f70f5SDmitry Osipenko static struct snd_soc_card snd_soc_tegra_wm9712 = { 447*cc8f70f5SDmitry Osipenko .dai_link = &tegra_wm9712_dai, 448*cc8f70f5SDmitry Osipenko .num_links = 1, 449*cc8f70f5SDmitry Osipenko .fully_routed = true, 450*cc8f70f5SDmitry Osipenko }; 451*cc8f70f5SDmitry Osipenko 452*cc8f70f5SDmitry Osipenko static const struct tegra_asoc_data tegra_wm9712_data = { 453*cc8f70f5SDmitry Osipenko .card = &snd_soc_tegra_wm9712, 454*cc8f70f5SDmitry Osipenko .add_common_dapm_widgets = true, 455*cc8f70f5SDmitry Osipenko .set_ac97 = true, 456*cc8f70f5SDmitry Osipenko }; 457*cc8f70f5SDmitry Osipenko 458*cc8f70f5SDmitry Osipenko /* MAX98090 machine */ 459*cc8f70f5SDmitry Osipenko 460*cc8f70f5SDmitry Osipenko SND_SOC_DAILINK_DEFS(max98090_hifi, 461*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_EMPTY()), 462*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")), 463*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_EMPTY())); 464*cc8f70f5SDmitry Osipenko 465*cc8f70f5SDmitry Osipenko static struct snd_soc_dai_link tegra_max98090_dai = { 466*cc8f70f5SDmitry Osipenko .name = "max98090", 467*cc8f70f5SDmitry Osipenko .stream_name = "max98090 PCM", 468*cc8f70f5SDmitry Osipenko .init = tegra_asoc_machine_init, 469*cc8f70f5SDmitry Osipenko .dai_fmt = SND_SOC_DAIFMT_I2S | 470*cc8f70f5SDmitry Osipenko SND_SOC_DAIFMT_NB_NF | 471*cc8f70f5SDmitry Osipenko SND_SOC_DAIFMT_CBS_CFS, 472*cc8f70f5SDmitry Osipenko SND_SOC_DAILINK_REG(max98090_hifi), 473*cc8f70f5SDmitry Osipenko }; 474*cc8f70f5SDmitry Osipenko 475*cc8f70f5SDmitry Osipenko static struct snd_soc_card snd_soc_tegra_max98090 = { 476*cc8f70f5SDmitry Osipenko .components = "codec:max98090", 477*cc8f70f5SDmitry Osipenko .dai_link = &tegra_max98090_dai, 478*cc8f70f5SDmitry Osipenko .num_links = 1, 479*cc8f70f5SDmitry Osipenko .fully_routed = true, 480*cc8f70f5SDmitry Osipenko }; 481*cc8f70f5SDmitry Osipenko 482*cc8f70f5SDmitry Osipenko static const struct tegra_asoc_data tegra_max98090_data = { 483*cc8f70f5SDmitry Osipenko .mclk_rate = tegra_machine_mclk_rate_12mhz, 484*cc8f70f5SDmitry Osipenko .card = &snd_soc_tegra_max98090, 485*cc8f70f5SDmitry Osipenko .add_common_dapm_widgets = true, 486*cc8f70f5SDmitry Osipenko .add_common_controls = true, 487*cc8f70f5SDmitry Osipenko .add_common_snd_ops = true, 488*cc8f70f5SDmitry Osipenko .add_mic_jack = true, 489*cc8f70f5SDmitry Osipenko .add_hp_jack = true, 490*cc8f70f5SDmitry Osipenko }; 491*cc8f70f5SDmitry Osipenko 492*cc8f70f5SDmitry Osipenko /* SGTL5000 machine */ 493*cc8f70f5SDmitry Osipenko 494*cc8f70f5SDmitry Osipenko SND_SOC_DAILINK_DEFS(sgtl5000_hifi, 495*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_EMPTY()), 496*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "sgtl5000")), 497*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_EMPTY())); 498*cc8f70f5SDmitry Osipenko 499*cc8f70f5SDmitry Osipenko static struct snd_soc_dai_link tegra_sgtl5000_dai = { 500*cc8f70f5SDmitry Osipenko .name = "sgtl5000", 501*cc8f70f5SDmitry Osipenko .stream_name = "HiFi", 502*cc8f70f5SDmitry Osipenko .dai_fmt = SND_SOC_DAIFMT_I2S | 503*cc8f70f5SDmitry Osipenko SND_SOC_DAIFMT_NB_NF | 504*cc8f70f5SDmitry Osipenko SND_SOC_DAIFMT_CBS_CFS, 505*cc8f70f5SDmitry Osipenko SND_SOC_DAILINK_REG(sgtl5000_hifi), 506*cc8f70f5SDmitry Osipenko }; 507*cc8f70f5SDmitry Osipenko 508*cc8f70f5SDmitry Osipenko static struct snd_soc_card snd_soc_tegra_sgtl5000 = { 509*cc8f70f5SDmitry Osipenko .dai_link = &tegra_sgtl5000_dai, 510*cc8f70f5SDmitry Osipenko .num_links = 1, 511*cc8f70f5SDmitry Osipenko .fully_routed = true, 512*cc8f70f5SDmitry Osipenko }; 513*cc8f70f5SDmitry Osipenko 514*cc8f70f5SDmitry Osipenko static const struct tegra_asoc_data tegra_sgtl5000_data = { 515*cc8f70f5SDmitry Osipenko .mclk_rate = tegra_machine_mclk_rate_12mhz, 516*cc8f70f5SDmitry Osipenko .card = &snd_soc_tegra_sgtl5000, 517*cc8f70f5SDmitry Osipenko .add_common_dapm_widgets = true, 518*cc8f70f5SDmitry Osipenko .add_common_snd_ops = true, 519*cc8f70f5SDmitry Osipenko }; 520*cc8f70f5SDmitry Osipenko 521*cc8f70f5SDmitry Osipenko /* TLV320AIC23 machine */ 522*cc8f70f5SDmitry Osipenko 523*cc8f70f5SDmitry Osipenko static const struct snd_soc_dapm_widget trimslice_dapm_widgets[] = { 524*cc8f70f5SDmitry Osipenko SND_SOC_DAPM_HP("Line Out", NULL), 525*cc8f70f5SDmitry Osipenko SND_SOC_DAPM_LINE("Line In", NULL), 526*cc8f70f5SDmitry Osipenko }; 527*cc8f70f5SDmitry Osipenko 528*cc8f70f5SDmitry Osipenko static const struct snd_soc_dapm_route trimslice_audio_map[] = { 529*cc8f70f5SDmitry Osipenko {"Line Out", NULL, "LOUT"}, 530*cc8f70f5SDmitry Osipenko {"Line Out", NULL, "ROUT"}, 531*cc8f70f5SDmitry Osipenko 532*cc8f70f5SDmitry Osipenko {"LLINEIN", NULL, "Line In"}, 533*cc8f70f5SDmitry Osipenko {"RLINEIN", NULL, "Line In"}, 534*cc8f70f5SDmitry Osipenko }; 535*cc8f70f5SDmitry Osipenko 536*cc8f70f5SDmitry Osipenko SND_SOC_DAILINK_DEFS(tlv320aic23_hifi, 537*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_EMPTY()), 538*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "tlv320aic23-hifi")), 539*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_EMPTY())); 540*cc8f70f5SDmitry Osipenko 541*cc8f70f5SDmitry Osipenko static struct snd_soc_dai_link tegra_tlv320aic23_dai = { 542*cc8f70f5SDmitry Osipenko .name = "TLV320AIC23", 543*cc8f70f5SDmitry Osipenko .stream_name = "AIC23", 544*cc8f70f5SDmitry Osipenko .dai_fmt = SND_SOC_DAIFMT_I2S | 545*cc8f70f5SDmitry Osipenko SND_SOC_DAIFMT_NB_NF | 546*cc8f70f5SDmitry Osipenko SND_SOC_DAIFMT_CBS_CFS, 547*cc8f70f5SDmitry Osipenko SND_SOC_DAILINK_REG(tlv320aic23_hifi), 548*cc8f70f5SDmitry Osipenko }; 549*cc8f70f5SDmitry Osipenko 550*cc8f70f5SDmitry Osipenko static struct snd_soc_card snd_soc_tegra_trimslice = { 551*cc8f70f5SDmitry Osipenko .dai_link = &tegra_tlv320aic23_dai, 552*cc8f70f5SDmitry Osipenko .num_links = 1, 553*cc8f70f5SDmitry Osipenko .dapm_widgets = trimslice_dapm_widgets, 554*cc8f70f5SDmitry Osipenko .num_dapm_widgets = ARRAY_SIZE(trimslice_dapm_widgets), 555*cc8f70f5SDmitry Osipenko .dapm_routes = trimslice_audio_map, 556*cc8f70f5SDmitry Osipenko .num_dapm_routes = ARRAY_SIZE(trimslice_audio_map), 557*cc8f70f5SDmitry Osipenko .fully_routed = true, 558*cc8f70f5SDmitry Osipenko }; 559*cc8f70f5SDmitry Osipenko 560*cc8f70f5SDmitry Osipenko static const struct tegra_asoc_data tegra_trimslice_data = { 561*cc8f70f5SDmitry Osipenko .mclk_rate = tegra_machine_mclk_rate_128, 562*cc8f70f5SDmitry Osipenko .card = &snd_soc_tegra_trimslice, 563*cc8f70f5SDmitry Osipenko .add_common_snd_ops = true, 564*cc8f70f5SDmitry Osipenko }; 565*cc8f70f5SDmitry Osipenko 566*cc8f70f5SDmitry Osipenko /* RT5677 machine */ 567*cc8f70f5SDmitry Osipenko 568*cc8f70f5SDmitry Osipenko static int tegra_rt5677_init(struct snd_soc_pcm_runtime *rtd) 569*cc8f70f5SDmitry Osipenko { 570*cc8f70f5SDmitry Osipenko struct snd_soc_card *card = rtd->card; 571*cc8f70f5SDmitry Osipenko int err; 572*cc8f70f5SDmitry Osipenko 573*cc8f70f5SDmitry Osipenko err = tegra_asoc_machine_init(rtd); 574*cc8f70f5SDmitry Osipenko if (err) 575*cc8f70f5SDmitry Osipenko return err; 576*cc8f70f5SDmitry Osipenko 577*cc8f70f5SDmitry Osipenko snd_soc_dapm_force_enable_pin(&card->dapm, "MICBIAS1"); 578*cc8f70f5SDmitry Osipenko 579*cc8f70f5SDmitry Osipenko return 0; 580*cc8f70f5SDmitry Osipenko } 581*cc8f70f5SDmitry Osipenko 582*cc8f70f5SDmitry Osipenko SND_SOC_DAILINK_DEFS(rt5677_aif1, 583*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_EMPTY()), 584*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5677-aif1")), 585*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_EMPTY())); 586*cc8f70f5SDmitry Osipenko 587*cc8f70f5SDmitry Osipenko static struct snd_soc_dai_link tegra_rt5677_dai = { 588*cc8f70f5SDmitry Osipenko .name = "RT5677", 589*cc8f70f5SDmitry Osipenko .stream_name = "RT5677 PCM", 590*cc8f70f5SDmitry Osipenko .init = tegra_rt5677_init, 591*cc8f70f5SDmitry Osipenko .dai_fmt = SND_SOC_DAIFMT_I2S | 592*cc8f70f5SDmitry Osipenko SND_SOC_DAIFMT_NB_NF | 593*cc8f70f5SDmitry Osipenko SND_SOC_DAIFMT_CBS_CFS, 594*cc8f70f5SDmitry Osipenko SND_SOC_DAILINK_REG(rt5677_aif1), 595*cc8f70f5SDmitry Osipenko }; 596*cc8f70f5SDmitry Osipenko 597*cc8f70f5SDmitry Osipenko static struct snd_soc_card snd_soc_tegra_rt5677 = { 598*cc8f70f5SDmitry Osipenko .dai_link = &tegra_rt5677_dai, 599*cc8f70f5SDmitry Osipenko .num_links = 1, 600*cc8f70f5SDmitry Osipenko .fully_routed = true, 601*cc8f70f5SDmitry Osipenko }; 602*cc8f70f5SDmitry Osipenko 603*cc8f70f5SDmitry Osipenko static const struct tegra_asoc_data tegra_rt5677_data = { 604*cc8f70f5SDmitry Osipenko .mclk_rate = tegra_machine_mclk_rate_256, 605*cc8f70f5SDmitry Osipenko .card = &snd_soc_tegra_rt5677, 606*cc8f70f5SDmitry Osipenko .add_common_dapm_widgets = true, 607*cc8f70f5SDmitry Osipenko .add_common_controls = true, 608*cc8f70f5SDmitry Osipenko .add_common_snd_ops = true, 609*cc8f70f5SDmitry Osipenko .add_mic_jack = true, 610*cc8f70f5SDmitry Osipenko .add_hp_jack = true, 611*cc8f70f5SDmitry Osipenko }; 612*cc8f70f5SDmitry Osipenko 613*cc8f70f5SDmitry Osipenko /* RT5640 machine */ 614*cc8f70f5SDmitry Osipenko 615*cc8f70f5SDmitry Osipenko SND_SOC_DAILINK_DEFS(rt5640_aif1, 616*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_EMPTY()), 617*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5640-aif1")), 618*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_EMPTY())); 619*cc8f70f5SDmitry Osipenko 620*cc8f70f5SDmitry Osipenko static struct snd_soc_dai_link tegra_rt5640_dai = { 621*cc8f70f5SDmitry Osipenko .name = "RT5640", 622*cc8f70f5SDmitry Osipenko .stream_name = "RT5640 PCM", 623*cc8f70f5SDmitry Osipenko .init = tegra_asoc_machine_init, 624*cc8f70f5SDmitry Osipenko .dai_fmt = SND_SOC_DAIFMT_I2S | 625*cc8f70f5SDmitry Osipenko SND_SOC_DAIFMT_NB_NF | 626*cc8f70f5SDmitry Osipenko SND_SOC_DAIFMT_CBS_CFS, 627*cc8f70f5SDmitry Osipenko SND_SOC_DAILINK_REG(rt5640_aif1), 628*cc8f70f5SDmitry Osipenko }; 629*cc8f70f5SDmitry Osipenko 630*cc8f70f5SDmitry Osipenko static struct snd_soc_card snd_soc_tegra_rt5640 = { 631*cc8f70f5SDmitry Osipenko .dai_link = &tegra_rt5640_dai, 632*cc8f70f5SDmitry Osipenko .num_links = 1, 633*cc8f70f5SDmitry Osipenko .fully_routed = true, 634*cc8f70f5SDmitry Osipenko }; 635*cc8f70f5SDmitry Osipenko 636*cc8f70f5SDmitry Osipenko static const struct tegra_asoc_data tegra_rt5640_data = { 637*cc8f70f5SDmitry Osipenko .mclk_rate = tegra_machine_mclk_rate_256, 638*cc8f70f5SDmitry Osipenko .card = &snd_soc_tegra_rt5640, 639*cc8f70f5SDmitry Osipenko .add_common_dapm_widgets = true, 640*cc8f70f5SDmitry Osipenko .add_common_controls = true, 641*cc8f70f5SDmitry Osipenko .add_common_snd_ops = true, 642*cc8f70f5SDmitry Osipenko .add_hp_jack = true, 643*cc8f70f5SDmitry Osipenko }; 644*cc8f70f5SDmitry Osipenko 645*cc8f70f5SDmitry Osipenko /* RT5632 machine */ 646*cc8f70f5SDmitry Osipenko 647*cc8f70f5SDmitry Osipenko SND_SOC_DAILINK_DEFS(rt5632_hifi, 648*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_EMPTY()), 649*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "alc5632-hifi")), 650*cc8f70f5SDmitry Osipenko DAILINK_COMP_ARRAY(COMP_EMPTY())); 651*cc8f70f5SDmitry Osipenko 652*cc8f70f5SDmitry Osipenko static struct snd_soc_dai_link tegra_rt5632_dai = { 653*cc8f70f5SDmitry Osipenko .name = "ALC5632", 654*cc8f70f5SDmitry Osipenko .stream_name = "ALC5632 PCM", 655*cc8f70f5SDmitry Osipenko .init = tegra_rt5677_init, 656*cc8f70f5SDmitry Osipenko .dai_fmt = SND_SOC_DAIFMT_I2S | 657*cc8f70f5SDmitry Osipenko SND_SOC_DAIFMT_NB_NF | 658*cc8f70f5SDmitry Osipenko SND_SOC_DAIFMT_CBS_CFS, 659*cc8f70f5SDmitry Osipenko SND_SOC_DAILINK_REG(rt5632_hifi), 660*cc8f70f5SDmitry Osipenko }; 661*cc8f70f5SDmitry Osipenko 662*cc8f70f5SDmitry Osipenko static struct snd_soc_card snd_soc_tegra_rt5632 = { 663*cc8f70f5SDmitry Osipenko .dai_link = &tegra_rt5632_dai, 664*cc8f70f5SDmitry Osipenko .num_links = 1, 665*cc8f70f5SDmitry Osipenko .fully_routed = true, 666*cc8f70f5SDmitry Osipenko }; 667*cc8f70f5SDmitry Osipenko 668*cc8f70f5SDmitry Osipenko static const struct tegra_asoc_data tegra_rt5632_data = { 669*cc8f70f5SDmitry Osipenko .mclk_rate = tegra_machine_mclk_rate_512, 670*cc8f70f5SDmitry Osipenko .card = &snd_soc_tegra_rt5632, 671*cc8f70f5SDmitry Osipenko .add_common_dapm_widgets = true, 672*cc8f70f5SDmitry Osipenko .add_common_controls = true, 673*cc8f70f5SDmitry Osipenko .add_common_snd_ops = true, 674*cc8f70f5SDmitry Osipenko .add_headset_jack = true, 675*cc8f70f5SDmitry Osipenko }; 676*cc8f70f5SDmitry Osipenko 677*cc8f70f5SDmitry Osipenko static const struct of_device_id tegra_machine_of_match[] = { 678*cc8f70f5SDmitry Osipenko { .compatible = "nvidia,tegra-audio-trimslice", .data = &tegra_trimslice_data }, 679*cc8f70f5SDmitry Osipenko { .compatible = "nvidia,tegra-audio-max98090", .data = &tegra_max98090_data }, 680*cc8f70f5SDmitry Osipenko { .compatible = "nvidia,tegra-audio-sgtl5000", .data = &tegra_sgtl5000_data }, 681*cc8f70f5SDmitry Osipenko { .compatible = "nvidia,tegra-audio-wm9712", .data = &tegra_wm9712_data }, 682*cc8f70f5SDmitry Osipenko { .compatible = "nvidia,tegra-audio-wm8753", .data = &tegra_wm8753_data }, 683*cc8f70f5SDmitry Osipenko { .compatible = "nvidia,tegra-audio-rt5677", .data = &tegra_rt5677_data }, 684*cc8f70f5SDmitry Osipenko { .compatible = "nvidia,tegra-audio-rt5640", .data = &tegra_rt5640_data }, 685*cc8f70f5SDmitry Osipenko { .compatible = "nvidia,tegra-audio-alc5632", .data = &tegra_rt5632_data }, 686*cc8f70f5SDmitry Osipenko {}, 687*cc8f70f5SDmitry Osipenko }; 688*cc8f70f5SDmitry Osipenko MODULE_DEVICE_TABLE(of, tegra_machine_of_match); 689*cc8f70f5SDmitry Osipenko 690*cc8f70f5SDmitry Osipenko static struct platform_driver tegra_asoc_machine_driver = { 691*cc8f70f5SDmitry Osipenko .driver = { 692*cc8f70f5SDmitry Osipenko .name = "tegra-audio", 693*cc8f70f5SDmitry Osipenko .of_match_table = tegra_machine_of_match, 694*cc8f70f5SDmitry Osipenko .pm = &snd_soc_pm_ops, 695*cc8f70f5SDmitry Osipenko }, 696*cc8f70f5SDmitry Osipenko .probe = tegra_asoc_machine_probe, 697*cc8f70f5SDmitry Osipenko }; 698*cc8f70f5SDmitry Osipenko module_platform_driver(tegra_asoc_machine_driver); 699*cc8f70f5SDmitry Osipenko 700*cc8f70f5SDmitry Osipenko MODULE_AUTHOR("Anatol Pomozov <anatol@google.com>"); 701*cc8f70f5SDmitry Osipenko MODULE_AUTHOR("Andrey Danin <danindrey@mail.ru>"); 702*cc8f70f5SDmitry Osipenko MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>"); 703*cc8f70f5SDmitry Osipenko MODULE_AUTHOR("Ion Agorria <ion@agorria.com>"); 704*cc8f70f5SDmitry Osipenko MODULE_AUTHOR("Leon Romanovsky <leon@leon.nu>"); 705*cc8f70f5SDmitry Osipenko MODULE_AUTHOR("Lucas Stach <dev@lynxeye.de>"); 706*cc8f70f5SDmitry Osipenko MODULE_AUTHOR("Marc Dietrich <marvin24@gmx.de>"); 707*cc8f70f5SDmitry Osipenko MODULE_AUTHOR("Marcel Ziswiler <marcel@ziswiler.com>"); 708*cc8f70f5SDmitry Osipenko MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>"); 709*cc8f70f5SDmitry Osipenko MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); 710*cc8f70f5SDmitry Osipenko MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>"); 711*cc8f70f5SDmitry Osipenko MODULE_DESCRIPTION("Tegra machine ASoC driver"); 712*cc8f70f5SDmitry Osipenko MODULE_LICENSE("GPL"); 713