[v2 03/17] ASoC: mediatek: mt8186: support adda in platform driver
AngeloGioacchino Del Regno
angelogioacchino.delregno at collabora.com
Fri Feb 18 06:54:16 PST 2022
Il 17/02/22 14:41, Jiaxin Yu ha scritto:
> This patch adds mt8186 adda dai driver
>
> Signed-off-by: Jiaxin Yu <jiaxin.yu at mediatek.com>
> ---
> sound/soc/mediatek/mt8186/mt8186-dai-adda.c | 891 ++++++++++++++++++++
> 1 file changed, 891 insertions(+)
> create mode 100644 sound/soc/mediatek/mt8186/mt8186-dai-adda.c
>
> diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-adda.c b/sound/soc/mediatek/mt8186/mt8186-dai-adda.c
> new file mode 100644
> index 000000000000..6d7dd1533da0
> --- /dev/null
> +++ b/sound/soc/mediatek/mt8186/mt8186-dai-adda.c
> @@ -0,0 +1,891 @@
> +// SPDX-License-Identifier: GPL-2.0
> +//
> +// MediaTek ALSA SoC Audio DAI ADDA Control
> +//
> +// Copyright (c) 2022 MediaTek Inc.
> +// Author: Jiaxin Yu <jiaxin.yu at mediatek.com>
> +
> +#include <linux/regmap.h>
> +#include <linux/delay.h>
> +#include "mt8186-afe-clk.h"
> +#include "mt8186-afe-common.h"
> +#include "mt8186-afe-gpio.h"
> +#include "mt8186-interconnection.h"
> +
..snip..
> +
> +static int mtk_adda_mtkaif_cfg_event(struct snd_soc_dapm_widget *w,
> + struct snd_kcontrol *kcontrol,
> + int event)
> +{
> + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
> + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
> + struct mt8186_afe_private *afe_priv = afe->platform_priv;
> + int delay_data;
> + int delay_cycle;
> +
> + switch (event) {
> + case SND_SOC_DAPM_PRE_PMU:
> + if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2) {
> + /* set protocol 2 */
> + regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0,
> + 0x00010000);
No leading zeros, please (also, it fits in one line):
regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, 0x10000);
> + /* mtkaif_rxif_clkinv_adc inverse */
> + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_CFG0,
> + MTKAIF_RXIF_CLKINV_ADC_MASK_SFT,
> + 0x1 << MTKAIF_RXIF_CLKINV_ADC_SFT);
Please use the BIT() macro:
BIT(MTKAIF_RXIF_CLKINV_ADC_SFT)
> +
> + if (strcmp(w->name, "ADDA_MTKAIF_CFG") == 0) {
> + if (afe_priv->mtkaif_chosen_phase[0] < 0 &&
> + afe_priv->mtkaif_chosen_phase[1] < 0) {
> + dev_err(afe->dev,
> + "%s(), calib fail mtkaif_chosen_phase[0/1]:%d/%d\n",
> + __func__,
> + afe_priv->mtkaif_chosen_phase[0],
> + afe_priv->mtkaif_chosen_phase[1]);
> + break;
> + }
> +
> + if (afe_priv->mtkaif_chosen_phase[0] < 0 ||
> + afe_priv->mtkaif_chosen_phase[1] < 0) {
> + dev_err(afe->dev,
> + "%s(), skip dealy setting mtkaif_chosen_phase[0/1]:%d/%d\n",
> + __func__,
> + afe_priv->mtkaif_chosen_phase[0],
> + afe_priv->mtkaif_chosen_phase[1]);
> + break;
> + }
> + }
> +
> + /* set delay for ch12 */
> + if (afe_priv->mtkaif_phase_cycle[0] >=
> + afe_priv->mtkaif_phase_cycle[1]) {
> + delay_data = DELAY_DATA_MISO1;
> + delay_cycle = afe_priv->mtkaif_phase_cycle[0] -
> + afe_priv->mtkaif_phase_cycle[1];
> + } else {
> + delay_data = DELAY_DATA_MISO2;
> + delay_cycle = afe_priv->mtkaif_phase_cycle[1] -
> + afe_priv->mtkaif_phase_cycle[0];
> + }
> +
> + regmap_update_bits(afe->regmap,
> + AFE_ADDA_MTKAIF_RX_CFG2,
> + MTKAIF_RXIF_DELAY_DATA_MASK_SFT,
> + delay_data <<
> + MTKAIF_RXIF_DELAY_DATA_SFT);
> +
> + regmap_update_bits(afe->regmap,
> + AFE_ADDA_MTKAIF_RX_CFG2,
> + MTKAIF_RXIF_DELAY_CYCLE_MASK_SFT,
> + delay_cycle <<
> + MTKAIF_RXIF_DELAY_CYCLE_SFT);
> +
> + } else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2) {
> + regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0,
> + 0x00010000);
No leading zeroes, please.
> + } else {
> + regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, 0x0);
0x0 -> 0
> + }
> +
> + break;
> + default:
> + break;
> + }
> +
> + return 0;
> +}
> +
> +static int mtk_adda_dl_event(struct snd_soc_dapm_widget *w,
> + struct snd_kcontrol *kcontrol,
> + int event)
> +{
> + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
> + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
> +
> + dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n",
> + __func__, w->name, event);
> +
> + switch (event) {
> + case SND_SOC_DAPM_PRE_PMU:
> + mt8186_afe_gpio_request(afe->dev, true, MT8186_DAI_ADDA, 0);
> + break;
> + case SND_SOC_DAPM_POST_PMD:
> + /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
> + usleep_range(125, 135);
> + mt8186_afe_gpio_request(afe->dev, false, MT8186_DAI_ADDA, 0);
> + break;
> + default:
> + break;
> + }
> +
> + return 0;
> +}
> +
> +static int mt8186_adda_dmic_get(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_value *ucontrol)
> +{
> + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
> + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
> + struct mt8186_afe_private *afe_priv = afe->platform_priv;
> +
> + ucontrol->value.integer.value[0] = afe_priv->mtkaif_dmic;
> +
> + return 0;
> +}
> +
> +static int mt8186_adda_dmic_set(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_value *ucontrol)
> +{
> + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
> + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
> + struct mt8186_afe_private *afe_priv = afe->platform_priv;
> + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
> + int dmic_on;
> +
> + if (ucontrol->value.enumerated.item[0] >= e->items)
> + return -EINVAL;
> +
> + dmic_on = ucontrol->value.integer.value[0];
> +
> + dev_info(afe->dev, "%s(), kcontrol name %s, dmic_on %d\n",
> + __func__, kcontrol->id.name, dmic_on);
Shouldn't this be a dev_dbg() instead?
> +
> + if (afe_priv->mtkaif_dmic == dmic_on)
> + return 0;
> +
> + afe_priv->mtkaif_dmic = dmic_on;
> +
> + return 1;
> +}
> +
...snip...
> +
> +#define HIRES_THRESHOLD 48000
> +static int mtk_afe_dac_hires_connect(struct snd_soc_dapm_widget *source,
> + struct snd_soc_dapm_widget *sink)
> +{
> + struct snd_soc_dapm_widget *w = source;
> + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
> + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
> + struct mtk_afe_adda_priv *adda_priv;
> +
> + adda_priv = get_adda_priv_by_name(afe, w->name);
> +
> + if (!adda_priv) {
> + dev_info(afe->dev, "%s(), adda_priv == NULL", __func__);
dev_err()
> + return 0;
> + }
> +
> + return (adda_priv->dl_rate > HIRES_THRESHOLD) ? 1 : 0;
> +}
> +
> +static int mtk_afe_adc_hires_connect(struct snd_soc_dapm_widget *source,
> + struct snd_soc_dapm_widget *sink)
> +{
> + struct snd_soc_dapm_widget *w = source;
> + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
> + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
> + struct mtk_afe_adda_priv *adda_priv;
> +
> + adda_priv = get_adda_priv_by_name(afe, w->name);
> +
> + if (!adda_priv) {
> + dev_info(afe->dev, "%s(), adda_priv == NULL", __func__);
dev_err()
> + return 0;
> + }
> +
> + return (adda_priv->ul_rate > HIRES_THRESHOLD) ? 1 : 0;
> +}
> +
..snip..
> +};
> +
> +/* dai ops */
> +static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
> + struct snd_pcm_hw_params *params,
> + struct snd_soc_dai *dai)
> +{
> + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
> + struct mt8186_afe_private *afe_priv = afe->platform_priv;
> + unsigned int rate = params_rate(params);
> + int id = dai->id;
> + struct mtk_afe_adda_priv *adda_priv = afe_priv->dai_priv[id];
> +
> + dev_info(afe->dev, "%s(), id %d, stream %d, rate %d\n",
> + __func__,
> + id,
> + substream->stream,
> + rate);
> +
> + if (!adda_priv) {
> + dev_info(afe->dev, "%s(), adda_priv == NULL", __func__);
> + return -EINVAL;
> + }
> +
> + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
> + unsigned int dl_src2_con0 = 0;
> + unsigned int dl_src2_con1 = 0;
This initialization is redundant: you're never using these variables
before initializing them later, so initializing them to zero is not
needed here.
> +
> + adda_priv->dl_rate = rate;
> +
> + /* set sampling rate */
> + dl_src2_con0 = adda_dl_rate_transform(afe, rate) <<
> + DL_2_INPUT_MODE_CTL_SFT;
> +
> + /* set output mode, UP_SAMPLING_RATE_X8 */
> + dl_src2_con0 |= (0x3 << DL_2_OUTPUT_SEL_CTL_SFT);
> +
> + /* turn off mute function */
> + dl_src2_con0 |= (0x01 << DL_2_MUTE_CH2_OFF_CTL_PRE_SFT);
BIT() macro, please
> + dl_src2_con0 |= (0x01 << DL_2_MUTE_CH1_OFF_CTL_PRE_SFT);
> +
> + /* set voice input data if input sample rate is 8k or 16k */
> + if (rate == 8000 || rate == 16000)
> + dl_src2_con0 |= 0x01 << DL_2_VOICE_MODE_CTL_PRE_SFT;
> +
> + /* SA suggest apply -0.3db to audio/speech path */
> + dl_src2_con1 = MTK_AFE_ADDA_DL_GAIN_NORMAL <<
> + DL_2_GAIN_CTL_PRE_SFT;
> +
> + /* turn on down-link gain */
> + dl_src2_con0 |= (0x01 << DL_2_GAIN_ON_CTL_PRE_SFT);
> +
> + if (id == MT8186_DAI_ADDA) {
> + /* clean predistortion */
> + regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON0, 0);
> + regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON1, 0);
> +
> + regmap_write(afe->regmap,
> + AFE_ADDA_DL_SRC2_CON0, dl_src2_con0);
> + regmap_write(afe->regmap,
> + AFE_ADDA_DL_SRC2_CON1, dl_src2_con1);
> +
> + /* set sdm gain */
> + regmap_update_bits(afe->regmap,
> + AFE_ADDA_DL_SDM_DCCOMP_CON,
> + ATTGAIN_CTL_MASK_SFT,
> + AUDIO_SDM_LEVEL_NORMAL <<
> + ATTGAIN_CTL_SFT);
> +
> + /* Use new 2nd sdm */
> + regmap_update_bits(afe->regmap,
> + AFE_ADDA_DL_SDM_DITHER_CON,
> + AFE_DL_SDM_DITHER_64TAP_EN_MASK_SFT,
> + 0x1 << AFE_DL_SDM_DITHER_64TAP_EN_SFT);
BIT(AFE_DL_SDM_DITHER_64TAP_EN_SFT)
> + regmap_update_bits(afe->regmap,
> + AFE_ADDA_DL_SDM_AUTO_RESET_CON,
> + AFE_DL_USE_NEW_2ND_SDM_MASK_SFT,
> + 0x1 << AFE_DL_USE_NEW_2ND_SDM_SFT);
BIT(AFE_DL_USE_NEW_2ND_SDM_SFT)
> + regmap_update_bits(afe->regmap,
> + AFE_ADDA_DL_SDM_DCCOMP_CON,
> + USE_3RD_SDM_MASK_SFT,
> + AUDIO_SDM_2ND << USE_3RD_SDM_SFT);
> +
> + /* sdm auto reset */
> + regmap_write(afe->regmap,
> + AFE_ADDA_DL_SDM_AUTO_RESET_CON,
> + SDM_AUTO_RESET_THRESHOLD);
> + regmap_update_bits(afe->regmap,
> + AFE_ADDA_DL_SDM_AUTO_RESET_CON,
> + SDM_AUTO_RESET_TEST_ON_MASK_SFT,
> + 0x1 << SDM_AUTO_RESET_TEST_ON_SFT);
BIT(SDM_AUTO_RESET_TEST_ON_SFT)
> + }
> + } else {
> + unsigned int voice_mode = 0;
what about...
unsigned int ul_src_con0 = 0; /* default value */
unsigned int voice_mode = adda_ul_rate_transform(afe, rate);
> + unsigned int ul_src_con0 = 0; /* default value */
> +
> + adda_priv->ul_rate = rate;
> +
> + voice_mode = adda_ul_rate_transform(afe, rate);
> +
> + ul_src_con0 |= (voice_mode << 17) & (0x7 << 17);
> +
> + /* enable iir */
> + ul_src_con0 |= (1 << UL_IIR_ON_TMP_CTL_SFT) &
> + UL_IIR_ON_TMP_CTL_MASK_SFT;
> + ul_src_con0 |= (UL_IIR_SW << UL_IIRMODE_CTL_SFT) &
> + UL_IIRMODE_CTL_MASK_SFT;
> + switch (id) {
> + case MT8186_DAI_ADDA:
> + case MT8186_DAI_AP_DMIC:
> + /* 35Hz @ 48k */
> + regmap_write(afe->regmap,
> + AFE_ADDA_IIR_COEF_02_01, 0x00000000);
Please drop leading zeroes:
regmap_write(afe->regmap, AFE_ADDA_IIR_COEF_02_01, 0);
> + regmap_write(afe->regmap,
> + AFE_ADDA_IIR_COEF_04_03, 0x00003FB8);
... and also please write hex in lower-case:
regmap_write(afe->regmap,
AFE_ADDA_IIR_COEF_04_03, 0x03fb8);
> + regmap_write(afe->regmap,
> + AFE_ADDA_IIR_COEF_06_05, 0x3FB80000);
> + regmap_write(afe->regmap,
> + AFE_ADDA_IIR_COEF_08_07, 0x3FB80000);
> + regmap_write(afe->regmap,
> + AFE_ADDA_IIR_COEF_10_09, 0x0000C048);
> +
> + regmap_write(afe->regmap,
> + AFE_ADDA_UL_SRC_CON0, ul_src_con0);
> +
> + /* Using Internal ADC */
> + regmap_update_bits(afe->regmap,
> + AFE_ADDA_TOP_CON0,
> + 0x1 << 0,
> + 0x0 << 0);
Please use the BIT() macro:
regmap_update_bits(afe->regmap, AFE_ADDA_TOP_CON0, BIT(0), 0);
P.S.: 87 columns is ok
> +
> + /* mtkaif_rxif_data_mode = 0, amic */
> + regmap_update_bits(afe->regmap,
> + AFE_ADDA_MTKAIF_RX_CFG0,
> + 0x1 << 0,
> + 0x0 << 0);
same here.
> + break;
> + default:
> + break;
> + }
> +
> + /* ap dmic */
> + switch (id) {
> + case MT8186_DAI_AP_DMIC:
> + mtk_adda_ul_src_dmic(afe, id);
> + break;
> + default:
> + break;
> + }
> + }
> +
> + return 0;
> +}
> +
Regards,
Angelo
More information about the Linux-mediatek
mailing list