|
@@ -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] =
|
|
|
+ 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__);
|
|
|
}
|
|
|
- return 0;
|
|
|
+end:
|
|
|
+ pr_debug("%s: ret %d\n", __func__, rc);
|
|
|
+ return rc;
|
|
|
}
|
|
|
|
|
|
-static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
|
|
|
- struct snd_ctl_elem_value *ucontrol)
|
|
|
+static int msm_pcm_channel_map_info(struct snd_kcontrol *kcontrol,
|
|
|
+ struct snd_ctl_elem_info *uinfo)
|
|
|
{
|
|
|
- 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;
|
|
|
-
|
|
|
- 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 */
|
|
|
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
|
|
+ uinfo->count = 8;
|
|
|
+ uinfo->value.integer.min = 0;
|
|
|
+ uinfo->value.integer.max = 0xFFFFFFFF;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- prtd = substream->runtime->private_data;
|
|
|
+static int msm_pcm_channel_map_get(struct snd_kcontrol *kcontrol,
|
|
|
+ struct snd_ctl_elem_value *ucontrol)
|
|
|
+{
|
|
|
+ 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;
|
|
|
|
|
|
- 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;
|
|
|
-
|
|
|
- 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;
|
|
|
+ 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,
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ if (!rtd) {
|
|
|
+ pr_err("%s: NULL rtd\n", __func__);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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);
|
|
|
|
|
|
- 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;
|
|
|
+ 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;
|
|
|
}
|
|
|
|