asoc: msm: update asm channel map for push pull mode
In noirq push pull mode channel map needs to be set during ASM open shared io stream. Add support for no irq driver to set channel map during ASM shared io stream open. CRs-Fixed: 2267809 Change-Id: Ic1abfe60bb54b6529fbb4cf999e50196befaba46 Signed-off-by: Surendar Karka <skarka@codeaurora.org>
This commit is contained in:
parent
d7c45292ba
commit
5628e8bc98
4 changed files with 149 additions and 80 deletions
|
@ -275,6 +275,8 @@ static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
int dir = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? IN : OUT;
|
||||
unsigned long topology;
|
||||
int perf_mode;
|
||||
bool use_default_chmap = true;
|
||||
char *chmap = NULL;
|
||||
|
||||
pdata = (struct msm_plat_data *)
|
||||
dev_get_drvdata(soc_prtd->platform->dev);
|
||||
|
@ -311,6 +313,13 @@ static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
if (prtd->enabled)
|
||||
return 0;
|
||||
|
||||
if (pdata->ch_map[soc_prtd->dai_link->id]) {
|
||||
use_default_chmap =
|
||||
!(pdata->ch_map[soc_prtd->dai_link->id]->set_ch_map);
|
||||
chmap =
|
||||
pdata->ch_map[soc_prtd->dai_link->id]->channel_map;
|
||||
}
|
||||
|
||||
switch (runtime->format) {
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
bits_per_sample = 24;
|
||||
|
@ -335,7 +344,8 @@ static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
config.bufsz = params_buffer_bytes(params) / params_periods(params);
|
||||
config.bufcnt = params_periods(params);
|
||||
|
||||
ret = q6asm_open_shared_io(prtd->audio_client, &config, dir);
|
||||
ret = q6asm_open_shared_io(prtd->audio_client, &config, dir,
|
||||
use_default_chmap, chmap);
|
||||
if (ret) {
|
||||
pr_err("%s: q6asm_open_write_shared_io failed ret: %d\n",
|
||||
__func__, ret);
|
||||
|
@ -718,89 +728,126 @@ static int msm_pcm_add_volume_control(struct snd_soc_pcm_runtime *rtd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
static int msm_pcm_channel_map_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
int i;
|
||||
struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
|
||||
unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
|
||||
struct snd_pcm_substream *substream;
|
||||
struct msm_audio *prtd;
|
||||
struct snd_soc_component *pcm = snd_kcontrol_chip(kcontrol);
|
||||
u64 fe_id = kcontrol->private_value;
|
||||
struct msm_plat_data *pdata = (struct msm_plat_data *)
|
||||
snd_soc_component_get_drvdata(pcm);
|
||||
int rc = 0, i = 0;
|
||||
|
||||
pr_debug("%s", __func__);
|
||||
substream = snd_pcm_chmap_substream(info, idx);
|
||||
if (!substream)
|
||||
return -ENODEV;
|
||||
if (!substream->runtime)
|
||||
return 0;
|
||||
pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
|
||||
|
||||
prtd = substream->runtime->private_data;
|
||||
if (prtd) {
|
||||
prtd->set_channel_map = true;
|
||||
for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
|
||||
prtd->channel_map[i] =
|
||||
(char)(ucontrol->value.integer.value[i]);
|
||||
if (fe_id >= MSM_FRONTEND_DAI_MAX) {
|
||||
pr_err("%s Received out of bounds fe_id %llu\n",
|
||||
__func__, fe_id);
|
||||
rc = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (pdata->ch_map[fe_id]) {
|
||||
pdata->ch_map[fe_id]->set_ch_map = true;
|
||||
for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
|
||||
pdata->ch_map[fe_id]->channel_map[i] =
|
||||
(char)(ucontrol->value.integer.value[i]);
|
||||
} else {
|
||||
pr_debug("%s: no memory for ch_map, default will be set\n",
|
||||
__func__);
|
||||
}
|
||||
end:
|
||||
pr_debug("%s: ret %d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_pcm_channel_map_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = 8;
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = 0xFFFFFFFF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
static int msm_pcm_channel_map_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
int i;
|
||||
struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
|
||||
unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
|
||||
struct snd_pcm_substream *substream;
|
||||
struct msm_audio *prtd;
|
||||
struct snd_soc_component *pcm = snd_kcontrol_chip(kcontrol);
|
||||
u64 fe_id = kcontrol->private_value;
|
||||
struct msm_plat_data *pdata = (struct msm_plat_data *)
|
||||
snd_soc_component_get_drvdata(pcm);
|
||||
int rc = 0, i = 0;
|
||||
|
||||
pr_debug("%s", __func__);
|
||||
substream = snd_pcm_chmap_substream(info, idx);
|
||||
if (!substream)
|
||||
return -ENODEV;
|
||||
memset(ucontrol->value.integer.value, 0,
|
||||
sizeof(ucontrol->value.integer.value));
|
||||
if (!substream->runtime)
|
||||
return 0; /* no channels set */
|
||||
|
||||
prtd = substream->runtime->private_data;
|
||||
|
||||
if (prtd && prtd->set_channel_map == true) {
|
||||
pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
|
||||
if (fe_id >= MSM_FRONTEND_DAI_MAX) {
|
||||
pr_err("%s: Received out of bounds fe_id %llu\n",
|
||||
__func__, fe_id);
|
||||
rc = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
if (pdata->ch_map[fe_id]) {
|
||||
for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
|
||||
ucontrol->value.integer.value[i] =
|
||||
(int)prtd->channel_map[i];
|
||||
} else {
|
||||
for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
|
||||
ucontrol->value.integer.value[i] = 0;
|
||||
pdata->ch_map[fe_id]->channel_map[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
end:
|
||||
pr_debug("%s: ret %d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_pcm_add_chmap_control(struct snd_soc_pcm_runtime *rtd)
|
||||
static int msm_pcm_add_channel_map_control(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
struct snd_pcm_chmap *chmap_info;
|
||||
struct snd_kcontrol *kctl;
|
||||
char device_num[12];
|
||||
int i, ret;
|
||||
const char *mixer_ctl_name = "Playback Channel Map";
|
||||
const char *deviceNo = "NN";
|
||||
char *mixer_str = NULL;
|
||||
struct msm_plat_data *pdata = NULL;
|
||||
int ctl_len = 0;
|
||||
struct snd_kcontrol_new fe_channel_map_control[1] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "?",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
||||
.info = msm_pcm_channel_map_info,
|
||||
.get = msm_pcm_channel_map_get,
|
||||
.put = msm_pcm_channel_map_put,
|
||||
.private_value = 0,
|
||||
}
|
||||
};
|
||||
|
||||
pr_debug("%s, Channel map cntrl add\n", __func__);
|
||||
ret = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
|
||||
snd_pcm_std_chmaps,
|
||||
PCM_FORMAT_MAX_NUM_CHANNEL, 0,
|
||||
&chmap_info);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!rtd) {
|
||||
pr_err("%s: NULL rtd\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
kctl = chmap_info->kctl;
|
||||
for (i = 0; i < kctl->count; i++)
|
||||
kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
|
||||
snprintf(device_num, sizeof(device_num), "%d", pcm->device);
|
||||
strlcat(kctl->id.name, device_num, sizeof(kctl->id.name));
|
||||
pr_debug("%s, Overwriting channel map control name to: %s",
|
||||
__func__, kctl->id.name);
|
||||
kctl->put = msm_pcm_chmap_ctl_put;
|
||||
kctl->get = msm_pcm_chmap_ctl_get;
|
||||
pr_debug("%s: added new pcm FE with name %s, id %d, cpu dai %s, device no %d\n",
|
||||
__func__, rtd->dai_link->name, rtd->dai_link->id,
|
||||
rtd->dai_link->cpu_dai_name, rtd->pcm->device);
|
||||
|
||||
ctl_len = strlen(mixer_ctl_name) + strlen(deviceNo) + 1;
|
||||
mixer_str = kzalloc(ctl_len, GFP_KERNEL);
|
||||
if (!mixer_str)
|
||||
return -ENOMEM;
|
||||
|
||||
snprintf(mixer_str, ctl_len, "%s%d", mixer_ctl_name, rtd->pcm->device);
|
||||
|
||||
fe_channel_map_control[0].name = mixer_str;
|
||||
fe_channel_map_control[0].private_value = rtd->dai_link->id;
|
||||
pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
|
||||
snd_soc_add_platform_controls(rtd->platform,
|
||||
fe_channel_map_control,
|
||||
ARRAY_SIZE(fe_channel_map_control));
|
||||
|
||||
pdata = snd_soc_platform_get_drvdata(rtd->platform);
|
||||
pdata->ch_map[rtd->dai_link->id] =
|
||||
kzalloc(sizeof(struct msm_pcm_ch_map), GFP_KERNEL);
|
||||
if (!pdata->ch_map[rtd->dai_link->id]) {
|
||||
pr_err("%s: Could not allocate memory for channel map\n",
|
||||
__func__);
|
||||
kfree(mixer_str);
|
||||
return -ENOMEM;
|
||||
}
|
||||
kfree(mixer_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1155,11 +1202,11 @@ static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
|||
if (!card->dev->coherent_dma_mask)
|
||||
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
|
||||
|
||||
ret = msm_pcm_add_chmap_control(rtd);
|
||||
if (ret) {
|
||||
pr_err("%s failed to add chmap cntls\n", __func__);
|
||||
goto exit;
|
||||
}
|
||||
ret = msm_pcm_add_channel_map_control(rtd);
|
||||
if (ret)
|
||||
pr_err("%s: Could not add pcm Channel Map Control\n",
|
||||
__func__);
|
||||
|
||||
ret = msm_pcm_add_volume_control(rtd);
|
||||
if (ret) {
|
||||
pr_err("%s: Could not add pcm Volume Control %d\n",
|
||||
|
@ -1181,7 +1228,7 @@ static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
|||
if (ret)
|
||||
pr_err("%s: Could not add hw dep node\n", __func__);
|
||||
pcm->nonatomic = true;
|
||||
exit:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#define _MSM_PCM_H
|
||||
#include <dsp/apr_audio-v2.h>
|
||||
#include <dsp/q6asm-v2.h>
|
||||
|
||||
#include "msm-pcm-routing-v2.h"
|
||||
|
||||
|
||||
/* Support unconventional sample rates 12000, 24000 as well */
|
||||
|
@ -125,6 +125,12 @@ struct output_meta_data_st {
|
|||
struct msm_plat_data {
|
||||
int perf_mode;
|
||||
struct snd_pcm *pcm;
|
||||
struct msm_pcm_ch_map *ch_map[MSM_FRONTEND_DAI_MAX];
|
||||
};
|
||||
|
||||
struct msm_pcm_ch_map {
|
||||
bool set_ch_map;
|
||||
char channel_map[PCM_FORMAT_MAX_NUM_CHANNEL];
|
||||
};
|
||||
|
||||
#endif /*_MSM_PCM_H*/
|
||||
|
|
25
dsp/q6asm.c
25
dsp/q6asm.c
|
@ -3937,11 +3937,13 @@ int q6asm_set_shared_pos_buff(struct audio_client *ac,
|
|||
* parameters
|
||||
* config - session parameters (channels, bits_per_sample, sr)
|
||||
* dir - stream direction (IN for playback, OUT for capture)
|
||||
* use_default_chmap: true if default channel map to be used
|
||||
* channel_map: input channel map
|
||||
* returns 0 if successful, error code otherwise
|
||||
*/
|
||||
int q6asm_open_shared_io(struct audio_client *ac,
|
||||
struct shared_io_config *config,
|
||||
int dir)
|
||||
int dir, bool use_default_chmap, u8 *channel_map)
|
||||
{
|
||||
struct asm_stream_cmd_open_shared_io *open;
|
||||
u8 *channel_mapping;
|
||||
|
@ -3951,6 +3953,12 @@ int q6asm_open_shared_io(struct audio_client *ac,
|
|||
if (!ac || !config)
|
||||
return -EINVAL;
|
||||
|
||||
if (!use_default_chmap && (channel_map == NULL)) {
|
||||
pr_err("%s: No valid chan map and can't use default\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bufsz = config->bufsz;
|
||||
bufcnt = config->bufcnt;
|
||||
num_watermarks = 0;
|
||||
|
@ -4047,10 +4055,17 @@ int q6asm_open_shared_io(struct audio_client *ac,
|
|||
|
||||
memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
|
||||
|
||||
rc = q6asm_map_channels(channel_mapping, config->channels, false);
|
||||
if (rc) {
|
||||
pr_err("%s: Map channels failed, ret: %d\n", __func__, rc);
|
||||
goto done;
|
||||
if (use_default_chmap) {
|
||||
rc = q6asm_map_channels(channel_mapping, config->channels,
|
||||
false);
|
||||
if (rc) {
|
||||
pr_err("%s: Map channels failed, ret: %d\n",
|
||||
__func__, rc);
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
memcpy(channel_mapping, channel_map,
|
||||
PCM_FORMAT_MAX_NUM_CHANNEL);
|
||||
}
|
||||
|
||||
open->num_watermark_levels = num_watermarks;
|
||||
|
|
|
@ -303,7 +303,8 @@ int q6asm_open_write_v2(struct audio_client *ac, uint32_t format,
|
|||
uint16_t bits_per_sample);
|
||||
|
||||
int q6asm_open_shared_io(struct audio_client *ac,
|
||||
struct shared_io_config *c, int dir);
|
||||
struct shared_io_config *c, int dir,
|
||||
bool use_default_chmap, u8 *channel_map);
|
||||
|
||||
int q6asm_open_write_v3(struct audio_client *ac, uint32_t format,
|
||||
uint16_t bits_per_sample);
|
||||
|
|
Loading…
Add table
Reference in a new issue