diff --git a/Makefile b/Makefile index 2bb0ae7f..829e5434 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,9 @@ # Enable upstream fuse helper functions ccflags-y += -DCONFIG_TEGRA_FUSE_UPSTREAM +LINUXINCLUDE += -I$(srctree.nvidia-oot)/include obj-m += drivers/ obj-m += sound/soc/tegra/ obj-m += sound/tegra-safety-audio/ +obj-m += sound/soc/tegra-virt-alt/ diff --git a/sound/soc/tegra-virt-alt/Makefile b/sound/soc/tegra-virt-alt/Makefile new file mode 100644 index 00000000..61bebe0e --- /dev/null +++ b/sound/soc/tegra-virt-alt/Makefile @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. + +GCOV_PROFILE := y + +subdir-ccflags-y := -Werror +ccflags-y += -I$(overlay)/$(src)/../tegra-virt-alt/include/ +ccflags-y += -I$(overlay)/$(src)/../codecs +ccflags-y += -I$(srctree.nvidia)/sound/soc/tegra-virt-alt/nvaudio_ivc/ + +# Tegra platform Support + +snd-soc-tegra210-virt-alt-admaif-objs := tegra210_virt_alt_admaif.o \ + tegra_asoc_xbar_virt_alt.o \ + tegra_asoc_util_virt_alt.o \ + tegra_asoc_machine_virt_alt.o \ + tegra_pcm_virt_alt.o \ + nvaudio_ivc/tegra_virt_alt_ivc.o + +snd-soc-tegra-virt-t210ref-pcm-objs := tegra_virt_ref_alt.o +obj-m += snd-soc-tegra210-virt-alt-admaif.o +obj-m += snd-soc-tegra-virt-t210ref-pcm.o \ No newline at end of file diff --git a/sound/soc/tegra-virt-alt/include/tegra_asoc_utils_alt.h b/sound/soc/tegra-virt-alt/include/tegra_asoc_utils_alt.h new file mode 100644 index 00000000..276df684 --- /dev/null +++ b/sound/soc/tegra-virt-alt/include/tegra_asoc_utils_alt.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + */ + +#ifndef __TEGRA_ASOC_UTILS_ALT_H_ +#define __TEGRA_ASOC_UTILS_ALT_H_ + +struct clk; +struct device; + +enum tegra_asoc_utils_soc { + TEGRA_ASOC_UTILS_SOC_TEGRA210, + TEGRA_ASOC_UTILS_SOC_TEGRA186, + TEGRA_ASOC_UTILS_SOC_TEGRA194, +}; + +/* + * Maintain same order in DT entry + * FIXME: (This would be removed going ahead) + */ +enum tegra_asoc_utils_clkrate { + PLLA_x11025_RATE, + AUD_MCLK_x11025_RATE, + PLLA_OUT0_x11025_RATE, + AHUB_x11025_RATE, + PLLA_x8000_RATE, + AUD_MCLK_x8000_RATE, + PLLA_OUT0_x8000_RATE, + AHUB_x8000_RATE, + MAX_NUM_RATES, +}; + +struct tegra_asoc_audio_clock_info { + struct device *dev; + struct snd_soc_card *card; + enum tegra_asoc_utils_soc soc; + struct clk *clk_pll_base; + struct clk *clk_pll_out; + struct clk *clk_aud_mclk; + struct reset_control *clk_cdev1_rst; + unsigned int *pll_base_rate; + u32 set_pll_base_rate; + u32 set_pll_out_rate; + u32 set_aud_mclk_rate; + u32 mclk_scale; + + /* FIXME: below would be removed going ahead */ + u32 clk_rates[MAX_NUM_RATES]; + u32 num_clk; +}; + +int tegra_alt_asoc_utils_set_rate(struct tegra_asoc_audio_clock_info *data, + unsigned int srate, unsigned int mclk, + unsigned int clk_out_rate); +int tegra_alt_asoc_utils_init(struct tegra_asoc_audio_clock_info *data, + struct device *dev, struct snd_soc_card *card); +int tegra_alt_asoc_utils_clk_enable(struct tegra_asoc_audio_clock_info *data); +int tegra_alt_asoc_utils_clk_disable(struct tegra_asoc_audio_clock_info *data); + +#endif \ No newline at end of file diff --git a/sound/soc/tegra-virt-alt/include/tegra_isomgr_bw_alt.h b/sound/soc/tegra-virt-alt/include/tegra_isomgr_bw_alt.h new file mode 100644 index 00000000..092ab1c3 --- /dev/null +++ b/sound/soc/tegra-virt-alt/include/tegra_isomgr_bw_alt.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + */ + +#ifndef __TEGRA_ISOMGR_BW_ALT_H__ +#define __TEGRA_ISOMGR_BW_ALT_H__ + +#if defined(CONFIG_TEGRA_ISOMGR) +void tegra_isomgr_adma_register(void); +void tegra_isomgr_adma_unregister(void); +void tegra_isomgr_adma_setbw(struct snd_pcm_substream *substream, + bool is_running); +void tegra_isomgr_adma_renegotiate(void *p, u32 avail_bw); +#else +static inline void tegra_isomgr_adma_register(void) { return; } +static inline void tegra_isomgr_adma_unregister(void) { return; } +static inline void tegra_isomgr_adma_setbw(struct snd_pcm_substream *substream, + bool is_running) { return; } +#endif + +#endif \ No newline at end of file diff --git a/sound/soc/tegra-virt-alt/include/tegra_pcm_alt.h b/sound/soc/tegra-virt-alt/include/tegra_pcm_alt.h new file mode 100644 index 00000000..8136e9d5 --- /dev/null +++ b/sound/soc/tegra-virt-alt/include/tegra_pcm_alt.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + */ + +#ifndef __TEGRA_PCM_ALT_H__ +#define __TEGRA_PCM_ALT_H__ + +#define MAX_DMA_REQ_COUNT 2 + +struct tegra_alt_pcm_dma_params { + unsigned long addr; + unsigned long width; + unsigned long req_sel; + const char *chan_name; + size_t buffer_size; +}; + +int tegra_alt_pcm_platform_register(struct device *dev); +void tegra_alt_pcm_platform_unregister(struct device *dev); + +#endif \ No newline at end of file diff --git a/sound/soc/tegra-virt-alt/nvaudio_ivc/tegra_virt_alt_ivc.c b/sound/soc/tegra-virt-alt/nvaudio_ivc/tegra_virt_alt_ivc.c new file mode 100644 index 00000000..76a234a4 --- /dev/null +++ b/sound/soc/tegra-virt-alt/nvaudio_ivc/tegra_virt_alt_ivc.c @@ -0,0 +1,265 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tegra_virt_alt_ivc.h" +#include "tegra_virt_alt_ivc_common.h" + +static struct nvaudio_ivc_ctxt *saved_ivc_ctxt; + +static void nvaudio_ivc_deinit(struct nvaudio_ivc_ctxt *ictxt); +static int nvaudio_ivc_init(struct nvaudio_ivc_ctxt *ictxt); + +int nvaudio_ivc_send_retry(struct nvaudio_ivc_ctxt *ictxt, + struct nvaudio_ivc_msg *msg, int size) +{ + int err = 0; + int dcnt = 50; + + if (!ictxt || !ictxt->ivck || !msg || !size) + return -EINVAL; + + err = nvaudio_ivc_send(ictxt, msg, size); + + while (err < 0 && dcnt--) { + udelay(100); + err = nvaudio_ivc_send(ictxt, msg, size); + } + return (dcnt < 0) ? -ETIMEDOUT : err; + +} +EXPORT_SYMBOL_GPL(nvaudio_ivc_send_retry); + +int nvaudio_ivc_send(struct nvaudio_ivc_ctxt *ictxt, + struct nvaudio_ivc_msg *msg, int size) +{ + int len = 0; + unsigned long flags = 0; + int err = 0; + int dcnt = 50; + + if (!ictxt || !ictxt->ivck || !msg || !size) + return -EINVAL; + + while (tegra_hv_ivc_channel_notified(ictxt->ivck) != 0) { + dev_err(ictxt->dev, "channel notified returns non zero\n"); + dcnt--; + udelay(100); + if (!dcnt) + return -EIO; + } + + spin_lock_irqsave(&ictxt->ivck_tx_lock, flags); + + if (!tegra_hv_ivc_can_write(ictxt->ivck)) { + err = -EBUSY; + goto fail; + } + + len = tegra_hv_ivc_write(ictxt->ivck, msg, size); + if (len != size) { + pr_err("%s: write Error\n", __func__); + err = -EIO; + goto fail; + } + + err = len; + +fail: + spin_unlock_irqrestore(&ictxt->ivck_tx_lock, flags); + return err; +} +EXPORT_SYMBOL_GPL(nvaudio_ivc_send); + +int nvaudio_ivc_send_receive(struct nvaudio_ivc_ctxt *ictxt, + struct nvaudio_ivc_msg *rx_msg, int size) +{ + + int len = 0; + unsigned long flags = 0, flags1 = 0; + int err = 0; + int dcnt = 50; + int status = -1; + struct nvaudio_ivc_msg *msg = rx_msg; + + if (!ictxt || !ictxt->ivck || !msg || !size) + return -EINVAL; + + while (tegra_hv_ivc_channel_notified(ictxt->ivck) != 0) { + dev_err(ictxt->dev, "channel notified returns non zero\n"); + dcnt--; + udelay(100); + if (!dcnt) + return -EIO; + } + + spin_lock_irqsave(&ictxt->ivck_rx_lock, flags); + spin_lock_irqsave(&ictxt->ivck_tx_lock, flags1); + + if (!tegra_hv_ivc_can_write(ictxt->ivck)) { + err = -EBUSY; + spin_unlock_irqrestore(&ictxt->ivck_tx_lock, flags1); + goto fail; + } + + len = tegra_hv_ivc_write(ictxt->ivck, msg, size); + if (len != size) { + pr_err("%s: write Error\n", __func__); + err = -EIO; + spin_unlock_irqrestore(&ictxt->ivck_tx_lock, flags1); + goto fail; + } + spin_unlock_irqrestore(&ictxt->ivck_tx_lock, flags1); + + err = readx_poll_timeout_atomic(tegra_hv_ivc_can_read, ictxt->ivck, + status, status, 10, NVAUDIO_IVC_WAIT_TIMEOUT); + + if (err == -ETIMEDOUT) { + pr_err("%s: Waited too long for msg reply\n", __func__); + goto fail; + } + + /* Message available */ + memset(rx_msg, 0, sizeof(struct nvaudio_ivc_msg)); + len = tegra_hv_ivc_read(ictxt->ivck, + rx_msg, + sizeof(struct nvaudio_ivc_msg)); + if (len != sizeof(struct nvaudio_ivc_msg)) { + dev_err(ictxt->dev, "IVC read failure (msg size error)\n"); + err = -1; + goto fail; + } + err = len; + +fail: + spin_unlock_irqrestore(&ictxt->ivck_rx_lock, flags); + + return err; + +} +EXPORT_SYMBOL_GPL(nvaudio_ivc_send_receive); + +/* Every communication with the server is identified + * with this ivc context. + * There can be one outstanding request to the server per + * ivc context. + */ +struct nvaudio_ivc_ctxt *nvaudio_ivc_alloc_ctxt(struct device *dev) +{ + struct nvaudio_ivc_ctxt *ictxt = NULL; + + if (saved_ivc_ctxt) + return saved_ivc_ctxt; + + ictxt = devm_kzalloc(dev, sizeof(struct nvaudio_ivc_ctxt), + GFP_KERNEL); + if (ictxt == NULL) { + dev_err(dev, "unable to allocate mem for ivc context\n"); + return NULL; + } + + saved_ivc_ctxt = ictxt; + ictxt->dev = dev; + ictxt->timeout = 250; /* Not used in polling */ + if (nvaudio_ivc_init(ictxt) != 0) { + dev_err(dev, "nvaudio_ivc_init failed\n"); + goto fail; + } + + spin_lock_init(&ictxt->ivck_rx_lock); + spin_lock_init(&ictxt->ivck_tx_lock); + + tegra_hv_ivc_channel_reset(ictxt->ivck); + + return ictxt; +fail: + nvaudio_ivc_free_ctxt(dev); + return NULL; +} +EXPORT_SYMBOL_GPL(nvaudio_ivc_alloc_ctxt); + +struct nvaudio_ivc_ctxt *nvaudio_get_ivc_alloc_ctxt(void) +{ + if (saved_ivc_ctxt) + return saved_ivc_ctxt; + + pr_err("%s: ivc ctxt not allocated\n", __func__); + return NULL; +} +EXPORT_SYMBOL_GPL(nvaudio_get_ivc_alloc_ctxt); + +/* hook to domain destroy */ +void nvaudio_ivc_free_ctxt(struct device *dev) +{ + if (saved_ivc_ctxt) { + nvaudio_ivc_deinit(saved_ivc_ctxt); + devm_kfree(dev, saved_ivc_ctxt); + saved_ivc_ctxt = NULL; + } +} +EXPORT_SYMBOL_GPL(nvaudio_ivc_free_ctxt); + +static void nvaudio_ivc_deinit(struct nvaudio_ivc_ctxt *ictxt) +{ + if (ictxt) + tegra_hv_ivc_unreserve(ictxt->ivck); +} + +static int nvaudio_ivc_init(struct nvaudio_ivc_ctxt *ictxt) +{ + int err, ivc_queue; + struct device_node *dn, *hv_dn; + struct device *dev = ictxt->dev; + struct tegra_hv_ivc_cookie *ivck = NULL; + + dn = dev->of_node; + if (dn == NULL) { + dev_err(dev, "No OF data\n"); + return -EINVAL; + } + + hv_dn = of_parse_phandle(dn, "ivc_queue", 0); + if (hv_dn == NULL) { + dev_err(dev, "Failed to parse phandle of ivc prop\n"); + return -EINVAL; + } + + err = of_property_read_u32_index(dn, "ivc_queue", 1, &ivc_queue); + if (err != 0) { + dev_err(dev, "Failed to read IVC property ID\n"); + of_node_put(hv_dn); + return -EINVAL; + } + + ivck = tegra_hv_ivc_reserve(hv_dn, ivc_queue, NULL); + + if (IS_ERR_OR_NULL(ivck)) { + dev_err(dev, "Failed to reserve ivc queue %d\n", ivc_queue); + if (ivck == ERR_PTR(-EPROBE_DEFER)) + return -EPROBE_DEFER; + else + return -EINVAL; + } + + of_node_put(hv_dn); + + ictxt->ivc_queue = ivc_queue; + ictxt->ivck = ivck; + + return 0; +} + +MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/sound/soc/tegra-virt-alt/nvaudio_ivc/tegra_virt_alt_ivc.h b/sound/soc/tegra-virt-alt/nvaudio_ivc/tegra_virt_alt_ivc.h new file mode 100644 index 00000000..c4a35336 --- /dev/null +++ b/sound/soc/tegra-virt-alt/nvaudio_ivc/tegra_virt_alt_ivc.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + */ + +#ifndef __TEGRA_VIRT_ALT_IVC_H__ +#define __TEGRA_VIRT_ALT_IVC_H__ + +#include "tegra_virt_alt_ivc_common.h" + +#define NVAUDIO_IVC_WAIT_TIMEOUT 1000000 +struct nvaudio_ivc_dev; + +struct nvaudio_ivc_ctxt { + struct tegra_hv_ivc_cookie *ivck; + struct device *dev; + int ivc_queue; + wait_queue_head_t wait; + int timeout; + enum rx_state_t rx_state; + struct nvaudio_ivc_dev *ivcdev; + spinlock_t ivck_rx_lock; + spinlock_t ivck_tx_lock; + spinlock_t lock; +}; + +void nvaudio_ivc_rx(struct tegra_hv_ivc_cookie *ivck); + +struct nvaudio_ivc_ctxt *nvaudio_ivc_alloc_ctxt(struct device *dev); + +void nvaudio_ivc_free_ctxt(struct device *dev); + +int nvaudio_ivc_send(struct nvaudio_ivc_ctxt *ictxt, + struct nvaudio_ivc_msg *msg, + int size); + +int nvaudio_ivc_send_retry(struct nvaudio_ivc_ctxt *ictxt, + struct nvaudio_ivc_msg *msg, + int size); + +int nvaudio_ivc_send_receive(struct nvaudio_ivc_ctxt *ictxt, + struct nvaudio_ivc_msg *msg, + int size); + +int tegra124_virt_xbar_set_ivc(struct nvaudio_ivc_ctxt *ictxt, + int rx_idx, + int tx_idx); +int tegra124_virt_xbar_get_ivc(struct nvaudio_ivc_ctxt *ictxt, + int rx_idx, + int *tx_idx); + +struct nvaudio_ivc_ctxt *nvaudio_get_ivc_alloc_ctxt(void); + +#endif \ No newline at end of file diff --git a/sound/soc/tegra-virt-alt/nvaudio_ivc/tegra_virt_alt_ivc_common.h b/sound/soc/tegra-virt-alt/nvaudio_ivc/tegra_virt_alt_ivc_common.h new file mode 100644 index 00000000..6e2650b6 --- /dev/null +++ b/sound/soc/tegra-virt-alt/nvaudio_ivc/tegra_virt_alt_ivc_common.h @@ -0,0 +1,279 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + */ + +#ifndef __TEGRA_VIRT_ALT_IVC_COMMON_H__ +#define __TEGRA_VIRT_ALT_IVC_COMMON_H__ + +#include + +#define TEGRA210_MIXER_AXBAR_RX_MAX 10 + +enum ivc_audio_err_t { + NVAUDIO_ERR_OK, + NVAUDIO_ERR_SERVER_STATE, + NVAUDIO_ERR_ARGS, + NVAUDIO_ERR_REQ, + NVAUDIO_ERR_UNSUPPORTED_REQ +}; + +enum rx_state_t { + RX_INIT, + RX_PENDING, + RX_AVAIL, + RX_DONE, +}; + +enum ivc_audio_regdump_t { + NVAUDIO_REGDUMP_RX_TX, + NVAUDIO_REGDUMP_RX, + NVAUDIO_REGDUMP_TX, + NVAUDIO_REGDUMP_GLOBAL +}; + +enum ivc_adsp_assert { + ASSERT, /* SET */ + DEASSERT /* CLEAR */ +}; + +enum ape_ahub_blocks_t { + ADMAIF1 = 1, + ADMAIF2, + ADMAIF3, + ADMAIF4, + ADMAIF5, + ADMAIF6, + ADMAIF7, + ADMAIF8, + ADMAIF9, + ADMAIF10, + ADMAIF11, + ADMAIF12, + ADMAIF13, + ADMAIF14, + ADMAIF15, + ADMAIF16, + ADMAIF17, + ADMAIF18, + ADMAIF19, + ADMAIF20, + AMX1, + AMX2, + AMX3, + AMX4, + ADX1, + ADX2, + ADX3, + ADX4, + MIXER1, + I2S1, + I2S2, + I2S3, + I2S4, + I2S5, + I2S6, + ASRC1, + SFC1, + SFC2, + SFC3, + SFC4, + AFC1, + AFC2, + AFC3, + AFC4, + AFC5, + AFC6, + MVC1, + MVC2, + ARAD1, + MAX_AHUB_RESOURCES +}; + +enum nvaudio_ivc_cmd_t { + NVAUDIO_DMAIF_SET_RXCIF, + NVAUDIO_DMAIF_SET_TXCIF, + NVAUDIO_START_PLAYBACK, + NVAUDIO_STOP_PLAYBACK, + NVAUDIO_START_CAPTURE, + NVAUDIO_STOP_CAPTURE, + NVAUDIO_XBAR_SET_ROUTE, + NVAUDIO_XBAR_GET_ROUTE, + NVAUDIO_AMIXER_SET_RX_GAIN, + NVAUDIO_AMIXER_SET_TX_ADDER_CONFIG, + NVAUDIO_AMIXER_SET_ENABLE, + NVAUDIO_AMIXER_GET_TX_ADDER_CONFIG, + NVAUDIO_AMIXER_GET_ENABLE, + NVAUDIO_SFC_SET_IN_FREQ, + NVAUDIO_SFC_GET_IN_FREQ, + NVAUDIO_SFC_SET_OUT_FREQ, + NVAUDIO_SFC_GET_OUT_FREQ, + NVAUDIO_ASRC_SET_INT_RATIO, + NVAUDIO_ASRC_GET_INT_RATIO, + NVAUDIO_ASRC_SET_FRAC_RATIO, + NVAUDIO_ASRC_GET_FRAC_RATIO, + NVAUDIO_ASRC_SET_RATIO_SOURCE, + NVAUDIO_ASRC_GET_RATIO_SOURCE, + NVAUDIO_ASRC_SET_STREAM_ENABLE, + NVAUDIO_ASRC_GET_STREAM_ENABLE, + NVAUDIO_ASRC_SET_HWCOMP_DISABLE, + NVAUDIO_ASRC_GET_HWCOMP_DISABLE, + NVAUDIO_ASRC_SET_INPUT_THRESHOLD, + NVAUDIO_ASRC_GET_INPUT_THRESHOLD, + NVAUDIO_ASRC_SET_OUTPUT_THRESHOLD, + NVAUDIO_ASRC_GET_OUTPUT_THRESHOLD, + NVAUDIO_ARAD_SET_LANE_SRC, + NVAUDIO_ARAD_GET_LANE_SRC, + NVAUDIO_ARAD_SET_PRESCALAR, + NVAUDIO_ARAD_GET_PRESCALAR, + NVAUDIO_ARAD_SET_LANE_ENABLE, + NVAUDIO_ARAD_GET_LANE_ENABLE, + NVAUDIO_ARAD_GET_LANE_RATIO, + NVAUDIO_AMX_SET_INPUT_STREAM_ENABLE, + NVAUDIO_I2S_SET_LOOPBACK_ENABLE, + NVAUDIO_I2S_GET_LOOPBACK_ENABLE, + NVAUDIO_I2S_GET_RATE, + NVAUDIO_I2S_SET_RATE, + NVAUDIO_ASRC_SET_RATIO, + NVAUDIO_ASRC_GET_RATIO, + NVAUDIO_MVC_SET_CURVETYPE, + NVAUDIO_MVC_GET_CURVETYPE, + NVAUDIO_MVC_SET_TAR_VOL, + NVAUDIO_MVC_GET_TAR_VOL, + NVAUDIO_MVC_SET_MUTE, + NVAUDIO_MVC_GET_MUTE, + NVAUDIO_AMIXER_GET_RX_GAIN, + NVAUDIO_AMIXER_SET_RX_DURATION, + NVAUDIO_AMIXER_GET_RX_DURATION, + NVAUDIO_AHUB_BLOCK_REGDUMP, + NVAUDIO_AMIXER_SET_FADE, + NVAUDIO_AMIXER_GET_FADE_STATUS, + NVAUDIO_AMX_SET_INPUT_IDLE_CNT, + NVAUDIO_ADSP_RESET, + NVAUDIO_ADMA_BLOCK_REGDUMP, + NVAUDIO_CMD_MAX, +}; + +struct nvaudio_ivc_t210_amx_info { + int32_t amx_id; + uint32_t amx_stream_id; + uint32_t amx_stream_enable; +}; + +struct nvaudio_ivc_t210_i2s_info { + int32_t i2s_id; + uint32_t i2s_loopback_enable; + uint32_t i2s_rate; +}; + +struct nvaudio_ivc_t210_amixer_info { + int32_t id; + uint32_t rx_idx; + uint32_t gain; + uint32_t adder_idx; + uint32_t adder_rx_idx; + uint32_t adder_rx_idx_enable; + uint32_t is_instant_gain; + uint32_t duration_n3; + uint32_t enable; +}; + +struct nvaudio_ivc_t210_sfc_info { + int32_t id; + uint32_t in_freq; + uint32_t out_freq; +}; + +struct nvaudio_ivc_t210_mvc_info { + int32_t id; + uint32_t curve_type; + uint32_t tar_vol; + uint32_t mute; +}; + +struct nvaudio_ivc_t186_asrc_info { + int32_t id; + int32_t stream_num; + uint32_t int_ratio; + uint32_t frac_ratio; + uint32_t input_threshold; + uint32_t output_threshold; + uint32_t hwcomp_disable; + uint32_t stream_enable; + uint32_t ratio_source; +}; + +struct nvaudio_ivc_t186_arad_info { + int32_t id; + uint32_t lane_id; + uint32_t int_ratio; + uint32_t frac_ratio; + int32_t num_source; + int32_t den_source; + int32_t num_prescalar; + int32_t den_prescalar; + uint32_t lane_enable; +}; + +struct nvaudio_ivc_xbar_link { + int32_t rx_reg; + uint32_t tx_value; + uint32_t tx_idx; + uint32_t bit_pos; +}; + +struct nvaudio_ivc_dmaif_info { + int32_t id; + int32_t value; +}; + +struct nvaudio_ivc_ahub_block { + uint32_t block_id; + uint32_t dump_cmd; + uint32_t stream_id; +}; + +struct nvaudio_ivc_t210_amixer_fade_info { + uint32_t id; + uint32_t rx_idx; + uint32_t gain_level[TEGRA210_MIXER_AXBAR_RX_MAX]; + uint32_t duration_n3[TEGRA210_MIXER_AXBAR_RX_MAX]; +}; + +struct nvaudio_ivc_t210_amixer_fade_status { + uint32_t id; + int32_t status[TEGRA210_MIXER_AXBAR_RX_MAX]; +}; + +struct nvaudio_ivc_adsp_reset { + uint32_t reset_req; +}; + +struct nvaudio_ivc_t210_adma_info { + uint32_t channel_num; +}; + +struct nvaudio_ivc_msg { + int32_t channel_id; + enum nvaudio_ivc_cmd_t cmd; + union { + struct nvaudio_ivc_dmaif_info dmaif_info; + struct nvaudio_ivc_t210_amixer_info amixer_info; + struct nvaudio_ivc_t210_sfc_info sfc_info; + struct nvaudio_ivc_t210_mvc_info mvc_info; + struct nvaudio_ivc_t186_asrc_info asrc_info; + struct nvaudio_ivc_t186_arad_info arad_info; + struct nvaudio_ivc_t210_amx_info amx_info; + struct nvaudio_ivc_t210_i2s_info i2s_info; + struct nvaudio_ivc_xbar_link xbar_info; + struct nvaudio_ivc_ahub_block ahub_block_info; + struct nvaudio_ivc_t210_amixer_fade_info fade_info; + struct nvaudio_ivc_t210_amixer_fade_status fade_status; + struct nvaudio_ivc_adsp_reset adsp_reset_info; + struct nvaudio_ivc_t210_adma_info adma_info; + } params; + bool ack_required; + int32_t err; +}; + +#endif \ No newline at end of file diff --git a/sound/soc/tegra-virt-alt/tegra210_virt_alt_admaif.c b/sound/soc/tegra-virt-alt/tegra210_virt_alt_admaif.c new file mode 100644 index 00000000..0a4f4c2c --- /dev/null +++ b/sound/soc/tegra-virt-alt/tegra210_virt_alt_admaif.c @@ -0,0 +1,949 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include "tegra210_virt_alt_admaif.h" +#include "tegra_virt_alt_ivc.h" +#include "tegra_pcm_alt.h" +#include "tegra_asoc_xbar_virt_alt.h" +#include "tegra_asoc_util_virt_alt.h" + +#define NUM_META_CONTROLS 3 + +static const unsigned int tegra210_rates[] = { + 8000, 11025, 12000, 16000, 22050, + 24000, 32000, 44100, 48000, 64000, + 88200, 96000, 176400, 192000 +}; + +static const struct snd_pcm_hw_constraint_list tegra210_rate_constraints = { + .count = ARRAY_SIZE(tegra210_rates), + .list = tegra210_rates, +}; + +static struct nvaudio_ivc_ctxt *svd_cntxt; + +static struct tegra210_admaif *admaif; +static int tegra210_admaif_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct device *dev = dai->dev; + struct tegra210_virt_admaif_client_data *data = + &admaif->client_data; + struct tegra210_virt_audio_cif cif_conf; + struct nvaudio_ivc_msg msg; + unsigned int value; + int err; + + memset(&cif_conf, 0, sizeof(struct tegra210_virt_audio_cif)); + cif_conf.audio_channels = params_channels(params); + cif_conf.client_channels = params_channels(params); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_8; + cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_8; + break; + case SNDRV_PCM_FORMAT_S16_LE: + cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_16; + cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_16; + break; + case SNDRV_PCM_FORMAT_S24_LE: + cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_24; + cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_24; + break; + case SNDRV_PCM_FORMAT_S32_LE: + cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_32; + cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_32; + break; + default: + dev_err(dev, "Wrong format!\n"); + return -EINVAL; + } + cif_conf.direction = substream->stream; + + value = (cif_conf.threshold << + TEGRA210_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | + ((cif_conf.audio_channels - 1) << + TEGRA210_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | + ((cif_conf.client_channels - 1) << + TEGRA210_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | + (cif_conf.audio_bits << + TEGRA210_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | + (cif_conf.client_bits << + TEGRA210_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) | + (cif_conf.expand << + TEGRA210_AUDIOCIF_CTRL_EXPAND_SHIFT) | + (cif_conf.stereo_conv << + TEGRA210_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) | + (cif_conf.replicate << + TEGRA210_AUDIOCIF_CTRL_REPLICATE_SHIFT) | + (cif_conf.truncate << + TEGRA210_AUDIOCIF_CTRL_TRUNCATE_SHIFT) | + (cif_conf.mono_conv << + TEGRA210_AUDIOCIF_CTRL_MONO_CONV_SHIFT); + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.params.dmaif_info.id = dai->id; + msg.params.dmaif_info.value = value; + if (!cif_conf.direction) + msg.cmd = NVAUDIO_DMAIF_SET_TXCIF; + else + msg.cmd = NVAUDIO_DMAIF_SET_RXCIF; + + err = nvaudio_ivc_send(data->hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + + if (err < 0) + pr_err("%s: error on ivc_send\n", __func__); + + return 0; +} + +static void tegra210_admaif_start_playback(struct snd_soc_dai *dai) +{ + struct tegra210_virt_admaif_client_data *data = + &admaif->client_data; + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_START_PLAYBACK; + msg.params.dmaif_info.id = dai->id; + msg.ack_required = true; + err = nvaudio_ivc_send_receive(data->hivc_client, + &msg, sizeof(struct nvaudio_ivc_msg)); + + if (err < 0) + pr_err("%s: error on ivc_send\n", __func__); +} + +static void tegra210_admaif_stop_playback(struct snd_soc_dai *dai) +{ + struct tegra210_virt_admaif_client_data *data = + &admaif->client_data; + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_STOP_PLAYBACK; + msg.params.dmaif_info.id = dai->id; + + msg.ack_required = true; + err = nvaudio_ivc_send_receive(data->hivc_client, + &msg, sizeof(struct nvaudio_ivc_msg)); + + if (err < 0) + pr_err("%s: error on ivc_send\n", __func__); +} + +static void tegra210_admaif_start_capture(struct snd_soc_dai *dai) +{ + struct tegra210_virt_admaif_client_data *data = + &admaif->client_data; + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_START_CAPTURE; + msg.params.dmaif_info.id = dai->id; + + msg.ack_required = true; + err = nvaudio_ivc_send_receive(data->hivc_client, + &msg, sizeof(struct nvaudio_ivc_msg)); + + if (err < 0) + pr_err("%s: error on ivc_send\n", __func__); +} + +static void tegra210_admaif_stop_capture(struct snd_soc_dai *dai) +{ + struct tegra210_virt_admaif_client_data *data = + &admaif->client_data; + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_STOP_CAPTURE; + msg.params.dmaif_info.id = dai->id; + + msg.ack_required = true; + err = nvaudio_ivc_send_receive(data->hivc_client, + &msg, sizeof(struct nvaudio_ivc_msg)); + if (err < 0) + pr_err("%s: error on ivc_send\n", __func__); +} + +static int tegra210_admaif_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + int err; + pr_info("Pcm trigger for admaif%d %s: cmd_id %d\n", dai->id+1, + (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? + "playback":"capture", cmd); + + err = snd_dmaengine_pcm_trigger(substream, cmd); + if (err) + return err; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + tegra210_admaif_start_playback(dai); + else + tegra210_admaif_start_capture(dai); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + tegra210_admaif_stop_playback(dai); + else + tegra210_admaif_stop_capture(dai); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int tegra210_admaif_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &tegra210_rate_constraints); +} + +static struct snd_soc_dai_ops tegra210_admaif_dai_ops = { + .hw_params = tegra210_admaif_hw_params, + .trigger = tegra210_admaif_trigger, + .startup = tegra210_admaif_startup, +}; + +static int tegra210_admaif_dai_probe(struct snd_soc_dai *dai) +{ + dai->capture_dma_data = &admaif->capture_dma_data[dai->id]; + dai->playback_dma_data = &admaif->playback_dma_data[dai->id]; + + return 0; +} + +#define ADMAIF_DAI(id) \ + { \ + .name = "ADMAIF" #id, \ + .probe = tegra210_admaif_dai_probe, \ + .playback = { \ + .stream_name = "Playback " #id, \ + .channels_min = 1, \ + .channels_max = 16, \ + .rates = SNDRV_PCM_RATE_8000_192000, \ + .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + }, \ + .capture = { \ + .stream_name = "Capture " #id, \ + .channels_min = 1, \ + .channels_max = 16, \ + .rates = SNDRV_PCM_RATE_8000_192000, \ + .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + }, \ + .ops = &tegra210_admaif_dai_ops, \ + } + +static struct snd_soc_dai_driver tegra210_admaif_dais[] = { + ADMAIF_DAI(1), + ADMAIF_DAI(2), + ADMAIF_DAI(3), + ADMAIF_DAI(4), + ADMAIF_DAI(5), + ADMAIF_DAI(6), + ADMAIF_DAI(7), + ADMAIF_DAI(8), + ADMAIF_DAI(9), + ADMAIF_DAI(10), + ADMAIF_DAI(11), + ADMAIF_DAI(12), + ADMAIF_DAI(13), + ADMAIF_DAI(14), + ADMAIF_DAI(15), + ADMAIF_DAI(16), + ADMAIF_DAI(17), + ADMAIF_DAI(18), + ADMAIF_DAI(19), + ADMAIF_DAI(20), +}; + +static const struct soc_enum tegra_virt_t186_asrc_source = + SOC_ENUM_SINGLE_EXT(NUM_ASRC_MODE, tegra186_asrc_ratio_source_text); + +static const struct soc_enum tegra_virt_t186_arad_source = + SOC_VALUE_ENUM_SINGLE(0, 0, 0, NUM_ARAD_SOURCES, + tegra186_arad_mux_text, + tegra186_arad_mux_value); + +static const struct soc_enum tegra_virt_t210_mvc_curvetype = + SOC_ENUM_SINGLE_EXT(NUM_MVC_CURVETYPE, tegra210_mvc_curve_type_text); + +static const struct snd_kcontrol_new tegra_virt_t210ref_controls[] = { +MIXER_GAIN_CTRL_DECL("RX1 Gain", 0x00), +MIXER_GAIN_CTRL_DECL("RX2 Gain", 0x01), +MIXER_GAIN_CTRL_DECL("RX3 Gain", 0x02), +MIXER_GAIN_CTRL_DECL("RX4 Gain", 0x03), +MIXER_GAIN_CTRL_DECL("RX5 Gain", 0x04), +MIXER_GAIN_CTRL_DECL("RX6 Gain", 0x05), +MIXER_GAIN_CTRL_DECL("RX7 Gain", 0x06), +MIXER_GAIN_CTRL_DECL("RX8 Gain", 0x07), +MIXER_GAIN_CTRL_DECL("RX9 Gain", 0x08), +MIXER_GAIN_CTRL_DECL("RX10 Gain", 0x09), + +MIXER_GAIN_INSTANT_CTRL_DECL("RX1 Gain Instant", 0x00), +MIXER_GAIN_INSTANT_CTRL_DECL("RX2 Gain Instant", 0x01), +MIXER_GAIN_INSTANT_CTRL_DECL("RX3 Gain Instant", 0x02), +MIXER_GAIN_INSTANT_CTRL_DECL("RX4 Gain Instant", 0x03), +MIXER_GAIN_INSTANT_CTRL_DECL("RX5 Gain Instant", 0x04), +MIXER_GAIN_INSTANT_CTRL_DECL("RX6 Gain Instant", 0x05), +MIXER_GAIN_INSTANT_CTRL_DECL("RX7 Gain Instant", 0x06), +MIXER_GAIN_INSTANT_CTRL_DECL("RX8 Gain Instant", 0x07), +MIXER_GAIN_INSTANT_CTRL_DECL("RX9 Gain Instant", 0x08), +MIXER_GAIN_INSTANT_CTRL_DECL("RX10 Gain Instant", 0x09), + +MIXER_DURATION_CTRL_DECL("RX1 Duration", 0x00), +MIXER_DURATION_CTRL_DECL("RX2 Duration", 0x01), +MIXER_DURATION_CTRL_DECL("RX3 Duration", 0x02), +MIXER_DURATION_CTRL_DECL("RX4 Duration", 0x03), +MIXER_DURATION_CTRL_DECL("RX5 Duration", 0x04), +MIXER_DURATION_CTRL_DECL("RX6 Duration", 0x05), +MIXER_DURATION_CTRL_DECL("RX7 Duration", 0x06), +MIXER_DURATION_CTRL_DECL("RX8 Duration", 0x07), +MIXER_DURATION_CTRL_DECL("RX9 Duration", 0x08), +MIXER_DURATION_CTRL_DECL("RX10 Duration", 0x09), + +MIXER_ENABLE_CTRL_DECL("Mixer Enable", 0x00), +MIXER_SET_FADE("Mixer fade", 0x00), +MIXER_GET_FADE_STATUS("Mixer fade status", 0x00), + +SFC_IN_FREQ_CTRL_DECL("SFC1 input rate", 0x00), +SFC_IN_FREQ_CTRL_DECL("SFC2 input rate", 0x01), +SFC_IN_FREQ_CTRL_DECL("SFC3 input rate", 0x02), +SFC_IN_FREQ_CTRL_DECL("SFC4 input rate", 0x03), + +SFC_OUT_FREQ_CTRL_DECL("SFC1 output rate", 0x00), +SFC_OUT_FREQ_CTRL_DECL("SFC2 output rate", 0x01), +SFC_OUT_FREQ_CTRL_DECL("SFC3 output rate", 0x02), +SFC_OUT_FREQ_CTRL_DECL("SFC4 output rate", 0x03), + +MVC_CURVE_TYPE_CTRL_DECL("MVC1 Curve Type", 0x00, + &tegra_virt_t210_mvc_curvetype), +MVC_CURVE_TYPE_CTRL_DECL("MVC2 Curve Type", 0x01, + &tegra_virt_t210_mvc_curvetype), + +MVC_TAR_VOL_CTRL_DECL("MVC1 Vol", 0x00), +MVC_TAR_VOL_CTRL_DECL("MVC2 Vol", 0x01), + +MVC_MUTE_CTRL_DECL("MVC1 Mute", 0x00), +MVC_MUTE_CTRL_DECL("MVC2 Mute", 0x01), + +AMX_ENABLE_CTRL_DECL("AMX1-1 Enable", 0x01, 0x01), +AMX_ENABLE_CTRL_DECL("AMX1-2 Enable", 0x01, 0x02), +AMX_ENABLE_CTRL_DECL("AMX1-3 Enable", 0x01, 0x03), +AMX_ENABLE_CTRL_DECL("AMX1-4 Enable", 0x01, 0x04), + +AMX_ENABLE_CTRL_DECL("AMX2-1 Enable", 0x02, 0x01), +AMX_ENABLE_CTRL_DECL("AMX2-2 Enable", 0x02, 0x02), +AMX_ENABLE_CTRL_DECL("AMX2-3 Enable", 0x02, 0x03), +AMX_ENABLE_CTRL_DECL("AMX2-4 Enable", 0x02, 0x04), + +I2S_LOOPBACK_ENABLE_CTRL_DECL("I2S1 Loopback", 0x01), +I2S_LOOPBACK_ENABLE_CTRL_DECL("I2S2 Loopback", 0x02), +I2S_LOOPBACK_ENABLE_CTRL_DECL("I2S3 Loopback", 0x03), +I2S_LOOPBACK_ENABLE_CTRL_DECL("I2S4 Loopback", 0x04), +I2S_LOOPBACK_ENABLE_CTRL_DECL("I2S5 Loopback", 0x05), + +REGDUMP_CTRL_DECL("ADMAIF1 regdump", ADMAIF1, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF2 regdump", ADMAIF2, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF3 regdump", ADMAIF3, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF4 regdump", ADMAIF4, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF5 regdump", ADMAIF5, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF6 regdump", ADMAIF6, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF7 regdump", ADMAIF7, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF8 regdump", ADMAIF8, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF9 regdump", ADMAIF9, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF10 regdump", ADMAIF10, 0, NVAUDIO_REGDUMP_RX_TX), + +REGDUMP_CTRL_DECL("AMX1 regdump", AMX1, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("AMX2 regdump", AMX2, 0, NVAUDIO_REGDUMP_RX_TX), + +REGDUMP_CTRL_DECL("ADX1 regdump", ADX1, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADX2 regdump", ADX2, 0, NVAUDIO_REGDUMP_RX_TX), + +REGDUMP_CTRL_DECL("MIXER1-1 RX regdump", MIXER1, 0, NVAUDIO_REGDUMP_RX), +REGDUMP_CTRL_DECL("MIXER1-2 RX regdump", MIXER1, 1, NVAUDIO_REGDUMP_RX), +REGDUMP_CTRL_DECL("MIXER1-3 RX regdump", MIXER1, 2, NVAUDIO_REGDUMP_RX), +REGDUMP_CTRL_DECL("MIXER1-4 RX regdump", MIXER1, 3, NVAUDIO_REGDUMP_RX), +REGDUMP_CTRL_DECL("MIXER1-5 RX regdump", MIXER1, 4, NVAUDIO_REGDUMP_RX), +REGDUMP_CTRL_DECL("MIXER1-6 RX regdump", MIXER1, 5, NVAUDIO_REGDUMP_RX), +REGDUMP_CTRL_DECL("MIXER1-7 RX regdump", MIXER1, 6, NVAUDIO_REGDUMP_RX), +REGDUMP_CTRL_DECL("MIXER1-8 RX regdump", MIXER1, 7, NVAUDIO_REGDUMP_RX), +REGDUMP_CTRL_DECL("MIXER1-9 RX regdump", MIXER1, 8, NVAUDIO_REGDUMP_RX), +REGDUMP_CTRL_DECL("MIXER1-10 RX regdump", MIXER1, 9, NVAUDIO_REGDUMP_RX), + +REGDUMP_CTRL_DECL("MIXER1-1 TX regdump", MIXER1, 0, NVAUDIO_REGDUMP_TX), +REGDUMP_CTRL_DECL("MIXER1-2 TX regdump", MIXER1, 1, NVAUDIO_REGDUMP_TX), +REGDUMP_CTRL_DECL("MIXER1-3 TX regdump", MIXER1, 2, NVAUDIO_REGDUMP_TX), +REGDUMP_CTRL_DECL("MIXER1-4 TX regdump", MIXER1, 3, NVAUDIO_REGDUMP_TX), +REGDUMP_CTRL_DECL("MIXER1-5 TX regdump", MIXER1, 4, NVAUDIO_REGDUMP_TX), + +REGDUMP_CTRL_DECL("I2S1 regdump", I2S1, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("I2S2 regdump", I2S2, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("I2S3 regdump", I2S3, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("I2S4 regdump", I2S4, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("I2S5 regdump", I2S5, 0, NVAUDIO_REGDUMP_RX_TX), + +REGDUMP_CTRL_DECL("SFC1 regdump", SFC1, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("SFC2 regdump", SFC2, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("SFC3 regdump", SFC3, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("SFC4 regdump", SFC4, 0, NVAUDIO_REGDUMP_RX_TX), + +REGDUMP_CTRL_DECL("MVC1 regdump", MVC1, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("MVC2 regdump", MVC2, 0, NVAUDIO_REGDUMP_RX_TX), + +ADMA_REGDUMP_CTRL_DECL("ADMA1 regdump", 1), +ADMA_REGDUMP_CTRL_DECL("ADMA2 regdump", 2), +ADMA_REGDUMP_CTRL_DECL("ADMA3 regdump", 3), +ADMA_REGDUMP_CTRL_DECL("ADMA4 regdump", 4), +ADMA_REGDUMP_CTRL_DECL("ADMA5 regdump", 5), +ADMA_REGDUMP_CTRL_DECL("ADMA6 regdump", 6), +ADMA_REGDUMP_CTRL_DECL("ADMA7 regdump", 7), +ADMA_REGDUMP_CTRL_DECL("ADMA8 regdump", 8), +ADMA_REGDUMP_CTRL_DECL("ADMA9 regdump", 9), +ADMA_REGDUMP_CTRL_DECL("ADMA10 regdump", 10), +ADMA_REGDUMP_CTRL_DECL("ADMA11 regdump", 11), +ADMA_REGDUMP_CTRL_DECL("ADMA12 regdump", 12), +ADMA_REGDUMP_CTRL_DECL("ADMA13 regdump", 13), +ADMA_REGDUMP_CTRL_DECL("ADMA14 regdump", 14), +ADMA_REGDUMP_CTRL_DECL("ADMA15 regdump", 15), +ADMA_REGDUMP_CTRL_DECL("ADMA16 regdump", 16), +ADMA_REGDUMP_CTRL_DECL("ADMA17 regdump", 17), +ADMA_REGDUMP_CTRL_DECL("ADMA18 regdump", 18), +ADMA_REGDUMP_CTRL_DECL("ADMA19 regdump", 19), +ADMA_REGDUMP_CTRL_DECL("ADMA20 regdump", 20), + +}; + +static const struct snd_kcontrol_new tegra_virt_t186ref_controls[] = { +MIXER_GAIN_CTRL_DECL("RX1 Gain", 0x00), +MIXER_GAIN_CTRL_DECL("RX2 Gain", 0x01), +MIXER_GAIN_CTRL_DECL("RX3 Gain", 0x02), +MIXER_GAIN_CTRL_DECL("RX4 Gain", 0x03), +MIXER_GAIN_CTRL_DECL("RX5 Gain", 0x04), +MIXER_GAIN_CTRL_DECL("RX6 Gain", 0x05), +MIXER_GAIN_CTRL_DECL("RX7 Gain", 0x06), +MIXER_GAIN_CTRL_DECL("RX8 Gain", 0x07), +MIXER_GAIN_CTRL_DECL("RX9 Gain", 0x08), +MIXER_GAIN_CTRL_DECL("RX10 Gain", 0x09), + +MIXER_GAIN_INSTANT_CTRL_DECL("RX1 Gain Instant", 0x00), +MIXER_GAIN_INSTANT_CTRL_DECL("RX2 Gain Instant", 0x01), +MIXER_GAIN_INSTANT_CTRL_DECL("RX3 Gain Instant", 0x02), +MIXER_GAIN_INSTANT_CTRL_DECL("RX4 Gain Instant", 0x03), +MIXER_GAIN_INSTANT_CTRL_DECL("RX5 Gain Instant", 0x04), +MIXER_GAIN_INSTANT_CTRL_DECL("RX6 Gain Instant", 0x05), +MIXER_GAIN_INSTANT_CTRL_DECL("RX7 Gain Instant", 0x06), +MIXER_GAIN_INSTANT_CTRL_DECL("RX8 Gain Instant", 0x07), +MIXER_GAIN_INSTANT_CTRL_DECL("RX9 Gain Instant", 0x08), +MIXER_GAIN_INSTANT_CTRL_DECL("RX10 Gain Instant", 0x09), + +MIXER_DURATION_CTRL_DECL("RX1 Duration", 0x00), +MIXER_DURATION_CTRL_DECL("RX2 Duration", 0x01), +MIXER_DURATION_CTRL_DECL("RX3 Duration", 0x02), +MIXER_DURATION_CTRL_DECL("RX4 Duration", 0x03), +MIXER_DURATION_CTRL_DECL("RX5 Duration", 0x04), +MIXER_DURATION_CTRL_DECL("RX6 Duration", 0x05), +MIXER_DURATION_CTRL_DECL("RX7 Duration", 0x06), +MIXER_DURATION_CTRL_DECL("RX8 Duration", 0x07), +MIXER_DURATION_CTRL_DECL("RX9 Duration", 0x08), +MIXER_DURATION_CTRL_DECL("RX10 Duration", 0x09), + +MIXER_ENABLE_CTRL_DECL("Mixer Enable", 0x00), +MIXER_SET_FADE("Mixer fade", 0x00), +MIXER_GET_FADE_STATUS("Mixer fade status", 0x00), + +SFC_IN_FREQ_CTRL_DECL("SFC1 input rate", 0x00), +SFC_IN_FREQ_CTRL_DECL("SFC2 input rate", 0x01), +SFC_IN_FREQ_CTRL_DECL("SFC3 input rate", 0x02), +SFC_IN_FREQ_CTRL_DECL("SFC4 input rate", 0x03), + +SFC_OUT_FREQ_CTRL_DECL("SFC1 output rate", 0x00), +SFC_OUT_FREQ_CTRL_DECL("SFC2 output rate", 0x01), +SFC_OUT_FREQ_CTRL_DECL("SFC3 output rate", 0x02), +SFC_OUT_FREQ_CTRL_DECL("SFC4 output rate", 0x03), + +MVC_CURVE_TYPE_CTRL_DECL("MVC1 Curve Type", 0x00, + &tegra_virt_t210_mvc_curvetype), +MVC_CURVE_TYPE_CTRL_DECL("MVC2 Curve Type", 0x01, + &tegra_virt_t210_mvc_curvetype), + +MVC_TAR_VOL_CTRL_DECL("MVC1 Vol", 0x00), +MVC_TAR_VOL_CTRL_DECL("MVC2 Vol", 0x01), + +MVC_MUTE_CTRL_DECL("MVC1 Mute", 0x00), +MVC_MUTE_CTRL_DECL("MVC2 Mute", 0x01), + +ASRC_RATIO_CTRL_DECL("ASRC1 Ratio1", 0x01), +ASRC_RATIO_CTRL_DECL("ASRC1 Ratio2", 0x02), +ASRC_RATIO_CTRL_DECL("ASRC1 Ratio3", 0x03), +ASRC_RATIO_CTRL_DECL("ASRC1 Ratio4", 0x04), +ASRC_RATIO_CTRL_DECL("ASRC1 Ratio5", 0x05), +ASRC_RATIO_CTRL_DECL("ASRC1 Ratio6", 0x06), + +ASRC_STREAM_RATIO_CTRL_DECL("ASRC1 Ratio1 SRC", 0x01, + &tegra_virt_t186_asrc_source), +ASRC_STREAM_RATIO_CTRL_DECL("ASRC1 Ratio2 SRC", 0x02, + &tegra_virt_t186_asrc_source), +ASRC_STREAM_RATIO_CTRL_DECL("ASRC1 Ratio3 SRC", 0x03, + &tegra_virt_t186_asrc_source), +ASRC_STREAM_RATIO_CTRL_DECL("ASRC1 Ratio4 SRC", 0x04, + &tegra_virt_t186_asrc_source), +ASRC_STREAM_RATIO_CTRL_DECL("ASRC1 Ratio5 SRC", 0x05, + &tegra_virt_t186_asrc_source), +ASRC_STREAM_RATIO_CTRL_DECL("ASRC1 Ratio6 SRC", 0x06, + &tegra_virt_t186_asrc_source), + +ASRC_STREAM_ENABLE_CTRL_DECL("ASRC1 Stream1 Enable", 0x01), +ASRC_STREAM_ENABLE_CTRL_DECL("ASRC1 Stream2 Enable", 0x02), +ASRC_STREAM_ENABLE_CTRL_DECL("ASRC1 Stream3 Enable", 0x03), +ASRC_STREAM_ENABLE_CTRL_DECL("ASRC1 Stream4 Enable", 0x04), +ASRC_STREAM_ENABLE_CTRL_DECL("ASRC1 Stream5 Enable", 0x05), +ASRC_STREAM_ENABLE_CTRL_DECL("ASRC1 Stream6 Enable", 0x06), + +ASRC_STREAM_HWCOMP_CTRL_DECL("ASRC1 Stream1 Hwcomp Disable", 0x01), +ASRC_STREAM_HWCOMP_CTRL_DECL("ASRC1 Stream2 Hwcomp Disable", 0x02), +ASRC_STREAM_HWCOMP_CTRL_DECL("ASRC1 Stream3 Hwcomp Disable", 0x03), +ASRC_STREAM_HWCOMP_CTRL_DECL("ASRC1 Stream4 Hwcomp Disable", 0x04), +ASRC_STREAM_HWCOMP_CTRL_DECL("ASRC1 Stream5 Hwcomp Disable", 0x05), +ASRC_STREAM_HWCOMP_CTRL_DECL("ASRC1 Stream6 Hwcomp Disable", 0x06), + +ASRC_STREAM_INPUT_THRESHOLD_CTRL_DECL("ASRC1 Stream1 Input Thresh", 0x01), +ASRC_STREAM_INPUT_THRESHOLD_CTRL_DECL("ASRC1 Stream2 Input Thresh", 0x02), +ASRC_STREAM_INPUT_THRESHOLD_CTRL_DECL("ASRC1 Stream3 Input Thresh", 0x03), +ASRC_STREAM_INPUT_THRESHOLD_CTRL_DECL("ASRC1 Stream4 Input Thresh", 0x04), +ASRC_STREAM_INPUT_THRESHOLD_CTRL_DECL("ASRC1 Stream5 Input Thresh", 0x05), +ASRC_STREAM_INPUT_THRESHOLD_CTRL_DECL("ASRC1 Stream6 Input Thresh", 0x06), + +ASRC_STREAM_OUTPUT_THRESHOLD_CTRL_DECL("ASRC1 Stream1 Output Thresh", 0x01), +ASRC_STREAM_OUTPUT_THRESHOLD_CTRL_DECL("ASRC1 Stream2 Output Thresh", 0x02), +ASRC_STREAM_OUTPUT_THRESHOLD_CTRL_DECL("ASRC1 Stream3 Output Thresh", 0x03), +ASRC_STREAM_OUTPUT_THRESHOLD_CTRL_DECL("ASRC1 Stream4 Output Thresh", 0x04), +ASRC_STREAM_OUTPUT_THRESHOLD_CTRL_DECL("ASRC1 Stream5 Output Thresh", 0x05), +ASRC_STREAM_OUTPUT_THRESHOLD_CTRL_DECL("ASRC1 Stream6 Output Thresh", 0x06), + +ARAD_LANE_SOURCE_CTRL_DECL("Numerator1 Mux", numerator1_enum, + &tegra_virt_t186_arad_source), +ARAD_LANE_SOURCE_CTRL_DECL("Numerator2 Mux", numerator2_enum, + &tegra_virt_t186_arad_source), +ARAD_LANE_SOURCE_CTRL_DECL("Numerator3 Mux", numerator3_enum, + &tegra_virt_t186_arad_source), +ARAD_LANE_SOURCE_CTRL_DECL("Numerator4 Mux", numerator4_enum, + &tegra_virt_t186_arad_source), +ARAD_LANE_SOURCE_CTRL_DECL("Numerator5 Mux", numerator5_enum, + &tegra_virt_t186_arad_source), +ARAD_LANE_SOURCE_CTRL_DECL("Numerator6 Mux", numerator6_enum, + &tegra_virt_t186_arad_source), + +ARAD_LANE_SOURCE_CTRL_DECL("Denominator1 Mux", denominator1_enum, + &tegra_virt_t186_arad_source), +ARAD_LANE_SOURCE_CTRL_DECL("Denominator2 Mux", denominator2_enum, + &tegra_virt_t186_arad_source), +ARAD_LANE_SOURCE_CTRL_DECL("Denominator3 Mux", denominator3_enum, + &tegra_virt_t186_arad_source), +ARAD_LANE_SOURCE_CTRL_DECL("Denominator4 Mux", denominator4_enum, + &tegra_virt_t186_arad_source), +ARAD_LANE_SOURCE_CTRL_DECL("Denominator5 Mux", denominator5_enum, + &tegra_virt_t186_arad_source), +ARAD_LANE_SOURCE_CTRL_DECL("Denominator6 Mux", denominator6_enum, + &tegra_virt_t186_arad_source), + +ARAD_LANE_PRESCALAR_CTRL_DECL("Numerator1 Prescalar", numerator1_enum), +ARAD_LANE_PRESCALAR_CTRL_DECL("Numerator2 Prescalar", numerator2_enum), +ARAD_LANE_PRESCALAR_CTRL_DECL("Numerator3 Prescalar", numerator3_enum), +ARAD_LANE_PRESCALAR_CTRL_DECL("Numerator4 Prescalar", numerator4_enum), +ARAD_LANE_PRESCALAR_CTRL_DECL("Numerator5 Prescalar", numerator5_enum), +ARAD_LANE_PRESCALAR_CTRL_DECL("Numerator6 Prescalar", numerator6_enum), + +ARAD_LANE_PRESCALAR_CTRL_DECL("Denominator1 Prescalar", denominator1_enum), +ARAD_LANE_PRESCALAR_CTRL_DECL("Denominator2 Prescalar", denominator2_enum), +ARAD_LANE_PRESCALAR_CTRL_DECL("Denominator3 Prescalar", denominator3_enum), +ARAD_LANE_PRESCALAR_CTRL_DECL("Denominator4 Prescalar", denominator4_enum), +ARAD_LANE_PRESCALAR_CTRL_DECL("Denominator5 Prescalar", denominator5_enum), +ARAD_LANE_PRESCALAR_CTRL_DECL("Denominator6 Prescalar", denominator6_enum), + +ARAD_LANE_ENABLE_CTRL_DECL("Lane1 enable", 0x00), +ARAD_LANE_ENABLE_CTRL_DECL("Lane2 enable", 0x01), +ARAD_LANE_ENABLE_CTRL_DECL("Lane3 enable", 0x02), +ARAD_LANE_ENABLE_CTRL_DECL("Lane4 enable", 0x03), +ARAD_LANE_ENABLE_CTRL_DECL("Lane5 enable", 0x04), +ARAD_LANE_ENABLE_CTRL_DECL("Lane6 enable", 0x05), + +ARAD_LANE_RATIO_CTRL_DECL("Lane1 Ratio", 0x00), +ARAD_LANE_RATIO_CTRL_DECL("Lane2 Ratio", 0x01), +ARAD_LANE_RATIO_CTRL_DECL("Lane3 Ratio", 0x02), +ARAD_LANE_RATIO_CTRL_DECL("Lane4 Ratio", 0x03), +ARAD_LANE_RATIO_CTRL_DECL("Lane5 Ratio", 0x04), +ARAD_LANE_RATIO_CTRL_DECL("Lane6 Ratio", 0x05), + +AMX_ENABLE_CTRL_DECL("AMX1-1 Enable", 0x01, 0x01), +AMX_ENABLE_CTRL_DECL("AMX1-2 Enable", 0x01, 0x02), +AMX_ENABLE_CTRL_DECL("AMX1-3 Enable", 0x01, 0x03), +AMX_ENABLE_CTRL_DECL("AMX1-4 Enable", 0x01, 0x04), + +AMX_ENABLE_CTRL_DECL("AMX2-1 Enable", 0x02, 0x01), +AMX_ENABLE_CTRL_DECL("AMX2-2 Enable", 0x02, 0x02), +AMX_ENABLE_CTRL_DECL("AMX2-3 Enable", 0x02, 0x03), +AMX_ENABLE_CTRL_DECL("AMX2-4 Enable", 0x02, 0x04), + +AMX_ENABLE_CTRL_DECL("AMX3-1 Enable", 0x03, 0x01), +AMX_ENABLE_CTRL_DECL("AMX3-2 Enable", 0x03, 0x02), +AMX_ENABLE_CTRL_DECL("AMX3-3 Enable", 0x03, 0x03), +AMX_ENABLE_CTRL_DECL("AMX3-4 Enable", 0x03, 0x04), + +AMX_ENABLE_CTRL_DECL("AMX4-1 Enable", 0x04, 0x01), +AMX_ENABLE_CTRL_DECL("AMX4-2 Enable", 0x04, 0x02), +AMX_ENABLE_CTRL_DECL("AMX4-3 Enable", 0x04, 0x03), +AMX_ENABLE_CTRL_DECL("AMX4-4 Enable", 0x04, 0x04), + +I2S_SET_RATE("I2S1 rate", 0x01), +I2S_SET_RATE("I2S2 rate", 0x02), +I2S_SET_RATE("I2S3 rate", 0x03), +I2S_SET_RATE("I2S4 rate", 0x04), +I2S_SET_RATE("I2S5 rate", 0x05), +I2S_SET_RATE("I2S6 rate", 0x06), + +I2S_LOOPBACK_ENABLE_CTRL_DECL("I2S1 Loopback", 0x01), +I2S_LOOPBACK_ENABLE_CTRL_DECL("I2S2 Loopback", 0x02), +I2S_LOOPBACK_ENABLE_CTRL_DECL("I2S3 Loopback", 0x03), +I2S_LOOPBACK_ENABLE_CTRL_DECL("I2S4 Loopback", 0x04), +I2S_LOOPBACK_ENABLE_CTRL_DECL("I2S5 Loopback", 0x05), +I2S_LOOPBACK_ENABLE_CTRL_DECL("I2S6 Loopback", 0x06), + +REGDUMP_CTRL_DECL("ADMAIF1 regdump", ADMAIF1, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF2 regdump", ADMAIF2, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF3 regdump", ADMAIF3, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF4 regdump", ADMAIF4, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF5 regdump", ADMAIF5, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF6 regdump", ADMAIF6, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF7 regdump", ADMAIF7, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF8 regdump", ADMAIF8, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF9 regdump", ADMAIF9, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF10 regdump", ADMAIF10, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF11 regdump", ADMAIF11, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF12 regdump", ADMAIF12, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF13 regdump", ADMAIF13, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF14 regdump", ADMAIF14, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF15 regdump", ADMAIF15, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF16 regdump", ADMAIF16, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF17 regdump", ADMAIF17, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF18 regdump", ADMAIF18, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF19 regdump", ADMAIF19, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADMAIF20 regdump", ADMAIF20, 0, NVAUDIO_REGDUMP_RX_TX), + +REGDUMP_CTRL_DECL("AMX1 regdump", AMX1, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("AMX2 regdump", AMX2, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("AMX3 regdump", AMX3, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("AMX4 regdump", AMX4, 0, NVAUDIO_REGDUMP_RX_TX), + +REGDUMP_CTRL_DECL("ADX1 regdump", ADX1, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADX2 regdump", ADX2, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADX3 regdump", ADX3, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ADX4 regdump", ADX4, 0, NVAUDIO_REGDUMP_RX_TX), + +REGDUMP_CTRL_DECL("MIXER1-1 RX regdump", MIXER1, 0, NVAUDIO_REGDUMP_RX), +REGDUMP_CTRL_DECL("MIXER1-2 RX regdump", MIXER1, 1, NVAUDIO_REGDUMP_RX), +REGDUMP_CTRL_DECL("MIXER1-3 RX regdump", MIXER1, 2, NVAUDIO_REGDUMP_RX), +REGDUMP_CTRL_DECL("MIXER1-4 RX regdump", MIXER1, 3, NVAUDIO_REGDUMP_RX), +REGDUMP_CTRL_DECL("MIXER1-5 RX regdump", MIXER1, 4, NVAUDIO_REGDUMP_RX), +REGDUMP_CTRL_DECL("MIXER1-6 RX regdump", MIXER1, 5, NVAUDIO_REGDUMP_RX), +REGDUMP_CTRL_DECL("MIXER1-7 RX regdump", MIXER1, 6, NVAUDIO_REGDUMP_RX), +REGDUMP_CTRL_DECL("MIXER1-8 RX regdump", MIXER1, 7, NVAUDIO_REGDUMP_RX), +REGDUMP_CTRL_DECL("MIXER1-9 RX regdump", MIXER1, 8, NVAUDIO_REGDUMP_RX), +REGDUMP_CTRL_DECL("MIXER1-10 RX regdump", MIXER1, 9, NVAUDIO_REGDUMP_RX), + +REGDUMP_CTRL_DECL("MIXER1-1 TX regdump", MIXER1, 0, NVAUDIO_REGDUMP_TX), +REGDUMP_CTRL_DECL("MIXER1-2 TX regdump", MIXER1, 1, NVAUDIO_REGDUMP_TX), +REGDUMP_CTRL_DECL("MIXER1-3 TX regdump", MIXER1, 2, NVAUDIO_REGDUMP_TX), +REGDUMP_CTRL_DECL("MIXER1-4 TX regdump", MIXER1, 3, NVAUDIO_REGDUMP_TX), +REGDUMP_CTRL_DECL("MIXER1-5 TX regdump", MIXER1, 4, NVAUDIO_REGDUMP_TX), + +REGDUMP_CTRL_DECL("I2S1 regdump", I2S1, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("I2S2 regdump", I2S2, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("I2S3 regdump", I2S3, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("I2S4 regdump", I2S4, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("I2S5 regdump", I2S5, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("I2S6 regdump", I2S6, 0, NVAUDIO_REGDUMP_RX_TX), + +REGDUMP_CTRL_DECL("ASRC1-1 regdump", ASRC1, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ASRC1-2 regdump", ASRC1, 1, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ASRC1-3 regdump", ASRC1, 2, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ASRC1-4 regdump", ASRC1, 3, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ASRC1-5 regdump", ASRC1, 4, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ASRC1-6 regdump", ASRC1, 5, NVAUDIO_REGDUMP_RX_TX), + +REGDUMP_CTRL_DECL("SFC1 regdump", SFC1, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("SFC2 regdump", SFC2, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("SFC3 regdump", SFC3, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("SFC4 regdump", SFC4, 0, NVAUDIO_REGDUMP_RX_TX), + +REGDUMP_CTRL_DECL("MVC1 regdump", MVC1, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("MVC2 regdump", MVC2, 0, NVAUDIO_REGDUMP_RX_TX), + +REGDUMP_CTRL_DECL("ARAD1 Lane1 regdump", ARAD1, 0, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ARAD1 Lane2 regdump", ARAD1, 1, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ARAD1 Lane3 regdump", ARAD1, 2, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ARAD1 Lane4 regdump", ARAD1, 3, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ARAD1 Lane5 regdump", ARAD1, 4, NVAUDIO_REGDUMP_RX_TX), +REGDUMP_CTRL_DECL("ARAD1 Lane6 regdump", ARAD1, 5, NVAUDIO_REGDUMP_RX_TX), + +ADMA_REGDUMP_CTRL_DECL("ADMA1 regdump", 1), +ADMA_REGDUMP_CTRL_DECL("ADMA2 regdump", 2), +ADMA_REGDUMP_CTRL_DECL("ADMA3 regdump", 3), +ADMA_REGDUMP_CTRL_DECL("ADMA4 regdump", 4), +ADMA_REGDUMP_CTRL_DECL("ADMA5 regdump", 5), +ADMA_REGDUMP_CTRL_DECL("ADMA6 regdump", 6), +ADMA_REGDUMP_CTRL_DECL("ADMA7 regdump", 7), +ADMA_REGDUMP_CTRL_DECL("ADMA8 regdump", 8), +ADMA_REGDUMP_CTRL_DECL("ADMA9 regdump", 9), +ADMA_REGDUMP_CTRL_DECL("ADMA10 regdump", 10), +ADMA_REGDUMP_CTRL_DECL("ADMA11 regdump", 11), +ADMA_REGDUMP_CTRL_DECL("ADMA12 regdump", 12), +ADMA_REGDUMP_CTRL_DECL("ADMA13 regdump", 13), +ADMA_REGDUMP_CTRL_DECL("ADMA14 regdump", 14), +ADMA_REGDUMP_CTRL_DECL("ADMA15 regdump", 15), +ADMA_REGDUMP_CTRL_DECL("ADMA16 regdump", 16), +ADMA_REGDUMP_CTRL_DECL("ADMA17 regdump", 17), +ADMA_REGDUMP_CTRL_DECL("ADMA18 regdump", 18), +ADMA_REGDUMP_CTRL_DECL("ADMA19 regdump", 19), +ADMA_REGDUMP_CTRL_DECL("ADMA20 regdump", 20), +ADMA_REGDUMP_CTRL_DECL("ADMA21 regdump", 21), +ADMA_REGDUMP_CTRL_DECL("ADMA22 regdump", 22), +ADMA_REGDUMP_CTRL_DECL("ADMA23 regdump", 23), +ADMA_REGDUMP_CTRL_DECL("ADMA24 regdump", 24), +ADMA_REGDUMP_CTRL_DECL("ADMA25 regdump", 25), +ADMA_REGDUMP_CTRL_DECL("ADMA26 regdump", 26), +ADMA_REGDUMP_CTRL_DECL("ADMA27 regdump", 27), +ADMA_REGDUMP_CTRL_DECL("ADMA28 regdump", 28), +ADMA_REGDUMP_CTRL_DECL("ADMA29 regdump", 29), +ADMA_REGDUMP_CTRL_DECL("ADMA30 regdump", 30), +ADMA_REGDUMP_CTRL_DECL("ADMA31 regdump", 31), +ADMA_REGDUMP_CTRL_DECL("ADMA32 regdump", 32), +}; + +static struct snd_soc_component_driver tegra210_admaif_dai_driver = { + .name = "tegra210-virt-pcm", + .controls = tegra_virt_t186ref_controls, + .num_controls = ARRAY_SIZE(tegra_virt_t186ref_controls), +}; + +int tegra210_virt_admaif_register_component(struct platform_device *pdev, + struct tegra_virt_admaif_soc_data *data) +{ + int i = 0; + int ret; + int admaif_ch_num = 0; + unsigned int admaif_ch_list[MAX_ADMAIF_IDS] = {0}; + struct tegra_virt_admaif_soc_data *soc_data = data; + int adma_count = 0; + bool meta_enabled = false; + unsigned int buffer_size; + + admaif = devm_kzalloc(&pdev->dev, sizeof(*admaif), GFP_KERNEL); + if (admaif == NULL) { + ret = -ENOMEM; + goto err; + } + admaif->client_data.hivc_client = + nvaudio_ivc_alloc_ctxt(&pdev->dev); + + if (!admaif->client_data.hivc_client) { + dev_err(&pdev->dev, "Failed to allocate IVC context\n"); + ret = -ENODEV; + goto err; + } + svd_cntxt = admaif->client_data.hivc_client; + + admaif->capture_dma_data = devm_kzalloc(&pdev->dev, + sizeof(struct tegra_alt_pcm_dma_params) * + soc_data->num_ch, + GFP_KERNEL); + if (admaif->capture_dma_data == NULL) { + ret = -ENOMEM; + goto err; + } + + admaif->playback_dma_data = devm_kzalloc(&pdev->dev, + sizeof(struct tegra_alt_pcm_dma_params) * + soc_data->num_ch, + GFP_KERNEL); + if (admaif->playback_dma_data == NULL) { + ret = -ENOMEM; + goto err; + } + + if (of_property_read_u32(pdev->dev.of_node, + "admaif_ch_num", &admaif_ch_num)) { + dev_err(&pdev->dev, "number of admaif channels is not set\n"); + return -EINVAL; + } + + if (of_property_read_u32_array(pdev->dev.of_node, + "admaif_ch_list", + admaif_ch_list, + admaif_ch_num)) { + dev_err(&pdev->dev, "admaif_ch_list is not populated\n"); + return -EINVAL; + } + + + for (i = 0; i < soc_data->num_ch; i++) { + if ((i + 1) != admaif_ch_list[adma_count]) + continue; + if (of_device_is_compatible(pdev->dev.of_node, + "nvidia,tegra186-virt-pcm")) { + admaif->playback_dma_data[i].addr = TEGRA186_ADMAIF_BASE + + TEGRA186_ADMAIF_XBAR_TX_FIFO_WRITE + + (i * TEGRA186_ADMAIF_CHANNEL_REG_STRIDE); + admaif->capture_dma_data[i].addr = TEGRA186_ADMAIF_BASE + + TEGRA186_ADMAIF_XBAR_RX_FIFO_READ + + (i * TEGRA186_ADMAIF_CHANNEL_REG_STRIDE); + } else if (of_device_is_compatible(pdev->dev.of_node, + "nvidia,tegra234-virt-pcm-oot")) { + admaif->playback_dma_data[i].addr = TEGRA186_ADMAIF_BASE + + TEGRA186_ADMAIF_XBAR_TX_FIFO_WRITE + + (i * TEGRA186_ADMAIF_CHANNEL_REG_STRIDE); + admaif->capture_dma_data[i].addr = TEGRA186_ADMAIF_BASE + + TEGRA186_ADMAIF_XBAR_RX_FIFO_READ + + (i * TEGRA186_ADMAIF_CHANNEL_REG_STRIDE); + } else if (of_device_is_compatible(pdev->dev.of_node, + "nvidia,tegra210-virt-pcm")) { + admaif->playback_dma_data[i].addr = TEGRA210_ADMAIF_BASE + + TEGRA210_ADMAIF_XBAR_TX_FIFO_WRITE + + (i * TEGRA210_ADMAIF_CHANNEL_REG_STRIDE); + admaif->capture_dma_data[i].addr = TEGRA210_ADMAIF_BASE + + TEGRA210_ADMAIF_XBAR_RX_FIFO_READ + + (i * TEGRA210_ADMAIF_CHANNEL_REG_STRIDE); + } else { + dev_err(&pdev->dev, + "Uncompatible device driver\n"); + ret = -ENODEV; + goto err; + } + + buffer_size = 0; + if (of_property_read_u32_index(pdev->dev.of_node, + "dma-buffer-size", + (i * 2) + 1, + &buffer_size) < 0) + dev_dbg(&pdev->dev, + "Missing property nvidia,dma-buffer-size\n"); + admaif->playback_dma_data[i].buffer_size = buffer_size; + admaif->playback_dma_data[i].width = 32; + admaif->playback_dma_data[i].req_sel = i + 1; + + if (of_property_read_string_index(pdev->dev.of_node, + "dma-names", + (adma_count * 2) + 1, + &admaif->playback_dma_data[i].chan_name) < 0) { + dev_err(&pdev->dev, + "Missing property nvidia,dma-names\n"); + ret = -ENODEV; + goto err; + } + + buffer_size = 0; + if (of_property_read_u32_index(pdev->dev.of_node, + "dma-buffer-size", + (i * 2), + &buffer_size) < 0) + dev_dbg(&pdev->dev, + "Missing property nvidia,dma-buffer-size\n"); + admaif->capture_dma_data[i].buffer_size = buffer_size; + admaif->capture_dma_data[i].width = 32; + admaif->capture_dma_data[i].req_sel = i + 1; + if (of_property_read_string_index(pdev->dev.of_node, + "dma-names", + (adma_count * 2), + &admaif->capture_dma_data[i].chan_name) < 0) { + dev_err(&pdev->dev, + "Missing property nvidia,dma-names\n"); + ret = -ENODEV; + goto err; + } + adma_count++; + } + + /* Remove exposing metadata controls if not enabled in device node */ + meta_enabled = of_property_read_bool(pdev->dev.of_node, + "sad_enabled"); + if (!meta_enabled) { + tegra210_admaif_dai_driver.num_controls = + ARRAY_SIZE(tegra_virt_t186ref_controls) - NUM_META_CONTROLS; + } + + ret = tegra_register_component(&pdev->dev, + &tegra210_admaif_dai_driver, + tegra210_admaif_dais, + soc_data->num_ch, "admaif"); + if (ret) { + dev_err(&pdev->dev, "Could not register DAIs %d: %d\n", + i, ret); + goto err; + } + + ret = tegra_alt_pcm_platform_register(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); + goto err_unregister_dais; + } + + return 0; +err_unregister_dais: + snd_soc_unregister_component(&pdev->dev); +err: + return ret; +} +EXPORT_SYMBOL_GPL(tegra210_virt_admaif_register_component); + +void tegra210_virt_admaif_unregister_component(struct platform_device *pdev) +{ + tegra_alt_pcm_platform_unregister(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); +} +EXPORT_SYMBOL_GPL(tegra210_virt_admaif_unregister_component); + +struct nvaudio_ivc_ctxt *nvaudio_get_saved_ivc_ctxt(void) +{ + if (svd_cntxt) + return svd_cntxt; + + pr_err("%s: ivc ctxt not allocated\n", __func__); + return NULL; +} +EXPORT_SYMBOL_GPL(nvaudio_get_saved_ivc_ctxt); + +MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/sound/soc/tegra-virt-alt/tegra210_virt_alt_admaif.h b/sound/soc/tegra-virt-alt/tegra210_virt_alt_admaif.h new file mode 100644 index 00000000..d71b5746 --- /dev/null +++ b/sound/soc/tegra-virt-alt/tegra210_virt_alt_admaif.h @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + */ + +#ifndef __TEGRA210_VIRT_ALT_ADMAIF_H__ +#define __TEGRA210_VIRT_ALT_ADMAIF_H__ + +#define DRV_NAME "virt-alt-pcm-oot" + +#define TEGRA210_ADMAIF_BASE 0x702d0000 +#define TEGRA210_ADMAIF_XBAR_RX_FIFO_READ 0x2c +#define TEGRA210_ADMAIF_XBAR_TX_FIFO_WRITE 0x32c +#define TEGRA210_ADMAIF_CHANNEL_REG_STRIDE 0x40 + +#define TEGRA186_ADMAIF_BASE 0x0290f000 +#define TEGRA186_ADMAIF_XBAR_RX_FIFO_READ 0x2c +#define TEGRA186_ADMAIF_XBAR_TX_FIFO_WRITE 0x52c +#define TEGRA186_ADMAIF_CHANNEL_REG_STRIDE 0x40 + +#define TEGRA210_AUDIOCIF_BITS_8 1 +#define TEGRA210_AUDIOCIF_BITS_12 2 +#define TEGRA210_AUDIOCIF_BITS_16 3 +#define TEGRA210_AUDIOCIF_BITS_20 4 +#define TEGRA210_AUDIOCIF_BITS_24 5 +#define TEGRA210_AUDIOCIF_BITS_28 6 +#define TEGRA210_AUDIOCIF_BITS_32 7 + +#define TEGRA210_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT 24 +#define TEGRA210_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT 20 +#define TEGRA210_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT 16 +#define TEGRA210_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT 12 +#define TEGRA210_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT 8 +#define TEGRA210_AUDIOCIF_CTRL_EXPAND_SHIFT 6 +#define TEGRA210_AUDIOCIF_CTRL_STEREO_CONV_SHIFT 4 +#define TEGRA210_AUDIOCIF_CTRL_REPLICATE_SHIFT 3 +#define TEGRA210_AUDIOCIF_CTRL_TRUNCATE_SHIFT 1 +#define TEGRA210_AUDIOCIF_CTRL_MONO_CONV_SHIFT 0 + +/* ADMAIF ids */ +enum { + ADMAIF_ID_0 = 0, + ADMAIF_ID_1, + ADMAIF_ID_2, + ADMAIF_ID_3, + ADMAIF_ID_4, + ADMAIF_ID_5, + ADMAIF_ID_6, + ADMAIF_ID_7, + ADMAIF_ID_8, + ADMAIF_ID_9, + ADMAIF_ID_10, + TEGRA210_ADMAIF_CHANNEL_COUNT = ADMAIF_ID_10, + ADMAIF_ID_11, + ADMAIF_ID_12, + ADMAIF_ID_13, + ADMAIF_ID_14, + ADMAIF_ID_15, + ADMAIF_ID_16, + ADMAIF_ID_17, + ADMAIF_ID_18, + ADMAIF_ID_19, + MAX_ADMAIF_T186_IDS, + TEGRA186_ADMAIF_CHANNEL_COUNT = MAX_ADMAIF_T186_IDS, + MAX_ADMAIF_IDS = MAX_ADMAIF_T186_IDS, +}; + +/* Audio cif definition */ +struct tegra210_virt_audio_cif { + unsigned int threshold; + unsigned int audio_channels; + unsigned int client_channels; + unsigned int audio_bits; + unsigned int client_bits; + unsigned int expand; + unsigned int stereo_conv; + unsigned int replicate; + int32_t direction; + unsigned int truncate; + unsigned int mono_conv; +}; + +/* apbif data */ +struct tegra210_virt_admaif_client_data { + struct nvaudio_ivc_ctxt *hivc_client; +}; + +struct tegra210_admaif { + struct tegra_alt_pcm_dma_params *capture_dma_data; + struct tegra_alt_pcm_dma_params *playback_dma_data; + struct tegra210_virt_admaif_client_data client_data; +}; + +struct tegra_virt_admaif_soc_data { + unsigned int num_ch; +}; + +int tegra210_virt_admaif_register_component(struct platform_device *pdev, + struct tegra_virt_admaif_soc_data *soc_data); +void tegra210_virt_admaif_unregister_component(struct platform_device *pdev); + +struct nvaudio_ivc_ctxt *nvaudio_get_saved_ivc_ctxt(void); + +#endif \ No newline at end of file diff --git a/sound/soc/tegra-virt-alt/tegra_asoc_machine_virt_alt.c b/sound/soc/tegra-virt-alt/tegra_asoc_machine_virt_alt.c new file mode 100644 index 00000000..cecd2953 --- /dev/null +++ b/sound/soc/tegra-virt-alt/tegra_asoc_machine_virt_alt.c @@ -0,0 +1,897 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "tegra_asoc_machine_virt_alt.h" + +#define CODEC_NAME NULL + +#define DAI_NAME(i) "AUDIO" #i +#define STREAM_NAME "playback" +#define LINK_CPU_NAME DRV_NAME +#define CPU_DAI_NAME(i) "ADMAIF" #i +#define CODEC_DAI_NAME "dit-hifi" +#define PLATFORM_NAME LINK_CPU_NAME + +static unsigned int num_dai_links; +static const struct snd_soc_pcm_stream default_params = { + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, +}; + +static const struct snd_soc_pcm_stream adsp_default_params = { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, +}; + +static struct snd_soc_pcm_stream adsp_admaif_params[MAX_ADMAIF_IDS]; + +SND_SOC_DAILINK_DEFS(audio1, + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, CPU_DAI_NAME(1))), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF1 CIF")), + DAILINK_COMP_ARRAY(COMP_PLATFORM(PLATFORM_NAME))); + +SND_SOC_DAILINK_DEFS(audio2, + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, CPU_DAI_NAME(2))), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF2 CIF")), + DAILINK_COMP_ARRAY(COMP_PLATFORM(PLATFORM_NAME))); + +SND_SOC_DAILINK_DEFS(audio3, + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, CPU_DAI_NAME(3))), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF3 CIF")), + DAILINK_COMP_ARRAY(COMP_PLATFORM(PLATFORM_NAME))); + +SND_SOC_DAILINK_DEFS(audio4, + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, CPU_DAI_NAME(4))), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF4 CIF")), + DAILINK_COMP_ARRAY(COMP_PLATFORM(PLATFORM_NAME))); + +SND_SOC_DAILINK_DEFS(audio5, + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, CPU_DAI_NAME(5))), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF5 CIF")), + DAILINK_COMP_ARRAY(COMP_PLATFORM(PLATFORM_NAME))); + +SND_SOC_DAILINK_DEFS(audio6, + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, CPU_DAI_NAME(6))), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF6 CIF")), + DAILINK_COMP_ARRAY(COMP_PLATFORM(PLATFORM_NAME))); + +SND_SOC_DAILINK_DEFS(audio7, + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, CPU_DAI_NAME(7))), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF7 CIF")), + DAILINK_COMP_ARRAY(COMP_PLATFORM(PLATFORM_NAME))); + +SND_SOC_DAILINK_DEFS(audio8, + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, CPU_DAI_NAME(8))), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF8 CIF")), + DAILINK_COMP_ARRAY(COMP_PLATFORM(PLATFORM_NAME))); + +SND_SOC_DAILINK_DEFS(audio9, + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, CPU_DAI_NAME(9))), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF9 CIF")), + DAILINK_COMP_ARRAY(COMP_PLATFORM(PLATFORM_NAME))); + +SND_SOC_DAILINK_DEFS(audio10, + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, CPU_DAI_NAME(10))), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF10 CIF")), + DAILINK_COMP_ARRAY(COMP_PLATFORM(PLATFORM_NAME))); + +SND_SOC_DAILINK_DEFS(audio11, + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, CPU_DAI_NAME(11))), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF11 CIF")), + DAILINK_COMP_ARRAY(COMP_PLATFORM(PLATFORM_NAME))); + +SND_SOC_DAILINK_DEFS(audio12, + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, CPU_DAI_NAME(12))), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF12 CIF")), + DAILINK_COMP_ARRAY(COMP_PLATFORM(PLATFORM_NAME))); + +SND_SOC_DAILINK_DEFS(audio13, + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, CPU_DAI_NAME(13))), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF13 CIF")), + DAILINK_COMP_ARRAY(COMP_PLATFORM(PLATFORM_NAME))); + +SND_SOC_DAILINK_DEFS(audio14, + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, CPU_DAI_NAME(14))), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF14 CIF")), + DAILINK_COMP_ARRAY(COMP_PLATFORM(PLATFORM_NAME))); + +SND_SOC_DAILINK_DEFS(audio15, + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, CPU_DAI_NAME(15))), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF15 CIF")), + DAILINK_COMP_ARRAY(COMP_PLATFORM(PLATFORM_NAME))); + +SND_SOC_DAILINK_DEFS(audio16, + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, CPU_DAI_NAME(16))), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF16 CIF")), + DAILINK_COMP_ARRAY(COMP_PLATFORM(PLATFORM_NAME))); + +SND_SOC_DAILINK_DEFS(audio17, + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, CPU_DAI_NAME(17))), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF17 CIF")), + DAILINK_COMP_ARRAY(COMP_PLATFORM(PLATFORM_NAME))); + +SND_SOC_DAILINK_DEFS(audio18, + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, CPU_DAI_NAME(18))), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF18 CIF")), + DAILINK_COMP_ARRAY(COMP_PLATFORM(PLATFORM_NAME))); + +SND_SOC_DAILINK_DEFS(audio19, + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, CPU_DAI_NAME(19))), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF19 CIF")), + DAILINK_COMP_ARRAY(COMP_PLATFORM(PLATFORM_NAME))); + +SND_SOC_DAILINK_DEFS(audio20, + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, CPU_DAI_NAME(20))), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF20 CIF")), + DAILINK_COMP_ARRAY(COMP_PLATFORM(PLATFORM_NAME))); + + +SND_SOC_DAILINK_DEFS(adsp_admaif1, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP-ADMAIF1")), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF1 CIF"))); + +SND_SOC_DAILINK_DEFS(adsp_admaif2, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP-ADMAIF2")), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF2 CIF"))); + +SND_SOC_DAILINK_DEFS(adsp_admaif3, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP-ADMAIF3")), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF3 CIF"))); + +SND_SOC_DAILINK_DEFS(adsp_admaif4, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP-ADMAIF4")), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF4 CIF"))); + +SND_SOC_DAILINK_DEFS(adsp_admaif5, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP-ADMAIF5")), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF5 CIF"))); + +SND_SOC_DAILINK_DEFS(adsp_admaif6, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP-ADMAIF6")), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF6 CIF"))); + +SND_SOC_DAILINK_DEFS(adsp_admaif7, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP-ADMAIF7")), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF7 CIF"))); + +SND_SOC_DAILINK_DEFS(adsp_admaif8, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP-ADMAIF8")), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF8 CIF"))); + +SND_SOC_DAILINK_DEFS(adsp_admaif9, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP-ADMAIF9")), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF9 CIF"))); + +SND_SOC_DAILINK_DEFS(adsp_admaif10, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP-ADMAIF10")), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF10 CIF"))); + +SND_SOC_DAILINK_DEFS(adsp_admaif11, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP-ADMAIF11")), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF11 CIF"))); + +SND_SOC_DAILINK_DEFS(adsp_admaif12, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP-ADMAIF12")), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF12 CIF"))); + +SND_SOC_DAILINK_DEFS(adsp_admaif13, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP-ADMAIF13")), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF13 CIF"))); + +SND_SOC_DAILINK_DEFS(adsp_admaif14, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP-ADMAIF14")), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF14 CIF"))); + +SND_SOC_DAILINK_DEFS(adsp_admaif15, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP-ADMAIF15")), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF15 CIF"))); + +SND_SOC_DAILINK_DEFS(adsp_admaif16, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP-ADMAIF16")), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF16 CIF"))); + +SND_SOC_DAILINK_DEFS(adsp_admaif17, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP-ADMAIF17")), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF17 CIF"))); + +SND_SOC_DAILINK_DEFS(adsp_admaif18, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP-ADMAIF18")), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF18 CIF"))); + +SND_SOC_DAILINK_DEFS(adsp_admaif19, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP-ADMAIF19")), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF19 CIF"))); + +SND_SOC_DAILINK_DEFS(adsp_admaif20, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP-ADMAIF20")), + DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF20 CIF"))); + + +SND_SOC_DAILINK_DEFS(adsp_pcm1, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP PCM1")), + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt", "ADSP-FE1")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("tegra210-adsp-virt"))); + +SND_SOC_DAILINK_DEFS(adsp_pcm2, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP PCM2")), + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt", "ADSP-FE2")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("tegra210-adsp-virt"))); + +SND_SOC_DAILINK_DEFS(adsp_pcm3, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP PCM3")), + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt", "ADSP-FE3")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("tegra210-adsp-virt"))); + +SND_SOC_DAILINK_DEFS(adsp_pcm4, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP PCM4")), + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt", "ADSP-FE4")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("tegra210-adsp-virt"))); + +SND_SOC_DAILINK_DEFS(adsp_pcm5, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP PCM5")), + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt", "ADSP-FE5")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("tegra210-adsp-virt"))); + +SND_SOC_DAILINK_DEFS(adsp_pcm6, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP PCM6")), + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt", "ADSP-FE6")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("tegra210-adsp-virt"))); + +SND_SOC_DAILINK_DEFS(adsp_pcm7, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP PCM7")), + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt", "ADSP-FE7")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("tegra210-adsp-virt"))); + +SND_SOC_DAILINK_DEFS(adsp_pcm8, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP PCM8")), + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt", "ADSP-FE8")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("tegra210-adsp-virt"))); + +SND_SOC_DAILINK_DEFS(adsp_pcm9, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP PCM9")), + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt", "ADSP-FE9")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("tegra210-adsp-virt"))); + +SND_SOC_DAILINK_DEFS(adsp_pcm10, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP PCM10")), + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt", "ADSP-FE10")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("tegra210-adsp-virt"))); + +SND_SOC_DAILINK_DEFS(adsp_pcm11, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP PCM11")), + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt", "ADSP-FE11")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("tegra210-adsp-virt"))); + +SND_SOC_DAILINK_DEFS(adsp_pcm12, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP PCM12")), + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt", "ADSP-FE12")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("tegra210-adsp-virt"))); + +SND_SOC_DAILINK_DEFS(adsp_pcm13, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP PCM13")), + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt", "ADSP-FE13")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("tegra210-adsp-virt"))); + +SND_SOC_DAILINK_DEFS(adsp_pcm14, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP PCM14")), + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt", "ADSP-FE14")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("tegra210-adsp-virt"))); + +SND_SOC_DAILINK_DEFS(adsp_pcm15, + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt","ADSP PCM15")), + DAILINK_COMP_ARRAY(COMP_CODEC("tegra210-adsp-virt", "ADSP-FE15")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("tegra210-adsp-virt"))); + +static struct snd_soc_dai_link tegra_virt_t186ref_pcm_links[] = { + { + /* 0 */ + .name = DAI_NAME(1), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(audio1), + }, + { + /* 1 */ + .name = DAI_NAME(2), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(audio2), + }, + { + /* 2 */ + .name = DAI_NAME(3), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(audio3), + }, + { + /* 3 */ + .name = DAI_NAME(4), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(audio4), + }, + { + /* 4 */ + .name = DAI_NAME(5), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(audio5), + }, + { + /* 5 */ + .name = DAI_NAME(6), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(audio6), + }, + { + /* 6 */ + .name = DAI_NAME(7), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(audio7), + }, + { + /* 7 */ + .name = DAI_NAME(8), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(audio8), + }, + { + /* 8 */ + .name = DAI_NAME(9), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(audio9), + }, + { + /* 9 */ + .name = DAI_NAME(10), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(audio10), + }, + { + /* 10 */ + .name = DAI_NAME(11), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(audio11), + }, + { + /* 11 */ + .name = DAI_NAME(12), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(audio12), + }, + { + /* 12 */ + .name = DAI_NAME(13), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(audio13), + }, + { + /* 13 */ + .name = DAI_NAME(14), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(audio14), + }, + { + /* 14 */ + .name = DAI_NAME(15), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(audio15), + }, + { + /* 15 */ + .name = DAI_NAME(16), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(audio16), + }, + { + /* 16 */ + .name = DAI_NAME(17), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(audio17), + }, + { + /* 17 */ + .name = DAI_NAME(18), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(audio18), + }, + { + /* 18 */ + .name = DAI_NAME(19), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(audio19), + }, + { + /* 19 */ + .name = DAI_NAME(20), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(audio20), + }, + { + /* 20 */ + .name = "ADSP ADMAIF1", + .stream_name = "ADSP AFMAIF1", + .params = &adsp_default_params, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(adsp_admaif1), + }, + { + /* 21 */ + .name = "ADSP ADMAIF2", + .stream_name = "ADSP AFMAIF2", + .params = &adsp_default_params, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(adsp_admaif2), + }, + { + /* 22 */ + .name = "ADSP ADMAIF3", + .stream_name = "ADSP AFMAIF3", + .params = &adsp_default_params, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(adsp_admaif3), + }, + { + /* 23 */ + .name = "ADSP ADMAIF4", + .stream_name = "ADSP AFMAIF4", + .params = &adsp_default_params, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(adsp_admaif4), + }, + { + /* 24 */ + .name = "ADSP ADMAIF5", + .stream_name = "ADSP AFMAIF5", + .params = &adsp_default_params, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(adsp_admaif5), + }, + { + /* 25 */ + .name = "ADSP ADMAIF6", + .stream_name = "ADSP AFMAIF6", + .params = &adsp_default_params, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(adsp_admaif6), + }, + { + /* 26 */ + .name = "ADSP ADMAIF7", + .stream_name = "ADSP AFMAIF7", + .params = &adsp_default_params, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(adsp_admaif7), + }, + { + /* 27 */ + .name = "ADSP ADMAIF8", + .stream_name = "ADSP AFMAIF8", + .params = &adsp_default_params, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(adsp_admaif8), + }, + { + /* 28 */ + .name = "ADSP ADMAIF9", + .stream_name = "ADSP AFMAIF9", + .params = &adsp_default_params, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(adsp_admaif9), + }, + { + /* 29 */ + .name = "ADSP ADMAIF10", + .stream_name = "ADSP AFMAIF10", + .params = &adsp_default_params, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(adsp_admaif10), + }, + { + /* 30 */ + .name = "ADSP ADMAIF11", + .stream_name = "ADSP AFMAIF11", + .params = &adsp_default_params, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(adsp_admaif11), + }, + { + /* 31 */ + .name = "ADSP ADMAIF12", + .stream_name = "ADSP AFMAIF12", + .params = &adsp_default_params, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(adsp_admaif12), + }, + { + /* 32 */ + .name = "ADSP ADMAIF13", + .stream_name = "ADSP AFMAIF13", + .params = &adsp_default_params, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(adsp_admaif13), + }, + { + /* 33 */ + .name = "ADSP ADMAIF14", + .stream_name = "ADSP AFMAIF14", + .params = &adsp_default_params, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(adsp_admaif14), + }, + { + /* 34 */ + .name = "ADSP ADMAIF15", + .stream_name = "ADSP AFMAIF15", + .params = &adsp_default_params, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(adsp_admaif15), + }, + { + /* 35 */ + .name = "ADSP ADMAIF16", + .stream_name = "ADSP AFMAIF16", + .params = &adsp_default_params, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(adsp_admaif16), + }, + { + /* 36 */ + .name = "ADSP ADMAIF17", + .stream_name = "ADSP AFMAIF17", + .params = &adsp_default_params, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(adsp_admaif17), + }, + { + /* 37 */ + .name = "ADSP ADMAIF18", + .stream_name = "ADSP AFMAIF18", + .params = &adsp_default_params, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(adsp_admaif18), + }, + { + /* 38 */ + .name = "ADSP ADMAIF19", + .stream_name = "ADSP AFMAIF19", + .params = &adsp_default_params, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(adsp_admaif19), + }, + { + /* 39 */ + .name = "ADSP ADMAIF20", + .stream_name = "ADSP AFMAIF20", + .params = &adsp_default_params, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(adsp_admaif20), + }, + { + /* 40 */ + .name = "ADSP PCM1", + .stream_name = "ADSP PCM1", + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(adsp_pcm1), + }, + { + /* 41 */ + .name = "ADSP PCM2", + .stream_name = "ADSP PCM2", + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(adsp_pcm2), + }, + { + .name = "ADSP PCM3", + .stream_name = "ADSP PCM3", + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(adsp_pcm3), + }, + { + .name = "ADSP PCM4", + .stream_name = "ADSP PCM4", + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(adsp_pcm4), + }, + { + .name = "ADSP PCM5", + .stream_name = "ADSP PCM5", + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(adsp_pcm5), + }, + { + .name = "ADSP PCM6", + .stream_name = "ADSP PCM6", + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(adsp_pcm6), + }, + { + .name = "ADSP PCM7", + .stream_name = "ADSP PCM7", + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(adsp_pcm7), + }, + { + .name = "ADSP PCM8", + .stream_name = "ADSP PCM8", + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(adsp_pcm8), + }, + { + .name = "ADSP PCM9", + .stream_name = "ADSP PCM9", + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(adsp_pcm9), + }, + { + .name = "ADSP PCM10", + .stream_name = "ADSP PCM10", + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(adsp_pcm10), + }, + { + .name = "ADSP PCM11", + .stream_name = "ADSP PCM11", + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(adsp_pcm11), + }, + { + .name = "ADSP PCM12", + .stream_name = "ADSP PCM12", + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(adsp_pcm12), + }, + { + .name = "ADSP PCM13", + .stream_name = "ADSP PCM13", + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(adsp_pcm13), + }, + { + .name = "ADSP PCM14", + .stream_name = "ADSP PCM14", + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(adsp_pcm14), + }, + { + .name = "ADSP PCM15", + .stream_name = "ADSP PCM15", + .ignore_pmdown_time = 1, + .ignore_suspend = 0, + SND_SOC_DAILINK_REG(adsp_pcm15), + }, +}; + +static struct snd_soc_dai_link tegra_virt_t210ref_pcm_links[] = { + { + /* 0 */ + .name = DAI_NAME(1), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(audio1), + }, + { + /* 1 */ + .name = DAI_NAME(2), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(audio2), + }, + { + /* 2 */ + .name = DAI_NAME(3), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(audio3), + }, + { + /* 3 */ + .name = DAI_NAME(4), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(audio4), + }, + { + /* 4 */ + .name = DAI_NAME(5), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(audio5), + }, + { + /* 5 */ + .name = DAI_NAME(6), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(audio6), + }, + { + /* 6 */ + .name = DAI_NAME(7), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(audio7), + }, + { + /* 7 */ + .name = DAI_NAME(8), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(audio8), + }, + { + /* 8 */ + .name = DAI_NAME(9), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(audio9), + }, + { + /* 9 */ + .name = DAI_NAME(10), + .stream_name = STREAM_NAME, + .params = &default_params, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(audio10), + }, +}; + +void tegra_virt_machine_set_num_dai_links(unsigned int val) +{ + num_dai_links = val; +} +EXPORT_SYMBOL(tegra_virt_machine_set_num_dai_links); + +unsigned int tegra_virt_machine_get_num_dai_links(void) +{ + return num_dai_links; +} +EXPORT_SYMBOL(tegra_virt_machine_get_num_dai_links); + +struct snd_soc_dai_link *tegra_virt_machine_get_dai_link(void) +{ + struct snd_soc_dai_link *link = tegra_virt_t186ref_pcm_links; + unsigned int size = TEGRA186_XBAR_DAI_LINKS; + + if (of_machine_is_compatible("nvidia,tegra210")) { + link = tegra_virt_t210ref_pcm_links; + size = TEGRA210_XBAR_DAI_LINKS; + } + + tegra_virt_machine_set_num_dai_links(size); + return link; +} +EXPORT_SYMBOL(tegra_virt_machine_get_dai_link); + +void tegra_virt_machine_set_adsp_admaif_dai_params( + uint32_t id, struct snd_soc_pcm_stream *params) +{ + struct snd_soc_dai_link *link = tegra_virt_t186ref_pcm_links; + + /* Check for valid ADSP ADMAIF ID */ + if (id >= MAX_ADMAIF_IDS) { + pr_err("Invalid ADSP ADMAIF ID: %d\n", id); + return; + } + + /* Find DAI link corresponding to ADSP ADMAIF */ + link += id + MAX_ADMAIF_IDS; + + memcpy(&adsp_admaif_params[id], params, + sizeof(struct snd_soc_pcm_stream)); + + link->params = &adsp_admaif_params[id]; +} +EXPORT_SYMBOL(tegra_virt_machine_set_adsp_admaif_dai_params); + +MODULE_AUTHOR("Dipesh Gandhi "); +MODULE_DESCRIPTION("Tegra Virt ASoC machine code"); +MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/sound/soc/tegra-virt-alt/tegra_asoc_machine_virt_alt.h b/sound/soc/tegra-virt-alt/tegra_asoc_machine_virt_alt.h new file mode 100644 index 00000000..fdd23a1f --- /dev/null +++ b/sound/soc/tegra-virt-alt/tegra_asoc_machine_virt_alt.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + */ + +#ifndef __TEGRA_ASOC_MACHINE_VIRT_ALT_H__ +#define __TEGRA_ASOC_MACHINE_VIRT_ALT_H__ + +#include "tegra210_virt_alt_admaif.h" + +enum tegra210_xbar_dai_link { + TEGRA210_DAI_LINK_ADMAIF1, + TEGRA210_DAI_LINK_ADMAIF2, + TEGRA210_DAI_LINK_ADMAIF3, + TEGRA210_DAI_LINK_ADMAIF4, + TEGRA210_DAI_LINK_ADMAIF5, + TEGRA210_DAI_LINK_ADMAIF6, + TEGRA210_DAI_LINK_ADMAIF7, + TEGRA210_DAI_LINK_ADMAIF8, + TEGRA210_DAI_LINK_ADMAIF9, + TEGRA210_DAI_LINK_ADMAIF10, + TEGRA210_XBAR_DAI_LINKS, /* Total number of xbar dai links */ +}; + +enum tegra186_xbar_dai_link { + TEGRA186_DAI_LINK_ADMAIF1, + TEGRA186_DAI_LINK_ADMAIF2, + TEGRA186_DAI_LINK_ADMAIF3, + TEGRA186_DAI_LINK_ADMAIF4, + TEGRA186_DAI_LINK_ADMAIF5, + TEGRA186_DAI_LINK_ADMAIF6, + TEGRA186_DAI_LINK_ADMAIF7, + TEGRA186_DAI_LINK_ADMAIF8, + TEGRA186_DAI_LINK_ADMAIF9, + TEGRA186_DAI_LINK_ADMAIF10, + TEGRA186_DAI_LINK_ADMAIF11, + TEGRA186_DAI_LINK_ADMAIF12, + TEGRA186_DAI_LINK_ADMAIF13, + TEGRA186_DAI_LINK_ADMAIF14, + TEGRA186_DAI_LINK_ADMAIF15, + TEGRA186_DAI_LINK_ADMAIF16, + TEGRA186_DAI_LINK_ADMAIF17, + TEGRA186_DAI_LINK_ADMAIF18, + TEGRA186_DAI_LINK_ADMAIF19, + TEGRA186_DAI_LINK_ADMAIF20, + TEGRA186_DAI_LINK_ADSP_ADMAIF1, + TEGRA186_DAI_LINK_ADSP_ADMAIF2, + TEGRA186_DAI_LINK_ADSP_ADMAIF3, + TEGRA186_DAI_LINK_ADSP_ADMAIF4, + TEGRA186_DAI_LINK_ADSP_ADMAIF5, + TEGRA186_DAI_LINK_ADSP_ADMAIF6, + TEGRA186_DAI_LINK_ADSP_ADMAIF7, + TEGRA186_DAI_LINK_ADSP_ADMAIF8, + TEGRA186_DAI_LINK_ADSP_ADMAIF9, + TEGRA186_DAI_LINK_ADSP_ADMAIF10, + TEGRA186_DAI_LINK_ADSP_ADMAIF11, + TEGRA186_DAI_LINK_ADSP_ADMAIF12, + TEGRA186_DAI_LINK_ADSP_ADMAIF13, + TEGRA186_DAI_LINK_ADSP_ADMAIF14, + TEGRA186_DAI_LINK_ADSP_ADMAIF15, + TEGRA186_DAI_LINK_ADSP_ADMAIF16, + TEGRA186_DAI_LINK_ADSP_ADMAIF17, + TEGRA186_DAI_LINK_ADSP_ADMAIF18, + TEGRA186_DAI_LINK_ADSP_ADMAIF19, + TEGRA186_DAI_LINK_ADSP_ADMAIF20, + TEGRA186_DAI_LINK_ADSP_PCM1, + TEGRA186_DAI_LINK_ADSP_PCM2, + TEGRA186_DAI_LINK_ADSP_PCM3, + TEGRA186_DAI_LINK_ADSP_PCM4, + TEGRA186_DAI_LINK_ADSP_PCM5, + TEGRA186_DAI_LINK_ADSP_PCM6, + TEGRA186_DAI_LINK_ADSP_PCM7, + TEGRA186_DAI_LINK_ADSP_PCM8, + TEGRA186_DAI_LINK_ADSP_PCM9, + TEGRA186_DAI_LINK_ADSP_PCM10, + TEGRA186_DAI_LINK_ADSP_PCM11, + TEGRA186_DAI_LINK_ADSP_PCM12, + TEGRA186_DAI_LINK_ADSP_PCM13, + TEGRA186_DAI_LINK_ADSP_PCM14, + TEGRA186_DAI_LINK_ADSP_PCM15, + TEGRA186_XBAR_DAI_LINKS, /* Total number of xbar dai links */ +}; + +struct snd_soc_dai_link *tegra_virt_machine_get_dai_link(void); +unsigned int tegra_virt_machine_get_num_dai_links(void); +void tegra_virt_machine_set_num_dai_links(unsigned int val); +void tegra_virt_machine_set_adsp_admaif_dai_params( + uint32_t id, struct snd_soc_pcm_stream *params); +#endif \ No newline at end of file diff --git a/sound/soc/tegra-virt-alt/tegra_asoc_util_virt_alt.c b/sound/soc/tegra-virt-alt/tegra_asoc_util_virt_alt.c new file mode 100644 index 00000000..8f7af313 --- /dev/null +++ b/sound/soc/tegra-virt-alt/tegra_asoc_util_virt_alt.c @@ -0,0 +1,1626 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + */ + +#include +#include + +#include "tegra_virt_alt_ivc.h" +#include "tegra_asoc_util_virt_alt.h" + +const int tegra186_arad_mux_value[] = { + -1, /* None */ + 0, 1, 2, 3, 4, 5, /* I2S1~6 */ + 28, 29, 30, 31, /* SPDIF_RX1,2 & SPDIF_TX1,2 */ +}; + +const char * const tegra186_arad_mux_text[] = { + "None", + "I2S1", + "I2S2", + "I2S3", + "I2S4", + "I2S5", + "I2S6", + "SPDIF1_RX1", + "SPDIF1_RX2", + "SPDIF1_TX1", + "SPDIF1_TX2", +}; + +const char * const tegra186_asrc_ratio_source_text[] = { + "ARAD", + "SW", +}; + +const char * const tegra210_mvc_curve_type_text[] = { + "Poly", + "Linear", +}; + +int tegra_virt_t210mixer_get_gain(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int32_t reg = mc->reg; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_AMIXER_GET_RX_GAIN; + msg.params.amixer_info.id = 0; + msg.params.amixer_info.rx_idx = reg; + + err = nvaudio_ivc_send_receive(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) + pr_err("%s: error on ivc_send_receive\n", __func__); + + ucontrol->value.integer.value[0] = + msg.params.amixer_info.gain; + + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210mixer_get_gain); + +int tegra_virt_t210mixer_set_gain(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int32_t reg = mc->reg; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_AMIXER_SET_RX_GAIN; + msg.params.amixer_info.id = 0; + msg.params.amixer_info.rx_idx = reg; + msg.params.amixer_info.gain = + ucontrol->value.integer.value[0]; + msg.params.amixer_info.is_instant_gain = 0; + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210mixer_set_gain); + +int tegra_virt_t210mixer_set_gain_instant(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int32_t reg = mc->reg; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_AMIXER_SET_RX_GAIN; + msg.params.amixer_info.id = 0; + msg.params.amixer_info.rx_idx = reg; + msg.params.amixer_info.gain = + ucontrol->value.integer.value[0]; + msg.params.amixer_info.is_instant_gain = 1; + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210mixer_set_gain_instant); + +int tegra_virt_t210mixer_get_duration(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int32_t reg = mc->reg; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_AMIXER_GET_RX_DURATION; + msg.params.amixer_info.id = 0; + msg.params.amixer_info.rx_idx = reg; + + err = nvaudio_ivc_send_receive(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) + pr_err("%s: error on ivc_send_receive\n", __func__); + + ucontrol->value.integer.value[0] = + msg.params.amixer_info.duration_n3; + + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210mixer_get_duration); + +int tegra_virt_t210mixer_set_duration(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int32_t reg = mc->reg; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_AMIXER_SET_RX_DURATION; + msg.params.amixer_info.id = 0; + msg.params.amixer_info.rx_idx = reg; + msg.params.amixer_info.duration_n3 = + ucontrol->value.integer.value[0]; + msg.params.amixer_info.is_instant_gain = 0; + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210mixer_set_duration); + +int tegra_virt_t210mixer_get_adder_config(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int32_t reg = mc->reg; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_AMIXER_GET_TX_ADDER_CONFIG; + msg.params.amixer_info.id = 0; + msg.params.amixer_info.adder_idx = ((reg) >> + MIXER_CONFIG_SHIFT_VALUE) & 0xFFFF; + msg.params.amixer_info.adder_rx_idx = (reg) & 0xFFFF; + + err = nvaudio_ivc_send_receive(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) + pr_err("%s: error on ivc_send_receive\n", __func__); + + ucontrol->value.integer.value[0] = + msg.params.amixer_info.adder_rx_idx_enable; + + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210mixer_get_adder_config); + +int tegra_virt_t210mixer_set_adder_config(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int32_t reg = mc->reg; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err, connect; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_AMIXER_SET_TX_ADDER_CONFIG; + msg.params.amixer_info.id = 0; + msg.params.amixer_info.adder_idx = ((reg) >> + MIXER_CONFIG_SHIFT_VALUE) & 0xFFFF; + msg.params.amixer_info.adder_rx_idx = (reg) & 0xFFFF; + msg.params.amixer_info.adder_rx_idx_enable = + ucontrol->value.integer.value[0]; + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + connect = !!ucontrol->value.integer.value[0]; + snd_soc_dapm_mixer_update_power(dapm, kcontrol, connect, NULL); + + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210mixer_set_adder_config); + +int tegra_virt_t210mixer_get_enable(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_AMIXER_GET_ENABLE; + msg.params.amixer_info.id = 0; + + err = nvaudio_ivc_send_receive(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) + pr_err("%s: error on ivc_send_receive\n", __func__); + + ucontrol->value.integer.value[0] = msg.params.amixer_info.enable; + + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210mixer_get_enable); +int tegra_virt_t210mixer_set_enable(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_AMIXER_SET_ENABLE; + msg.params.amixer_info.id = 0; + msg.params.amixer_info.enable = + ucontrol->value.integer.value[0]; + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210mixer_set_enable); + +int tegra_virt_t210sfc_get_in_freq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg = mc->reg; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_SFC_GET_IN_FREQ; + msg.params.sfc_info.id = reg; + + err = nvaudio_ivc_send_receive(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + + ucontrol->value.integer.value[0] = msg.params.sfc_info.in_freq; + + if (err < 0) { + pr_err("%s: error on ivc_send_receive\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210sfc_get_in_freq); +int tegra_virt_t210sfc_set_in_freq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg = mc->reg; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_SFC_SET_IN_FREQ; + msg.params.sfc_info.id = reg; + msg.params.sfc_info.in_freq = + ucontrol->value.integer.value[0]; + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210sfc_set_in_freq); + +int tegra_virt_t210sfc_get_out_freq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg = mc->reg; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_SFC_GET_OUT_FREQ; + msg.params.sfc_info.id = reg; + + err = nvaudio_ivc_send_receive(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + + ucontrol->value.integer.value[0] = msg.params.sfc_info.out_freq; + + if (err < 0) { + pr_err("%s: error on ivc_send_receive\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210sfc_get_out_freq); +int tegra_virt_t210sfc_set_out_freq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int32_t reg = mc->reg; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_SFC_SET_OUT_FREQ; + msg.params.sfc_info.id = reg; + msg.params.sfc_info.out_freq = + ucontrol->value.integer.value[0]; + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210sfc_set_out_freq); + +int tegra_virt_t210mvc_get_curve_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg = mc->reg; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_MVC_GET_CURVETYPE; + msg.params.mvc_info.id = reg; + + err = nvaudio_ivc_send_receive(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + + if (err < 0) { + pr_err("%s: error on ivc_send_receive\n", __func__); + return err; + } + + ucontrol->value.integer.value[0] = msg.params.mvc_info.curve_type; + + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210mvc_get_curve_type); + +int tegra_virt_t210mvc_set_curve_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + long int reg = (long int)kcontrol->tlv.p; + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_MVC_SET_CURVETYPE; + msg.params.mvc_info.id = reg; + msg.params.mvc_info.curve_type = + ucontrol->value.integer.value[0]; + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210mvc_set_curve_type); + +int tegra_virt_t210mvc_get_tar_vol(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg = mc->reg; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_MVC_GET_TAR_VOL; + msg.params.mvc_info.id = reg; + + err = nvaudio_ivc_send_receive(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + + if (err < 0) { + pr_err("%s: error on ivc_send_receive\n", __func__); + return err; + } + + ucontrol->value.integer.value[0] = msg.params.mvc_info.tar_vol; + + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210mvc_get_tar_vol); + +int tegra_virt_t210mvc_set_tar_vol(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg = mc->reg; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_MVC_SET_TAR_VOL; + msg.params.mvc_info.id = reg; + msg.params.mvc_info.tar_vol = + ucontrol->value.integer.value[0]; + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210mvc_set_tar_vol); + +int tegra_virt_t210mvc_get_mute(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int32_t reg = mc->reg; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_MVC_GET_MUTE; + msg.params.mvc_info.id = reg; + + err = nvaudio_ivc_send_receive(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + + if (err < 0) { + pr_err("%s: error on ivc_send_receive\n", __func__); + return err; + } + + ucontrol->value.integer.value[0] = msg.params.mvc_info.mute; + + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210mvc_get_mute); + +int tegra_virt_t210mvc_set_mute(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg = mc->reg; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_MVC_SET_MUTE; + msg.params.mvc_info.id = reg; + msg.params.mvc_info.mute = + ucontrol->value.integer.value[0]; + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210mvc_set_mute); + +int tegra186_virt_asrc_get_ratio(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; + int32_t reg = mc->regbase; + int err; + uint64_t val; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_ASRC_GET_RATIO; + msg.params.asrc_info.id = 0; + msg.params.asrc_info.stream_num = reg; + + err = nvaudio_ivc_send_receive(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: error on ivc_send_receive\n", __func__); + return err; + } + + val = (uint64_t) msg.params.asrc_info.int_ratio << 32; + val &= 0xffffffff00000000ULL; + val |= msg.params.asrc_info.frac_ratio; + ucontrol->value.integer64.value[0] = val; + + return 0; +} +EXPORT_SYMBOL(tegra186_virt_asrc_get_ratio); + +int tegra186_virt_asrc_set_ratio(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; + int32_t reg = mc->regbase; + int err; + uint64_t val; + struct nvaudio_ivc_msg msg; + + val = ucontrol->value.integer64.value[0]; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_ASRC_SET_RATIO; + msg.params.asrc_info.id = 0; + msg.params.asrc_info.stream_num = reg; + msg.params.asrc_info.int_ratio = + (val >> 32) & 0xffffffffULL; + msg.params.asrc_info.frac_ratio = + (val & 0xffffffffULL); + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra186_virt_asrc_set_ratio); + +int tegra186_virt_asrc_get_ratio_source(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + uint64_t reg = (uint64_t)kcontrol->tlv.p; + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_ASRC_GET_RATIO_SOURCE; + msg.params.asrc_info.stream_num = reg; + + err = nvaudio_ivc_send_receive(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: error on ivc_send_receive\n", __func__); + return err; + } + + ucontrol->value.integer.value[0] = msg.params.asrc_info.ratio_source; + + return 0; +} +EXPORT_SYMBOL(tegra186_virt_asrc_get_ratio_source); + +int tegra186_virt_asrc_set_ratio_source(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + uint64_t reg = (uint64_t)kcontrol->tlv.p; + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_ASRC_SET_RATIO_SOURCE; + msg.params.asrc_info.id = 0; + msg.params.asrc_info.stream_num = reg; + msg.params.asrc_info.ratio_source = + ucontrol->value.integer.value[0]; + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra186_virt_asrc_set_ratio_source); + +int tegra186_virt_asrc_get_stream_enable(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int32_t reg = mc->reg; + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_ASRC_GET_STREAM_ENABLE; + msg.params.asrc_info.id = 0; + msg.params.asrc_info.stream_num = reg; + + err = nvaudio_ivc_send_receive(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: error on ivc_send_receive\n", __func__); + return err; + } + + ucontrol->value.integer.value[0] = msg.params.asrc_info.stream_enable; + + return 0; +} +EXPORT_SYMBOL(tegra186_virt_asrc_get_stream_enable); + +int tegra186_virt_asrc_set_stream_enable(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int32_t reg = mc->reg; + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_ASRC_SET_STREAM_ENABLE; + msg.params.asrc_info.id = 0; + msg.params.asrc_info.stream_num = reg; + msg.params.asrc_info.stream_enable = + ucontrol->value.integer.value[0]; + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra186_virt_asrc_set_stream_enable); + +int tegra186_virt_asrc_get_hwcomp_disable(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int32_t reg = mc->reg; + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_ASRC_GET_HWCOMP_DISABLE; + msg.params.asrc_info.id = 0; + msg.params.asrc_info.stream_num = reg; + + err = nvaudio_ivc_send_receive(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + ucontrol->value.integer.value[0] = msg.params.asrc_info.hwcomp_disable; + + return 0; +} +EXPORT_SYMBOL(tegra186_virt_asrc_get_hwcomp_disable); + +int tegra186_virt_asrc_set_hwcomp_disable(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int32_t reg = mc->reg; + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_ASRC_SET_HWCOMP_DISABLE; + msg.params.asrc_info.id = 0; + msg.params.asrc_info.stream_num = reg; + msg.params.asrc_info.hwcomp_disable = + ucontrol->value.integer.value[0]; + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra186_virt_asrc_set_hwcomp_disable); + +int tegra186_virt_asrc_get_input_threshold(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int32_t reg = mc->reg; + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_ASRC_GET_INPUT_THRESHOLD; + msg.params.asrc_info.id = 0; + msg.params.asrc_info.stream_num = reg; + + err = nvaudio_ivc_send_receive(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + + ucontrol->value.integer.value[0] = msg.params.sfc_info.out_freq; + + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + ucontrol->value.integer.value[0] = msg.params.asrc_info.input_threshold; + + return 0; +} +EXPORT_SYMBOL(tegra186_virt_asrc_get_input_threshold); + +int tegra186_virt_asrc_set_input_threshold(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int32_t reg = mc->reg; + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_ASRC_SET_INPUT_THRESHOLD; + msg.params.asrc_info.id = 0; + msg.params.asrc_info.stream_num = reg; + msg.params.asrc_info.input_threshold = + ucontrol->value.integer.value[0]; + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra186_virt_asrc_set_input_threshold); + +int tegra186_virt_asrc_get_output_threshold( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int32_t reg = mc->reg; + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_ASRC_GET_OUTPUT_THRESHOLD; + msg.params.asrc_info.id = 0; + msg.params.asrc_info.stream_num = reg; + + err = nvaudio_ivc_send_receive(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + ucontrol->value.integer.value[0] = + msg.params.asrc_info.output_threshold; + + return 0; +} +EXPORT_SYMBOL(tegra186_virt_asrc_get_output_threshold); + +int tegra186_virt_asrc_set_output_threshold( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int32_t reg = mc->reg; + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_ASRC_SET_OUTPUT_THRESHOLD; + msg.params.asrc_info.id = 0; + msg.params.asrc_info.stream_num = reg; + msg.params.asrc_info.output_threshold = + ucontrol->value.integer.value[0]; + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra186_virt_asrc_set_output_threshold); + +int tegra_virt_t210_amx_get_input_stream_enable( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210_amx_get_input_stream_enable); + +int tegra_virt_t210_amx_set_input_stream_enable( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int32_t reg = mc->reg; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_AMX_SET_INPUT_STREAM_ENABLE; + msg.params.amx_info.amx_id = ((reg) >> + MIXER_CONFIG_SHIFT_VALUE) & 0xFFFF; + msg.params.amx_info.amx_stream_id = (reg) & 0xFFFF; + msg.params.amx_info.amx_stream_enable = + ucontrol->value.integer.value[0]; + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210_amx_set_input_stream_enable); + +int tegra186_virt_arad_get_lane_source( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + uint64_t reg = (uint64_t)kcontrol->tlv.p; + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err, i; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_ARAD_GET_LANE_SRC; + msg.params.arad_info.id = 0; + msg.params.arad_info.lane_id = reg % NUM_ARAD_LANES; + + err = nvaudio_ivc_send_receive(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + /* numerator reg 0 to 5, denominator reg 6 to 11 */ + if (reg/NUM_ARAD_LANES) { + for (i = 0; i < NUM_ARAD_SOURCES; i++) { + if (e->values[i] == + msg.params.arad_info.den_source) + break; + } + ucontrol->value.integer.value[0] = i; + } else { + for (i = 0; i < NUM_ARAD_SOURCES; i++) { + if (e->values[i] == + msg.params.arad_info.num_source) + break; + } + ucontrol->value.integer.value[0] = i; + } + + return 0; +} +EXPORT_SYMBOL(tegra186_virt_arad_get_lane_source); + +int tegra186_virt_arad_set_lane_source( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + uint64_t reg = (uint64_t)kcontrol->tlv.p; + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + int source; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_ARAD_SET_LANE_SRC; + msg.params.arad_info.id = 0; + msg.params.arad_info.lane_id = reg % NUM_ARAD_LANES; + + /* numerator reg 0 to 5, denominator reg 6 to 11 */ + source = e->values[ucontrol->value.integer.value[0]]; + if (reg/NUM_ARAD_LANES) { + msg.params.arad_info.num_source = -1; + msg.params.arad_info.den_source = source; + } else { + msg.params.arad_info.num_source = source; + msg.params.arad_info.den_source = -1; + } + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra186_virt_arad_set_lane_source); + +int tegra186_virt_arad_get_lane_prescalar( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg = mc->reg; + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_ARAD_GET_PRESCALAR; + msg.params.arad_info.id = 0; + msg.params.arad_info.lane_id = reg % NUM_ARAD_LANES; + + err = nvaudio_ivc_send_receive(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + /* numerator reg 0 to 5, denominator reg 6 to 11 */ + if (reg/NUM_ARAD_LANES) + ucontrol->value.integer.value[0] = + msg.params.arad_info.den_prescalar; + else + ucontrol->value.integer.value[0] = + msg.params.arad_info.num_prescalar; + + return 0; +} +EXPORT_SYMBOL(tegra186_virt_arad_get_lane_prescalar); + +int tegra186_virt_arad_set_lane_prescalar( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg = mc->reg; + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_ARAD_SET_PRESCALAR; + msg.params.arad_info.id = 0; + msg.params.arad_info.lane_id = reg % NUM_ARAD_LANES; + + /* numerator reg 0 to 5, denominator reg 6 to 11 */ + if (reg/NUM_ARAD_LANES) { + msg.params.arad_info.num_prescalar = -1; + msg.params.arad_info.den_prescalar = + ucontrol->value.integer.value[0]; + } else { + msg.params.arad_info.num_prescalar = + ucontrol->value.integer.value[0]; + msg.params.arad_info.den_prescalar = -1; + } + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra186_virt_arad_set_lane_prescalar); + +int tegra186_virt_arad_get_lane_enable( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg = mc->reg; + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_ARAD_GET_LANE_ENABLE; + msg.params.arad_info.id = 0; + msg.params.arad_info.lane_id = reg; + + err = nvaudio_ivc_send_receive(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + ucontrol->value.integer.value[0] = + msg.params.arad_info.lane_enable; + + return 0; +} +EXPORT_SYMBOL(tegra186_virt_arad_get_lane_enable); + +int tegra186_virt_arad_set_lane_enable( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg = mc->reg; + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_ARAD_SET_LANE_ENABLE; + msg.params.arad_info.id = 0; + msg.params.arad_info.lane_id = reg; + msg.params.arad_info.lane_enable = + ucontrol->value.integer.value[0]; + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra186_virt_arad_set_lane_enable); + +int tegra186_virt_arad_get_lane_ratio( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg = mc->reg; + int err; + uint64_t val; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_ARAD_GET_LANE_RATIO; + msg.params.arad_info.id = 0; + msg.params.arad_info.lane_id = reg; + + err = nvaudio_ivc_send_receive(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + val = (uint64_t)msg.params.arad_info.int_ratio << 32; + val &= 0xffffffff00000000ULL; + val |= (uint64_t)msg.params.arad_info.frac_ratio; + ucontrol->value.integer64.value[0] = val; + + return 0; +} +EXPORT_SYMBOL(tegra186_virt_arad_get_lane_ratio); + +int tegra_virt_i2s_get_loopback_enable( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg = mc->reg; + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_I2S_GET_LOOPBACK_ENABLE; + msg.params.i2s_info.i2s_id = reg; + + err = nvaudio_ivc_send_receive(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + ucontrol->value.integer.value[0] = + msg.params.i2s_info.i2s_loopback_enable; + + return 0; +} +EXPORT_SYMBOL(tegra_virt_i2s_get_loopback_enable); + +int tegra_virt_i2s_set_loopback_enable( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg = mc->reg; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_I2S_SET_LOOPBACK_ENABLE; + msg.params.i2s_info.i2s_id = reg; + msg.params.i2s_info.i2s_loopback_enable = + ucontrol->value.integer.value[0]; + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra_virt_i2s_set_loopback_enable); + +int tegra_virt_i2s_get_rate( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg = mc->reg; + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_I2S_GET_RATE; + msg.params.i2s_info.i2s_id = reg; + + err = nvaudio_ivc_send_receive(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + ucontrol->value.integer.value[0] = + msg.params.i2s_info.i2s_rate; + + return 0; +} +EXPORT_SYMBOL(tegra_virt_i2s_get_rate); + +int tegra_virt_i2s_set_rate( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int32_t reg = mc->reg; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_I2S_SET_RATE; + msg.params.i2s_info.i2s_id = reg; + msg.params.i2s_info.i2s_rate = + ucontrol->value.integer.value[0]; + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra_virt_i2s_set_rate); + +int tegra_virt_t210ahub_get_regdump(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210ahub_get_regdump); + +int tegra_virt_t210ahub_set_regdump(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int32_t reg = mc->reg; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_AHUB_BLOCK_REGDUMP; + msg.params.ahub_block_info.block_id = (reg) & 0xFFFF; + msg.params.ahub_block_info.stream_id = ((reg) >> + STREAM_ID_SHIFT_VALUE) & 0xFF; + msg.params.ahub_block_info.dump_cmd = ((reg) >> + REGDUMP_CMD_SHIFT_VALUE) & 0xFF; + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210ahub_set_regdump); + + +int tegra_virt_t210adma_get_regdump(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210adma_get_regdump); + +int tegra_virt_t210adma_set_regdump(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg = mc->reg; + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_ADMA_BLOCK_REGDUMP; + msg.params.adma_info.channel_num = (uint32_t)reg; + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210adma_set_regdump); + +//Set mixer fade +int tegra_virt_t210mixer_set_fade(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err, id; + uint32_t rx_id, rx_gain, rx_dur; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_AMIXER_SET_FADE; + msg.params.fade_info.id = 0; + + for (id = 0; id < TEGRA210_MIXER_AXBAR_RX_MAX; id++) { + + rx_id = ucontrol->value.integer.value[3 * id]; + rx_gain = ucontrol->value.integer.value[(3 * id) + 1]; + rx_dur = ucontrol->value.integer.value[(3 * id) + 2]; + + // Checking for end of input data + if (rx_id == 0 && rx_gain == 0 && rx_dur == 0) + break; + + // Checking for valid rx id + if (rx_id <= 0 || rx_id > TEGRA210_MIXER_AXBAR_RX_MAX) { + pr_err("Mixer id is out of range\n"); + return -EINVAL; + } + + // Making rx id zero-indexed for audio server + rx_id = rx_id - 1; + + msg.params.fade_info.rx_idx |= (1 << rx_id); + msg.params.fade_info.gain_level[rx_id] = rx_gain; + msg.params.fade_info.duration_n3[rx_id] = rx_dur; + + } + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210mixer_set_fade); + +// Dummy get fade +int tegra_virt_t210mixer_get_fade(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210mixer_get_fade); + +//Get fade status +int tegra_virt_t210mixer_get_fade_status(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + + int err, id; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_AMIXER_GET_FADE_STATUS; + msg.params.fade_status.id = 0; + + err = nvaudio_ivc_send_receive(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) + pr_err("%s: error on ivc_send_receive\n", __func__); + + for (id = 0; id < TEGRA210_MIXER_AXBAR_RX_MAX; id++) { + ucontrol->value.integer.value[id] = + msg.params.fade_status.status[id]; + } + + return 0; +} +EXPORT_SYMBOL(tegra_virt_t210mixer_get_fade_status); + +//Fade param info +int tegra_virt_t210mixer_param_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct soc_bytes *params = (void *)kcontrol->private_value; + + if (params->mask == SNDRV_CTL_ELEM_TYPE_INTEGER) { + params->num_regs = 30; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 0xffffffff; + } + uinfo->type = params->mask; + uinfo->count = params->num_regs; + + return 0; +} + +MODULE_AUTHOR("Dipesh Gandhi "); +MODULE_DESCRIPTION("Tegra Virt ASoC utility code"); +MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/sound/soc/tegra-virt-alt/tegra_asoc_util_virt_alt.h b/sound/soc/tegra-virt-alt/tegra_asoc_util_virt_alt.h new file mode 100644 index 00000000..035497db --- /dev/null +++ b/sound/soc/tegra-virt-alt/tegra_asoc_util_virt_alt.h @@ -0,0 +1,418 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + */ + +#ifndef __LINUX_VIRT_UTIL_H +#define __LINUX_VIRT_UTIL_H + +#include + +#define MIXER_CONFIG_SHIFT_VALUE 16 +#define STREAM_ID_SHIFT_VALUE 16 +#define REGDUMP_CMD_SHIFT_VALUE 24 +#define MIXER_MAX_RX_GAIN 0x7FFFFFFF +#define TEGRA186_ASRC_STREAM_RATIO_INTEGER_PART_MASK 0x1F +#define TEGRA186_ASRC_STREAM_RATIO_FRAC_PART_MASK 0xFFFFFFFF +#define TEGRA186_ASRC_STREAM_RATIO_MASK 0x1FFFFFFFFF +#define NUM_ARAD_SOURCES 11 +#define NUM_ARAD_LANES 6 +#define NUM_ASRC_MODE 2 +#define NUM_MVC_CURVETYPE 2 +#define MAX_MVC_TAR_VOL 16000 + +#define MIXER_GAIN_CTRL_DECL(ename, reg) \ + SOC_SINGLE_EXT(ename, reg, \ + 0, MIXER_MAX_RX_GAIN, 0, \ + tegra_virt_t210mixer_get_gain, \ + tegra_virt_t210mixer_set_gain) + +#define MIXER_GAIN_INSTANT_CTRL_DECL(ename, reg) \ + SOC_SINGLE_EXT(ename, reg, \ + 0, MIXER_MAX_RX_GAIN, 0, \ + tegra_virt_t210mixer_get_gain, \ + tegra_virt_t210mixer_set_gain_instant) + +#define MIXER_DURATION_CTRL_DECL(ename, reg) \ + SOC_SINGLE_EXT(ename, reg, \ + 64, 0x7FFFFFFF, 0, \ + tegra_virt_t210mixer_get_duration, \ + tegra_virt_t210mixer_set_duration) + +#define REG_PACK(id1, id2) ((id1 << MIXER_CONFIG_SHIFT_VALUE) | id2) +#define MIXER_ADDER_CTRL_DECL(ename, reg1, reg2) \ + SOC_SINGLE_EXT(ename, REG_PACK(reg1, reg2), \ + 0, 1, 0, \ + tegra_virt_t210mixer_get_adder_config, \ + tegra_virt_t210mixer_set_adder_config) + +#define MIXER_ENABLE_CTRL_DECL(ename, reg) \ + SOC_SINGLE_EXT(ename, reg, \ + 0, 1, 0, \ + tegra_virt_t210mixer_get_enable, \ + tegra_virt_t210mixer_set_enable) + +#define SFC_IN_FREQ_CTRL_DECL(ename, id) \ + SOC_SINGLE_EXT(ename, id, \ + 0, 192000, 0, \ + tegra_virt_t210sfc_get_in_freq, \ + tegra_virt_t210sfc_set_in_freq) + +#define SFC_OUT_FREQ_CTRL_DECL(ename, id) \ + SOC_SINGLE_EXT(ename, id, \ + 0, 192000, 0, \ + tegra_virt_t210sfc_get_out_freq, \ + tegra_virt_t210sfc_set_out_freq) + +#define MVC_CURVE_TYPE_CTRL_DECL(ename, reg, src) \ + SOC_ENUM_EXT_REG(ename, reg, \ + src, \ + tegra_virt_t210mvc_get_curve_type, \ + tegra_virt_t210mvc_set_curve_type) + +#define MVC_TAR_VOL_CTRL_DECL(ename, id) \ + SOC_SINGLE_EXT(ename, id, \ + 0, MAX_MVC_TAR_VOL, 0, \ + tegra_virt_t210mvc_get_tar_vol, \ + tegra_virt_t210mvc_set_tar_vol) + +#define MVC_MUTE_CTRL_DECL(ename, reg) \ + SOC_SINGLE_EXT(ename, reg, \ + 0, 1, 0, \ + tegra_virt_t210mvc_get_mute, \ + tegra_virt_t210mvc_set_mute) + +#define SOC_SINGLE_EXT_FRAC(xname, xregbase, xmax, xget, xput) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .info = snd_soc_info_xr_sx, .get = xget, \ + .put = xput, \ + .private_value = (unsigned long)&(struct soc_mreg_control) \ + {.regbase = xregbase, .regcount = 1, .nbits = 32, \ + .invert = 0, .min = 0, .max = xmax} } + +#define ASRC_RATIO_CTRL_DECL(ename, reg) \ + SOC_SINGLE_EXT_FRAC(ename, reg, \ + TEGRA186_ASRC_STREAM_RATIO_MASK, \ + tegra186_virt_asrc_get_ratio, \ + tegra186_virt_asrc_set_ratio) + +#define ASRC_STREAM_RATIO_CTRL_DECL(ename, reg, src) \ + SOC_ENUM_EXT_REG(ename, reg, \ + src, \ + tegra186_virt_asrc_get_ratio_source, \ + tegra186_virt_asrc_set_ratio_source) + +#define ASRC_STREAM_ENABLE_CTRL_DECL(ename, reg) \ + SOC_SINGLE_EXT(ename, reg, \ + 0, 1, 0, \ + tegra186_virt_asrc_get_stream_enable, \ + tegra186_virt_asrc_set_stream_enable) + +#define ASRC_STREAM_HWCOMP_CTRL_DECL(ename, reg) \ + SOC_SINGLE_EXT(ename, reg, \ + 0, 1, 0, \ + tegra186_virt_asrc_get_hwcomp_disable, \ + tegra186_virt_asrc_set_hwcomp_disable) + +#define ASRC_STREAM_INPUT_THRESHOLD_CTRL_DECL(ename, reg) \ + SOC_SINGLE_EXT(ename, reg, \ + 0, 3, 0, \ + tegra186_virt_asrc_get_input_threshold, \ + tegra186_virt_asrc_set_input_threshold) + +#define ASRC_STREAM_OUTPUT_THRESHOLD_CTRL_DECL(ename, reg) \ + SOC_SINGLE_EXT(ename, reg, \ + 0, 3, 0, \ + tegra186_virt_asrc_get_output_threshold, \ + tegra186_virt_asrc_set_output_threshold) + +#define AMX_ENABLE_CTRL_DECL(ename, reg1, reg2) \ + SOC_SINGLE_EXT(ename, REG_PACK(reg1, reg2), \ + 0, 1, 0, \ + tegra_virt_t210_amx_get_input_stream_enable, \ + tegra_virt_t210_amx_set_input_stream_enable) + +#define ARAD_LANE_SOURCE_CTRL_DECL(ename, reg, src) \ + SOC_ENUM_EXT_REG(ename, reg, \ + src, \ + tegra186_virt_arad_get_lane_source, \ + tegra186_virt_arad_set_lane_source) + +#define ARAD_LANE_PRESCALAR_CTRL_DECL(ename, reg) \ + SOC_SINGLE_EXT(ename, reg, \ + 0, 65535, 0, \ + tegra186_virt_arad_get_lane_prescalar, \ + tegra186_virt_arad_set_lane_prescalar) + +#define ARAD_LANE_ENABLE_CTRL_DECL(ename, reg) \ + SOC_SINGLE_EXT(ename, reg, \ + 0, 1, 0, \ + tegra186_virt_arad_get_lane_enable, \ + tegra186_virt_arad_set_lane_enable) + +#define ARAD_LANE_RATIO_CTRL_DECL(ename, reg) \ + SOC_SINGLE_EXT(ename, reg, \ + 0, 0xFFFFFFFF, 0, \ + tegra186_virt_arad_get_lane_ratio, NULL) + +#define I2S_LOOPBACK_ENABLE_CTRL_DECL(ename, reg) \ + SOC_SINGLE_EXT(ename, reg, \ + 0, 1, 0, \ + tegra_virt_i2s_get_loopback_enable, \ + tegra_virt_i2s_set_loopback_enable) + +#define I2S_SET_RATE(ename, reg) \ + SOC_SINGLE_EXT(ename, reg, \ + 0, 96000, 0, \ + tegra_virt_i2s_get_rate, \ + tegra_virt_i2s_set_rate) + +#define MIXER_SET_FADE(xname, xbase) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .info = tegra_virt_t210mixer_param_info, \ + .name = xname, \ + .put = tegra_virt_t210mixer_set_fade, \ + .get = tegra_virt_t210mixer_get_fade, \ + .private_value = \ + ((unsigned long)&(struct soc_bytes) \ + {.base = xbase, .num_regs = 128, \ + .mask = SNDRV_CTL_ELEM_TYPE_INTEGER}) } + +#define MIXER_GET_FADE_STATUS(xname, xbase) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .info = tegra_virt_t210mixer_param_info, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ, \ + .name = xname, \ + .get = tegra_virt_t210mixer_get_fade_status, \ + .private_value = \ + ((unsigned long)&(struct soc_bytes) \ + {.base = xbase, .num_regs = 128, \ + .mask = SNDRV_CTL_ELEM_TYPE_INTEGER}) } + +#define REGDUMP_PACK(id1, id2, id3) \ + (id1 | (id2 << STREAM_ID_SHIFT_VALUE) | (id3 << REGDUMP_CMD_SHIFT_VALUE)) +#define REGDUMP_CTRL_DECL(ename, id, stream_id, cmd) \ + SOC_SINGLE_EXT(ename, REGDUMP_PACK(id, stream_id, cmd), \ + 0, 1, 0, \ + tegra_virt_t210ahub_get_regdump, \ + tegra_virt_t210ahub_set_regdump) + +#define ADMA_REGDUMP_CTRL_DECL(ename, channel_id) \ + SOC_SINGLE_EXT(ename, channel_id, \ + 0, 1, 0, \ + tegra_virt_t210adma_get_regdump, \ + tegra_virt_t210adma_set_regdump) + +#define ADDER_CTRL_DECL(name, id) \ + static const struct snd_kcontrol_new name[] = { \ +MIXER_ADDER_CTRL_DECL("RX1", id, 0x01), \ +MIXER_ADDER_CTRL_DECL("RX2", id, 0x02), \ +MIXER_ADDER_CTRL_DECL("RX3", id, 0x03), \ +MIXER_ADDER_CTRL_DECL("RX4", id, 0x04), \ +MIXER_ADDER_CTRL_DECL("RX5", id, 0x05), \ +MIXER_ADDER_CTRL_DECL("RX6", id, 0x06), \ +MIXER_ADDER_CTRL_DECL("RX7", id, 0x07), \ +MIXER_ADDER_CTRL_DECL("RX8", id, 0x08), \ +MIXER_ADDER_CTRL_DECL("RX9", id, 0x09), \ +MIXER_ADDER_CTRL_DECL("RX10", id, 0x0a), \ +} + +enum { + numerator1_enum = 0, + numerator2_enum, + numerator3_enum, + numerator4_enum, + numerator5_enum, + numerator6_enum, + denominator1_enum = NUM_ARAD_LANES, + denominator2_enum, + denominator3_enum, + denominator4_enum, + denominator5_enum, + denominator6_enum, +}; + +extern const int tegra186_arad_mux_value[]; +extern const char * const tegra186_arad_mux_text[]; +extern const char * const tegra186_asrc_ratio_source_text[]; +extern const char * const tegra210_mvc_curve_type_text[]; + +static inline int tegra_register_component(struct device *dev, + const struct snd_soc_component_driver *component_driver, + struct snd_soc_dai_driver *dai_drv, + int num_dai, const char *debugfs_prefix) +{ + struct snd_soc_component *component; + int ret; + + component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL); + if (!component) + return -ENOMEM; + + ret = snd_soc_component_initialize(component, component_driver, dev); + if (ret < 0) + return ret; + +#ifdef CONFIG_DEBUG_FS + component->debugfs_prefix = debugfs_prefix; +#endif + + return snd_soc_add_component(component, dai_drv, num_dai); +} + +int tegra_virt_t210mixer_get_gain(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int tegra_virt_t210mixer_set_gain(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int tegra_virt_t210mixer_set_gain_instant(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra_virt_t210mixer_get_duration(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int tegra_virt_t210mixer_set_duration(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra_virt_t210mixer_get_adder_config(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra_virt_t210mixer_set_adder_config(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra_virt_t210mixer_get_enable(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra_virt_t210mixer_set_enable(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra_virt_t210sfc_get_in_freq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra_virt_t210sfc_set_in_freq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra_virt_t210sfc_get_out_freq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int tegra_virt_t210sfc_set_out_freq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra_virt_t210mvc_get_curve_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int tegra_virt_t210mvc_set_curve_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra_virt_t210mvc_get_tar_vol(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int tegra_virt_t210mvc_set_tar_vol(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra_virt_t210mvc_get_mute(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int tegra_virt_t210mvc_set_mute(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra186_virt_asrc_get_ratio(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra186_virt_asrc_set_ratio(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra186_virt_asrc_get_ratio_source(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int tegra186_virt_asrc_set_ratio_source(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int tegra186_virt_asrc_get_stream_enable(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra186_virt_asrc_set_stream_enable(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra186_virt_asrc_get_hwcomp_disable(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra186_virt_asrc_set_hwcomp_disable(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int tegra186_virt_asrc_get_input_threshold(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra186_virt_asrc_set_input_threshold(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra186_virt_asrc_get_output_threshold( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int tegra186_virt_asrc_set_output_threshold(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra_virt_t210_amx_get_input_stream_enable(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int tegra_virt_t210_amx_set_input_stream_enable(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + + +int tegra186_virt_arad_get_lane_source( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int tegra186_virt_arad_set_lane_source( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra186_virt_arad_get_lane_prescalar( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra186_virt_arad_set_lane_prescalar( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra186_virt_arad_get_lane_enable( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra186_virt_arad_set_lane_enable( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra186_virt_arad_get_lane_ratio( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra_virt_i2s_set_loopback_enable( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int tegra_virt_i2s_get_loopback_enable( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra_virt_i2s_set_rate( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int tegra_virt_i2s_get_rate( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +//Mixer fade +int tegra_virt_t210mixer_get_fade_status( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int tegra_virt_t210mixer_set_fade( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int tegra_virt_t210mixer_get_fade( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int tegra_virt_t210mixer_param_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +int tegra_virt_t210ahub_get_regdump( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int tegra_virt_t210ahub_set_regdump( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int tegra_virt_t210adma_set_regdump( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int tegra_virt_t210adma_get_regdump( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +#endif \ No newline at end of file diff --git a/sound/soc/tegra-virt-alt/tegra_asoc_xbar_virt_alt.c b/sound/soc/tegra-virt-alt/tegra_asoc_xbar_virt_alt.c new file mode 100644 index 00000000..ccff82a1 --- /dev/null +++ b/sound/soc/tegra-virt-alt/tegra_asoc_xbar_virt_alt.c @@ -0,0 +1,1127 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + */ + +#include + +#include "tegra_virt_alt_ivc.h" +#include "tegra_asoc_util_virt_alt.h" +#include "tegra_asoc_xbar_virt_alt.h" + +static const struct soc_enum *tegra_virt_enum_source; + +#define DAI(sname) \ + { \ + .name = #sname " CIF", \ + .playback = { \ + .stream_name = #sname " CIF Receive", \ + .channels_min = 1, \ + .channels_max = 16, \ + .rates = SNDRV_PCM_RATE_8000_192000, \ + .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + }, \ + .capture = { \ + .stream_name = #sname " CIF Transmit", \ + .channels_min = 1, \ + .channels_max = 16, \ + .rates = SNDRV_PCM_RATE_8000_192000, \ + .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + }, \ + } + +static struct snd_soc_dai_driver tegra186_virt_xbar_dais[] = { + DAI(ADMAIF1), + DAI(ADMAIF2), + DAI(ADMAIF3), + DAI(ADMAIF4), + DAI(ADMAIF5), + DAI(ADMAIF6), + DAI(ADMAIF7), + DAI(ADMAIF8), + DAI(ADMAIF9), + DAI(ADMAIF10), + DAI(ADMAIF11), + DAI(ADMAIF12), + DAI(ADMAIF13), + DAI(ADMAIF14), + DAI(ADMAIF15), + DAI(ADMAIF16), + DAI(ADMAIF17), + DAI(ADMAIF18), + DAI(ADMAIF19), + DAI(ADMAIF20), +}; + +const int tegra_virt_t210ref_source_value[] = { + /* Mux0 input, Mux1 input, Mux2 input */ + 0, + MUX_VALUE(0, 0), + MUX_VALUE(0, 1), + MUX_VALUE(0, 2), + MUX_VALUE(0, 3), + MUX_VALUE(0, 4), + MUX_VALUE(0, 5), + MUX_VALUE(0, 6), + MUX_VALUE(0, 7), + MUX_VALUE(0, 8), + MUX_VALUE(0, 9), + MUX_VALUE(0, 16), + MUX_VALUE(0, 17), + MUX_VALUE(0, 18), + MUX_VALUE(0, 19), + MUX_VALUE(0, 20), + MUX_VALUE(0, 24), + MUX_VALUE(0, 25), + MUX_VALUE(0, 26), + MUX_VALUE(0, 27), + MUX_VALUE(1, 0), + MUX_VALUE(1, 1), + MUX_VALUE(1, 2), + MUX_VALUE(1, 3), + MUX_VALUE(1, 4), + MUX_VALUE(1, 8), + MUX_VALUE(1, 9), + MUX_VALUE(1, 20), + MUX_VALUE(1, 21), + MUX_VALUE(1, 24), + MUX_VALUE(1, 25), + MUX_VALUE(1, 26), + MUX_VALUE(1, 27), + MUX_VALUE(1, 28), + MUX_VALUE(1, 29), + MUX_VALUE(2, 0), + MUX_VALUE(2, 1), + MUX_VALUE(2, 4), + MUX_VALUE(2, 8), + MUX_VALUE(2, 9), + MUX_VALUE(2, 12), + MUX_VALUE(2, 13), + MUX_VALUE(2, 14), + MUX_VALUE(2, 15), + MUX_VALUE(2, 18), + MUX_VALUE(2, 19), + MUX_VALUE(2, 20), + MUX_VALUE(2, 24), + MUX_VALUE(2, 25), + MUX_VALUE(2, 26), + MUX_VALUE(2, 27), + MUX_VALUE(2, 28), + MUX_VALUE(2, 29), + MUX_VALUE(2, 30), + MUX_VALUE(2, 31), + /* index 35..53 above are inputs of PART2 Mux */ +}; + +const char * const tegra_virt_t210ref_source_text[] = { + "None", + "ADMAIF1", + "ADMAIF2", + "ADMAIF3", + "ADMAIF4", + "ADMAIF5", + "ADMAIF6", + "ADMAIF7", + "ADMAIF8", + "ADMAIF9", + "ADMAIF10", + "I2S1", + "I2S2", + "I2S3", + "I2S4", + "I2S5", + "SFC1", + "SFC2", + "SFC3", + "SFC4", + "MIXER1-1", + "MIXER1-2", + "MIXER1-3", + "MIXER1-4", + "MIXER1-5", + "AMX1", + "AMX2", + "SPDIF1-1", + "SPDIF1-2", + "AFC1", + "AFC2", + "AFC3", + "AFC4", + "AFC5", + "AFC6", + "OPE1", + "OPE2", + "SPKPROT1", + "MVC1", + "MVC2", + "IQC1-1", + "IQC1-2", + "IQC2-1", + "IQC2-2", + "DMIC1", + "DMIC2", + "DMIC3", + "ADX1-1", + "ADX1-2", + "ADX1-3", + "ADX1-4", + "ADX2-1", + "ADX2-2", + "ADX2-3", + "ADX2-4", +}; + +const int tegra_virt_t186ref_source_value[] = { + 0, + MUX_VALUE(0, 0), + MUX_VALUE(0, 1), + MUX_VALUE(0, 2), + MUX_VALUE(0, 3), + MUX_VALUE(0, 4), + MUX_VALUE(0, 5), + MUX_VALUE(0, 6), + MUX_VALUE(0, 7), + MUX_VALUE(0, 8), + MUX_VALUE(0, 9), + MUX_VALUE(0, 10), + MUX_VALUE(0, 11), + MUX_VALUE(0, 12), + MUX_VALUE(0, 13), + MUX_VALUE(0, 14), + MUX_VALUE(0, 15), + MUX_VALUE(0, 16), + MUX_VALUE(0, 17), + MUX_VALUE(0, 18), + MUX_VALUE(0, 19), + MUX_VALUE(0, 20), + MUX_VALUE(0, 21), + MUX_VALUE(0, 24), + MUX_VALUE(0, 25), + MUX_VALUE(0, 26), + MUX_VALUE(0, 27), + MUX_VALUE(1, 0), + MUX_VALUE(1, 1), + MUX_VALUE(1, 2), + MUX_VALUE(1, 3), + MUX_VALUE(1, 4), + MUX_VALUE(1, 8), + MUX_VALUE(1, 9), + MUX_VALUE(1, 10), + MUX_VALUE(1, 11), + MUX_VALUE(1, 16), + MUX_VALUE(1, 20), + MUX_VALUE(1, 21), + MUX_VALUE(1, 24), + MUX_VALUE(1, 25), + MUX_VALUE(1, 26), + MUX_VALUE(1, 27), + MUX_VALUE(1, 28), + MUX_VALUE(1, 29), + MUX_VALUE(2, 0), + MUX_VALUE(2, 4), + MUX_VALUE(2, 8), + MUX_VALUE(2, 9), + MUX_VALUE(2, 12), + MUX_VALUE(2, 13), + MUX_VALUE(2, 14), + MUX_VALUE(2, 15), + MUX_VALUE(2, 18), + MUX_VALUE(2, 19), + MUX_VALUE(2, 20), + MUX_VALUE(2, 21), + MUX_VALUE(2, 24), + MUX_VALUE(2, 25), + MUX_VALUE(2, 26), + MUX_VALUE(2, 27), + MUX_VALUE(2, 28), + MUX_VALUE(2, 29), + MUX_VALUE(2, 30), + MUX_VALUE(2, 31), + MUX_VALUE(3, 0), + MUX_VALUE(3, 1), + MUX_VALUE(3, 2), + MUX_VALUE(3, 3), + MUX_VALUE(3, 4), + MUX_VALUE(3, 5), + MUX_VALUE(3, 6), + MUX_VALUE(3, 7), + MUX_VALUE(3, 16), + MUX_VALUE(3, 17), + MUX_VALUE(3, 18), + MUX_VALUE(3, 19), + MUX_VALUE(3, 24), + MUX_VALUE(3, 25), + MUX_VALUE(3, 26), + MUX_VALUE(3, 27), + MUX_VALUE(3, 28), + MUX_VALUE(3, 29), +}; + +const char * const tegra_virt_t186ref_source_text[] = { + "None", + "ADMAIF1", + "ADMAIF2", + "ADMAIF3", + "ADMAIF4", + "ADMAIF5", + "ADMAIF6", + "ADMAIF7", + "ADMAIF8", + "ADMAIF9", + "ADMAIF10", + "ADMAIF11", + "ADMAIF12", + "ADMAIF13", + "ADMAIF14", + "ADMAIF15", + "ADMAIF16", + "I2S1", + "I2S2", + "I2S3", + "I2S4", + "I2S5", + "I2S6", + "SFC1", + "SFC2", + "SFC3", + "SFC4", + "MIXER1-1", + "MIXER1-2", + "MIXER1-3", + "MIXER1-4", + "MIXER1-5", + "AMX1", + "AMX2", + "AMX3", + "AMX4", + "ARAD1", + "SPDIF1-1", + "SPDIF1-2", + "AFC1", + "AFC2", + "AFC3", + "AFC4", + "AFC5", + "AFC6", + "OPE1", + "SPKPROT1", + "MVC1", + "MVC2", + "IQC1-1", + "IQC1-2", + "IQC2-1", + "IQC2-2", + "DMIC1", + "DMIC2", + "DMIC3", + "DMIC4", + "ADX1-1", + "ADX1-2", + "ADX1-3", + "ADX1-4", + "ADX2-1", + "ADX2-2", + "ADX2-3", + "ADX2-4", + "ADX3-1", + "ADX3-2", + "ADX3-3", + "ADX3-4", + "ADX4-1", + "ADX4-2", + "ADX4-3", + "ADX4-4", + "ADMAIF17", + "ADMAIF18", + "ADMAIF19", + "ADMAIF20", + "ASRC1-1", + "ASRC1-2", + "ASRC1-3", + "ASRC1-4", + "ASRC1-5", + "ASRC1-6", +}; + +MUX_ENUM_CTRL_DECL_186(admaif1_tx, 0x00); +MUX_ENUM_CTRL_DECL_186(admaif2_tx, 0x01); +MUX_ENUM_CTRL_DECL_186(admaif3_tx, 0x02); +MUX_ENUM_CTRL_DECL_186(admaif4_tx, 0x03); +MUX_ENUM_CTRL_DECL_186(admaif5_tx, 0x04); +MUX_ENUM_CTRL_DECL_186(admaif6_tx, 0x05); +MUX_ENUM_CTRL_DECL_186(admaif7_tx, 0x06); +MUX_ENUM_CTRL_DECL_186(admaif8_tx, 0x07); +MUX_ENUM_CTRL_DECL_186(admaif9_tx, 0x08); +MUX_ENUM_CTRL_DECL_186(admaif10_tx, 0x09); +MUX_ENUM_CTRL_DECL_186(i2s1_tx, 0x10); +MUX_ENUM_CTRL_DECL_186(i2s2_tx, 0x11); +MUX_ENUM_CTRL_DECL_186(i2s3_tx, 0x12); +MUX_ENUM_CTRL_DECL_186(i2s4_tx, 0x13); +MUX_ENUM_CTRL_DECL_186(i2s5_tx, 0x14); +MUX_ENUM_CTRL_DECL_186(sfc1_tx, 0x18); +MUX_ENUM_CTRL_DECL_186(sfc2_tx, 0x19); +MUX_ENUM_CTRL_DECL_186(sfc3_tx, 0x1a); +MUX_ENUM_CTRL_DECL_186(sfc4_tx, 0x1b); +MUX_ENUM_CTRL_DECL_186(mixer11_tx, 0x20); +MUX_ENUM_CTRL_DECL_186(mixer12_tx, 0x21); +MUX_ENUM_CTRL_DECL_186(mixer13_tx, 0x22); +MUX_ENUM_CTRL_DECL_186(mixer14_tx, 0x23); +MUX_ENUM_CTRL_DECL_186(mixer15_tx, 0x24); +MUX_ENUM_CTRL_DECL_186(mixer16_tx, 0x25); +MUX_ENUM_CTRL_DECL_186(mixer17_tx, 0x26); +MUX_ENUM_CTRL_DECL_186(mixer18_tx, 0x27); +MUX_ENUM_CTRL_DECL_186(mixer19_tx, 0x28); +MUX_ENUM_CTRL_DECL_186(mixer110_tx, 0x29); +MUX_ENUM_CTRL_DECL_186(spdif11_tx, 0x34); +MUX_ENUM_CTRL_DECL_186(spdif12_tx, 0x35); +MUX_ENUM_CTRL_DECL_186(afc1_tx, 0x38); +MUX_ENUM_CTRL_DECL_186(afc2_tx, 0x39); +MUX_ENUM_CTRL_DECL_186(afc3_tx, 0x3a); +MUX_ENUM_CTRL_DECL_186(afc4_tx, 0x3b); +MUX_ENUM_CTRL_DECL_186(afc5_tx, 0x3c); +MUX_ENUM_CTRL_DECL_186(afc6_tx, 0x3d); +MUX_ENUM_CTRL_DECL_186(ope1_tx, 0x40); +MUX_ENUM_CTRL_DECL_186(spkprot_tx, 0x44); +MUX_ENUM_CTRL_DECL_186(mvc1_tx, 0x48); +MUX_ENUM_CTRL_DECL_186(mvc2_tx, 0x49); +MUX_ENUM_CTRL_DECL_186(amx11_tx, 0x50); +MUX_ENUM_CTRL_DECL_186(amx12_tx, 0x51); +MUX_ENUM_CTRL_DECL_186(amx13_tx, 0x52); +MUX_ENUM_CTRL_DECL_186(amx14_tx, 0x53); +MUX_ENUM_CTRL_DECL_186(amx21_tx, 0x54); +MUX_ENUM_CTRL_DECL_186(amx22_tx, 0x55); +MUX_ENUM_CTRL_DECL_186(amx23_tx, 0x56); +MUX_ENUM_CTRL_DECL_186(amx24_tx, 0x57); +MUX_ENUM_CTRL_DECL_186(adx1_tx, 0x60); +MUX_ENUM_CTRL_DECL_186(adx2_tx, 0x61); +MUX_ENUM_CTRL_DECL_186(dspk1_tx, 0x30); +MUX_ENUM_CTRL_DECL_186(dspk2_tx, 0x31); +MUX_ENUM_CTRL_DECL_186(amx31_tx, 0x58); +MUX_ENUM_CTRL_DECL_186(amx32_tx, 0x59); +MUX_ENUM_CTRL_DECL_186(amx33_tx, 0x5a); +MUX_ENUM_CTRL_DECL_186(amx34_tx, 0x5b); +MUX_ENUM_CTRL_DECL_186(amx41_tx, 0x64); +MUX_ENUM_CTRL_DECL_186(amx42_tx, 0x65); +MUX_ENUM_CTRL_DECL_186(amx43_tx, 0x66); +MUX_ENUM_CTRL_DECL_186(amx44_tx, 0x67); +MUX_ENUM_CTRL_DECL_186(admaif11_tx, 0x0a); +MUX_ENUM_CTRL_DECL_186(admaif12_tx, 0x0b); +MUX_ENUM_CTRL_DECL_186(admaif13_tx, 0x0c); +MUX_ENUM_CTRL_DECL_186(admaif14_tx, 0x0d); +MUX_ENUM_CTRL_DECL_186(admaif15_tx, 0x0e); +MUX_ENUM_CTRL_DECL_186(admaif16_tx, 0x0f); +MUX_ENUM_CTRL_DECL_186(i2s6_tx, 0x15); +MUX_ENUM_CTRL_DECL_186(adx3_tx, 0x62); +MUX_ENUM_CTRL_DECL_186(adx4_tx, 0x63); +MUX_ENUM_CTRL_DECL_186(admaif17_tx, 0x68); +MUX_ENUM_CTRL_DECL_186(admaif18_tx, 0x69); +MUX_ENUM_CTRL_DECL_186(admaif19_tx, 0x6a); +MUX_ENUM_CTRL_DECL_186(admaif20_tx, 0x6b); +MUX_ENUM_CTRL_DECL_186(asrc11_tx, 0x6c); +MUX_ENUM_CTRL_DECL_186(asrc12_tx, 0x6d); +MUX_ENUM_CTRL_DECL_186(asrc13_tx, 0x6e); +MUX_ENUM_CTRL_DECL_186(asrc14_tx, 0x6f); +MUX_ENUM_CTRL_DECL_186(asrc15_tx, 0x70); +MUX_ENUM_CTRL_DECL_186(asrc16_tx, 0x71); +MUX_ENUM_CTRL_DECL_186(asrc17_tx, 0x72); + + +ADDER_CTRL_DECL(Adder1, 0x0); +ADDER_CTRL_DECL(Adder2, 0x1); +ADDER_CTRL_DECL(Adder3, 0x2); +ADDER_CTRL_DECL(Adder4, 0x3); +ADDER_CTRL_DECL(Adder5, 0x4); + +/*T234 specific Controls */ +MUX_ENUM_CTRL_DECL_186(t234_afc1_tx, 0x34); +MUX_ENUM_CTRL_DECL_186(t234_afc2_tx, 0x35); +MUX_ENUM_CTRL_DECL_186(t234_afc3_tx, 0x36); +MUX_ENUM_CTRL_DECL_186(t234_afc4_tx, 0x37); +MUX_ENUM_CTRL_DECL_186(t234_afc5_tx, 0x38); +MUX_ENUM_CTRL_DECL_186(t234_afc6_tx, 0x39); +MUX_ENUM_CTRL_DECL_186(t234_spkprot_tx, 0x41); +MUX_ENUM_CTRL_DECL_186(t234_mvc1_tx, 0x44); +MUX_ENUM_CTRL_DECL_186(t234_mvc2_tx, 0x45); +MUX_ENUM_CTRL_DECL_186(t234_amx11_tx, 0x48); +MUX_ENUM_CTRL_DECL_186(t234_amx12_tx, 0x49); +MUX_ENUM_CTRL_DECL_186(t234_amx13_tx, 0x4a); +MUX_ENUM_CTRL_DECL_186(t234_amx14_tx, 0x4b); +MUX_ENUM_CTRL_DECL_186(t234_amx21_tx, 0x4c); +MUX_ENUM_CTRL_DECL_186(t234_amx22_tx, 0x4d); +MUX_ENUM_CTRL_DECL_186(t234_amx23_tx, 0x4e); +MUX_ENUM_CTRL_DECL_186(t234_amx24_tx, 0x4f); +MUX_ENUM_CTRL_DECL_186(t234_amx31_tx, 0x50); +MUX_ENUM_CTRL_DECL_186(t234_amx32_tx, 0x51); +MUX_ENUM_CTRL_DECL_186(t234_amx33_tx, 0x52); +MUX_ENUM_CTRL_DECL_186(t234_amx34_tx, 0x53); +MUX_ENUM_CTRL_DECL_186(t234_adx1_tx, 0x58); +MUX_ENUM_CTRL_DECL_186(t234_adx2_tx, 0x59); +MUX_ENUM_CTRL_DECL_186(t234_adx3_tx, 0x5a); +MUX_ENUM_CTRL_DECL_186(t234_adx4_tx, 0x5b); +MUX_ENUM_CTRL_DECL_186(t234_amx41_tx, 0x5c); +MUX_ENUM_CTRL_DECL_186(t234_amx42_tx, 0x5d); +MUX_ENUM_CTRL_DECL_186(t234_amx43_tx, 0x5e); +MUX_ENUM_CTRL_DECL_186(t234_amx44_tx, 0x5f); +MUX_ENUM_CTRL_DECL_186(t234_admaif17_tx, 0x60); +MUX_ENUM_CTRL_DECL_186(t234_admaif18_tx, 0x61); +MUX_ENUM_CTRL_DECL_186(t234_admaif19_tx, 0x62); +MUX_ENUM_CTRL_DECL_186(t234_admaif20_tx, 0x63); +MUX_ENUM_CTRL_DECL_186(t234_asrc11_tx, 0x64); +MUX_ENUM_CTRL_DECL_186(t234_asrc12_tx, 0x65); +MUX_ENUM_CTRL_DECL_186(t234_asrc13_tx, 0x66); +MUX_ENUM_CTRL_DECL_186(t234_asrc14_tx, 0x67); +MUX_ENUM_CTRL_DECL_186(t234_asrc15_tx, 0x68); +MUX_ENUM_CTRL_DECL_186(t234_asrc16_tx, 0x69); +MUX_ENUM_CTRL_DECL_186(t234_asrc17_tx, 0x6a); +MUX_ENUM_CTRL_DECL_186(t234_spdif11_tx, 0x71); +MUX_ENUM_CTRL_DECL_186(t234_spdif12_tx, 0x72); + +static struct snd_soc_dapm_widget tegra234_virt_xbar_widgets[] = { + WIDGETS("ADMAIF1", admaif1_tx), + WIDGETS("ADMAIF2", admaif2_tx), + WIDGETS("ADMAIF3", admaif3_tx), + WIDGETS("ADMAIF4", admaif4_tx), + WIDGETS("ADMAIF5", admaif5_tx), + WIDGETS("ADMAIF6", admaif6_tx), + WIDGETS("ADMAIF7", admaif7_tx), + WIDGETS("ADMAIF8", admaif8_tx), + WIDGETS("ADMAIF9", admaif9_tx), + WIDGETS("ADMAIF10", admaif10_tx), + WIDGETS("I2S1", i2s1_tx), + WIDGETS("I2S2", i2s2_tx), + WIDGETS("I2S3", i2s3_tx), + WIDGETS("I2S4", i2s4_tx), + WIDGETS("I2S5", i2s5_tx), + WIDGETS("SFC1", sfc1_tx), + WIDGETS("SFC2", sfc2_tx), + WIDGETS("SFC3", sfc3_tx), + WIDGETS("SFC4", sfc4_tx), + MIXER_IN_WIDGETS("MIXER1-1", mixer11_tx), + MIXER_IN_WIDGETS("MIXER1-2", mixer12_tx), + MIXER_IN_WIDGETS("MIXER1-3", mixer13_tx), + MIXER_IN_WIDGETS("MIXER1-4", mixer14_tx), + MIXER_IN_WIDGETS("MIXER1-5", mixer15_tx), + MIXER_IN_WIDGETS("MIXER1-6", mixer16_tx), + MIXER_IN_WIDGETS("MIXER1-7", mixer17_tx), + MIXER_IN_WIDGETS("MIXER1-8", mixer18_tx), + MIXER_IN_WIDGETS("MIXER1-9", mixer19_tx), + MIXER_IN_WIDGETS("MIXER1-10", mixer110_tx), + + MIXER_OUT_WIDGETS("MIXER1-1"), + MIXER_OUT_WIDGETS("MIXER1-2"), + MIXER_OUT_WIDGETS("MIXER1-3"), + MIXER_OUT_WIDGETS("MIXER1-4"), + MIXER_OUT_WIDGETS("MIXER1-5"), + SND_SOC_DAPM_MIXER("Adder1", SND_SOC_NOPM, 1, 0, + Adder1, ARRAY_SIZE(Adder1)), + SND_SOC_DAPM_MIXER("Adder2", SND_SOC_NOPM, 1, 0, + Adder2, ARRAY_SIZE(Adder2)), + SND_SOC_DAPM_MIXER("Adder3", SND_SOC_NOPM, 1, 0, + Adder3, ARRAY_SIZE(Adder3)), + SND_SOC_DAPM_MIXER("Adder4", SND_SOC_NOPM, 1, 0, + Adder4, ARRAY_SIZE(Adder4)), + SND_SOC_DAPM_MIXER("Adder5", SND_SOC_NOPM, 1, 0, + Adder5, ARRAY_SIZE(Adder5)), + WIDGETS("SPDIF1-1", t234_spdif11_tx), + WIDGETS("SPDIF1-2", t234_spdif12_tx), + WIDGETS("AFC1", t234_afc1_tx), + WIDGETS("AFC2", t234_afc2_tx), + WIDGETS("AFC3", t234_afc3_tx), + WIDGETS("AFC4", t234_afc4_tx), + WIDGETS("AFC5", t234_afc5_tx), + WIDGETS("AFC6", t234_afc6_tx), + WIDGETS("OPE1", ope1_tx), + WIDGETS("SPKPROT1", t234_spkprot_tx), + WIDGETS("MVC1", t234_mvc1_tx), + WIDGETS("MVC2", t234_mvc2_tx), + WIDGETS("AMX1-1", t234_amx11_tx), + WIDGETS("AMX1-2", t234_amx12_tx), + WIDGETS("AMX1-3", t234_amx13_tx), + WIDGETS("AMX1-4", t234_amx14_tx), + WIDGETS("AMX2-1", t234_amx21_tx), + WIDGETS("AMX2-2", t234_amx22_tx), + WIDGETS("AMX2-3", t234_amx23_tx), + WIDGETS("AMX2-4", t234_amx24_tx), + WIDGETS("ADX1", t234_adx1_tx), + WIDGETS("ADX2", t234_adx2_tx), + TX_WIDGETS("IQC1-1"), + TX_WIDGETS("IQC1-2"), + TX_WIDGETS("IQC2-1"), + TX_WIDGETS("IQC2-2"), + TX_WIDGETS("DMIC1"), + TX_WIDGETS("DMIC2"), + TX_WIDGETS("DMIC3"), + TX_WIDGETS("AMX1"), + TX_WIDGETS("ADX1-1"), + TX_WIDGETS("ADX1-2"), + TX_WIDGETS("ADX1-3"), + TX_WIDGETS("ADX1-4"), + TX_WIDGETS("AMX2"), + TX_WIDGETS("ADX2-1"), + TX_WIDGETS("ADX2-2"), + TX_WIDGETS("ADX2-3"), + TX_WIDGETS("ADX2-4"), + WIDGETS("ADMAIF11", admaif11_tx), + WIDGETS("ADMAIF12", admaif12_tx), + WIDGETS("ADMAIF13", admaif13_tx), + WIDGETS("ADMAIF14", admaif14_tx), + WIDGETS("ADMAIF15", admaif15_tx), + WIDGETS("ADMAIF16", admaif16_tx), + WIDGETS("ADMAIF17", t234_admaif17_tx), + WIDGETS("ADMAIF18", t234_admaif18_tx), + WIDGETS("ADMAIF19", t234_admaif19_tx), + WIDGETS("ADMAIF20", t234_admaif20_tx), + WIDGETS("I2S6", i2s6_tx), + WIDGETS("AMX3-1", t234_amx31_tx), + WIDGETS("AMX3-2", t234_amx32_tx), + WIDGETS("AMX3-3", t234_amx33_tx), + WIDGETS("AMX3-4", t234_amx34_tx), + WIDGETS("AMX4-1", t234_amx41_tx), + WIDGETS("AMX4-2", t234_amx42_tx), + WIDGETS("AMX4-3", t234_amx43_tx), + WIDGETS("AMX4-4", t234_amx44_tx), + WIDGETS("ADX3", t234_adx3_tx), + WIDGETS("ADX4", t234_adx4_tx), + WIDGETS("ASRC1-1", t234_asrc11_tx), + WIDGETS("ASRC1-2", t234_asrc12_tx), + WIDGETS("ASRC1-3", t234_asrc13_tx), + WIDGETS("ASRC1-4", t234_asrc14_tx), + WIDGETS("ASRC1-5", t234_asrc15_tx), + WIDGETS("ASRC1-6", t234_asrc16_tx), + WIDGETS("ASRC1-7", t234_asrc17_tx), + TX_WIDGETS("AMX3"), + TX_WIDGETS("ADX3-1"), + TX_WIDGETS("ADX3-2"), + TX_WIDGETS("ADX3-3"), + TX_WIDGETS("ADX3-4"), + TX_WIDGETS("AMX4"), + TX_WIDGETS("ADX4-1"), + TX_WIDGETS("ADX4-2"), + TX_WIDGETS("ADX4-3"), + TX_WIDGETS("ADX4-4"), + TX_WIDGETS("DMIC4"), + TX_WIDGETS("ARAD1"), + CODEC_WIDGET("I2S1"), + CODEC_WIDGET("I2S2"), + CODEC_WIDGET("I2S3"), + CODEC_WIDGET("I2S4"), + CODEC_WIDGET("I2S5"), + CODEC_WIDGET("I2S6"), +}; + +static struct snd_soc_dapm_widget tegra186_virt_xbar_widgets[] = { + WIDGETS("ADMAIF1", admaif1_tx), + WIDGETS("ADMAIF2", admaif2_tx), + WIDGETS("ADMAIF3", admaif3_tx), + WIDGETS("ADMAIF4", admaif4_tx), + WIDGETS("ADMAIF5", admaif5_tx), + WIDGETS("ADMAIF6", admaif6_tx), + WIDGETS("ADMAIF7", admaif7_tx), + WIDGETS("ADMAIF8", admaif8_tx), + WIDGETS("ADMAIF9", admaif9_tx), + WIDGETS("ADMAIF10", admaif10_tx), + WIDGETS("I2S1", i2s1_tx), + WIDGETS("I2S2", i2s2_tx), + WIDGETS("I2S3", i2s3_tx), + WIDGETS("I2S4", i2s4_tx), + WIDGETS("I2S5", i2s5_tx), + WIDGETS("SFC1", sfc1_tx), + WIDGETS("SFC2", sfc2_tx), + WIDGETS("SFC3", sfc3_tx), + WIDGETS("SFC4", sfc4_tx), + MIXER_IN_WIDGETS("MIXER1-1", mixer11_tx), + MIXER_IN_WIDGETS("MIXER1-2", mixer12_tx), + MIXER_IN_WIDGETS("MIXER1-3", mixer13_tx), + MIXER_IN_WIDGETS("MIXER1-4", mixer14_tx), + MIXER_IN_WIDGETS("MIXER1-5", mixer15_tx), + MIXER_IN_WIDGETS("MIXER1-6", mixer16_tx), + MIXER_IN_WIDGETS("MIXER1-7", mixer17_tx), + MIXER_IN_WIDGETS("MIXER1-8", mixer18_tx), + MIXER_IN_WIDGETS("MIXER1-9", mixer19_tx), + MIXER_IN_WIDGETS("MIXER1-10", mixer110_tx), + + MIXER_OUT_WIDGETS("MIXER1-1"), + MIXER_OUT_WIDGETS("MIXER1-2"), + MIXER_OUT_WIDGETS("MIXER1-3"), + MIXER_OUT_WIDGETS("MIXER1-4"), + MIXER_OUT_WIDGETS("MIXER1-5"), + SND_SOC_DAPM_MIXER("Adder1", SND_SOC_NOPM, 1, 0, + Adder1, ARRAY_SIZE(Adder1)), + SND_SOC_DAPM_MIXER("Adder2", SND_SOC_NOPM, 1, 0, + Adder2, ARRAY_SIZE(Adder2)), + SND_SOC_DAPM_MIXER("Adder3", SND_SOC_NOPM, 1, 0, + Adder3, ARRAY_SIZE(Adder3)), + SND_SOC_DAPM_MIXER("Adder4", SND_SOC_NOPM, 1, 0, + Adder4, ARRAY_SIZE(Adder4)), + SND_SOC_DAPM_MIXER("Adder5", SND_SOC_NOPM, 1, 0, + Adder5, ARRAY_SIZE(Adder5)), + WIDGETS("SPDIF1-1", spdif11_tx), + WIDGETS("SPDIF1-2", spdif12_tx), + WIDGETS("AFC1", afc1_tx), + WIDGETS("AFC2", afc2_tx), + WIDGETS("AFC3", afc3_tx), + WIDGETS("AFC4", afc4_tx), + WIDGETS("AFC5", afc5_tx), + WIDGETS("AFC6", afc6_tx), + WIDGETS("OPE1", ope1_tx), + WIDGETS("SPKPROT1", spkprot_tx), + WIDGETS("MVC1", mvc1_tx), + WIDGETS("MVC2", mvc2_tx), + WIDGETS("AMX1-1", amx11_tx), + WIDGETS("AMX1-2", amx12_tx), + WIDGETS("AMX1-3", amx13_tx), + WIDGETS("AMX1-4", amx14_tx), + WIDGETS("AMX2-1", amx21_tx), + WIDGETS("AMX2-2", amx22_tx), + WIDGETS("AMX2-3", amx23_tx), + WIDGETS("AMX2-4", amx24_tx), + WIDGETS("ADX1", adx1_tx), + WIDGETS("ADX2", adx2_tx), + TX_WIDGETS("IQC1-1"), + TX_WIDGETS("IQC1-2"), + TX_WIDGETS("IQC2-1"), + TX_WIDGETS("IQC2-2"), + TX_WIDGETS("DMIC1"), + TX_WIDGETS("DMIC2"), + TX_WIDGETS("DMIC3"), + TX_WIDGETS("AMX1"), + TX_WIDGETS("ADX1-1"), + TX_WIDGETS("ADX1-2"), + TX_WIDGETS("ADX1-3"), + TX_WIDGETS("ADX1-4"), + TX_WIDGETS("AMX2"), + TX_WIDGETS("ADX2-1"), + TX_WIDGETS("ADX2-2"), + TX_WIDGETS("ADX2-3"), + TX_WIDGETS("ADX2-4"), + WIDGETS("ADMAIF11", admaif11_tx), + WIDGETS("ADMAIF12", admaif12_tx), + WIDGETS("ADMAIF13", admaif13_tx), + WIDGETS("ADMAIF14", admaif14_tx), + WIDGETS("ADMAIF15", admaif15_tx), + WIDGETS("ADMAIF16", admaif16_tx), + WIDGETS("ADMAIF17", admaif17_tx), + WIDGETS("ADMAIF18", admaif18_tx), + WIDGETS("ADMAIF19", admaif19_tx), + WIDGETS("ADMAIF20", admaif20_tx), + WIDGETS("I2S6", i2s6_tx), + WIDGETS("AMX3-1", amx31_tx), + WIDGETS("AMX3-2", amx32_tx), + WIDGETS("AMX3-3", amx33_tx), + WIDGETS("AMX3-4", amx34_tx), + WIDGETS("AMX4-1", amx41_tx), + WIDGETS("AMX4-2", amx42_tx), + WIDGETS("AMX4-3", amx43_tx), + WIDGETS("AMX4-4", amx44_tx), + WIDGETS("ADX3", adx3_tx), + WIDGETS("ADX4", adx4_tx), + WIDGETS("ASRC1-1", asrc11_tx), + WIDGETS("ASRC1-2", asrc12_tx), + WIDGETS("ASRC1-3", asrc13_tx), + WIDGETS("ASRC1-4", asrc14_tx), + WIDGETS("ASRC1-5", asrc15_tx), + WIDGETS("ASRC1-6", asrc16_tx), + WIDGETS("ASRC1-7", asrc17_tx), + TX_WIDGETS("AMX3"), + TX_WIDGETS("ADX3-1"), + TX_WIDGETS("ADX3-2"), + TX_WIDGETS("ADX3-3"), + TX_WIDGETS("ADX3-4"), + TX_WIDGETS("AMX4"), + TX_WIDGETS("ADX4-1"), + TX_WIDGETS("ADX4-2"), + TX_WIDGETS("ADX4-3"), + TX_WIDGETS("ADX4-4"), + TX_WIDGETS("DMIC4"), + TX_WIDGETS("ARAD1"), + CODEC_WIDGET("I2S1"), + CODEC_WIDGET("I2S2"), + CODEC_WIDGET("I2S3"), + CODEC_WIDGET("I2S4"), + CODEC_WIDGET("I2S5"), + CODEC_WIDGET("I2S6"), +}; + + +#define MUX_ROUTES(name) \ + { name " Mux", "ADMAIF1", "ADMAIF1 RX" }, \ + { name " Mux", "ADMAIF2", "ADMAIF2 RX" }, \ + { name " Mux", "ADMAIF3", "ADMAIF3 RX" }, \ + { name " Mux", "ADMAIF4", "ADMAIF4 RX" }, \ + { name " Mux", "ADMAIF5", "ADMAIF5 RX" }, \ + { name " Mux", "ADMAIF6", "ADMAIF6 RX" }, \ + { name " Mux", "ADMAIF7", "ADMAIF7 RX" }, \ + { name " Mux", "ADMAIF8", "ADMAIF8 RX" }, \ + { name " Mux", "ADMAIF9", "ADMAIF9 RX" }, \ + { name " Mux", "ADMAIF10", "ADMAIF10 RX" }, \ + { name " Mux", "I2S1", "I2S1 RX" }, \ + { name " Mux", "I2S2", "I2S2 RX" }, \ + { name " Mux", "I2S3", "I2S3 RX" }, \ + { name " Mux", "I2S4", "I2S4 RX" }, \ + { name " Mux", "I2S5", "I2S5 RX" }, \ + { name " Mux", "SFC1", "SFC1 RX" }, \ + { name " Mux", "SFC2", "SFC2 RX" }, \ + { name " Mux", "SFC3", "SFC3 RX" }, \ + { name " Mux", "SFC4", "SFC4 RX" }, \ + { name " Mux", "MIXER1-1", "MIXER1-1 RX" }, \ + { name " Mux", "MIXER1-2", "MIXER1-2 RX" }, \ + { name " Mux", "MIXER1-3", "MIXER1-3 RX" }, \ + { name " Mux", "MIXER1-4", "MIXER1-4 RX" }, \ + { name " Mux", "MIXER1-5", "MIXER1-5 RX" }, \ + { name " Mux", "SPDIF1-1", "SPDIF1-1 RX" }, \ + { name " Mux", "SPDIF1-2", "SPDIF1-2 RX" }, \ + { name " Mux", "AFC1", "AFC1 RX" }, \ + { name " Mux", "AFC2", "AFC2 RX" }, \ + { name " Mux", "AFC3", "AFC3 RX" }, \ + { name " Mux", "AFC4", "AFC4 RX" }, \ + { name " Mux", "AFC5", "AFC5 RX" }, \ + { name " Mux", "AFC6", "AFC6 RX" }, \ + { name " Mux", "OPE1", "OPE1 RX" }, \ + { name " Mux", "MVC1", "MVC1 RX" }, \ + { name " Mux", "MVC2", "MVC2 RX" }, \ + { name " Mux", "IQC1-1", "IQC1-1 RX" }, \ + { name " Mux", "IQC1-2", "IQC1-2 RX" }, \ + { name " Mux", "IQC2-1", "IQC2-1 RX" }, \ + { name " Mux", "IQC2-2", "IQC2-2 RX" }, \ + { name " Mux", "DMIC1", "DMIC1 RX" }, \ + { name " Mux", "DMIC2", "DMIC2 RX" }, \ + { name " Mux", "DMIC3", "DMIC3 RX" }, \ + { name " Mux", "AMX1", "AMX1 RX" }, \ + { name " Mux", "ADX1-1", "ADX1-1 RX" }, \ + { name " Mux", "ADX1-2", "ADX1-2 RX" }, \ + { name " Mux", "ADX1-3", "ADX1-3 RX" }, \ + { name " Mux", "ADX1-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" }, \ + { name " Mux", "ADMAIF11", "ADMAIF11 RX" }, \ + { name " Mux", "ADMAIF12", "ADMAIF12 RX" }, \ + { name " Mux", "ADMAIF13", "ADMAIF13 RX" }, \ + { name " Mux", "ADMAIF14", "ADMAIF14 RX" }, \ + { name " Mux", "ADMAIF15", "ADMAIF15 RX" }, \ + { name " Mux", "ADMAIF16", "ADMAIF16 RX" }, \ + { name " Mux", "ADMAIF17", "ADMAIF17 RX" }, \ + { name " Mux", "ADMAIF18", "ADMAIF18 RX" }, \ + { name " Mux", "ADMAIF19", "ADMAIF19 RX" }, \ + { name " Mux", "ADMAIF20", "ADMAIF20 RX" }, \ + { name " Mux", "DMIC4", "DMIC4 RX" }, \ + { name " Mux", "I2S6", "I2S6 RX" }, \ + { name " Mux", "ASRC1-1", "ASRC1-1 RX" }, \ + { name " Mux", "ASRC1-2", "ASRC1-2 RX" }, \ + { name " Mux", "ASRC1-3", "ASRC1-3 RX" }, \ + { name " Mux", "ASRC1-4", "ASRC1-4 RX" }, \ + { name " Mux", "ASRC1-5", "ASRC1-5 RX" }, \ + { name " Mux", "ASRC1-6", "ASRC1-6 RX" }, \ + { name " Mux", "AMX3", "AMX3 RX" }, \ + { name " Mux", "ADX3-1", "ADX3-1 RX" }, \ + { name " Mux", "ADX3-2", "ADX3-2 RX" }, \ + { name " Mux", "ADX3-3", "ADX3-3 RX" }, \ + { name " Mux", "ADX3-4", "ADX3-4 RX" }, \ + { name " Mux", "AMX4", "AMX4 RX" }, \ + { name " Mux", "ADX4-1", "ADX4-1 RX" }, \ + { name " Mux", "ADX4-2", "ADX4-2 RX" }, \ + { name " Mux", "ADX4-3", "ADX4-3 RX" }, \ + { name " Mux", "ADX4-4", "ADX4-4 RX" }, \ + { name " Mux", "ARAD1", "ARAD1 RX" }, + +#define AMX_OUT_ROUTES(name) \ + { name " RX", NULL, name "-1 Mux" }, \ + { name " RX", NULL, name "-2 Mux" }, \ + { name " RX", NULL, name "-3 Mux" }, \ + { name " RX", NULL, name "-4 Mux" }, + +#define ADX_IN_ROUTES(name) \ + { name "-1 RX", NULL, name " Mux" }, \ + { name "-2 RX", NULL, name " Mux" }, \ + { name "-3 RX", NULL, name " Mux" }, \ + { name "-4 RX", NULL, name " Mux" }, \ + TEGRA210_ROUTES(name) + +#define IN_OUT_ROUTES(name) \ + { name " RX", NULL, name " CIF Receive"}, \ + { name " CIF Transmit", NULL, name " Mux"}, \ + MUX_ROUTES(name) + +#define TEGRA210_ROUTES(name) \ + { name " RX", NULL, name " Mux"}, \ + MUX_ROUTES(name) + +#define MIXER_IN_ROUTES(name) \ + MUX_ROUTES(name) + +#define MIC_SPK_ROUTES(name) \ + { name " RX", NULL, name " MIC"}, \ + { name " HEADPHONE", NULL, name " Mux"}, \ + MUX_ROUTES(name) + +#define MIXER_ROUTES(name, id) \ + {name, "RX1", "MIXER1-1 Mux",}, \ + {name, "RX2", "MIXER1-2 Mux",}, \ + {name, "RX3", "MIXER1-3 Mux",}, \ + {name, "RX4", "MIXER1-4 Mux",}, \ + {name, "RX5", "MIXER1-5 Mux",}, \ + {name, "RX6", "MIXER1-6 Mux",}, \ + {name, "RX7", "MIXER1-7 Mux",}, \ + {name, "RX8", "MIXER1-8 Mux",}, \ + {name, "RX9", "MIXER1-9 Mux",}, \ + {name, "RX10", "MIXER1-10 Mux"}, \ + {"MIXER1-"#id " RX", NULL, name} + + + +static struct snd_soc_dapm_route tegra186_virt_xbar_routes[] = { + IN_OUT_ROUTES("ADMAIF1") + IN_OUT_ROUTES("ADMAIF2") + IN_OUT_ROUTES("ADMAIF3") + IN_OUT_ROUTES("ADMAIF4") + IN_OUT_ROUTES("ADMAIF5") + IN_OUT_ROUTES("ADMAIF6") + IN_OUT_ROUTES("ADMAIF7") + IN_OUT_ROUTES("ADMAIF8") + IN_OUT_ROUTES("ADMAIF9") + IN_OUT_ROUTES("ADMAIF10") + MIC_SPK_ROUTES("I2S1") + MIC_SPK_ROUTES("I2S2") + MIC_SPK_ROUTES("I2S3") + MIC_SPK_ROUTES("I2S4") + MIC_SPK_ROUTES("I2S5") + TEGRA210_ROUTES("SFC1") + TEGRA210_ROUTES("SFC2") + TEGRA210_ROUTES("SFC3") + TEGRA210_ROUTES("SFC4") + MIXER_IN_ROUTES("MIXER1-1") + MIXER_IN_ROUTES("MIXER1-2") + MIXER_IN_ROUTES("MIXER1-3") + MIXER_IN_ROUTES("MIXER1-4") + MIXER_IN_ROUTES("MIXER1-5") + MIXER_IN_ROUTES("MIXER1-6") + MIXER_IN_ROUTES("MIXER1-7") + MIXER_IN_ROUTES("MIXER1-8") + MIXER_IN_ROUTES("MIXER1-9") + MIXER_IN_ROUTES("MIXER1-10") + + MIXER_ROUTES("Adder1", 1), + MIXER_ROUTES("Adder2", 2), + MIXER_ROUTES("Adder3", 3), + MIXER_ROUTES("Adder4", 4), + MIXER_ROUTES("Adder5", 5), + + TEGRA210_ROUTES("SPDIF1-1") + TEGRA210_ROUTES("SPDIF1-2") + TEGRA210_ROUTES("AFC1") + TEGRA210_ROUTES("AFC2") + TEGRA210_ROUTES("AFC3") + TEGRA210_ROUTES("AFC4") + TEGRA210_ROUTES("AFC5") + TEGRA210_ROUTES("AFC6") + TEGRA210_ROUTES("OPE1") + TEGRA210_ROUTES("SPKPROT1") + TEGRA210_ROUTES("MVC1") + TEGRA210_ROUTES("MVC2") + TEGRA210_ROUTES("AMX1-1") + TEGRA210_ROUTES("AMX1-2") + TEGRA210_ROUTES("AMX1-3") + TEGRA210_ROUTES("AMX1-4") + TEGRA210_ROUTES("AMX2-1") + TEGRA210_ROUTES("AMX2-2") + TEGRA210_ROUTES("AMX2-3") + TEGRA210_ROUTES("AMX2-4") + ADX_IN_ROUTES("ADX1") + ADX_IN_ROUTES("ADX2") + AMX_OUT_ROUTES("AMX1") + AMX_OUT_ROUTES("AMX2") + IN_OUT_ROUTES("ADMAIF11") + IN_OUT_ROUTES("ADMAIF12") + IN_OUT_ROUTES("ADMAIF13") + IN_OUT_ROUTES("ADMAIF14") + IN_OUT_ROUTES("ADMAIF15") + IN_OUT_ROUTES("ADMAIF16") + IN_OUT_ROUTES("ADMAIF17") + IN_OUT_ROUTES("ADMAIF18") + IN_OUT_ROUTES("ADMAIF19") + IN_OUT_ROUTES("ADMAIF20") + TEGRA210_ROUTES("AMX3-1") + TEGRA210_ROUTES("AMX3-2") + TEGRA210_ROUTES("AMX3-3") + TEGRA210_ROUTES("AMX3-4") + TEGRA210_ROUTES("AMX4-1") + TEGRA210_ROUTES("AMX4-2") + TEGRA210_ROUTES("AMX4-3") + TEGRA210_ROUTES("AMX4-4") + ADX_IN_ROUTES("ADX3") + ADX_IN_ROUTES("ADX4") + MIC_SPK_ROUTES("I2S6") + TEGRA210_ROUTES("ASRC1-1") + TEGRA210_ROUTES("ASRC1-2") + TEGRA210_ROUTES("ASRC1-3") + TEGRA210_ROUTES("ASRC1-4") + TEGRA210_ROUTES("ASRC1-5") + TEGRA210_ROUTES("ASRC1-6") + TEGRA210_ROUTES("ASRC1-7") + AMX_OUT_ROUTES("AMX3") + AMX_OUT_ROUTES("AMX4") +}; + +static unsigned int tegra_virt_xbar_read(struct snd_soc_component *component, + unsigned int reg) +{ + return 0; +} + +static int tegra_virt_xbar_write(struct snd_soc_component *component, + unsigned int reg, unsigned int val) +{ + return 0; +} + +static int tegra_virt_xbar_component_probe(struct snd_soc_component *component) +{ + return 0; +} + +static struct snd_soc_component_driver tegra186_virt_xbar_codec = { + .probe = tegra_virt_xbar_component_probe, + .read = tegra_virt_xbar_read, + .write = tegra_virt_xbar_write, + .dapm_widgets = tegra186_virt_xbar_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra186_virt_xbar_widgets), + .dapm_routes = tegra186_virt_xbar_routes, + .num_dapm_routes = ARRAY_SIZE(tegra186_virt_xbar_routes), +}; + +static const struct snd_soc_component_driver tegra234_virt_xbar_codec = { + .probe = tegra_virt_xbar_component_probe, + .read = tegra_virt_xbar_read, + .write = tegra_virt_xbar_write, + .dapm_widgets = tegra234_virt_xbar_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra234_virt_xbar_widgets), + .dapm_routes = tegra186_virt_xbar_routes, + .num_dapm_routes = ARRAY_SIZE(tegra186_virt_xbar_routes), +}; + +int tegra_virt_get_route(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int32_t reg = e->reg; + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err, i = 0; + struct nvaudio_ivc_msg msg; + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_XBAR_GET_ROUTE; + msg.params.xbar_info.rx_reg = reg; + + err = nvaudio_ivc_send_receive(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) + pr_err("%s: error on ivc_send_receive\n", __func__); + + for (i = 0; i < e->items; i++) { + if (msg.params.xbar_info.bit_pos == + e->values[i]) + break; + } + + if (i == e->items) + ucontrol->value.integer.value[0] = 0; + + ucontrol->value.integer.value[0] = i; + + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(tegra_virt_get_route); + + +int tegra_virt_put_route(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int32_t reg = e->reg; + struct nvaudio_ivc_ctxt *hivc_client = + nvaudio_ivc_alloc_ctxt(card->dev); + int err; + struct nvaudio_ivc_msg msg; + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + + memset(&msg, 0, sizeof(struct nvaudio_ivc_msg)); + msg.cmd = NVAUDIO_XBAR_SET_ROUTE; + msg.params.xbar_info.rx_reg = reg; + msg.params.xbar_info.tx_value = + e->values[ucontrol->value.integer.value[0]]; + + msg.params.xbar_info.tx_idx = + ucontrol->value.integer.value[0] - 1; + + err = nvaudio_ivc_send_retry(hivc_client, + &msg, + sizeof(struct nvaudio_ivc_msg)); + if (err < 0) { + pr_err("%s: Timedout on ivc_send_retry\n", __func__); + return err; + } + + snd_soc_dapm_mux_update_power(dapm, kcontrol, + ucontrol->value.integer.value[0], e, NULL); + + return 0; +} +EXPORT_SYMBOL(tegra_virt_put_route); + +void tegra_virt_set_enum_source(const struct soc_enum *enum_virt) +{ + tegra_virt_enum_source = enum_virt; +} +EXPORT_SYMBOL(tegra_virt_set_enum_source); + +static inline const struct soc_enum *tegra_virt_get_enum_source(void) +{ + return tegra_virt_enum_source; +} + +int tegra_virt_xbar_register_codec(struct platform_device *pdev) +{ + + int ret; + + if (of_device_is_compatible(pdev->dev.of_node, + "nvidia,tegra234-virt-pcm-oot")) { + ret = tegra_register_component(&pdev->dev, + &tegra234_virt_xbar_codec, + tegra186_virt_xbar_dais, + ARRAY_SIZE(tegra186_virt_xbar_dais), "xbar"); + } else { + ret = tegra_register_component(&pdev->dev, + &tegra186_virt_xbar_codec, + tegra186_virt_xbar_dais, + ARRAY_SIZE(tegra186_virt_xbar_dais), "xbar"); + } + + if (ret != 0) { + dev_err(&pdev->dev, "Could not register CODEC: %d\n", ret); + return -EBUSY; + } + + return 0; +} +EXPORT_SYMBOL(tegra_virt_xbar_register_codec); +MODULE_AUTHOR("Dipesh Gandhi "); +MODULE_DESCRIPTION("Tegra Virt ASoC XBAR code"); +MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/sound/soc/tegra-virt-alt/tegra_asoc_xbar_virt_alt.h b/sound/soc/tegra-virt-alt/tegra_asoc_xbar_virt_alt.h new file mode 100644 index 00000000..568e0597 --- /dev/null +++ b/sound/soc/tegra-virt-alt/tegra_asoc_xbar_virt_alt.h @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + */ + +#ifndef __TEGRA_VIRT_ALT_XBAR_H__ +#define __TEGRA_VIRT_ALT_XBAR_H__ + +#include + +#define TEGRA_XBAR_RX_STRIDE 0x4 +#define TEGRA_T186_SRC_NUM_MUX 83 +#define TEGRA_T210_SRC_NUM_MUX 55 + +#define MUX_REG(id) (TEGRA_XBAR_RX_STRIDE * (id)) +#define SOC_ENUM_EXT_REG(xname, xcount, xenum, xhandler_get, xhandler_put) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_info_enum_double, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = (unsigned long)xenum, \ + .tlv.p = (unsigned int *) xcount, \ +} + +#define SOC_VALUE_ENUM_WIDE(xreg, shift, xmax, xtexts, xvalues) \ +{ .reg = xreg, .shift_l = shift, .shift_r = shift, \ + .items = xmax, .texts = xtexts, .values = xvalues, \ + .mask = xmax ? roundup_pow_of_two(xmax) - 1 : 0} + +#define SOC_VALUE_ENUM_WIDE_DECL(name, xreg, shift, \ + xtexts, xvalues) \ + static struct soc_enum name = SOC_VALUE_ENUM_WIDE(xreg, shift, \ + ARRAY_SIZE(xtexts), xtexts, xvalues) + +#define MUX_ENUM_CTRL_DECL_186(ename, id) \ + SOC_VALUE_ENUM_WIDE_DECL(ename##_enum, MUX_REG(id), 0, \ + tegra_virt_t186ref_source_text, \ + tegra_virt_t186ref_source_value); \ + static const struct snd_kcontrol_new ename##_control = \ + SOC_DAPM_ENUM_EXT("Route", ename##_enum,\ + tegra_virt_get_route,\ + tegra_virt_put_route) + +#define MUX_VALUE(npart, nbit) (1 + nbit + npart * 32) + +#define WIDGETS(sname, ename) \ + SND_SOC_DAPM_AIF_IN(sname " RX", NULL, 0, SND_SOC_NOPM, 0, 0), \ + SND_SOC_DAPM_MUX(sname " Mux", SND_SOC_NOPM, 0, 0, &ename##_control) + +#define TX_WIDGETS(sname) \ + SND_SOC_DAPM_AIF_IN(sname " RX", NULL, 0, SND_SOC_NOPM, 0, 0) + +#define MIXER_IN_WIDGETS(sname, ename) \ + SND_SOC_DAPM_MUX(sname " Mux", SND_SOC_NOPM, 0, 0, &ename##_control) + +#define MIXER_OUT_WIDGETS(sname) \ + SND_SOC_DAPM_AIF_IN(sname " RX", NULL, 0, SND_SOC_NOPM, 0, 0) + +#define SND_SOC_DAPM_OUT(wname) \ + {.id = snd_soc_dapm_spk, .name = wname, .kcontrol_news = NULL, \ + .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = NULL,} + +#define SND_SOC_DAPM_IN(wname) \ + {.id = snd_soc_dapm_mic, .name = wname, .kcontrol_news = NULL, \ + .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = NULL,} + +#define CODEC_WIDGET(sname) \ + SND_SOC_DAPM_IN(sname " MIC"), \ + SND_SOC_DAPM_OUT(sname " HEADPHONE") + + +extern const int tegra_virt_t210ref_source_value[]; +extern const char * const tegra_virt_t210ref_source_text[]; +extern const int tegra_virt_t186ref_source_value[]; +extern const char * const tegra_virt_t186ref_source_text[]; + +int tegra_virt_get_route(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int tegra_virt_put_route(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +void tegra_virt_set_enum_source(const struct soc_enum *enum_virt); +int tegra_virt_xbar_register_codec(struct platform_device *pdev); +#endif \ No newline at end of file diff --git a/sound/soc/tegra-virt-alt/tegra_pcm_virt_alt.c b/sound/soc/tegra-virt-alt/tegra_pcm_virt_alt.c new file mode 100644 index 00000000..ac63701e --- /dev/null +++ b/sound/soc/tegra-virt-alt/tegra_pcm_virt_alt.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "tegra_pcm_alt.h" +#include "tegra_asoc_util_virt_alt.h" + +static const struct snd_pcm_hardware tegra_alt_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_INTERLEAVED, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + .period_bytes_min = 128, + .period_bytes_max = PAGE_SIZE * 4, + .periods_min = 1, + .periods_max = 8, + .buffer_bytes_max = PAGE_SIZE * 8, + .fifo_size = 4, +}; + +static int tegra_alt_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct tegra_alt_pcm_dma_params *dmap; + struct dma_chan *chan; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + int ret; + + if (rtd->dai_link->no_pcm) + return 0; + + dmap = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream); + + /* Set HW params now that initialization is complete */ + snd_soc_set_runtime_hwparams(substream, &tegra_alt_pcm_hardware); + + /* Update buffer size from device tree */ + if (dmap->buffer_size > substream->runtime->hw.buffer_bytes_max) { + substream->runtime->hw.buffer_bytes_max = dmap->buffer_size; + substream->runtime->hw.period_bytes_max = dmap->buffer_size / 2; + } + + /* Ensure period size is multiple of 8 */ + ret = snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 0x8); + if (ret) { + dev_err(cpu_dai->dev, "failed to set constraint %d\n", ret); + return ret; + } + + chan = dma_request_slave_channel(cpu_dai->dev, dmap->chan_name); + if (!chan) { + dev_err(cpu_dai->dev, + "dmaengine request slave channel failed! (%s)\n", + dmap->chan_name); + return -ENODEV; + } + ret = snd_dmaengine_pcm_open(substream, chan); + + if (ret) { + dev_err(cpu_dai->dev, "dmaengine pcm open failed with err %d\n", ret); + return ret; + } + + return 0; +} + +static int tegra_alt_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + + if (rtd->dai_link->no_pcm) + return 0; + + snd_dmaengine_pcm_close_release_chan(substream); + + return 0; +} + +static int tegra_alt_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct device *dev = rtd->dev; + struct dma_chan *chan; + struct tegra_alt_pcm_dma_params *dmap; + struct dma_slave_config slave_config; + int ret; + + if (rtd->dai_link->no_pcm) + return 0; + + dmap = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream); + if (!dmap) + return 0; + + chan = snd_dmaengine_pcm_get_chan(substream); + + ret = snd_hwparams_to_dma_slave_config(substream, params, + &slave_config); + if (ret) { + dev_err(dev, "hw params config failed with err %d\n", ret); + return ret; + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + slave_config.dst_addr = dmap->addr; + slave_config.dst_maxburst = 8; + } else { + slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + slave_config.src_addr = dmap->addr; + slave_config.src_maxburst = 8; + } + + ret = dmaengine_slave_config(chan, &slave_config); + if (ret < 0) { + dev_err(dev, "dma slave config failed with err %d\n", ret); + return ret; + } + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + return 0; +} + +static int tegra_alt_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + + if (rtd->dai_link->no_pcm) + return 0; + + snd_pcm_set_runtime_buffer(substream, NULL); + return 0; +} + +static int tegra_alt_pcm_mmap(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + + if (rtd->dai_link->no_pcm) + return 0; + + return dma_mmap_wc(substream->pcm->card->dev, vma, + runtime->dma_area, + runtime->dma_addr, + runtime->dma_bytes); +} + +static snd_pcm_uframes_t tegra_alt_pcm_pointer + (struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + + snd_pcm_uframes_t appl_offset, pos = 0; + struct snd_pcm_runtime *runtime = substream->runtime; + char *appl_ptr; + + pos = snd_dmaengine_pcm_pointer(substream); + + /* In DRAINING state pointer callback comes from dma completion, here + * we want to make sure if if dma completion callback is late we should + * not endup playing stale data. + */ + if ((runtime->status->state == SNDRV_PCM_STATE_DRAINING) && + (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)) { + appl_offset = runtime->control->appl_ptr % + runtime->buffer_size; + appl_ptr = runtime->dma_area + frames_to_bytes(runtime, + appl_offset); + if (pos < appl_offset) { + memset(appl_ptr, 0, frames_to_bytes(runtime, + runtime->buffer_size - appl_offset)); + memset(runtime->dma_area, 0, frames_to_bytes(runtime, + pos)); + } else + memset(appl_ptr, 0, frames_to_bytes(runtime, + pos - appl_offset)); + } + + return pos; +} + +static int tegra_alt_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, + unsigned int stream, size_t size) +{ + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + buf->area = dma_alloc_coherent(pcm->card->dev, size, + &buf->addr, GFP_KERNEL); + if (!buf->area) + return -ENOMEM; + buf->private_data = NULL; + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = pcm->card->dev; + buf->bytes = size; + + return 0; +} + +static void tegra_alt_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, unsigned int stream) +{ + struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + + substream = pcm->streams[stream].substream; + if (!substream) + return; + + buf = &substream->dma_buffer; + if (!buf->area) + return; + + dma_free_coherent(pcm->card->dev, buf->bytes, + buf->area, buf->addr); + buf->area = NULL; +} + +static int tegra_alt_pcm_dma_allocate(struct snd_soc_pcm_runtime *rtd, + size_t size) +{ + struct snd_card *card = rtd->card->snd_card; + struct snd_pcm *pcm = rtd->pcm; + struct tegra_alt_pcm_dma_params *dmap; + size_t buffer_size = size; + int ret; + + ret = dma_set_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + dmap = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), + pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream); + if (dmap->buffer_size > size) + buffer_size = dmap->buffer_size; + if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { + ret = tegra_alt_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_PLAYBACK, + buffer_size); + if (ret) + goto err; + } + + dmap = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), + pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); + if (dmap->buffer_size > size) + buffer_size = dmap->buffer_size; + if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { + ret = tegra_alt_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_CAPTURE, + buffer_size); + if (ret) + goto err_free_play; + } + + return 0; + +err_free_play: + tegra_alt_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK); +err: + return ret; +} + +static int tegra_alt_pcm_new(struct snd_soc_component *c, + struct snd_soc_pcm_runtime *rtd) +{ + return tegra_alt_pcm_dma_allocate(rtd, + tegra_alt_pcm_hardware.buffer_bytes_max); +} + +static void tegra_alt_pcm_free(struct snd_soc_component *c, + struct snd_pcm *pcm) +{ + tegra_alt_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE); + tegra_alt_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK); +} + +static int tegra_alt_pcm_ioctl(struct snd_soc_component *component, + struct snd_pcm_substream *substream, unsigned int cmd, void *arg) +{ + return snd_pcm_lib_ioctl(substream, cmd, arg); +} + + +static int tegra_alt_pcm_probe(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + dapm->idle_bias_off = 1; + return 0; +} + +static struct snd_soc_component_driver tegra_alt_pcm_platform = { + .open = tegra_alt_pcm_open, + .close = tegra_alt_pcm_close, + .ioctl = tegra_alt_pcm_ioctl, + .hw_params = tegra_alt_pcm_hw_params, + .hw_free = tegra_alt_pcm_hw_free, + .pointer = tegra_alt_pcm_pointer, + .mmap = tegra_alt_pcm_mmap, + .pcm_construct = tegra_alt_pcm_new, + .pcm_destruct = tegra_alt_pcm_free, + .probe = tegra_alt_pcm_probe, +}; + +int tegra_alt_pcm_platform_register(struct device *dev) +{ + return tegra_register_component(dev, &tegra_alt_pcm_platform, NULL, 0, "pcm"); +} +EXPORT_SYMBOL_GPL(tegra_alt_pcm_platform_register); + +void tegra_alt_pcm_platform_unregister(struct device *dev) +{ + snd_soc_unregister_component(dev); +} +EXPORT_SYMBOL_GPL(tegra_alt_pcm_platform_unregister); + +MODULE_AUTHOR("Stephen Warren "); +MODULE_DESCRIPTION("Tegra Alt PCM ASoC driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/tegra-virt-alt/tegra_virt_ref_alt.c b/sound/soc/tegra-virt-alt/tegra_virt_ref_alt.c new file mode 100644 index 00000000..2fcd5f69 --- /dev/null +++ b/sound/soc/tegra-virt-alt/tegra_virt_ref_alt.c @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tegra210_virt_alt_admaif.h" +#include "tegra_asoc_machine_virt_alt.h" +#include "tegra_asoc_util_virt_alt.h" +#include "tegra_asoc_xbar_virt_alt.h" +#include "tegra_virt_alt_ivc.h" + +static struct snd_soc_card tegra_virt_t210ref_card = { + .name = "t210ref-virt-card", + .owner = THIS_MODULE, + .fully_routed = true, +}; + +static struct snd_soc_card tegra_virt_t186ref_card = { + .name = "t186ref-virt-card", + .owner = THIS_MODULE, + .fully_routed = true, +}; + +static void tegra_virt_set_dai_params( + struct snd_soc_dai_link *dai_link, + struct snd_soc_pcm_stream *user_params, + unsigned int dai_id) +{ + dai_link[dai_id].params = user_params; +} + +static struct tegra_virt_admaif_soc_data soc_data_tegra186 = { + .num_ch = TEGRA186_ADMAIF_CHANNEL_COUNT, +}; + + +static const struct of_device_id tegra_virt_machine_of_match[] = { + { .compatible = "nvidia,tegra186-virt-pcm", + .data = &soc_data_tegra186}, + { .compatible = "nvidia,tegra234-virt-pcm-oot", + .data = &soc_data_tegra186}, + {}, +}; + +static int tegra_virt_machine_driver_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = NULL; + int i, ret = 0; + int admaif_ch_num = 0; + bool adsp_enabled = false; + unsigned int admaif_ch_list[MAX_ADMAIF_IDS]; + const struct of_device_id *match; + struct tegra_virt_admaif_soc_data *soc_data; + char buffer[30]; + int32_t adsp_admaif_bits, adsp_admaif_format; + int32_t adsp_admaif_channels; + struct snd_soc_pcm_stream adsp_admaif_dt_params; + struct snd_soc_pcm_runtime *rtd; + + match = tegra_virt_machine_of_match; + if (of_device_is_compatible(pdev->dev.of_node, + "nvidia,tegra210-virt-pcm")) { + card = &tegra_virt_t210ref_card; + match = of_match_device(tegra_virt_machine_of_match, + &pdev->dev); + if (!match) + return -ENODEV; + soc_data = (struct tegra_virt_admaif_soc_data *)match->data; + } else { + card = &tegra_virt_t186ref_card; + match = of_match_device(tegra_virt_machine_of_match, + &pdev->dev); + if (!match) + return -ENODEV; + soc_data = (struct tegra_virt_admaif_soc_data *)match->data; + } + + card->dev = &pdev->dev; + card->dai_link = tegra_virt_machine_get_dai_link(); + card->num_links = tegra_virt_machine_get_num_dai_links(); + adsp_enabled = of_property_read_bool(pdev->dev.of_node, + "adsp_enabled"); + + + if (adsp_enabled) { + dev_info(&pdev->dev, "virt-alt-pcm: adsp config is set\n"); + + /* Get ADSP ADMAIF default param info */ + for (i = 0; i < MAX_ADMAIF_IDS; i++) { + if ((sprintf(buffer, "adsp-admaif%d-channels", i + 1)) < 0) + return -EINVAL; + if (of_property_read_u32(pdev->dev.of_node, + buffer, &adsp_admaif_channels)) + adsp_admaif_channels = 2; + + if ((sprintf(buffer, "adsp-admaif%d-bits", i + 1) < 0)) + return -EINVAL; + if (of_property_read_u32(pdev->dev.of_node, + buffer, &adsp_admaif_bits)) + adsp_admaif_bits = 16; + + if (adsp_admaif_channels > 16 || adsp_admaif_channels < 1) { + dev_err(&pdev->dev, + "unsupported channels %d for adsp admaif %d, setting default 2 channel\n", + adsp_admaif_channels, i + 1); + adsp_admaif_channels = 2; + } + + switch (adsp_admaif_bits) { + + case 8: + adsp_admaif_format = SNDRV_PCM_FMTBIT_S8; + break; + case 16: + adsp_admaif_format = SNDRV_PCM_FMTBIT_S16_LE; + break; + case 32: + adsp_admaif_format = SNDRV_PCM_FMTBIT_S32_LE; + break; + default: + adsp_admaif_format = SNDRV_PCM_FMTBIT_S16_LE; + dev_err(&pdev->dev, + "unsupported bits %d for adsp admaif %d, setting default 16 bit\n", + adsp_admaif_bits, i + 1); + adsp_admaif_bits = 16; + break; + } + adsp_admaif_dt_params.formats = adsp_admaif_format; + adsp_admaif_dt_params.rate_min = 48000; + adsp_admaif_dt_params.rate_max = 48000; + adsp_admaif_dt_params.channels_min = adsp_admaif_channels; + adsp_admaif_dt_params.channels_max = adsp_admaif_channels; + + tegra_virt_machine_set_adsp_admaif_dai_params( + i, &adsp_admaif_dt_params); + } + } else { + dev_info(&pdev->dev, "virt-alt-pcm: adsp config is not set\n"); + card->num_links = soc_data->num_ch; + } + + if (tegra210_virt_admaif_register_component(pdev, soc_data)) { + dev_err(&pdev->dev, "Failed register admaif component\n"); + return -EINVAL; + } + + if (tegra_virt_xbar_register_codec(pdev)) { + dev_err(&pdev->dev, "Failed register xbar component\n"); + ret = -EINVAL; + goto undo_register_component; + } + + if (of_property_read_u32(pdev->dev.of_node, + "admaif_ch_num", &admaif_ch_num)) { + dev_err(&pdev->dev, "number of admaif channels is not set\n"); + ret = -EINVAL; + goto undo_register_codec; + } + + if (of_property_read_string(pdev->dev.of_node, "cardname", &card->name)) + dev_warn(&pdev->dev, "Using default card name %s\n", + card->name); + + if (admaif_ch_num > 0) { + + if (of_property_read_u32_array(pdev->dev.of_node, + "admaif_ch_list", + admaif_ch_list, + admaif_ch_num)) { + dev_err(&pdev->dev, "admaif_ch_list os not populated\n"); + ret = -EINVAL; + goto undo_register_codec; + } + for (i = 0; i < admaif_ch_num; i++) { + tegra_virt_set_dai_params( + tegra_virt_machine_get_dai_link(), + NULL, + (admaif_ch_list[i] - 1)); + } + } + + ret = snd_soc_register_card(card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); + ret = -EPROBE_DEFER; + goto undo_register_codec; + } + + list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_dai_driver *codec_drv = codec_dai->driver; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai_driver *cpu_drv = cpu_dai->driver; + + cpu_drv->playback.rates = SNDRV_PCM_RATE_KNOT; + cpu_drv->playback.rate_min = 8000; + cpu_drv->playback.rate_max = 192000; + cpu_drv->capture.rates = SNDRV_PCM_RATE_KNOT; + cpu_drv->capture.rate_min = 8000; + cpu_drv->capture.rate_max = 192000; + + codec_drv->playback.rates = SNDRV_PCM_RATE_KNOT; + codec_drv->playback.rate_min = 8000; + codec_drv->playback.rate_max = 192000; + codec_drv->capture.rates = SNDRV_PCM_RATE_KNOT; + codec_drv->capture.rate_min = 8000; + codec_drv->capture.rate_max = 192000; + } + + pm_runtime_forbid(&pdev->dev); + + return 0; + +undo_register_codec: + snd_soc_unregister_component(&pdev->dev); +undo_register_component: + tegra210_virt_admaif_unregister_component(pdev); + + nvaudio_ivc_free_ctxt(&pdev->dev); + + return ret; +} + +static int tegra_virt_machine_driver_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + + snd_soc_unregister_card(card); + + return 0; +} + +static struct platform_driver tegra_virt_machine_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + .of_match_table = + of_match_ptr(tegra_virt_machine_of_match), + }, + .probe = tegra_virt_machine_driver_probe, + .remove = tegra_virt_machine_driver_remove, +}; +module_platform_driver(tegra_virt_machine_driver); + +MODULE_AUTHOR("Paresh Anandathirtha "); +MODULE_DESCRIPTION("Tegra virt machine driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(of, tegra_virt_machine_of_match); +MODULE_ALIAS("platform:" DRV_NAME); +MODULE_SOFTDEP("pre: snd_soc_tegra210_virt_alt_adsp"); \ No newline at end of file