From 5b4d158b309a151979fce2334fec616d71506b77 Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Wed, 14 Oct 2026 15:01:47 +0300 Subject: [PATCH 1/2] ASoC: dt-bindings: nvidia,tegra-audio: Document WM8994 CODEC Add dt-binding for WM8994 CODEC. Signed-off-by: Svyatoslav Ryhel Link: https://patch.msgid.link/20261014120148.126160-2-clamor95@gmail.com Signed-off-by: Mark Brown --- .../sound/nvidia,tegra-audio-wm8994.yaml | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8994.yaml diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8994.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8994.yaml new file mode 100644 index 000000000000..d2c317f831ce --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8994.yaml @@ -0,0 +1,110 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra-audio-wm8994.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra audio complex with WM8994 CODEC + +maintainers: + - Svyatoslav Ryhel + +allOf: + - $ref: nvidia,tegra-audio-common.yaml# + +properties: + compatible: + items: + - pattern: '^[a-z0-9]+,tegra-audio-wm8994(-[a-z0-9]+)+$' + - const: nvidia,tegra-audio-wm8994 + + nvidia,audio-routing: + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + description: | + A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the pins (documented in the binding document), + and the jacks on the board. + minItems: 2 + items: + enum: + # Board Connectors + - Headphone Jack + - Int Spk + - Earpiece + - Line Out + - Mic Jack + - Int Mic + - Internal Mic 1 + - Internal Mic 2 + - FM Radio + + # CODEC Pins + - SPKOUTLP + - SPKOUTLN + - SPKOUTRP + - SPKOUTRN + - HPOUT1L + - HPOUT1R + - HPOUT2P + - HPOUT2N + - LINEOUT1P + - LINEOUT1N + - LINEOUT2P + - LINEOUT2N + - IN1LN + - IN1LP + - IN2LN + - IN2LP:VXRN + - IN1RN + - IN1RP + - IN2RN + - IN2RP:VXRP + - DMIC1DAT + - DMIC2DAT + - MICBIAS1 + - MICBIAS2 + +required: + - nvidia,i2s-controller + +unevaluatedProperties: false + +examples: + - | + #include + #include + + sound { + compatible = "lg,tegra-audio-wm8994-star", + "nvidia,tegra-audio-wm8994"; + nvidia,model = "LG Optimus 2X WM8994"; + + nvidia,audio-routing = + "Headphone Jack", "HPOUT1L", + "Headphone Jack", "HPOUT1R", + "Int Spk", "SPKOUTLN", + "Int Spk", "SPKOUTLP", + "Earpiece", "HPOUT2N", + "Earpiece", "HPOUT2P", + "IN2RN", "MICBIAS2", + "IN2RN", "Mic Jack", + "IN1LN", "MICBIAS1", + "IN1LN", "Internal Mic 1", + "IN1RN", "MICBIAS1", + "IN1RN", "Internal Mic 2"; + + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&wm8994>; + + nvidia,hp-det-gpios = <&gpio 51 GPIO_ACTIVE_HIGH>; + nvidia,mic-det-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>; + nvidia,ext-mic-en-gpios = <&gpio 57 GPIO_ACTIVE_HIGH>; + nvidia,coupled-mic-hp-det; + + clocks = <&tegra_car TEGRA20_CLK_PLL_A>, + <&tegra_car TEGRA20_CLK_PLL_A_OUT0>, + <&tegra_car TEGRA20_CLK_CDEV1>; + clock-names = "pll_a", "pll_a_out0", "mclk"; + }; From e38398539f79dddba1b695ae344aec811c63111a Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Wed, 14 Oct 2026 15:01:48 +0300 Subject: [PATCH 2/2] ASoC: tegra: Support WM8994 by machine driver Add Wolfson Microelectronics WM8994 codec support to the Tegra ASoC machine driver. The WM8994 codec is found on devices like LG Optimus 2X (P990/star) and Samsung Captivate Glide (SGH-i927). Signed-off-by: Svyatoslav Ryhel Link: https://patch.msgid.link/20261014120148.126160-3-clamor95@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/Kconfig | 10 ++ sound/soc/tegra/Makefile | 2 + sound/soc/tegra/tegra_asoc_machine.c | 2 + sound/soc/tegra/tegra_wm8994.c | 175 +++++++++++++++++++++++++++ 4 files changed, 189 insertions(+) create mode 100644 sound/soc/tegra/tegra_wm8994.c diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index fdc954028d62..dd3b2d3d6c4c 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig @@ -239,6 +239,16 @@ config SND_SOC_TEGRA_WM8962 boards using the WM8962 codec. Currently, the supported boards are Microsoft Surface RT. +config SND_SOC_TEGRA_WM8994 + tristate "SoC Audio support for Tegra boards using a WM8994 codec" + depends on I2C && GPIOLIB && MFD_WM8994 + select SND_SOC_TEGRA_MACHINE_DRV + select SND_SOC_WM8994 + help + Say Y or M here if you want to add support for SoC audio on Tegra + boards using the WM8994 codec. Currently, the supported boards are + LG Optimus X2 P990. + config SND_SOC_TEGRA_WM9712 tristate "SoC Audio support for Tegra boards using a WM9712 codec" depends on GPIOLIB diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index 1c18ef6971c0..b8f90149bfa6 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile @@ -43,10 +43,12 @@ obj-$(CONFIG_SND_SOC_TEGRA210_OPE) += snd-soc-tegra210-ope.o # Tegra machine Support snd-soc-tegra-wm8903-y := tegra_wm8903.o snd-soc-tegra-wm8962-y := tegra_wm8962.o +snd-soc-tegra-wm8994-y := tegra_wm8994.o snd-soc-tegra-machine-y := tegra_asoc_machine.o snd-soc-tegra-audio-graph-card-y := tegra_audio_graph_card.o obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o obj-$(CONFIG_SND_SOC_TEGRA_WM8962) += snd-soc-tegra-wm8962.o +obj-$(CONFIG_SND_SOC_TEGRA_WM8994) += snd-soc-tegra-wm8994.o obj-$(CONFIG_SND_SOC_TEGRA_MACHINE_DRV) += snd-soc-tegra-machine.o obj-$(CONFIG_SND_SOC_TEGRA_AUDIO_GRAPH_CARD) += snd-soc-tegra-audio-graph-card.o diff --git a/sound/soc/tegra/tegra_asoc_machine.c b/sound/soc/tegra/tegra_asoc_machine.c index e4af049fd7e8..e2d0e5947339 100644 --- a/sound/soc/tegra/tegra_asoc_machine.c +++ b/sound/soc/tegra/tegra_asoc_machine.c @@ -122,6 +122,8 @@ static const struct snd_soc_dapm_widget tegra_machine_dapm_widgets[] = { SND_SOC_DAPM_LINE("Line In Jack", NULL), SND_SOC_DAPM_LINE("Line In", NULL), SND_SOC_DAPM_LINE("LineIn", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), + SND_SOC_DAPM_INPUT("FM Radio"), }; static const struct snd_kcontrol_new tegra_machine_controls[] = { diff --git a/sound/soc/tegra/tegra_wm8994.c b/sound/soc/tegra/tegra_wm8994.c new file mode 100644 index 000000000000..1550faeba725 --- /dev/null +++ b/sound/soc/tegra/tegra_wm8994.c @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// tegra_wm8994.c - Tegra machine ASoC driver for boards using WM8994 codec. +// +// Copyright (C) 2026 Svyatoslav Ryhel +// +// Based on tegra_wm8994 code copyright/by: +// +// Author: Sumit Bhattacharya +// Copyright (C) 2010-2011 - NVIDIA, Inc. +// +// Based on code copyright/by: +// +// (c) 2009, 2010 Nvidia Graphics Pvt. Ltd. +// +// Copyright 2007 Wolfson Microelectronics PLC. +// Author: Graeme Gregory +// graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com + +#include +#include +#include +#include + +#include +#include +#include + +#include "../codecs/wm8994.h" + +#include "tegra_asoc_machine.h" + +static struct snd_soc_jack_pin tegra_wm8994_mic_jack_pins[] = { + { .pin = "Mic Jack", .mask = SND_JACK_MICROPHONE }, +}; + +static unsigned int tegra_wm8994_mclk_rate(unsigned int srate) +{ + unsigned int mclk; + + switch (srate) { + case 8000: + case 16000: + case 24000: + case 32000: + case 48000: + case 64000: + case 96000: + mclk = 12288000; + break; + case 11025: + case 22050: + case 44100: + case 88200: + mclk = 11289600; + break; + default: + mclk = 12000000; + break; + } + + return mclk; +} + +static const struct snd_kcontrol_new tegra_wm8994_controls[] = { + SOC_DAPM_PIN_SWITCH("Speakers"), + SOC_DAPM_PIN_SWITCH("Int Spk"), + SOC_DAPM_PIN_SWITCH("Int Mic"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Internal Mic 1"), + SOC_DAPM_PIN_SWITCH("Internal Mic 2"), + SOC_DAPM_PIN_SWITCH("Headphones"), + SOC_DAPM_PIN_SWITCH("Mic Jack"), + SOC_DAPM_PIN_SWITCH("Line Out"), + SOC_DAPM_PIN_SWITCH("FM Radio"), +}; + +static int tegra_wm8994_init(struct snd_soc_pcm_runtime *rtd) +{ + struct tegra_machine *machine = snd_soc_card_get_drvdata(rtd->card); + int err; + + err = tegra_asoc_machine_init(rtd); + if (err) + return err; + + if (!machine->gpiod_mic_det && machine->asoc->add_mic_jack) { + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + struct snd_soc_component *component = codec_dai->component; + + err = snd_soc_card_jack_new_pins(rtd->card, "Mic Jack", + SND_JACK_MICROPHONE, + machine->mic_jack, + tegra_wm8994_mic_jack_pins, + ARRAY_SIZE(tegra_wm8994_mic_jack_pins)); + if (err) { + dev_err(rtd->dev, "Mic Jack creation failed: %d\n", err); + return err; + } + + wm8994_mic_detect(component, machine->mic_jack, 1); + } + + return 0; +} + +static int tegra_wm8994_remove(struct snd_soc_card *card) +{ + struct snd_soc_dai_link *link = &card->dai_link[0]; + struct snd_soc_pcm_runtime *rtd = snd_soc_get_pcm_runtime(card, link); + struct tegra_machine *machine = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + struct snd_soc_component *component = codec_dai->component; + + if (!machine->gpiod_mic_det && machine->asoc->add_mic_jack) + wm8994_mic_detect(component, NULL, 1); + + return 0; +} + +SND_SOC_DAILINK_DEFS(wm8994_hifi, + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif1")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static struct snd_soc_dai_link tegra_wm8994_dai = { + .name = "WM8994", + .stream_name = "WM8994 PCM", + .init = tegra_wm8994_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBC_CFC, + SND_SOC_DAILINK_REG(wm8994_hifi), +}; + +static struct snd_soc_card snd_soc_tegra_wm8994 = { + .components = "codec:wm8994", + .owner = THIS_MODULE, + .dai_link = &tegra_wm8994_dai, + .num_links = 1, + .controls = tegra_wm8994_controls, + .num_controls = ARRAY_SIZE(tegra_wm8994_controls), + .remove = tegra_wm8994_remove, + .fully_routed = true, +}; + +static const struct tegra_asoc_data tegra_wm8994_data = { + .mclk_rate = tegra_wm8994_mclk_rate, + .mclk_id = WM8994_SYSCLK_MCLK1, + .card = &snd_soc_tegra_wm8994, + .add_common_dapm_widgets = true, + .add_common_snd_ops = true, + .add_mic_jack = true, + .add_hp_jack = true, +}; + +static const struct of_device_id tegra_wm8994_of_match[] = { + { .compatible = "nvidia,tegra-audio-wm8994", .data = &tegra_wm8994_data }, + { }, +}; +MODULE_DEVICE_TABLE(of, tegra_wm8994_of_match); + +static struct platform_driver tegra_wm8994_driver = { + .driver = { + .name = "tegra-wm8994", + .of_match_table = tegra_wm8994_of_match, + .pm = &snd_soc_pm_ops, + }, + .probe = tegra_asoc_machine_probe, +}; +module_platform_driver(tegra_wm8994_driver); + +MODULE_AUTHOR("Svyatoslav Ryhel "); +MODULE_DESCRIPTION("Tegra+WM8994 machine ASoC driver"); +MODULE_LICENSE("GPL");