From ce3c3a600a92ab0215ae2a24586faaecd3e1c8c6 Mon Sep 17 00:00:00 2001 From: Naresh Tanniru Date: Tue, 27 Sep 2016 18:56:31 +0530 Subject: [PATCH] ASoC: msm: qdsp6v2: support for configurable bit format for AFE encoder Add support for configurable bit width for AFE encoder. Add new mixer ctl to set for usecases which enables configuring different input/output bit format on AFE for usecases such as APTXHD encoder for 24bit input and 16bit output. Change-Id: I62326a097cbd71a3ec2b93a0120284d8f71f5d57 Signed-off-by: Naresh Tanniru --- include/sound/q6afe-v2.h | 2 +- sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c | 71 +++++++++++++++++++++++++++++++++++ sound/soc/msm/qdsp6v2/q6afe.c | 29 ++++++++------ 3 files changed, 90 insertions(+), 12 deletions(-) diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h index 9ed6510cd0e1..31f7c02b54b3 100644 --- a/include/sound/q6afe-v2.h +++ b/include/sound/q6afe-v2.h @@ -281,7 +281,7 @@ void afe_set_cal_mode(u16 port_id, enum afe_cal_mode afe_cal_mode); int afe_port_start(u16 port_id, union afe_port_config *afe_config, u32 rate); int afe_port_start_v2(u16 port_id, union afe_port_config *afe_config, - u32 rate, u16 afe_in_channels, + u32 rate, u16 afe_in_channels, u16 afe_in_bit_width, struct afe_enc_config *enc_config); int afe_spk_prot_feed_back_cfg(int src_port, int dst_port, int l_ch, int r_ch, u32 enable); diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c index a89d88eac41e..776f00211f04 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c @@ -173,6 +173,7 @@ struct msm_dai_q6_dai_data { u32 bitwidth; u32 cal_mode; u32 afe_in_channels; + u16 afe_in_bitformat; struct afe_enc_config enc_config; union afe_port_config port_config; }; @@ -1417,11 +1418,20 @@ static int msm_dai_q6_prepare(struct snd_pcm_substream *substream, if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) { if (dai_data->enc_config.format != ENC_FMT_NONE) { + int bitwidth = 0; + + if (dai_data->afe_in_bitformat == + SNDRV_PCM_FORMAT_S24_LE) + bitwidth = 24; + else if (dai_data->afe_in_bitformat == + SNDRV_PCM_FORMAT_S16_LE) + bitwidth = 16; pr_debug("%s: calling AFE_PORT_START_V2 with enc_format: %d\n", __func__, dai_data->enc_config.format); rc = afe_port_start_v2(dai->id, &dai_data->port_config, dai_data->rate, dai_data->afe_in_channels, + bitwidth, &dai_data->enc_config); if (rc < 0) pr_err("%s: afe_port_start_v2 failed error: %d\n", @@ -2140,6 +2150,12 @@ static const struct soc_enum afe_input_chs_enum[] = { SOC_ENUM_SINGLE_EXT(3, afe_input_chs_text), }; +static const char *const afe_input_bit_format_text[] = {"S16_LE", "S24_LE"}; + +static const struct soc_enum afe_input_bit_format_enum[] = { + SOC_ENUM_SINGLE_EXT(2, afe_input_bit_format_text), +}; + static int msm_dai_q6_afe_input_channel_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2168,6 +2184,58 @@ static int msm_dai_q6_afe_input_channel_put(struct snd_kcontrol *kcontrol, return 0; } +static int msm_dai_q6_afe_input_bit_format_get( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data; + + if (!dai_data) { + pr_err("%s: Invalid dai data\n", __func__); + return -EINVAL; + } + + switch (dai_data->afe_in_bitformat) { + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("%s: afe input bit format : %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int msm_dai_q6_afe_input_bit_format_put( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data; + + if (!dai_data) { + pr_err("%s: Invalid dai data\n", __func__); + return -EINVAL; + } + switch (ucontrol->value.integer.value[0]) { + case 1: + dai_data->afe_in_bitformat = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + dai_data->afe_in_bitformat = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: updating afe input bit format : %d\n", + __func__, dai_data->afe_in_bitformat); + + return 0; +} + + static const struct snd_kcontrol_new afe_enc_config_controls[] = { { .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -2181,6 +2249,9 @@ static const struct snd_kcontrol_new afe_enc_config_controls[] = { SOC_ENUM_EXT("AFE Input Channels", afe_input_chs_enum[0], msm_dai_q6_afe_input_channel_get, msm_dai_q6_afe_input_channel_put), + SOC_ENUM_EXT("AFE Input Bit Format", afe_input_bit_format_enum[0], + msm_dai_q6_afe_input_bit_format_get, + msm_dai_q6_afe_input_bit_format_put), }; static const char * const afe_cal_mode_text[] = { diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c index af5a99e56afc..be0a8b2e3abe 100644 --- a/sound/soc/msm/qdsp6v2/q6afe.c +++ b/sound/soc/msm/qdsp6v2/q6afe.c @@ -2645,8 +2645,9 @@ exit: } static int q6afe_send_enc_config(u16 port_id, - union afe_enc_config_data *cfg, u32 format, - union afe_port_config afe_config, u16 afe_in_channels) + union afe_enc_config_data *cfg, u32 format, + union afe_port_config afe_config, + u16 afe_in_channels, u16 afe_in_bit_width) { struct afe_audioif_config_command config; int index; @@ -2728,8 +2729,13 @@ static int q6afe_send_enc_config(u16 port_id, config.pdata.param_id = AFE_PARAM_ID_PORT_MEDIA_TYPE; config.port.media_type.minor_version = AFE_API_VERSION_PORT_MEDIA_TYPE; config.port.media_type.sample_rate = afe_config.slim_sch.sample_rate; - config.port.media_type.bit_width = afe_config.slim_sch.bit_width; - if (afe_in_channels != 0) + if (afe_in_bit_width) + config.port.media_type.bit_width = afe_in_bit_width; + else + config.port.media_type.bit_width = + afe_config.slim_sch.bit_width; + + if (afe_in_channels) config.port.media_type.num_channels = afe_in_channels; else config.port.media_type.num_channels = @@ -2749,8 +2755,8 @@ exit: } static int __afe_port_start(u16 port_id, union afe_port_config *afe_config, - u32 rate, u16 afe_in_channels, - union afe_enc_config_data *cfg, u32 enc_format) + u32 rate, u16 afe_in_channels, u16 afe_in_bit_width, + union afe_enc_config_data *cfg, u32 enc_format) { struct afe_audioif_config_command config; int ret = 0; @@ -2989,7 +2995,8 @@ static int __afe_port_start(u16 port_id, union afe_port_config *afe_config, pr_debug("%s: Found AFE encoder support for SLIMBUS enc_format = %d\n", __func__, enc_format); ret = q6afe_send_enc_config(port_id, cfg, enc_format, - *afe_config, afe_in_channels); + *afe_config, afe_in_channels, + afe_in_bit_width); if (ret) { pr_err("%s: AFE encoder config for port 0x%x failed %d\n", __func__, port_id, ret); @@ -3043,7 +3050,7 @@ int afe_port_start(u16 port_id, union afe_port_config *afe_config, u32 rate) { return __afe_port_start(port_id, afe_config, rate, - 0, NULL, ASM_MEDIA_FMT_NONE); + 0, 0, NULL, ASM_MEDIA_FMT_NONE); } EXPORT_SYMBOL(afe_port_start); @@ -3061,12 +3068,12 @@ EXPORT_SYMBOL(afe_port_start); * Returns 0 on success or error value on port start failure. */ int afe_port_start_v2(u16 port_id, union afe_port_config *afe_config, - u32 rate, u16 afe_in_channels, + u32 rate, u16 afe_in_channels, u16 afe_in_bit_width, struct afe_enc_config *enc_cfg) { return __afe_port_start(port_id, afe_config, rate, - afe_in_channels, &enc_cfg->data, - enc_cfg->format); + afe_in_channels, afe_in_bit_width, + &enc_cfg->data, enc_cfg->format); } EXPORT_SYMBOL(afe_port_start_v2); -- 2.11.0