From 66c053253b7bd5a2395735906d3402a53498f54e Mon Sep 17 00:00:00 2001 From: Soumya Managoli Date: Thu, 3 Nov 2022 16:51:00 +0530 Subject: [PATCH 1/5] 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 2/5] 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 @@ done: 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 3/5] 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 4/5] 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 3aea11c50c57a8b9a23078e5d9c47ea40a226e4c Mon Sep 17 00:00:00 2001 From: Shalini Manjunatha Date: Mon, 5 Dec 2022 11:18:20 +0530 Subject: [PATCH 5/5] 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; }