From: Sameer Pujar <spujar@nvidia.com>
To: <broonie@kernel.org>, <lgirdwood@gmail.com>, <perex@perex.cz>,
<tiwai@suse.com>
Cc: <jonathanh@nvidia.com>, <thierry.reding@gmail.com>,
<alsa-devel@alsa-project.org>, <linux-tegra@vger.kernel.org>,
<linux-kernel@vger.kernel.org>, Sameer Pujar <spujar@nvidia.com>
Subject: [PATCH] ASoC: tegra: Add master volume/mute control support
Date: Mon, 25 Oct 2021 16:36:16 +0530 [thread overview]
Message-ID: <1635159976-17355-1-git-send-email-spujar@nvidia.com> (raw)
The MVC module has a per channel control bit, based on which it decides
to apply channel specific volume/mute settings. When per channel control
bit is enabled (which is the default HW configuration), all MVC channel
volume/mute can be independently controlled. If the control is disabled,
channel-0 volume/mute setting is applied by HW to all remaining channels.
Thus add support to leverage this HW feature by exposing master controls
for volume/mute.
With this, now there are per channel and master volume/mute controls.
Users need to just use controls which are suitable for their applications.
The per channel control enable/disable is mananged in driver and hidden
from users, so that they need to just worry about respective volume/mute
controls.
Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
sound/soc/tegra/tegra210_mvc.c | 95 +++++++++++++++++++++++++++++++++++++-----
sound/soc/tegra/tegra210_mvc.h | 2 +
2 files changed, 87 insertions(+), 10 deletions(-)
diff --git a/sound/soc/tegra/tegra210_mvc.c b/sound/soc/tegra/tegra210_mvc.c
index 7b9c700..40cd21a 100644
--- a/sound/soc/tegra/tegra210_mvc.c
+++ b/sound/soc/tegra/tegra210_mvc.c
@@ -123,7 +123,42 @@ static int tegra210_mvc_get_mute(struct snd_kcontrol *kcontrol,
mute_mask = (val >> TEGRA210_MVC_MUTE_SHIFT) &
TEGRA210_MUTE_MASK_EN;
- ucontrol->value.integer.value[0] = mute_mask;
+ if (strstr(kcontrol->id.name, "Per Chan Mute Mask")) {
+ /*
+ * If per channel control is enabled, then return
+ * exact mute/unmute setting of all channels.
+ *
+ * Else report setting based on CH0 bit to reflect
+ * the correct HW state.
+ */
+ if (val & TEGRA210_MVC_PER_CHAN_CTRL_EN) {
+ ucontrol->value.integer.value[0] = mute_mask;
+ } else {
+ if (mute_mask & TEGRA210_MVC_CH0_MUTE_EN)
+ ucontrol->value.integer.value[0] =
+ TEGRA210_MUTE_MASK_EN;
+ else
+ ucontrol->value.integer.value[0] = 0;
+ }
+ } else {
+ /*
+ * If per channel control is disabled, then return
+ * master mute/unmute setting based on CH0 bit.
+ *
+ * Else report settings based on state of all
+ * channels.
+ */
+ if (!(val & TEGRA210_MVC_PER_CHAN_CTRL_EN)) {
+ ucontrol->value.integer.value[0] =
+ mute_mask & TEGRA210_MVC_CH0_MUTE_EN;
+ } else {
+ if (mute_mask == TEGRA210_MUTE_MASK_EN)
+ ucontrol->value.integer.value[0] =
+ TEGRA210_MVC_CH0_MUTE_EN;
+ else
+ ucontrol->value.integer.value[0] = 0;
+ }
+ }
return 0;
}
@@ -136,6 +171,7 @@ static int tegra210_mvc_put_mute(struct snd_kcontrol *kcontrol,
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt);
unsigned int value;
+ u32 reg_mask;
u8 mute_mask;
int err;
@@ -150,11 +186,22 @@ static int tegra210_mvc_put_mute(struct snd_kcontrol *kcontrol,
mute_mask = ucontrol->value.integer.value[0];
- err = regmap_update_bits(mvc->regmap, mc->reg,
- TEGRA210_MVC_MUTE_MASK,
- mute_mask << TEGRA210_MVC_MUTE_SHIFT);
- if (err < 0)
- goto end;
+ if (strstr(kcontrol->id.name, "Per Chan Mute Mask")) {
+ regmap_update_bits(mvc->regmap, TEGRA210_MVC_CTRL,
+ TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK,
+ TEGRA210_MVC_PER_CHAN_CTRL_EN);
+
+ reg_mask = TEGRA210_MVC_MUTE_MASK;
+ } else {
+ regmap_update_bits(mvc->regmap, TEGRA210_MVC_CTRL,
+ TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK,
+ 0);
+
+ reg_mask = TEGRA210_MVC_CH0_MUTE_MASK;
+ }
+
+ regmap_update_bits(mvc->regmap, mc->reg, reg_mask,
+ mute_mask << TEGRA210_MVC_MUTE_SHIFT);
return 1;
@@ -212,11 +259,31 @@ static int tegra210_mvc_put_vol(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0]);
/* Configure init volume same as target volume */
- regmap_write(mvc->regmap,
- TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_INIT_VOL, chan),
- mvc->volume[chan]);
+ if (strstr(kcontrol->id.name, "Channel")) {
+ regmap_update_bits(mvc->regmap, TEGRA210_MVC_CTRL,
+ TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK,
+ TEGRA210_MVC_PER_CHAN_CTRL_EN);
+
+ regmap_write(mvc->regmap,
+ TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_INIT_VOL, chan),
+ mvc->volume[chan]);
+
+ regmap_write(mvc->regmap, reg, mvc->volume[chan]);
+ } else {
+ int i;
+
+ regmap_update_bits(mvc->regmap, TEGRA210_MVC_CTRL,
+ TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK,
+ 0);
+
+ for (i = 1; i < TEGRA210_MVC_MAX_CHAN_COUNT; i++)
+ mvc->volume[i] = mvc->volume[0];
- regmap_write(mvc->regmap, reg, mvc->volume[chan]);
+ regmap_write(mvc->regmap, TEGRA210_MVC_INIT_VOL,
+ mvc->volume[0]);
+
+ regmap_write(mvc->regmap, reg, mvc->volume[0]);
+ }
regmap_update_bits(mvc->regmap, TEGRA210_MVC_SWITCH,
TEGRA210_MVC_VOLUME_SWITCH_MASK,
@@ -422,6 +489,14 @@ static const struct snd_kcontrol_new tegra210_mvc_vol_ctrl[] = {
TEGRA210_MVC_CTRL, 0, TEGRA210_MUTE_MASK_EN, 0,
tegra210_mvc_get_mute, tegra210_mvc_put_mute),
+ /* Master volume */
+ SOC_SINGLE_EXT("Volume", TEGRA210_MVC_TARGET_VOL, 0, 16000, 0,
+ tegra210_mvc_get_vol, tegra210_mvc_put_vol),
+
+ /* Master mute */
+ SOC_SINGLE_EXT("Mute", TEGRA210_MVC_CTRL, 0, 1, 0,
+ tegra210_mvc_get_mute, tegra210_mvc_put_mute),
+
SOC_ENUM_EXT("Curve Type", tegra210_mvc_curve_type_ctrl,
tegra210_mvc_get_curve_type, tegra210_mvc_put_curve_type),
};
diff --git a/sound/soc/tegra/tegra210_mvc.h b/sound/soc/tegra/tegra210_mvc.h
index def29c4..7f2567e 100644
--- a/sound/soc/tegra/tegra210_mvc.h
+++ b/sound/soc/tegra/tegra210_mvc.h
@@ -59,6 +59,8 @@
#define TEGRA210_MUTE_MASK_EN 0xff
#define TEGRA210_MVC_MUTE_MASK (TEGRA210_MUTE_MASK_EN << TEGRA210_MVC_MUTE_SHIFT)
#define TEGRA210_MVC_MUTE_EN (TEGRA210_MUTE_MASK_EN << TEGRA210_MVC_MUTE_SHIFT)
+#define TEGRA210_MVC_CH0_MUTE_EN 1
+#define TEGRA210_MVC_CH0_MUTE_MASK (TEGRA210_MVC_CH0_MUTE_EN << TEGRA210_MVC_MUTE_SHIFT)
#define TEGRA210_MVC_PER_CHAN_CTRL_EN_SHIFT 30
#define TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK (1 << TEGRA210_MVC_PER_CHAN_CTRL_EN_SHIFT)
--
2.7.4
next reply other threads:[~2021-10-25 11:06 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-10-25 11:06 Sameer Pujar [this message]
2021-10-25 12:58 ` [PATCH] ASoC: tegra: Add master volume/mute control support Jaroslav Kysela
2021-10-26 6:23 ` Sameer Pujar
2021-10-29 15:08 ` Sameer Pujar
2021-10-29 15:22 ` Mark Brown
2021-10-29 15:26 ` Jaroslav Kysela
2021-11-03 5:12 ` Sameer Pujar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1635159976-17355-1-git-send-email-spujar@nvidia.com \
--to=spujar@nvidia.com \
--cc=alsa-devel@alsa-project.org \
--cc=broonie@kernel.org \
--cc=jonathanh@nvidia.com \
--cc=lgirdwood@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-tegra@vger.kernel.org \
--cc=perex@perex.cz \
--cc=thierry.reding@gmail.com \
--cc=tiwai@suse.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).