diff options
| author | Haynes Mathew George <hgeorge@codeaurora.org> | 2017-01-13 16:25:43 -0800 |
|---|---|---|
| committer | Haynes Mathew George <hgeorge@codeaurora.org> | 2017-02-09 12:05:52 -0800 |
| commit | c16632d1d6c17e78358f70800a1e832d96641603 (patch) | |
| tree | 2a52af4a5a1061d3aba1d4fe9d2be2210038d966 | |
| parent | 147b2394be6d487f75445ed84794b60c4dc8cfc8 (diff) | |
ASoC: msm: qdsp6v2: NOIRQ dynamic perf mode control
Expose mixer control to dynamically set performance
mode for NOIRQ FE instance.
CRs-Fixed: 2002360
Change-Id: I1a20325882ba45b24633920de1a45b75d315fb72
Signed-off-by: Haynes Mathew George <hgeorge@codeaurora.org>
| -rw-r--r-- | sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c | 131 |
1 files changed, 127 insertions, 4 deletions
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c index 1fdb878a1a1f..33c5b6486cca 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -139,6 +139,17 @@ static struct snd_pcm_hw_constraint_list constraints_sample_rates = { .mask = 0, }; +static unsigned long msm_pcm_fe_topology[MSM_FRONTEND_DAI_MAX]; + +/* default value is DTS (i.e read from device tree) */ +static char const *msm_pcm_fe_topology_text[] = { + "DTS", "ULL", "ULL_PP", "LL" }; + +static const struct soc_enum msm_pcm_fe_topology_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(msm_pcm_fe_topology_text), + msm_pcm_fe_topology_text), +}; + static void event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, void *priv) { @@ -258,6 +269,8 @@ static int msm_pcm_hw_params(struct snd_pcm_substream *substream, uint16_t bits_per_sample; int ret; int dir = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? IN : OUT; + unsigned long topology; + int perf_mode; pdata = (struct msm_plat_data *) dev_get_drvdata(soc_prtd->platform->dev); @@ -268,11 +281,24 @@ static int msm_pcm_hw_params(struct snd_pcm_substream *substream, return ret; } + topology = msm_pcm_fe_topology[soc_prtd->dai_link->be_id]; + + if (!strcmp(msm_pcm_fe_topology_text[topology], "ULL_PP")) + perf_mode = ULL_POST_PROCESSING_PCM_MODE; + else if (!strcmp(msm_pcm_fe_topology_text[topology], "ULL")) + perf_mode = ULTRA_LOW_LATENCY_PCM_MODE; + else if (!strcmp(msm_pcm_fe_topology_text[topology], "LL")) + perf_mode = LOW_LATENCY_PCM_MODE; + else + /* use the default from the device tree */ + perf_mode = pdata->perf_mode; + + /* need to set LOW_LATENCY_PCM_MODE for capture since * push mode does not support ULL */ prtd->audio_client->perf_mode = (dir == IN) ? - pdata->perf_mode : + perf_mode : LOW_LATENCY_PCM_MODE; /* rate and channels are sent to audio driver */ @@ -721,6 +747,93 @@ static int msm_pcm_add_chmap_control(struct snd_soc_pcm_runtime *rtd) return 0; } +static int msm_pcm_fe_topology_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + const struct soc_enum *e = &msm_pcm_fe_topology_enum[0]; + + return snd_ctl_enum_info(uinfo, 1, e->items, e->texts); +} + +static int msm_pcm_fe_topology_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + unsigned long fe_id = kcontrol->private_value; + + if (fe_id >= MSM_FRONTEND_DAI_MAX) { + pr_err("%s Received out of bound fe_id %lu\n", __func__, fe_id); + return -EINVAL; + } + + pr_debug("%s: %lu topology %s\n", __func__, fe_id, + msm_pcm_fe_topology_text[msm_pcm_fe_topology[fe_id]]); + ucontrol->value.enumerated.item[0] = msm_pcm_fe_topology[fe_id]; + return 0; +} + +static int msm_pcm_fe_topology_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + unsigned long fe_id = kcontrol->private_value; + unsigned int item; + + if (fe_id >= MSM_FRONTEND_DAI_MAX) { + pr_err("%s Received out of bound fe_id %lu\n", __func__, fe_id); + return -EINVAL; + } + + item = ucontrol->value.enumerated.item[0]; + if (item >= ARRAY_SIZE(msm_pcm_fe_topology_text)) { + pr_err("%s Received out of bound topology %lu\n", __func__, + fe_id); + return -EINVAL; + } + + pr_debug("%s: %lu new topology %s\n", __func__, fe_id, + msm_pcm_fe_topology_text[item]); + msm_pcm_fe_topology[fe_id] = item; + return 0; +} + +static int msm_pcm_add_fe_topology_control(struct snd_soc_pcm_runtime *rtd) +{ + const char *mixer_ctl_name = "PCM_Dev"; + const char *deviceNo = "NN"; + const char *topo_text = "Topology"; + char *mixer_str = NULL; + int ctl_len; + int ret; + struct snd_kcontrol_new topology_control[1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "?", + .info = msm_pcm_fe_topology_info, + .get = msm_pcm_fe_topology_get, + .put = msm_pcm_fe_topology_put, + .private_value = 0, + }, + }; + + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1 + + strlen(topo_text) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + + if (!mixer_str) + return -ENOMEM; + + snprintf(mixer_str, ctl_len, "%s %d %s", mixer_ctl_name, + rtd->pcm->device, topo_text); + + topology_control[0].name = mixer_str; + topology_control[0].private_value = rtd->dai_link->be_id; + ret = snd_soc_add_platform_controls(rtd->platform, topology_control, + ARRAY_SIZE(topology_control)); + msm_pcm_fe_topology[rtd->dai_link->be_id] = 0; + kfree(mixer_str); + return ret; +} + static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; @@ -741,6 +854,12 @@ static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd) pr_err("%s: Could not add pcm Volume Control %d\n", __func__, ret); } + + ret = msm_pcm_add_fe_topology_control(rtd); + if (ret) { + pr_err("%s: Could not add pcm topology control %d\n", + __func__, ret); + } pcm->nonatomic = true; exit: return ret; @@ -778,8 +897,12 @@ static int msm_pcm_probe(struct platform_device *pdev) rc = of_property_read_string(pdev->dev.of_node, "qcom,latency-level", &latency_level); - if (!rc && !strcmp(latency_level, "ultra")) - perf_mode = ULTRA_LOW_LATENCY_PCM_MODE; + if (!rc) { + if (!strcmp(latency_level, "ultra")) + perf_mode = ULTRA_LOW_LATENCY_PCM_MODE; + else if (!strcmp(latency_level, "ull-pp")) + perf_mode = ULL_POST_PROCESSING_PCM_MODE; + } } pdata = devm_kzalloc(&pdev->dev, |
