// SPDX-License-Identifier: GPL-2.0-only // // SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION. All rights reserved. #include #include #include "nvaudio_ivc/tegra_virt_alt_ivc.h" #include "tegra_asoc_util_virt_alt.h" #if TEGRA_ARAD const int tegra186_arad_mux_value[] = { -1, /* None */ 0, 1, 2, 3, 4, 5, /* I2S1~6 */ 12, 13, 14, 15, /* DMIC1~4 */ 24, 25, /* DSPK1~2 */ }; const char * const tegra186_arad_mux_text[] = { "None", "I2S1", "I2S2", "I2S3", "I2S4", "I2S5", "I2S6", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DSPK1", "DSPK2", }; #endif 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_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_ratio_param_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct soc_mreg_control *mc = (struct soc_mreg_control *)kcontrol->private_value; uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER64; uinfo->count = 1; uinfo->value.integer.min = mc->min; uinfo->value.integer.max = mc->max; return 0; } EXPORT_SYMBOL(tegra186_virt_ratio_param_info); 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_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); #if TEGRA_ARAD 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); #endif 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); #if TEGRA_REGDUMP 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); #endif //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; } if (strstr(kcontrol->id.name, "Status")) params->num_regs = 10; 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");