|
@@ -26,6 +26,9 @@
|
|
|
#include "codecs/sdm660_cdc/msm-analog-cdc.h"
|
|
|
#include "codecs/wsa881x.h"
|
|
|
|
|
|
+#define __CHIPSET__ "SDM660 "
|
|
|
+#define MSM_DAILINK_NAME(name) (__CHIPSET__#name)
|
|
|
+
|
|
|
#define DRV_NAME "sdm660-asoc-snd"
|
|
|
|
|
|
#define MSM_INT_DIGITAL_CODEC "msm-dig-codec"
|
|
@@ -33,6 +36,7 @@
|
|
|
|
|
|
#define DEV_NAME_STR_LEN 32
|
|
|
#define DEFAULT_MCLK_RATE 9600000
|
|
|
+#define MSM_LL_QOS_VALUE 300 /* time in us to ensure LPM doesn't go in C3/C4 */
|
|
|
|
|
|
struct dev_config {
|
|
|
u32 sample_rate;
|
|
@@ -303,6 +307,7 @@ static char const *usb_sample_rate_text[] = {"KHZ_8", "KHZ_11P025",
|
|
|
static char const *ext_disp_bit_format_text[] = {"S16_LE", "S24_LE"};
|
|
|
static char const *ext_disp_sample_rate_text[] = {"KHZ_48", "KHZ_96",
|
|
|
"KHZ_192"};
|
|
|
+static const char *const qos_text[] = {"Disable", "Enable"};
|
|
|
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_chs, ch_text);
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(proxy_rx_chs, ch_text);
|
|
@@ -361,6 +366,9 @@ static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_sample_rate, tdm_sample_rate_text);
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_chs, tdm_ch_text);
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_format, tdm_bit_format_text);
|
|
|
static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_sample_rate, tdm_sample_rate_text);
|
|
|
+static SOC_ENUM_SINGLE_EXT_DECL(qos_vote, qos_text);
|
|
|
+
|
|
|
+static int qos_vote_status;
|
|
|
|
|
|
static struct afe_clk_set mi2s_clk[MI2S_MAX] = {
|
|
|
{
|
|
@@ -1877,6 +1885,57 @@ static int ext_disp_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int msm_qos_ctl_get(struct snd_kcontrol *kcontrol,
|
|
|
+ struct snd_ctl_elem_value *ucontrol)
|
|
|
+{
|
|
|
+ ucontrol->value.enumerated.item[0] = qos_vote_status;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int msm_qos_ctl_put(struct snd_kcontrol *kcontrol,
|
|
|
+ struct snd_ctl_elem_value *ucontrol)
|
|
|
+{
|
|
|
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
|
|
+ struct snd_soc_card *card = codec->component.card;
|
|
|
+ const char *fe_name = MSM_DAILINK_NAME(LowLatency);
|
|
|
+ struct snd_soc_pcm_runtime *rtd;
|
|
|
+ struct snd_pcm_substream *substream;
|
|
|
+ s32 usecs;
|
|
|
+
|
|
|
+ rtd = snd_soc_get_pcm_runtime(card, fe_name);
|
|
|
+ if (!rtd) {
|
|
|
+ pr_err("%s: fail to get pcm runtime for %s\n",
|
|
|
+ __func__, fe_name);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ substream = rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
|
|
|
+ if (!substream) {
|
|
|
+ pr_err("%s: substream is null\n", __func__);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ qos_vote_status = ucontrol->value.enumerated.item[0];
|
|
|
+ if (qos_vote_status) {
|
|
|
+ if (pm_qos_request_active(&substream->latency_pm_qos_req))
|
|
|
+ pm_qos_remove_request(&substream->latency_pm_qos_req);
|
|
|
+ if (!substream->runtime) {
|
|
|
+ pr_err("%s: runtime is null\n", __func__);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ usecs = MSM_LL_QOS_VALUE;
|
|
|
+ if (usecs >= 0)
|
|
|
+ pm_qos_add_request(&substream->latency_pm_qos_req,
|
|
|
+ PM_QOS_CPU_DMA_LATENCY, usecs);
|
|
|
+ } else {
|
|
|
+ if (pm_qos_request_active(&substream->latency_pm_qos_req))
|
|
|
+ pm_qos_remove_request(&substream->latency_pm_qos_req);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
const struct snd_kcontrol_new msm_common_snd_controls[] = {
|
|
|
SOC_ENUM_EXT("PROXY_RX Channels", proxy_rx_chs,
|
|
|
proxy_rx_ch_get, proxy_rx_ch_put),
|
|
@@ -2101,6 +2160,8 @@ const struct snd_kcontrol_new msm_common_snd_controls[] = {
|
|
|
SOC_ENUM_EXT("QUIN_TDM_TX_0 Channels", tdm_tx_chs,
|
|
|
tdm_tx_ch_get,
|
|
|
tdm_tx_ch_put),
|
|
|
+ SOC_ENUM_EXT("MultiMedia5_RX QOS Vote", qos_vote, msm_qos_ctl_get,
|
|
|
+ msm_qos_ctl_put),
|
|
|
};
|
|
|
|
|
|
/**
|