diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index e098e2329ac6..7564f4881e3f 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -6768,6 +6768,12 @@ struct admx_mic_gain { /*< Clients must set this field to zero. */ } __packed; +struct adm_set_mic_gain_params { + struct adm_cmd_set_pp_params_v5 params; + struct adm_param_data_v5 data; + struct admx_mic_gain mic_gain_data; +} __packed; + /* end_addtogroup audio_pp_param_ids */ /* @ingroup audio_pp_module_ids diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h index c9a429d8607d..806c0778253b 100644 --- a/include/sound/q6adm-v2.h +++ b/include/sound/q6adm-v2.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -130,6 +130,8 @@ int adm_set_volume(int port_id, int copp_idx, int volume); int adm_set_softvolume(int port_id, int copp_idx, struct audproc_softvolume_params *softvol_param); +int adm_set_mic_gain(int port_id, int copp_idx, int volume); + int adm_param_enable(int port_id, int copp_idx, int module_id, int enable); int adm_send_calibration(int port_id, int copp_idx, int path, int perf_mode, diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c index 832d7c0170f4..ccd098d65160 100644 --- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c +++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c @@ -81,6 +81,10 @@ static int msm_route_hfp_vol_control; static const DECLARE_TLV_DB_LINEAR(hfp_rx_vol_gain, 0, INT_RX_VOL_MAX_STEPS); +static int msm_route_icc_vol_control; +static const DECLARE_TLV_DB_LINEAR(icc_rx_vol_gain, 0, + INT_RX_VOL_MAX_STEPS); + static int msm_route_pri_auxpcm_lb_vol_ctrl; static const DECLARE_TLV_DB_LINEAR(pri_auxpcm_lb_vol_gain, 0, INT_RX_VOL_MAX_STEPS); @@ -493,6 +497,23 @@ static int msm_qti_pp_set_slimbus_8_lb_vol_mixer(struct snd_kcontrol *kcontrol, return ret; } +static int msm_qti_pp_get_icc_vol_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = msm_route_icc_vol_control; + return 0; +} + +static int msm_qti_pp_set_icc_vol_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + adm_set_mic_gain(AFE_PORT_ID_QUATERNARY_TDM_TX, + adm_get_default_copp_idx(AFE_PORT_ID_QUATERNARY_TDM_TX), + ucontrol->value.integer.value[0]); + msm_route_icc_vol_control = ucontrol->value.integer.value[0]; + return 0; +} + static int msm_qti_pp_get_quat_mi2s_fm_vol_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -809,6 +830,12 @@ static const struct snd_kcontrol_new int_hfp_vol_mixer_controls[] = { msm_qti_pp_set_hfp_vol_mixer, hfp_rx_vol_gain), }; +static const struct snd_kcontrol_new int_icc_vol_mixer_controls[] = { + SOC_SINGLE_EXT_TLV("Internal ICC Volume", SND_SOC_NOPM, 0, + INT_RX_VOL_GAIN, 0, msm_qti_pp_get_icc_vol_mixer, + msm_qti_pp_set_icc_vol_mixer, icc_rx_vol_gain), +}; + static const struct snd_kcontrol_new pri_auxpcm_lb_vol_mixer_controls[] = { SOC_SINGLE_EXT_TLV("PRI AUXPCM LOOPBACK Volume", AFE_PORT_ID_PRIMARY_PCM_TX, 0, INT_RX_VOL_GAIN, 0, @@ -1001,6 +1028,9 @@ void msm_qti_pp_add_controls(struct snd_soc_platform *platform) snd_soc_add_platform_controls(platform, int_hfp_vol_mixer_controls, ARRAY_SIZE(int_hfp_vol_mixer_controls)); + snd_soc_add_platform_controls(platform, int_icc_vol_mixer_controls, + ARRAY_SIZE(int_icc_vol_mixer_controls)); + snd_soc_add_platform_controls(platform, pri_auxpcm_lb_vol_mixer_controls, ARRAY_SIZE(pri_auxpcm_lb_vol_mixer_controls)); diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c index 30876b52ec9e..3a4cb988ab02 100644 --- a/sound/soc/msm/qdsp6v2/q6adm.c +++ b/sound/soc/msm/qdsp6v2/q6adm.c @@ -3471,6 +3471,84 @@ fail_cmd: return rc; } +int adm_set_mic_gain(int port_id, int copp_idx, int volume) +{ + struct adm_set_mic_gain_params mic_gain_params; + int rc = 0; + int sz, port_idx; + + pr_debug("%s:\n", __func__); + 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 0x%x\n", __func__, port_id); + return -EINVAL; + } + + sz = sizeof(struct adm_set_mic_gain_params); + + mic_gain_params.params.hdr.hdr_field = + APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); + mic_gain_params.params.hdr.pkt_size = sz; + mic_gain_params.params.hdr.src_svc = APR_SVC_ADM; + mic_gain_params.params.hdr.src_domain = APR_DOMAIN_APPS; + mic_gain_params.params.hdr.src_port = port_id; + mic_gain_params.params.hdr.dest_svc = APR_SVC_ADM; + mic_gain_params.params.hdr.dest_domain = APR_DOMAIN_ADSP; + mic_gain_params.params.hdr.dest_port = + atomic_read(&this_adm.copp.id[port_idx][copp_idx]); + mic_gain_params.params.hdr.token = port_idx << 16 | copp_idx; + mic_gain_params.params.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5; + mic_gain_params.params.payload_addr_lsw = 0; + mic_gain_params.params.payload_addr_msw = 0; + mic_gain_params.params.mem_map_handle = 0; + mic_gain_params.params.payload_size = + sizeof(struct adm_param_data_v5) + + sizeof(struct admx_mic_gain); + mic_gain_params.data.module_id = ADM_MODULE_IDX_MIC_GAIN_CTRL; + mic_gain_params.data.param_id = ADM_PARAM_IDX_MIC_GAIN; + mic_gain_params.data.param_size = + sizeof(struct admx_mic_gain); + mic_gain_params.data.reserved = 0; + mic_gain_params.mic_gain_data.tx_mic_gain = volume; + mic_gain_params.mic_gain_data.reserved = 0; + pr_debug("%s: Mic Gain set to %d at port_id 0x%x\n", + __func__, volume, port_id); + + atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1); + rc = apr_send_pkt(this_adm.apr, (uint32_t *)&mic_gain_params); + if (rc < 0) { + pr_err("%s: Set params failed port = %#x\n", + __func__, port_id); + rc = -EINVAL; + goto fail_cmd; + } + /* Wait for the callback */ + rc = 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 (!rc) { + pr_err("%s: Mic Gain Set params timed out port = %#x\n", + __func__, port_id); + rc = -EINVAL; + goto fail_cmd; + } else if (atomic_read(&this_adm.copp.stat + [port_idx][copp_idx]) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&this_adm.copp.stat + [port_idx][copp_idx]))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&this_adm.copp.stat + [port_idx][copp_idx])); + goto fail_cmd; + } + rc = 0; +fail_cmd: + return rc; +} + int adm_param_enable(int port_id, int copp_idx, int module_id, int enable) { struct audproc_enable_param_t adm_mod_enable;