mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 17:25:35 +03:00
ASoC: tegra-alt: channels inside ahub via controls
Certain usecase requires different audio and client channels settings inside ahub, so this needs to be handled with dedicated Channels mixer control for each module. This change will introduce channels mixer control and cif controls to admaif,dmic,i2s and all other internal module is control with a single channel control. -Support mono channel SFC -Support mono channel Mixer -Cleanup drivers Bug 1839027 Change-Id: Id997519ebdc9f518c83debc2d4cd58fde34e79b6 Signed-off-by: Mohan Kumar <mkumard@nvidia.com> Reviewed-on: http://git-master/r/1258877 Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
committed by
Sameer Pujar
parent
dc94ff5770
commit
4ecda75d43
@@ -320,16 +320,16 @@ static int tegra210_admaif_hw_params(struct snd_pcm_substream *substream,
|
||||
struct tegra210_admaif *admaif = snd_soc_dai_get_drvdata(dai);
|
||||
struct tegra210_xbar_cif_conf cif_conf;
|
||||
unsigned int reg;
|
||||
int valid_bit;
|
||||
int valid_bit, channels;
|
||||
|
||||
memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf));
|
||||
if (admaif->override_channels[dai->id] > 0) {
|
||||
cif_conf.audio_channels = admaif->override_channels[dai->id];
|
||||
cif_conf.client_channels = admaif->override_channels[dai->id];
|
||||
} else {
|
||||
cif_conf.audio_channels = params_channels(params);
|
||||
cif_conf.client_channels = params_channels(params);
|
||||
}
|
||||
|
||||
channels = params_channels(params);
|
||||
if (admaif->override_channels[dai->id] > 0)
|
||||
channels = admaif->override_channels[dai->id];
|
||||
|
||||
cif_conf.audio_channels = channels;
|
||||
cif_conf.client_channels = channels;
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S8:
|
||||
@@ -360,9 +360,27 @@ static int tegra210_admaif_hw_params(struct snd_pcm_substream *substream,
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
reg = TEGRA210_ADMAIF_CHAN_ACIF_TX_CTRL +
|
||||
(dai->id * TEGRA210_ADMAIF_CHANNEL_REG_STRIDE);
|
||||
/* For playback path, the mono input from client channel
|
||||
* can be converted to stereo using cif controls.
|
||||
*/
|
||||
if (admaif->tx_mono_to_stereo[dai->id] > 0) {
|
||||
cif_conf.mono_conv =
|
||||
admaif->tx_mono_to_stereo[dai->id] - 1;
|
||||
cif_conf.audio_channels = 2;
|
||||
cif_conf.client_channels = 1;
|
||||
}
|
||||
} else {
|
||||
reg = TEGRA210_ADMAIF_CHAN_ACIF_RX_CTRL +
|
||||
(dai->id * TEGRA210_ADMAIF_CHANNEL_REG_STRIDE);
|
||||
/* For capture path, the stereo audio channel can be
|
||||
* converted to mono using cif controls.
|
||||
*/
|
||||
if (admaif->rx_stereo_to_mono[dai->id] > 0) {
|
||||
cif_conf.stereo_conv =
|
||||
admaif->rx_stereo_to_mono[dai->id] - 1;
|
||||
cif_conf.audio_channels = 2;
|
||||
cif_conf.client_channels = 1;
|
||||
}
|
||||
}
|
||||
|
||||
tegra210_admaif_set_pack_mode(admaif->regmap, reg, valid_bit);
|
||||
@@ -478,19 +496,40 @@ static struct snd_soc_dai_ops tegra210_admaif_dai_ops = {
|
||||
.prepare = tegra210_admaif_prepare,
|
||||
};
|
||||
|
||||
static int tegra210_admaif_get_channels(struct snd_kcontrol *kcontrol,
|
||||
static int tegra210_admaif_get_format(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct soc_mixer_control *mc =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
struct tegra210_admaif *admaif = snd_soc_codec_get_drvdata(codec);
|
||||
int i;
|
||||
char buf[50];
|
||||
|
||||
if (strstr(kcontrol->id.name, "Channels"))
|
||||
ucontrol->value.integer.value[0] =
|
||||
admaif->override_channels[mc->reg];
|
||||
else {
|
||||
for (i = 0 ; i < TEGRA210_ADMAIF_CHANNEL_COUNT; i++) {
|
||||
snprintf(buf, 50, "ADMAIF%d RX stereo to mono", i+1);
|
||||
if (strstr(kcontrol->id.name, buf)) {
|
||||
ucontrol->value.integer.value[0] =
|
||||
admaif->rx_stereo_to_mono[i];
|
||||
break;
|
||||
}
|
||||
snprintf(buf, 50, "ADMAIF%d TX mono to stereo", i+1);
|
||||
if (strstr(kcontrol->id.name, buf)) {
|
||||
ucontrol->value.integer.value[0] =
|
||||
admaif->tx_mono_to_stereo[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ucontrol->value.integer.value[0] = admaif->override_channels[mc->reg];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra210_admaif_put_channels(struct snd_kcontrol *kcontrol,
|
||||
static int tegra210_admaif_put_format(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct soc_mixer_control *mc =
|
||||
@@ -498,12 +537,30 @@ static int tegra210_admaif_put_channels(struct snd_kcontrol *kcontrol,
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct tegra210_admaif *admaif = snd_soc_codec_get_drvdata(codec);
|
||||
int value = ucontrol->value.integer.value[0];
|
||||
int i;
|
||||
char buf[50];
|
||||
|
||||
if (value > 0 && value <= 16) {
|
||||
admaif->override_channels[mc->reg] = value;
|
||||
return 0;
|
||||
} else
|
||||
return -EINVAL;
|
||||
if (strstr(kcontrol->id.name, "Channels")) {
|
||||
if (value > 0 && value <= 16)
|
||||
admaif->override_channels[mc->reg] = value;
|
||||
else
|
||||
return -EINVAL;
|
||||
} else {
|
||||
for (i = 0 ; i < TEGRA210_ADMAIF_CHANNEL_COUNT; i++) {
|
||||
snprintf(buf, 50, "ADMAIF%d RX stereo to mono", i+1);
|
||||
if (strstr(kcontrol->id.name, buf)) {
|
||||
admaif->rx_stereo_to_mono[i] = value;
|
||||
break;
|
||||
}
|
||||
snprintf(buf, 50, "ADMAIF%d TX mono to stereo", i+1);
|
||||
if (strstr(kcontrol->id.name, buf)) {
|
||||
admaif->tx_mono_to_stereo[i] = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra210_admaif_dai_probe(struct snd_soc_dai *dai)
|
||||
@@ -728,9 +785,37 @@ static const struct snd_soc_dapm_route tegra210_admaif_routes[] = {
|
||||
ADMAIF_ROUTES(20)
|
||||
};
|
||||
|
||||
static const char * const tegra_admaif_stereo_conv_text[] = {
|
||||
"None", "CH0", "CH1", "AVG",
|
||||
};
|
||||
|
||||
static const char * const tegra_admaif_mono_conv_text[] = {
|
||||
"None", "ZERO", "COPY",
|
||||
};
|
||||
|
||||
static const struct soc_enum tegra_admaif_mono_conv_enum =
|
||||
SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
|
||||
ARRAY_SIZE(tegra_admaif_mono_conv_text),
|
||||
tegra_admaif_mono_conv_text);
|
||||
|
||||
static const struct soc_enum tegra_admaif_stereo_conv_enum =
|
||||
SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
|
||||
ARRAY_SIZE(tegra_admaif_stereo_conv_text),
|
||||
tegra_admaif_stereo_conv_text);
|
||||
|
||||
#define TEGRA210_ADMAIF_CHANNEL_CTRL(reg) \
|
||||
SOC_SINGLE_EXT("ADMAIF" #reg " Channels", reg - 1, 0, 16, 0, \
|
||||
tegra210_admaif_get_channels, tegra210_admaif_put_channels)
|
||||
tegra210_admaif_get_format, tegra210_admaif_put_format)
|
||||
|
||||
#define TEGRA210_ADMAIF_TX_CIF_CTRL(reg) \
|
||||
SOC_ENUM_EXT("ADMAIF" #reg " TX mono to stereo conv", \
|
||||
tegra_admaif_mono_conv_enum, tegra210_admaif_get_format, \
|
||||
tegra210_admaif_put_format)
|
||||
|
||||
#define TEGRA210_ADMAIF_RX_CIF_CTRL(reg) \
|
||||
SOC_ENUM_EXT("ADMAIF" #reg " RX stereo to mono conv", \
|
||||
tegra_admaif_stereo_conv_enum, tegra210_admaif_get_format, \
|
||||
tegra210_admaif_put_format)
|
||||
|
||||
static struct snd_kcontrol_new tegra210_admaif_controls[] = {
|
||||
TEGRA210_ADMAIF_CHANNEL_CTRL(1),
|
||||
@@ -753,7 +838,51 @@ static struct snd_kcontrol_new tegra210_admaif_controls[] = {
|
||||
TEGRA210_ADMAIF_CHANNEL_CTRL(17),
|
||||
TEGRA210_ADMAIF_CHANNEL_CTRL(18),
|
||||
TEGRA210_ADMAIF_CHANNEL_CTRL(19),
|
||||
TEGRA210_ADMAIF_CHANNEL_CTRL(20)
|
||||
TEGRA210_ADMAIF_CHANNEL_CTRL(20),
|
||||
#endif
|
||||
TEGRA210_ADMAIF_RX_CIF_CTRL(1),
|
||||
TEGRA210_ADMAIF_RX_CIF_CTRL(2),
|
||||
TEGRA210_ADMAIF_RX_CIF_CTRL(3),
|
||||
TEGRA210_ADMAIF_RX_CIF_CTRL(4),
|
||||
TEGRA210_ADMAIF_RX_CIF_CTRL(5),
|
||||
TEGRA210_ADMAIF_RX_CIF_CTRL(6),
|
||||
TEGRA210_ADMAIF_RX_CIF_CTRL(7),
|
||||
TEGRA210_ADMAIF_RX_CIF_CTRL(8),
|
||||
TEGRA210_ADMAIF_RX_CIF_CTRL(9),
|
||||
TEGRA210_ADMAIF_RX_CIF_CTRL(10),
|
||||
#if defined(CONFIG_ARCH_TEGRA_18x_SOC)
|
||||
TEGRA210_ADMAIF_RX_CIF_CTRL(11),
|
||||
TEGRA210_ADMAIF_RX_CIF_CTRL(12),
|
||||
TEGRA210_ADMAIF_RX_CIF_CTRL(13),
|
||||
TEGRA210_ADMAIF_RX_CIF_CTRL(14),
|
||||
TEGRA210_ADMAIF_RX_CIF_CTRL(15),
|
||||
TEGRA210_ADMAIF_RX_CIF_CTRL(16),
|
||||
TEGRA210_ADMAIF_RX_CIF_CTRL(17),
|
||||
TEGRA210_ADMAIF_RX_CIF_CTRL(18),
|
||||
TEGRA210_ADMAIF_RX_CIF_CTRL(19),
|
||||
TEGRA210_ADMAIF_RX_CIF_CTRL(20),
|
||||
#endif
|
||||
TEGRA210_ADMAIF_TX_CIF_CTRL(1),
|
||||
TEGRA210_ADMAIF_TX_CIF_CTRL(2),
|
||||
TEGRA210_ADMAIF_TX_CIF_CTRL(3),
|
||||
TEGRA210_ADMAIF_TX_CIF_CTRL(4),
|
||||
TEGRA210_ADMAIF_TX_CIF_CTRL(5),
|
||||
TEGRA210_ADMAIF_TX_CIF_CTRL(6),
|
||||
TEGRA210_ADMAIF_TX_CIF_CTRL(7),
|
||||
TEGRA210_ADMAIF_TX_CIF_CTRL(8),
|
||||
TEGRA210_ADMAIF_TX_CIF_CTRL(9),
|
||||
TEGRA210_ADMAIF_TX_CIF_CTRL(10),
|
||||
#if defined(CONFIG_ARCH_TEGRA_18x_SOC)
|
||||
TEGRA210_ADMAIF_TX_CIF_CTRL(11),
|
||||
TEGRA210_ADMAIF_TX_CIF_CTRL(12),
|
||||
TEGRA210_ADMAIF_TX_CIF_CTRL(13),
|
||||
TEGRA210_ADMAIF_TX_CIF_CTRL(14),
|
||||
TEGRA210_ADMAIF_TX_CIF_CTRL(15),
|
||||
TEGRA210_ADMAIF_TX_CIF_CTRL(16),
|
||||
TEGRA210_ADMAIF_TX_CIF_CTRL(17),
|
||||
TEGRA210_ADMAIF_TX_CIF_CTRL(18),
|
||||
TEGRA210_ADMAIF_TX_CIF_CTRL(19),
|
||||
TEGRA210_ADMAIF_TX_CIF_CTRL(20),
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -319,11 +319,15 @@ static int tegra210_amx_set_audio_cif(struct snd_soc_dai *dai,
|
||||
|
||||
memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf));
|
||||
|
||||
channels = params_channels(params);
|
||||
|
||||
if (strstr(dai->name, "OUT")) {
|
||||
channels = amx->output_channels > 0 ?
|
||||
amx->output_channels : params_channels(params);
|
||||
} else
|
||||
channels = params_channels(params);
|
||||
amx->output_channels : channels;
|
||||
} else {
|
||||
channels = amx->input_channels[dai->id] > 0 ?
|
||||
amx->input_channels[dai->id] : channels;
|
||||
}
|
||||
|
||||
if (channels < 1 || channels > 16)
|
||||
return -EINVAL;
|
||||
@@ -513,28 +517,49 @@ static int tegra210_amx_put_byte_map(struct snd_kcontrol *kcontrol,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra210_amx_get_output_channels(struct snd_kcontrol *kcontrol,
|
||||
static int tegra210_amx_get_channels(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct soc_mixer_control *mc =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
struct tegra210_amx *amx = snd_soc_codec_get_drvdata(codec);
|
||||
int reg = mc->reg;
|
||||
char buf[50];
|
||||
|
||||
snprintf(buf, 50, "Input%d Channels", reg);
|
||||
if (strstr(kcontrol->id.name, buf))
|
||||
ucontrol->value.integer.value[0] = amx->input_channels[reg - 1];
|
||||
else if (strstr(kcontrol->id.name, "Output Channels"))
|
||||
ucontrol->value.integer.value[0] = amx->output_channels;
|
||||
|
||||
ucontrol->value.integer.value[0] = amx->output_channels;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra210_amx_put_output_channels(struct snd_kcontrol *kcontrol,
|
||||
static int tegra210_amx_put_channels(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct soc_mixer_control *mc =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
struct tegra210_amx *amx = snd_soc_codec_get_drvdata(codec);
|
||||
int reg = mc->reg;
|
||||
int value = ucontrol->value.integer.value[0];
|
||||
char buf[50];
|
||||
|
||||
if (value > 0 && value <= 16) {
|
||||
amx->output_channels = value;
|
||||
return 0;
|
||||
} else
|
||||
return -EINVAL;
|
||||
snprintf(buf, 50, "Input%d Channels", reg);
|
||||
if (strstr(kcontrol->id.name, buf)) {
|
||||
if (value > 0 && value <= 16)
|
||||
amx->input_channels[reg - 1] = value;
|
||||
else
|
||||
return -EINVAL;
|
||||
} else if (strstr(kcontrol->id.name, "Output Channels")) {
|
||||
if (value > 0 && value <= 16)
|
||||
amx->output_channels = value;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra210_amx_codec_probe(struct snd_soc_codec *codec)
|
||||
@@ -618,8 +643,13 @@ static const struct snd_soc_dapm_route tegra210_amx_routes[] = {
|
||||
|
||||
#define TEGRA210_AMX_OUTPUT_CHANNELS_CTRL(reg) \
|
||||
SOC_SINGLE_EXT("Output Channels", reg, 0, 16, 0, \
|
||||
tegra210_amx_get_output_channels, \
|
||||
tegra210_amx_put_output_channels)
|
||||
tegra210_amx_get_channels, \
|
||||
tegra210_amx_put_channels)
|
||||
|
||||
#define TEGRA210_AMX_INPUT_CHANNELS_CTRL(reg) \
|
||||
SOC_SINGLE_EXT("Input" #reg " Channels", reg, 0, 16, 0, \
|
||||
tegra210_amx_get_channels, \
|
||||
tegra210_amx_put_channels)
|
||||
|
||||
static struct snd_kcontrol_new tegra210_amx_controls[] = {
|
||||
TEGRA210_AMX_BYTE_MAP_CTRL(0),
|
||||
@@ -688,6 +718,10 @@ static struct snd_kcontrol_new tegra210_amx_controls[] = {
|
||||
TEGRA210_AMX_BYTE_MAP_CTRL(63),
|
||||
|
||||
TEGRA210_AMX_OUTPUT_CHANNELS_CTRL(1),
|
||||
TEGRA210_AMX_INPUT_CHANNELS_CTRL(1),
|
||||
TEGRA210_AMX_INPUT_CHANNELS_CTRL(2),
|
||||
TEGRA210_AMX_INPUT_CHANNELS_CTRL(3),
|
||||
TEGRA210_AMX_INPUT_CHANNELS_CTRL(4),
|
||||
};
|
||||
|
||||
static struct snd_soc_codec_driver tegra210_amx_codec = {
|
||||
|
||||
@@ -154,7 +154,6 @@ static int tegra210_dmic_hw_params(struct snd_pcm_substream *substream,
|
||||
|
||||
memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf));
|
||||
|
||||
channels = params_channels(params);
|
||||
srate = params_rate(params);
|
||||
dmic_clk = (1 << (6+osr)) * srate;
|
||||
|
||||
@@ -166,6 +165,17 @@ static int tegra210_dmic_hw_params(struct snd_pcm_substream *substream,
|
||||
channel_select = dmic->ch_select;
|
||||
}
|
||||
|
||||
cif_conf.client_channels = channels;
|
||||
cif_conf.audio_channels = channels;
|
||||
|
||||
/* For capture path, the mono input from client channel
|
||||
* can be converted to stereo with cif controls.
|
||||
*/
|
||||
if (dmic->tx_mono_to_stereo > 0) {
|
||||
cif_conf.mono_conv = dmic->tx_mono_to_stereo - 1;
|
||||
cif_conf.audio_channels = 2;
|
||||
}
|
||||
|
||||
if ((tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) {
|
||||
program_dmic_gpio();
|
||||
program_dmic_clk(dmic_clk);
|
||||
@@ -241,9 +251,6 @@ static int tegra210_dmic_hw_params(struct snd_pcm_substream *substream,
|
||||
regmap_write(dmic->regmap,
|
||||
TEGRA210_DMIC_LP_BIQUAD_1_COEF_4, 0x00000000);
|
||||
|
||||
cif_conf.audio_channels = channels;
|
||||
cif_conf.client_channels = channels;
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_16;
|
||||
@@ -274,6 +281,9 @@ static int tegra210_dmic_get_control(struct snd_kcontrol *kcontrol,
|
||||
ucontrol->value.integer.value[0] = dmic->boost_gain;
|
||||
else if (strstr(kcontrol->id.name, "Mono"))
|
||||
ucontrol->value.integer.value[0] = dmic->ch_select;
|
||||
else if (strstr(kcontrol->id.name, "TX mono to stereo"))
|
||||
ucontrol->value.integer.value[0] =
|
||||
dmic->tx_mono_to_stereo;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -283,11 +293,14 @@ static int tegra210_dmic_put_control(struct snd_kcontrol *kcontrol,
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct tegra210_dmic *dmic = snd_soc_codec_get_drvdata(codec);
|
||||
int value = ucontrol->value.integer.value[0];
|
||||
|
||||
if (strstr(kcontrol->id.name, "Boost"))
|
||||
dmic->boost_gain = ucontrol->value.integer.value[0];
|
||||
dmic->boost_gain = value;
|
||||
else if (strstr(kcontrol->id.name, "Mono"))
|
||||
dmic->ch_select = ucontrol->value.integer.value[0];
|
||||
else if (strstr(kcontrol->id.name, "TX mono to stereo"))
|
||||
dmic->tx_mono_to_stereo = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -349,16 +362,29 @@ static const struct snd_soc_dapm_route tegra210_dmic_routes[] = {
|
||||
static const char * const tegra210_dmic_ch_select[] = {
|
||||
"None", "L", "R",
|
||||
};
|
||||
|
||||
static const struct soc_enum tegra210_dmic_ch_enum =
|
||||
SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
|
||||
ARRAY_SIZE(tegra210_dmic_ch_select),
|
||||
tegra210_dmic_ch_select);
|
||||
|
||||
static const char * const tegra210_dmic_mono_conv_text[] = {
|
||||
"None", "ZERO", "COPY",
|
||||
};
|
||||
|
||||
static const struct soc_enum tegra210_dmic_mono_conv_enum =
|
||||
SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
|
||||
ARRAY_SIZE(tegra210_dmic_mono_conv_text),
|
||||
tegra210_dmic_mono_conv_text);
|
||||
|
||||
static const struct snd_kcontrol_new tegra210_dmic_controls[] = {
|
||||
SOC_SINGLE_EXT("Boost Gain", 0, 0, 25600, 0,
|
||||
tegra210_dmic_get_control, tegra210_dmic_put_control),
|
||||
SOC_ENUM_EXT("Mono Channel Select", tegra210_dmic_ch_enum,
|
||||
tegra210_dmic_get_control, tegra210_dmic_put_control),
|
||||
};
|
||||
SOC_ENUM_EXT("TX mono to stereo conv", tegra210_dmic_mono_conv_enum,
|
||||
tegra210_dmic_get_control, tegra210_dmic_put_control),
|
||||
};
|
||||
|
||||
static struct snd_soc_codec_driver tegra210_dmic_codec = {
|
||||
.probe = tegra210_dmic_codec_probe,
|
||||
|
||||
@@ -141,6 +141,39 @@ static int tegra210_mixer_write_ram(struct tegra210_mixer *mixer,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra210_mixer_put_format(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct soc_mixer_control *mc =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct tegra210_mixer *mixer = snd_soc_codec_get_drvdata(codec);
|
||||
int value = ucontrol->value.integer.value[0];
|
||||
|
||||
if (strstr(kcontrol->id.name, "Channels")) {
|
||||
if (value > 0 && value <= 8)
|
||||
mixer->channels_via_control[mc->reg - 1] = value;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra210_mixer_get_format(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct soc_mixer_control *mc =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct tegra210_mixer *mixer = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (strstr(kcontrol->id.name, "Channels"))
|
||||
ucontrol->value.integer.value[0] =
|
||||
mixer->channels_via_control[mc->reg - 1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int tegra210_mixer_get_gain(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
@@ -189,7 +222,8 @@ static int tegra210_mixer_put_gain(struct snd_kcontrol *kcontrol,
|
||||
|
||||
static int tegra210_mixer_set_audio_cif(struct tegra210_mixer *mixer,
|
||||
struct snd_pcm_hw_params *params,
|
||||
unsigned int reg)
|
||||
unsigned int reg,
|
||||
unsigned int id)
|
||||
{
|
||||
int channels, audio_bits;
|
||||
struct tegra210_xbar_cif_conf cif_conf;
|
||||
@@ -197,8 +231,9 @@ static int tegra210_mixer_set_audio_cif(struct tegra210_mixer *mixer,
|
||||
memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf));
|
||||
|
||||
channels = params_channels(params);
|
||||
if (channels < 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (mixer->channels_via_control[id])
|
||||
channels = mixer->channels_via_control[id];
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
@@ -230,7 +265,8 @@ static int tegra210_mixer_in_hw_params(struct snd_pcm_substream *substream,
|
||||
|
||||
ret = tegra210_mixer_set_audio_cif(mixer, params,
|
||||
TEGRA210_MIXER_AXBAR_RX1_CIF_CTRL +
|
||||
(dai->id * TEGRA210_MIXER_AXBAR_RX_STRIDE));
|
||||
(dai->id * TEGRA210_MIXER_AXBAR_RX_STRIDE),
|
||||
dai->id);
|
||||
|
||||
/* write the gain config poly coefficients */
|
||||
for (i = 0; i < 14; i++) {
|
||||
@@ -261,7 +297,8 @@ static int tegra210_mixer_out_hw_params(struct snd_pcm_substream *substream,
|
||||
|
||||
ret = tegra210_mixer_set_audio_cif(mixer, params,
|
||||
TEGRA210_MIXER_AXBAR_TX1_CIF_CTRL +
|
||||
((dai->id-10) * TEGRA210_MIXER_AXBAR_TX_STRIDE));
|
||||
((dai->id-10) * TEGRA210_MIXER_AXBAR_TX_STRIDE),
|
||||
dai->id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -394,6 +431,36 @@ static const struct snd_kcontrol_new tegra210_mixer_gain_ctls[] = { \
|
||||
0x20000, 0, tegra210_mixer_get_gain, tegra210_mixer_put_gain),
|
||||
SOC_SINGLE_EXT("RX10 Gain Instant", MIXER_GAIN_CONFIG_RAM_ADDR(9), 0,
|
||||
0x20000, 0, tegra210_mixer_get_gain, tegra210_mixer_put_gain),
|
||||
SOC_SINGLE_EXT("RX1 Channels", 1, 0, 8, 0,
|
||||
tegra210_mixer_get_format, tegra210_mixer_put_format),
|
||||
SOC_SINGLE_EXT("RX2 Channels", 2, 0, 8, 0,
|
||||
tegra210_mixer_get_format, tegra210_mixer_put_format),
|
||||
SOC_SINGLE_EXT("RX3 Channels", 3, 0, 8, 0,
|
||||
tegra210_mixer_get_format, tegra210_mixer_put_format),
|
||||
SOC_SINGLE_EXT("RX4 Channels", 4, 0, 8, 0,
|
||||
tegra210_mixer_get_format, tegra210_mixer_put_format),
|
||||
SOC_SINGLE_EXT("RX5 Channels", 5, 0, 8, 0,
|
||||
tegra210_mixer_get_format, tegra210_mixer_put_format),
|
||||
SOC_SINGLE_EXT("RX6 Channels", 6, 0, 8, 0,
|
||||
tegra210_mixer_get_format, tegra210_mixer_put_format),
|
||||
SOC_SINGLE_EXT("RX7 Channels", 7, 0, 8, 0,
|
||||
tegra210_mixer_get_format, tegra210_mixer_put_format),
|
||||
SOC_SINGLE_EXT("RX8 Channels", 8, 0, 8, 0,
|
||||
tegra210_mixer_get_format, tegra210_mixer_put_format),
|
||||
SOC_SINGLE_EXT("RX9 Channels", 9, 0, 8, 0,
|
||||
tegra210_mixer_get_format, tegra210_mixer_put_format),
|
||||
SOC_SINGLE_EXT("RX10 Channels", 10, 0, 8, 0,
|
||||
tegra210_mixer_get_format, tegra210_mixer_put_format),
|
||||
SOC_SINGLE_EXT("TX1 Channels", 11, 0, 8, 0,
|
||||
tegra210_mixer_get_format, tegra210_mixer_put_format),
|
||||
SOC_SINGLE_EXT("TX2 Channels", 12, 0, 8, 0,
|
||||
tegra210_mixer_get_format, tegra210_mixer_put_format),
|
||||
SOC_SINGLE_EXT("TX3 Channels", 13, 0, 8, 0,
|
||||
tegra210_mixer_get_format, tegra210_mixer_put_format),
|
||||
SOC_SINGLE_EXT("TX4 Channels", 14, 0, 8, 0,
|
||||
tegra210_mixer_get_format, tegra210_mixer_put_format),
|
||||
SOC_SINGLE_EXT("TX5 Channels", 15, 0, 8, 0,
|
||||
tegra210_mixer_get_format, tegra210_mixer_put_format),
|
||||
SOC_SINGLE("Mixer Enable", TEGRA210_MIXER_ENABLE, 0, 1, 0),
|
||||
};
|
||||
|
||||
|
||||
@@ -325,7 +325,7 @@ static int tegra210_mvc_put_channels(struct snd_kcontrol *kcontrol,
|
||||
unsigned int val;
|
||||
|
||||
val = ucontrol->value.integer.value[0];
|
||||
if ((val > 0) && (val << 16))
|
||||
if ((val > 0) && (val <= 8))
|
||||
mvc->cif_channels = val;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
@@ -301,8 +301,6 @@ static int tegra210_sfc_set_audio_cif(struct tegra210_sfc *sfc,
|
||||
memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf));
|
||||
|
||||
channels = params_channels(params);
|
||||
if (channels < 2)
|
||||
return -EINVAL;
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
@@ -315,6 +313,9 @@ static int tegra210_sfc_set_audio_cif(struct tegra210_sfc *sfc,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (sfc->channels_via_control)
|
||||
channels = sfc->channels_via_control;
|
||||
|
||||
if (sfc->stereo_conv_input > 0 && 2 == channels &&
|
||||
(reg == TEGRA210_SFC_AXBAR_RX_CIF_CTRL)) {
|
||||
cif_conf.stereo_conv = sfc->stereo_conv_input - 1;
|
||||
@@ -473,9 +474,10 @@ static int tegra210_sfc_get_format(struct snd_kcontrol *kcontrol,
|
||||
/* get the format control flag */
|
||||
if (strstr(kcontrol->id.name, "input"))
|
||||
ucontrol->value.integer.value[0] = sfc->format_in;
|
||||
|
||||
if (strstr(kcontrol->id.name, "output"))
|
||||
else if (strstr(kcontrol->id.name, "output"))
|
||||
ucontrol->value.integer.value[0] = sfc->format_out;
|
||||
else if (strstr(kcontrol->id.name, "Channels"))
|
||||
ucontrol->value.integer.value[0] = sfc->channels_via_control;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -485,13 +487,19 @@ static int tegra210_sfc_put_format(struct snd_kcontrol *kcontrol,
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct tegra210_sfc *sfc = snd_soc_codec_get_drvdata(codec);
|
||||
int value = ucontrol->value.integer.value[0];
|
||||
|
||||
/* set the format control flag */
|
||||
if (strstr(kcontrol->id.name, "input"))
|
||||
sfc->format_in = ucontrol->value.integer.value[0];
|
||||
|
||||
if (strstr(kcontrol->id.name, "output"))
|
||||
sfc->format_out = ucontrol->value.integer.value[0];
|
||||
sfc->format_in = value;
|
||||
else if (strstr(kcontrol->id.name, "output"))
|
||||
sfc->format_out = value;
|
||||
else if (strstr(kcontrol->id.name, "Channels")) {
|
||||
if (value > 0 && value <= 2)
|
||||
sfc->channels_via_control = value;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -657,7 +665,7 @@ static struct snd_soc_dai_driver tegra210_sfc_dais[] = {
|
||||
.capture = {
|
||||
.stream_name = "SFC Transmit",
|
||||
.channels_min = 1,
|
||||
.channels_max = 16,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S8 |
|
||||
SNDRV_PCM_FMTBIT_S16_LE |
|
||||
@@ -719,6 +727,8 @@ static const struct snd_kcontrol_new tegra210_sfc_controls[] = {
|
||||
tegra210_sfc_get_format, tegra210_sfc_put_format),
|
||||
SOC_ENUM_EXT("output bit format", tegra210_sfc_format_enum,
|
||||
tegra210_sfc_get_format, tegra210_sfc_put_format),
|
||||
SOC_SINGLE_EXT("Channels", 0, 0, 2, 0,
|
||||
tegra210_sfc_get_format, tegra210_sfc_put_format),
|
||||
SOC_SINGLE_EXT("init", 0, 0, 1, 0,
|
||||
tegra210_sfc_init_get, tegra210_sfc_init_put),
|
||||
SOC_ENUM_EXT("input stereo conv", tegra210_sfc_stereo_conv_enum,
|
||||
|
||||
Reference in New Issue
Block a user