ASoC: msm8960: Add LPA volume control
LPA volume is controlled via dsp stream volume support
available. Add TLV mixer control to set LPA stream volume
Signed-off-by: Asish Bhattacharya <asishb@codeaurora.org>
diff --git a/sound/soc/msm/msm-pcm-lpa.c b/sound/soc/msm/msm-pcm-lpa.c
index 9248b04..f7aa7a6 100644
--- a/sound/soc/msm/msm-pcm-lpa.c
+++ b/sound/soc/msm/msm-pcm-lpa.c
@@ -34,9 +34,10 @@
static struct audio_locks the_locks;
struct snd_msm {
- struct snd_card *card;
- struct snd_pcm *pcm;
+ struct msm_audio *prtd;
+ unsigned volume;
};
+static struct snd_msm lpa_audio;
static struct snd_pcm_hardware msm_pcm_hardware = {
.info = (SNDRV_PCM_INFO_MMAP |
@@ -280,10 +281,26 @@
prtd->dsp_cnt = 0;
prtd->pending_buffer = 1;
runtime->private_data = prtd;
+ lpa_audio.prtd = prtd;
+ lpa_set_volume(lpa_audio.volume);
return 0;
}
+int lpa_set_volume(unsigned volume)
+{
+ int rc = 0;
+ if (lpa_audio.prtd && lpa_audio.prtd->audio_client) {
+ rc = q6asm_set_volume(lpa_audio.prtd->audio_client, volume);
+ if (rc < 0) {
+ pr_err("%s: Send Volume command failed"
+ " rc=%d\n", __func__, rc);
+ }
+ }
+ lpa_audio.volume = volume;
+ return rc;
+}
+
static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -301,6 +318,7 @@
prtd->cmd_ack, 5 * HZ);
if (ret < 0)
pr_err("%s: CMD_EOS failed\n", __func__);
+ lpa_audio.prtd = NULL;
q6asm_audio_client_buf_free_contiguous(dir,
prtd->audio_client);
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 39529c4..097bd1c 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -60,6 +60,13 @@
static const DECLARE_TLV_DB_SCALE(fm_rx_vol_gain, 0,
INT_FM_RX_VOL_MAX_STEPS, 0);
+#define INT_LPA_RX_VOL_MAX_STEPS 0x100
+#define INT_LPA_RX_VOL_GAIN 0x3FFF
+
+static int msm_route_lpa_vol_control;
+static const DECLARE_TLV_DB_SCALE(lpa_rx_vol_gain, 0,
+ INT_LPA_RX_VOL_MAX_STEPS, 0);
+
/* Tx mixer session is stored based on BE DAI ID
* Need to map to actual AFE port ID since AFE port
* ID can get really large.
@@ -405,6 +412,23 @@
return 0;
}
+static int msm_routing_get_lpa_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm_route_lpa_vol_control;
+ return 0;
+}
+
+static int msm_routing_set_lpa_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ if (!lpa_set_volume(ucontrol->value.integer.value[0]))
+ msm_route_lpa_vol_control =
+ ucontrol->value.integer.value[0];
+
+ return 0;
+}
+
static const struct snd_kcontrol_new pri_i2s_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia1", AUDIO_MIXER_PRI_I2S_RX ,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
@@ -542,6 +566,12 @@
msm_routing_set_fm_vol_mixer, fm_rx_vol_gain),
};
+static const struct snd_kcontrol_new lpa_vol_mixer_controls[] = {
+ SOC_SINGLE_EXT_TLV("LPA RX Volume", SND_SOC_NOPM, 0,
+ INT_LPA_RX_VOL_GAIN, 0, msm_routing_get_lpa_vol_mixer,
+ msm_routing_set_lpa_vol_mixer, lpa_rx_vol_gain),
+};
+
static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
/* Frontend AIF */
/* Widget name equals to Front-End DAI name<Need confirmation>,
@@ -707,6 +737,10 @@
snd_soc_add_platform_controls(platform,
int_fm_vol_mixer_controls,
ARRAY_SIZE(int_fm_vol_mixer_controls));
+
+ snd_soc_add_platform_controls(platform,
+ lpa_vol_mixer_controls,
+ ARRAY_SIZE(lpa_vol_mixer_controls));
return 0;
}
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index c45f95b..7dacebc 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -78,4 +78,5 @@
int stream_type);
void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type);
+int lpa_set_volume(unsigned volume);
#endif /*_MSM_PCM_H*/