From 66c053253b7bd5a2395735906d3402a53498f54e Mon Sep 17 00:00:00 2001 From: Soumya Managoli Date: Thu, 3 Nov 2022 16:51:00 +0530 Subject: [PATCH 01/13] dsp: Remove lock in voice_map_cal_memory voice_map_cal_memory is already under locked context of common_lock from fn voc_register_vocproc_vol_table from where it is invoked. Remove locking the same lock again in voice_map_cal_memory to avoid deadlock. Change-Id: Ibd6c7169377418c7bda3310a0e422279fd4e7295 --- dsp/q6voice.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/dsp/q6voice.c b/dsp/q6voice.c index e7f7646b7eea..1f3b1448fb8d 100644 --- a/dsp/q6voice.c +++ b/dsp/q6voice.c @@ -3850,7 +3850,6 @@ static int voice_map_cal_memory(struct cal_block_data *cal_block, goto done; } - mutex_lock(&common.common_lock); v = &common.voice[voc_index]; result = voice_map_memory_physical_cmd(v, @@ -3864,12 +3863,10 @@ static int voice_map_cal_memory(struct cal_block_data *cal_block, &cal_block->cal_data.paddr, cal_block->map_data.map_size); - goto done_unlock; + goto done; } cal_block->map_data.q6map_handle = common.cal_mem_handle; -done_unlock: - mutex_unlock(&common.common_lock); done: return result; } From 7581982cee85c8e652bfefe7ddf997e6f4577307 Mon Sep 17 00:00:00 2001 From: Srinivasa Reddy M N Date: Thu, 20 Oct 2022 17:59:48 +0530 Subject: [PATCH 02/13] ASoC: Add support "adm cmd register" and "adm pp" events Added support for "ADM_CMD_REGISTER_EVENT" and "ADM_PP_EVENT" events. Signed-off-by: Srinivasa Reddy M N Change-Id: I80d8dc6d9fccdac67ea616d19415aa2133a3f370 --- asoc/msm-pcm-q6-v2.c | 29 ++- asoc/msm-pcm-routing-auto.c | 339 +++++++++++++++++++++++++++ asoc/msm-pcm-routing-v2.c | 50 ++++ asoc/msm-pcm-routing-v2.h | 3 + asoc/msm-qti-pp-config.c | 211 +++++++++++++++++ asoc/msm-qti-pp-config.h | 8 + dsp/q6adm.c | 186 +++++++++++++++ include/dsp/apr_audio-v2.h | 29 +++ include/dsp/q6adm-v2.h | 7 + include/uapi/audio/linux/msm_audio.h | 14 ++ 10 files changed, 875 insertions(+), 1 deletion(-) mode change 100755 => 100644 asoc/msm-pcm-routing-auto.c mode change 100755 => 100644 asoc/msm-pcm-routing-v2.c mode change 100755 => 100644 include/dsp/apr_audio-v2.h diff --git a/asoc/msm-pcm-q6-v2.c b/asoc/msm-pcm-q6-v2.c index 3d337efc98c1..1dfa857be5ea 100644 --- a/asoc/msm-pcm-q6-v2.c +++ b/asoc/msm-pcm-q6-v2.c @@ -565,6 +565,8 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream) uint16_t format = 0; uint16_t req_format = 0; uint16_t input_file_format = 0; + int port_id = 0, copp_idx = -1; + bool found = false; if (!component) { pr_err("%s: component is NULL\n", __func__); @@ -691,6 +693,15 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream) return ret; } + found = msm_pcm_routing_get_portid_copp_idx(soc_prtd->dai_link->id, + SESSION_TYPE_RX, &port_id, &copp_idx); + if (found) { + q6adm_update_rtd_info(soc_prtd, port_id, copp_idx, + soc_prtd->dai_link->id, 1); + } else { + pr_err("%s: copp_idx not found\n", __func__); + } + /*Format block is configure with input file bits_per_sample*/ switch (input_file_format) { case SNDRV_PCM_FORMAT_S32_LE: @@ -1070,8 +1081,10 @@ static int msm_pcm_open(struct snd_pcm_substream *substream) prtd->reset_event = false; runtime->private_data = prtd; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { msm_adsp_init_mixer_ctl_pp_event_queue(soc_prtd); + msm_adsp_init_mixer_ctl_adm_pp_event_queue(soc_prtd); + } /* Vote to update the Rx thread priority to RT Thread for playback */ if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) && @@ -1189,6 +1202,8 @@ static int msm_pcm_playback_close(struct snd_pcm_substream *substream) uint32_t timeout; int dir = 0; int ret = 0; + int port_id = 0, copp_idx = -1; + bool found = false; pr_debug("%s: cmd_pending 0x%lx\n", __func__, prtd->cmd_pending); @@ -1239,9 +1254,21 @@ static int msm_pcm_playback_close(struct snd_pcm_substream *substream) prtd->audio_client); q6asm_audio_client_free(prtd->audio_client); } + + found = msm_pcm_routing_get_portid_copp_idx(soc_prtd->dai_link->id, + SESSION_TYPE_RX, &port_id, &copp_idx); + if (found) { + q6adm_update_rtd_info(soc_prtd, port_id, copp_idx, + soc_prtd->dai_link->id, 0); + q6adm_clear_callback(); + } else { + pr_err("%s: copp_idx not found\n", __func__); + } + msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id, SNDRV_PCM_STREAM_PLAYBACK); msm_adsp_clean_mixer_ctl_pp_event_queue(soc_prtd); + msm_adsp_clean_mixer_ctl_adm_pp_event_queue(soc_prtd); kfree(prtd); runtime->private_data = NULL; mutex_unlock(&pdata->lock); diff --git a/asoc/msm-pcm-routing-auto.c b/asoc/msm-pcm-routing-auto.c old mode 100755 new mode 100644 index 4eccb8c4f398..f8e15f51fc24 --- a/asoc/msm-pcm-routing-auto.c +++ b/asoc/msm-pcm-routing-auto.c @@ -103,6 +103,10 @@ static int afe_loopback_tx_port_id = -1; static struct msm_pcm_channel_mixer ec_ref_chmix_cfg[MSM_FRONTEND_DAI_MAX]; static struct msm_ec_ref_port_cfg ec_ref_port_cfg; +static uint32_t adm_pp_reg_event_opcode[] = { + ADM_CMD_REGISTER_EVENT +}; + #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]; @@ -2418,6 +2422,56 @@ int msm_pcm_routing_set_channel_mixer_runtime(int be_id, int session_id, } EXPORT_SYMBOL(msm_pcm_routing_set_channel_mixer_runtime); +/* + * msm_pcm_routing_get_portid_copp_idx: + * update the port_id and copp_idx for a given + * fe_id + * + * @fe_id: front end id + * @session_type: indicates session is of type TX or RX + * port: port_id to be updated as output + * copp_idx: copp_idx is updated as output + * @stream_type: indicates either Audio or Listen stream type + */ +bool msm_pcm_routing_get_portid_copp_idx(int fe_id, + int session_type, int *port, int *copp_idx) +{ + int idx = 0; + bool found = false; + int be_index = 0, port_id = 0; + + pr_debug("%s:fe_id[%d] sess_type [%d]\n", + __func__, fe_id, session_type); + if (!is_mm_lsm_fe_id(fe_id)) { + /* bad ID assigned in machine driver */ + pr_err("%s: bad MM ID %d\n", __func__, fe_id); + 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; + + for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) { + unsigned long copp_id = + session_copp_map[fe_id][session_type][be_index]; + if (test_bit(idx, &copp_id)) { + pr_debug("%s: port_id: %d, copp_idx:%d\n", + __func__, port_id, idx); + *port = port_id; + *copp_idx = idx; + found = true; + break; + } + } + } + + return found; +} +EXPORT_SYMBOL(msm_pcm_routing_get_portid_copp_idx); + int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode, int dspst_id, int stream_type) { @@ -32481,6 +32535,273 @@ static void msm_routing_unload_topology(uint32_t topology_id) } +static int msm_audio_get_copp_idx_from_port_id(int port_id, int session_type, + int *copp_idx) +{ + int i = 0, idx = 0, be_idx = 0; + int ret = 0; + unsigned long copp = 0; + + pr_debug("%s: Enter, port_id=%d\n", __func__, port_id); + + ret = q6audio_validate_port(port_id); + if (ret < 0) { + pr_err("%s: port validation failed id 0x%x ret %d\n", + __func__, port_id, ret); + + ret = -EINVAL; + goto done; + } + + for (be_idx = 0; be_idx < MSM_BACKEND_DAI_MAX; be_idx++) { + if (msm_bedais[be_idx].port_id == port_id) + break; + } + if (be_idx >= MSM_BACKEND_DAI_MAX) { + pr_err("%s: Invalid be id %d\n", __func__, be_idx); + + ret = -EINVAL; + goto done; + } + + for_each_set_bit(i, &msm_bedais[be_idx].fe_sessions[0], + MSM_FRONTEND_DAI_MAX) { + if (!(is_mm_lsm_fe_id(i) && + route_check_fe_id_adm_support(i))) + continue; + + for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) { + copp = session_copp_map[i] + [session_type][be_idx]; + if (test_bit(idx, &copp)) + break; + } + if (idx >= MAX_COPPS_PER_PORT) + continue; + else + break; + } + if (i >= MSM_FRONTEND_DAI_MAX) { + pr_err("%s: Invalid FE, exiting\n", __func__); + + ret = -EINVAL; + goto done; + } + *copp_idx = idx; + pr_debug("%s: copp_idx=%d\n", __func__, *copp_idx); + +done: + return ret; +} + +static int msm_routing_put_copp_dtmf_module_enable + (struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + uint8_t *be_id = NULL, be_id_val = 0; + int copp_idx = -1, port_id = 0; + struct param_hdr_v3 param_hdr = {0}; + int rc = 0; + u32 flag = (bool)ucontrol->value.integer.value[0]; + + be_id = (uint8_t *)ucontrol->value.bytes.data; + be_id_val = *be_id; + + if((be_id_val < 0) || (be_id_val >= MSM_BACKEND_DAI_MAX)) { + pr_err("%s: received invalid be_id %lu\n", __func__, be_id_val); + return -EINVAL; + } + + port_id = msm_bedais[be_id_val].port_id; + rc = msm_audio_get_copp_idx_from_port_id(port_id, SESSION_TYPE_RX, + &copp_idx); + + if (rc) { + pr_err(" %s:failure in getting copp_idx\n", __func__); + return rc; + } + + memset(¶m_hdr, 0, sizeof(param_hdr)); + param_hdr.module_id = AUDPROC_MODULE_ID_DTMF_DETECTION; + param_hdr.instance_id = INSTANCE_ID_0; + param_hdr.param_id = AUDPROC_PARAM_ID_ENABLE; + param_hdr.param_size = 4; + + rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr, + (u8 *)&flag); + if (rc) + pr_err("%s: Failed to set adm_pack_and_set_one_pp_param, err %d\n", + __func__, rc); + + return rc; + +} + +static const struct snd_kcontrol_new copp_dtmf_detect_enable_mixer_controls[] = { + SOC_SINGLE_EXT("MultiMedia1 COPP DTMF Detect Enable", SND_SOC_NOPM, + MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, NULL, + msm_routing_put_copp_dtmf_module_enable), + SOC_SINGLE_EXT("MultiMedia6 COPP DTMF Detect Enable", SND_SOC_NOPM, + MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, NULL, + msm_routing_put_copp_dtmf_module_enable), + SOC_SINGLE_EXT("MultiMedia21 COPP DTMF Detect Enable", SND_SOC_NOPM, + MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, NULL, + msm_routing_put_copp_dtmf_module_enable), +}; + +static int adsp_copp_event_handler(uint32_t opcode, + uint32_t token_adm, uint32_t *payload, void *priv) +{ + struct snd_soc_pcm_runtime *rtd = priv; + int ret = 0; + + if (!rtd) { + pr_err("%s: rtd is NULL\n", __func__); + return -EINVAL; + } + + ret = msm_adsp_copp_inform_mixer_ctl(rtd, payload); + if (ret) { + pr_err("%s: failed to inform mixer ctrl. err = %d\n", + __func__, ret); + return -EINVAL; + } + + return ret; +} + +static int msm_routing_get_copp_callback_event(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + uint32_t payload_size = 0; + struct dsp_adm_callback_list *oldest_event = NULL; + unsigned long spin_flags = 0; + struct dsp_adm_callback_prtd *kctl_prtd = NULL; + int ret = 0; + + kctl_prtd = (struct dsp_adm_callback_prtd *) + kcontrol->private_data; + + if (kctl_prtd == NULL) { + pr_err("%s: ADM PP event queue is not initialized.\n", + __func__); + ret = -EINVAL; + goto done; + } + + spin_lock_irqsave(&kctl_prtd->prtd_spin_lock, spin_flags); + pr_debug("%s: %d events in queue.\n", __func__, kctl_prtd->event_count); + if (list_empty(&kctl_prtd->event_queue)) { + pr_err("%s: ADM PP event queue is empty.\n", __func__); + ret = -EINVAL; + spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags); + goto done; + } + + oldest_event = list_first_entry(&kctl_prtd->event_queue, + struct dsp_adm_callback_list, list); + list_del(&oldest_event->list); + kctl_prtd->event_count--; + spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags); + + payload_size = oldest_event->event.payload_len; + pr_debug("%s: event fetched: type %d length %d\n", + __func__, oldest_event->event.event_type, + oldest_event->event.payload_len); + memcpy(ucontrol->value.bytes.data, &oldest_event->event, + sizeof(struct msm_adsp_event_data) + payload_size); + kfree(oldest_event); + +done: + return ret; +} + +static int msm_routing_put_copp_callback_event(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s\n", __func__); + return 0; +} + +static int msm_copp_callback_event_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = + sizeof(((struct snd_ctl_elem_value *)0)->value.bytes.data); + + return 0; +} + +static const struct snd_kcontrol_new copp_callback_event_controls[] = { + { + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "ADSP COPP Callback Event", + .info = msm_copp_callback_event_info, + .get = msm_routing_get_copp_callback_event, + .put = msm_routing_put_copp_callback_event, + }, +}; + +int msm_copp_event_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = + sizeof(((struct snd_ctl_elem_value *)0)->value.bytes.data); + + return 0; +} + +static int msm_routing_get_copp_event_cmd(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s\n", __func__); + return 0; +} + +static int msm_routing_put_copp_event_cmd(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct msm_adm_event_data *ev = NULL; + int be_id = 0, ret = 0, param_size = 0, opcode = 0; + int copp_idx = -1, port_id = 0; + + ev = (struct msm_adm_event_data *)ucontrol->value.bytes.data; + param_size = ev->payload_length - sizeof(struct module_info_data); + opcode = adm_pp_reg_event_opcode[(ev->event_type) + - ADSP_ADM_SERVICE_ID]; + be_id = ev->mod_info.be_id; + port_id = msm_bedais[be_id].port_id; + + pr_debug("%s: port_id= 0x%x, be_id=%d\n", __func__,port_id, be_id); + + ret = msm_audio_get_copp_idx_from_port_id(port_id, SESSION_TYPE_RX, + &copp_idx); + + if (ret) { + pr_debug("%s:failure in getting copp_idx\n", __func__); + return ret; + } + + q6adm_register_callback(&adsp_copp_event_handler); + q6adm_send_event_register_cmd(port_id, copp_idx, (u8 *) (ev->payload), + param_size, opcode); + return ret; +} + +static const struct snd_kcontrol_new copp_event_controls[] = { + { + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "COPP Event Cmd", + .info = msm_copp_event_info, + .get = msm_routing_get_copp_event_cmd, + .put = msm_routing_put_copp_event_cmd, + }, +}; + static int msm_routing_put_device_pp_params_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -33661,6 +33982,7 @@ static void snd_soc_dapm_add_routes_aux_pcm(struct snd_soc_component *component) /* Not used but frame seems to require it */ static int msm_routing_probe(struct snd_soc_component *component) { + struct snd_kcontrol *kctl = NULL; snd_soc_dapm_new_controls(&component->dapm, msm_qdsp6_widgets, ARRAY_SIZE(msm_qdsp6_widgets)); @@ -33718,10 +34040,27 @@ static int msm_routing_probe(struct snd_soc_component *component) ARRAY_SIZE(asrc_config_controls)); snd_soc_add_component_controls(component, asrc_start_controls, ARRAY_SIZE(asrc_start_controls)); + snd_soc_add_component_controls(component, + copp_dtmf_detect_enable_mixer_controls, + ARRAY_SIZE(copp_dtmf_detect_enable_mixer_controls)); + #ifdef CONFIG_MSM_INTERNAL_MCLK snd_soc_add_component_controls(component, internal_mclk_control, ARRAY_SIZE(internal_mclk_control)); #endif + snd_soc_add_component_controls(component, copp_callback_event_controls, + ARRAY_SIZE(copp_callback_event_controls)); + snd_soc_add_component_controls(component, copp_event_controls, + ARRAY_SIZE(copp_event_controls)); + + kctl = snd_soc_card_get_kcontrol(component->dapm.card, + "ADSP COPP Callback Event"); + if (!kctl) { + pr_err("%s: failed to get kctl %s.\n", __func__, + "ADSP COPP Callback Event"); + return -EINVAL; + } + kctl->private_data = NULL; return 0; } diff --git a/asoc/msm-pcm-routing-v2.c b/asoc/msm-pcm-routing-v2.c old mode 100755 new mode 100644 index 3849f6470242..6ec26e7d53b9 --- a/asoc/msm-pcm-routing-v2.c +++ b/asoc/msm-pcm-routing-v2.c @@ -2458,6 +2458,56 @@ int msm_pcm_routing_set_channel_mixer_runtime(int be_id, int session_id, } EXPORT_SYMBOL(msm_pcm_routing_set_channel_mixer_runtime); +/* + * msm_pcm_routing_get_portid_copp_idx: + * update the port_id and copp_idx for a given + * fe_id + * + * @fe_id: front end id + * @session_type: indicates session is of type TX or RX + * port: port_id to be updated as output + * copp_idx: copp_idx is updated as output + * @stream_type: indicates either Audio or Listen stream type + */ +bool msm_pcm_routing_get_portid_copp_idx(int fe_id, + int session_type, int *port, int *copp_idx) +{ + int idx = 0; + bool found = false; + int be_index = 0, port_id = 0; + + pr_debug("%s:fe_id[%d] sess_type [%d]\n", + __func__, fe_id, session_type); + if (!is_mm_lsm_fe_id(fe_id)) { + /* bad ID assigned in machine driver */ + pr_err("%s: bad MM ID %d\n", __func__, fe_id); + 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; + + for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) { + unsigned long copp_id = + session_copp_map[fe_id][session_type][be_index]; + if (test_bit(idx, &copp_id)) { + pr_debug("%s: port_id: %d, copp_idx:%d\n", + __func__, port_id, idx); + *port = port_id; + *copp_idx = idx; + found = true; + break; + } + } + } + + return found; +} +EXPORT_SYMBOL(msm_pcm_routing_get_portid_copp_idx); + int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode, int dspst_id, int stream_type) { diff --git a/asoc/msm-pcm-routing-v2.h b/asoc/msm-pcm-routing-v2.h index 752fe58c1ec5..d57851b7bec4 100644 --- a/asoc/msm-pcm-routing-v2.h +++ b/asoc/msm-pcm-routing-v2.h @@ -897,4 +897,7 @@ int snd_pcm_add_usr_ctls(struct snd_pcm *pcm, int stream, unsigned long private_value, struct snd_pcm_usr **info_ret); #endif + +bool msm_pcm_routing_get_portid_copp_idx(int fe_id, + int session_type, int *port_id, int *copp_idx); #endif /*_MSM_PCM_H*/ diff --git a/asoc/msm-qti-pp-config.c b/asoc/msm-qti-pp-config.c index 2e62922dc805..cdc0f38168f5 100644 --- a/asoc/msm-qti-pp-config.c +++ b/asoc/msm-qti-pp-config.c @@ -1207,6 +1207,217 @@ int msm_adsp_clean_mixer_ctl_pp_event_queue(struct snd_soc_pcm_runtime *rtd) return ret; } +int msm_adsp_init_mixer_ctl_adm_pp_event_queue(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_kcontrol *kctl = NULL; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + const char *mixer_ctl_name = DSP_ADM_CALLBACK; + struct dsp_adm_callback_prtd *kctl_prtd = NULL; + + if (!rtd) { + pr_err("%s: rtd is NULL\n", __func__); + ret = -EINVAL; + goto done; + } + + ctl_len = strlen(mixer_ctl_name) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) { + ret = -EINVAL; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s", mixer_ctl_name); + kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str); + kfree(mixer_str); + if (!kctl) { + pr_err("%s: failed to get kctl.\n", __func__); + ret = -EINVAL; + goto done; + } + + if (kctl->private_data != NULL) { + pr_err("%s: kctl_prtd is not NULL at initialization.\n", + __func__); + return -EINVAL; + } + + kctl_prtd = kzalloc(sizeof(struct dsp_adm_callback_prtd), + GFP_KERNEL); + if (!kctl_prtd) { + ret = -ENOMEM; + goto done; + } + + spin_lock_init(&kctl_prtd->prtd_spin_lock); + INIT_LIST_HEAD(&kctl_prtd->event_queue); + kctl_prtd->event_count = 0; + kctl->private_data = kctl_prtd; + +done: + return ret; +} + +int msm_adsp_clean_mixer_ctl_adm_pp_event_queue(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_kcontrol *kctl = NULL; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + struct dsp_adm_callback_list *node = NULL, *n = NULL; + unsigned long spin_flags = 0; + const char *mixer_ctl_name = DSP_ADM_CALLBACK; + struct dsp_adm_callback_prtd *kctl_prtd = NULL; + + if (!rtd) { + pr_err("%s: rtd is NULL\n", __func__); + ret = -EINVAL; + goto done; + } + + ctl_len = strlen(mixer_ctl_name) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) { + ret = -EINVAL; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s", mixer_ctl_name); + kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str); + kfree(mixer_str); + if (!kctl) { + pr_err("%s: failed to get kctl.\n", __func__); + ret = -EINVAL; + goto done; + } + + kctl_prtd = (struct dsp_adm_callback_prtd *) + kctl->private_data; + if (kctl_prtd != NULL) { + spin_lock_irqsave(&kctl_prtd->prtd_spin_lock, spin_flags); + /* clean the queue */ + list_for_each_entry_safe(node, n, + &kctl_prtd->event_queue, list) { + list_del(&node->list); + kctl_prtd->event_count--; + pr_debug("%s: %d remaining events after del.\n", + __func__, kctl_prtd->event_count); + kfree(node); + } + spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags); + } + + kfree(kctl_prtd); + kctl->private_data = NULL; + +done: + return ret; +} + +int msm_adsp_copp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd, + uint32_t *payload) +{ + /* adsp adm pp event notifier */ + struct snd_kcontrol *kctl = NULL; + struct snd_ctl_elem_value control = {0}; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + struct dsp_adm_callback_list *new_event = NULL; + struct dsp_adm_callback_list *oldest_event = NULL; + unsigned long spin_flags = 0; + struct dsp_adm_callback_prtd *kctl_prtd = NULL; + struct msm_adsp_event_data *event_data = NULL; + const char *mixer_ctl_name = DSP_ADM_CALLBACK; + struct snd_ctl_elem_info kctl_info = {0}; + + if (!rtd || !payload) { + pr_err("%s: %s is NULL\n", __func__, + (!rtd) ? "rtd" : "payload"); + ret = -EINVAL; + goto done; + } + + if (rtd->card->snd_card == NULL) { + pr_err("%s: snd_card is null.\n", __func__); + ret = -EINVAL; + goto done; + } + + ctl_len = strlen(mixer_ctl_name) + 1; + mixer_str = kzalloc(ctl_len, GFP_ATOMIC); + if (!mixer_str) { + ret = -EINVAL; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s", mixer_ctl_name); + kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str); + kfree(mixer_str); + if (!kctl) { + pr_err("%s: failed to get kctl.\n", __func__); + ret = -EINVAL; + goto done; + } + + event_data = (struct msm_adsp_event_data *)payload; + kctl->info(kctl, &kctl_info); + if (sizeof(struct msm_adsp_event_data) + + event_data->payload_len > kctl_info.count) { + pr_err("%s: payload length exceeds limit of %u bytes.\n", + __func__, kctl_info.count); + ret = -EINVAL; + goto done; + } + + kctl_prtd = (struct dsp_adm_callback_prtd *) + kctl->private_data; + if (kctl_prtd == NULL) { + /* queue is not initialized */ + ret = -EINVAL; + pr_err("%s: event queue is not initialized.\n", __func__); + goto done; + } + + new_event = kzalloc(sizeof(struct dsp_adm_callback_list) + + event_data->payload_len + sizeof(uint32_t), + GFP_ATOMIC); + if (new_event == NULL) { + ret = -ENOMEM; + goto done; + } + memcpy((void *)&new_event->event, (void *)payload, + event_data->payload_len + + sizeof(struct msm_adsp_event_data)); + + + spin_lock_irqsave(&kctl_prtd->prtd_spin_lock, spin_flags); + while (kctl_prtd->event_count >= DSP_ADM_CALLBACK_QUEUE_SIZE) { + pr_info("%s: queue of size %d is full. delete oldest one.\n", + __func__, DSP_ADM_CALLBACK_QUEUE_SIZE); + oldest_event = list_first_entry(&kctl_prtd->event_queue, + struct dsp_adm_callback_list, list); + pr_info("%s: event deleted: type %d length %d\n", + __func__, oldest_event->event.event_type, + oldest_event->event.payload_len); + list_del(&oldest_event->list); + kctl_prtd->event_count--; + kfree(oldest_event); + } + + list_add_tail(&new_event->list, &kctl_prtd->event_queue); + kctl_prtd->event_count++; + spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags); + + control.id = kctl->id; + + snd_ctl_notify(rtd->card->snd_card, + SNDRV_CTL_EVENT_MASK_INFO, + &control.id); + +done: + return ret; +} + int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd, uint32_t *payload) { diff --git a/asoc/msm-qti-pp-config.h b/asoc/msm-qti-pp-config.h index 7fddb9f49840..b91746e34d36 100644 --- a/asoc/msm-qti-pp-config.h +++ b/asoc/msm-qti-pp-config.h @@ -9,6 +9,14 @@ #include #define DSP_BIT_WIDTH_MIXER_CTL "ASM Bit Width" #ifdef CONFIG_QTI_PP + +int msm_adsp_adm_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd, + uint32_t *payload); +int msm_adsp_init_mixer_ctl_adm_pp_event_queue(struct snd_soc_pcm_runtime *rtd); +int msm_adsp_clean_mixer_ctl_adm_pp_event_queue( + struct snd_soc_pcm_runtime *rtd); +int msm_adsp_copp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd, + uint32_t *payload); int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd, uint32_t *payload); int msm_adsp_init_mixer_ctl_pp_event_queue(struct snd_soc_pcm_runtime *rtd); diff --git a/dsp/q6adm.c b/dsp/q6adm.c index eae22f7c528f..f2ae327ee554 100644 --- a/dsp/q6adm.c +++ b/dsp/q6adm.c @@ -52,6 +52,9 @@ enum adm_cal_status { ADM_STATUS_MAX, }; +typedef int (*adm_cb)(uint32_t opcode, uint32_t token, + uint32_t *pp_event_package, void *pvt); + struct adm_copp { atomic_t id[AFE_MAX_PORTS][MAX_COPPS_PER_PORT]; @@ -71,6 +74,8 @@ struct adm_copp { uint32_t adm_delay[AFE_MAX_PORTS][MAX_COPPS_PER_PORT]; unsigned long adm_status[AFE_MAX_PORTS][MAX_COPPS_PER_PORT]; atomic_t token[AFE_MAX_PORTS][MAX_COPPS_PER_PORT]; + adm_cb cb; + void *priv[AFE_MAX_PORTS][MAX_COPPS_PER_PORT][MAX_FE_ID]; }; struct source_tracking_data { @@ -163,6 +168,93 @@ static int adm_arrange_mch_map_v8( int channel_mode, int port_idx); +static uint32_t adm_pp_raise_event_opcode[] = { + ADM_PP_EVENT }; + +int q6adm_send_event_register_cmd(int port_id, int copp_idx, u8 *data, + int param_size, int opcode) +{ + struct adm_register_event *adm_reg_params = NULL; + int ret = 0, port_idx = 0, sz = 0; + + 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; + } + + sz = sizeof(struct apr_hdr) + param_size; + adm_reg_params = kzalloc(sz, GFP_KERNEL); + + if (!adm_reg_params) + return -ENOMEM; + + memcpy(adm_reg_params->payload, data, param_size); + + adm_reg_params->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); + adm_reg_params->hdr.src_svc = APR_SVC_ADM; + adm_reg_params->hdr.src_domain = APR_DOMAIN_APPS; + adm_reg_params->hdr.src_port = port_id; + adm_reg_params->hdr.dest_svc = APR_SVC_ADM; + adm_reg_params->hdr.dest_domain = APR_DOMAIN_ADSP; + adm_reg_params->hdr.dest_port = + atomic_read(&this_adm.copp.id[port_idx][copp_idx]); + adm_reg_params->hdr.token = port_idx << 16 | copp_idx; + adm_reg_params->hdr.opcode = opcode; + adm_reg_params->hdr.pkt_size = sz; + + atomic_set(&this_adm.copp.stat[port_idx][copp_idx], 0); + ret = apr_send_pkt(this_adm.apr, (uint32_t *)adm_reg_params); + if (ret < 0) { + pr_err("%s: Set adm register 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_reg_params); + + return ret; +} +EXPORT_SYMBOL(q6adm_send_event_register_cmd); + + +static int is_adsp_adm_raise_event(uint32_t cmd) +{ + int i = 0; + for (i = 0; i < ARRAY_SIZE(adm_pp_raise_event_opcode); i++) { + if (cmd == adm_pp_raise_event_opcode[i]) + return i; + } + return -EINVAL; +} + +void q6adm_register_callback(void *cb) +{ + this_adm.copp.cb = cb; +} +EXPORT_SYMBOL(q6adm_register_callback); + +void q6adm_clear_callback(void) +{ + this_adm.copp.cb = NULL; +} +EXPORT_SYMBOL(q6adm_clear_callback); + /** * adm_validate_and_get_port_index - * validate given port id @@ -1578,6 +1670,9 @@ static int32_t adm_callback(struct apr_client_data *data, void *priv) int port_idx, copp_idx, idx, client_id; int num_modules; int ret; + int payload_size = 0, i = 0; + struct msm_adsp_event_data *pp_event_package = NULL; + struct adm_usr_info usr_data = {0}; if (data == NULL) { pr_err("%s: data parameter is null\n", __func__); @@ -1749,6 +1844,13 @@ static int32_t adm_callback(struct apr_client_data *data, void *priv) pr_err("%s: ADM get topo list error = %d\n", __func__, payload[1]); break; + case ADM_CMD_REGISTER_EVENT: + pr_debug("%s:ADM_CMD_REGISTER_EVENT\n", + __func__); + if (payload[1] != 0) + pr_err("%s: ADM_CMD_REGISTER_EVENT error = %d\n", + __func__, payload[1]); + break; default: pr_err("%s: Unknown Cmd: 0x%x\n", __func__, payload[0]); @@ -1859,6 +1961,63 @@ static int32_t adm_callback(struct apr_client_data *data, void *priv) atomic_set(&this_adm.adm_stat, 0); wake_up(&this_adm.adm_wait); break; + case ADM_PP_EVENT: + if (data->payload_size < (2 * sizeof(uint32_t))) { + pr_err("%s: payload has invalid size %d\n", + __func__, data->payload_size); + return -EINVAL; + } + + pr_debug("%s: ADM_PP_EVENT payload[0][0x%x] payload[1][0x%x]\n", + __func__, payload[0], payload[1]); + + ret = is_adsp_adm_raise_event(data->opcode); + + if (ret < 0) + return 0; + + /* + * repack payload for adm_copp_pp_event + * package is composed of event type + size + payload + */ + payload_size = data->payload_size; + pp_event_package = kzalloc(payload_size + + sizeof(struct msm_adsp_event_data) + , GFP_ATOMIC); + + if (!pp_event_package) + return -ENOMEM; + + pp_event_package->event_type = ret + + ADSP_ADM_SERVICE_ID; + usr_data.service_id = ADSP_ADM_SERVICE_ID; + usr_data.token_coppidx = data->token; + + pp_event_package->payload_len = data->payload_size + + sizeof(struct adm_usr_info); + + memcpy((void *)pp_event_package->payload, &(usr_data), + sizeof(struct adm_usr_info)); + + memcpy((void *)pp_event_package->payload + + sizeof(struct adm_usr_info), + data->payload, data->payload_size); + if (this_adm.copp.cb) { + for (i = 0; i < MAX_FE_ID; i++) { + if (this_adm.copp.priv[port_idx] + [copp_idx][i]) { + pr_debug("%s: calling adm callback for feid %d port_idx %d copp_idx %d\n", + __func__, i, port_idx, copp_idx); + this_adm.copp.cb(data->opcode, + data->token, + (void *)pp_event_package, + this_adm.copp.priv[port_idx] + [copp_idx][i]); + } + } + } + kfree(pp_event_package); + break; default: pr_err("%s: Unknown cmd:0x%x\n", __func__, data->opcode); @@ -3006,6 +3165,33 @@ static int adm_arrange_mch_ep2_map_v8( return rc; } +int q6adm_update_rtd_info(void *rtd, int port_id, + int copp_idx, int fe_id, int enable) +{ + int port_idx = 0; + + port_id = q6audio_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 0x%x\n", __func__, port_id); + return -EINVAL; + } + + pr_debug("%s: port_id %#x copp_idx %d fe_id %d enable %d\n", + __func__, port_id, copp_idx, fe_id, enable); + + if (enable) { + this_adm.copp.priv[port_idx][copp_idx][fe_id] = rtd; + } + else { + this_adm.copp.priv[port_idx][copp_idx][fe_id] = NULL; + } + + return 0; +} +EXPORT_SYMBOL(q6adm_update_rtd_info); + static int adm_copp_set_ec_ref_mfc_cfg_v2(int port_id, int copp_idx, int sample_rate, int bps, struct msm_pcm_channel_mixer *cfg) diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h old mode 100755 new mode 100644 index b6bdfeaa2aa5..f1c73e5087b8 --- a/include/dsp/apr_audio-v2.h +++ b/include/dsp/apr_audio-v2.h @@ -30,6 +30,11 @@ struct param_outband { /* Instance ID definitions */ #define INSTANCE_ID_0 0x0000 +struct adm_register_event { + struct apr_hdr hdr; + __u8 payload[0]; +} __packed; + struct mem_mapping_hdr { /* * LSW of parameter data payload address. Supported values: any. @@ -135,6 +140,10 @@ struct module_instance_info { #define ADM_CMD_MATRIX_MAP_ROUTINGS_V5 0x00010325 #define ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5 0x0001033D + +#define ADM_CMD_REGISTER_EVENT 0x00010365 +#define ADM_PP_EVENT 0x00010366 + /* Enumeration for an audio Rx matrix ID.*/ #define ADM_MATRIX_ID_AUDIO_RX 0 @@ -671,6 +680,26 @@ struct dsp_stream_callback_prtd { spinlock_t prtd_spin_lock; }; +#define DSP_ADM_CALLBACK "ADSP COPP Callback Event" +#define DSP_ADM_CALLBACK_QUEUE_SIZE 1024 + +struct dsp_adm_callback_list { + struct list_head list; + struct msm_adsp_event_data event; +}; + +struct adm_usr_info { + u32 service_id; + u32 reserved; + u32 token_coppidx; +}; + +struct dsp_adm_callback_prtd { + uint16_t event_count; + struct list_head event_queue; + spinlock_t prtd_spin_lock; +}; + /* set customized mixing on matrix mixer */ #define ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5 0x00010344 struct adm_cmd_set_pspd_mtmx_strtr_params_v5 { diff --git a/include/dsp/q6adm-v2.h b/include/dsp/q6adm-v2.h index d6c20a962c64..a010b56cb5ac 100644 --- a/include/dsp/q6adm-v2.h +++ b/include/dsp/q6adm-v2.h @@ -16,6 +16,7 @@ #include #define MAX_MODULES_IN_TOPO 16 +#define MAX_FE_ID 33 #define ADM_GET_TOPO_MODULE_LIST_LENGTH\ ((MAX_MODULES_IN_TOPO + 1) * sizeof(uint32_t)) #define ADM_GET_TOPO_MODULE_INSTANCE_LIST_LENGTH \ @@ -246,4 +247,10 @@ void adm_set_native_mode(int mode); int adm_set_ffecns_freeze_event(bool ffecns_freeze_event); int adm_apr_send_pkt(void *data, wait_queue_head_t *wait, int port_idx, int copp_idx, int opcode); +void q6adm_register_callback(void *cb); +void q6adm_clear_callback(void); +int q6adm_send_event_register_cmd(int port_id, int copp_idx, u8 *data, + int param_size, int opcode); +int q6adm_update_rtd_info(void *rtd, int port_id, + int copp_idx, int fe_id, int enable); #endif /* __Q6_ADM_V2_H__ */ diff --git a/include/uapi/audio/linux/msm_audio.h b/include/uapi/audio/linux/msm_audio.h index c072b1363b9d..dda50ebc7fe1 100644 --- a/include/uapi/audio/linux/msm_audio.h +++ b/include/uapi/audio/linux/msm_audio.h @@ -456,6 +456,7 @@ struct msm_hwacc_effects_config { #define ADSP_STREAM_ENCDEC_EVENT 1 #define ADSP_STREAM_IEC_61937_FMT_UPDATE_EVENT 2 #define ADSP_STREAM_EVENT_MAX 3 +#define ADSP_ADM_SERVICE_ID 3 struct msm_adsp_event_data { __u32 event_type; @@ -463,4 +464,17 @@ struct msm_adsp_event_data { __u8 payload[0]; }; +struct module_info_data { + __u32 module_id; + __u32 instance_id; + __u32 be_id; + __u32 fe_id; +}; + +struct msm_adm_event_data { + __u32 event_type; + __u32 payload_length; + struct module_info_data mod_info; + __u8 payload[0]; +}; #endif From 9e4c582937f60d49e57694e72e68789a7ad5bf1c Mon Sep 17 00:00:00 2001 From: Manoj Kumar N D Date: Fri, 18 Nov 2022 17:35:47 +0530 Subject: [PATCH 03/13] asoc : enable mclk after ssr for talos Enable the mclk after the ssr for audio bring up in 6155. Change-Id: I87d5bb2d16a24fd9618eae08e4be75f116ae1a5b Signed-off-by: Manoj Kumar N D --- asoc/sa6155.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/asoc/sa6155.c b/asoc/sa6155.c index b7e9dc49d424..588d0e0df41f 100644 --- a/asoc/sa6155.c +++ b/asoc/sa6155.c @@ -143,6 +143,8 @@ static const char *const tdm_gpio_phandle[] = {"qcom,pri-tdm-gpios", static const char *const mclk_gpio_phandle[] = { "qcom,internal-mclk2-gpios" }; +static bool mclk_enable_status = false; + enum { TDM_0 = 0, TDM_1, @@ -4253,7 +4255,7 @@ static int msm_pinctrl_init(struct platform_device *pdev, enum pinctrl_mode mode ret = -EIO; goto err; } - + mclk_enable_status = true; ret = pinctrl_select_state(pinctrl_info->pinctrl, pinctrl_info->active); if (ret != 0) { pr_err("%s: set pin state to active failed with %d\n", @@ -7567,7 +7569,7 @@ static int sa6155_ssr_enable(struct device *dev, void *data) { struct platform_device *pdev = to_platform_device(dev); struct snd_soc_card *card = platform_get_drvdata(pdev); - int ret = 0; + int ret = 0, i; if (!card) { dev_err(dev, "%s: card is NULL\n", __func__); @@ -7575,6 +7577,19 @@ static int sa6155_ssr_enable(struct device *dev, void *data) goto err; } + if (mclk_enable_status == true) { + for (i = 0; i < MCLK_MAX; i++) { + ret = afe_set_lpass_clock_v2(AFE_PORT_ID_TDM_PORT_RANGE_START, + &internal_mclk[i]); + if (ret < 0) { + pr_err("%s: afe lpass clock failed to enable clock, err:%d\n", + __func__, ret); + ret = -EIO; + goto err; + } + } + } + dev_info(dev, "%s: setting snd_card to ONLINE\n", __func__); #if IS_ENABLED(CONFIG_AUDIO_QGKI) snd_soc_card_change_online_state(card, 1); From 065923bf1b3448e5330c2d83c93607e17fd3b4c1 Mon Sep 17 00:00:00 2001 From: Vaibhav Raut Date: Tue, 20 Dec 2022 15:54:10 +0530 Subject: [PATCH 04/13] asoc: wsa881x: Fix to set the correct volume level To avoid mismatch volume level on WSA8810, update the enum. Change-Id: I01f592d0817d83a1e0ea7b736c0c101e6903cceb Signed-off-by: Shashi Kant Maurya --- asoc/codecs/wsa881x-analog.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/asoc/codecs/wsa881x-analog.c b/asoc/codecs/wsa881x-analog.c index 50ba75bfea6c..57615c414ba8 100755 --- a/asoc/codecs/wsa881x-analog.c +++ b/asoc/codecs/wsa881x-analog.c @@ -75,6 +75,7 @@ struct wsa881x_pdata { int clk_cnt; int enable_cnt; int version; + int wsa881x_id; struct mutex bg_lock; struct mutex res_lock; struct delayed_work ocp_ctl_work; @@ -91,6 +92,10 @@ enum { WSA881X_STATUS_I2C, }; +enum { + WSA8810, + WSA8815, +}; #define WSA881X_OCP_CTL_TIMER_SEC 2 #define WSA881X_OCP_CTL_TEMP_CELSIUS 25 #define WSA881X_OCP_CTL_POLL_TIMER_SEC 60 @@ -119,9 +124,14 @@ static int wsa881x_i2c_addr = -1; static int wsa881x_probing_count; static int wsa881x_presence_count; +/* Gain value maximum of 18dBv supported on WSA8815 +* and maximum of 13.5dBv on WSA8810 +*/ static const char * const wsa881x_spk_pa_gain_text[] = { -"POS_13P5_DB", "POS_12_DB", "POS_10P5_DB", "POS_9_DB", "POS_7P5_DB", -"POS_6_DB", "POS_4P5_DB", "POS_3_DB", "POS_1P5_DB", "POS_0_DB"}; +"POS_18_DB", "POS_16P5_DB", "POS_15_DB", "POS_13P5_DB", +"POS_12_DB", "POS_10P5_DB", "POS_9_DB", "POS_7P5_DB", +"POS_6_DB", "POS_4P5_DB", "POS_3_DB", "POS_1P5_DB", +"POS_0_DB"}; static const struct soc_enum wsa881x_spk_pa_gain_enum[] = { SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wsa881x_spk_pa_gain_text), @@ -158,6 +168,12 @@ static int wsa881x_spk_pa_gain_put(struct snd_kcontrol *kcontrol, __func__, ucontrol->value.integer.value[0]); return -EINVAL; } + if (ucontrol->value.integer.value[0] < 3 && + wsa881x->wsa881x_id == WSA8810) { + dev_err(component->dev, "%s: Unsupported gain val %ld for WSA8810\n", + __func__, ucontrol->value.integer.value[0]); + return -EINVAL; + } wsa881x->spk_pa_gain = ucontrol->value.integer.value[0]; dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", __func__, ucontrol->value.integer.value[0]); @@ -1538,6 +1554,14 @@ static int wsa881x_i2c_probe(struct i2c_client *client, pdata->regmap[WSA881X_DIGITAL_SLAVE], WSA881X_DIGITAL_SLAVE); } + pdata->wsa881x_id = wsa881x_i2c_read_device(pdata, + WSA881X_OTP_REG_0); + if (pdata->wsa881x_id & 0x01) { + pdata->wsa881x_id = WSA8815; + } else { + pdata->wsa881x_id = WSA8810; + } + pr_debug("%s: wsa881x_id : %d\n", __func__, pdata->wsa881x_id); wsa881x_presence_count++; wsa881x_probing_count++; From 7af6a8b6a445f3941703a13a4bb9a5167f13f11e Mon Sep 17 00:00:00 2001 From: Shalini Manjunatha Date: Mon, 19 Dec 2022 19:05:22 +0530 Subject: [PATCH 05/13] asoc: wcd938x/wcd937x: add null pointer check for mbhc variable Whenever MBHC is disabled through kernel config file, particular vaiable of mbhc is not guarded for NULL pointer check causing kernel panic, Hence add NULL check for that pointer variable. Change-Id: Iae4950ceb076239a130b4f033cb2f08cd65a92a9 Signed-off-by: Shalini Manjunatha --- asoc/codecs/wcd937x/wcd937x.c | 8 +++++--- asoc/codecs/wcd938x/wcd938x.c | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/asoc/codecs/wcd937x/wcd937x.c b/asoc/codecs/wcd937x/wcd937x.c index c002574d26b2..7bec6b399a87 100644 --- a/asoc/codecs/wcd937x/wcd937x.c +++ b/asoc/codecs/wcd937x/wcd937x.c @@ -1734,8 +1734,9 @@ static int wcd937x_event_notify(struct notifier_block *block, case BOLERO_SLV_EVT_SSR_DOWN: wcd937x->mbhc->wcd_mbhc.deinit_in_progress = true; mbhc = &wcd937x->mbhc->wcd_mbhc; - wcd937x->usbc_hs_status = get_usbc_hs_status(component, - mbhc->mbhc_cfg); + if(mbhc->mbhc_cfg) + wcd937x->usbc_hs_status = get_usbc_hs_status(component, + mbhc->mbhc_cfg); wcd937x_mbhc_ssr_down(wcd937x->mbhc, component); wcd937x_reset_low(wcd937x->dev); break; @@ -1755,7 +1756,8 @@ static int wcd937x_event_notify(struct notifier_block *block, dev_err(component->dev, "%s: mbhc initialization failed\n", __func__); } else { - wcd937x_mbhc_hs_detect(component, mbhc->mbhc_cfg); + if(mbhc->mbhc_cfg) + wcd937x_mbhc_hs_detect(component, mbhc->mbhc_cfg); if (wcd937x->usbc_hs_status) mdelay(500); } diff --git a/asoc/codecs/wcd938x/wcd938x.c b/asoc/codecs/wcd938x/wcd938x.c index 1a976b86007d..3448e41f0727 100644 --- a/asoc/codecs/wcd938x/wcd938x.c +++ b/asoc/codecs/wcd938x/wcd938x.c @@ -2161,8 +2161,9 @@ static int wcd938x_event_notify(struct notifier_block *block, NULL); wcd938x->mbhc->wcd_mbhc.deinit_in_progress = true; mbhc = &wcd938x->mbhc->wcd_mbhc; - wcd938x->usbc_hs_status = get_usbc_hs_status(component, - mbhc->mbhc_cfg); + if(mbhc->mbhc_cfg) + wcd938x->usbc_hs_status = get_usbc_hs_status(component, + mbhc->mbhc_cfg); wcd938x_mbhc_ssr_down(wcd938x->mbhc, component); wcd938x_reset_low(wcd938x->dev); break; @@ -2184,7 +2185,8 @@ static int wcd938x_event_notify(struct notifier_block *block, dev_err(component->dev, "%s: mbhc initialization failed\n", __func__); } else { - wcd938x_mbhc_hs_detect(component, mbhc->mbhc_cfg); + if(mbhc->mbhc_cfg) + wcd938x_mbhc_hs_detect(component, mbhc->mbhc_cfg); } wcd938x->mbhc->wcd_mbhc.deinit_in_progress = false; wcd938x->dev_up = true; From 3aea11c50c57a8b9a23078e5d9c47ea40a226e4c Mon Sep 17 00:00:00 2001 From: Shalini Manjunatha Date: Mon, 5 Dec 2022 11:18:20 +0530 Subject: [PATCH 06/13] asoc: lahaina: set correct swr port map when wcd disabled When wcd is disabled, due to incorrect swr port map being set, crash is seen. Hence set correct default port map for SWR through corresponding bolero macro. Change-Id: Ib17642832f98fb47c9e571cf7763f38a191bdfba Signed-off-by: Shalini Manjunatha --- asoc/lahaina.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/asoc/lahaina.c b/asoc/lahaina.c index f5ad209553b9..191f4b9960ee 100644 --- a/asoc/lahaina.c +++ b/asoc/lahaina.c @@ -7919,6 +7919,8 @@ static int msm_rx_tx_codec_init(struct snd_soc_pcm_runtime *rtd) bolero_register_wake_irq(component, false); if (pdata->wcd_disabled) { + bolero_set_port_map(bolero_component, + ARRAY_SIZE(sm_port_map), sm_port_map); codec_reg_done = true; return 0; } From 9e949d228f101118550895a92eefcefd60f96281 Mon Sep 17 00:00:00 2001 From: Manoj Kumar N D Date: Mon, 14 Nov 2022 19:14:09 +0530 Subject: [PATCH 07/13] asoc : send chanel mixer while rerouting sound device Channel mixer has to sent while the sound devices are rerouted as capture/playback prepare will not be called during rerouting. Change-Id: I8473d89c7aff9f5f2a1dd2f3f4a8fa5d387b2429 Signed-off-by: Manoj Kumar N D --- asoc/msm-pcm-routing-auto.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/asoc/msm-pcm-routing-auto.c b/asoc/msm-pcm-routing-auto.c index f8e15f51fc24..10e94d74f8f9 100644 --- a/asoc/msm-pcm-routing-auto.c +++ b/asoc/msm-pcm-routing-auto.c @@ -32338,6 +32338,9 @@ static int msm_pcm_routing_prepare(struct snd_pcm_substream *substream) (fdai->passthr_mode == LEGACY_PCM)) msm_pcm_routing_cfg_pp(port_id, copp_idx, topology, channels); + if(msm_pcm_routing_channel_mixer(i, fdai->perf_mode,fdai->strm_id, session_type)){ + pr_err("%s: failed to send channel mixer \n", __func__); + } } } From 7d196f8368cffb9a735f3f58531e7b4a63e820dc Mon Sep 17 00:00:00 2001 From: Manoj Kumar N D Date: Tue, 13 Dec 2022 12:16:31 +0530 Subject: [PATCH 08/13] dsp : assign null to pointer that has freed address After freeing up the memory assign null to the pointer that had the address. Change-Id: I242a936c434dc449ec9fd19b0c34e843c3cf0913 Signed-off-by: Manoj Kumar N D --- dsp/audio_cal_utils.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dsp/audio_cal_utils.c b/dsp/audio_cal_utils.c index 01e9c349142d..1406088b4ea6 100644 --- a/dsp/audio_cal_utils.c +++ b/dsp/audio_cal_utils.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include @@ -458,6 +459,7 @@ static void delete_cal_block(struct cal_block_data *cal_block) cal_block->map_data.dma_buf = NULL; } kfree(cal_block); + cal_block = NULL; done: return; } From 02230ca65b59b3290245dee87acafef0d8943226 Mon Sep 17 00:00:00 2001 From: Soumya Managoli Date: Fri, 6 Jan 2023 14:37:20 +0530 Subject: [PATCH 09/13] ASoC: msm-pcm-q6-v2: Add dsp buf check Current logic copies user buf size of data from the avail dsp buf at a given offset. If this offset returned from DSP in READ_DONE event goes out of bounds or is corrupted, then it can lead to out of bounds DSP buffer access, resulting in memory fault. Fix is to add check for this buf offset, if it is within the buf size range. Change-Id: I7753cc6db394704dbb959477150141d42b836bef Signed-off-by: Soumya Managoli --- asoc/msm-pcm-q6-v2.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/asoc/msm-pcm-q6-v2.c b/asoc/msm-pcm-q6-v2.c index 1dfa857be5ea..b26ae17520c7 100644 --- a/asoc/msm-pcm-q6-v2.c +++ b/asoc/msm-pcm-q6-v2.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ /* * Add support for 24 and 32bit format for ASM loopback and playback session. @@ -1328,6 +1328,14 @@ static int msm_pcm_capture_copy(struct snd_pcm_substream *substream, xfer = size; offset = prtd->in_frame_info[idx].offset; pr_debug("Offset value = %d\n", offset); + + if (offset >= size) { + pr_err("%s: Invalid dsp buf offset\n", __func__); + ret = -EFAULT; + q6asm_cpu_buf_release(OUT, prtd->audio_client); + goto fail; + } + if (size == 0 || size < prtd->pcm_count) { memset(bufptr + offset + size, 0, prtd->pcm_count - size); if (fbytes > prtd->pcm_count) From 89e9d61385b76b5f47c9215b82dcec079645e12b Mon Sep 17 00:00:00 2001 From: Soumya Managoli Date: Mon, 12 Dec 2022 12:22:23 +0530 Subject: [PATCH 10/13] ASoC: Add check for pm_qos_req before removal Check if pm_qos_req is active before removal. Change-Id: I0076a73ffa6310dbb4cb207ca7a651aa1d3fdf04 Signed-off-by: Soumya Managoli --- asoc/msm-pcm-hostless.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/asoc/msm-pcm-hostless.c b/asoc/msm-pcm-hostless.c index 63c5db85fe42..aaf714bc9907 100644 --- a/asoc/msm-pcm-hostless.c +++ b/asoc/msm-pcm-hostless.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2011-2014, 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -18,7 +19,8 @@ static int msm_pcm_hostless_prepare(struct snd_pcm_substream *substream) pr_err("%s: invalid params\n", __func__); return -EINVAL; } - pm_qos_remove_request(&substream->latency_pm_qos_req); + if (pm_qos_request_active(&substream->latency_pm_qos_req)) + pm_qos_remove_request(&substream->latency_pm_qos_req); return 0; } From b12f10836f3120d0e614ae1f34705435c7e53ce6 Mon Sep 17 00:00:00 2001 From: ronghuiz Date: Wed, 1 Feb 2023 10:28:05 +0800 Subject: [PATCH 11/13] asoc: kona: Add QUAD I2S EBIT clk define to kona Hdmi-in used QUAD-I2S to input, need configure I2S to slave mode. Change-Id: I1d27d51c766538bb8f61cd74c5dcb6cc18954e81 Signed-off-by: ronghuiz --- asoc/kona.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/asoc/kona.c b/asoc/kona.c index 2c1a86c8b973..d801702c667c 100644 --- a/asoc/kona.c +++ b/asoc/kona.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -328,6 +328,7 @@ static u32 mi2s_ebit_clk[MI2S_MAX] = { Q6AFE_LPASS_CLK_ID_PRI_MI2S_EBIT, Q6AFE_LPASS_CLK_ID_SEC_MI2S_EBIT, Q6AFE_LPASS_CLK_ID_TER_MI2S_EBIT, + Q6AFE_LPASS_CLK_ID_QUAD_MI2S_EBIT, }; static struct mi2s_conf mi2s_intf_conf[MI2S_MAX]; From 8972574067e47c05d4011e9bea21110e5b372cfe Mon Sep 17 00:00:00 2001 From: Boyuan Yan Date: Tue, 7 Feb 2023 14:51:14 +0530 Subject: [PATCH 12/13] asoc: Add build option for qcs6490 Add build option for qcs6490. Change-Id: I2cd3ac1e296c8eb64702d26d0cb461052bc3ade2 Signed-off-by: Boyuan Yan --- Makefile.am | 10 ++++++++++ asoc/Kbuild | 5 +++++ asoc/codecs/Kbuild | 5 +++++ asoc/codecs/bolero/Kbuild | 5 +++++ asoc/codecs/wcd937x/Kbuild | 5 +++++ asoc/codecs/wcd938x/Kbuild | 5 +++++ asoc/codecs/wsa883x/Kbuild | 1 + dsp/Kbuild | 4 ++++ dsp/codecs/Kbuild | 5 +++++ ipc/Kbuild | 5 +++++ soc/Kbuild | 5 +++++ 11 files changed, 55 insertions(+) diff --git a/Makefile.am b/Makefile.am index 5a1b82f16a5f..e9fd72731fa5 100755 --- a/Makefile.am +++ b/Makefile.am @@ -18,6 +18,9 @@ endif ifeq ($(TARGET_SUPPORT), qrb5165) KBUILD_OPTIONS += CONFIG_ARCH_KONA=y endif +ifeq ($(TARGET_SUPPORT), qcs6490) +KBUILD_OPTIONS += CONFIG_ARCH_LAHAINA=y +endif subdir-ccflags-y += -I$(AUDIO_ROOT)/include/uapi/ @@ -48,6 +51,13 @@ obj-m += asoc/codecs/wcd938x/ bj-m += asoc/codecs/wsa883x/ KBUILD_CFLAGS += -Wno-error endif +ifeq ($(TARGET_SUPPORT), $(filter $(TARGET_SUPPORT), qcs6490)) +obj-m += asoc/codecs/bolero/ +obj-m += asoc/codecs/wcd937x/ +obj-m += asoc/codecs/wcd938x/ +obj-m += asoc/codecs/wsa883x/ +KBUILD_CFLAGS += -Wno-error +endif ifeq ($(TARGET_SUPPORT), sdmsteppe) obj-m += asoc/codecs/bolero/ obj-m += asoc/codecs/wcd937x/ diff --git a/asoc/Kbuild b/asoc/Kbuild index 6014ba9c5634..c3a0458ccf3e 100755 --- a/asoc/Kbuild +++ b/asoc/Kbuild @@ -72,6 +72,11 @@ else include $(AUDIO_ROOT)/config/konaauto.conf INCS += -include $(AUDIO_ROOT)/config/konaautoconf.h endif + ifeq ($(CONFIG_ARCH_LAHAINA), y) + include $(AUDIO_ROOT)/config/lahainaauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/lahainaautoconf.h + endif ifeq ($(CONFIG_ARCH_LITO), y) include $(AUDIO_ROOT)/config/litoauto.conf export diff --git a/asoc/codecs/Kbuild b/asoc/codecs/Kbuild index 8f19011f6f02..e8cb6f140854 100755 --- a/asoc/codecs/Kbuild +++ b/asoc/codecs/Kbuild @@ -72,6 +72,11 @@ else include $(AUDIO_ROOT)/config/konaauto.conf INCS += -include $(AUDIO_ROOT)/config/konaautoconf.h endif + ifeq ($(CONFIG_ARCH_LAHAINA), y) + include $(AUDIO_ROOT)/config/lahainaauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/lahainaautoconf.h + endif ifeq ($(CONFIG_ARCH_LITO), y) include $(AUDIO_ROOT)/config/litoauto.conf export diff --git a/asoc/codecs/bolero/Kbuild b/asoc/codecs/bolero/Kbuild index a6a11c1a0e7d..4552b59ea7ee 100644 --- a/asoc/codecs/bolero/Kbuild +++ b/asoc/codecs/bolero/Kbuild @@ -30,6 +30,11 @@ ifeq ($(KERNEL_BUILD), 0) include $(AUDIO_ROOT)/config/konaauto.conf INCS += -include $(AUDIO_ROOT)/config/konaautoconf.h endif + ifeq ($(CONFIG_ARCH_LAHAINA), y) + include $(AUDIO_ROOT)/config/lahainaauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/lahainaautoconf.h + endif ifeq ($(CONFIG_ARCH_LITO), y) include $(AUDIO_ROOT)/config/litoauto.conf export diff --git a/asoc/codecs/wcd937x/Kbuild b/asoc/codecs/wcd937x/Kbuild index c7286d0cd875..12efaf338108 100644 --- a/asoc/codecs/wcd937x/Kbuild +++ b/asoc/codecs/wcd937x/Kbuild @@ -36,6 +36,11 @@ ifeq ($(KERNEL_BUILD), 0) export INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h endif + ifeq ($(CONFIG_ARCH_LAHAINA), y) + include $(AUDIO_ROOT)/config/lahainaauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/lahainaautoconf.h + endif endif # As per target team, build is done as follows: diff --git a/asoc/codecs/wcd938x/Kbuild b/asoc/codecs/wcd938x/Kbuild index 873a7b29d434..21181c0f8b5f 100644 --- a/asoc/codecs/wcd938x/Kbuild +++ b/asoc/codecs/wcd938x/Kbuild @@ -23,6 +23,11 @@ ifeq ($(KERNEL_BUILD), 0) export INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h endif + ifeq ($(CONFIG_ARCH_LAHAINA), y) + include $(AUDIO_ROOT)/config/lahainaauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/lahainaautoconf.h + endif endif diff --git a/asoc/codecs/wsa883x/Kbuild b/asoc/codecs/wsa883x/Kbuild index 6cda76756dc2..e9ca09d0eb60 100644 --- a/asoc/codecs/wsa883x/Kbuild +++ b/asoc/codecs/wsa883x/Kbuild @@ -16,6 +16,7 @@ endif ifeq ($(KERNEL_BUILD), 0) ifeq ($(CONFIG_ARCH_LAHAINA), y) include $(AUDIO_ROOT)/config/lahainaauto.conf + export INCS += -include $(AUDIO_ROOT)/config/lahainaautoconf.h endif ifeq ($(CONFIG_ARCH_LITO), y) diff --git a/dsp/Kbuild b/dsp/Kbuild index 2c5506ff7c5c..060ce5d88009 100755 --- a/dsp/Kbuild +++ b/dsp/Kbuild @@ -61,6 +61,10 @@ else include $(AUDIO_ROOT)/config/konaauto.conf INCS += -include $(AUDIO_ROOT)/config/konaautoconf.h endif + ifeq ($(CONFIG_ARCH_LAHAINA), y) + include $(AUDIO_ROOT)/config/lahainaauto.conf + INCS += -include $(AUDIO_ROOT)/config/lahainaautoconf.h + endif ifeq ($(CONFIG_ARCH_LITO), y) include $(AUDIO_ROOT)/config/litoauto.conf export diff --git a/dsp/codecs/Kbuild b/dsp/codecs/Kbuild index 68b05ffacced..c87c4224de79 100644 --- a/dsp/codecs/Kbuild +++ b/dsp/codecs/Kbuild @@ -28,6 +28,11 @@ ifeq ($(KERNEL_BUILD), 0) include $(AUDIO_ROOT)/config/konaauto.conf INCS += -include $(AUDIO_ROOT)/config/konaautoconf.h endif + ifeq ($(CONFIG_ARCH_LAHAINA), y) + include $(AUDIO_ROOT)/config/lahainaauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/lahainaautoconf.h + endif ifeq ($(CONFIG_ARCH_LITO), y) include $(AUDIO_ROOT)/config/litoauto.conf export diff --git a/ipc/Kbuild b/ipc/Kbuild index 06a1f42b9063..1a70731e6dfc 100755 --- a/ipc/Kbuild +++ b/ipc/Kbuild @@ -62,6 +62,11 @@ else include $(AUDIO_ROOT)/config/konaauto.conf INCS += -include $(AUDIO_ROOT)/config/konaautoconf.h endif + ifeq ($(CONFIG_ARCH_LAHAINA), y) + include $(AUDIO_ROOT)/config/lahainaauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/lahainaautoconf.h + endif ifeq ($(CONFIG_ARCH_LITO), y) include $(AUDIO_ROOT)/config/litoauto.conf export diff --git a/soc/Kbuild b/soc/Kbuild index edb9aeee478b..6548624ad390 100755 --- a/soc/Kbuild +++ b/soc/Kbuild @@ -56,6 +56,11 @@ else include $(AUDIO_ROOT)/config/konaauto.conf INCS += -include $(AUDIO_ROOT)/config/konaautoconf.h endif + ifeq ($(CONFIG_ARCH_LAHAINA), y) + include $(AUDIO_ROOT)/config/lahainaauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/lahainaautoconf.h + endif ifeq ($(CONFIG_ARCH_LITO), y) include $(AUDIO_ROOT)/config/litoauto.conf export From 60eaf5fe50079a65a815e04d08cdd4b2de629b33 Mon Sep 17 00:00:00 2001 From: Manoj Kumar N D Date: Tue, 7 Feb 2023 18:47:55 +0530 Subject: [PATCH 13/13] asoc : mark used cal block as stale Mark the used cal block as stale so that it is not reused. Change-Id: I142d21d6d32a1b5ad24c3a2708b1df023d70947e Signed-off-by: Manoj Kumar N D --- asoc/msm-pcm-routing-auto.c | 1 + 1 file changed, 1 insertion(+) diff --git a/asoc/msm-pcm-routing-auto.c b/asoc/msm-pcm-routing-auto.c index 10e94d74f8f9..73960cb46e65 100644 --- a/asoc/msm-pcm-routing-auto.c +++ b/asoc/msm-pcm-routing-auto.c @@ -1818,6 +1818,7 @@ static int msm_routing_find_topology_on_index(int fedai_id, int session_type, in if (cal_block != NULL) { topology = ((struct audio_cal_info_adm_top *) cal_block->cal_info)->topology; + cal_utils_mark_cal_used(cal_block); } mutex_unlock(&cal_data[idx]->lock); return topology;