Loading asoc/msm-compress-q6-v2.c +119 −0 Original line number Diff line number Diff line Loading @@ -3894,6 +3894,16 @@ static int msm_compr_probe(struct snd_soc_platform *platform) return 0; } static int msm_compr_chmix_cfg_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 128; uinfo->value.integer.min = 0; uinfo->value.integer.max = 0xFFFFFFFF; return 0; } static int msm_compr_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { Loading Loading @@ -4317,6 +4327,112 @@ static int msm_compr_add_app_type_cfg_control(struct snd_soc_pcm_runtime *rtd) return 0; } static int msm_compr_chmix_cfg_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); struct msm_compr_pdata *pdata = (struct msm_compr_pdata *) snd_soc_component_get_drvdata(comp); struct snd_compr_stream *cstream = NULL; struct snd_soc_pcm_runtime *rtd = NULL; u64 fe_id = kcontrol->private_value; int ip_channel_cnt, op_channel_cnt; int i, index = 0; int ch_coeff[PCM_FORMAT_MAX_NUM_CHANNEL * PCM_FORMAT_MAX_NUM_CHANNEL]; bool use_default_chmap = true; char *chmap = NULL; 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); return -EINVAL; } cstream = pdata->cstream[fe_id]; if (!cstream) { pr_err("%s: stream inactive\n", __func__); return -EINVAL; } rtd = cstream->private_data; if (!rtd) { pr_err("%s: stream inactive\n", __func__); return -EINVAL; } use_default_chmap = !(pdata->ch_map[rtd->dai_link->id]->set_ch_map); chmap = pdata->ch_map[rtd->dai_link->id]->channel_map; ip_channel_cnt = ucontrol->value.integer.value[index++]; op_channel_cnt = ucontrol->value.integer.value[index++]; /* * wght coeff of first out channel corresponding to each in channel * are sent followed by second out channel for each in channel etc. */ memset(ch_coeff, 0, sizeof(ch_coeff)); for (i = 0; i < op_channel_cnt * ip_channel_cnt; i++) { ch_coeff[i] = ucontrol->value.integer.value[index++]; } msm_pcm_routing_send_chmix_cfg(fe_id, ip_channel_cnt, op_channel_cnt, ch_coeff, SESSION_TYPE_RX, use_default_chmap, chmap); return 0; } static int msm_compr_chmix_cfg_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { return 0; } static int msm_compr_add_chmix_cfg_controls(struct snd_soc_pcm_runtime *rtd) { const char *mixer_ctl_name = "Audio Stream"; const char *deviceNo = "NN"; const char *suffix = "Channel Mix Cfg"; int ctl_len; char *mixer_str = NULL; struct snd_kcontrol_new chmix_cfg_controls[1] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "?", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .info = msm_compr_chmix_cfg_ctl_info, .get = msm_compr_chmix_cfg_ctl_get, .put = msm_compr_chmix_cfg_ctl_put, .private_value = 0, } }; if (!rtd) { pr_err("%s NULL rtd\n", __func__); return -EINVAL; } pr_debug("%s: added new compr 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) + 1 + strlen(deviceNo) + 1 + strlen(suffix) + 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, suffix); chmix_cfg_controls[0].name = mixer_str; chmix_cfg_controls[0].private_value = rtd->dai_link->id; pr_debug("%s: Registering new mixer ctl %s", __func__, mixer_str); snd_soc_add_platform_controls(rtd->platform, chmix_cfg_controls, ARRAY_SIZE(chmix_cfg_controls)); kfree(mixer_str); return 0; } static int msm_compr_add_channel_map_control(struct snd_soc_pcm_runtime *rtd) { const char *mixer_ctl_name = "Playback Channel Map"; Loading Loading @@ -4513,6 +4629,9 @@ static int msm_compr_new(struct snd_soc_pcm_runtime *rtd) if (rc) pr_err("%s: Could not add Compr Channel Map Control\n", __func__); rc = msm_compr_add_chmix_cfg_controls(rtd); if (rc) pr_err("%s: add chmix cfg controls failed:%d\n", __func__, rc); return 0; } Loading asoc/msm-pcm-q6-v2.c +147 −0 Original line number Diff line number Diff line Loading @@ -1753,6 +1753,150 @@ static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd) return 0; } static int msm_pcm_chmix_cfg_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 128; uinfo->value.integer.min = 0; uinfo->value.integer.max = 0xFFFFFFFF; return 0; } static int msm_pcm_chmix_cfg_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *usr_info = snd_kcontrol_chip(kcontrol); struct snd_soc_platform *platform; struct msm_plat_data *pdata; struct snd_pcm_substream *substream; struct msm_audio *prtd; u64 fe_id = kcontrol->private_value; int ip_channel_cnt, op_channel_cnt; int i, index = 0, ret = 0; int ch_coeff[PCM_FORMAT_MAX_NUM_CHANNEL * PCM_FORMAT_MAX_NUM_CHANNEL]; bool use_default_chmap = true; char *ch_map = NULL; 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); ret = -EINVAL; goto done; } if (!usr_info) { pr_err("%s: usr_info is null\n", __func__); ret = -EINVAL; goto done; } platform = snd_soc_component_to_platform(usr_info); if (!platform) { pr_err("%s: platform is null\n", __func__); ret = -EINVAL; goto done; } pdata = dev_get_drvdata(platform->dev); if (!pdata) { pr_err("%s: pdata is null\n", __func__); ret = -EINVAL; goto done; } substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; if (!substream) { pr_err("%s substream not found\n", __func__); return -ENODEV; } if (!substream->runtime) { pr_err("%s substream runtime not found\n", __func__); ret = -EINVAL; goto done; } prtd = substream->runtime->private_data; if (!prtd) { pr_err("%s: stream inactive\n", __func__); ret = -EINVAL; goto done; } use_default_chmap = !prtd->set_channel_map; ch_map = prtd->channel_map; ip_channel_cnt = ucontrol->value.integer.value[index++]; op_channel_cnt = ucontrol->value.integer.value[index++]; /* * wght coeff of first out channel corresponding to each in channel * are sent followed by second out channel for each in channel etc. */ memset(ch_coeff, 0, sizeof(ch_coeff)); for (i = 0; i < op_channel_cnt * ip_channel_cnt; i++) { ch_coeff[i] = ucontrol->value.integer.value[index++]; } msm_pcm_routing_send_chmix_cfg(fe_id, ip_channel_cnt, op_channel_cnt, ch_coeff, SESSION_TYPE_RX, use_default_chmap, ch_map); done: return ret; } static int msm_pcm_chmix_cfg_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { return 0; } static int msm_pcm_add_chmix_cfg_controls(struct snd_soc_pcm_runtime *rtd) { const char *mixer_ctl_name = "Audio Stream"; const char *deviceNo = "NN"; const char *suffix = "Channel Mix Cfg"; char *mixer_str = NULL; int ctl_len = 0; struct msm_plat_data *pdata; struct snd_kcontrol_new chmix_cfg_controls[1] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "?", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .info = msm_pcm_chmix_cfg_ctl_info, .get = msm_pcm_chmix_cfg_ctl_get, .put = msm_pcm_chmix_cfg_ctl_put, .private_value = 0, } }; if (!rtd) { pr_err("%s: NULL rtd\n", __func__); return -EINVAL; } ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1 + strlen(suffix) + 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, suffix); chmix_cfg_controls[0].name = mixer_str; chmix_cfg_controls[0].private_value = rtd->dai_link->id; pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str); pdata = dev_get_drvdata(rtd->platform->dev); if (pdata) { if (!pdata->pcm) pdata->pcm = rtd->pcm; snd_soc_add_platform_controls(rtd->platform, chmix_cfg_controls, ARRAY_SIZE(chmix_cfg_controls)); } else { pr_err("%s: NULL pdata\n", __func__); return -EINVAL; } kfree(mixer_str); return 0; } static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd) { int ret = 0; Loading @@ -1765,6 +1909,9 @@ 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_chmix_cfg_controls(rtd); if (ret) pr_err("%s: add chmix cfg controls failed:%d\n", __func__, ret); return ret; } Loading asoc/msm-pcm-routing-v2.c +77 −1 Original line number Diff line number Diff line Loading @@ -792,6 +792,79 @@ static bool is_mm_lsm_fe_id(int fe_id) return rc; } /* * msm_pcm_routing_send_chmix_cfg * * Receives fe_id, ip_channel_cnt, op_channel_cnt, channel weight, session_type * use_default_chmap and channel map to map in channel mixer and send to * adm programmable matrix. * * fe_id - Passed value, frontend id which is wanted * ip_channel_cnt - Passed value, number of input channels * op_channel_cnt - Passed value, number of output channels * ch_wght_coeff - Passed reference, weights for each output channel * session_type - Passed value, session_type for RX or TX * use_default_chmap - true if default channel map to be used * ch_map - input/output channel map for playback/capture session respectively */ int msm_pcm_routing_send_chmix_cfg(int fe_id, int ip_channel_cnt, int op_channel_cnt, int *ch_wght_coeff, int session_type, bool use_default_chmap, char *channel_map) { int rc = 0, idx = 0, i, j; int be_index = 0, port_id, index = 0; unsigned int session_id = 0; pr_debug("%s: fe_id[%d] ip_ch[%d] op_ch[%d] sess_type [%d]\n", __func__, fe_id, ip_channel_cnt, op_channel_cnt, session_type); if (!use_default_chmap && (channel_map == NULL)) { pr_err("%s: No valid chan map and can't use default\n", __func__); return -EINVAL; } if ((ch_wght_coeff == NULL) || (op_channel_cnt > ADM_MAX_CHANNELS) || (ip_channel_cnt > ADM_MAX_CHANNELS)) { pr_err("%s: Invalid channels or null coefficients\n", __func__); return -EINVAL; } for (be_index = 0; be_index < MSM_BACKEND_DAI_MAX; be_index++) { port_id = msm_bedais[be_index].port_id; if (!msm_bedais[be_index].active || !test_bit(fe_id, &msm_bedais[be_index].fe_sessions[0])) continue; session_id = fe_dai_map[fe_id][session_type].strm_id; channel_mixer[fe_id].input_channels[0] = ip_channel_cnt; channel_mixer[fe_id].output_channel = op_channel_cnt; channel_mixer[fe_id].rule = 0; for (j = 0; j < op_channel_cnt; j++) { for (i = 0; i < ip_channel_cnt; i++) channel_mixer[fe_id].channel_weight[j][i] = ch_wght_coeff[index++]; } for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) { unsigned long copp = session_copp_map[fe_id][session_type][be_index]; if (!test_bit(idx, &copp)) continue; rc = adm_programable_channel_mixer(port_id, idx, session_id, session_type, channel_mixer + fe_id, 0, use_default_chmap, channel_map); if (rc < 0) pr_err("%s: err setting channel mix config\n", __func__); } } return 0; } int msm_pcm_routing_reg_stream_app_type_cfg( int fedai_id, int session_type, int be_id, struct msm_pcm_stream_app_type_cfg *cfg_data) Loading Loading @@ -1326,6 +1399,8 @@ static int msm_pcm_routing_channel_mixer(int fe_id, bool perf_mode, int sess_type = 0; int i = 0, j = 0, be_id; int ret = 0; bool use_default_chmap = true; char *ch_map = NULL; if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) { pr_err("%s: invalid FE %d\n", __func__, fe_id); Loading Loading @@ -1368,7 +1443,8 @@ static int msm_pcm_routing_channel_mixer(int fe_id, bool perf_mode, ret = adm_programable_channel_mixer( msm_bedais[be_id].port_id, copp_idx, dspst_id, sess_type, channel_mixer + fe_id, i); channel_mixer + fe_id, i, use_default_chmap, ch_map); } } Loading asoc/msm-pcm-routing-v2.h +4 −0 Original line number Diff line number Diff line Loading @@ -525,4 +525,8 @@ int msm_pcm_routing_reg_stream_app_type_cfg( int msm_pcm_routing_get_stream_app_type_cfg( int fedai_id, int session_type, int *be_id, struct msm_pcm_stream_app_type_cfg *cfg_data); int msm_pcm_routing_send_chmix_cfg(int fe_id, int ip_channel_cnt, int op_channel_cnt, int *ch_wght_coeff, int session_type, bool use_default_chmap, char *channel_map); #endif /*_MSM_PCM_H*/ dsp/q6adm.c +94 −81 Original line number Diff line number Diff line Loading @@ -635,18 +635,21 @@ static int adm_populate_channel_weight(u16 *ptr, * session_type - Passed value, session_type for RX or TX * ch_mixer - Passed value, ch_mixer for which channel mixer config is needed * channel_index - Passed value, channel_index for which channel is needed * use_default_chmap - true if default channel map to be used * ch_map - input/output channel map for playback/capture session respectively */ int adm_programable_channel_mixer(int port_id, int copp_idx, int session_id, int session_type, struct msm_pcm_channel_mixer *ch_mixer, int channel_index) int channel_index, bool use_default_chmap, char *ch_map) { struct adm_cmd_set_pspd_mtmx_strtr_params_v5 *adm_params = NULL; struct adm_param_data_v5 data_v5; int ret = 0, port_idx, sz = 0, param_size = 0; u16 *adm_pspd_params; u16 *ptr; int index = 0; int index = 0, i; pr_debug("%s: port_id = %d\n", __func__, port_id); port_id = afe_convert_virtual_to_portid(port_id); Loading @@ -671,7 +674,8 @@ int adm_programable_channel_mixer(int port_id, int copp_idx, int session_id, ch_mixer->input_channels[channel_index] + ch_mixer->input_channels[channel_index] * ch_mixer->output_channel); roundup(param_size, 4); /* Params size should be multiple of 4 bytes i.e 32bit aligned */ param_size = round_up(param_size, 4); sz = sizeof(struct adm_cmd_set_pspd_mtmx_strtr_params_v5) + sizeof(struct default_chmixer_param_id_coeff) + Loading Loading @@ -713,6 +717,10 @@ int adm_programable_channel_mixer(int port_id, int copp_idx, int session_id, adm_pspd_params[3] = ch_mixer->input_channels[channel_index]; index = 4; if ((session_type == SESSION_TYPE_TX) && !use_default_chmap && ch_map) { for (i = 0; i < ch_mixer->output_channel; i++) adm_pspd_params[index++] = ch_map[i]; } else { if (ch_mixer->output_channel == 1) { adm_pspd_params[index] = PCM_CHANNEL_FC; } else if (ch_mixer->output_channel == 2) { Loading Loading @@ -750,8 +758,13 @@ int adm_programable_channel_mixer(int port_id, int copp_idx, int session_id, adm_pspd_params[index + 6] = PCM_CHANNEL_LB; adm_pspd_params[index + 7] = PCM_CHANNEL_RB; } index = index + ch_mixer->output_channel; } if ((session_type == SESSION_TYPE_RX) && !use_default_chmap && ch_map) { for (i = 0; i < ch_mixer->input_channels[channel_index]; i++) adm_pspd_params[index++] = ch_map[i]; } else { if (ch_mixer->input_channels[channel_index] == 1) { adm_pspd_params[index] = PCM_CHANNEL_FC; } else if (ch_mixer->input_channels[channel_index] == 2) { Loading Loading @@ -789,8 +802,8 @@ int adm_programable_channel_mixer(int port_id, int copp_idx, int session_id, adm_pspd_params[index + 6] = PCM_CHANNEL_LB; adm_pspd_params[index + 7] = PCM_CHANNEL_RB; } index = index + ch_mixer->input_channels[channel_index]; } ret = adm_populate_channel_weight(&adm_pspd_params[index], ch_mixer, channel_index); if (ret) { Loading Loading
asoc/msm-compress-q6-v2.c +119 −0 Original line number Diff line number Diff line Loading @@ -3894,6 +3894,16 @@ static int msm_compr_probe(struct snd_soc_platform *platform) return 0; } static int msm_compr_chmix_cfg_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 128; uinfo->value.integer.min = 0; uinfo->value.integer.max = 0xFFFFFFFF; return 0; } static int msm_compr_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { Loading Loading @@ -4317,6 +4327,112 @@ static int msm_compr_add_app_type_cfg_control(struct snd_soc_pcm_runtime *rtd) return 0; } static int msm_compr_chmix_cfg_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); struct msm_compr_pdata *pdata = (struct msm_compr_pdata *) snd_soc_component_get_drvdata(comp); struct snd_compr_stream *cstream = NULL; struct snd_soc_pcm_runtime *rtd = NULL; u64 fe_id = kcontrol->private_value; int ip_channel_cnt, op_channel_cnt; int i, index = 0; int ch_coeff[PCM_FORMAT_MAX_NUM_CHANNEL * PCM_FORMAT_MAX_NUM_CHANNEL]; bool use_default_chmap = true; char *chmap = NULL; 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); return -EINVAL; } cstream = pdata->cstream[fe_id]; if (!cstream) { pr_err("%s: stream inactive\n", __func__); return -EINVAL; } rtd = cstream->private_data; if (!rtd) { pr_err("%s: stream inactive\n", __func__); return -EINVAL; } use_default_chmap = !(pdata->ch_map[rtd->dai_link->id]->set_ch_map); chmap = pdata->ch_map[rtd->dai_link->id]->channel_map; ip_channel_cnt = ucontrol->value.integer.value[index++]; op_channel_cnt = ucontrol->value.integer.value[index++]; /* * wght coeff of first out channel corresponding to each in channel * are sent followed by second out channel for each in channel etc. */ memset(ch_coeff, 0, sizeof(ch_coeff)); for (i = 0; i < op_channel_cnt * ip_channel_cnt; i++) { ch_coeff[i] = ucontrol->value.integer.value[index++]; } msm_pcm_routing_send_chmix_cfg(fe_id, ip_channel_cnt, op_channel_cnt, ch_coeff, SESSION_TYPE_RX, use_default_chmap, chmap); return 0; } static int msm_compr_chmix_cfg_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { return 0; } static int msm_compr_add_chmix_cfg_controls(struct snd_soc_pcm_runtime *rtd) { const char *mixer_ctl_name = "Audio Stream"; const char *deviceNo = "NN"; const char *suffix = "Channel Mix Cfg"; int ctl_len; char *mixer_str = NULL; struct snd_kcontrol_new chmix_cfg_controls[1] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "?", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .info = msm_compr_chmix_cfg_ctl_info, .get = msm_compr_chmix_cfg_ctl_get, .put = msm_compr_chmix_cfg_ctl_put, .private_value = 0, } }; if (!rtd) { pr_err("%s NULL rtd\n", __func__); return -EINVAL; } pr_debug("%s: added new compr 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) + 1 + strlen(deviceNo) + 1 + strlen(suffix) + 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, suffix); chmix_cfg_controls[0].name = mixer_str; chmix_cfg_controls[0].private_value = rtd->dai_link->id; pr_debug("%s: Registering new mixer ctl %s", __func__, mixer_str); snd_soc_add_platform_controls(rtd->platform, chmix_cfg_controls, ARRAY_SIZE(chmix_cfg_controls)); kfree(mixer_str); return 0; } static int msm_compr_add_channel_map_control(struct snd_soc_pcm_runtime *rtd) { const char *mixer_ctl_name = "Playback Channel Map"; Loading Loading @@ -4513,6 +4629,9 @@ static int msm_compr_new(struct snd_soc_pcm_runtime *rtd) if (rc) pr_err("%s: Could not add Compr Channel Map Control\n", __func__); rc = msm_compr_add_chmix_cfg_controls(rtd); if (rc) pr_err("%s: add chmix cfg controls failed:%d\n", __func__, rc); return 0; } Loading
asoc/msm-pcm-q6-v2.c +147 −0 Original line number Diff line number Diff line Loading @@ -1753,6 +1753,150 @@ static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd) return 0; } static int msm_pcm_chmix_cfg_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 128; uinfo->value.integer.min = 0; uinfo->value.integer.max = 0xFFFFFFFF; return 0; } static int msm_pcm_chmix_cfg_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *usr_info = snd_kcontrol_chip(kcontrol); struct snd_soc_platform *platform; struct msm_plat_data *pdata; struct snd_pcm_substream *substream; struct msm_audio *prtd; u64 fe_id = kcontrol->private_value; int ip_channel_cnt, op_channel_cnt; int i, index = 0, ret = 0; int ch_coeff[PCM_FORMAT_MAX_NUM_CHANNEL * PCM_FORMAT_MAX_NUM_CHANNEL]; bool use_default_chmap = true; char *ch_map = NULL; 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); ret = -EINVAL; goto done; } if (!usr_info) { pr_err("%s: usr_info is null\n", __func__); ret = -EINVAL; goto done; } platform = snd_soc_component_to_platform(usr_info); if (!platform) { pr_err("%s: platform is null\n", __func__); ret = -EINVAL; goto done; } pdata = dev_get_drvdata(platform->dev); if (!pdata) { pr_err("%s: pdata is null\n", __func__); ret = -EINVAL; goto done; } substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; if (!substream) { pr_err("%s substream not found\n", __func__); return -ENODEV; } if (!substream->runtime) { pr_err("%s substream runtime not found\n", __func__); ret = -EINVAL; goto done; } prtd = substream->runtime->private_data; if (!prtd) { pr_err("%s: stream inactive\n", __func__); ret = -EINVAL; goto done; } use_default_chmap = !prtd->set_channel_map; ch_map = prtd->channel_map; ip_channel_cnt = ucontrol->value.integer.value[index++]; op_channel_cnt = ucontrol->value.integer.value[index++]; /* * wght coeff of first out channel corresponding to each in channel * are sent followed by second out channel for each in channel etc. */ memset(ch_coeff, 0, sizeof(ch_coeff)); for (i = 0; i < op_channel_cnt * ip_channel_cnt; i++) { ch_coeff[i] = ucontrol->value.integer.value[index++]; } msm_pcm_routing_send_chmix_cfg(fe_id, ip_channel_cnt, op_channel_cnt, ch_coeff, SESSION_TYPE_RX, use_default_chmap, ch_map); done: return ret; } static int msm_pcm_chmix_cfg_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { return 0; } static int msm_pcm_add_chmix_cfg_controls(struct snd_soc_pcm_runtime *rtd) { const char *mixer_ctl_name = "Audio Stream"; const char *deviceNo = "NN"; const char *suffix = "Channel Mix Cfg"; char *mixer_str = NULL; int ctl_len = 0; struct msm_plat_data *pdata; struct snd_kcontrol_new chmix_cfg_controls[1] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "?", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .info = msm_pcm_chmix_cfg_ctl_info, .get = msm_pcm_chmix_cfg_ctl_get, .put = msm_pcm_chmix_cfg_ctl_put, .private_value = 0, } }; if (!rtd) { pr_err("%s: NULL rtd\n", __func__); return -EINVAL; } ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1 + strlen(suffix) + 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, suffix); chmix_cfg_controls[0].name = mixer_str; chmix_cfg_controls[0].private_value = rtd->dai_link->id; pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str); pdata = dev_get_drvdata(rtd->platform->dev); if (pdata) { if (!pdata->pcm) pdata->pcm = rtd->pcm; snd_soc_add_platform_controls(rtd->platform, chmix_cfg_controls, ARRAY_SIZE(chmix_cfg_controls)); } else { pr_err("%s: NULL pdata\n", __func__); return -EINVAL; } kfree(mixer_str); return 0; } static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd) { int ret = 0; Loading @@ -1765,6 +1909,9 @@ 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_chmix_cfg_controls(rtd); if (ret) pr_err("%s: add chmix cfg controls failed:%d\n", __func__, ret); return ret; } Loading
asoc/msm-pcm-routing-v2.c +77 −1 Original line number Diff line number Diff line Loading @@ -792,6 +792,79 @@ static bool is_mm_lsm_fe_id(int fe_id) return rc; } /* * msm_pcm_routing_send_chmix_cfg * * Receives fe_id, ip_channel_cnt, op_channel_cnt, channel weight, session_type * use_default_chmap and channel map to map in channel mixer and send to * adm programmable matrix. * * fe_id - Passed value, frontend id which is wanted * ip_channel_cnt - Passed value, number of input channels * op_channel_cnt - Passed value, number of output channels * ch_wght_coeff - Passed reference, weights for each output channel * session_type - Passed value, session_type for RX or TX * use_default_chmap - true if default channel map to be used * ch_map - input/output channel map for playback/capture session respectively */ int msm_pcm_routing_send_chmix_cfg(int fe_id, int ip_channel_cnt, int op_channel_cnt, int *ch_wght_coeff, int session_type, bool use_default_chmap, char *channel_map) { int rc = 0, idx = 0, i, j; int be_index = 0, port_id, index = 0; unsigned int session_id = 0; pr_debug("%s: fe_id[%d] ip_ch[%d] op_ch[%d] sess_type [%d]\n", __func__, fe_id, ip_channel_cnt, op_channel_cnt, session_type); if (!use_default_chmap && (channel_map == NULL)) { pr_err("%s: No valid chan map and can't use default\n", __func__); return -EINVAL; } if ((ch_wght_coeff == NULL) || (op_channel_cnt > ADM_MAX_CHANNELS) || (ip_channel_cnt > ADM_MAX_CHANNELS)) { pr_err("%s: Invalid channels or null coefficients\n", __func__); return -EINVAL; } for (be_index = 0; be_index < MSM_BACKEND_DAI_MAX; be_index++) { port_id = msm_bedais[be_index].port_id; if (!msm_bedais[be_index].active || !test_bit(fe_id, &msm_bedais[be_index].fe_sessions[0])) continue; session_id = fe_dai_map[fe_id][session_type].strm_id; channel_mixer[fe_id].input_channels[0] = ip_channel_cnt; channel_mixer[fe_id].output_channel = op_channel_cnt; channel_mixer[fe_id].rule = 0; for (j = 0; j < op_channel_cnt; j++) { for (i = 0; i < ip_channel_cnt; i++) channel_mixer[fe_id].channel_weight[j][i] = ch_wght_coeff[index++]; } for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) { unsigned long copp = session_copp_map[fe_id][session_type][be_index]; if (!test_bit(idx, &copp)) continue; rc = adm_programable_channel_mixer(port_id, idx, session_id, session_type, channel_mixer + fe_id, 0, use_default_chmap, channel_map); if (rc < 0) pr_err("%s: err setting channel mix config\n", __func__); } } return 0; } int msm_pcm_routing_reg_stream_app_type_cfg( int fedai_id, int session_type, int be_id, struct msm_pcm_stream_app_type_cfg *cfg_data) Loading Loading @@ -1326,6 +1399,8 @@ static int msm_pcm_routing_channel_mixer(int fe_id, bool perf_mode, int sess_type = 0; int i = 0, j = 0, be_id; int ret = 0; bool use_default_chmap = true; char *ch_map = NULL; if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) { pr_err("%s: invalid FE %d\n", __func__, fe_id); Loading Loading @@ -1368,7 +1443,8 @@ static int msm_pcm_routing_channel_mixer(int fe_id, bool perf_mode, ret = adm_programable_channel_mixer( msm_bedais[be_id].port_id, copp_idx, dspst_id, sess_type, channel_mixer + fe_id, i); channel_mixer + fe_id, i, use_default_chmap, ch_map); } } Loading
asoc/msm-pcm-routing-v2.h +4 −0 Original line number Diff line number Diff line Loading @@ -525,4 +525,8 @@ int msm_pcm_routing_reg_stream_app_type_cfg( int msm_pcm_routing_get_stream_app_type_cfg( int fedai_id, int session_type, int *be_id, struct msm_pcm_stream_app_type_cfg *cfg_data); int msm_pcm_routing_send_chmix_cfg(int fe_id, int ip_channel_cnt, int op_channel_cnt, int *ch_wght_coeff, int session_type, bool use_default_chmap, char *channel_map); #endif /*_MSM_PCM_H*/
dsp/q6adm.c +94 −81 Original line number Diff line number Diff line Loading @@ -635,18 +635,21 @@ static int adm_populate_channel_weight(u16 *ptr, * session_type - Passed value, session_type for RX or TX * ch_mixer - Passed value, ch_mixer for which channel mixer config is needed * channel_index - Passed value, channel_index for which channel is needed * use_default_chmap - true if default channel map to be used * ch_map - input/output channel map for playback/capture session respectively */ int adm_programable_channel_mixer(int port_id, int copp_idx, int session_id, int session_type, struct msm_pcm_channel_mixer *ch_mixer, int channel_index) int channel_index, bool use_default_chmap, char *ch_map) { struct adm_cmd_set_pspd_mtmx_strtr_params_v5 *adm_params = NULL; struct adm_param_data_v5 data_v5; int ret = 0, port_idx, sz = 0, param_size = 0; u16 *adm_pspd_params; u16 *ptr; int index = 0; int index = 0, i; pr_debug("%s: port_id = %d\n", __func__, port_id); port_id = afe_convert_virtual_to_portid(port_id); Loading @@ -671,7 +674,8 @@ int adm_programable_channel_mixer(int port_id, int copp_idx, int session_id, ch_mixer->input_channels[channel_index] + ch_mixer->input_channels[channel_index] * ch_mixer->output_channel); roundup(param_size, 4); /* Params size should be multiple of 4 bytes i.e 32bit aligned */ param_size = round_up(param_size, 4); sz = sizeof(struct adm_cmd_set_pspd_mtmx_strtr_params_v5) + sizeof(struct default_chmixer_param_id_coeff) + Loading Loading @@ -713,6 +717,10 @@ int adm_programable_channel_mixer(int port_id, int copp_idx, int session_id, adm_pspd_params[3] = ch_mixer->input_channels[channel_index]; index = 4; if ((session_type == SESSION_TYPE_TX) && !use_default_chmap && ch_map) { for (i = 0; i < ch_mixer->output_channel; i++) adm_pspd_params[index++] = ch_map[i]; } else { if (ch_mixer->output_channel == 1) { adm_pspd_params[index] = PCM_CHANNEL_FC; } else if (ch_mixer->output_channel == 2) { Loading Loading @@ -750,8 +758,13 @@ int adm_programable_channel_mixer(int port_id, int copp_idx, int session_id, adm_pspd_params[index + 6] = PCM_CHANNEL_LB; adm_pspd_params[index + 7] = PCM_CHANNEL_RB; } index = index + ch_mixer->output_channel; } if ((session_type == SESSION_TYPE_RX) && !use_default_chmap && ch_map) { for (i = 0; i < ch_mixer->input_channels[channel_index]; i++) adm_pspd_params[index++] = ch_map[i]; } else { if (ch_mixer->input_channels[channel_index] == 1) { adm_pspd_params[index] = PCM_CHANNEL_FC; } else if (ch_mixer->input_channels[channel_index] == 2) { Loading Loading @@ -789,8 +802,8 @@ int adm_programable_channel_mixer(int port_id, int copp_idx, int session_id, adm_pspd_params[index + 6] = PCM_CHANNEL_LB; adm_pspd_params[index + 7] = PCM_CHANNEL_RB; } index = index + ch_mixer->input_channels[channel_index]; } ret = adm_populate_channel_weight(&adm_pspd_params[index], ch_mixer, channel_index); if (ret) { Loading