Commit be7a2dad authored by Mark Brown's avatar Mark Brown

Fix sound on ASUS Transformers

Merge series from Svyatoslav Ryhel <clamor95@gmail.com>:

- add quirk for headset detection used by some T30 devices
  (ASUS Transformers, LG Optimus 4X HD and Vu);
- add RT5631 and MAX9808x machine drivers
- update bindings

---
Changes from v1
- fm34 dropped for re-work
- quirk for headset detection and rt5631 bringup splitted
- minor adjustments in binding updates
- improvement of rt5631 rate asignment
---

David Heidelberg (1):
  dt-bindings: sound: nvidia,tegra-audio: add RT5631 CODEC

Svyatoslav Ryhel (7):
  dt-bindings: sound: nvidia,tegra-audio-common: add
    coupled-mic-hp-detect property
  ASoC: tegra: Support coupled mic-hp detection
  ARM: tegra: transformers: update sound nodes
  ASoC: tegra: Support RT5631 by machine driver
  ARM: tegra: transformers: bind RT5631 sound nodes
  dt-bindings: sound: nvidia,tegra-audio: add MAX9808x CODEC
  ASoC: tegra: Support MAX9808x by machine driver

 .../sound/nvidia,tegra-audio-common.yaml      |   4 +
 .../sound/nvidia,tegra-audio-max9808x.yaml    |  90 +++++++++++++
 .../sound/nvidia,tegra-audio-rt5631.yaml      |  85 ++++++++++++
 arch/arm/boot/dts/tegra20-asus-tf101.dts      |   7 +-
 arch/arm/boot/dts/tegra30-asus-tf201.dts      |  17 +++
 arch/arm/boot/dts/tegra30-asus-tf300t.dts     |   5 +-
 arch/arm/boot/dts/tegra30-asus-tf300tg.dts    |  17 +++
 arch/arm/boot/dts/tegra30-asus-tf700t.dts     |  17 +++
 .../dts/tegra30-asus-transformer-common.dtsi  |   9 +-
 sound/soc/tegra/Kconfig                       |  18 +++
 sound/soc/tegra/tegra_asoc_machine.c          | 125 +++++++++++++++++-
 11 files changed, 380 insertions(+), 14 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max9808x.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5631.yaml

