linux/sound/soc/tegra/tegra_audio_graph_card.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2//
   3// tegra_audio_graph_card.c - Audio Graph based Tegra Machine Driver
   4//
   5// Copyright (c) 2020-2021 NVIDIA CORPORATION.  All rights reserved.
   6
   7#include <linux/math64.h>
   8#include <linux/module.h>
   9#include <linux/of_device.h>
  10#include <linux/platform_device.h>
  11#include <sound/graph_card.h>
  12#include <sound/pcm_params.h>
  13
  14#define MAX_PLLA_OUT0_DIV 128
  15
  16#define simple_to_tegra_priv(simple) \
  17                container_of(simple, struct tegra_audio_priv, simple)
  18
  19enum srate_type {
  20        /*
  21         * Sample rates multiple of 8000 Hz and below are supported:
  22         * ( 8000, 16000, 32000, 48000, 96000, 192000 Hz )
  23         */
  24        x8_RATE,
  25
  26        /*
  27         * Sample rates multiple of 11025 Hz and below are supported:
  28         * ( 11025, 22050, 44100, 88200, 176400 Hz )
  29         */
  30        x11_RATE,
  31
  32        NUM_RATE_TYPE,
  33};
  34
  35struct tegra_audio_priv {
  36        struct asoc_simple_priv simple;
  37        struct clk *clk_plla_out0;
  38        struct clk *clk_plla;
  39};
  40
  41/* Tegra audio chip data */
  42struct tegra_audio_cdata {
  43        unsigned int plla_rates[NUM_RATE_TYPE];
  44        unsigned int plla_out0_rates[NUM_RATE_TYPE];
  45};
  46
  47/* Setup PLL clock as per the given sample rate */
  48static int tegra_audio_graph_update_pll(struct snd_pcm_substream *substream,
  49                                        struct snd_pcm_hw_params *params)
  50{
  51        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
  52        struct asoc_simple_priv *simple = snd_soc_card_get_drvdata(rtd->card);
  53        struct tegra_audio_priv *priv = simple_to_tegra_priv(simple);
  54        struct device *dev = rtd->card->dev;
  55        const struct tegra_audio_cdata *data = of_device_get_match_data(dev);
  56        unsigned int plla_rate, plla_out0_rate, bclk;
  57        unsigned int srate = params_rate(params);
  58        int err;
  59
  60        switch (srate) {
  61        case 11025:
  62        case 22050:
  63        case 44100:
  64        case 88200:
  65        case 176400:
  66                plla_out0_rate = data->plla_out0_rates[x11_RATE];
  67                plla_rate = data->plla_rates[x11_RATE];
  68                break;
  69        case 8000:
  70        case 16000:
  71        case 32000:
  72        case 48000:
  73        case 96000:
  74        case 192000:
  75                plla_out0_rate = data->plla_out0_rates[x8_RATE];
  76                plla_rate = data->plla_rates[x8_RATE];
  77                break;
  78        default:
  79                dev_err(rtd->card->dev, "Unsupported sample rate %u\n",
  80                        srate);
  81                return -EINVAL;
  82        }
  83
  84        /*
  85         * Below is the clock relation:
  86         *
  87         *      PLLA
  88         *        |
  89         *        |--> PLLA_OUT0
  90         *                |
  91         *                |---> I2S modules
  92         *                |
  93         *                |---> DMIC modules
  94         *                |
  95         *                |---> DSPK modules
  96         *
  97         *
  98         * Default PLLA_OUT0 rate might be too high when I/O is running
  99         * at minimum PCM configurations. This may result in incorrect
 100         * clock rates and glitchy audio. The maximum divider is 128
 101         * and any thing higher than that won't work. Thus reduce PLLA_OUT0
 102         * to work for lower configurations.
 103         *
 104         * This problem is seen for I2S only, as DMIC and DSPK minimum
 105         * clock requirements are under allowed divider limits.
 106         */
 107        bclk = srate * params_channels(params) * params_width(params);
 108        if (div_u64(plla_out0_rate, bclk) > MAX_PLLA_OUT0_DIV)
 109                plla_out0_rate >>= 1;
 110
 111        dev_dbg(rtd->card->dev,
 112                "Update clock rates: PLLA(= %u Hz) and PLLA_OUT0(= %u Hz)\n",
 113                plla_rate, plla_out0_rate);
 114
 115        /* Set PLLA rate */
 116        err = clk_set_rate(priv->clk_plla, plla_rate);
 117        if (err) {
 118                dev_err(rtd->card->dev,
 119                        "Can't set plla rate for %u, err: %d\n",
 120                        plla_rate, err);
 121                return err;
 122        }
 123
 124        /* Set PLLA_OUT0 rate */
 125        err = clk_set_rate(priv->clk_plla_out0, plla_out0_rate);
 126        if (err) {
 127                dev_err(rtd->card->dev,
 128                        "Can't set plla_out0 rate %u, err: %d\n",
 129                        plla_out0_rate, err);
 130                return err;
 131        }
 132
 133        return err;
 134}
 135
 136static int tegra_audio_graph_hw_params(struct snd_pcm_substream *substream,
 137                                       struct snd_pcm_hw_params *params)
 138{
 139        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 140        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 141        int err;
 142
 143        /*
 144         * This gets called for each DAI link (FE or BE) when DPCM is used.
 145         * We may not want to update PLLA rate for each call. So PLLA update
 146         * must be restricted to external I/O links (I2S, DMIC or DSPK) since
 147         * they actually depend on it. I/O modules update their clocks in
 148         * hw_param() of their respective component driver and PLLA rate
 149         * update here helps them to derive appropriate rates.
 150         *
 151         * TODO: When more HW accelerators get added (like sample rate
 152         * converter, volume gain controller etc., which don't really
 153         * depend on PLLA) we need a better way to filter here.
 154         */
 155        if (cpu_dai->driver->ops && rtd->dai_link->no_pcm) {
 156                err = tegra_audio_graph_update_pll(substream, params);
 157                if (err)
 158                        return err;
 159        }
 160
 161        return asoc_simple_hw_params(substream, params);
 162}
 163
 164static const struct snd_soc_ops tegra_audio_graph_ops = {
 165        .startup        = asoc_simple_startup,
 166        .shutdown       = asoc_simple_shutdown,
 167        .hw_params      = tegra_audio_graph_hw_params,
 168};
 169
 170static int tegra_audio_graph_card_probe(struct snd_soc_card *card)
 171{
 172        struct asoc_simple_priv *simple = snd_soc_card_get_drvdata(card);
 173        struct tegra_audio_priv *priv = simple_to_tegra_priv(simple);
 174
 175        priv->clk_plla = devm_clk_get(card->dev, "pll_a");
 176        if (IS_ERR(priv->clk_plla)) {
 177                dev_err(card->dev, "Can't retrieve clk pll_a\n");
 178                return PTR_ERR(priv->clk_plla);
 179        }
 180
 181        priv->clk_plla_out0 = devm_clk_get(card->dev, "plla_out0");
 182        if (IS_ERR(priv->clk_plla_out0)) {
 183                dev_err(card->dev, "Can't retrieve clk plla_out0\n");
 184                return PTR_ERR(priv->clk_plla_out0);
 185        }
 186
 187        return asoc_graph_card_probe(card);
 188}
 189
 190static int tegra_audio_graph_probe(struct platform_device *pdev)
 191{
 192        struct tegra_audio_priv *priv;
 193        struct device *dev = &pdev->dev;
 194        struct snd_soc_card *card;
 195
 196        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 197        if (!priv)
 198                return -ENOMEM;
 199
 200        card = simple_priv_to_card(&priv->simple);
 201        card->driver_name = "tegra-ape";
 202
 203        card->probe = tegra_audio_graph_card_probe;
 204
 205        /* audio_graph_parse_of() depends on below */
 206        card->component_chaining = 1;
 207        priv->simple.ops = &tegra_audio_graph_ops;
 208        priv->simple.force_dpcm = 1;
 209
 210        return audio_graph_parse_of(&priv->simple, dev);
 211}
 212
 213static const struct tegra_audio_cdata tegra210_data = {
 214        /* PLLA */
 215        .plla_rates[x8_RATE] = 368640000,
 216        .plla_rates[x11_RATE] = 338688000,
 217        /* PLLA_OUT0 */
 218        .plla_out0_rates[x8_RATE] = 49152000,
 219        .plla_out0_rates[x11_RATE] = 45158400,
 220};
 221
 222static const struct tegra_audio_cdata tegra186_data = {
 223        /* PLLA */
 224        .plla_rates[x8_RATE] = 245760000,
 225        .plla_rates[x11_RATE] = 270950400,
 226        /* PLLA_OUT0 */
 227        .plla_out0_rates[x8_RATE] = 49152000,
 228        .plla_out0_rates[x11_RATE] = 45158400,
 229};
 230
 231static const struct of_device_id graph_of_tegra_match[] = {
 232        { .compatible = "nvidia,tegra210-audio-graph-card",
 233          .data = &tegra210_data },
 234        { .compatible = "nvidia,tegra186-audio-graph-card",
 235          .data = &tegra186_data },
 236        {},
 237};
 238MODULE_DEVICE_TABLE(of, graph_of_tegra_match);
 239
 240static struct platform_driver tegra_audio_graph_card = {
 241        .driver = {
 242                .name = "tegra-audio-graph-card",
 243                .pm = &snd_soc_pm_ops,
 244                .of_match_table = graph_of_tegra_match,
 245        },
 246        .probe = tegra_audio_graph_probe,
 247        .remove = asoc_simple_remove,
 248};
 249module_platform_driver(tegra_audio_graph_card);
 250
 251MODULE_LICENSE("GPL v2");
 252MODULE_DESCRIPTION("ASoC Tegra Audio Graph Sound Card");
 253MODULE_AUTHOR("Sameer Pujar <spujar@nvidia.com>");
 254