ASoC: tegra-alt: Create t210ref machine driver
Arun Shamanna Lakshmi [Wed, 17 Sep 2014 02:53:04 +0000 (19:53 -0700)]
This change is for creating t210ref machine driver for automotive

Bug 1442940
Bug 1537191

Change-Id: I6f13a5acdd36973ed79bd950b5ffeba19246a4d6
Signed-off-by: Arun Shamanna Lakshmi <aruns@nvidia.com>
Signed-off-by: Junghyun Kim <juskim@nvidia.com>
Reviewed-on: http://git-master/r/499969

12 files changed:
sound/soc/tegra-alt/Kconfig
sound/soc/tegra-alt/Makefile
sound/soc/tegra-alt/tegra210_admaif_alt.c
sound/soc/tegra-alt/tegra210_adx_alt.c
sound/soc/tegra-alt/tegra210_afc_alt.c
sound/soc/tegra-alt/tegra210_amx_alt.c
sound/soc/tegra-alt/tegra210_i2s_alt.c
sound/soc/tegra-alt/tegra210_i2s_alt.h
sound/soc/tegra-alt/tegra210_xbar_alt.c
sound/soc/tegra-alt/tegra_asoc_hwdep_alt.c
sound/soc/tegra-alt/tegra_asoc_machine_alt.c
sound/soc/tegra-alt/tegra_t210ref_alt.c [new file with mode: 0644]

index b5c4a4e..961834a 100644 (file)
@@ -261,3 +261,28 @@ config SND_SOC_TEGRA_T210REF_MOBILE_ES755_ALT
        select SND_SOC_TAS2552
        help
          Say Y or M here.
+
+config SND_SOC_TEGRA_T210REF_ALT
+       tristate "SoC Audio support for T210Ref"
+       depends on SND_SOC_TEGRA_ALT
+       depends on MACH_GRENADA
+       select SND_SOC_TEGRA210_XBAR_ALT
+       select SND_SOC_TEGRA210_PCM_ALT
+       select SND_SOC_TEGRA210_ADMA_ALT
+       select SND_SOC_TEGRA210_ADMAIF_ALT
+       select SND_SOC_TEGRA210_I2S_ALT
+       select SND_SOC_TEGRA210_AMX_ALT
+       select SND_SOC_TEGRA210_ADX_ALT
+       select SND_SOC_TEGRA210_MIXER_ALT
+       select SND_SOC_TEGRA210_SFC_ALT
+       select SND_SOC_TEGRA210_AFC_ALT
+       select SND_SOC_TEGRA210_MVC_ALT
+       select SND_SOC_TEGRA210_OPE_ALT
+       select SND_SOC_TEGRA210_SPDIF_ALT
+       select SND_SOC_TEGRA210_ADSP_ALT
+       select SND_SOC_TEGRA_ASOC_HWDEP_ALT
+       select SND_SOC_SPDIF
+       select SND_SOC_AD193X
+       select SND_SOC_AK4618
+       help
+         Say Y or M here.
index 057c1be..30787af 100644 (file)
@@ -67,6 +67,8 @@ snd-soc-tegra-alt-vcm30t124-objs := tegra_vcm30t124_alt.o
 snd-soc-tegra-alt-grenada-objs := tegra_grenada_alt.o
 snd-soc-tegra-alt-t210ref-mobile-objs := tegra_t210ref_mobile_alt.o
 snd-soc-tegra-alt-t210ref-mobile-es755-objs := tegra_t210ref_mobile_es755_alt.o
+snd-soc-tegra-alt-t210ref-objs := tegra_t210ref_alt.o
+
 obj-$(CONFIG_SND_SOC_TEGRA_VCM30T124_ALT) += snd-soc-tegra-alt-machine.o
 obj-$(CONFIG_SND_SOC_TEGRA_VCM30T124_ALT) += snd-soc-tegra-alt-vcm30t124.o
 obj-$(CONFIG_SND_SOC_TEGRA_GRENADA_ALT) += snd-soc-tegra-alt-machine.o
@@ -75,3 +77,5 @@ obj-$(CONFIG_SND_SOC_TEGRA_T210REF_MOBILE_ALT) += snd-soc-tegra-alt-machine.o
 obj-$(CONFIG_SND_SOC_TEGRA_T210REF_MOBILE_ALT) += snd-soc-tegra-alt-t210ref-mobile.o
 obj-$(CONFIG_SND_SOC_TEGRA_T210REF_MOBILE_ES755_ALT) += snd-soc-tegra-alt-machine.o
 obj-$(CONFIG_SND_SOC_TEGRA_T210REF_MOBILE_ES755_ALT) += snd-soc-tegra-alt-t210ref-mobile-es755.o
+obj-$(CONFIG_SND_SOC_TEGRA_T210REF_ALT) += snd-soc-tegra-alt-machine.o
+obj-$(CONFIG_SND_SOC_TEGRA_T210REF_ALT) += snd-soc-tegra-alt-t210ref.o
index d8daee9..5c36841 100644 (file)
@@ -280,6 +280,11 @@ static int tegra210_admaif_hw_params(struct snd_pcm_substream *substream,
                        TEGRA210_ADMAIF_XBAR_DMA_FIFO_SIZE_MASK,
                        fifo_size << TEGRA210_ADMAIF_XBAR_DMA_FIFO_SIZE_SHIFT);
 
+       regmap_update_bits(admaif->regmap, fifo_ctrl,
+               TEGRA210_ADMAIF_XBAR_DMA_FIFO_START_ADDR_MASK,
+               (0x4 * dai->id)
+                       << TEGRA210_ADMAIF_XBAR_DMA_FIFO_START_ADDR_SHIFT);
+
        return 0;
 }
 
index 7cf1b8f..3fff4bc 100644 (file)
@@ -211,9 +211,15 @@ static int tegra210_adx_set_audio_cif(struct tegra210_adx *adx,
                return -EINVAL;
 
        switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S8:
+               audio_bits = TEGRA210_AUDIOCIF_BITS_8;
+               break;
        case SNDRV_PCM_FORMAT_S16_LE:
                audio_bits = TEGRA210_AUDIOCIF_BITS_16;
                break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               audio_bits = TEGRA210_AUDIOCIF_BITS_24;
+               break;
        case SNDRV_PCM_FORMAT_S32_LE:
                audio_bits = TEGRA210_AUDIOCIF_BITS_32;
                break;
index 9143b35..da37f08 100644 (file)
@@ -15,6 +15,7 @@
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
+#include <linux/delay.h>
 #include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/io.h>
@@ -103,6 +104,13 @@ static unsigned int tegra210_afc_get_sfc_id(unsigned int afc_id)
        return val;
 }
 
+static void tegra210_afc_set_ppm_diff(struct tegra210_afc *afc,
+                       unsigned int ppm_diff)
+{
+       regmap_update_bits(afc->regmap,
+               TEGRA210_AFC_CLK_PPM_DIFF, 0xFFFF, ppm_diff);
+}
+
 static int tegra210_afc_set_thresholds(struct tegra210_afc *afc,
                                unsigned int afc_id)
 {
@@ -186,6 +194,8 @@ static int tegra210_afc_hw_params(struct snd_pcm_substream *substream,
                return ret;
        }
 
+       tegra210_afc_set_ppm_diff(afc, 50);
+
        /* program the thresholds, destn i2s id, PPM values */
        tegra210_afc_set_thresholds(afc, dev->id);
 
@@ -411,6 +421,10 @@ static int tegra210_afc_platform_probe(struct platform_device *pdev)
                        goto err_pm_disable;
        }
 