--
2.37.2
parents 9934844f 85a375fe
...@@ -80,4 +80,8 @@ properties: ...@@ -80,4 +80,8 @@ properties:
type: boolean type: boolean
description: The Mic Jack represents state of the headset microphone pin description: The Mic Jack represents state of the headset microphone pin
nvidia,coupled-mic-hp-det:
type: boolean
description: The Mic detect GPIO is viable only if HP detect GPIO is active
additionalProperties: true additionalProperties: true
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/nvidia,tegra-audio-max9808x.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NVIDIA Tegra audio complex with MAX9808x CODEC
maintainers:
- Jon Hunter <jonathanh@nvidia.com>
- Thierry Reding <thierry.reding@gmail.com>
allOf:
- $ref: nvidia,tegra-audio-common.yaml#
properties:
compatible:
oneOf:
- items:
- pattern: '^[a-z0-9]+,tegra-audio-max98088(-[a-z0-9]+)+$'
- const: nvidia,tegra-audio-max98088
- items:
- pattern: '^[a-z0-9]+,tegra-audio-max98089(-[a-z0-9]+)+$'
- const: nvidia,tegra-audio-max98089
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
- "Int Spk"
- "Headphone Jack"
- "Earpiece"
- "Headset Mic"
- "Internal Mic 1"
- "Internal Mic 2"
# CODEC Pins
- HPL
- HPR
- SPKL
- SPKR
- RECL
- RECR
- INA1
- INA2
- INB1
- INB2
- MIC1
- MIC2
- MICBIAS
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/tegra30-car.h>
#include <dt-bindings/soc/tegra-pmc.h>
sound {
compatible = "lge,tegra-audio-max98089-p895",
"nvidia,tegra-audio-max98089";
nvidia,model = "LG Optimus Vu MAX98089";
nvidia,audio-routing =
"Headphone Jack", "HPL",
"Headphone Jack", "HPR",
"Int Spk", "SPKL",
"Int Spk", "SPKR",
"Earpiece", "RECL",
"Earpiece", "RECR",
"INA1", "Headset Mic",
"MIC1", "MICBIAS",
"MICBIAS", "Internal Mic 1",
"MIC2", "Internal Mic 2";
nvidia,i2s-controller = <&tegra_i2s0>;
nvidia,audio-codec = <&codec>;
clocks = <&tegra_car TEGRA30_CLK_PLL_A>,
<&tegra_car TEGRA30_CLK_PLL_A_OUT0>,
<&tegra_pmc TEGRA_PMC_CLK_OUT_1>;
clock-names = "pll_a", "pll_a_out0", "mclk";
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/nvidia,tegra-audio-rt5631.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NVIDIA Tegra audio complex with RT5631 CODEC
maintainers:
- Jon Hunter <jonathanh@nvidia.com>
- Thierry Reding <thierry.reding@gmail.com>
allOf:
- $ref: nvidia,tegra-audio-common.yaml#
properties:
compatible:
items:
- pattern: '^[a-z0-9]+,tegra-audio-rt5631(-[a-z0-9]+)+$'
- const: nvidia,tegra-audio-rt5631
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
- "Int Spk"
- "Headphone Jack"
- "Mic Jack"
- "Int Mic"
# CODEC Pins
- MIC1
- MIC2
- AXIL
- AXIR
- MONOIN_RXN
- MONOIN_RXP
- DMIC
- MIC Bias1
- MIC Bias2
- MONO_IN
- AUXO1
- AUXO2
- SPOL
- SPOR
- HPOL
- HPOR
- MONO
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/tegra30-car.h>
#include <dt-bindings/soc/tegra-pmc.h>
sound {
compatible = "asus,tegra-audio-rt5631-tf700t",
"nvidia,tegra-audio-rt5631";
nvidia,model = "Asus Transformer Infinity TF700T RT5631";
nvidia,audio-routing =
"Headphone Jack", "HPOL",
"Headphone Jack", "HPOR",
"Int Spk", "SPOL",
"Int Spk", "SPOR",
"MIC1", "MIC Bias1",
"MIC Bias1", "Mic Jack",
"DMIC", "Int Mic";
nvidia,i2s-controller = <&tegra_i2s1>;
nvidia,audio-codec = <&rt5631>;
clocks = <&tegra_car TEGRA30_CLK_PLL_A>,
<&tegra_car TEGRA30_CLK_PLL_A_OUT0>,
<&tegra_pmc TEGRA_PMC_CLK_OUT_1>;
clock-names = "pll_a", "pll_a_out0", "mclk";
};
...@@ -189,6 +189,15 @@ config SND_SOC_TEGRA_AUDIO_GRAPH_CARD ...@@ -189,6 +189,15 @@ config SND_SOC_TEGRA_AUDIO_GRAPH_CARD
config SND_SOC_TEGRA_MACHINE_DRV config SND_SOC_TEGRA_MACHINE_DRV
tristate tristate
config SND_SOC_TEGRA_RT5631
tristate "SoC Audio support for Tegra boards using an RT5631 codec"
depends on SND_SOC_TEGRA && I2C && GPIOLIB
select SND_SOC_TEGRA_MACHINE_DRV
select SND_SOC_RT5631
help
Say Y or M here if you want to add support for SoC audio on Tegra
boards using the RT5631 codec, such as Transformer.
config SND_SOC_TEGRA_RT5640 config SND_SOC_TEGRA_RT5640
tristate "SoC Audio support for Tegra boards using an RT5640 codec" tristate "SoC Audio support for Tegra boards using an RT5640 codec"
depends on I2C && GPIOLIB depends on I2C && GPIOLIB
...@@ -254,6 +263,15 @@ config SND_SOC_TEGRA_MAX98090 ...@@ -254,6 +263,15 @@ config SND_SOC_TEGRA_MAX98090
Say Y or M here if you want to add support for SoC audio on Tegra Say Y or M here if you want to add support for SoC audio on Tegra
boards using the MAX98090 codec, such as Venice2. boards using the MAX98090 codec, such as Venice2.
config SND_SOC_TEGRA_MAX98088
tristate "SoC Audio support for Tegra boards using a MAX9808x codec"
depends on I2C && GPIOLIB
select SND_SOC_TEGRA_MACHINE_DRV
select SND_SOC_MAX98088
help
Say Y or M here if you want to add support for SoC audio on Tegra
boards using the MAX98088 codec, such as LG X3.
config SND_SOC_TEGRA_RT5677 config SND_SOC_TEGRA_RT5677
tristate "SoC Audio support for Tegra boards using a RT5677 codec" tristate "SoC Audio support for Tegra boards using a RT5677 codec"
depends on I2C && GPIOLIB depends on I2C && GPIOLIB
......
...@@ -51,6 +51,17 @@ static struct snd_soc_jack_gpio tegra_machine_headset_jack_gpio = { ...@@ -51,6 +51,17 @@ static struct snd_soc_jack_gpio tegra_machine_headset_jack_gpio = {
}; };
/* Mic Jack */ /* Mic Jack */
static int coupled_mic_hp_check(void *data)
{
struct tegra_machine *machine = (struct tegra_machine *)data;
/* Detect mic insertion only if 3.5 jack is in */
if (gpiod_get_value_cansleep(machine->gpiod_hp_det) &&
gpiod_get_value_cansleep(machine->gpiod_mic_det))
return SND_JACK_MICROPHONE;
return 0;
}
static struct snd_soc_jack tegra_machine_mic_jack; static struct snd_soc_jack tegra_machine_mic_jack;
...@@ -75,11 +86,11 @@ static int tegra_machine_event(struct snd_soc_dapm_widget *w, ...@@ -75,11 +86,11 @@ static int tegra_machine_event(struct snd_soc_dapm_widget *w,
gpiod_set_value_cansleep(machine->gpiod_spkr_en, gpiod_set_value_cansleep(machine->gpiod_spkr_en,
SND_SOC_DAPM_EVENT_ON(event)); SND_SOC_DAPM_EVENT_ON(event));
if (!strcmp(w->name, "Mic Jack")) if (!strcmp(w->name, "Mic Jack") || !strcmp(w->name, "Headset Mic"))
gpiod_set_value_cansleep(machine->gpiod_ext_mic_en, gpiod_set_value_cansleep(machine->gpiod_ext_mic_en,
SND_SOC_DAPM_EVENT_ON(event)); SND_SOC_DAPM_EVENT_ON(event));
if (!strcmp(w->name, "Int Mic")) if (!strcmp(w->name, "Int Mic") || !strcmp(w->name, "Internal Mic 2"))
gpiod_set_value_cansleep(machine->gpiod_int_mic_en, gpiod_set_value_cansleep(machine->gpiod_int_mic_en,
SND_SOC_DAPM_EVENT_ON(event)); SND_SOC_DAPM_EVENT_ON(event));
...@@ -97,11 +108,12 @@ static const struct snd_soc_dapm_widget tegra_machine_dapm_widgets[] = { ...@@ -97,11 +108,12 @@ static const struct snd_soc_dapm_widget tegra_machine_dapm_widgets[] = {
SND_SOC_DAPM_HP("Headphones", NULL), SND_SOC_DAPM_HP("Headphones", NULL),
SND_SOC_DAPM_SPK("Speakers", tegra_machine_event), SND_SOC_DAPM_SPK("Speakers", tegra_machine_event),
SND_SOC_DAPM_SPK("Int Spk", tegra_machine_event), SND_SOC_DAPM_SPK("Int Spk", tegra_machine_event),
SND_SOC_DAPM_SPK("Earpiece", NULL),
SND_SOC_DAPM_MIC("Int Mic", tegra_machine_event), SND_SOC_DAPM_MIC("Int Mic", tegra_machine_event),
SND_SOC_DAPM_MIC("Mic Jack", tegra_machine_event), SND_SOC_DAPM_MIC("Mic Jack", tegra_machine_event),
SND_SOC_DAPM_MIC("Internal Mic 1", NULL), SND_SOC_DAPM_MIC("Internal Mic 1", NULL),
SND_SOC_DAPM_MIC("Internal Mic 2", NULL), SND_SOC_DAPM_MIC("Internal Mic 2", tegra_machine_event),
SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Headset Mic", tegra_machine_event),
SND_SOC_DAPM_MIC("Digital Mic", NULL), SND_SOC_DAPM_MIC("Digital Mic", NULL),
SND_SOC_DAPM_MIC("Mic", NULL), SND_SOC_DAPM_MIC("Mic", NULL),
SND_SOC_DAPM_LINE("Line In Jack", NULL), SND_SOC_DAPM_LINE("Line In Jack", NULL),
...@@ -112,6 +124,7 @@ static const struct snd_soc_dapm_widget tegra_machine_dapm_widgets[] = { ...@@ -112,6 +124,7 @@ static const struct snd_soc_dapm_widget tegra_machine_dapm_widgets[] = {
static const struct snd_kcontrol_new tegra_machine_controls[] = { static const struct snd_kcontrol_new tegra_machine_controls[] = {
SOC_DAPM_PIN_SWITCH("Speakers"), SOC_DAPM_PIN_SWITCH("Speakers"),
SOC_DAPM_PIN_SWITCH("Int Spk"), SOC_DAPM_PIN_SWITCH("Int Spk"),
SOC_DAPM_PIN_SWITCH("Earpiece"),
SOC_DAPM_PIN_SWITCH("Int Mic"), SOC_DAPM_PIN_SWITCH("Int Mic"),
SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("Internal Mic 1"), SOC_DAPM_PIN_SWITCH("Internal Mic 1"),
...@@ -183,8 +196,15 @@ int tegra_asoc_machine_init(struct snd_soc_pcm_runtime *rtd) ...@@ -183,8 +196,15 @@ int tegra_asoc_machine_init(struct snd_soc_pcm_runtime *rtd)
return err; return err;
} }
tegra_machine_mic_jack_gpio.data = machine;
tegra_machine_mic_jack_gpio.desc = machine->gpiod_mic_det; tegra_machine_mic_jack_gpio.desc = machine->gpiod_mic_det;
if (of_property_read_bool(card->dev->of_node,
"nvidia,coupled-mic-hp-det")) {
tegra_machine_mic_jack_gpio.desc = machine->gpiod_hp_det;
tegra_machine_mic_jack_gpio.jack_status_check = coupled_mic_hp_check;
};
err = snd_soc_jack_add_gpios(&tegra_machine_mic_jack, 1, err = snd_soc_jack_add_gpios(&tegra_machine_mic_jack, 1,
&tegra_machine_mic_jack_gpio); &tegra_machine_mic_jack_gpio);
if (err) if (err)
...@@ -238,6 +258,32 @@ static unsigned int tegra_machine_mclk_rate_12mhz(unsigned int srate) ...@@ -238,6 +258,32 @@ static unsigned int tegra_machine_mclk_rate_12mhz(unsigned int srate)
return mclk; return mclk;
} }
static unsigned int tegra_machine_mclk_rate_6mhz(unsigned int srate)
{
unsigned int mclk;
switch (srate) {
case 8000:
case 16000:
case 64000:
mclk = 8192000;
break;
case 11025:
case 22050:
case 88200:
mclk = 11289600;
break;
case 96000:
mclk = 12288000;
break;
default:
mclk = 256 * srate;
break;
}
return mclk;
}
static int tegra_machine_hw_params(struct snd_pcm_substream *substream, static int tegra_machine_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params) struct snd_pcm_hw_params *params)
{ {
...@@ -674,6 +720,40 @@ static const struct tegra_asoc_data tegra_max98090_data = { ...@@ -674,6 +720,40 @@ static const struct tegra_asoc_data tegra_max98090_data = {
.add_hp_jack = true, .add_hp_jack = true,
}; };
/* MAX98088 machine */
SND_SOC_DAILINK_DEFS(max98088_hifi,
DAILINK_COMP_ARRAY(COMP_EMPTY()),
DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
static struct snd_soc_dai_link tegra_max98088_dai = {
.name = "MAX98088",
.stream_name = "MAX98088 PCM",
.init = tegra_asoc_machine_init,
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
SND_SOC_DAILINK_REG(max98088_hifi),
};
static struct snd_soc_card snd_soc_tegra_max98088 = {
.components = "codec:max98088",
.dai_link = &tegra_max98088_dai,
.num_links = 1,
.fully_routed = true,
};
static const struct tegra_asoc_data tegra_max98088_data = {
.mclk_rate = tegra_machine_mclk_rate_12mhz,
.card = &snd_soc_tegra_max98088,
.add_common_dapm_widgets = true,
.add_common_controls = true,
.add_common_snd_ops = true,
.add_mic_jack = true,
.add_hp_jack = true,
};
/* SGTL5000 machine */ /* SGTL5000 machine */
SND_SOC_DAILINK_DEFS(sgtl5000_hifi, SND_SOC_DAILINK_DEFS(sgtl5000_hifi,
...@@ -865,15 +945,52 @@ static const struct tegra_asoc_data tegra_rt5632_data = { ...@@ -865,15 +945,52 @@ static const struct tegra_asoc_data tegra_rt5632_data = {
.add_headset_jack = true, .add_headset_jack = true,
}; };
/* RT5631 machine */
SND_SOC_DAILINK_DEFS(rt5631_hifi,
DAILINK_COMP_ARRAY(COMP_EMPTY()),
DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5631-hifi")),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
static struct snd_soc_dai_link tegra_rt5631_dai = {
.name = "RT5631",
.stream_name = "RT5631 PCM",
.init = tegra_asoc_machine_init,
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
SND_SOC_DAILINK_REG(rt5631_hifi),
};
static struct snd_soc_card snd_soc_tegra_rt5631 = {
.components = "codec:rt5631",
.dai_link = &tegra_rt5631_dai,
.num_links = 1,
.fully_routed = true,
};
static const struct tegra_asoc_data tegra_rt5631_data = {
.mclk_rate = tegra_machine_mclk_rate_6mhz,
.card = &snd_soc_tegra_rt5631,
.add_common_dapm_widgets = true,
.add_common_controls = true,
.add_common_snd_ops = true,
.add_mic_jack = true,
.add_hp_jack = true,
};
static const struct of_device_id tegra_machine_of_match[] = { static const struct of_device_id tegra_machine_of_match[] = {
{ .compatible = "nvidia,tegra-audio-trimslice", .data = &tegra_trimslice_data }, { .compatible = "nvidia,tegra-audio-trimslice", .data = &tegra_trimslice_data },
{ .compatible = "nvidia,tegra-audio-max98090", .data = &tegra_max98090_data }, { .compatible = "nvidia,tegra-audio-max98090", .data = &tegra_max98090_data },
{ .compatible = "nvidia,tegra-audio-max98088", .data = &tegra_max98088_data },
{ .compatible = "nvidia,tegra-audio-max98089", .data = &tegra_max98088_data },
{ .compatible = "nvidia,tegra-audio-sgtl5000", .data = &tegra_sgtl5000_data }, { .compatible = "nvidia,tegra-audio-sgtl5000", .data = &tegra_sgtl5000_data },
{ .compatible = "nvidia,tegra-audio-wm9712", .data = &tegra_wm9712_data }, { .compatible = "nvidia,tegra-audio-wm9712", .data = &tegra_wm9712_data },
{ .compatible = "nvidia,tegra-audio-wm8753", .data = &tegra_wm8753_data }, { .compatible = "nvidia,tegra-audio-wm8753", .data = &tegra_wm8753_data },
{ .compatible = "nvidia,tegra-audio-rt5677", .data = &tegra_rt5677_data }, { .compatible = "nvidia,tegra-audio-rt5677", .data = &tegra_rt5677_data },
{ .compatible = "nvidia,tegra-audio-rt5640", .data = &tegra_rt5640_data }, { .compatible = "nvidia,tegra-audio-rt5640", .data = &tegra_rt5640_data },
{ .compatible = "nvidia,tegra-audio-alc5632", .data = &tegra_rt5632_data }, { .compatible = "nvidia,tegra-audio-alc5632", .data = &tegra_rt5632_data },
{ .compatible = "nvidia,tegra-audio-rt5631", .data = &tegra_rt5631_data },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, tegra_machine_of_match); MODULE_DEVICE_TABLE(of, tegra_machine_of_match);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment