Merge series "Tegra210 audio graph card" from Sameer Pujar <spujar@nvidia.com>:
This series adds audio graph based sound card support for Tegra210 platforms like Jetson-TX1 an Jetson-Nano. The following preparatory audio graph enhancement series is already merged. * https://patchwork.kernel.org/project/alsa-devel/list/?series=375629&state=* Following are the summary of changes: * Add graph/audio-graph based schemas or schema updates for Tegra210 component and machine drivers. * Add Tegra audio graph machine driver. * Add required DT support for Jetson-TX1/Nano. This work is based on earlier discussion of DPCM usage for Tegra and simple card driver updates. * https://lkml.org/lkml/2020/4/30/519 * https://lkml.org/lkml/2020/6/27/4 Original v6 series was sent about 6-7 weeks back. The dependency commit, https://lore.kernel.org/alsa-devel/1610948585-16286-1-git-send-email-spujar@nvidia.com/ is now merged. Resending this now to appear in the top of the mail list. Changelog ========= v5 -> v6 -------- * Added ports or port description in YAML docs for Tegra AHUB devices and graph card in patch 1/6 and 2/6. Reference of audio-graph-port.yaml is used for AHUB devices. * Dropped redundant NULL check return for of_device_get_match_data() in patch 3/6. * Added 'Reviewed-by' tag from Jon Hunter. * No changes in remaining patches. v4 -> v5 -------- * Audio graph related changes were sent in separate v5 series as mentioned above and are dropped from current series. * Graph and audio graph doc patches are dropped from this series and are sent separately as mentioned above. * Minor change with phandle label for TX1 and Nano platform DT files. * No changes in other patches. v3 -> v4 -------- * Added new patches to convert graph.txt and audio-graph-card.txt to corresponding json-schema files. Later these references are used in Tegra audio graph schema. * AHUB component binding docs are updated to reflect the usage of ports/port/endpoint * More common stuff is moved into graph_parse_of() and this is used by both generic and Tegra audio graph. * DT binding for Tegra audio graph is updated to included "ports { }" * As per the suggestion 'void *data' member is dropped from 'asoc_simple_priv' and instead container method is used to maintain required custom data internal to Tegra audio graph. v2 -> v3 -------- * Dropped new compatible addition in generic graph driver after reviewing it with Morimoto-san. Instead added Tegra audio graph driver and new compatibles are added in the same. * Added new patches to expose new members for customization in audio graph driver. * Added new patch for Tegra audio graph driver and related documentation. * Minor change in below commit where mutex version of helper is used "ASoC: audio-graph: Identify 'no_pcm' DAI links for DPCM" * DT binding is updated to use the newly exposed compatibles * No changes in other patches v1 -> v2 -------- * Re-organized ports/endpoints description for ADMAIF and XBAR. Updated DT patches accordingly. * After above change, multiple Codec endpoint support is not required and hence dropped for now. This will be considered separately if at all required in future. * Re-ordered patches in the series. Sameer Pujar (6): ASoC: dt-bindings: tegra: Add graph bindings ASoC: dt-bindings: tegra: Add json-schema for Tegra audio graph card ASoC: tegra: Add audio graph based card driver arm64: defconfig: Enable Tegra audio graph card driver arm64: tegra: Audio graph header for Tegra210 arm64: tegra: Audio graph sound card for Jetson Nano and TX1 .../sound/nvidia,tegra-audio-graph-card.yaml | 187 +++++++++++++++ .../bindings/sound/nvidia,tegra186-dspk.yaml | 18 +- .../bindings/sound/nvidia,tegra210-admaif.yaml | 13 +- .../bindings/sound/nvidia,tegra210-ahub.yaml | 13 +- .../bindings/sound/nvidia,tegra210-dmic.yaml | 18 +- .../bindings/sound/nvidia,tegra210-i2s.yaml | 18 +- .../boot/dts/nvidia/tegra210-audio-graph.dtsi | 153 ++++++++++++ arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts | 262 +++++++++++++++++++++ arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts | 146 ++++++++++++ arch/arm64/configs/defconfig | 1 + sound/soc/tegra/Kconfig | 9 + sound/soc/tegra/Makefile | 2 + sound/soc/tegra/tegra_audio_graph_card.c | 251 ++++++++++++++++++++ 13 files changed, 1085 insertions(+), 6 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-graph-card.yaml create mode 100644 arch/arm64/boot/dts/nvidia/tegra210-audio-graph.dtsi create mode 100644 sound/soc/tegra/tegra_audio_graph_card.c -- 2.7.4
This commit is contained in:
commit
6b050d45a6
|
@ -0,0 +1,187 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/nvidia,tegra-audio-graph-card.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Audio Graph based Tegra sound card driver
|
||||
|
||||
description: |
|
||||
This is based on generic audio graph card driver along with additional
|
||||
customizations for Tegra platforms. It uses the same bindings with
|
||||
additional standard clock DT bindings required for Tegra.
|
||||
|
||||
maintainers:
|
||||
- Jon Hunter <jonathanh@nvidia.com>
|
||||
- Sameer Pujar <spujar@nvidia.com>
|
||||
|
||||
allOf:
|
||||
- $ref: audio-graph.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- nvidia,tegra210-audio-graph-card
|
||||
- nvidia,tegra186-audio-graph-card
|
||||
|
||||
clocks:
|
||||
minItems: 2
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
items:
|
||||
- const: pll_a
|
||||
- const: plla_out0
|
||||
|
||||
assigned-clocks:
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
|
||||
assigned-clock-parents:
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
|
||||
assigned-clock-rates:
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
|
||||
required:
|
||||
- clocks
|
||||
- clock-names
|
||||
- assigned-clocks
|
||||
- assigned-clock-parents
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include<dt-bindings/clock/tegra210-car.h>
|
||||
|
||||
tegra_sound {
|
||||
compatible = "nvidia,tegra210-audio-graph-card";
|
||||
|
||||
clocks = <&tegra_car TEGRA210_CLK_PLL_A>,
|
||||
<&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
|
||||
clock-names = "pll_a", "plla_out0";
|
||||
|
||||
assigned-clocks = <&tegra_car TEGRA210_CLK_PLL_A>,
|
||||
<&tegra_car TEGRA210_CLK_PLL_A_OUT0>,
|
||||
<&tegra_car TEGRA210_CLK_EXTERN1>;
|
||||
assigned-clock-parents = <0>, <0>, <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
|
||||
assigned-clock-rates = <368640000>, <49152000>, <12288000>;
|
||||
|
||||
dais = /* FE */
|
||||
<&admaif1_port>,
|
||||
/* Router */
|
||||
<&xbar_i2s1_port>,
|
||||
/* I/O DAP Ports */
|
||||
<&i2s1_port>;
|
||||
|
||||
label = "jetson-tx1-ape";
|
||||
};
|
||||
|
||||
// The ports are defined for AHUB and its child devices.
|
||||
ahub@702d0800 {
|
||||
compatible = "nvidia,tegra210-ahub";
|
||||
reg = <0x702d0800 0x800>;
|
||||
clocks = <&tegra_car TEGRA210_CLK_D_AUDIO>;
|
||||
clock-names = "ahub";
|
||||
assigned-clocks = <&tegra_car TEGRA210_CLK_D_AUDIO>;
|
||||
assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0x702d0000 0x702d0000 0x0000e400>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0x0>;
|
||||
xbar_admaif1_ep: endpoint {
|
||||
remote-endpoint = <&admaif1_ep>;
|
||||
};
|
||||
};
|
||||
|
||||
// ...
|
||||
|
||||
xbar_i2s1_port: port@a {
|
||||
reg = <0xa>;
|
||||
xbar_i2s1_ep: endpoint {
|
||||
remote-endpoint = <&i2s1_cif_ep>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
admaif@702d0000 {
|
||||
compatible = "nvidia,tegra210-admaif";
|
||||
reg = <0x702d0000 0x800>;
|
||||
dmas = <&adma 1>, <&adma 1>,
|
||||
<&adma 2>, <&adma 2>,
|
||||
<&adma 3>, <&adma 3>,
|
||||
<&adma 4>, <&adma 4>,
|
||||
<&adma 5>, <&adma 5>,
|
||||
<&adma 6>, <&adma 6>,
|
||||
<&adma 7>, <&adma 7>,
|
||||
<&adma 8>, <&adma 8>,
|
||||
<&adma 9>, <&adma 9>,
|
||||
<&adma 10>, <&adma 10>;
|
||||
dma-names = "rx1", "tx1",
|
||||
"rx2", "tx2",
|
||||
"rx3", "tx3",
|
||||
"rx4", "tx4",
|
||||
"rx5", "tx5",
|
||||
"rx6", "tx6",
|
||||
"rx7", "tx7",
|
||||
"rx8", "tx8",
|
||||
"rx9", "tx9",
|
||||
"rx10", "tx10";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
admaif1_port: port@0 {
|
||||
reg = <0x0>;
|
||||
admaif1_ep: endpoint {
|
||||
remote-endpoint = <&xbar_admaif1_ep>;
|
||||
};
|
||||
};
|
||||
|
||||
// More ADMAIF ports to follow
|
||||
};
|
||||
};
|
||||
|
||||
i2s@702d1000 {
|
||||
compatible = "nvidia,tegra210-i2s";
|
||||
clocks = <&tegra_car TEGRA210_CLK_I2S0>;
|
||||
clock-names = "i2s";
|
||||
assigned-clocks = <&tegra_car TEGRA210_CLK_I2S0>;
|
||||
assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
|
||||
assigned-clock-rates = <1536000>;
|
||||
reg = <0x702d1000 0x100>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0x0>;
|
||||
|
||||
i2s1_cif_ep: endpoint {
|
||||
remote-endpoint = <&xbar_i2s1_ep>;
|
||||
};
|
||||
};
|
||||
|
||||
i2s1_port: port@1 {
|
||||
reg = <0x1>;
|
||||
|
||||
i2s1_dap: endpoint {
|
||||
dai-format = "i2s";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
|
@ -17,6 +17,9 @@ maintainers:
|
|||
- Jon Hunter <jonathanh@nvidia.com>
|
||||
- Sameer Pujar <spujar@nvidia.com>
|
||||
|
||||
allOf:
|
||||
- $ref: audio-graph-port.yaml#
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^dspk@[0-9a-f]*$"
|
||||
|
@ -55,6 +58,19 @@ properties:
|
|||
The name can be "DSPK1" or "DSPKx", where x depends on the maximum
|
||||
available instances on a Tegra SoC.
|
||||
|
||||
ports:
|
||||
type: object
|
||||
properties:
|
||||
port@0:
|
||||
description: |
|
||||
DSPK ACIF (Audio Client Interface) port connected to the
|
||||
corresponding AHUB (Audio Hub) ACIF port.
|
||||
|
||||
port@1:
|
||||
description: |
|
||||
DSPK DAP (Digital Audio Port) interface which can be connected
|
||||
to external audio codec for playback.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -64,7 +80,7 @@ required:
|
|||
- assigned-clock-parents
|
||||
- sound-name-prefix
|
||||
|
||||
additionalProperties: false
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
|
|
@ -17,6 +17,9 @@ maintainers:
|
|||
- Jon Hunter <jonathanh@nvidia.com>
|
||||
- Sameer Pujar <spujar@nvidia.com>
|
||||
|
||||
allOf:
|
||||
- $ref: audio-graph-port.yaml#
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^admaif@[0-9a-f]*$"
|
||||
|
@ -37,6 +40,14 @@ properties:
|
|||
|
||||
dma-names: true
|
||||
|
||||
ports:
|
||||
description: |
|
||||
Contains list of ACIF (Audio CIF) port nodes for ADMAIF channels.
|
||||
The number of port nodes depends on the number of ADMAIF channels
|
||||
that SoC may have. These are interfaced with respective ACIF ports
|
||||
in AHUB (Audio Hub). Each port is capable of data transfers in
|
||||
both directions.
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -81,7 +92,7 @@ required:
|
|||
- dmas
|
||||
- dma-names
|
||||
|
||||
additionalProperties: false
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
|
|
@ -17,6 +17,9 @@ maintainers:
|
|||
- Jon Hunter <jonathanh@nvidia.com>
|
||||
- Sameer Pujar <spujar@nvidia.com>
|
||||
|
||||
allOf:
|
||||
- $ref: audio-graph-port.yaml#
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^ahub@[0-9a-f]*$"
|
||||
|
@ -56,6 +59,13 @@ properties:
|
|||
|
||||
ranges: true
|
||||
|
||||
ports:
|
||||
description: |
|
||||
Contains list of ACIF (Audio CIF) port nodes for AHUB (Audio Hub).
|
||||
These are connected to ACIF interfaces of AHUB clients. Thus the
|
||||
number of port nodes depend on the number of clients that AHUB may
|
||||
have depending on the SoC revision.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -67,8 +77,7 @@ required:
|
|||
- "#size-cells"
|
||||
- ranges
|
||||
|
||||
additionalProperties:
|
||||
type: object
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
|
|
@ -16,6 +16,9 @@ maintainers:
|
|||
- Jon Hunter <jonathanh@nvidia.com>
|
||||
- Sameer Pujar <spujar@nvidia.com>
|
||||
|
||||
allOf:
|
||||
- $ref: audio-graph-port.yaml#
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^dmic@[0-9a-f]*$"
|
||||
|
@ -56,6 +59,19 @@ properties:
|
|||
The name can be "DMIC1" or "DMIC2" ... "DMICx", where x depends
|
||||
on the maximum available instances on a Tegra SoC.
|
||||
|
||||
ports:
|
||||
type: object
|
||||
properties:
|
||||
port@0:
|
||||
description: |
|
||||
DMIC ACIF (Audio Client Interface) port connected to the
|
||||
corresponding AHUB (Audio Hub) ACIF port.
|
||||
|
||||
port@1:
|
||||
description: |
|
||||
DMIC DAP (Digital Audio Port) interface which can be connected
|
||||
to external audio codec for capture.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -64,7 +80,7 @@ required:
|
|||
- assigned-clocks
|
||||
- assigned-clock-parents
|
||||
|
||||
additionalProperties: false
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
|
|
@ -16,6 +16,9 @@ maintainers:
|
|||
- Jon Hunter <jonathanh@nvidia.com>
|
||||
- Sameer Pujar <spujar@nvidia.com>
|
||||
|
||||
allOf:
|
||||
- $ref: audio-graph-port.yaml#
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^i2s@[0-9a-f]*$"
|
||||
|
@ -74,6 +77,19 @@ properties:
|
|||
The name can be "I2S1" or "I2S2" ... "I2Sx", where x depends
|
||||
on the maximum available instances on a Tegra SoC.
|
||||
|
||||
ports:
|
||||
type: object
|
||||
properties:
|
||||
port@0:
|
||||
description: |
|
||||
I2S ACIF (Audio Client Interface) port connected to the
|
||||
corresponding AHUB (Audio Hub) ACIF port.
|
||||
|
||||
port@1:
|
||||
description: |
|
||||
I2S DAP (Digital Audio Port) interface which can be connected
|
||||
to external audio codec for playback or capture.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -82,7 +98,7 @@ required:
|
|||
- assigned-clocks
|
||||
- assigned-clock-parents
|
||||
|
||||
additionalProperties: false
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
|
|
@ -117,6 +117,15 @@ 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,251 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
//
|
||||
// tegra_audio_graph_card.c - Audio Graph based Tegra Machine Driver
|
||||
//
|
||||
// Copyright (c) 2020 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 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;
|
||||
|
||||
/* graph_parse_of() depends on below */
|
||||
card->component_chaining = 1;
|
||||
priv->simple.ops = &tegra_audio_graph_ops;
|
||||
priv->simple.force_dpcm = 1;
|
||||
|
||||
return 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,
|
||||
};
|
||||
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>");
|
Loading…
Reference in New Issue