diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h index 900d2455993a..e689e9357012 100644 --- a/include/sound/q6adm-v2.h +++ b/include/sound/q6adm-v2.h @@ -65,6 +65,20 @@ struct route_payload { unsigned int session_id; }; +struct default_chmixer_param_id_coeff { + uint32_t index; + uint16_t num_output_channels; + uint16_t num_input_channels; +}; + +struct msm_pcm_channel_mixer { + int output_channel; + int input_channels[ADM_MAX_CHANNELS]; + bool enable; + int rule; + int channel_weight[ADM_MAX_CHANNELS][ADM_MAX_CHANNELS]; +}; + int srs_trumedia_open(int port_id, int copp_idx, __s32 srs_tech_id, void *srs_params); @@ -166,4 +180,8 @@ int adm_get_source_tracking(int port_id, int copp_idx, struct source_tracking_param *sourceTrackingData); int adm_swap_speaker_channels(int port_id, int copp_idx, int sample_rate, bool spk_swap); +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); #endif /* __Q6_ADM_V2_H__ */ diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index f41c6107aac8..974d4a582540 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -81,6 +81,12 @@ static bool is_custom_stereo_on; static bool is_ds2_on; static bool swap_ch; +#define WEIGHT_0_DB 0x4000 +/* all the FEs which can support channel mixer */ +static struct msm_pcm_channel_mixer channel_mixer[MSM_FRONTEND_DAI_MM_SIZE]; +/* input BE for each FE */ +static int channel_input[MSM_FRONTEND_DAI_MM_SIZE][ADM_MAX_CHANNELS]; + enum { MADNONE, MADAUDIO, @@ -1257,6 +1263,62 @@ static u32 msm_pcm_routing_get_voc_sessionid(u16 val) return session_id; } +static int msm_pcm_routing_channel_mixer(int fe_id, bool perf_mode, + int dspst_id, int stream_type) +{ + int copp_idx = 0; + int sess_type = 0; + int i = 0, j = 0, be_id; + int ret = 0; + + if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) { + pr_err("%s: invalid FE %d\n", __func__, fe_id); + return 0; + } + + if (!(channel_mixer[fe_id].enable)) { + pr_debug("%s: channel mixer not enabled for FE %d\n", + __func__, fe_id); + return 0; + } + + if (stream_type == SNDRV_PCM_STREAM_PLAYBACK) + sess_type = SESSION_TYPE_RX; + else + sess_type = SESSION_TYPE_TX; + + for (i = 0; i < ADM_MAX_CHANNELS && channel_input[fe_id][i] > 0; + ++i) { + be_id = channel_input[fe_id][i] - 1; + channel_mixer[fe_id].input_channels[i] = + msm_bedais[be_id].channel; + + if ((msm_bedais[be_id].active) && + test_bit(fe_id, + &msm_bedais[be_id].fe_sessions[0])) { + unsigned long copp = + session_copp_map[fe_id][sess_type][be_id]; + for (j = 0; j < MAX_COPPS_PER_PORT; j++) { + if (test_bit(j, &copp)) { + copp_idx = j; + break; + } + } + + pr_debug("%s: fe %d, be %d, channel %d, copp %d\n", + __func__, + fe_id, be_id, msm_bedais[be_id].channel, + copp_idx); + ret = adm_programable_channel_mixer( + msm_bedais[be_id].port_id, + copp_idx, dspst_id, sess_type, + channel_mixer + fe_id, i); + } + } + + return ret; +} + int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode, int dspst_id, int stream_type) { @@ -1265,6 +1327,7 @@ int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode, u32 channels, sample_rate; uint16_t bits_per_sample = 16; uint32_t passthr_mode = LEGACY_PCM; + int ret = 0; if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) { /* bad ID assigned in machine driver */ @@ -1388,8 +1451,11 @@ int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode, adm_matrix_map(path_type, payload, perf_mode, passthr_mode); msm_pcm_routng_cfg_matrix_map_pp(payload, path_type, perf_mode); } + + ret = msm_pcm_routing_channel_mixer(fedai_id, perf_mode, + dspst_id, stream_type); mutex_unlock(&routing_lock); - return 0; + return ret; } int msm_pcm_routing_reg_phy_stream_v2(int fedai_id, int perf_mode, @@ -2614,6 +2680,649 @@ static int msm_routing_put_port_mixer(struct snd_kcontrol *kcontrol, return 1; } +static int msm_pcm_get_channel_rule_index(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u16 fe_id = 0; + + fe_id = ((struct soc_mixer_control *) + kcontrol->private_value)->shift; + if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) { + pr_err("%s: invalid FE %d\n", __func__, fe_id); + return -EINVAL; + } + + ucontrol->value.integer.value[0] = channel_mixer[fe_id].rule; + + return 0; +} + +static int msm_pcm_put_channel_rule_index(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u16 fe_id = 0; + + fe_id = ((struct soc_mixer_control *) + kcontrol->private_value)->shift; + if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) { + pr_err("%s: invalid FE %d\n", __func__, fe_id); + return -EINVAL; + } + + channel_mixer[fe_id].rule = ucontrol->value.integer.value[0]; + + return 1; +} + +static int msm_pcm_get_out_chs(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u16 fe_id = 0; + + fe_id = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) { + pr_err("%s: invalid FE %d\n", __func__, fe_id); + return -EINVAL; + } + + ucontrol->value.integer.value[0] = + channel_mixer[fe_id].output_channel; + return 0; +} + +static int msm_pcm_put_out_chs(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u16 fe_id = 0; + + fe_id = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) { + pr_err("%s: invalid FE %d\n", __func__, fe_id); + return -EINVAL; + } + + pr_debug("%s: fe_id is %d, output channels = %d\n", __func__, + fe_id, + (unsigned int)(ucontrol->value.integer.value[0])); + channel_mixer[fe_id].output_channel = + (unsigned int)(ucontrol->value.integer.value[0]); + + return 1; +} + +static const char *const ch_mixer[] = {"Disable", "Enable"}; + +/* If new backend is added, need update this array */ +static const char *const be_name[] = { +"ZERO", "PRI_I2S_RX", "PRI_I2S_TX", "SLIM_0_RX", +"SLIM_0_TX", "HDMI_RX", "INT_BT_SCO_RX", "INT_BT_SCO_TX", +"INT_FM_RX", "INT_FM_TX", "AFE_PCM_RX", "AFE_PCM_TX", +"AUXPCM_RX", "AUXPCM_TX", "VOICE_PLAYBACK_TX", "VOICE2_PLAYBACK_TX", +"INCALL_RECORD_RX", "INCALL_RECORD_TX", "MI2S_RX", "MI2S_TX", +"SEC_I2S_RX", "SLIM_1_RX", "SLIM_1_TX", "SLIM_2_RX", +"SLIM_2_TX", "SLIM_3_RX", "SLIM_3_TX", "SLIM_4_RX", +"SLIM_4_TX", "SLIM_5_RX", "SLIM_5_TX", "SLIM_6_RX", +"SLIM_6_TX", "SLIM_7_RX", "SLIM_7_TX", "SLIM_8_RX", +"SLIM_8_TX", "EXTPROC_RX", "EXTPROC_TX", "EXPROC_EC_TX", +"QUAT_MI2S_RX", "QUAT_MI2S_TX", "SECOND_MI2S_RX", "SECOND_MI2S_TX", +"PRI_MI2S_RX", "PRI_MI2S_TX", "TERT_MI2S_RX", "TERT_MI2S_TX", +"AUDIO_I2S_RX", "SEC_AUXPCM_RX", "SEC_AUXPCM_TX", "SPDIF_RX", +"SECOND_MI2S_RX_SD1", "QUIN_MI2S_RX", "QUIN_MI2S_TX", "SENARY_MI2S_TX", +"PRI_TDM_RX_0", "PRI_TDM_TX_0", "PRI_TDM_RX_1", "PRI_TDM_TX_1", +"PRI_TDM_RX_2", "PRI_TDM_TX_2", "PRI_TDM_RX_3", "PRI_TDM_TX_3", +"PRI_TDM_RX_4", "PRI_TDM_TX_4", "PRI_TDM_RX_5", "PRI_TDM_TX_5", +"PRI_TDM_RX_6", "PRI_TDM_TX_6", "PRI_TDM_RX_7", "PRI_TDM_TX_7", +"SEC_TDM_RX_0", "SEC_TDM_TX_0", "SEC_TDM_RX_1", "SEC_TDM_TX_1", +"SEC_TDM_RX_2", "SEC_TDM_TX_2", "SEC_TDM_RX_3", "SEC_TDM_TX_3", +"SEC_TDM_RX_4", "SEC_TDM_TX_4", "SEC_TDM_RX_5", "SEC_TDM_TX_5", +"SEC_TDM_RX_6", "SEC_TDM_TX_6", "SEC_TDM_RX_7", "SEC_TDM_TX_7", +"TERT_TDM_RX_0", "TERT_TDM_TX_0", "TERT_TDM_RX_1", "TERT_TDM_TX_1", +"TERT_TDM_RX_2", "TERT_TDM_TX_2", "TERT_TDM_RX_3", "TERT_TDM_TX_3", +"TERT_TDM_RX_4", "TERT_TDM_TX_4", "TERT_TDM_RX_5", "TERT_TDM_TX_5", +"TERT_TDM_RX_6", "TERT_TDM_TX_6", "TERT_TDM_RX_7", "TERT_TDM_TX_7", +"QUAT_TDM_RX_0", "QUAT_TDM_TX_0", "QUAT_TDM_RX_1", "QUAT_TDM_TX_1", +"QUAT_TDM_RX_2", "QUAT_TDM_TX_2", "QUAT_TDM_RX_3", "QUAT_TDM_TX_3", +"QUAT_TDM_RX_4", "QUAT_TDM_TX_4", "QUAT_TDM_RX_5", "QUAT_TDM_TX_5", +"QUAT_TDM_RX_6", "QUAT_TDM_TX_6", "QUAT_TDM_RX_7", "QUAT_TDM_TX_7", +"INT_BT_A2DP_RX", "USB_RX", "USB_TX", "DISPLAY_PORT_RX", +"TERT_AUXPCM_RX", "TERT_AUXPCM_TX", "QUAT_AUXPCM_RX", "QUAT_AUXPCM_TX", +"INT0_MI2S_RX", "INT0_MI2S_TX", "INT1_MI2S_RX", "INT1_MI2S_TX", +"INT2_MI2S_RX", "INT2_MI2S_TX", "INT3_MI2S_RX", "INT3_MI2S_TX", +"INT4_MI2S_RX", "INT4_MI2S_TX", "INT5_MI2S_RX", "INT5_MI2S_TX", +"INT6_MI2S_RX", "INT6_MI2S_TX" +}; + +static SOC_ENUM_SINGLE_DECL(mm1_channel_mux, + SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA1, ch_mixer); +static SOC_ENUM_SINGLE_DECL(mm2_channel_mux, + SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA2, ch_mixer); +static SOC_ENUM_SINGLE_DECL(mm3_channel_mux, + SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA3, ch_mixer); +static SOC_ENUM_SINGLE_DECL(mm4_channel_mux, + SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA4, ch_mixer); + +static SOC_ENUM_DOUBLE_DECL(mm1_ch1_enum, + SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA1, 0, be_name); +static SOC_ENUM_DOUBLE_DECL(mm1_ch2_enum, + SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, be_name); +static SOC_ENUM_DOUBLE_DECL(mm1_ch3_enum, + SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA1, 2, be_name); +static SOC_ENUM_DOUBLE_DECL(mm1_ch4_enum, + SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA1, 3, be_name); +static SOC_ENUM_DOUBLE_DECL(mm1_ch5_enum, + SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA1, 4, be_name); +static SOC_ENUM_DOUBLE_DECL(mm1_ch6_enum, + SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA1, 5, be_name); +static SOC_ENUM_DOUBLE_DECL(mm1_ch7_enum, + SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA1, 6, be_name); +static SOC_ENUM_DOUBLE_DECL(mm1_ch8_enum, + SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA1, 7, be_name); + +static int msm_pcm_get_ctl_enum_info(struct snd_ctl_elem_info *uinfo, + unsigned int channels, + unsigned int items, const char *const names[]) +{ + if (uinfo->value.enumerated.item >= items) + uinfo->value.enumerated.item = items - 1; + + WARN(strlen(names[uinfo->value.enumerated.item]) >= + sizeof(uinfo->value.enumerated.name), + "ALSA: too long item name '%s'\n", + names[uinfo->value.enumerated.item]); + strlcpy(uinfo->value.enumerated.name, + names[uinfo->value.enumerated.item], + sizeof(uinfo->value.enumerated.name)); + return 0; +} + +static int msm_pcm_channel_mixer_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + + uinfo->value.enumerated.items = ARRAY_SIZE(ch_mixer); + msm_pcm_get_ctl_enum_info(uinfo, 1, e->items, e->texts); + + return 0; +} +static int msm_pcm_channel_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u16 fe_id = 0; + + fe_id = ((struct soc_enum *) + kcontrol->private_value)->shift_l; + if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) { + pr_err("%s: invalid FE %d\n", __func__, fe_id); + return -EINVAL; + } + + pr_debug("%s: FE %d %s\n", __func__, + fe_id, + channel_mixer[fe_id].enable ? "Enabled" : "Disabled"); + ucontrol->value.enumerated.item[0] = channel_mixer[fe_id].enable; + return 0; +} + +static int msm_pcm_channel_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u16 fe_id = 0; + + fe_id = ((struct soc_enum *) + kcontrol->private_value)->shift_l; + if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) { + pr_err("%s: invalid FE %d\n", __func__, fe_id); + return -EINVAL; + } + + channel_mixer[fe_id].enable = ucontrol->value.enumerated.item[0]; + pr_debug("%s: %s FE %d\n", __func__, + channel_mixer[fe_id].enable ? "Enable" : "Disable", + fe_id); + return 0; +} + +static int msm_pcm_channel_input_be_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + + uinfo->value.enumerated.items = ARRAY_SIZE(be_name); + msm_pcm_get_ctl_enum_info(uinfo, 1, e->items, e->texts); + + return 0; +} + +static int msm_pcm_channel_input_be_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + u16 fe_id = 0, in_ch = 0; + + fe_id = e->shift_l; + in_ch = e->shift_r; + if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) { + pr_err("%s: invalid FE %d\n", __func__, fe_id); + return -EINVAL; + } + if (in_ch >= ADM_MAX_CHANNELS) { + pr_err("%s: invalid input channel %d\n", __func__, in_ch); + return -EINVAL; + } + + channel_input[fe_id][in_ch] = ucontrol->value.enumerated.item[0]; + return 1; +} + +static int msm_pcm_channel_input_be_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + u16 fe_id = 0, in_ch = 0; + + fe_id = e->shift_l; + in_ch = e->shift_r; + if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) { + pr_err("%s: invalid FE %d\n", __func__, fe_id); + return -EINVAL; + } + if (in_ch >= ADM_MAX_CHANNELS) { + pr_err("%s: invalid input channel %d\n", __func__, in_ch); + return -EINVAL; + } + + ucontrol->value.enumerated.item[0] = channel_input[fe_id][in_ch]; + return 1; +} + + +static int msm_pcm_channel_weight_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = ADM_MAX_CHANNELS; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = WEIGHT_0_DB; + + return 0; +} + +static int msm_pcm_channel_weight_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u16 fe_id = 0, out_ch = 0; + int i, weight; + + fe_id = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + out_ch = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->rshift; + if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) { + pr_err("%s: invalid FE %d\n", __func__, fe_id); + return -EINVAL; + } + if (out_ch >= ADM_MAX_CHANNELS) { + pr_err("%s: invalid input channel %d\n", __func__, out_ch); + return -EINVAL; + } + + pr_debug("%s: FE_ID: %d, channel weight %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld\n", + __func__, fe_id, + ucontrol->value.integer.value[0], + ucontrol->value.integer.value[1], + ucontrol->value.integer.value[2], + ucontrol->value.integer.value[3], + ucontrol->value.integer.value[4], + ucontrol->value.integer.value[5], + ucontrol->value.integer.value[6], + ucontrol->value.integer.value[7]); + + for (i = 0; i < ADM_MAX_CHANNELS; ++i) { + weight = ucontrol->value.integer.value[i]; + channel_mixer[fe_id].channel_weight[out_ch][i] = weight; + pr_debug("%s: FE_ID %d, output %d input %d weight %d\n", + __func__, fe_id, out_ch, i, + channel_mixer[fe_id].channel_weight[out_ch][i]); + } + + return 0; +} + +static int msm_pcm_channel_weight_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u16 fe_id = 0, out_ch = 0; + int i; + + fe_id = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + out_ch = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->rshift; + if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) { + pr_err("%s: invalid FE %d\n", __func__, fe_id); + return -EINVAL; + } + if (out_ch >= ADM_MAX_CHANNELS) { + pr_err("%s: invalid input channel %d\n", __func__, out_ch); + return -EINVAL; + } + + for (i = 0; i < ADM_MAX_CHANNELS; ++i) + ucontrol->value.integer.value[i] = + channel_mixer[fe_id].channel_weight[out_ch][i]; + + pr_debug("%s: FE_ID: %d, weight %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld", + __func__, fe_id, + ucontrol->value.integer.value[0], + ucontrol->value.integer.value[1], + ucontrol->value.integer.value[2], + ucontrol->value.integer.value[3], + ucontrol->value.integer.value[4], + ucontrol->value.integer.value[5], + ucontrol->value.integer.value[6], + ucontrol->value.integer.value[7]); + + return 0; +} + +static const struct snd_kcontrol_new channel_mixer_controls[] = { + SOC_SINGLE_EXT("MultiMedia1 Channel Rule", SND_SOC_NOPM, + MSM_FRONTEND_DAI_MULTIMEDIA1, 8, 0, + msm_pcm_get_channel_rule_index, + msm_pcm_put_channel_rule_index), + SOC_SINGLE_EXT("MultiMedia2 Channel Rule", SND_SOC_NOPM, + MSM_FRONTEND_DAI_MULTIMEDIA2, 8, 0, + msm_pcm_get_channel_rule_index, + msm_pcm_put_channel_rule_index), + SOC_SINGLE_EXT("MultiMedia3 Channel Rule", SND_SOC_NOPM, + MSM_FRONTEND_DAI_MULTIMEDIA3, 8, 0, + msm_pcm_get_channel_rule_index, + msm_pcm_put_channel_rule_index), + SOC_SINGLE_EXT("MultiMedia4 Channel Rule", SND_SOC_NOPM, + MSM_FRONTEND_DAI_MULTIMEDIA4, 8, 0, + msm_pcm_get_channel_rule_index, + msm_pcm_put_channel_rule_index), + SOC_SINGLE_EXT("MultiMedia5 Channel Rule", SND_SOC_NOPM, + MSM_FRONTEND_DAI_MULTIMEDIA5, 8, 0, + msm_pcm_get_channel_rule_index, + msm_pcm_put_channel_rule_index), + SOC_SINGLE_EXT("MultiMedia6 Channel Rule", SND_SOC_NOPM, + MSM_FRONTEND_DAI_MULTIMEDIA6, 8, 0, + msm_pcm_get_channel_rule_index, + msm_pcm_put_channel_rule_index), + + SOC_SINGLE_EXT("MultiMedia1 Channels", SND_SOC_NOPM, + MSM_FRONTEND_DAI_MULTIMEDIA1, 8, 0, + msm_pcm_get_out_chs, + msm_pcm_put_out_chs), + SOC_SINGLE_EXT("MultiMedia2 Channels", SND_SOC_NOPM, + MSM_FRONTEND_DAI_MULTIMEDIA2, 8, 0, + msm_pcm_get_out_chs, + msm_pcm_put_out_chs), + SOC_SINGLE_EXT("MultiMedia3 Channels", SND_SOC_NOPM, + MSM_FRONTEND_DAI_MULTIMEDIA3, 8, 0, + msm_pcm_get_out_chs, + msm_pcm_put_out_chs), + SOC_SINGLE_EXT("MultiMedia4 Channels", SND_SOC_NOPM, + MSM_FRONTEND_DAI_MULTIMEDIA4, 8, 0, + msm_pcm_get_out_chs, + msm_pcm_put_out_chs), + SOC_SINGLE_EXT("MultiMedia5 Channels", SND_SOC_NOPM, + MSM_FRONTEND_DAI_MULTIMEDIA5, 8, 0, + msm_pcm_get_out_chs, + msm_pcm_put_out_chs), + SOC_SINGLE_EXT("MultiMedia6 Channels", SND_SOC_NOPM, + MSM_FRONTEND_DAI_MULTIMEDIA6, 8, 0, + msm_pcm_get_out_chs, + msm_pcm_put_out_chs), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia1 Channel Mixer", + .info = msm_pcm_channel_mixer_info, + .get = msm_pcm_channel_mixer_get, + .put = msm_pcm_channel_mixer_put, + .private_value = (unsigned long)&(mm1_channel_mux) + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia2 Channel Mixer", + .info = msm_pcm_channel_mixer_info, + .get = msm_pcm_channel_mixer_get, + .put = msm_pcm_channel_mixer_put, + .private_value = (unsigned long)&(mm2_channel_mux) + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia3 Channel Mixer", + .info = msm_pcm_channel_mixer_info, + .get = msm_pcm_channel_mixer_get, + .put = msm_pcm_channel_mixer_put, + .private_value = (unsigned long)&(mm3_channel_mux) + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia4 Channel Mixer", + .info = msm_pcm_channel_mixer_info, + .get = msm_pcm_channel_mixer_get, + .put = msm_pcm_channel_mixer_put, + .private_value = (unsigned long)&(mm4_channel_mux) + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia1 Output Channel1", + .info = msm_pcm_channel_weight_info, + .get = msm_pcm_channel_weight_get, + .put = msm_pcm_channel_weight_put, + .private_value = (unsigned long)&(struct soc_multi_mixer_control) + { .shift = MSM_FRONTEND_DAI_MULTIMEDIA1, .rshift = 0,} + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia1 Output Channel2", + .info = msm_pcm_channel_weight_info, + .get = msm_pcm_channel_weight_get, + .put = msm_pcm_channel_weight_put, + .private_value = (unsigned long)&(struct soc_multi_mixer_control) + { .shift = MSM_FRONTEND_DAI_MULTIMEDIA1, .rshift = 1, } + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia1 Output Channel3", + .info = msm_pcm_channel_weight_info, + .get = msm_pcm_channel_weight_get, + .put = msm_pcm_channel_weight_put, + .private_value = (unsigned long)&(struct soc_multi_mixer_control) + { .shift = MSM_FRONTEND_DAI_MULTIMEDIA1, .rshift = 2,} + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia1 Output Channel4", + .info = msm_pcm_channel_weight_info, + .get = msm_pcm_channel_weight_get, + .put = msm_pcm_channel_weight_put, + .private_value = (unsigned long)&(struct soc_multi_mixer_control) + { .shift = MSM_FRONTEND_DAI_MULTIMEDIA1, .rshift = 3,} + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia1 Output Channel5", + .info = msm_pcm_channel_weight_info, + .get = msm_pcm_channel_weight_get, + .put = msm_pcm_channel_weight_put, + .private_value = (unsigned long)&(struct soc_multi_mixer_control) + { .shift = MSM_FRONTEND_DAI_MULTIMEDIA1, .rshift = 4,} + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia1 Output Channel6", + .info = msm_pcm_channel_weight_info, + .get = msm_pcm_channel_weight_get, + .put = msm_pcm_channel_weight_put, + .private_value = (unsigned long)&(struct soc_multi_mixer_control) + { .shift = MSM_FRONTEND_DAI_MULTIMEDIA1, .rshift = 5,} + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia1 Output Channel7", + .info = msm_pcm_channel_weight_info, + .get = msm_pcm_channel_weight_get, + .put = msm_pcm_channel_weight_put, + .private_value = (unsigned long)&(struct soc_multi_mixer_control) + { .shift = MSM_FRONTEND_DAI_MULTIMEDIA1, .rshift = 6,} + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia1 Output Channel8", + .info = msm_pcm_channel_weight_info, + .get = msm_pcm_channel_weight_get, + .put = msm_pcm_channel_weight_put, + .private_value = (unsigned long)&(struct soc_multi_mixer_control) + { .shift = MSM_FRONTEND_DAI_MULTIMEDIA1, .rshift = 7,} + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia2 Output Channel1", + .info = msm_pcm_channel_weight_info, + .get = msm_pcm_channel_weight_get, + .put = msm_pcm_channel_weight_put, + .private_value = (unsigned long)&(struct soc_multi_mixer_control) + {.shift = MSM_FRONTEND_DAI_MULTIMEDIA2, .rshift = 0,} + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia2 Output Channel2", + .info = msm_pcm_channel_weight_info, + .get = msm_pcm_channel_weight_get, + .put = msm_pcm_channel_weight_put, + .private_value = (unsigned long)&(struct soc_multi_mixer_control) + {.shift = MSM_FRONTEND_DAI_MULTIMEDIA2, .rshift = 1,} + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia2 Output Channel3", + .info = msm_pcm_channel_weight_info, + .get = msm_pcm_channel_weight_get, + .put = msm_pcm_channel_weight_put, + .private_value = (unsigned long)&(struct soc_multi_mixer_control) + {.shift = MSM_FRONTEND_DAI_MULTIMEDIA2, .rshift = 2,} + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia3 Output Channel1", + .info = msm_pcm_channel_weight_info, + .get = msm_pcm_channel_weight_get, + .put = msm_pcm_channel_weight_put, + .private_value = (unsigned long)&(struct soc_multi_mixer_control) + {.shift = MSM_FRONTEND_DAI_MULTIMEDIA3, .rshift = 0,} + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia3 Output Channel2", + .info = msm_pcm_channel_weight_info, + .get = msm_pcm_channel_weight_get, + .put = msm_pcm_channel_weight_put, + .private_value = (unsigned long)&(struct soc_multi_mixer_control) + {.shift = MSM_FRONTEND_DAI_MULTIMEDIA3, .rshift = 1,} + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia1 Channel1", + .info = msm_pcm_channel_input_be_info, + .get = msm_pcm_channel_input_be_get, + .put = msm_pcm_channel_input_be_put, + .private_value = (unsigned long)&(mm1_ch1_enum) + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia1 Channel2", + .info = msm_pcm_channel_input_be_info, + .get = msm_pcm_channel_input_be_get, + .put = msm_pcm_channel_input_be_put, + .private_value = (unsigned long)&(mm1_ch2_enum) + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia1 Channel3", + .info = msm_pcm_channel_input_be_info, + .get = msm_pcm_channel_input_be_get, + .put = msm_pcm_channel_input_be_put, + .private_value = (unsigned long)&(mm1_ch3_enum) + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia1 Channel4", + .info = msm_pcm_channel_input_be_info, + .get = msm_pcm_channel_input_be_get, + .put = msm_pcm_channel_input_be_put, + .private_value = (unsigned long)&(mm1_ch4_enum) + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia1 Channel5", + .info = msm_pcm_channel_input_be_info, + .get = msm_pcm_channel_input_be_get, + .put = msm_pcm_channel_input_be_put, + .private_value = (unsigned long)&(mm1_ch5_enum) + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia1 Channel6", + .info = msm_pcm_channel_input_be_info, + .get = msm_pcm_channel_input_be_get, + .put = msm_pcm_channel_input_be_put, + .private_value = (unsigned long)&(mm1_ch6_enum) + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia1 Channel7", + .info = msm_pcm_channel_input_be_info, + .get = msm_pcm_channel_input_be_get, + .put = msm_pcm_channel_input_be_put, + .private_value = (unsigned long)&(mm1_ch7_enum) + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .name = "MultiMedia1 Channel8", + .info = msm_pcm_channel_input_be_info, + .get = msm_pcm_channel_input_be_get, + .put = msm_pcm_channel_input_be_put, + .private_value = (unsigned long)&(mm1_ch8_enum) + }, +}; static int msm_ec_ref_ch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -14809,6 +15518,9 @@ static int msm_routing_probe(struct snd_soc_platform *platform) snd_soc_add_platform_controls(platform, ec_ref_param_controls, ARRAY_SIZE(ec_ref_param_controls)); + snd_soc_add_platform_controls(platform, channel_mixer_controls, + ARRAY_SIZE(channel_mixer_controls)); + msm_qti_pp_add_controls(platform); msm_dts_srs_tm_add_controls(platform); diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c index 7cf19a9ed335..61dd478b97e4 100644 --- a/sound/soc/msm/qdsp6v2/q6adm.c +++ b/sound/soc/msm/qdsp6v2/q6adm.c @@ -520,6 +520,267 @@ fail_cmd: return ret; } +static int adm_populate_channel_weight(u16 *ptr, + struct msm_pcm_channel_mixer *ch_mixer, + int channel_index) +{ + u16 i, j, start_index = 0; + + if (channel_index > ch_mixer->output_channel) { + pr_err("%s: channel index %d is larger than output_channel %d\n", + __func__, channel_index, ch_mixer->output_channel); + return -EINVAL; + } + + for (i = 0; i < ch_mixer->output_channel; i++) { + pr_debug("%s: weight for output %d:", __func__, i); + for (j = 0; j < ADM_MAX_CHANNELS; j++) + pr_debug(" %d", + ch_mixer->channel_weight[i][j]); + pr_debug("\n"); + } + + for (i = 0; i < channel_index; ++i) + start_index += ch_mixer->input_channels[i]; + + for (i = 0; i < ch_mixer->output_channel; ++i) { + for (j = start_index; + j < start_index + + ch_mixer->input_channels[channel_index]; j++) { + *ptr = ch_mixer->channel_weight[i][j]; + pr_debug("%s: ptr[%d][%d] = %d\n", + __func__, i, j, *ptr); + ptr++; + } + } + + return 0; +} + +/* + * adm_programable_channel_mixer + * + * Receives port_id, copp_idx, session_id, session_type, ch_mixer + * and channel_index to send ADM command to mix COPP data. + * + * port_id - Passed value, port_id for which backend is wanted + * copp_idx - Passed value, copp_idx for which COPP is wanted + * session_id - Passed value, session_id for which session is needed + * 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 + */ +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) +{ + 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; + + pr_debug("%s: port_id = %d\n", __func__, port_id); + port_id = afe_convert_virtual_to_portid(port_id); + port_idx = adm_validate_and_get_port_index(port_id); + if (port_idx < 0) { + pr_err("%s: Invalid port_id %#x\n", __func__, port_id); + return -EINVAL; + } + /* + * First 8 bytes are 4 bytes as rule number, 2 bytes as output + * channel and 2 bytes as input channel. + * 2 * ch_mixer->output_channel means output channel mapping. + * 2 * ch_mixer->input_channels[channel_index]) means input + * channel mapping. + * 2 * ch_mixer->input_channels[channel_index] * + * ch_mixer->output_channel) means the channel mixer weighting + * coefficients. + * param_size needs to be a multiple of 4 bytes. + */ + + param_size = 2 * (4 + ch_mixer->output_channel + + ch_mixer->input_channels[channel_index] + + ch_mixer->input_channels[channel_index] * + ch_mixer->output_channel); + roundup(param_size, 4); + + sz = sizeof(struct adm_cmd_set_pspd_mtmx_strtr_params_v5) + + sizeof(struct default_chmixer_param_id_coeff) + + sizeof(struct adm_param_data_v5) + param_size; + pr_debug("%s: sz = %d\n", __func__, sz); + adm_params = kzalloc(sz, GFP_KERNEL); + if (!adm_params) + return -ENOMEM; + + adm_params->payload_addr_lsw = 0; + adm_params->payload_addr_msw = 0; + adm_params->mem_map_handle = 0; + adm_params->direction = session_type; + adm_params->sessionid = session_id; + pr_debug("%s: copp_id = %d, session id %d\n", __func__, + atomic_read(&this_adm.copp.id[port_idx][copp_idx]), + session_id); + adm_params->deviceid = atomic_read( + &this_adm.copp.id[port_idx][copp_idx]); + adm_params->reserved = 0; + + data_v5.module_id = MTMX_MODULE_ID_DEFAULT_CHMIXER; + data_v5.param_id = DEFAULT_CHMIXER_PARAM_ID_COEFF; + data_v5.reserved = 0; + data_v5.param_size = param_size; + adm_params->payload_size = + sizeof(struct default_chmixer_param_id_coeff) + + sizeof(struct adm_param_data_v5) + data_v5.param_size; + adm_pspd_params = (u16 *)((u8 *)adm_params + + sizeof(struct adm_cmd_set_pspd_mtmx_strtr_params_v5)); + memcpy(adm_pspd_params, &data_v5, sizeof(data_v5)); + + adm_pspd_params = (u16 *)((u8 *)adm_params + + sizeof(struct adm_cmd_set_pspd_mtmx_strtr_params_v5) + + sizeof(data_v5)); + + adm_pspd_params[0] = ch_mixer->rule; + adm_pspd_params[2] = ch_mixer->output_channel; + adm_pspd_params[3] = ch_mixer->input_channels[channel_index]; + index = 4; + + if (ch_mixer->output_channel == 1) { + adm_pspd_params[index] = PCM_CHANNEL_FC; + } else if (ch_mixer->output_channel == 2) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + } else if (ch_mixer->output_channel == 3) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + adm_pspd_params[index + 2] = PCM_CHANNEL_FC; + } else if (ch_mixer->output_channel == 4) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + adm_pspd_params[index + 2] = PCM_CHANNEL_LS; + adm_pspd_params[index + 3] = PCM_CHANNEL_RS; + } else if (ch_mixer->output_channel == 5) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + adm_pspd_params[index + 2] = PCM_CHANNEL_FC; + adm_pspd_params[index + 3] = PCM_CHANNEL_LS; + adm_pspd_params[index + 4] = PCM_CHANNEL_RS; + } else if (ch_mixer->output_channel == 6) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + adm_pspd_params[index + 2] = PCM_CHANNEL_LFE; + adm_pspd_params[index + 3] = PCM_CHANNEL_FC; + adm_pspd_params[index + 4] = PCM_CHANNEL_LS; + adm_pspd_params[index + 5] = PCM_CHANNEL_RS; + } else if (ch_mixer->output_channel == 8) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + adm_pspd_params[index + 2] = PCM_CHANNEL_LFE; + adm_pspd_params[index + 3] = PCM_CHANNEL_FC; + adm_pspd_params[index + 4] = PCM_CHANNEL_LS; + adm_pspd_params[index + 5] = PCM_CHANNEL_RS; + adm_pspd_params[index + 6] = PCM_CHANNEL_LB; + adm_pspd_params[index + 7] = PCM_CHANNEL_RB; + } + + index = index + ch_mixer->output_channel; + if (ch_mixer->input_channels[channel_index] == 1) { + adm_pspd_params[index] = PCM_CHANNEL_FC; + } else if (ch_mixer->input_channels[channel_index] == 2) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + } else if (ch_mixer->input_channels[channel_index] == 3) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + adm_pspd_params[index + 2] = PCM_CHANNEL_FC; + } else if (ch_mixer->input_channels[channel_index] == 4) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + adm_pspd_params[index + 2] = PCM_CHANNEL_LS; + adm_pspd_params[index + 3] = PCM_CHANNEL_RS; + } else if (ch_mixer->input_channels[channel_index] == 5) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + adm_pspd_params[index + 2] = PCM_CHANNEL_FC; + adm_pspd_params[index + 3] = PCM_CHANNEL_LS; + adm_pspd_params[index + 4] = PCM_CHANNEL_RS; + } else if (ch_mixer->input_channels[channel_index] == 6) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + adm_pspd_params[index + 2] = PCM_CHANNEL_LFE; + adm_pspd_params[index + 3] = PCM_CHANNEL_FC; + adm_pspd_params[index + 4] = PCM_CHANNEL_LS; + adm_pspd_params[index + 5] = PCM_CHANNEL_RS; + } else if (ch_mixer->input_channels[channel_index] == 8) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + adm_pspd_params[index + 2] = PCM_CHANNEL_LFE; + adm_pspd_params[index + 3] = PCM_CHANNEL_FC; + adm_pspd_params[index + 4] = PCM_CHANNEL_LS; + adm_pspd_params[index + 5] = PCM_CHANNEL_RS; + 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) { + pr_err("%s: fail to get channel weight with error %d\n", + __func__, ret); + goto fail_cmd; + } + + adm_params->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); + adm_params->hdr.src_svc = APR_SVC_ADM; + adm_params->hdr.src_domain = APR_DOMAIN_APPS; + adm_params->hdr.src_port = port_id; + adm_params->hdr.dest_svc = APR_SVC_ADM; + adm_params->hdr.dest_domain = APR_DOMAIN_ADSP; + adm_params->hdr.dest_port = + atomic_read(&this_adm.copp.id[port_idx][copp_idx]); + adm_params->hdr.token = port_idx << 16 | copp_idx; + adm_params->hdr.opcode = ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5; + adm_params->hdr.pkt_size = sz; + adm_params->payload_addr_lsw = 0; + adm_params->payload_addr_msw = 0; + adm_params->mem_map_handle = 0; + adm_params->reserved = 0; + + ptr = (u16 *)adm_params; + for (index = 0; index < (sz / 2); index++) + pr_debug("%s: adm_params[%d] = 0x%x\n", + __func__, index, (unsigned int)ptr[index]); + + atomic_set(&this_adm.copp.stat[port_idx][copp_idx], 0); + ret = apr_send_pkt(this_adm.apr, (uint32_t *)adm_params); + if (ret < 0) { + pr_err("%s: Set params failed port %d rc %d\n", __func__, + port_id, ret); + ret = -EINVAL; + goto fail_cmd; + } + + ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx], + atomic_read( + &this_adm.copp.stat[port_idx][copp_idx]) >= 0, + msecs_to_jiffies(TIMEOUT_MS)); + if (!ret) { + pr_err("%s: set params timed out port = %d\n", + __func__, port_id); + ret = -ETIMEDOUT; + goto fail_cmd; + } + ret = 0; +fail_cmd: + kfree(adm_params); + + return ret; +} + int adm_set_stereo_to_custom_stereo(int port_id, int copp_idx, unsigned int session_id, char *params, uint32_t params_length)