From b61865d95c7d74150694edf66d11cae3862af64c Mon Sep 17 00:00:00 2001 From: Prabhu Annabathula <prabhu.annabathula@motorola.com> Date: Thu, 25 Sep 2014 20:32:14 -0500 Subject: [PATCH] ASoC msm: add controls for motorola audio effects appi module Module used for Loudspeaker Quality Optimizations and Bass Enhancement Change-Id: I20299f789840380e962c6d35935cd1194576aa3a Signed-off-by: Prabhu Annabathula <prabhu.annabathula@motorola.com> --- include/sound/apr_audio-v2.h | 15 +++ include/sound/q6asm-v2.h | 2 + include/uapi/sound/audio_effects.h | 28 +++++ .../soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c | 59 +++++++++ .../soc/msm/qdsp6v2/msm-audio-effects-q6-v2.h | 5 + sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c | 112 +++++++++++++++++- sound/soc/msm/qdsp6v2/msm-qti-pp-config.c | 93 ++++++++++++++- sound/soc/msm/qdsp6v2/q6asm.c | 48 ++++++++ 8 files changed, 357 insertions(+), 5 deletions(-) diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index f281d54fc027..ed1f80c501f6 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -5045,6 +5045,21 @@ struct Audio_AigParam { } __packed; +#define AUDPROC_MODULE_ID_MMIFX (0x1000E0B0) +#define AUDPROC_PARAM_ID_MMIFX_ENABLE (0x1000E3B0) +#define AUDPROC_PARAM_ID_MMIFX_PRESET (0x1000E3A0) +#define AUDPROC_PARAM_ID_MMIFX_TABLE (0x1000E300) +#define AUDPROC_PARAM_ID_MMIFX_DEVICE (0x1000E310) + +struct asm_mmfx_enable_config { + struct apr_hdr hdr; + struct asm_stream_cmd_set_pp_params_v2 param; + struct asm_stream_param_data_v2 data; + uint32_t enable_flag; +/*< Specifies whether mmfx eq is disabled (0) or enabled (nonzero).*/ + +} __packed; + #define ADM_MODULE_ID_EANS 0x00010C4A #define ADM_PARAM_ID_EANS_ENABLE 0x00010C4B diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h index 95621de24932..66823366c31e 100644 --- a/include/sound/q6asm-v2.h +++ b/include/sound/q6asm-v2.h @@ -422,4 +422,6 @@ int q6asm_send_meta_data(struct audio_client *ac, uint32_t initial_samples, int q6asm_stream_send_meta_data(struct audio_client *ac, uint32_t stream_id, uint32_t initial_samples, uint32_t trailing_samples); +int q6asm_mmfxeq(struct audio_client *ac, uint32_t enable); + #endif /* __Q6_ASM_H__ */ diff --git a/include/uapi/sound/audio_effects.h b/include/uapi/sound/audio_effects.h index 4071a6e37b6d..0c0ae45328e9 100644 --- a/include/uapi/sound/audio_effects.h +++ b/include/uapi/sound/audio_effects.h @@ -280,4 +280,32 @@ struct eq_params { uint32_t freq_millihertz; }; +#define MMIFX_EQ_MODULE 0x00005000 +#define MMIFX_EQ_ENABLE 0x00005001 +#define MMIFX_EQ_PRESET 0x00005020 +#define MMIFX_EQ_DEVICE 0x00005300 + + + +#define MMIFX_ENABLE_PARAM_LEN 1 +#define MMIFX_ENABLE_PARAM_SZ \ + (MMIFX_ENABLE_PARAM_LEN*sizeof(uint32_t)) +#define MMIFX_PARAM_LEN 1 +#define MMIFX_PRESET_PARAM_SZ \ + (MMIFX_PARAM_LEN*sizeof(uint32_t)) +#define MMIFX_PARAM_TABLE_LEN 2000 +#define MMIFX_PARAM_TABLE_SZ \ + (MMIFX_PARAM_TABLE_LEN*sizeof(uint16_t)) +#define MMIFX_DEVICE_PARAM_SZ \ + (MMIFX_PARAM_LEN*sizeof(uint32_t)) + + +struct mmi_eq_params { + uint32_t device; + uint32_t enable_flag; + uint32_t preset; +}; + + #endif /*_MSM_AUDIO_EFFECTS_H*/ + diff --git a/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c index 5e4d9d3209c9..7efde8bbe83a 100644 --- a/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c @@ -719,3 +719,62 @@ invalid_config: kfree(params); return rc; } + +int msm_audio_effects_mmifx_send_eq_params(struct audio_client *ac, + struct mmi_eq_params *mmifx, uint32_t cmds) +{ + char *params; + int *updt_params; + uint32_t params_length = (MAX_INBAND_PARAM_SZ); + + pr_debug("%s\n", __func__); + if (!ac) { + pr_err("%s: cannot set audio effects\n", __func__); + return -EINVAL; + } + params = kzalloc(params_length, GFP_KERNEL); + if (!params) { + pr_err("%s, params memory alloc failed\n", __func__); + return -ENOMEM; + + } + updt_params = (int *)params; + params_length = 0; + + if ((cmds & MMIFX_EQ_ENABLE) == MMIFX_EQ_ENABLE) { + pr_debug("%s: MMIFX_EQ_ENABLE %d\n", __func__, mmifx->enable_flag); + *updt_params++ = AUDPROC_MODULE_ID_MMIFX; + *updt_params++ = AUDPROC_PARAM_ID_MMIFX_ENABLE; + *updt_params++ = MMIFX_ENABLE_PARAM_SZ; + *updt_params++ = mmifx->enable_flag; + params_length += COMMAND_PAYLOAD_SZ + + MMIFX_ENABLE_PARAM_SZ; + } + + if ((cmds & MMIFX_EQ_PRESET) == MMIFX_EQ_PRESET) { + pr_debug("%s: MMIFX_EQ_PRESET %d\n", __func__, mmifx->preset); + *updt_params++ = AUDPROC_MODULE_ID_MMIFX; + *updt_params++ = AUDPROC_PARAM_ID_MMIFX_ENABLE; + *updt_params++ = MMIFX_ENABLE_PARAM_SZ; + *updt_params++ = mmifx->preset; + params_length += COMMAND_PAYLOAD_SZ + + MMIFX_ENABLE_PARAM_SZ; + } + + if ((cmds & MMIFX_EQ_DEVICE) == MMIFX_EQ_DEVICE) { + pr_debug("%s: MMIFX_EQ_DEVICE %d\n", __func__, mmifx->device); + *updt_params++ = AUDPROC_MODULE_ID_MMIFX; + *updt_params++ = AUDPROC_PARAM_ID_MMIFX_ENABLE; + *updt_params++ = MMIFX_ENABLE_PARAM_SZ; + *updt_params++ = mmifx->device; + params_length += COMMAND_PAYLOAD_SZ + + MMIFX_ENABLE_PARAM_SZ; + } + + if (params_length) + q6asm_send_audio_effects_params(ac, params, + params_length); + + kfree(params); + return 0; +} diff --git a/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.h index 3d2e6d4065c4..687a2b22d12d 100644 --- a/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.h +++ b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.h @@ -30,4 +30,9 @@ int msm_audio_effects_virtualizer_handler(struct audio_client *ac, int msm_audio_effects_popless_eq_handler(struct audio_client *ac, struct eq_params *eq, long *values); +int msm_audio_effects_mmifx_eq_handler(struct audio_client *ac, + struct mmi_eq_params *mmifx, + long *values); +int msm_audio_effects_mmifx_send_eq_params(struct audio_client *ac, + struct mmi_eq_params *mmifx, uint32_t cmds); #endif /*_MSM_AUDIO_EFFECTS_H*/ diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index ad0479706324..060b0e1e2af1 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -162,6 +162,14 @@ struct msm_compr_audio_effects { struct eq_params equalizer; }; +struct mmi_eq_vals { + struct mmi_eq_params eq_params; + uint32_t num_cmds; + uint32_t cmds; +}; + +struct mmi_eq_vals mmifx[MSM_FRONTEND_DAI_MAX]; + struct msm_compr_dec_params { struct snd_dec_ddp ddp_params; }; @@ -734,7 +742,8 @@ static int msm_compr_open(struct snd_compr_stream *cstream) prtd->cstream = cstream; pdata->cstream[rtd->dai_link->be_id] = cstream; pdata->audio_effects[rtd->dai_link->be_id] = - kzalloc(sizeof(struct msm_compr_audio_effects), GFP_KERNEL); + kzalloc(sizeof(struct msm_compr_audio_effects), GFP_KERNEL); + if (!pdata->audio_effects[rtd->dai_link->be_id]) { pr_err("%s: Could not allocate memory for effects\n", __func__); pdata->cstream[rtd->dai_link->be_id] = NULL; @@ -1119,6 +1128,15 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) if (rc) pr_err("%s : Set Volume failed : %d\n", __func__, rc); + + if (mmifx[fe_id].cmds != 0) { + pr_debug("%s: Update MMIFX EQ Module params send\n", __func__); + msm_audio_effects_mmifx_send_eq_params(prtd->audio_client, + &(mmifx[fe_id].eq_params), + mmifx[fe_id].cmds); + mmifx[fe_id].cmds = 0; + } + break; case SNDRV_PCM_TRIGGER_STOP: spin_lock_irqsave(&prtd->lock, flags); @@ -1793,6 +1811,70 @@ static int msm_compr_volume_get(struct snd_kcontrol *kcontrol, return 0; } +static int msm_audio_effects_mmifx_params(struct mmi_eq_vals *mmifx_eq, + long *values) +{ + int devices = *values++; + int num_commands = *values++; + uint32_t params_length = (MAX_INBAND_PARAM_SZ); + int rc = 0; + int i; + struct mmi_eq_params *mmifx = &(mmifx_eq->eq_params); + + pr_debug("%s: device: %d num commands %d\n", __func__, devices, num_commands); + mmifx_eq->num_cmds = num_commands; + params_length = 0; + for (i = 0; i < num_commands; i++) { + uint32_t command_id = *values++; + /*command_config_state */ + uint32_t command_config_state = *values++; + uint32_t index_offset = *values++; + uint32_t length = *values++; + switch (command_id) { + case MMIFX_EQ_ENABLE: + pr_debug("%s: MMIFX_EQ_ENABLE\n", __func__); + if (length != 1 || index_offset != 0) { + pr_err("no valid params\n"); + rc = -EINVAL; + goto invalid_config; + } + mmifx->enable_flag = *values++; + mmifx_eq->cmds |= command_id; + break; + case MMIFX_EQ_DEVICE: + pr_debug("%s: MMIFX_DEVICE\n", __func__); + if (length != 1 || index_offset != 0) { + pr_err("no valid params\n"); + rc = -EINVAL; + goto invalid_config; + } + if (command_config_state == CONFIG_SET) { + mmifx->device = devices; + mmifx_eq->cmds |= command_id; + } + break; + case MMIFX_EQ_PRESET: + pr_debug("%s: MMIFX_EQ_PRESET\n", __func__); + if (length != 1 || index_offset != 0) { + pr_err("no valid params\n"); + rc = -EINVAL; + goto invalid_config; + } + if (command_config_state == CONFIG_SET) { + mmifx->preset= *values++; + mmifx_eq->cmds |= command_id; + } + break; + default: + pr_err("%s: Invalid command to set config\n", __func__); + break; + } + } + +invalid_config: + return rc; +} + static int msm_compr_audio_effects_config_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1807,6 +1889,7 @@ static int msm_compr_audio_effects_config_put(struct snd_kcontrol *kcontrol, int effects_module; pr_debug("%s\n", __func__); + effects_module = *values++; if (fe_id >= MSM_FRONTEND_DAI_MAX) { pr_err("%s Received out of bounds fe_id %lu\n", __func__, fe_id); @@ -1814,13 +1897,23 @@ static int msm_compr_audio_effects_config_put(struct snd_kcontrol *kcontrol, } cstream = pdata->cstream[fe_id]; audio_effects = pdata->audio_effects[fe_id]; - if (!cstream || !audio_effects) { - pr_err("%s: stream or effects inactive\n", __func__); + if (!cstream || !audio_effects || !cstream->runtime) { + pr_err("%s: stream or effects inactive %ld\n", __func__, fe_id); + if (effects_module == MMIFX_EQ_MODULE) + /* update mmfx params, will be set when compr + * session is started + */ + msm_audio_effects_mmifx_params(&(mmifx[fe_id]), + values); return -EINVAL; } + prtd = cstream->runtime->private_data; if (!prtd) { pr_err("%s: cannot set audio effects\n", __func__); + if (effects_module == MMIFX_EQ_MODULE) + msm_audio_effects_mmifx_params(&(mmifx[fe_id]), + values); return -EINVAL; } if (prtd->compr_passthr != LEGACY_PCM) { @@ -1831,7 +1924,7 @@ static int msm_compr_audio_effects_config_put(struct snd_kcontrol *kcontrol, pr_debug("%s: Effects supported for compr_type[%d]\n", __func__, prtd->compr_passthr); } - effects_module = *values++; + switch (effects_module) { case VIRTUALIZER_MODULE: pr_debug("%s: VIRTUALIZER_MODULE\n", __func__); @@ -1857,6 +1950,17 @@ static int msm_compr_audio_effects_config_put(struct snd_kcontrol *kcontrol, &(audio_effects->equalizer), values); break; + case MMIFX_EQ_MODULE: + pr_debug("%s: MMIFX EQ Module\n", __func__); + msm_audio_effects_mmifx_params(&(mmifx[fe_id]), + values); + if (atomic_read(&prtd->start)) { + msm_audio_effects_mmifx_send_eq_params(prtd->audio_client, + &(mmifx[fe_id].eq_params), + mmifx[fe_id].cmds); + mmifx[fe_id].cmds = 0; + } + break; default: pr_err("%s Invalid effects config module\n", __func__); return -EINVAL; diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c index 9bff9b113daa..d1ab17975b91 100644 --- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c +++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c @@ -62,6 +62,8 @@ struct msm_audio_eq_stream_config { struct msm_audio_eq_stream_config eq_data[MAX_EQ_SESSIONS]; +static uint32_t mmfx_enable[MAX_EQ_SESSIONS]; + static void msm_qti_pp_send_eq_values_(int eq_idx) { int result; @@ -88,6 +90,32 @@ done: return; } +static void msm_pcm_mmfx_enable_send(int eq_idx) +{ + int result; + struct msm_pcm_routing_fdai_data fe_dai; + int fe_dai_perf_mode; + struct audio_client *ac = NULL; + + msm_pcm_routing_get_fedai_info(eq_idx, SESSION_TYPE_RX, &fe_dai, + &fe_dai_perf_mode); + ac = q6asm_get_audio_client(fe_dai.strm_id); + + if (ac == NULL) { + pr_err("%s: Could not get audio client for session: %d\n", + __func__, fe_dai.strm_id); + goto done; + } + + result = q6asm_mmfxeq(ac, mmfx_enable[eq_idx]); + + if (result < 0) + pr_err("%s: Call to ASM equalizer failed, returned = %d\n", + __func__, result); +done: + return; +} + static int msm_qti_pp_get_eq_enable_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -116,8 +144,47 @@ static int msm_qti_pp_put_eq_enable_mixer(struct snd_kcontrol *kcontrol, pr_debug("%s: EQ #%d enable %d\n", __func__, eq_idx, value); eq_data[eq_idx].enable = value; + + msm_pcm_routing_acquire_lock(); + msm_pcm_mmfx_enable_send(eq_idx); + msm_pcm_routing_release_lock(); + return 0; +} + +static int msm_qti_pp_get_mmfx_eq_enable_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int eq_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + if ((eq_idx < 0) || (eq_idx >= MAX_EQ_SESSIONS)) { + pr_debug("%s : return einval\n", __func__); + return -EINVAL; + } + + ucontrol->value.integer.value[0] = mmfx_enable[eq_idx]; + + pr_debug("%s: EQ #%d enable %d\n", __func__, + eq_idx, mmfx_enable[eq_idx]); + return 0; +} + +static int msm_qti_pp_put_mmfx_eq_enable_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int eq_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + int value = ucontrol->value.integer.value[0]; + pr_debug("%s: enter EQ #%d enable %d\n", __func__, + eq_idx, value); + if ((eq_idx < 0) || (eq_idx >= MAX_EQ_SESSIONS)) + return -EINVAL; + pr_debug("%s: EQ #%d enable %d\n", __func__, + eq_idx, value); + mmfx_enable[eq_idx] = value; msm_pcm_routing_acquire_lock(); - msm_qti_pp_send_eq_values_(eq_idx); + msm_pcm_mmfx_enable_send(eq_idx); + msm_pcm_routing_release_lock(); return 0; } @@ -222,6 +289,13 @@ void msm_qti_pp_send_eq_values(int fedai_id) msm_qti_pp_send_eq_values_(fedai_id); } + +void msm_qti_pp_mmfx_eq_send_eq_values(int fedai_id) +{ + if (eq_data[fedai_id].enable) + msm_qti_pp_send_eq_values_(fedai_id); +} + /* CUSTOM MIXING */ int msm_qti_pp_send_stereo_to_custom_stereo_cmd(int port_id, unsigned int session_id, @@ -510,6 +584,19 @@ static const struct snd_kcontrol_new eq_enable_mixer_controls[] = { msm_qti_pp_put_eq_enable_mixer), }; + +static const struct snd_kcontrol_new mmfx_eq_enable_mixer_controls[] = { + SOC_SINGLE_EXT("MMFX MultiMedia1 EQ Enable", SND_SOC_NOPM, + MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_qti_pp_get_mmfx_eq_enable_mixer, + msm_qti_pp_put_mmfx_eq_enable_mixer), + SOC_SINGLE_EXT("MMFX MultiMedia2 EQ Enable", SND_SOC_NOPM, + MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_qti_pp_get_mmfx_eq_enable_mixer, + msm_qti_pp_put_mmfx_eq_enable_mixer), + SOC_SINGLE_EXT("MMFX MultiMedia3 EQ Enable", SND_SOC_NOPM, + MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_qti_pp_get_mmfx_eq_enable_mixer, + msm_qti_pp_put_mmfx_eq_enable_mixer), +}; + static const struct snd_kcontrol_new eq_band_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia1 EQ Band Count", SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA1, 11, 0, @@ -657,6 +744,10 @@ void msm_qti_pp_add_controls(struct snd_soc_platform *platform) snd_soc_add_platform_controls(platform, eq_enable_mixer_controls, ARRAY_SIZE(eq_enable_mixer_controls)); + + snd_soc_add_platform_controls(platform, mmfx_eq_enable_mixer_controls, + ARRAY_SIZE(mmfx_eq_enable_mixer_controls)); + snd_soc_add_platform_controls(platform, eq_band_mixer_controls, ARRAY_SIZE(eq_band_mixer_controls)); diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index 194ec99dbdfc..eaf644eac2e9 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -3695,6 +3695,54 @@ fail_cmd: return rc; } +int q6asm_mmfxeq(struct audio_client *ac, uint32_t enable) +{ + struct asm_mmfx_enable_config cfg; + int sz = 0; + int rc = 0; + + if (!ac || ac->apr == NULL) { + pr_err("%s: APR handle NULL\n", __func__); + rc = -EINVAL; + goto fail_cmd; + } + pr_info("%s: value %d\n", __func__, enable); + sz = sizeof(struct asm_mmfx_enable_config); + q6asm_add_hdr_async(ac, &cfg.hdr, sz, TRUE); + atomic_set(&ac->cmd_state, 1); + cfg.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2; + cfg.param.data_payload_addr_lsw = 0; + cfg.param.data_payload_addr_msw = 0; + cfg.param.mem_map_handle = 0; + cfg.param.data_payload_size = sizeof(cfg) - + sizeof(cfg.hdr) - sizeof(cfg.param); + cfg.data.module_id = AUDPROC_MODULE_ID_MMIFX; + cfg.data.param_id = AUDPROC_PARAM_ID_MMIFX_ENABLE; + cfg.data.param_size = cfg.param.data_payload_size - sizeof(cfg.data); + cfg.data.reserved = 0; + cfg.enable_flag = enable; + + rc = apr_send_pkt(ac->apr, (uint32_t *) &cfg); + if (rc < 0) { + pr_err("%s: set-params send failed paramid[0x%x]\n", __func__, + cfg.data.param_id); + rc = -EINVAL; + goto fail_cmd; + } + + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) == 0), 5*HZ); + if (!rc) { + pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__, + cfg.data.param_id); + rc = -EINVAL; + goto fail_cmd; + } + rc = 0; +fail_cmd: + return rc; +} + int q6asm_set_softpause(struct audio_client *ac, struct asm_softpause_params *pause_param) { -- GitLab