summaryrefslogtreecommitdiffstats
path: root/sound/soc/tegra
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/tegra')
-rw-r--r--sound/soc/tegra/Kconfig42
-rw-r--r--sound/soc/tegra/Makefile2
-rw-r--r--sound/soc/tegra/tegra186_dspk.c2
-rw-r--r--sound/soc/tegra/tegra20_i2s.c2
-rw-r--r--sound/soc/tegra/tegra210_dmic.c2
-rw-r--r--sound/soc/tegra/tegra210_i2s.c2
-rw-r--r--sound/soc/tegra/tegra30_ahub.c64
-rw-r--r--sound/soc/tegra/tegra30_ahub.h5
-rw-r--r--sound/soc/tegra/tegra30_i2s.c2
-rw-r--r--sound/soc/tegra/tegra_audio_graph_card.c252
-rw-r--r--sound/soc/tegra/tegra_pcm.c6
11 files changed, 324 insertions, 57 deletions
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index a62cc87551ac..a4e6760944d0 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -9,9 +9,10 @@ config SND_SOC_TEGRA
help
Say Y or M here if you want support for SoC audio on Tegra.
+if SND_SOC_TEGRA
+
config SND_SOC_TEGRA20_AC97
tristate "Tegra20 AC97 interface"
- depends on SND_SOC_TEGRA
select SND_SOC_AC97_BUS
select SND_SOC_TEGRA20_DAS
help
@@ -21,7 +22,6 @@ config SND_SOC_TEGRA20_AC97
config SND_SOC_TEGRA20_DAS
tristate "Tegra20 DAS module"
- depends on SND_SOC_TEGRA
help
Say Y or M if you want to add support for the Tegra20 DAS module.
You will also need to select the individual machine drivers to
@@ -29,7 +29,6 @@ config SND_SOC_TEGRA20_DAS
config SND_SOC_TEGRA20_I2S
tristate "Tegra20 I2S interface"
- depends on SND_SOC_TEGRA
select SND_SOC_TEGRA20_DAS
help
Say Y or M if you want to add support for codecs attached to the
@@ -38,7 +37,6 @@ config SND_SOC_TEGRA20_I2S
config SND_SOC_TEGRA20_SPDIF
tristate "Tegra20 SPDIF interface"
- depends on SND_SOC_TEGRA
help
Say Y or M if you want to add support for the Tegra20 SPDIF interface.
You will also need to select the individual machine drivers to support
@@ -46,7 +44,6 @@ config SND_SOC_TEGRA20_SPDIF
config SND_SOC_TEGRA30_AHUB
tristate "Tegra30 AHUB module"
- depends on SND_SOC_TEGRA
help
Say Y or M if you want to add support for the Tegra30 AHUB module.
You will also need to select the individual machine drivers to
@@ -54,7 +51,6 @@ config SND_SOC_TEGRA30_AHUB
config SND_SOC_TEGRA30_I2S
tristate "Tegra30 I2S interface"
- depends on SND_SOC_TEGRA
select SND_SOC_TEGRA30_AHUB
help
Say Y or M if you want to add support for codecs attached to the
@@ -63,7 +59,6 @@ config SND_SOC_TEGRA30_I2S
config SND_SOC_TEGRA210_AHUB
tristate "Tegra210 AHUB module"
- depends on SND_SOC_TEGRA
help
Config to enable Audio Hub (AHUB) module, which comprises of a
switch called Audio Crossbar (AXBAR) used to configure or modify
@@ -73,7 +68,6 @@ config SND_SOC_TEGRA210_AHUB
config SND_SOC_TEGRA210_DMIC
tristate "Tegra210 DMIC module"
- depends on SND_SOC_TEGRA
help
Config to enable the Digital MIC (DMIC) controller which is used
to interface with Pulse Density Modulation (PDM) input devices.
@@ -84,7 +78,6 @@ config SND_SOC_TEGRA210_DMIC
config SND_SOC_TEGRA210_I2S
tristate "Tegra210 I2S module"
- depends on SND_SOC_TEGRA
help
Config to enable the Inter-IC Sound (I2S) Controller which
implements full-duplex and bidirectional and single direction
@@ -94,7 +87,6 @@ config SND_SOC_TEGRA210_I2S
config SND_SOC_TEGRA186_DSPK
tristate "Tegra186 DSPK module"
- depends on SND_SOC_TEGRA
help
Config to enable the Digital Speaker Controller (DSPK) which
converts the multi-bit Pulse Code Modulation (PCM) audio input to
@@ -107,7 +99,6 @@ config SND_SOC_TEGRA186_DSPK
config SND_SOC_TEGRA210_ADMAIF
tristate "Tegra210 ADMAIF module"
- depends on SND_SOC_TEGRA
help
Config to enable ADMAIF which is the interface between ADMA and
Audio Hub (AHUB). Each ADMA channel that sends/receives data to/
@@ -117,9 +108,18 @@ config SND_SOC_TEGRA210_ADMAIF
channel. Buffer size is configurable for each ADMAIIF channel.
Say Y or M if you want to add support for Tegra210 ADMAIF module.
+config SND_SOC_TEGRA_AUDIO_GRAPH_CARD
+ tristate "Audio Graph Card based Tegra driver"
+ depends on SND_AUDIO_GRAPH_CARD
+ help
+ Config to enable Tegra audio machine driver based on generic
+ audio graph driver. It is a thin driver written to customize
+ few things for Tegra audio. Most of the code is re-used from
+ audio graph driver and the same DT bindings are used.
+
config SND_SOC_TEGRA_RT5640
tristate "SoC Audio support for Tegra boards using an RT5640 codec"
- depends on SND_SOC_TEGRA && I2C && GPIOLIB
+ depends on I2C && GPIOLIB
select SND_SOC_RT5640
help
Say Y or M here if you want to add support for SoC audio on Tegra
@@ -127,7 +127,7 @@ config SND_SOC_TEGRA_RT5640
config SND_SOC_TEGRA_WM8753
tristate "SoC Audio support for Tegra boards using a WM8753 codec"
- depends on SND_SOC_TEGRA && I2C && GPIOLIB
+ depends on I2C && GPIOLIB
select SND_SOC_WM8753
help
Say Y or M here if you want to add support for SoC audio on Tegra
@@ -135,7 +135,7 @@ config SND_SOC_TEGRA_WM8753
config SND_SOC_TEGRA_WM8903
tristate "SoC Audio support for Tegra boards using a WM8903 codec"
- depends on SND_SOC_TEGRA && I2C && GPIOLIB
+ depends on I2C && GPIOLIB
select SND_SOC_WM8903
help
Say Y or M here if you want to add support for SoC audio on Tegra
@@ -144,7 +144,7 @@ config SND_SOC_TEGRA_WM8903
config SND_SOC_TEGRA_WM9712
tristate "SoC Audio support for Tegra boards using a WM9712 codec"
- depends on SND_SOC_TEGRA && GPIOLIB
+ depends on GPIOLIB
select SND_SOC_TEGRA20_AC97
select SND_SOC_WM9712
help
@@ -153,7 +153,7 @@ config SND_SOC_TEGRA_WM9712
config SND_SOC_TEGRA_TRIMSLICE
tristate "SoC Audio support for TrimSlice board"
- depends on SND_SOC_TEGRA && I2C
+ depends on I2C
select SND_SOC_TLV320AIC23_I2C
help
Say Y or M here if you want to add support for SoC audio on the
@@ -161,7 +161,7 @@ config SND_SOC_TEGRA_TRIMSLICE
config SND_SOC_TEGRA_ALC5632
tristate "SoC Audio support for Tegra boards using an ALC5632 codec"
- depends on SND_SOC_TEGRA && I2C && GPIOLIB
+ depends on I2C && GPIOLIB
select SND_SOC_ALC5632
help
Say Y or M here if you want to add support for SoC audio on the
@@ -169,7 +169,7 @@ config SND_SOC_TEGRA_ALC5632
config SND_SOC_TEGRA_MAX98090
tristate "SoC Audio support for Tegra boards using a MAX98090 codec"
- depends on SND_SOC_TEGRA && I2C && GPIOLIB
+ depends on I2C && GPIOLIB
select SND_SOC_MAX98090
help
Say Y or M here if you want to add support for SoC audio on Tegra
@@ -177,7 +177,7 @@ config SND_SOC_TEGRA_MAX98090
config SND_SOC_TEGRA_RT5677
tristate "SoC Audio support for Tegra boards using a RT5677 codec"
- depends on SND_SOC_TEGRA && I2C && GPIOLIB
+ depends on I2C && GPIOLIB
select SND_SOC_RT5677
help
Say Y or M here if you want to add support for SoC audio on Tegra
@@ -185,9 +185,11 @@ config SND_SOC_TEGRA_RT5677
config SND_SOC_TEGRA_SGTL5000
tristate "SoC Audio support for Tegra boards using a SGTL5000 codec"
- depends on SND_SOC_TEGRA && I2C && GPIOLIB
+ depends on I2C && GPIOLIB
select SND_SOC_SGTL5000
help
Say Y or M here if you want to add support for SoC audio on Tegra
boards using the SGTL5000 codec, such as Apalis T30, Apalis TK1 or
Colibri T30.
+
+endif
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index 60040a06b814..b17dd6eef92a 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -38,6 +38,7 @@ snd-soc-tegra-trimslice-objs := trimslice.o
snd-soc-tegra-alc5632-objs := tegra_alc5632.o
snd-soc-tegra-max98090-objs := tegra_max98090.o
snd-soc-tegra-sgtl5000-objs := tegra_sgtl5000.o
+snd-soc-tegra-audio-graph-card-objs := tegra_audio_graph_card.o
obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o
obj-$(CONFIG_SND_SOC_TEGRA_RT5677) += snd-soc-tegra-rt5677.o
@@ -48,3 +49,4 @@ obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o
obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o
obj-$(CONFIG_SND_SOC_TEGRA_MAX98090) += snd-soc-tegra-max98090.o
obj-$(CONFIG_SND_SOC_TEGRA_SGTL5000) += snd-soc-tegra-sgtl5000.o
+obj-$(CONFIG_SND_SOC_TEGRA_AUDIO_GRAPH_CARD) += snd-soc-tegra-audio-graph-card.o
diff --git a/sound/soc/tegra/tegra186_dspk.c b/sound/soc/tegra/tegra186_dspk.c
index 7d9948fb2ca7..8ee9a77bd83d 100644
--- a/sound/soc/tegra/tegra186_dspk.c
+++ b/sound/soc/tegra/tegra186_dspk.c
@@ -217,7 +217,7 @@ static struct snd_soc_dai_driver tegra186_dspk_dais[] = {
SNDRV_PCM_FMTBIT_S32_LE,
},
.ops = &tegra186_dspk_dai_ops,
- .symmetric_rates = 1,
+ .symmetric_rate = 1,
},
};
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
index 005fc4e645aa..d7a3d046c8f8 100644
--- a/sound/soc/tegra/tegra20_i2s.c
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -260,7 +260,7 @@ static const struct snd_soc_dai_driver tegra20_i2s_dai_template = {
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.ops = &tegra20_i2s_dai_ops,
- .symmetric_rates = 1,
+ .symmetric_rate = 1,
};
static const struct snd_soc_component_driver tegra20_i2s_component = {
diff --git a/sound/soc/tegra/tegra210_dmic.c b/sound/soc/tegra/tegra210_dmic.c
index ead2c99bf72e..b096478cd2ef 100644
--- a/sound/soc/tegra/tegra210_dmic.c
+++ b/sound/soc/tegra/tegra210_dmic.c
@@ -228,7 +228,7 @@ static struct snd_soc_dai_driver tegra210_dmic_dais[] = {
SNDRV_PCM_FMTBIT_S32_LE,
},
.ops = &tegra210_dmic_dai_ops,
- .symmetric_rates = 1,
+ .symmetric_rate = 1,
},
};
diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c
index ca31ec92e508..45f31ccb49d8 100644
--- a/sound/soc/tegra/tegra210_i2s.c
+++ b/sound/soc/tegra/tegra210_i2s.c
@@ -577,7 +577,7 @@ static struct snd_soc_dai_driver tegra210_i2s_dais[] = {
SNDRV_PCM_FMTBIT_S32_LE,
},
.ops = &tegra210_i2s_dai_ops,
- .symmetric_rates = 1,
+ .symmetric_rate = 1,
},
};
diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
index 156e3b9d613c..9ef05ca4f6c4 100644
--- a/sound/soc/tegra/tegra30_ahub.c
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -45,8 +45,7 @@ static int tegra30_ahub_runtime_suspend(struct device *dev)
regcache_cache_only(ahub->regmap_apbif, true);
regcache_cache_only(ahub->regmap_ahub, true);
- clk_disable_unprepare(ahub->clk_apbif);
- clk_disable_unprepare(ahub->clk_d_audio);
+ clk_bulk_disable_unprepare(ahub->nclocks, ahub->clocks);
return 0;
}
@@ -66,22 +65,39 @@ static int tegra30_ahub_runtime_resume(struct device *dev)
{
int ret;
- ret = clk_prepare_enable(ahub->clk_d_audio);
- if (ret) {
- dev_err(dev, "clk_enable d_audio failed: %d\n", ret);
+ ret = reset_control_assert(ahub->reset);
+ if (ret)
return ret;
- }
- ret = clk_prepare_enable(ahub->clk_apbif);
- if (ret) {
- dev_err(dev, "clk_enable apbif failed: %d\n", ret);
- clk_disable(ahub->clk_d_audio);
+
+ ret = clk_bulk_prepare_enable(ahub->nclocks, ahub->clocks);
+ if (ret)
return ret;
- }
+
+ usleep_range(10, 100);
+
+ ret = reset_control_deassert(ahub->reset);
+ if (ret)
+ goto disable_clocks;
regcache_cache_only(ahub->regmap_apbif, false);
regcache_cache_only(ahub->regmap_ahub, false);
+ regcache_mark_dirty(ahub->regmap_apbif);
+ regcache_mark_dirty(ahub->regmap_ahub);
+
+ ret = regcache_sync(ahub->regmap_apbif);
+ if (ret)
+ goto disable_clocks;
+
+ ret = regcache_sync(ahub->regmap_ahub);
+ if (ret)
+ goto disable_clocks;
return 0;
+
+disable_clocks:
+ clk_bulk_disable_unprepare(ahub->nclocks, ahub->clocks);
+
+ return ret;
}
int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
@@ -337,6 +353,8 @@ static const struct {
const char *rst_name;
u32 mod_list_mask;
} configlink_mods[] = {
+ { "d_audio", MOD_LIST_MASK_TEGRA30_OR_LATER },
+ { "apbif", MOD_LIST_MASK_TEGRA30_OR_LATER },
{ "i2s0", MOD_LIST_MASK_TEGRA30_OR_LATER },
{ "i2s1", MOD_LIST_MASK_TEGRA30_OR_LATER },
{ "i2s2", MOD_LIST_MASK_TEGRA30_OR_LATER },
@@ -526,7 +544,6 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
/*
* The AHUB hosts a register bus: the "configlink". For this to
* operate correctly, all devices on this bus must be out of reset.
- * Ensure that here.
*/
for (i = 0; i < ARRAY_SIZE(configlink_mods); i++) {
if (!(configlink_mods[i].mod_list_mask &
@@ -542,10 +559,8 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
return ret;
}
- ret = reset_control_deassert(rst);
+ /* just check presence of the reset control in DT */
reset_control_put(rst);
- if (ret)
- return ret;
}
ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub),
@@ -557,18 +572,17 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
ahub->soc_data = soc_data;
ahub->dev = &pdev->dev;
- ahub->clk_d_audio = devm_clk_get(&pdev->dev, "d_audio");
- if (IS_ERR(ahub->clk_d_audio)) {
- dev_err(&pdev->dev, "Can't retrieve ahub d_audio clock\n");
- ret = PTR_ERR(ahub->clk_d_audio);
- return ret;
- }
+ ahub->clocks[ahub->nclocks++].id = "apbif";
+ ahub->clocks[ahub->nclocks++].id = "d_audio";
- ahub->clk_apbif = devm_clk_get(&pdev->dev, "apbif");
- if (IS_ERR(ahub->clk_apbif)) {
- dev_err(&pdev->dev, "Can't retrieve ahub apbif clock\n");
- ret = PTR_ERR(ahub->clk_apbif);
+ ret = devm_clk_bulk_get(&pdev->dev, ahub->nclocks, ahub->clocks);
+ if (ret)
return ret;
+
+ ahub->reset = devm_reset_control_array_get_exclusive(&pdev->dev);
+ if (IS_ERR(ahub->reset)) {
+ dev_err(&pdev->dev, "Can't get resets: %pe\n", ahub->reset);
+ return PTR_ERR(ahub->reset);
}
res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h
index 6889c5f23d02..3b85244f87f1 100644
--- a/sound/soc/tegra/tegra30_ahub.h
+++ b/sound/soc/tegra/tegra30_ahub.h
@@ -511,8 +511,9 @@ struct tegra30_ahub_soc_data {
struct tegra30_ahub {
const struct tegra30_ahub_soc_data *soc_data;
struct device *dev;
- struct clk *clk_d_audio;
- struct clk *clk_apbif;
+ struct reset_control *reset;
+ struct clk_bulk_data clocks[2];
+ unsigned int nclocks;
resource_size_t apbif_addr;
struct regmap *regmap_apbif;
struct regmap *regmap_ahub;
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index db5a8587bfa4..6740df541508 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -316,7 +316,7 @@ static const struct snd_soc_dai_driver tegra30_i2s_dai_template = {
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.ops = &tegra30_i2s_dai_ops,
- .symmetric_rates = 1,
+ .symmetric_rate = 1,
};
static const struct snd_soc_component_driver tegra30_i2s_component = {
diff --git a/sound/soc/tegra/tegra_audio_graph_card.c b/sound/soc/tegra/tegra_audio_graph_card.c
new file mode 100644
index 000000000000..ddedf18adde1
--- /dev/null
+++ b/sound/soc/tegra/tegra_audio_graph_card.c
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra_audio_graph_card.c - Audio Graph based Tegra Machine Driver
+//
+// Copyright (c) 2020-2021 NVIDIA CORPORATION. All rights reserved.
+
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <sound/graph_card.h>
+#include <sound/pcm_params.h>
+
+#define MAX_PLLA_OUT0_DIV 128
+
+#define simple_to_tegra_priv(simple) \
+ container_of(simple, struct tegra_audio_priv, simple)
+
+enum srate_type {
+ /*
+ * Sample rates multiple of 8000 Hz and below are supported:
+ * ( 8000, 16000, 32000, 48000, 96000, 192000 Hz )
+ */
+ x8_RATE,
+
+ /*
+ * Sample rates multiple of 11025 Hz and below are supported:
+ * ( 11025, 22050, 44100, 88200, 176400 Hz )
+ */
+ x11_RATE,
+
+ NUM_RATE_TYPE,
+};
+
+struct tegra_audio_priv {
+ struct asoc_simple_priv simple;
+ struct clk *clk_plla_out0;
+ struct clk *clk_plla;
+};
+
+/* Tegra audio chip data */
+struct tegra_audio_cdata {
+ unsigned int plla_rates[NUM_RATE_TYPE];
+ unsigned int plla_out0_rates[NUM_RATE_TYPE];
+};
+
+/* Setup PLL clock as per the given sample rate */
+static int tegra_audio_graph_update_pll(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct asoc_simple_priv *simple = snd_soc_card_get_drvdata(rtd->card);
+ struct tegra_audio_priv *priv = simple_to_tegra_priv(simple);
+ struct device *dev = rtd->card->dev;
+ const struct tegra_audio_cdata *data = of_device_get_match_data(dev);
+ unsigned int plla_rate, plla_out0_rate, bclk;
+ unsigned int srate = params_rate(params);
+ int err;
+
+ switch (srate) {
+ case 11025:
+ case 22050:
+ case 44100:
+ case 88200:
+ case 176400:
+ plla_out0_rate = data->plla_out0_rates[x11_RATE];
+ plla_rate = data->plla_rates[x11_RATE];
+ break;
+ case 8000:
+ case 16000:
+ case 32000:
+ case 48000:
+ case 96000:
+ case 192000:
+ plla_out0_rate = data->plla_out0_rates[x8_RATE];
+ plla_rate = data->plla_rates[x8_RATE];
+ break;
+ default:
+ dev_err(rtd->card->dev, "Unsupported sample rate %u\n",
+ srate);
+ return -EINVAL;
+ }
+
+ /*
+ * Below is the clock relation:
+ *
+ * PLLA
+ * |
+ * |--> PLLA_OUT0
+ * |
+ * |---> I2S modules
+ * |
+ * |---> DMIC modules
+ * |
+ * |---> DSPK modules
+ *
+ *
+ * Default PLLA_OUT0 rate might be too high when I/O is running
+ * at minimum PCM configurations. This may result in incorrect
+ * clock rates and glitchy audio. The maximum divider is 128
+ * and any thing higher than that won't work. Thus reduce PLLA_OUT0
+ * to work for lower configurations.
+ *
+ * This problem is seen for I2S only, as DMIC and DSPK minimum
+ * clock requirements are under allowed divider limits.
+ */
+ bclk = srate * params_channels(params) * params_width(params);
+ if (div_u64(plla_out0_rate, bclk) > MAX_PLLA_OUT0_DIV)
+ plla_out0_rate >>= 1;
+
+ dev_dbg(rtd->card->dev,
+ "Update clock rates: PLLA(= %u Hz) and PLLA_OUT0(= %u Hz)\n",
+ plla_rate, plla_out0_rate);
+
+ /* Set PLLA rate */
+ err = clk_set_rate(priv->clk_plla, plla_rate);
+ if (err) {
+ dev_err(rtd->card->dev,
+ "Can't set plla rate for %u, err: %d\n",
+ plla_rate, err);
+ return err;
+ }
+
+ /* Set PLLA_OUT0 rate */
+ err = clk_set_rate(priv->clk_plla_out0, plla_out0_rate);
+ if (err) {
+ dev_err(rtd->card->dev,
+ "Can't set plla_out0 rate %u, err: %d\n",
+ plla_out0_rate, err);
+ return err;
+ }
+
+ return err;
+}
+
+static int tegra_audio_graph_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ int err;
+
+ /*
+ * This gets called for each DAI link (FE or BE) when DPCM is used.
+ * We may not want to update PLLA rate for each call. So PLLA update
+ * must be restricted to external I/O links (I2S, DMIC or DSPK) since
+ * they actually depend on it. I/O modules update their clocks in
+ * hw_param() of their respective component driver and PLLA rate
+ * update here helps them to derive appropriate rates.
+ *
+ * TODO: When more HW accelerators get added (like sample rate
+ * converter, volume gain controller etc., which don't really
+ * depend on PLLA) we need a better way to filter here.
+ */
+ if (cpu_dai->driver->ops && rtd->dai_link->no_pcm) {
+ err = tegra_audio_graph_update_pll(substream, params);
+ if (err)
+ return err;
+ }
+
+ return asoc_simple_hw_params(substream, params);
+}
+
+static const struct snd_soc_ops tegra_audio_graph_ops = {
+ .startup = asoc_simple_startup,
+ .shutdown = asoc_simple_shutdown,
+ .hw_params = tegra_audio_graph_hw_params,
+};
+
+static int tegra_audio_graph_card_probe(struct snd_soc_card *card)
+{
+ struct asoc_simple_priv *simple = snd_soc_card_get_drvdata(card);
+ struct tegra_audio_priv *priv = simple_to_tegra_priv(simple);
+
+ priv->clk_plla = devm_clk_get(card->dev, "pll_a");
+ if (IS_ERR(priv->clk_plla)) {
+ dev_err(card->dev, "Can't retrieve clk pll_a\n");
+ return PTR_ERR(priv->clk_plla);
+ }
+
+ priv->clk_plla_out0 = devm_clk_get(card->dev, "plla_out0");
+ if (IS_ERR(priv->clk_plla_out0)) {
+ dev_err(card->dev, "Can't retrieve clk plla_out0\n");
+ return PTR_ERR(priv->clk_plla_out0);
+ }
+
+ return audio_graph_card_probe(card);
+}
+
+static int tegra_audio_graph_probe(struct platform_device *pdev)
+{
+ struct tegra_audio_priv *priv;
+ struct device *dev = &pdev->dev;
+ struct snd_soc_card *card;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ card = simple_priv_to_card(&priv->simple);
+
+ card->probe = tegra_audio_graph_card_probe;
+
+ /* audio_graph_parse_of() depends on below */
+ card->component_chaining = 1;
+ priv->simple.ops = &tegra_audio_graph_ops;
+ priv->simple.force_dpcm = 1;
+
+ return audio_graph_parse_of(&priv->simple, dev);
+}
+
+static const struct tegra_audio_cdata tegra210_data = {
+ /* PLLA */
+ .plla_rates[x8_RATE] = 368640000,
+ .plla_rates[x11_RATE] = 338688000,
+ /* PLLA_OUT0 */
+ .plla_out0_rates[x8_RATE] = 49152000,
+ .plla_out0_rates[x11_RATE] = 45158400,
+};
+
+static const struct tegra_audio_cdata tegra186_data = {
+ /* PLLA */
+ .plla_rates[x8_RATE] = 245760000,
+ .plla_rates[x11_RATE] = 270950400,
+ /* PLLA_OUT0 */
+ .plla_out0_rates[x8_RATE] = 49152000,
+ .plla_out0_rates[x11_RATE] = 45158400,
+};
+
+static const struct of_device_id graph_of_tegra_match[] = {
+ { .compatible = "nvidia,tegra210-audio-graph-card",
+ .data = &tegra210_data },
+ { .compatible = "nvidia,tegra186-audio-graph-card",
+ .data = &tegra186_data },
+ {},
+};
+MODULE_DEVICE_TABLE(of, graph_of_tegra_match);
+
+static struct platform_driver tegra_audio_graph_card = {
+ .driver = {
+ .name = "tegra-audio-graph-card",
+ .pm = &snd_soc_pm_ops,
+ .of_match_table = graph_of_tegra_match,
+ },
+ .probe = tegra_audio_graph_probe,
+ .remove = audio_graph_remove,
+};
+module_platform_driver(tegra_audio_graph_card);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ASoC Tegra Audio Graph Sound Card");
+MODULE_AUTHOR("Sameer Pujar <spujar@nvidia.com>");
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index b3f36515cbc1..573374b89b10 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -255,11 +255,7 @@ static int tegra_pcm_dma_allocate(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm *pcm = rtd->pcm;
int ret;
- ret = dma_set_mask(card->dev, DMA_BIT_MASK(32));
- if (ret < 0)
- return ret;
-
- ret = dma_set_coherent_mask(card->dev, DMA_BIT_MASK(32));
+ ret = dma_set_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
if (ret < 0)
return ret;