Loading sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +215 −4 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ struct snd_msm { #define CMD_EOS_MIN_TIMEOUT_LENGTH 50 #define CMD_EOS_TIMEOUT_MULTIPLIER (HZ * 50) #define MAX_PB_COPY_RETRIES 3 #define MAX_PCM_STREAMS 2 static struct snd_pcm_hardware msm_pcm_hardware_capture = { .info = (SNDRV_PCM_INFO_MMAP | Loading Loading @@ -117,6 +118,17 @@ static struct snd_pcm_hw_constraint_list constraints_sample_rates = { .mask = 0, }; static unsigned long msm_pcm_fe_topology[MSM_FRONTEND_DAI_MAX][MAX_PCM_STREAMS]; /* 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 msm_pcm_route_event_handler(enum msm_pcm_routing_event event, void *priv_data) { Loading Loading @@ -305,8 +317,8 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream) if (prtd->enabled) return 0; prtd->audio_client->perf_mode = pdata->perf_mode; pr_debug("%s: perf: %x\n", __func__, pdata->perf_mode); prtd->audio_client->perf_mode = pdata->perf_mode_set; pr_debug("%s: perf: %x\n", __func__, prtd->audio_client->perf_mode); switch (params_format(params)) { case SNDRV_PCM_FORMAT_S24_LE: Loading Loading @@ -393,14 +405,14 @@ static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream) if (prtd->enabled == IDLE) { pr_debug("%s:perf_mode=%d periods=%d\n", __func__, pdata->perf_mode, runtime->periods); pdata->perf_mode_set, runtime->periods); params = &soc_prtd->dpcm[substream->stream].hw_params; if ((params_format(params) == SNDRV_PCM_FORMAT_S24_LE) || (params_format(params) == SNDRV_PCM_FORMAT_S24_3LE)) bits_per_sample = 24; /* ULL mode is not supported in capture path */ if (pdata->perf_mode == LEGACY_PCM_MODE) if (pdata->perf_mode_set == LEGACY_PCM_MODE) prtd->audio_client->perf_mode = LEGACY_PCM_MODE; else prtd->audio_client->perf_mode = LOW_LATENCY_PCM_MODE; Loading Loading @@ -939,15 +951,41 @@ static int msm_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *soc_prtd = substream->private_data; struct msm_audio *prtd = runtime->private_data; struct msm_plat_data *pdata; struct snd_dma_buffer *dma_buf = &substream->dma_buffer; struct audio_buffer *buf; int dir, ret; unsigned long fe_id = soc_prtd->dai_link->be_id; unsigned long topology; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) dir = IN; else dir = OUT; pdata = (struct msm_plat_data *) dev_get_drvdata(soc_prtd->platform->dev); if (!pdata) { ret = -EINVAL; pr_err("%s: platform data not populated ret: %d\n", __func__, ret); return ret; } topology = msm_pcm_fe_topology[fe_id][substream->stream]; if (!strcmp(msm_pcm_fe_topology_text[topology], "ULL_PP")) pdata->perf_mode_set = ULL_POST_PROCESSING_PCM_MODE; else if (!strcmp(msm_pcm_fe_topology_text[topology], "ULL")) pdata->perf_mode_set = ULTRA_LOW_LATENCY_PCM_MODE; else if (!strcmp(msm_pcm_fe_topology_text[topology], "LL")) pdata->perf_mode_set = LOW_LATENCY_PCM_MODE; else /* use the default from the device tree */ pdata->perf_mode_set = pdata->perf_mode; ret = q6asm_audio_client_buf_alloc_contiguous(dir, prtd->audio_client, (params_buffer_bytes(params) / params_periods(params)), Loading Loading @@ -1162,6 +1200,173 @@ static int msm_pcm_add_chmap_controls(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_playback_topology_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { unsigned long fe_id = kcontrol->private_value; unsigned long topology; if (fe_id >= MSM_FRONTEND_DAI_MAX) { pr_err("%s Received out of bound fe_id %lu\n", __func__, fe_id); return -EINVAL; } topology = msm_pcm_fe_topology[fe_id][SNDRV_PCM_STREAM_PLAYBACK]; pr_debug("%s: %lu topology %s\n", __func__, fe_id, msm_pcm_fe_topology_text[topology]); ucontrol->value.enumerated.item[0] = topology; return 0; } static int msm_pcm_fe_playback_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][SNDRV_PCM_STREAM_PLAYBACK] = item; return 0; } static int msm_pcm_fe_capture_topology_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { unsigned long fe_id = kcontrol->private_value; unsigned long topology; if (fe_id >= MSM_FRONTEND_DAI_MAX) { pr_err("%s Received out of bound fe_id %lu\n", __func__, fe_id); return -EINVAL; } topology = msm_pcm_fe_topology[fe_id][SNDRV_PCM_STREAM_CAPTURE]; pr_debug("%s: %lu topology %s\n", __func__, fe_id, msm_pcm_fe_topology_text[topology]); ucontrol->value.enumerated.item[0] = topology; return 0; } static int msm_pcm_fe_capture_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][SNDRV_PCM_STREAM_CAPTURE] = item; return 0; } static int msm_pcm_add_fe_topology_control(struct snd_soc_pcm_runtime *rtd) { struct snd_pcm *pcm = rtd->pcm->streams[0].pcm; const char *mixer_ctl_name = "PCM_Dev"; const char *deviceNo = "NN"; const char *topo_playback = "Topology Playback"; const char *topo_capture = "Topology Capture"; char *mixer_str = NULL, *mixer_str1 = NULL; int ctl_len, ret; unsigned long fe_id = rtd->dai_link->be_id; struct snd_kcontrol_new topology_control[2] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .name = "?", .info = msm_pcm_fe_topology_info, .get = msm_pcm_fe_playback_topology_get, .put = msm_pcm_fe_playback_topology_put, .private_value = 0, }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .name = "?", .info = msm_pcm_fe_topology_info, .get = msm_pcm_fe_capture_topology_get, .put = msm_pcm_fe_capture_topology_put, .private_value = 0, }, }; if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1 + strlen(topo_playback) + 1; mixer_str = kzalloc(ctl_len, GFP_KERNEL); if (!mixer_str) { ret = -ENOMEM; goto err1; } snprintf(mixer_str, ctl_len, "%s %d %s", mixer_ctl_name, rtd->pcm->device, topo_playback); topology_control[0].name = mixer_str; topology_control[0].private_value = fe_id; } if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1 + strlen(topo_capture) + 1; mixer_str1 = kzalloc(ctl_len, GFP_KERNEL); if (!mixer_str1) { ret = -ENOMEM; goto err; } snprintf(mixer_str1, ctl_len, "%s %d %s", mixer_ctl_name, rtd->pcm->device, topo_capture); topology_control[1].name = mixer_str1; topology_control[1].private_value = fe_id; } ret = snd_soc_add_platform_controls(rtd->platform, topology_control, ARRAY_SIZE(topology_control)); msm_pcm_fe_topology[fe_id][SNDRV_PCM_STREAM_PLAYBACK] = 0; msm_pcm_fe_topology[fe_id][SNDRV_PCM_STREAM_CAPTURE] = 0; kfree(mixer_str1); err: kfree(mixer_str); err1: return ret; } static int msm_pcm_playback_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { Loading Loading @@ -1349,6 +1554,12 @@ static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd) if (ret) pr_err("%s: pcm add app type controls failed:%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); } return ret; } Loading sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h +2 −1 Original line number Diff line number Diff line /* * Copyright (C) 2008 Google, Inc. * Copyright (C) 2008 HTC Corporation * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and Loading Loading @@ -123,6 +123,7 @@ struct output_meta_data_st { struct msm_plat_data { int perf_mode; int perf_mode_set; }; #endif /*_MSM_PCM_H*/ Loading
sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +215 −4 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ struct snd_msm { #define CMD_EOS_MIN_TIMEOUT_LENGTH 50 #define CMD_EOS_TIMEOUT_MULTIPLIER (HZ * 50) #define MAX_PB_COPY_RETRIES 3 #define MAX_PCM_STREAMS 2 static struct snd_pcm_hardware msm_pcm_hardware_capture = { .info = (SNDRV_PCM_INFO_MMAP | Loading Loading @@ -117,6 +118,17 @@ static struct snd_pcm_hw_constraint_list constraints_sample_rates = { .mask = 0, }; static unsigned long msm_pcm_fe_topology[MSM_FRONTEND_DAI_MAX][MAX_PCM_STREAMS]; /* 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 msm_pcm_route_event_handler(enum msm_pcm_routing_event event, void *priv_data) { Loading Loading @@ -305,8 +317,8 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream) if (prtd->enabled) return 0; prtd->audio_client->perf_mode = pdata->perf_mode; pr_debug("%s: perf: %x\n", __func__, pdata->perf_mode); prtd->audio_client->perf_mode = pdata->perf_mode_set; pr_debug("%s: perf: %x\n", __func__, prtd->audio_client->perf_mode); switch (params_format(params)) { case SNDRV_PCM_FORMAT_S24_LE: Loading Loading @@ -393,14 +405,14 @@ static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream) if (prtd->enabled == IDLE) { pr_debug("%s:perf_mode=%d periods=%d\n", __func__, pdata->perf_mode, runtime->periods); pdata->perf_mode_set, runtime->periods); params = &soc_prtd->dpcm[substream->stream].hw_params; if ((params_format(params) == SNDRV_PCM_FORMAT_S24_LE) || (params_format(params) == SNDRV_PCM_FORMAT_S24_3LE)) bits_per_sample = 24; /* ULL mode is not supported in capture path */ if (pdata->perf_mode == LEGACY_PCM_MODE) if (pdata->perf_mode_set == LEGACY_PCM_MODE) prtd->audio_client->perf_mode = LEGACY_PCM_MODE; else prtd->audio_client->perf_mode = LOW_LATENCY_PCM_MODE; Loading Loading @@ -939,15 +951,41 @@ static int msm_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *soc_prtd = substream->private_data; struct msm_audio *prtd = runtime->private_data; struct msm_plat_data *pdata; struct snd_dma_buffer *dma_buf = &substream->dma_buffer; struct audio_buffer *buf; int dir, ret; unsigned long fe_id = soc_prtd->dai_link->be_id; unsigned long topology; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) dir = IN; else dir = OUT; pdata = (struct msm_plat_data *) dev_get_drvdata(soc_prtd->platform->dev); if (!pdata) { ret = -EINVAL; pr_err("%s: platform data not populated ret: %d\n", __func__, ret); return ret; } topology = msm_pcm_fe_topology[fe_id][substream->stream]; if (!strcmp(msm_pcm_fe_topology_text[topology], "ULL_PP")) pdata->perf_mode_set = ULL_POST_PROCESSING_PCM_MODE; else if (!strcmp(msm_pcm_fe_topology_text[topology], "ULL")) pdata->perf_mode_set = ULTRA_LOW_LATENCY_PCM_MODE; else if (!strcmp(msm_pcm_fe_topology_text[topology], "LL")) pdata->perf_mode_set = LOW_LATENCY_PCM_MODE; else /* use the default from the device tree */ pdata->perf_mode_set = pdata->perf_mode; ret = q6asm_audio_client_buf_alloc_contiguous(dir, prtd->audio_client, (params_buffer_bytes(params) / params_periods(params)), Loading Loading @@ -1162,6 +1200,173 @@ static int msm_pcm_add_chmap_controls(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_playback_topology_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { unsigned long fe_id = kcontrol->private_value; unsigned long topology; if (fe_id >= MSM_FRONTEND_DAI_MAX) { pr_err("%s Received out of bound fe_id %lu\n", __func__, fe_id); return -EINVAL; } topology = msm_pcm_fe_topology[fe_id][SNDRV_PCM_STREAM_PLAYBACK]; pr_debug("%s: %lu topology %s\n", __func__, fe_id, msm_pcm_fe_topology_text[topology]); ucontrol->value.enumerated.item[0] = topology; return 0; } static int msm_pcm_fe_playback_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][SNDRV_PCM_STREAM_PLAYBACK] = item; return 0; } static int msm_pcm_fe_capture_topology_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { unsigned long fe_id = kcontrol->private_value; unsigned long topology; if (fe_id >= MSM_FRONTEND_DAI_MAX) { pr_err("%s Received out of bound fe_id %lu\n", __func__, fe_id); return -EINVAL; } topology = msm_pcm_fe_topology[fe_id][SNDRV_PCM_STREAM_CAPTURE]; pr_debug("%s: %lu topology %s\n", __func__, fe_id, msm_pcm_fe_topology_text[topology]); ucontrol->value.enumerated.item[0] = topology; return 0; } static int msm_pcm_fe_capture_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][SNDRV_PCM_STREAM_CAPTURE] = item; return 0; } static int msm_pcm_add_fe_topology_control(struct snd_soc_pcm_runtime *rtd) { struct snd_pcm *pcm = rtd->pcm->streams[0].pcm; const char *mixer_ctl_name = "PCM_Dev"; const char *deviceNo = "NN"; const char *topo_playback = "Topology Playback"; const char *topo_capture = "Topology Capture"; char *mixer_str = NULL, *mixer_str1 = NULL; int ctl_len, ret; unsigned long fe_id = rtd->dai_link->be_id; struct snd_kcontrol_new topology_control[2] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .name = "?", .info = msm_pcm_fe_topology_info, .get = msm_pcm_fe_playback_topology_get, .put = msm_pcm_fe_playback_topology_put, .private_value = 0, }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .name = "?", .info = msm_pcm_fe_topology_info, .get = msm_pcm_fe_capture_topology_get, .put = msm_pcm_fe_capture_topology_put, .private_value = 0, }, }; if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1 + strlen(topo_playback) + 1; mixer_str = kzalloc(ctl_len, GFP_KERNEL); if (!mixer_str) { ret = -ENOMEM; goto err1; } snprintf(mixer_str, ctl_len, "%s %d %s", mixer_ctl_name, rtd->pcm->device, topo_playback); topology_control[0].name = mixer_str; topology_control[0].private_value = fe_id; } if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1 + strlen(topo_capture) + 1; mixer_str1 = kzalloc(ctl_len, GFP_KERNEL); if (!mixer_str1) { ret = -ENOMEM; goto err; } snprintf(mixer_str1, ctl_len, "%s %d %s", mixer_ctl_name, rtd->pcm->device, topo_capture); topology_control[1].name = mixer_str1; topology_control[1].private_value = fe_id; } ret = snd_soc_add_platform_controls(rtd->platform, topology_control, ARRAY_SIZE(topology_control)); msm_pcm_fe_topology[fe_id][SNDRV_PCM_STREAM_PLAYBACK] = 0; msm_pcm_fe_topology[fe_id][SNDRV_PCM_STREAM_CAPTURE] = 0; kfree(mixer_str1); err: kfree(mixer_str); err1: return ret; } static int msm_pcm_playback_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { Loading Loading @@ -1349,6 +1554,12 @@ static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd) if (ret) pr_err("%s: pcm add app type controls failed:%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); } return ret; } Loading
sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h +2 −1 Original line number Diff line number Diff line /* * Copyright (C) 2008 Google, Inc. * Copyright (C) 2008 HTC Corporation * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and Loading Loading @@ -123,6 +123,7 @@ struct output_meta_data_st { struct msm_plat_data { int perf_mode; int perf_mode_set; }; #endif /*_MSM_PCM_H*/