On 11/11/2020 18:34, Sameer Pujar wrote: > Add Tegra audio machine driver which is based on generic audio graph card > driver. It re-uses most of the common stuff from audio graph driver and > uses the same DT binding. Required Tegra specific customizations are done > in the driver and additional DT bindings are required for clock handling. > > Details on the customizations done: > > - Update PLL rates at runtime: Tegra HW supports multiple sample rates > (multiples of 8x and 11.025x) and both of these groups require different > PLL rates. Hence there is a requirement to update this at runtime. > This is achieved by providing a custom 'snd_soc_ops' and in hw_param() > callback PLL rate is updated as per the sample rate. > > - Internal structure 'tegra_audio_graph_data' is used to maintain clock > handles of PLL. > > - The 'force_dpcm' flag is set to use DPCM for all DAI links. > > - The 'component_chaining' flag is set to use DPCM with component model. > > Signed-off-by: Sameer Pujar <spujar@xxxxxxxxxx> > --- > sound/soc/tegra/Kconfig | 9 ++ > sound/soc/tegra/Makefile | 2 + > sound/soc/tegra/tegra_audio_graph_card.c | 255 +++++++++++++++++++++++++++++++ > 3 files changed, 266 insertions(+) > create mode 100644 sound/soc/tegra/tegra_audio_graph_card.c > > diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig > index a62cc87..6dc83ad 100644 > --- a/sound/soc/tegra/Kconfig > +++ b/sound/soc/tegra/Kconfig > @@ -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 > diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile > index 60040a0..b17dd6e 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/tegra_audio_graph_card.c b/sound/soc/tegra/tegra_audio_graph_card.c > new file mode 100644 > index 0000000..f4d826d > --- /dev/null > +++ b/sound/soc/tegra/tegra_audio_graph_card.c > @@ -0,0 +1,255 @@ > +// 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; > + > + /* There is nothing to configure */ > + if (!data) > + return 0; Seems like this should never happen and so if it did this is an error. Any reason why we don't return an error here? Cheers Jon -- nvpublic