+       /* Disable SLGC */
+       regmap_write(afc->regmap, TEGRA210_AFC_CG, 0);
+       regcache_cache_only(afc->regmap, true);
+
        ret = snd_soc_register_codec(&pdev->dev, &tegra210_afc_codec,
                                     tegra210_afc_dais,
                                     ARRAY_SIZE(tegra210_afc_dais));
index 363647f..80c167f 100644 (file)
@@ -237,9 +237,15 @@ static int tegra210_amx_set_audio_cif(struct tegra210_amx *amx,
                return -EINVAL;
 
        switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S8:
+               audio_bits = TEGRA210_AUDIOCIF_BITS_8;
+               break;
        case SNDRV_PCM_FORMAT_S16_LE:
                audio_bits = TEGRA210_AUDIOCIF_BITS_16;
                break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               audio_bits = TEGRA210_AUDIOCIF_BITS_24;
+               break;
        case SNDRV_PCM_FORMAT_S32_LE:
                audio_bits = TEGRA210_AUDIOCIF_BITS_32;
                break;
index 6af80c7..51680f6 100644 (file)
@@ -66,11 +66,17 @@ static int tegra210_i2s_set_clock_rate(struct device *dev, int clock_rate)
                        return ret;
                }
 
-               ret = clk_set_parent(i2s->clk_i2s, i2s->clk_i2s_sync);
+               ret = clk_set_parent(i2s->clk_i2s, i2s->clk_audio_sync);
                if (ret) {
                        dev_err(dev, "Can't set parent of i2s clock\n");
                        return ret;
                }
+
+               ret = clk_set_rate(i2s->clk_i2s, clock_rate);
+               if (ret) {
+                       dev_err(dev, "Can't set I2S clock rate: %d\n", ret);
+                       return ret;
+               }
        }
 
        return ret;
@@ -215,16 +221,6 @@ static int tegra210_i2s_set_fmt(struct snd_soc_dai *dai,
        return 0;
 }
 
-static int tegra210_i2s_set_dai_sysclk(struct snd_soc_dai *dai,
-               int clk_id, unsigned int freq, int dir)
-{
-       struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-
-       i2s->srate = freq;
-
-       return 0;
-}
-
 static int tegra210_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai,
                unsigned int ratio)
 {
@@ -270,7 +266,7 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream,
 
        regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, mask, val);
 
-       srate = i2s->srate;
+       srate = params_rate(params);
 
        regmap_read(i2s->regmap, TEGRA210_I2S_CTRL, &val);
 
@@ -360,7 +356,6 @@ static int tegra210_i2s_codec_probe(struct snd_soc_codec *codec)
 static struct snd_soc_dai_ops tegra210_i2s_dai_ops = {
        .set_fmt        = tegra210_i2s_set_fmt,
        .hw_params      = tegra210_i2s_hw_params,
-       .set_sysclk     = tegra210_i2s_set_dai_sysclk,
        .set_bclk_ratio = tegra210_i2s_set_dai_bclk_ratio,
 };
 
@@ -372,14 +367,20 @@ static struct snd_soc_dai_driver tegra210_i2s_dais[] = {
                        .channels_min = 1,
                        .channels_max = 16,
                        .rates = SNDRV_PCM_RATE_8000_96000,
-                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                       .formats = SNDRV_PCM_FMTBIT_S8 |
+                               SNDRV_PCM_FMTBIT_S16_LE |
+                               SNDRV_PCM_FMTBIT_S24_LE |
+                               SNDRV_PCM_FMTBIT_S32_LE,
                },
                .capture = {
                        .stream_name = "CIF Transmit",
                        .channels_min = 1,
                        .channels_max = 16,
                        .rates = SNDRV_PCM_RATE_8000_96000,
-                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                       .formats = SNDRV_PCM_FMTBIT_S8 |
+                               SNDRV_PCM_FMTBIT_S16_LE |
+                               SNDRV_PCM_FMTBIT_S24_LE |
+                               SNDRV_PCM_FMTBIT_S32_LE,
                },
        },
        {
@@ -389,14 +390,20 @@ static struct snd_soc_dai_driver tegra210_i2s_dais[] = {
                        .channels_min = 1,
                        .channels_max = 16,
                        .rates = SNDRV_PCM_RATE_8000_96000,
-                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                       .formats = SNDRV_PCM_FMTBIT_S8 |
+                               SNDRV_PCM_FMTBIT_S16_LE |
+                               SNDRV_PCM_FMTBIT_S24_LE |
+                               SNDRV_PCM_FMTBIT_S32_LE,
                },
                .capture = {
                        .stream_name = "DAP Transmit",
                        .channels_min = 1,
                        .channels_max = 16,
                        .rates = SNDRV_PCM_RATE_8000_96000,
-                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                       .formats = SNDRV_PCM_FMTBIT_S8 |
+                               SNDRV_PCM_FMTBIT_S16_LE |
+                               SNDRV_PCM_FMTBIT_S24_LE |
+                               SNDRV_PCM_FMTBIT_S32_LE,
                },
                .ops = &tegra210_i2s_dai_ops,
                .symmetric_rates = 1,
@@ -577,9 +584,6 @@ static int tegra210_i2s_platform_probe(struct platform_device *pdev)
        i2s->soc_data = soc_data;
        i2s->bclk_ratio = 2;
 
-       /* initialize srate with default sampling rate */
-       i2s->srate = 48000;
-
        i2s->clk_i2s = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(i2s->clk_i2s)) {
                dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
@@ -594,11 +598,18 @@ static int tegra210_i2s_platform_probe(struct platform_device *pdev)
                goto err_clk_put;
        }
 
+       i2s->clk_audio_sync = devm_clk_get(&pdev->dev, "audio_sync");
+       if (IS_ERR(i2s->clk_audio_sync)) {
+               dev_err(&pdev->dev, "Can't retrieve audio sync clock\n");
+               ret = PTR_ERR(i2s->clk_audio_sync);
+               goto err_i2s_sync_clk_put;
+       }
+
        i2s->clk_pll_a_out0 = clk_get_sys(NULL, "pll_a_out0");
        if (IS_ERR(i2s->clk_pll_a_out0)) {
                dev_err(&pdev->dev, "Can't retrieve pll_a_out0 clock\n");
                ret = PTR_ERR(i2s->clk_pll_a_out0);
-               goto err_i2s_sync_clk_put;
+               goto err_audio_sync_clk_put;
        }
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -716,6 +727,8 @@ err_pm_disable:
        pm_runtime_disable(&pdev->dev);
 err_pll_a_out0_clk_put:
        clk_put(i2s->clk_pll_a_out0);
+err_audio_sync_clk_put:
+       devm_clk_put(&pdev->dev, i2s->clk_audio_sync);
 err_i2s_sync_clk_put:
        devm_clk_put(&pdev->dev, i2s->clk_i2s_sync);
 err_clk_put:
@@ -735,6 +748,7 @@ static int tegra210_i2s_platform_remove(struct platform_device *pdev)
                tegra210_i2s_runtime_suspend(&pdev->dev);
 
        devm_clk_put(&pdev->dev, i2s->clk_i2s);
+       devm_clk_put(&pdev->dev, i2s->clk_audio_sync);
        devm_clk_put(&pdev->dev, i2s->clk_i2s_sync);
        clk_put(i2s->clk_pll_a_out0);
 
index 5f76709..94e6769 100644 (file)
@@ -187,13 +187,13 @@ struct tegra210_i2s {
        const struct tegra210_i2s_soc_data *soc_data;
        struct clk *clk_i2s;
        struct clk *clk_i2s_sync;
+       struct clk *clk_audio_sync;
        struct clk *clk_pll_a_out0;
        struct regmap *regmap;
        struct pinctrl *pinctrl;
        struct pinctrl_state *pin_default_state;
        struct pinctrl_state *pin_idle_state;
        struct regulator_bulk_data *supplies;
-       unsigned int srate;
        int num_supplies;
        int bclk_ratio;
 };
index dce631b..47c0b21 100644 (file)
@@ -621,11 +621,11 @@ static const struct snd_soc_dapm_widget tegra210_xbar_widgets[] = {
        { name " Mux",      "ADX1-2",           "ADX1-2 RX" },          \
        { name " Mux",      "ADX1-3",           "ADX1-3 RX" },          \
        { name " Mux",      "ADX1-4",           "ADX1-4 RX" },          \
-       { name " Mux",      "AMX2",             "AMX1 RX" },            \
-       { name " Mux",      "ADX2-1",           "ADX1-1 RX" },          \
-       { name " Mux",      "ADX2-2",           "ADX1-2 RX" },          \
-       { name " Mux",      "ADX2-3",           "ADX1-3 RX" },          \
-       { name " Mux",      "ADX2-4",           "ADX1-4 RX" },
+       { name " Mux",      "AMX2",             "AMX2 RX" },            \
+       { name " Mux",      "ADX2-1",           "ADX2-1 RX" },          \
+       { name " Mux",      "ADX2-2",           "ADX2-2 RX" },          \
+       { name " Mux",      "ADX2-3",           "ADX2-3 RX" },          \
+       { name " Mux",      "ADX2-4",           "ADX2-4 RX" },
 
 
 #define IN_OUT_ROUTES(name)                            \
@@ -866,6 +866,13 @@ static int tegra210_xbar_probe(struct platform_device *pdev)
                goto err_clk_put_ape;
        }
 
