Files
linux-nv-oot/sound/soc/tegra-virt-alt/tegra_asoc_util_virt_alt.c
Dipesh Gandhi e7a37d936b kernel-nvidia: Read ivc response
- RD sends a response back to gos for every ivc sent to audio-server
- Changing gos side to read response for amixer commands for admaif
  set rxcif/txcif, i2s set loopback & set route.
- for asrc, arad and mixer commands
- Change API to ivc_send_receive for rest of the messages.

This commit is a cherry-pick/squash of following 3 changes -

https://git-master.nvidia.com/r/c/linux-nvidia/+/2824045
https://git-master.nvidia.com/r/c/linux-nvidia/+/2838626
https://git-master.nvidia.com/r/c/linux-nvidia/+/2849664

Bug 3663881
Bug 3930086
Bug 3917240

Signed-off-by: Niranjan Dighe <ndighe@nvidia.com>
Change-Id: If943e50eda081cd7db4022a34d104e143c9e48d2
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2869777
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-by: svcacv <svcacv@nvidia.com>
Reviewed-by: Dipesh Gandhi <dipeshg@nvidia.com>
Reviewed-by: Swati Sachdeva <ssachdeva@nvidia.com>
Reviewed-by: Uday Gupta <udayg@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
2023-03-15 01:57:24 -07:00

1649 lines
44 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#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;
msg.ack_required = true;
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;
}
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;
msg.ack_required = true;
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;
}
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;
msg.ack_required = true;
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;
}
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];
msg.ack_required = true;
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;
}
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;
msg.ack_required = true;
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];
msg.ack_required = true;
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;
}
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];
msg.ack_required = true;
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;
}
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];
msg.ack_required = true;
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;
}
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];
msg.ack_required = true;
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;
}
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];
msg.ack_required = true;
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;
}
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];
msg.ack_required = true;
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;
}
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);
msg.ack_required = true;
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;
}
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];
msg.ack_required = true;
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;
}
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];
msg.ack_required = true;
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;
}
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: error on ivc_send_receive\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];
msg.ack_required = true;
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;
}
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: error on ivc_send_receive\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];
msg.ack_required = true;
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;
}
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: error on ivc_send_receive\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];
msg.ack_required = true;
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;
}
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];
msg.ack_required = true;
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;
}
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: error on ivc_send_receive\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;
}
msg.ack_required = true;
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;
}
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: error on ivc_send_receive\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;
}
msg.ack_required = true;
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;
}
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: error on ivc_send_receive\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];
msg.ack_required = true;
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;
}
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: error on ivc_send_receive\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: error on ivc_send_receive\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];
msg.ack_required = true;
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;
}
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: error on ivc_send_receive\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];
msg.ack_required = true;
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;
}
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;
msg.ack_required = true;
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;
}
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;
msg.ack_required = true;
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;
}
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;
}
msg.ack_required = true;
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;
}
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 <dipeshg@nvidia.com>");
MODULE_DESCRIPTION("Tegra Virt ASoC utility code");
MODULE_LICENSE("GPL");