// SPDX-License-Identifier: GPL-2.0
//
// MediaTek ALSA SoC Audio DAI SRC Control
//
// Copyright (c) 2022 MediaTek Inc.
// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
#include <linux/regmap.h>
#include "mt8186-afe-common.h"
#include "mt8186-interconnection.h"
struct mtk_afe_src_priv {
int dl_rate;
int ul_rate;
};
static const unsigned int src_iir_coeff_32_to_16[] = {
0 x0dbae6, 0 xff9b0a, 0 x0dbae6, 0 x05e488, 0 xe072b9, 0 x000002,
0 x0dbae6, 0 x000f3b, 0 x0dbae6, 0 x06a537, 0 xe17d79, 0 x000002,
0 x0dbae6, 0 x01246a, 0 x0dbae6, 0 x087261, 0 xe306be, 0 x000002,
0 x0dbae6, 0 x03437d, 0 x0dbae6, 0 x0bc16f, 0 xe57c87, 0 x000002,
0 x0dbae6, 0 x072981, 0 x0dbae6, 0 x111dd3, 0 xe94f2a, 0 x000002,
0 x0dbae6, 0 x0dc4a6, 0 x0dbae6, 0 x188611, 0 xee85a0, 0 x000002,
0 x0dbae6, 0 x168b9a, 0 x0dbae6, 0 x200e8f, 0 xf3ccf1, 0 x000002,
0 x000000, 0 x1b75cb, 0 x1b75cb, 0 x2374a2, 0 x000000, 0 x000001
};
static const unsigned int src_iir_coeff_44_to_16[] = {
0 x09ae28, 0 xf7d97d, 0 x09ae28, 0 x212a3d, 0 xe0ac3a, 0 x000002,
0 x09ae28, 0 xf8525a, 0 x09ae28, 0 x216d72, 0 xe234be, 0 x000002,
0 x09ae28, 0 xf980f5, 0 x09ae28, 0 x22a057, 0 xe45a81, 0 x000002,
0 x09ae28, 0 xfc0a08, 0 x09ae28, 0 x24d3bd, 0 xe7752d, 0 x000002,
0 x09ae28, 0 x016162, 0 x09ae28, 0 x27da01, 0 xeb6ea8, 0 x000002,
0 x09ae28, 0 x0b67df, 0 x09ae28, 0 x2aca4a, 0 xef34c4, 0 x000002,
0 x000000, 0 x135c50, 0 x135c50, 0 x2c1079, 0 x000000, 0 x000001
};
static const unsigned int src_iir_coeff_44_to_32[] = {
0 x096966, 0 x0c4d35, 0 x096966, 0 xedee81, 0 xf05070, 0 x000003,
0 x12d2cc, 0 x193910, 0 x12d2cc, 0 xddbf4f, 0 xe21e1d, 0 x000002,
0 x12d2cc, 0 x1a9e60, 0 x12d2cc, 0 xe18916, 0 xe470fd, 0 x000002,
0 x12d2cc, 0 x1d06e0, 0 x12d2cc, 0 xe8a4a6, 0 xe87b24, 0 x000002,
0 x12d2cc, 0 x207578, 0 x12d2cc, 0 xf4fe62, 0 xef5917, 0 x000002,
0 x12d2cc, 0 x24055f, 0 x12d2cc, 0 x05ee2b, 0 xf8b502, 0 x000002,
0 x000000, 0 x25a599, 0 x25a599, 0 x0fabe2, 0 x000000, 0 x000001
};
static const unsigned int src_iir_coeff_48_to_16[] = {
0 x0296a4, 0 xfd69dd, 0 x0296a4, 0 x209439, 0 xe01ff9, 0 x000002,
0 x0f4ff3, 0 xf0d6d4, 0 x0f4ff3, 0 x209bc9, 0 xe076c3, 0 x000002,
0 x0e8490, 0 xf1fe63, 0 x0e8490, 0 x20cfd6, 0 xe12124, 0 x000002,
0 x14852f, 0 xed794a, 0 x14852f, 0 x21503d, 0 xe28b32, 0 x000002,
0 x136222, 0 xf17677, 0 x136222, 0 x225be1, 0 xe56964, 0 x000002,
0 x0a8d85, 0 xfc4a97, 0 x0a8d85, 0 x24310c, 0 xea6952, 0 x000002,
0 x05eff5, 0 x043455, 0 x05eff5, 0 x4ced8f, 0 xe134d6, 0 x000001,
0 x000000, 0 x3aebe6, 0 x3aebe6, 0 x04f3b0, 0 x000000, 0 x000004
};
static const unsigned int src_iir_coeff_48_to_32[] = {
0 x10c1b8, 0 x10a7df, 0 x10c1b8, 0 xe7514e, 0 xe0b41f, 0 x000002,
0 x10c1b8, 0 x116257, 0 x10c1b8, 0 xe9402f, 0 xe25aaa, 0 x000002,
0 x10c1b8, 0 x130c89, 0 x10c1b8, 0 xed3cc3, 0 xe4dddb, 0 x000002,
0 x10c1b8, 0 x1600dd, 0 x10c1b8, 0 xf48000, 0 xe90c55, 0 x000002,
0 x10c1b8, 0 x1a672e, 0 x10c1b8, 0 x00494c, 0 xefa807, 0 x000002,
0 x10c1b8, 0 x1f38e6, 0 x10c1b8, 0 x0ee076, 0 xf7c5f3, 0 x000002,
0 x000000, 0 x218370, 0 x218370, 0 x168b40, 0 x000000, 0 x000001
};
static const unsigned int src_iir_coeff_48_to_44[] = {
0 x0bf71c, 0 x170f3f, 0 x0bf71c, 0 xe3a4c8, 0 xf096cb, 0 x000003,
0 x0bf71c, 0 x17395e, 0 x0bf71c, 0 xe58085, 0 xf210c8, 0 x000003,
0 x0bf71c, 0 x1782bd, 0 x0bf71c, 0 xe95ef6, 0 xf4c899, 0 x000003,
0 x0bf71c, 0 x17cd97, 0 x0bf71c, 0 xf1608a, 0 xfa3b18, 0 x000003,
0 x000000, 0 x2fdc6f, 0 x2fdc6f, 0 xf15663, 0 x000000, 0 x000001
};
static const unsigned int src_iir_coeff_96_to_16[] = {
0 x0805a1, 0 xf21ae3, 0 x0805a1, 0 x3840bb, 0 xe02a2e, 0 x000002,
0 x0d5dd8, 0 xe8f259, 0 x0d5dd8, 0 x1c0af6, 0 xf04700, 0 x000003,
0 x0bb422, 0 xec08d9, 0 x0bb422, 0 x1bfccc, 0 xf09216, 0 x000003,
0 x08fde6, 0 xf108be, 0 x08fde6, 0 x1bf096, 0 xf10ae0, 0 x000003,
0 x0ae311, 0 xeeeda3, 0 x0ae311, 0 x37c646, 0 xe385f5, 0 x000002,
0 x044089, 0 xfa7242, 0 x044089, 0 x37a785, 0 xe56526, 0 x000002,
0 x00c75c, 0 xffb947, 0 x00c75c, 0 x378ba3, 0 xe72c5f, 0 x000002,
0 x000000, 0 x0ef76e, 0 x0ef76e, 0 x377fda, 0 x000000, 0 x000001,
};
static const unsigned int src_iir_coeff_96_to_44[] = {
0 x08b543, 0 xfd80f4, 0 x08b543, 0 x0e2332, 0 xe06ed0, 0 x000002,
0 x1b6038, 0 xf90e7e, 0 x1b6038, 0 x0ec1ac, 0 xe16f66, 0 x000002,
0 x188478, 0 xfbb921, 0 x188478, 0 x105859, 0 xe2e596, 0 x000002,
0 x13eff3, 0 xffa707, 0 x13eff3, 0 x13455c, 0 xe533b7, 0 x000002,
0 x0dc239, 0 x03d458, 0 x0dc239, 0 x17f120, 0 xe8b617, 0 x000002,
0 x0745f1, 0 x05d790, 0 x0745f1, 0 x1e3d75, 0 xed5f18, 0 x000002,
0 x05641f, 0 x085e2b, 0 x05641f, 0 x48efd0, 0 xe3e9c8, 0 x000001,
0 x000000, 0 x28f632, 0 x28f632, 0 x273905, 0 x000000, 0 x000001,
};
static unsigned int mtk_get_src_freq_mode(struct mtk_base_afe *afe, int rate)
{
switch (rate) {
case 8000 :
return 0 x50000;
case 11025 :
return 0 x6e400;
case 12000 :
return 0 x78000;
case 16000 :
return 0 xa0000;
case 22050 :
return 0 xdc800;
case 24000 :
return 0 xf0000;
case 32000 :
return 0 x140000;
case 44100 :
return 0 x1b9000;
case 48000 :
return 0 x1e0000;
case 88200 :
return 0 x372000;
case 96000 :
return 0 x3c0000;
case 176400 :
return 0 x6e4000;
case 192000 :
return 0 x780000;
default :
dev_err(afe->dev, "%s(), rate %d invalid!!!\n" ,
__func__, rate);
return 0 ;
}
}
static const unsigned int *get_iir_coeff(unsigned int rate_in,
unsigned int rate_out,
unsigned int *param_num)
{
if (rate_in == 32000 && rate_out == 16000 ) {
*param_num = ARRAY_SIZE(src_iir_coeff_32_to_16);
return src_iir_coeff_32_to_16;
} else if (rate_in == 44100 && rate_out == 16000 ) {
*param_num = ARRAY_SIZE(src_iir_coeff_44_to_16);
return src_iir_coeff_44_to_16;
} else if (rate_in == 44100 && rate_out == 32000 ) {
*param_num = ARRAY_SIZE(src_iir_coeff_44_to_32);
return src_iir_coeff_44_to_32;
} else if ((rate_in == 48000 && rate_out == 16000 ) ||
(rate_in == 96000 && rate_out == 32000 )) {
*param_num = ARRAY_SIZE(src_iir_coeff_48_to_16);
return src_iir_coeff_48_to_16;
} else if (rate_in == 48000 && rate_out == 32000 ) {
*param_num = ARRAY_SIZE(src_iir_coeff_48_to_32);
return src_iir_coeff_48_to_32;
} else if (rate_in == 48000 && rate_out == 44100 ) {
*param_num = ARRAY_SIZE(src_iir_coeff_48_to_44);
return src_iir_coeff_48_to_44;
} else if (rate_in == 96000 && rate_out == 16000 ) {
*param_num = ARRAY_SIZE(src_iir_coeff_96_to_16);
return src_iir_coeff_96_to_16;
} else if ((rate_in == 96000 && rate_out == 44100 ) ||
(rate_in == 48000 && rate_out == 22050 )) {
*param_num = ARRAY_SIZE(src_iir_coeff_96_to_44);
return src_iir_coeff_96_to_44;
}
*param_num = 0 ;
return NULL;
}
static int mtk_set_src_1_param(struct mtk_base_afe *afe, int id)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
struct mtk_afe_src_priv *src_priv = afe_priv->dai_priv[id];
unsigned int iir_coeff_num;
unsigned int iir_stage;
int rate_in = src_priv->dl_rate;
int rate_out = src_priv->ul_rate;
unsigned int out_freq_mode = mtk_get_src_freq_mode(afe, rate_out);
unsigned int in_freq_mode = mtk_get_src_freq_mode(afe, rate_in);
/* set out freq mode */
regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON3,
G_SRC_ASM_FREQ_4_MASK_SFT,
out_freq_mode << G_SRC_ASM_FREQ_4_SFT);
/* set in freq mode */
regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON4,
G_SRC_ASM_FREQ_5_MASK_SFT,
in_freq_mode << G_SRC_ASM_FREQ_5_SFT);
regmap_write(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON5, 0 x3f5986);
regmap_write(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON5, 0 x3f5987);
regmap_write(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON6, 0 x1fbd);
regmap_write(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON2, 0 );
/* set iir if in_rate > out_rate */
if (rate_in > rate_out) {
int i;
const unsigned int *iir_coeff = get_iir_coeff(rate_in, rate_out,
&iir_coeff_num);
if (iir_coeff_num == 0 || !iir_coeff) {
dev_err(afe->dev, "%s(), iir coeff error, num %d, coeff %p\n" ,
__func__, iir_coeff_num, iir_coeff);
return -EINVAL;
}
/* COEFF_SRAM_CTRL */
regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON0,
G_SRC_COEFF_SRAM_CTRL_MASK_SFT,
BIT(G_SRC_COEFF_SRAM_CTRL_SFT));
/* Clear coeff history to r/w coeff from the first position */
regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON13,
G_SRC_COEFF_SRAM_ADR_MASK_SFT, 0 );
/* Write SRC coeff, should not read the reg during write */
for (i = 0 ; i < iir_coeff_num; i++)
regmap_write(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON12,
iir_coeff[i]);
/* disable sram access */
regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON0,
G_SRC_COEFF_SRAM_CTRL_MASK_SFT, 0 );
/* CHSET_IIR_STAGE */
iir_stage = (iir_coeff_num / 6 ) - 1 ;
regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON2,
G_SRC_CHSET_IIR_STAGE_MASK_SFT,
iir_stage << G_SRC_CHSET_IIR_STAGE_SFT);
/* CHSET_IIR_EN */
regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON2,
G_SRC_CHSET_IIR_EN_MASK_SFT,
BIT(G_SRC_CHSET_IIR_EN_SFT));
} else {
/* CHSET_IIR_EN off */
regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON2,
G_SRC_CHSET_IIR_EN_MASK_SFT, 0 );
}
return 0 ;
}
static int mtk_set_src_2_param(struct mtk_base_afe *afe, int id)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
struct mtk_afe_src_priv *src_priv = afe_priv->dai_priv[id];
unsigned int iir_coeff_num;
unsigned int iir_stage;
int rate_in = src_priv->dl_rate;
int rate_out = src_priv->ul_rate;
unsigned int out_freq_mode = mtk_get_src_freq_mode(afe, rate_out);
unsigned int in_freq_mode = mtk_get_src_freq_mode(afe, rate_in);
/* set out freq mode */
regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON3,
G_SRC_ASM_FREQ_4_MASK_SFT,
out_freq_mode << G_SRC_ASM_FREQ_4_SFT);
/* set in freq mode */
regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON4,
G_SRC_ASM_FREQ_5_MASK_SFT,
in_freq_mode << G_SRC_ASM_FREQ_5_SFT);
regmap_write(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON5, 0 x3f5986);
regmap_write(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON5, 0 x3f5987);
regmap_write(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON6, 0 x1fbd);
regmap_write(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON2, 0 );
/* set iir if in_rate > out_rate */
if (rate_in > rate_out) {
int i;
const unsigned int *iir_coeff = get_iir_coeff(rate_in, rate_out,
&iir_coeff_num);
if (iir_coeff_num == 0 || !iir_coeff) {
dev_err(afe->dev, "%s(), iir coeff error, num %d, coeff %p\n" ,
__func__, iir_coeff_num, iir_coeff);
return -EINVAL;
}
/* COEFF_SRAM_CTRL */
regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON0,
G_SRC_COEFF_SRAM_CTRL_MASK_SFT,
BIT(G_SRC_COEFF_SRAM_CTRL_SFT));
/* Clear coeff history to r/w coeff from the first position */
regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON13,
G_SRC_COEFF_SRAM_ADR_MASK_SFT, 0 );
/* Write SRC coeff, should not read the reg during write */
for (i = 0 ; i < iir_coeff_num; i++)
regmap_write(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON12,
iir_coeff[i]);
/* disable sram access */
regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON0,
G_SRC_COEFF_SRAM_CTRL_MASK_SFT, 0 );
/* CHSET_IIR_STAGE */
iir_stage = (iir_coeff_num / 6 ) - 1 ;
regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON2,
G_SRC_CHSET_IIR_STAGE_MASK_SFT,
iir_stage << G_SRC_CHSET_IIR_STAGE_SFT);
/* CHSET_IIR_EN */
regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON2,
G_SRC_CHSET_IIR_EN_MASK_SFT,
BIT(G_SRC_CHSET_IIR_EN_SFT));
} else {
/* CHSET_IIR_EN off */
regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON2,
G_SRC_CHSET_IIR_EN_MASK_SFT, 0 );
}
return 0 ;
}
#define HW_SRC_1_EN_W_NAME "HW_SRC_1_Enable"
#define HW_SRC_2_EN_W_NAME "HW_SRC_2_Enable"
static int mtk_hw_src_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 id;
struct mtk_afe_src_priv *src_priv;
unsigned int reg;
if (snd_soc_dapm_widget_name_cmp(w, HW_SRC_1_EN_W_NAME) == 0 )
id = MT8186_DAI_SRC_1;
else
id = MT8186_DAI_SRC_2;
src_priv = afe_priv->dai_priv[id];
dev_dbg(afe->dev,
"%s(), name %s, event 0x%x, id %d, src_priv %p, dl_rate %d, ul_rate %d\n" ,
__func__, w->name, event, id, src_priv,
src_priv->dl_rate, src_priv->ul_rate);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
if (id == MT8186_DAI_SRC_1)
mtk_set_src_1_param(afe, id);
else
mtk_set_src_2_param(afe, id);
break ;
case SND_SOC_DAPM_POST_PMU:
reg = (id == MT8186_DAI_SRC_1) ?
AFE_GENERAL1_ASRC_2CH_CON0 : AFE_GENERAL2_ASRC_2CH_CON0;
/* ASM_ON */
regmap_update_bits(afe->regmap, reg,
G_SRC_ASM_ON_MASK_SFT,
BIT(G_SRC_ASM_ON_SFT));
/* CHSET_ON */
regmap_update_bits(afe->regmap, reg,
G_SRC_CHSET_ON_MASK_SFT,
BIT(G_SRC_CHSET_ON_SFT));
/* CHSET_STR_CLR */
regmap_update_bits(afe->regmap, reg,
G_SRC_CHSET_STR_CLR_MASK_SFT,
BIT(G_SRC_CHSET_STR_CLR_SFT));
break ;
case SND_SOC_DAPM_PRE_PMD:
reg = (id == MT8186_DAI_SRC_1) ?
AFE_GENERAL1_ASRC_2CH_CON0 : AFE_GENERAL2_ASRC_2CH_CON0;
/* ASM_OFF */
regmap_update_bits(afe->regmap, reg, G_SRC_ASM_ON_MASK_SFT, 0 );
/* CHSET_OFF */
regmap_update_bits(afe->regmap, reg, G_SRC_CHSET_ON_MASK_SFT, 0 );
/* CHSET_STR_CLR */
regmap_update_bits(afe->regmap, reg, G_SRC_CHSET_STR_CLR_MASK_SFT, 0 );
break ;
default :
break ;
}
return 0 ;
}
/* dai component */
static const struct snd_kcontrol_new mtk_hw_src_1_in_ch1_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch" , AFE_CONN40,
I_DL1_CH1, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch" , AFE_CONN40,
I_DL2_CH1, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch" , AFE_CONN40,
I_DL3_CH1, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch" , AFE_CONN40_1,
I_DL4_CH1, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch" , AFE_CONN40_1,
I_DL6_CH1, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1 Switch" , AFE_CONN40,
I_I2S0_CH1, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch" , AFE_CONN40_1,
I_DL5_CH1, 1 , 0 ),
};
static const struct snd_kcontrol_new mtk_hw_src_1_in_ch2_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch" , AFE_CONN41,
I_DL1_CH2, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch" , AFE_CONN41,
I_DL2_CH2, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch" , AFE_CONN41,
I_DL3_CH2, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch" , AFE_CONN41_1,
I_DL4_CH2, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch" , AFE_CONN41_1,
I_DL6_CH2, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2 Switch" , AFE_CONN41,
I_I2S0_CH2, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch" , AFE_CONN41_1,
I_DL5_CH2, 1 , 0 ),
};
static const struct snd_kcontrol_new mtk_hw_src_2_in_ch1_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch" , AFE_CONN42,
I_DL1_CH1, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch" , AFE_CONN42,
I_DL2_CH1, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch" , AFE_CONN42,
I_DL3_CH1, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch" , AFE_CONN42,
I_DL4_CH1, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch" , AFE_CONN42_1,
I_DL5_CH1, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch" , AFE_CONN42_1,
I_DL6_CH1, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN2_OUT_CH1 Switch" , AFE_CONN42,
I_GAIN2_OUT_CH1, 1 , 0 ),
};
static const struct snd_kcontrol_new mtk_hw_src_2_in_ch2_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch" , AFE_CONN43,
I_DL1_CH2, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch" , AFE_CONN43,
I_DL2_CH2, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch" , AFE_CONN43,
I_DL3_CH2, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch" , AFE_CONN43,
I_DL4_CH2, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch" , AFE_CONN43_1,
I_DL5_CH2, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch" , AFE_CONN43_1,
I_DL6_CH2, 1 , 0 ),
SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN2_OUT_CH2 Switch" , AFE_CONN43,
I_GAIN2_OUT_CH2, 1 , 0 ),
};
static const struct snd_soc_dapm_widget mtk_dai_src_widgets[] = {
/* inter-connections */
SND_SOC_DAPM_MIXER("HW_SRC_1_IN_CH1" , SND_SOC_NOPM, 0 , 0 ,
mtk_hw_src_1_in_ch1_mix,
ARRAY_SIZE(mtk_hw_src_1_in_ch1_mix)),
SND_SOC_DAPM_MIXER("HW_SRC_1_IN_CH2" , SND_SOC_NOPM, 0 , 0 ,
mtk_hw_src_1_in_ch2_mix,
ARRAY_SIZE(mtk_hw_src_1_in_ch2_mix)),
SND_SOC_DAPM_MIXER("HW_SRC_2_IN_CH1" , SND_SOC_NOPM, 0 , 0 ,
mtk_hw_src_2_in_ch1_mix,
ARRAY_SIZE(mtk_hw_src_2_in_ch1_mix)),
SND_SOC_DAPM_MIXER("HW_SRC_2_IN_CH2" , SND_SOC_NOPM, 0 , 0 ,
mtk_hw_src_2_in_ch2_mix,
ARRAY_SIZE(mtk_hw_src_2_in_ch2_mix)),
SND_SOC_DAPM_SUPPLY(HW_SRC_1_EN_W_NAME,
GENERAL_ASRC_EN_ON, GENERAL1_ASRC_EN_ON_SFT, 0 ,
mtk_hw_src_event,
SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_SUPPLY(HW_SRC_2_EN_W_NAME,
GENERAL_ASRC_EN_ON, GENERAL2_ASRC_EN_ON_SFT, 0 ,
mtk_hw_src_event,
SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_INPUT("HW SRC 1 Out Endpoint" ),
SND_SOC_DAPM_INPUT("HW SRC 2 Out Endpoint" ),
SND_SOC_DAPM_OUTPUT("HW SRC 1 In Endpoint" ),
SND_SOC_DAPM_OUTPUT("HW SRC 2 In Endpoint" ),
};
static int mtk_afe_src_en_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 mt8186_afe_private *afe_priv = afe->platform_priv;
struct mtk_afe_src_priv *src_priv;
if (snd_soc_dapm_widget_name_cmp(w, HW_SRC_1_EN_W_NAME) == 0 )
src_priv = afe_priv->dai_priv[MT8186_DAI_SRC_1];
else
src_priv = afe_priv->dai_priv[MT8186_DAI_SRC_2];
dev_dbg(afe->dev,
"%s(), source %s, sink %s, dl_rate %d, ul_rate %d\n" ,
__func__, source->name, sink->name,
src_priv->dl_rate, src_priv->ul_rate);
return (src_priv->dl_rate > 0 && src_priv->ul_rate > 0 ) ? 1 : 0 ;
}
static const struct snd_soc_dapm_route mtk_dai_src_routes[] = {
{"HW_SRC_1_IN_CH1" , "DL1_CH1 Switch" , "DL1" },
{"HW_SRC_1_IN_CH2" , "DL1_CH2 Switch" , "DL1" },
{"HW_SRC_2_IN_CH1" , "DL1_CH1 Switch" , "DL1" },
{"HW_SRC_2_IN_CH2" , "DL1_CH2 Switch" , "DL1" },
{"HW_SRC_1_IN_CH1" , "DL2_CH1 Switch" , "DL2" },
{"HW_SRC_1_IN_CH2" , "DL2_CH2 Switch" , "DL2" },
{"HW_SRC_2_IN_CH1" , "DL2_CH1 Switch" , "DL2" },
{"HW_SRC_2_IN_CH2" , "DL2_CH2 Switch" , "DL2" },
{"HW_SRC_1_IN_CH1" , "DL3_CH1 Switch" , "DL3" },
{"HW_SRC_1_IN_CH2" , "DL3_CH2 Switch" , "DL3" },
{"HW_SRC_2_IN_CH1" , "DL3_CH1 Switch" , "DL3" },
{"HW_SRC_2_IN_CH2" , "DL3_CH2 Switch" , "DL3" },
{"HW_SRC_1_IN_CH1" , "DL6_CH1 Switch" , "DL6" },
{"HW_SRC_1_IN_CH2" , "DL6_CH2 Switch" , "DL6" },
{"HW_SRC_2_IN_CH1" , "DL6_CH1 Switch" , "DL6" },
{"HW_SRC_2_IN_CH2" , "DL6_CH2 Switch" , "DL6" },
{"HW_SRC_1_IN_CH1" , "DL5_CH1 Switch" , "DL5" },
{"HW_SRC_1_IN_CH2" , "DL5_CH2 Switch" , "DL5" },
{"HW_SRC_2_IN_CH1" , "DL5_CH1 Switch" , "DL5" },
{"HW_SRC_2_IN_CH2" , "DL5_CH2 Switch" , "DL5" },
{"HW_SRC_1_IN_CH1" , "DL4_CH1 Switch" , "DL4" },
{"HW_SRC_1_IN_CH2" , "DL4_CH2 Switch" , "DL4" },
{"HW_SRC_2_IN_CH1" , "DL4_CH1 Switch" , "DL4" },
{"HW_SRC_2_IN_CH2" , "DL4_CH2 Switch" , "DL4" },
{"HW_SRC_1_In" , NULL, "HW_SRC_1_IN_CH1" },
{"HW_SRC_1_In" , NULL, "HW_SRC_1_IN_CH2" },
{"HW_SRC_2_In" , NULL, "HW_SRC_2_IN_CH1" },
{"HW_SRC_2_In" , NULL, "HW_SRC_2_IN_CH2" },
{"HW_SRC_1_In" , NULL, HW_SRC_1_EN_W_NAME, mtk_afe_src_en_connect},
{"HW_SRC_1_Out" , NULL, HW_SRC_1_EN_W_NAME, mtk_afe_src_en_connect},
{"HW_SRC_2_In" , NULL, HW_SRC_2_EN_W_NAME, mtk_afe_src_en_connect},
{"HW_SRC_2_Out" , NULL, HW_SRC_2_EN_W_NAME, mtk_afe_src_en_connect},
{"HW SRC 1 In Endpoint" , NULL, "HW_SRC_1_In" },
{"HW SRC 2 In Endpoint" , NULL, "HW_SRC_2_In" },
{"HW_SRC_1_Out" , NULL, "HW SRC 1 Out Endpoint" },
{"HW_SRC_2_Out" , NULL, "HW SRC 2 Out Endpoint" },
};
/* dai ops */
static int mtk_dai_src_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;
int id = dai->id;
struct mtk_afe_src_priv *src_priv = afe_priv->dai_priv[id];
unsigned int sft, mask;
unsigned int rate = params_rate(params);
unsigned int rate_reg = mt8186_rate_transform(afe->dev, rate, id);
dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n" ,
__func__, id, substream->stream, rate);
/* rate */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
src_priv->dl_rate = rate;
if (id == MT8186_DAI_SRC_1) {
sft = GENERAL1_ASRCIN_MODE_SFT;
mask = GENERAL1_ASRCIN_MODE_MASK;
} else {
sft = GENERAL2_ASRCIN_MODE_SFT;
mask = GENERAL2_ASRCIN_MODE_MASK;
}
} else {
src_priv->ul_rate = rate;
if (id == MT8186_DAI_SRC_1) {
sft = GENERAL1_ASRCOUT_MODE_SFT;
mask = GENERAL1_ASRCOUT_MODE_MASK;
} else {
sft = GENERAL2_ASRCOUT_MODE_SFT;
mask = GENERAL2_ASRCOUT_MODE_MASK;
}
}
regmap_update_bits(afe->regmap, GENERAL_ASRC_MODE, mask << sft, rate_reg << sft);
return 0 ;
}
static int mtk_dai_src_hw_free(struct snd_pcm_substream *substream,
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;
int id = dai->id;
struct mtk_afe_src_priv *src_priv = afe_priv->dai_priv[id];
dev_dbg(afe->dev, "%s(), id %d, stream %d\n" ,
__func__, id, substream->stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
src_priv->dl_rate = 0 ;
else
src_priv->ul_rate = 0 ;
return 0 ;
}
static const struct snd_soc_dai_ops mtk_dai_src_ops = {
.hw_params = mtk_dai_src_hw_params,
.hw_free = mtk_dai_src_hw_free,
};
/* dai driver */
#define MTK_SRC_RATES (SNDRV_PCM_RATE_8000_48000 |\
SNDRV_PCM_RATE_88200 |\
SNDRV_PCM_RATE_96000 |\
SNDRV_PCM_RATE_176400 |\
SNDRV_PCM_RATE_192000)
#define MTK_SRC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S24_LE |\
SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_driver mtk_dai_src_driver[] = {
{
.name = "HW_SRC_1" ,
.id = MT8186_DAI_SRC_1,
.playback = {
.stream_name = "HW_SRC_1_In" ,
.channels_min = 1 ,
.channels_max = 2 ,
.rates = MTK_SRC_RATES,
.formats = MTK_SRC_FORMATS,
},
.capture = {
.stream_name = "HW_SRC_1_Out" ,
.channels_min = 1 ,
.channels_max = 2 ,
.rates = MTK_SRC_RATES,
.formats = MTK_SRC_FORMATS,
},
.ops = &mtk_dai_src_ops,
},
{
.name = "HW_SRC_2" ,
.id = MT8186_DAI_SRC_2,
.playback = {
.stream_name = "HW_SRC_2_In" ,
.channels_min = 1 ,
.channels_max = 2 ,
.rates = MTK_SRC_RATES,
.formats = MTK_SRC_FORMATS,
},
.capture = {
.stream_name = "HW_SRC_2_Out" ,
.channels_min = 1 ,
.channels_max = 2 ,
.rates = MTK_SRC_RATES,
.formats = MTK_SRC_FORMATS,
},
.ops = &mtk_dai_src_ops,
},
};
int mt8186_dai_src_register(struct mtk_base_afe *afe)
{
struct mtk_base_afe_dai *dai;
int ret;
dai = devm_kzalloc(afe->dev, sizeof (*dai), GFP_KERNEL);
if (!dai)
return -ENOMEM;
list_add(&dai->list, &afe->sub_dais);
dai->dai_drivers = mtk_dai_src_driver;
dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_src_driver);
dai->dapm_widgets = mtk_dai_src_widgets;
dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_src_widgets);
dai->dapm_routes = mtk_dai_src_routes;
dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_src_routes);
/* set dai priv */
ret = mt8186_dai_set_priv(afe, MT8186_DAI_SRC_1,
sizeof (struct mtk_afe_src_priv), NULL);
if (ret)
return ret;
ret = mt8186_dai_set_priv(afe, MT8186_DAI_SRC_2,
sizeof (struct mtk_afe_src_priv), NULL);
if (ret)
return ret;
return 0 ;
}
Messung V0.5 in Prozent C=97 H=97 G=96
¤ Dauer der Verarbeitung: 0.2 Sekunden
(vorverarbeitet am 2026-06-06)
¤
*© Formatika GbR, Deutschland