+       ret = clk_set_rate(xbar->clk, 12288000);
+
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to set clock rate of ahub\n");
+               goto err_clk_put_ape;
+       }
+
        regs = devm_request_and_ioremap(&pdev->dev, pdev->resource);
        if (!regs) {
                dev_err(&pdev->dev, "request/iomap region failed\n");
index 1f8e7d4..7e7ab61 100644 (file)
@@ -20,6 +20,7 @@
 #include <sound/hwdep.h>
 #include <sound/asound.h>
 #include <linux/module.h>
+#include <linux/of.h>
 
 #include "tegra_asoc_machine_alt.h"
 #include "tegra_asoc_hwdep_alt.h"
@@ -33,6 +34,18 @@ static int tegra_asoc_hwdep_update_mapping_table(struct snd_soc_card *card,
                struct tegra_asoc_hwdep_tdm_map *map_info,
                unsigned int amx_adx)
 {
+       unsigned int amx_out_dai_link =
+               of_machine_is_compatible("nvidia,tegra210") ?
+                       TEGRA210_DAI_LINK_AMX1 : TEGRA124_DAI_LINK_AMX0;
+       unsigned int amx_in_dai_link =
+               of_machine_is_compatible("nvidia,tegra210") ?
+                       TEGRA210_DAI_LINK_AMX1_1 : TEGRA124_DAI_LINK_AMX0_0;
+       unsigned int adx_in_dai_link =
+               of_machine_is_compatible("nvidia,tegra210") ?
+                       TEGRA210_DAI_LINK_ADX1 : TEGRA124_DAI_LINK_ADX0;
+       unsigned int adx_out_dai_link =
+               of_machine_is_compatible("nvidia,tegra210") ?
+                       TEGRA210_DAI_LINK_ADX1_1 : TEGRA124_DAI_LINK_ADX0_0;
        struct snd_soc_dai *amx_adx_dai;
        struct snd_soc_pcm_stream *dai_params;
        unsigned int *map;
@@ -61,7 +74,7 @@ static int tegra_asoc_hwdep_update_mapping_table(struct snd_soc_card *card,
 
        if (!amx_adx) {
                /* DAI LINK for AMX OUT to XBAR */
-               amx_adx_dai = card->rtd[AMX_ADX_LINK_IDX(TEGRA124_DAI_LINK_AMX0,
+               amx_adx_dai = card->rtd[AMX_ADX_LINK_IDX(amx_out_dai_link,
                                                map_info->id)].cpu_dai;
 
                if (amx_adx_dai->driver->ops->set_channel_map)
@@ -70,11 +83,11 @@ static int tegra_asoc_hwdep_update_mapping_table(struct snd_soc_card *card,
                                0, 0);
 
                /* update dai_idx to set the CIF of AMX INPUT DAI */
-               dai_idx = AMX_ADX_LINK_IDX(TEGRA124_DAI_LINK_AMX0_0,
+               dai_idx = AMX_ADX_LINK_IDX(amx_in_dai_link,
                                map_info->id);
        } else {
                /* DAI LINK for XBAR to ADX IN */
-               amx_adx_dai = card->rtd[AMX_ADX_LINK_IDX(TEGRA124_DAI_LINK_ADX0,
+               amx_adx_dai = card->rtd[AMX_ADX_LINK_IDX(adx_in_dai_link,
                                                map_info->id)].codec_dai;
 
                if (amx_adx_dai->driver->ops->set_channel_map)
@@ -83,7 +96,7 @@ static int tegra_asoc_hwdep_update_mapping_table(struct snd_soc_card *card,
                                map_info->num_byte_map, map);
 
                /* update dai_idx to set the CIF of ADX OUTPUT DAI */
-               dai_idx = AMX_ADX_LINK_IDX(TEGRA124_DAI_LINK_ADX0_0,
+               dai_idx = AMX_ADX_LINK_IDX(adx_out_dai_link,
                                map_info->id);
        }
 
index c0a16c9..2ddaa3c 100644 (file)
@@ -1854,7 +1854,7 @@ struct snd_soc_dai_link *tegra_machine_new_codec_links(
                }
        }
 
-       /* i is for DAP and j is for CIF */
+       /* variable i is for DAP and j is for CIF */
        for (i = 0, j = num_codec_links; i < num_codec_links; i++, j++) {
                memset((void *)dai_link_name, '\0', MAX_STR_SIZE);
                sprintf(dai_link_name, "nvidia,dai-link-%d", i+1);
@@ -2119,6 +2119,5 @@ void tegra_machine_remove_extra_mem_alloc(unsigned int num_codec_links)
 }
 EXPORT_SYMBOL_GPL(tegra_machine_remove_extra_mem_alloc);
 
-
 MODULE_AUTHOR("Arun Shamanna Lakshmi <aruns@nvidia.com>");
 MODULE_AUTHOR("Junghyun Kim <juskim@nvidia.com>");
diff --git a/sound/soc/tegra-alt/tegra_t210ref_alt.c b/sound/soc/tegra-alt/tegra_t210ref_alt.c
new file mode 100644 (file)
index 0000000..6bf5103
--- /dev/null
@@ -0,0 +1,943 @@
+/*
+ * tegra_t210ref_alt.c - Tegra t210ref Machine driver
+ *
+ * Copyright (c) 2013-2014 NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/i2c.h>
+#include <linux/regulator/consumer.h>
+#include <linux/tegra-pmc.h>
+#include <linux/pm_runtime.h>
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <asm-generic/gpio.h>
+#include <sound/soc.h>
+#include "../codecs/wm8731.h"
+#include "../codecs/ad193x.h"
+
+#include "tegra_asoc_utils_alt.h"
+#include "tegra_asoc_machine_alt.h"
+#include "tegra_asoc_hwdep_alt.h"
+
+#define DRV_NAME "tegra-snd-t210ref"
+
+#define MAX_TX_SLOT_SIZE 32
+#define MAX_RX_SLOT_SIZE 32
+
+struct tegra_t210ref {
+       struct tegra_asoc_audio_clock_info audio_clock;
+       unsigned int num_codec_links;
+       int ad_rate_via_kcontrol;
+       int ak_rate_via_kcontrol;
+       struct i2c_client *max9485_client;
+       struct regulator *codec_reg;
+       struct regulator *digital_reg;
+       struct regulator *analog_reg;
+       struct regulator *dmic_reg;
+};
+
+static struct i2c_board_info max9485_info = {
+       .type = "max9485",
+};
+
+#define MAX9485_MCLK_FREQ_163840 0x31
+#define MAX9485_MCLK_FREQ_112896 0x22
+#define MAX9485_MCLK_FREQ_122880 0x23
+#define MAX9485_MCLK_FREQ_225792 0x32
+#define MAX9485_MCLK_FREQ_245760 0x33
+
+static void set_max9485_clk(struct i2c_client *i2s, int mclk)
+{
+       char clk;
+
+       switch (mclk) {
+       case 16384000:
+               clk =  MAX9485_MCLK_FREQ_163840;
+               break;
+       case 11289600:
+               clk = MAX9485_MCLK_FREQ_112896;
+               break;
+       case 12288000:
+               clk = MAX9485_MCLK_FREQ_122880;
+               break;
+       case 22579200:
+               clk = MAX9485_MCLK_FREQ_225792;
+               break;
+       case 24576000:
+               clk = MAX9485_MCLK_FREQ_245760;
+               break;
+       default:
+               return;
+       }
+       i2c_master_send(i2s, &clk, 1);
+}
+
+
+static struct snd_soc_pcm_stream tegra_t210ref_amx_input_params[] = {
+       [0] = {
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               .rate_min = 48000,
+               .rate_max = 48000,
+               .channels_min = 2,
+               .channels_max = 2,
+       },
+       [1] = {
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               .rate_min = 48000,
+               .rate_max = 48000,
+               .channels_min = 2,
+               .channels_max = 2,
+       },
+       [2] = {
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               .rate_min = 48000,
+               .rate_max = 48000,
+               .channels_min = 2,
+               .channels_max = 2,
+       },
+       [3] = {
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               .rate_min = 48000,
+               .rate_max = 48000,
+               .channels_min = 2,
+               .channels_max = 2,
+       },
+};
+
+static struct snd_soc_pcm_stream tegra_t210ref_adx_input_params[] = {
+       [0] = {
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               .rate_min = 48000,
+               .rate_max = 48000,
+               .channels_min = 2,
+               .channels_max = 2,
+       },
+       [1] = {
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               .rate_min = 48000,
+               .rate_max = 48000,
+               .channels_min = 2,
+               .channels_max = 2,
+       },
+       [2] = {
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               .rate_min = 48000,
+               .rate_max = 48000,
+               .channels_min = 2,
+               .channels_max = 2,
+       },
+       [3] = {
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               .rate_min = 48000,
+               .rate_max = 48000,
+               .channels_min = 2,
+               .channels_max = 2,
+       },
+};
+
+static int tegra_t210ref_ad1937_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dai *ad1937_dai = rtd->codec_dai;
+       struct snd_soc_dai *i2s_dai = rtd->cpu_dai;
+       struct snd_soc_codec *codec = ad1937_dai->codec;
+       struct snd_soc_card *card = codec->card;
+       struct tegra_t210ref *machine = snd_soc_card_get_drvdata(card);
+       struct snd_soc_pcm_stream *dai_params =
+               (struct snd_soc_pcm_stream *)rtd->dai_link->params;
+       unsigned int fmt = rtd->dai_link->dai_fmt;
+       unsigned int mclk, val;
+       int err;
+
+       mclk = dai_params->rate_min * 512;
+
+       err = tegra_alt_asoc_utils_set_extern_parent(&machine->audio_clock,
+                                                       "pll_a_out0");
+       if (err < 0) {
+               dev_err(card->dev, "Failed to set extern clk parent\n");
+               return err;
+       }
+
+       /* initialize 256fs by default */
+       tegra_alt_asoc_utils_set_rate(&machine->audio_clock,
+                       dai_params->rate_min, mclk, mclk);
+
+       if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM) {
+               /* direct MCLK mode in AD1937, mclk needs to be srate * 512 */
+               if (max9485_info.addr)
+                       set_max9485_clk(machine->max9485_client, mclk);
+
+               err = snd_soc_dai_set_sysclk(ad1937_dai, 0, mclk,
+                                               SND_SOC_CLOCK_IN);
+               if (err < 0) {
+                       dev_err(card->dev, "ad1937 clock not set\n");
+                       return err;
+               }
+
+               snd_soc_write(ad1937_dai->codec, AD193X_PLL_CLK_CTRL1, 0x03);
+
+               /*
+                * AD193X driver enables both DAC and ADC as MASTER
+                * so both ADC and DAC drive LRCLK and BCLK and it causes
+                * noise. To solve this, we need to disable one of them.
+                */
+               val = snd_soc_read(ad1937_dai->codec, AD193X_DAC_CTRL1);
+               val &= ~AD193X_DAC_LCR_MASTER;
+               val &= ~AD193X_DAC_BCLK_MASTER;
+               snd_soc_write(ad1937_dai->codec, AD193X_DAC_CTRL1, val);
+       } else {
+               /* set PLL_SRC with LRCLK for AD1937 slave mode */
+               snd_soc_write(ad1937_dai->codec, AD193X_PLL_CLK_CTRL0, 0xb9);
+       }
+
+       err = snd_soc_dai_set_bclk_ratio(i2s_dai,
+                       tegra_machine_get_bclk_ratio(rtd));
+       if (err < 0) {
+               dev_err(card->dev, "Failed to set cpu dai bclk ratio\n");
+               return err;
+       }
+
+       if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_DSP_A)
+               ad1937_dai->driver->ops->set_tdm_slot(ad1937_dai, 0, 0, 8, 0);
+
+       return 0;
+}
+
+static int tegra_t210ref_spdif_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct snd_soc_card *card = codec->card;
+       struct tegra_t210ref *machine = snd_soc_card_get_drvdata(card);
+       struct snd_soc_pcm_stream *dai_params =
+               (struct snd_soc_pcm_stream *)rtd->dai_link->params;
+       unsigned int mclk, clk_out_rate, srate;
+       int err = 0;
+
+       /* Default sampling rate*/
+       srate = dai_params->rate_min;
+       clk_out_rate = srate * 256;
+       mclk = clk_out_rate * 2;
+
+       err = tegra_alt_asoc_utils_set_rate(&machine->audio_clock,
+                                       srate, mclk, clk_out_rate);
+       if (err < 0) {
+               dev_err(card->dev, "Can't configure clocks\n");
+               return err;
+       }
+
+       err = snd_soc_dai_set_sysclk(cpu_dai, 0, srate,
+                                       SND_SOC_CLOCK_OUT);
+       err = snd_soc_dai_set_sysclk(cpu_dai, 0, srate,
+                                       SND_SOC_CLOCK_IN);
+       if (err < 0) {
+               dev_err(card->dev, "%s cpu DAI clock not set\n",
+                       cpu_dai->name);
+       }
+
+       return err;
+}
+
+static int tegra_t210ref_amx1_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dai *amx_dai = rtd->cpu_dai;
+       struct device_node *np = rtd->card->dev->of_node;
+       unsigned int tx_slot[MAX_TX_SLOT_SIZE], i, j;
+
+       if (of_property_read_u32_array(np, "nvidia,amx-slot-map",
+               tx_slot, MAX_TX_SLOT_SIZE))
+               for (i = 0, j = 0; i < MAX_TX_SLOT_SIZE; i += 8) {
+                       tx_slot[i] = 0;
+                       tx_slot[i + 1] = 0;
+                       tx_slot[i + 2] = (j << 16) | (1 << 8) | 0;
+                       tx_slot[i + 3] = (j << 16) | (1 << 8) | 1;
+                       tx_slot[i + 4] = 0;
+                       tx_slot[i + 5] = 0;
+                       tx_slot[i + 6] = (j << 16) | (2 << 8) | 0;
+                       tx_slot[i + 7] = (j << 16) | (2 << 8) | 1;
+                       j++;
+               }
+
+       if (amx_dai->driver->ops->set_channel_map)
+               amx_dai->driver->ops->set_channel_map(amx_dai,
+                       MAX_TX_SLOT_SIZE, tx_slot, 0, 0);
+
+       return 0;
+}
+
+static int tegra_t210ref_amx2_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dai *amx_dai = rtd->cpu_dai;
+       struct device_node *np = rtd->card->dev->of_node;
+       unsigned int tx_slot[MAX_TX_SLOT_SIZE], i, j;
+
+       if (of_property_read_u32_array(np, "nvidia,amx-slot-map",
+               tx_slot, MAX_TX_SLOT_SIZE))
+               for (i = 0, j = 0; i < MAX_TX_SLOT_SIZE; i += 8) {
+                       tx_slot[i] = 0;
+                       tx_slot[i + 1] = 0;
+                       tx_slot[i + 2] = (j << 16) | (1 << 8) | 0;
+                       tx_slot[i + 3] = (j << 16) | (1 << 8) | 1;
+                       tx_slot[i + 4] = 0;
+                       tx_slot[i + 5] = 0;
+                       tx_slot[i + 6] = (j << 16) | (2 << 8) | 0;
+                       tx_slot[i + 7] = (j << 16) | (2 << 8) | 1;
+                       j++;
+               }
+
+       if (amx_dai->driver->ops->set_channel_map)
+               amx_dai->driver->ops->set_channel_map(amx_dai,
+                       MAX_TX_SLOT_SIZE, tx_slot, 0, 0);
+
+       return 0;
+}
+
+static int tegra_t210ref_adx1_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dai *adx_dai = rtd->codec_dai;
+       struct device_node *np = rtd->card->dev->of_node;
+       unsigned int rx_slot[MAX_RX_SLOT_SIZE], i, j;
+
+       if (of_property_read_u32_array(np, "nvidia,adx-slot-map",
+               rx_slot, MAX_RX_SLOT_SIZE))
+               for (i = 0, j = 0; i < MAX_RX_SLOT_SIZE; i += 8) {
+                       rx_slot[i] = 0;
+                       rx_slot[i + 1] = 0;
+                       rx_slot[i + 2] = (j << 16) | (1 << 8) | 0;
+                       rx_slot[i + 3] = (j << 16) | (1 << 8) | 1;
+                       rx_slot[i + 4] = 0;
+                       rx_slot[i + 5] = 0;
+                       rx_slot[i + 6] = (j << 16) | (2 << 8) | 0;
+                       rx_slot[i + 7] = (j << 16) | (2 << 8) | 1;
+                       j++;
+               }
+
+       if (adx_dai->driver->ops->set_channel_map)
+               adx_dai->driver->ops->set_channel_map(adx_dai,
+                       0, 0, MAX_RX_SLOT_SIZE, rx_slot);
+
+       return 0;
+}
+
+static int tegra_t210ref_adx2_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dai *adx_dai = rtd->codec_dai;
+       struct device_node *np = rtd->card->dev->of_node;
+       unsigned int rx_slot[MAX_RX_SLOT_SIZE], i, j;
+
+       if (of_property_read_u32_array(np, "nvidia,adx-slot-map",
+               rx_slot, MAX_RX_SLOT_SIZE))
+               for (i = 0, j = 0; i < MAX_RX_SLOT_SIZE; i += 8) {
+                       rx_slot[i] = 0;
+                       rx_slot[i + 1] = 0;
+                       rx_slot[i + 2] = (j << 16) | (1 << 8) | 0;
+                       rx_slot[i + 3] = (j << 16) | (1 << 8) | 1;
+                       rx_slot[i + 4] = 0;
+                       rx_slot[i + 5] = 0;
+                       rx_slot[i + 6] = (j << 16) | (2 << 8) | 0;
+                       rx_slot[i + 7] = (j << 16) | (2 << 8) | 1;
+                       j++;
+               }
+
+       if (adx_dai->driver->ops->set_channel_map)
+               adx_dai->driver->ops->set_channel_map(adx_dai,
+                       0, 0, MAX_RX_SLOT_SIZE, rx_slot);
+
+       return 0;
+}
+
+static int tegra_t210ref_sfc1_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       unsigned int in_srate, out_srate;
+       int err;
+
+       in_srate = 48000;
+       out_srate = 8000;
+
+       err = snd_soc_dai_set_sysclk(codec_dai, 0, out_srate,
+                                       SND_SOC_CLOCK_OUT);
+       err = snd_soc_dai_set_sysclk(codec_dai, 0, in_srate,
+                                       SND_SOC_CLOCK_IN);
+       return 0;
+}
+
+static int tegra_t210ref_sfc2_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       unsigned int in_srate, out_srate;
+       int err;
+
+       in_srate = 8000;
+       out_srate = 48000;
+
+       err = snd_soc_dai_set_sysclk(codec_dai, 0, out_srate,
+                                       SND_SOC_CLOCK_OUT);
+       err = snd_soc_dai_set_sysclk(codec_dai, 0, in_srate,
+                                       SND_SOC_CLOCK_IN);
+       return 0;
+}
+
+static int tegra_t210ref_sfc3_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       unsigned int in_srate, out_srate;
+       int err;
+
+       in_srate = 48000;
+       out_srate = 8000;
+
+       err = snd_soc_dai_set_sysclk(codec_dai, 0, out_srate,
+                                       SND_SOC_CLOCK_OUT);
+       err = snd_soc_dai_set_sysclk(codec_dai, 0, in_srate,
+                                       SND_SOC_CLOCK_IN);
+       return 0;
+}
+
+static int tegra_t210ref_sfc4_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       unsigned int in_srate, out_srate;
+       int err;
+
+       in_srate = 8000;
+       out_srate = 48000;
+
+       err = snd_soc_dai_set_sysclk(codec_dai, 0, out_srate,
+                                       SND_SOC_CLOCK_OUT);
+       err = snd_soc_dai_set_sysclk(codec_dai, 0, in_srate,
+                                       SND_SOC_CLOCK_IN);
+       return 0;
+}
+
+static int tegra_t210ref_ad1937_hw_params(
+                       struct snd_pcm_substream *substream,
+                       struct snd_pcm_hw_params *params,
+                       unsigned int idx, char *prefix)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct snd_soc_card *card = codec->card;
+       struct tegra_t210ref *machine = snd_soc_card_get_drvdata(card);
+       struct snd_soc_pcm_stream *dai_params;
+       unsigned int fmt;
+       int mclk, clk_out_rate, val;
+       int err;
+
+       /* check if idx has valid number */
+       if (idx == -EINVAL)
+               return idx;
+
+       dai_params =
+               (struct snd_soc_pcm_stream *)card->rtd[idx].dai_link->params;
+       fmt = card->rtd[idx].dai_link->dai_fmt;
+
+       /* rate is either supplied by pcm params or via kcontrol */
+       if (!machine->ad_rate_via_kcontrol)
+               dai_params->rate_min = params_rate(params);
+
+       switch (dai_params->rate_min) {
+       case 64000:
+       case 88200:
+       case 96000:
+               clk_out_rate = dai_params->rate_min * 128;
+               break;
+       default:
+               clk_out_rate = dai_params->rate_min * 256;
+               break;
+       }
+
+       mclk = clk_out_rate * 2;
+
+       if (max9485_info.addr)
+               set_max9485_clk(machine->max9485_client, mclk);
+
+       err = snd_soc_dai_set_sysclk(card->rtd[idx].codec_dai,
+                       0, mclk,
+                       SND_SOC_CLOCK_IN);
+       if (err < 0) {
+               dev_err(card->dev,
+                       "%s codec_dai clock(%d) not set\n", prefix, mclk);
+               return err;
+       }
+
+       /*
+        * AD193X driver enables both DAC and ADC as MASTER
+        * so both ADC and DAC drive LRCLK and BCLK and it causes
+        * noise. To solve this, we need to disable one of them.
+        */
+       if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM) {
+               val = snd_soc_read(card->rtd[idx].codec_dai->codec,
+                               AD193X_DAC_CTRL1);
+               val &= ~AD193X_DAC_LCR_MASTER;
+               val &= ~AD193X_DAC_BCLK_MASTER;
+               snd_soc_write(card->rtd[idx].codec_dai->codec,
+                               AD193X_DAC_CTRL1, val);
+       }
+
+       return 0;
+}
+
+
+static int tegra_t210ref_ad1937_x_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *params)
+{
+       return tegra_t210ref_ad1937_hw_params(substream, params,
+               tegra_machine_get_codec_dai_link_idx("ad193x.0-0004"), "x");
+}
+
+static int tegra_t210ref_ad1937_y_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *params)
+{
+       return tegra_t210ref_ad1937_hw_params(substream, params,
+               tegra_machine_get_codec_dai_link_idx("ad193x.0-0005"), "y");
+}
+
+static int tegra_t210ref_spdif_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *params)
+{
+       /* dummy hw_params; clocks set in the init function */
+
+       return 0;
+}
+
+static struct snd_soc_ops tegra_t210ref_ad1937_x_ops = {
+       .hw_params = tegra_t210ref_ad1937_x_hw_params,
+};
+
+static struct snd_soc_ops tegra_t210ref_ad1937_y_ops = {
+       .hw_params = tegra_t210ref_ad1937_y_hw_params,
+};
+
+static struct snd_soc_ops tegra_t210ref_spdif_ops = {
+       .hw_params = tegra_t210ref_spdif_hw_params,
+};
+
+static const struct snd_soc_dapm_widget tegra_t210ref_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone-x", NULL),
+       SND_SOC_DAPM_HP("Headphone-y", NULL),
+       SND_SOC_DAPM_HP("Headphone-z", NULL),
+       SND_SOC_DAPM_HP("Headphone-s", NULL),
+       SND_SOC_DAPM_LINE("LineIn-x", NULL),
+       SND_SOC_DAPM_LINE("LineIn-y", NULL),
+       SND_SOC_DAPM_MIC("Mic-x", NULL),
+       SND_SOC_DAPM_MIC("Mic-y", NULL),
+       SND_SOC_DAPM_MIC("Mic-z", NULL),
+       SND_SOC_DAPM_MIC("Mic-s", NULL),
+};
+
+static const struct snd_soc_dapm_route tegra_t210ref_audio_map[] = {
+};
+
+static const int tegra_t210ref_srate_values[] = {
+       0,
+       8000,
+       16000,
+       44100,
+       48000,
+       11025,
+       22050,
+       24000,
+       32000,
+       88200,
+       96000,
+       176000,
+       192000,
+};
+
+static const char * const tegra_t210ref_srate_text[] = {
+       "None",
+       "8kHz",
+       "16kHz",
+       "44kHz",
+       "48kHz",
+       "11kHz",
+       "22kHz",
+       "24kHz",
+       "32kHz",
+       "88kHz",
+       "96kHz",
+       "176kHz",
+       "192kHz",
+};
+
+static int tegra_t210ref_ad1937_get_rate(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+       struct tegra_t210ref *machine = snd_soc_card_get_drvdata(card);
+
+       ucontrol->value.integer.value[0] = machine->ad_rate_via_kcontrol;
+
+       return 0;
+}
+
+static int tegra_t210ref_ad1937_put_rate(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+       struct tegra_t210ref *machine = snd_soc_card_get_drvdata(card);
+       unsigned int idx =  tegra_machine_get_codec_dai_link_idx("ad193x");
+       struct snd_soc_pcm_stream *dai_params =
+               (struct snd_soc_pcm_stream *)card->dai_link[idx].params;
+
+       /* set the rate control flag */
+       machine->ad_rate_via_kcontrol = ucontrol->value.integer.value[0];
+
+       /* update the dai params rate */
+       dai_params->rate_min =
+               tegra_t210ref_srate_values[machine->ad_rate_via_kcontrol];
+
+       return 0;
+}
+
+static int tegra_t210ref_remove(struct snd_soc_card *card)
+{
+       return 0;
+}
+
+static const struct soc_enum tegra_t210ref_codec_rate =
+       SOC_ENUM_SINGLE_EXT(13, tegra_t210ref_srate_text);
+
+static const struct snd_kcontrol_new tegra_t210ref_controls[] = {
+       SOC_ENUM_EXT("codec-ad rate", tegra_t210ref_codec_rate,
+               tegra_t210ref_ad1937_get_rate,
+               tegra_t210ref_ad1937_put_rate),
+};
+
+static struct snd_soc_card snd_soc_tegra_t210ref = {
+       .name = "tegra-t210ref",
+       .owner = THIS_MODULE,
+       .remove = tegra_t210ref_remove,
+       .dapm_widgets = tegra_t210ref_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(tegra_t210ref_dapm_widgets),
+       .controls = tegra_t210ref_controls,
+       .num_controls = ARRAY_SIZE(tegra_t210ref_controls),
+       .fully_routed = true,
+};
+
+static int tegra_t210ref_driver_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct snd_soc_card *card = &snd_soc_tegra_t210ref;
+       struct tegra_t210ref *machine;
+       struct snd_soc_dai_link *tegra_machine_dai_links = NULL;
+       struct snd_soc_dai_link *tegra_t210ref_codec_links = NULL;
+       struct snd_soc_codec_conf *tegra_machine_codec_conf = NULL;
+       struct snd_soc_codec_conf *tegra_t210ref_codec_conf = NULL;
+       unsigned int num_amx, num_adx;
+       int ret = 0, i, j;
+
+       machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_t210ref),
+                              GFP_KERNEL);
+       if (!machine) {
+               dev_err(&pdev->dev, "Can't allocate tegra_t210ref struct\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       card->dev = &pdev->dev;
+       platform_set_drvdata(pdev, card);
+       snd_soc_card_set_drvdata(card, machine);
+
+       if (np) {
+               ret = snd_soc_of_parse_card_name(card, "nvidia,model");
+               if (ret)
+                       goto err;
+
+               ret = snd_soc_of_parse_audio_routing(card,
+                                       "nvidia,audio-routing");
+               if (ret)
+                       goto err;
+
+               if (of_property_read_u32(np,
+                       "nvidia,num-amx", (u32 *)&num_amx)) {
+                       goto err;
+               }
+               if (of_property_read_u32(np,
+                       "nvidia,num-adx", (u32 *)&num_adx)) {
+                       goto err;
+               }
+       }
+
+       tegra_t210ref_codec_links = tegra_machine_new_codec_links(pdev,
+               tegra_t210ref_codec_links,
+               &machine->num_codec_links);
+       if (!tegra_t210ref_codec_links)
+               goto err_alloc_dai_link;
+
+       tegra_t210ref_codec_conf = tegra_machine_new_codec_conf(pdev,
+               tegra_t210ref_codec_conf,
+               &machine->num_codec_links);
+       if (!tegra_t210ref_codec_conf)
+               goto err_alloc_dai_link;
+
+       /* get the xbar dai link/codec conf structure */
+       tegra_machine_dai_links = tegra_machine_get_dai_link();
+       if (!tegra_machine_dai_links)
+               goto err_alloc_dai_link;
+       tegra_machine_codec_conf = tegra_machine_get_codec_conf();
+       if (!tegra_machine_codec_conf)
+               goto err_alloc_dai_link;
+
+       /* set AMX/ADX dai_init */
+       tegra_machine_set_dai_init(TEGRA210_DAI_LINK_AMX1,
+               &tegra_t210ref_amx1_dai_init);
+       tegra_machine_set_dai_init(TEGRA210_DAI_LINK_ADX1,
+               &tegra_t210ref_adx1_dai_init);
+       tegra_machine_set_dai_init(TEGRA210_DAI_LINK_AMX2,
+               &tegra_t210ref_amx2_dai_init);
+       tegra_machine_set_dai_init(TEGRA210_DAI_LINK_ADX2,
+               &tegra_t210ref_adx2_dai_init);
+
+       /* set codec init */
+       for (i = 0; i < machine->num_codec_links; i++) {
+               if (tegra_t210ref_codec_links[i].codec_of_node->name) {
+                       if (strstr(tegra_t210ref_codec_links[i]
+                               .codec_of_node->name, "ad193x"))
+                               tegra_t210ref_codec_links[i].init =
+                                       tegra_t210ref_ad1937_init;
+                       else if (strstr(tegra_t210ref_codec_links[i]
+                               .codec_of_node->name, "spdif"))
+                               tegra_t210ref_codec_links[i].init =
+                               tegra_t210ref_spdif_init;
+               }
+       }
+
+       /* set AMX/ADX params */
+       if (num_amx) {
+               switch (num_amx) {
+               case 2:
+                       tegra_machine_set_dai_params(TEGRA210_DAI_LINK_AMX2_1,
+                               (struct snd_soc_pcm_stream *)
+                               &tegra_t210ref_amx_input_params[0]);
+                       tegra_machine_set_dai_params(TEGRA210_DAI_LINK_AMX2_2,
+                               (struct snd_soc_pcm_stream *)
+                               &tegra_t210ref_amx_input_params[1]);
+                       tegra_machine_set_dai_params(TEGRA210_DAI_LINK_AMX2_3,
+                               (struct snd_soc_pcm_stream *)
+                               &tegra_t210ref_amx_input_params[2]);
+                       tegra_machine_set_dai_params(TEGRA210_DAI_LINK_AMX2_4,
+                               (struct snd_soc_pcm_stream *)
+                               &tegra_t210ref_amx_input_params[3]);
+               case 1:
+                       tegra_machine_set_dai_params(TEGRA210_DAI_LINK_AMX1_1,
+                               (struct snd_soc_pcm_stream *)
+                               &tegra_t210ref_amx_input_params[0]);
+                       tegra_machine_set_dai_params(TEGRA210_DAI_LINK_AMX1_2,
+                               (struct snd_soc_pcm_stream *)
+                               &tegra_t210ref_amx_input_params[1]);
+                       tegra_machine_set_dai_params(TEGRA210_DAI_LINK_AMX1_3,
+                               (struct snd_soc_pcm_stream *)
+                               &tegra_t210ref_amx_input_params[2]);
+                       tegra_machine_set_dai_params(TEGRA210_DAI_LINK_AMX1_4,
+                               (struct snd_soc_pcm_stream *)
+                               &tegra_t210ref_amx_input_params[3]);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       if (num_adx) {
+               switch (num_adx) {
+               case 2:
+                       tegra_machine_set_dai_params(TEGRA210_DAI_LINK_ADX2_1,
+                               (struct snd_soc_pcm_stream *)
+                               &tegra_t210ref_adx_input_params[0]);
+                       tegra_machine_set_dai_params(TEGRA210_DAI_LINK_ADX2_2,
+                               (struct snd_soc_pcm_stream *)
+                               &tegra_t210ref_adx_input_params[1]);
+                       tegra_machine_set_dai_params(TEGRA210_DAI_LINK_ADX2_3,
+                               (struct snd_soc_pcm_stream *)
+                               &tegra_t210ref_adx_input_params[2]);
+                       tegra_machine_set_dai_params(TEGRA210_DAI_LINK_ADX2_4,
+                               (struct snd_soc_pcm_stream *)
+                               &tegra_t210ref_adx_input_params[3]);
+               case 1:
+                       tegra_machine_set_dai_params(TEGRA210_DAI_LINK_ADX1_1,
+                               (struct snd_soc_pcm_stream *)
+                               &tegra_t210ref_adx_input_params[0]);
+                       tegra_machine_set_dai_params(TEGRA210_DAI_LINK_ADX1_2,
+                               (struct snd_soc_pcm_stream *)
+                               &tegra_t210ref_adx_input_params[1]);
+                       tegra_machine_set_dai_params(TEGRA210_DAI_LINK_ADX1_3,
+                               (struct snd_soc_pcm_stream *)
+                               &tegra_t210ref_adx_input_params[2]);
+                       tegra_machine_set_dai_params(TEGRA210_DAI_LINK_ADX1_4,
+                               (struct snd_soc_pcm_stream *)
+                               &tegra_t210ref_adx_input_params[3]);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       /* set sfc dai_init */
+       tegra_machine_set_dai_init(TEGRA210_DAI_LINK_SFC1_RX,
+               &tegra_t210ref_sfc1_init);      /* in - 8000Hz, out - 48000Hz */
+       tegra_machine_set_dai_init(TEGRA210_DAI_LINK_SFC2_RX,
+               &tegra_t210ref_sfc2_init);      /* in - 48000Hz, out - 8000Hz */
+       tegra_machine_set_dai_init(TEGRA210_DAI_LINK_SFC3_RX,
+               &tegra_t210ref_sfc3_init);      /* in - 8000Hz, out - 48000Hz */
+       tegra_machine_set_dai_init(TEGRA210_DAI_LINK_SFC4_RX,
+               &tegra_t210ref_sfc4_init);      /* in - 48000Hz, out - 8000Hz */
+
+       /* set ADSP PCM/COMPR */
+       for (i = TEGRA210_DAI_LINK_ADSP_PCM;
+               i <= TEGRA210_DAI_LINK_ADSP_COMPR2; i++) {
+               tegra_machine_set_dai_ops(i, &tegra_t210ref_spdif_ops);
+       }
+
+       /* set ADMAIF dai_ops */
+       for (i = TEGRA210_DAI_LINK_ADMAIF1;
+               i <= TEGRA210_DAI_LINK_ADMAIF10; i++)
+               tegra_machine_set_dai_ops(i, &tegra_t210ref_spdif_ops);
+
+       for (i = 0; i < machine->num_codec_links; i++) {
+               if (tegra_t210ref_codec_links[i].codec_of_node->name) {
+                       if (strstr(tegra_t210ref_codec_links[i]
+                               .codec_of_node->name, "ad193x.0-0004")) {
+                               for (j = TEGRA210_DAI_LINK_ADMAIF1;
+                                       j <= TEGRA210_DAI_LINK_ADMAIF4; j++)
+                                       tegra_machine_set_dai_ops(j,
+                                               &tegra_t210ref_ad1937_x_ops);
+                       } else if (strstr(tegra_t210ref_codec_links[i]
+                               .codec_of_node->name, "ad193x.0-0005")) {
+                               for (j = TEGRA210_DAI_LINK_ADMAIF5;
+                                       j <= TEGRA210_DAI_LINK_ADMAIF8; j++)
+                                       tegra_machine_set_dai_ops(j,
+                                               &tegra_t210ref_ad1937_y_ops);
+                       }
+               }
+       }
+
+       /* append t210ref specific dai_links */
+       card->num_links =
+               tegra_machine_append_dai_link(tegra_t210ref_codec_links,
+                       2 * machine->num_codec_links);
+       tegra_machine_dai_links = tegra_machine_get_dai_link();
+       card->dai_link = tegra_machine_dai_links;
+
+       /* append t210ref specific codec_conf */
+       card->num_configs =
+               tegra_machine_append_codec_conf(tegra_t210ref_codec_conf,
+                       machine->num_codec_links);
+       tegra_machine_codec_conf = tegra_machine_get_codec_conf();
+       card->codec_conf = tegra_machine_codec_conf;
+
+       machine->ad_rate_via_kcontrol = 0;
+       machine->ak_rate_via_kcontrol = 0;
+
+       ret = of_property_read_u32(np,
+               "nvidia,addr_max9485", (u32 *)&max9485_info.addr);
+
+       if (max9485_info.addr && !ret) {
+               machine->max9485_client = i2c_new_device(i2c_get_adapter(0),
+                                                       &max9485_info);
+               if (!machine->max9485_client) {
+                       dev_err(&pdev->dev, "cannot get i2c device for max9485\n");
+                       goto err_alloc_dai_link;
+               }
+       }
+
+       pwr_detect_bit_write(AUDIO_HV_PWR_DET, false);
+       pwr_detect_bit_write(SPI_HV_PWR_DET, false);
+
+       ret = tegra_alt_asoc_utils_init(&machine->audio_clock,
+                                       &pdev->dev,
+                                       card);
+       if (ret)
+               goto err_alloc_dai_link;
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+                       ret);
+               goto err_register_card;
+       }
+
+       ret = tegra_asoc_hwdep_create(card);
+       if (ret) {
+               dev_err(&pdev->dev, "can't create tegra_machine_hwdep (%d)\n",
+                       ret);
+               goto err_unregister_card;
+       }
+
+       return 0;
+
+err_unregister_card:
+       snd_soc_unregister_card(card);
+
+err_register_card:
+       if (machine->max9485_client)
+               i2c_unregister_device(machine->max9485_client);
+err_alloc_dai_link:
+       tegra_machine_remove_extra_mem_alloc(machine->num_codec_links);
+       tegra_machine_remove_dai_link();
+       tegra_machine_remove_codec_conf();
+err:
+       return ret;
+}
+
+static int tegra_t210ref_driver_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct tegra_t210ref *machine = snd_soc_card_get_drvdata(card);
+
+       snd_soc_unregister_card(card);
+
+       tegra_machine_remove_extra_mem_alloc(machine->num_codec_links);
+       tegra_machine_remove_dai_link();
+       tegra_machine_remove_codec_conf();
+
+       if (machine->max9485_client)
+               i2c_unregister_device(machine->max9485_client);
+
+       return 0;
+}
+
+static const struct of_device_id tegra_t210ref_of_match[] = {
+       { .compatible = "nvidia,tegra-audio-t210ref", },
+       {},
+};
+
+static struct platform_driver tegra_t210ref_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+               .pm = &snd_soc_pm_ops,
+               .of_match_table = tegra_t210ref_of_match,
+       },
+       .probe = tegra_t210ref_driver_probe,
+       .remove = tegra_t210ref_driver_remove,
+};
+module_platform_driver(tegra_t210ref_driver);
+
+MODULE_AUTHOR("Junghyun Kim <juskim@nvidia.com>");
+MODULE_DESCRIPTION("Tegra+t210ref machine ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra_t210ref_of_match);