kernel-brax3-ubuntu-touch/sound/soc/mediatek/mt6985/mt6985-dai-etdm.c
erascape f319b992b1 kernel-5.15: Initial import brax3 UT kernel
* halium configs enabled

Signed-off-by: erascape <erascape@proton.me>
2025-09-23 15:17:10 +00:00

1251 lines
37 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2022 MediaTek Inc.
* Author: yiwen chiou<yiwen.chiou@mediatek.com
*/
#include <linux/regmap.h>
#include <linux/of_device.h>
#include <sound/pcm_params.h>
#include "mt6985-afe-clk.h"
#include "mt6985-afe-common.h"
#include "mt6985-afe-gpio.h"
#include "mt6985-interconnection.h"
struct mtk_afe_etdm_priv {
int id;
int etdm_rate;
int mclk_id;
int mclk_rate;
int mclk_apll;
};
enum {
ETDM_CLK_SOURCE_H26M = 0,
ETDM_CLK_SOURCE_APLL = 1,
ETDM_CLK_SOURCE_SPDIF = 2,
ETDM_CLK_SOURCE_HDMI = 3,
ETDM_CLK_SOURCE_EARC = 4,
ETDM_CLK_SOURCE_LINEIN = 5,
};
enum {
ETDM_RELATCH_SEL_H26M = 0,
ETDM_RELATCH_SEL_APLL = 1,
};
enum {
ETDM_USE_INTERCONN = 0,
ETDM_USE_TINYCONN = 1,
};
enum {
ETDM_RATE_8K = 0,
ETDM_RATE_12K = 1,
ETDM_RATE_16K = 2,
ETDM_RATE_24K = 3,
ETDM_RATE_32K = 4,
ETDM_RATE_48K = 5,
ETDM_RATE_64K = 6, //not support
ETDM_RATE_96K = 7,
ETDM_RATE_128K = 8, //not support
ETDM_RATE_192K = 9,
ETDM_RATE_256K = 10, //not support
ETDM_RATE_384K = 11,
ETDM_RATE_11025 = 16,
ETDM_RATE_22050 = 17,
ETDM_RATE_44100 = 18,
ETDM_RATE_88200 = 19,
ETDM_RATE_176400 = 20,
ETDM_RATE_352800 = 21,
};
enum {
ETDM_CONN_8K = 0,
ETDM_CONN_11K = 1,
ETDM_CONN_12K = 2,
ETDM_CONN_16K = 4,
ETDM_CONN_22K = 5,
ETDM_CONN_24K = 6,
ETDM_CONN_32K = 8,
ETDM_CONN_44K = 9,
ETDM_CONN_48K = 10,
ETDM_CONN_88K = 13,
ETDM_CONN_96K = 14,
ETDM_CONN_176K = 17,
ETDM_CONN_192K = 18,
ETDM_CONN_352K = 21,
ETDM_CONN_384K = 22,
};
enum {
ETDM_WLEN_8_BIT = 0x7,
ETDM_WLEN_16_BIT = 0xf,
ETDM_WLEN_32_BIT = 0x1f,
};
enum {
ETDM_SLAVE_SEL_ETDMIN0_MASTER = 0,
ETDM_SLAVE_SEL_ETDMIN0_SLAVE = 1,
ETDM_SLAVE_SEL_ETDMIN1_MASTER = 2,
ETDM_SLAVE_SEL_ETDMIN1_SLAVE = 3,
ETDM_SLAVE_SEL_ETDMIN2_MASTER = 4,
ETDM_SLAVE_SEL_ETDMIN2_SLAVE = 5,
ETDM_SLAVE_SEL_ETDMIN3_MASTER = 6,
ETDM_SLAVE_SEL_ETDMIN3_SLAVE = 7,
ETDM_SLAVE_SEL_ETDMOUT0_MASTER = 8,
ETDM_SLAVE_SEL_ETDMOUT0_SLAVE = 9,
ETDM_SLAVE_SEL_ETDMOUT1_MASTER = 10,
ETDM_SLAVE_SEL_ETDMOUT1_SLAVE = 11,
ETDM_SLAVE_SEL_ETDMOUT2_MASTER = 12,
ETDM_SLAVE_SEL_ETDMOUT2_SLAVE = 13,
ETDM_SLAVE_SEL_ETDMOUT3_MASTER = 14,
ETDM_SLAVE_SEL_ETDMOUT3_SLAVE = 15,
};
enum {
DAI_ETDMIN = 0,
DAI_ETDMOUT,
DAI_ETDM_NUM,
};
#define ETDMIN_MCLK_EN_W_NAME "ETDMIN_MCLK_EN"
#define ETDMOUT_MCLK_EN_W_NAME "ETDMOUT_MCLK_EN"
static const struct mtk_afe_etdm_priv mt6985_etdm_priv[DAI_ETDM_NUM] = {
[DAI_ETDMIN] = {
.id = MT6985_DAI_ETDMIN,
.etdm_rate = SNDRV_PCM_RATE_8000,
},
[DAI_ETDMOUT] = {
.id = MT6985_DAI_ETDMOUT,
.etdm_rate = SNDRV_PCM_RATE_8000,
},
};
static int get_etdm_id_by_name(struct mtk_base_afe *afe,
const char *name)
{
if (strstr(name, "ETDM Capture"))
return MT6985_DAI_ETDMIN;
else if (strstr(name, "ETDM Playback"))
return MT6985_DAI_ETDMOUT;
else
return -EINVAL;
}
static struct mtk_afe_etdm_priv *get_etdm_priv_by_name(struct mtk_base_afe *afe,
const char *name)
{
struct mt6985_afe_private *afe_priv = afe->platform_priv;
int dai_id = get_etdm_id_by_name(afe, name);
if (dai_id < 0)
return NULL;
return afe_priv->dai_priv[dai_id];
}
static unsigned int get_etdm_wlen(snd_pcm_format_t format)
{
unsigned int wlen = 0;
/* The reg_word_length should be >= reg_bit_length */
wlen = snd_pcm_format_physical_width(format);
pr_info("%s wlen %d\n", __func__, wlen);
if (wlen < 16)
return ETDM_WLEN_16_BIT;
else
return ETDM_WLEN_32_BIT;
}
static unsigned int get_etdm_lrck_width(snd_pcm_format_t format)
{
/* The valid data bit number should be large than 7 due to hardware limitation. */
return snd_pcm_format_physical_width(format) - 1;
}
static unsigned int get_etdm_rate(unsigned int rate)
{
switch (rate) {
case 8000:
return ETDM_RATE_8K;
case 12000:
return ETDM_RATE_12K;
case 16000:
return ETDM_RATE_16K;
case 24000:
return ETDM_RATE_24K;
case 32000:
return ETDM_RATE_32K;
case 48000:
return ETDM_RATE_48K;
case 64000:
return ETDM_RATE_64K;
case 96000:
return ETDM_RATE_96K;
case 128000:
return ETDM_RATE_128K;
case 192000:
return ETDM_RATE_192K;
case 256000:
return ETDM_RATE_256K;
case 384000:
return ETDM_RATE_384K;
case 11025:
return ETDM_RATE_11025;
case 22050:
return ETDM_RATE_22050;
case 44100:
return ETDM_RATE_44100;
case 88200:
return ETDM_RATE_88200;
case 176400:
return ETDM_RATE_176400;
case 352800:
return ETDM_RATE_352800;
default:
return 0;
}
}
static unsigned int get_etdm_inconn_rate(unsigned int rate)
{
pr_info("%s rate %d\n", __func__, rate);
switch (rate) {
case 8000:
return ETDM_CONN_8K;
case 12000:
return ETDM_CONN_12K;
case 16000:
return ETDM_CONN_16K;
case 24000:
return ETDM_CONN_24K;
case 32000:
return ETDM_CONN_32K;
case 48000:
return ETDM_CONN_48K;
case 96000:
return ETDM_CONN_96K;
case 192000:
return ETDM_CONN_192K;
case 384000:
return ETDM_CONN_384K;
case 11025:
return ETDM_CONN_11K;
case 22050:
return ETDM_CONN_22K;
case 44100:
return ETDM_CONN_44K;
case 88200:
return ETDM_CONN_88K;
case 176400:
return ETDM_CONN_176K;
case 352800:
return ETDM_CONN_352K;
default:
return 0;
}
}
static int etdm_out_sgen_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component =
snd_soc_kcontrol_component(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
unsigned int value = 0;
unsigned int reg = 0;
unsigned int mask = 0;
unsigned int shift = 0;
if (!strcmp(kcontrol->id.name, "ETDM_OUT1_SGEN")) {
reg = ETDM_0_3_COWORK_CON3;
mask = ETDM_OUT1_USE_SGEN_MASK_SFT;
shift = ETDM_OUT1_USE_SGEN_SFT;
} else if (!strcmp(kcontrol->id.name, "ETDM_OUT0_SGEN")) {
reg = ETDM_0_3_COWORK_CON3;
mask = ETDM_OUT1_USE_SGEN_MASK_SFT;
shift = ETDM_OUT1_USE_SGEN_SFT;
}
if (reg)
regmap_read(afe->regmap, reg, &value);
value &= mask;
value >>= shift;
ucontrol->value.enumerated.item[0] = value;
return 0;
}
static int etdm_out_sgen_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
unsigned int value = 0;
unsigned int reg = 0;
unsigned int val = 0;
unsigned int mask = 0;
if (!strcmp(kcontrol->id.name, "ETDM_OUT1_SGEN")) {
reg = ETDM_0_3_COWORK_CON3;
mask = ETDM_OUT1_USE_SGEN_MASK_SFT;
val = value << ETDM_OUT1_USE_SGEN_SFT;
} else if (!strcmp(kcontrol->id.name, "ETDM_OUT0_SGEN")) {
reg = ETDM_0_3_COWORK_CON3;
mask = ETDM_OUT0_USE_SGEN_MASK_SFT;
val = value << ETDM_OUT0_USE_SGEN_SFT;
}
if (reg)
regmap_update_bits(afe->regmap, reg, mask, val);
return 0;
}
static const char *const etdm_out_sgen_map[] = {
"Off", "On",
};
static SOC_ENUM_SINGLE_EXT_DECL(etdm_out_sgen_map_enum,
etdm_out_sgen_map);
/* lpbk */
static const int etdm_lpbk_idx[] = {
0x0, 0xa,
};
static int etdm_lpbk_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component =
snd_soc_kcontrol_component(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
unsigned int value = 0;
unsigned int reg = 0;
unsigned int mask = 0;
unsigned int shift = 0;
if (!strcmp(kcontrol->id.name, "ETDM_LPBK_0")) {
reg = ETDM_0_3_COWORK_CON1;
mask = ETDM_IN1_SDATA0_SEL_MASK_SFT;
shift = ETDM_IN1_SDATA0_SEL_SFT;
} else if (!strcmp(kcontrol->id.name, "ETDM_LPBK_1")) {
reg = ETDM_0_3_COWORK_CON1;
mask = ETDM_IN1_SDATA1_15_SEL_MASK_SFT;
shift = ETDM_IN1_SDATA1_15_SEL_SFT;
}
if (reg)
regmap_read(afe->regmap, reg, &value);
value &= mask;
value >>= shift;
ucontrol->value.enumerated.item[0] = value;
if (value == 0xa)
ucontrol->value.enumerated.item[0] = 1;
else
ucontrol->value.enumerated.item[0] = 0;
return 0;
}
static int etdm_lpbk_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
unsigned int value = ucontrol->value.integer.value[0];
unsigned int reg = 0;
unsigned int val = 0;
unsigned int mask = 0;
if (value >= ARRAY_SIZE(etdm_lpbk_idx))
return -EINVAL;
if (!strcmp(kcontrol->id.name, "ETDM_LPBK_0")) {
reg = ETDM_0_3_COWORK_CON1;
mask = ETDM_IN1_SDATA0_SEL_MASK_SFT;
val = etdm_lpbk_idx[value] << ETDM_IN1_SDATA0_SEL_SFT;
} else if (!strcmp(kcontrol->id.name, "ETDM_LPBK_1")) {
reg = ETDM_0_3_COWORK_CON1;
mask = ETDM_IN1_SDATA1_15_SEL_MASK_SFT;
val = etdm_lpbk_idx[value] << ETDM_IN1_SDATA1_15_SEL_SFT;
}
if (reg)
regmap_update_bits(afe->regmap, reg, mask, val);
return 0;
}
static const char *const etdm_lpbk_map[] = {
"Off", "On",
};
static SOC_ENUM_SINGLE_EXT_DECL(etdm_lpbk_map_enum,
etdm_lpbk_map);
/* lpbk */
/* multi-ip mode */
static const int etdm_ip_mode_idx[] = {
0x0, 0x1,
};
static int etdm_ip_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component =
snd_soc_kcontrol_component(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
unsigned int value = 0;
unsigned int reg = 0;
unsigned int mask = 0;
unsigned int shift = 0;
reg = ETDM_IN1_CON2;
mask = REG_MULTI_IP_MODE_MASK_SFT;
shift = REG_MULTI_IP_MODE_SFT;
if (reg)
regmap_read(afe->regmap, reg, &value);
value &= mask;
value >>= shift;
ucontrol->value.enumerated.item[0] = value;
return 0;
}
static int etdm_ip_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
unsigned int value = ucontrol->value.integer.value[0];
if (value >= ARRAY_SIZE(etdm_ip_mode_idx))
return -EINVAL;
/* 0: One IP multi-channel 1: Multi-IP 2-channel */
regmap_update_bits(afe->regmap, ETDM_IN1_CON2,
REG_MULTI_IP_MODE_MASK_SFT,
etdm_ip_mode_idx[value] << REG_MULTI_IP_MODE_SFT);
return 0;
}
static const char *const etdm_ip_mode_map[] = {
"Off", "On",
};
static SOC_ENUM_SINGLE_EXT_DECL(etdm_ip_mode_map_enum,
etdm_ip_mode_map);
/* multi-ip mode */
/* ch num */
static const int etdm_ch_num_idx[] = {
0x2, 0x4, 0x6, 0x8,
};
static int etdm_ch_num_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component =
snd_soc_kcontrol_component(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
unsigned int value = 0;
unsigned int reg = 0;
unsigned int mask = 0;
unsigned int shift = 0;
if (!strcmp(kcontrol->id.name, "ETDM_IN1_CH_NUM"))
reg = ETDM_IN1_CON0;
else if (!strcmp(kcontrol->id.name, "ETDM_OUT1_CH_NUM"))
reg = ETDM_OUT1_CON0;
mask = REG_CH_NUM_MASK_SFT;
shift = REG_CH_NUM_SFT;
if (reg)
regmap_read(afe->regmap, reg, &value);
value &= mask;
value >>= shift;
if (value == 0x1)
ucontrol->value.enumerated.item[0] = 0;
else if (value == 0x3)
ucontrol->value.enumerated.item[0] = 1;
else if (value == 0x5)
ucontrol->value.enumerated.item[0] = 2;
else
ucontrol->value.enumerated.item[0] = 3;
return 0;
}
static int etdm_ch_num_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
unsigned int value = ucontrol->value.integer.value[0];
unsigned int reg = 0;
unsigned int val = 0;
unsigned int mask = 0;
if (value >= ARRAY_SIZE(etdm_ch_num_idx))
return -EINVAL;
if (!strcmp(kcontrol->id.name, "ETDM_IN1_CH_NUM"))
reg = ETDM_IN1_CON0;
else if (!strcmp(kcontrol->id.name, "ETDM_OUT1_CH_NUM"))
reg = ETDM_OUT1_CON0;
mask = REG_CH_NUM_MASK_SFT;
val = (etdm_ch_num_idx[value] - 1) << REG_CH_NUM_SFT;
if (reg)
regmap_update_bits(afe->regmap, reg, mask, val);
return 0;
}
static const char *const etdm_ch_num_map[] = {
"2CH", "4CH", "6CH", "8CH",
};
static SOC_ENUM_SINGLE_EXT_DECL(etdm_ch_num_map_enum,
etdm_ch_num_map);
/* ch num */
/* dai component */
static const struct snd_kcontrol_new mtk_etdm_playback_ch1_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("DL11_CH1", AFE_CONN62_2, I_DL11_CH1, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN62, I_ADDA_UL_CH1, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN62, I_PCM_2_CAP_CH1, 1, 0),
};
static const struct snd_kcontrol_new mtk_etdm_playback_ch2_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("DL11_CH2", AFE_CONN63_2, I_DL11_CH2, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN63, I_ADDA_UL_CH2, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN63, I_ADDA_UL_CH2, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN63, I_PCM_2_CAP_CH1, 1, 0),
};
static const struct snd_kcontrol_new mtk_etdm_playback_ch3_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("DL11_CH3", AFE_CONN64_2, I_DL11_CH3, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN62, I_ADDA_UL_CH1, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN64, I_PCM_2_CAP_CH1, 1, 0),
};
static const struct snd_kcontrol_new mtk_etdm_playback_ch4_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("DL11_CH4", AFE_CONN65_2, I_DL11_CH4, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN63, I_ADDA_UL_CH2, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN65, I_PCM_2_CAP_CH1, 1, 0),
};
static const struct snd_kcontrol_new mtk_etdm_playback_ch5_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("DL11_CH5", AFE_CONN66_2, I_DL11_CH5, 1, 0),
};
static const struct snd_kcontrol_new mtk_etdm_playback_ch6_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("DL11_CH6", AFE_CONN67_2, I_DL11_CH6, 1, 0),
};
static const struct snd_kcontrol_new mtk_etdm_playback_ch7_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("DL11_CH7", AFE_CONN68_2, I_DL11_CH7, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("DL11_CH1", AFE_CONN68_2, I_DL11_CH1, 1, 0),
};
static const struct snd_kcontrol_new mtk_etdm_playback_ch8_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("DL11_CH8", AFE_CONN69_2, I_DL11_CH8, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("DL11_CH2", AFE_CONN69_2, I_DL11_CH2, 1, 0),
};
enum {
SUPPLY_SEQ_APLL,
SUPPLY_SEQ_ETDM_MCLK_EN,
SUPPLY_SEQ_ETDM_EN,
};
/* Tinyconn Mux */
enum {
TINYCONN_CH1_MUX_DL11 = 32,
TINYCONN_CH2_MUX_DL11 = 33,
TINYCONN_CH3_MUX_DL11 = 34,
TINYCONN_CH4_MUX_DL11 = 35,
TINYCONN_CH5_MUX_DL11 = 36,
TINYCONN_CH6_MUX_DL11 = 37,
TINYCONN_CH7_MUX_DL11 = 38,
TINYCONN_CH8_MUX_DL11 = 39,
TINYCONN_MUX_NONE = 0x1f,
};
static const char * const tinyconn_mux_map[] = {
"NONE",
"DL11_CH1",
"DL11_CH2",
"DL11_CH3",
"DL11_CH4",
"DL11_CH5",
"DL11_CH6",
"DL11_CH7",
"DL11_CH8",
};
static int tinyconn_mux_map_value[] = {
TINYCONN_MUX_NONE,
TINYCONN_CH1_MUX_DL11,
TINYCONN_CH2_MUX_DL11,
TINYCONN_CH3_MUX_DL11,
TINYCONN_CH4_MUX_DL11,
TINYCONN_CH5_MUX_DL11,
TINYCONN_CH6_MUX_DL11,
TINYCONN_CH7_MUX_DL11,
TINYCONN_CH8_MUX_DL11,
};
static SOC_VALUE_ENUM_SINGLE_DECL(etdm_out_ch1_tinyconn_mux_map_enum,
AFE_TINY_CONN10, O_42_CFG_SFT,
O_42_CFG_MASK, tinyconn_mux_map,
tinyconn_mux_map_value);
static const struct snd_kcontrol_new etdm_out_ch1_tinyconn_mux_control =
SOC_DAPM_ENUM("etdm ch1 tinyconn Select",
etdm_out_ch1_tinyconn_mux_map_enum);
static SOC_VALUE_ENUM_SINGLE_DECL(etdm_out_ch2_tinyconn_mux_map_enum,
AFE_TINY_CONN10, O_43_CFG_SFT,
O_43_CFG_MASK, tinyconn_mux_map,
tinyconn_mux_map_value);
static const struct snd_kcontrol_new etdm_out_ch2_tinyconn_mux_control =
SOC_DAPM_ENUM("etdm ch2 tinyconn Select",
etdm_out_ch2_tinyconn_mux_map_enum);
static SOC_VALUE_ENUM_SINGLE_DECL(etdm_out_ch3_tinyconn_mux_map_enum,
AFE_TINY_CONN11, O_44_CFG_SFT,
O_44_CFG_MASK, tinyconn_mux_map,
tinyconn_mux_map_value);
static const struct snd_kcontrol_new etdm_out_ch3_tinyconn_mux_control =
SOC_DAPM_ENUM("etdm ch3 tinyconn Select",
etdm_out_ch3_tinyconn_mux_map_enum);
static SOC_VALUE_ENUM_SINGLE_DECL(etdm_out_ch4_tinyconn_mux_map_enum,
AFE_TINY_CONN11, O_45_CFG_SFT,
O_45_CFG_MASK, tinyconn_mux_map,
tinyconn_mux_map_value);
static const struct snd_kcontrol_new etdm_out_ch4_tinyconn_mux_control =
SOC_DAPM_ENUM("etdm ch4 tinyconn Select",
etdm_out_ch4_tinyconn_mux_map_enum);
static SOC_VALUE_ENUM_SINGLE_DECL(etdm_out_ch5_tinyconn_mux_map_enum,
AFE_TINY_CONN11, O_46_CFG_SFT,
O_46_CFG_MASK, tinyconn_mux_map,
tinyconn_mux_map_value);
static const struct snd_kcontrol_new etdm_out_ch5_tinyconn_mux_control =
SOC_DAPM_ENUM("etdm ch5 tinyconn Select",
etdm_out_ch5_tinyconn_mux_map_enum);
static SOC_VALUE_ENUM_SINGLE_DECL(etdm_out_ch6_tinyconn_mux_map_enum,
AFE_TINY_CONN11, O_47_CFG_SFT,
O_47_CFG_MASK, tinyconn_mux_map,
tinyconn_mux_map_value);
static const struct snd_kcontrol_new etdm_out_ch6_tinyconn_mux_control =
SOC_DAPM_ENUM("etdm ch6 tinyconn Select",
etdm_out_ch6_tinyconn_mux_map_enum);
static SOC_VALUE_ENUM_SINGLE_DECL(etdm_out_ch7_tinyconn_mux_map_enum,
AFE_TINY_CONN12, O_48_CFG_SFT,
O_48_CFG_MASK, tinyconn_mux_map,
tinyconn_mux_map_value);
static const struct snd_kcontrol_new etdm_out_ch7_tinyconn_mux_control =
SOC_DAPM_ENUM("etdm ch7 tinyconn Select",
etdm_out_ch7_tinyconn_mux_map_enum);
static SOC_VALUE_ENUM_SINGLE_DECL(etdm_out_ch8_tinyconn_mux_map_enum,
AFE_TINY_CONN12, O_49_CFG_SFT,
O_49_CFG_MASK, tinyconn_mux_map,
tinyconn_mux_map_value);
static const struct snd_kcontrol_new etdm_out_ch8_tinyconn_mux_control =
SOC_DAPM_ENUM("etdm ch8 tinyconn Select",
etdm_out_ch8_tinyconn_mux_map_enum);
static int etdm_out_tinyconn_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_info(afe->dev, "%s(), event 0x%x\n", __func__, event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
regmap_update_bits(afe->regmap, ETDM_OUT1_CON0,
REG_USE_TINYCONN_32BIT_MASK_SFT,
ETDM_USE_TINYCONN << REG_USE_TINYCONN_32BIT_SFT);
break;
case SND_SOC_DAPM_PRE_PMD:
regmap_update_bits(afe->regmap, ETDM_OUT1_CON0,
REG_USE_TINYCONN_32BIT_MASK_SFT,
ETDM_USE_INTERCONN << REG_USE_TINYCONN_32BIT_SFT);
break;
default:
break;
}
return 0;
}
static int mtk_mclk_en_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 mtk_afe_etdm_priv *etdm_priv;
dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
__func__, w->name, event);
etdm_priv = get_etdm_priv_by_name(afe, w->name);
if (!etdm_priv) {
AUDIO_AEE("i2s_priv == NULL");
return -EINVAL;
}
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
mt6985_mck_enable(afe, etdm_priv->mclk_id, etdm_priv->mclk_rate);
break;
case SND_SOC_DAPM_POST_PMD:
etdm_priv->mclk_rate = 0;
mt6985_mck_disable(afe, etdm_priv->mclk_id);
break;
default:
break;
}
return 0;
}
static int mtk_afe_etdm_apll_connect(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink)
{
struct snd_soc_dapm_widget *w = sink;
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_etdm_priv *etdm_priv;
int cur_apll = 0;
int apll = 0;
etdm_priv = get_etdm_priv_by_name(afe, w->name);
/* which apll */
cur_apll = mt6985_get_apll_by_name(afe, source->name);
if (etdm_priv)
apll = mt6985_get_apll_by_rate(afe, etdm_priv->etdm_rate);
else
dev_info(cmpnt->dev, "%s(), get etdm_priv null\n", __func__);
return (apll == cur_apll) ? 1 : 0;
}
static int mtk_etdm_en_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_info(cmpnt->dev, "%s(), name %s, event 0x%x\n",
__func__, w->name, event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
mt6985_afe_gpio_request(afe, true, MT6985_DAI_ETDMIN, 0);
mt6985_afe_gpio_request(afe, true, MT6985_DAI_ETDMOUT, 0);
break;
case SND_SOC_DAPM_POST_PMD:
mt6985_afe_gpio_request(afe, false, MT6985_DAI_ETDMIN, 0);
mt6985_afe_gpio_request(afe, false, MT6985_DAI_ETDMOUT, 0);
break;
default:
break;
}
return 0;
}
static const struct snd_kcontrol_new mtk_dai_etdm_controls[] = {
SOC_ENUM_EXT("ETDM_OUT1_SGEN", etdm_out_sgen_map_enum,
etdm_out_sgen_get, etdm_out_sgen_put),
SOC_ENUM_EXT("ETDM_OUT0_SGEN", etdm_out_sgen_map_enum,
etdm_out_sgen_get, etdm_out_sgen_put),
SOC_ENUM_EXT("ETDM_LPBK_0", etdm_lpbk_map_enum,
etdm_lpbk_get, etdm_lpbk_put),
SOC_ENUM_EXT("ETDM_LPBK_1", etdm_lpbk_map_enum,
etdm_lpbk_get, etdm_lpbk_put),
SOC_ENUM_EXT("ETDM_IN1_IP_MODE", etdm_ip_mode_map_enum,
etdm_ip_mode_get, etdm_ip_mode_put),
SOC_ENUM_EXT("ETDM_IN1_CH_NUM", etdm_ch_num_map_enum,
etdm_ch_num_get, etdm_ch_num_put),
SOC_ENUM_EXT("ETDM_OUT1_CH_NUM", etdm_ch_num_map_enum,
etdm_ch_num_get, etdm_ch_num_put),
};
static const struct snd_soc_dapm_widget mtk_dai_etdm_widgets[] = {
/* inter-connections */
SND_SOC_DAPM_MIXER("ETDM_OUT_CH1", SND_SOC_NOPM, 0, 0,
mtk_etdm_playback_ch1_mix,
ARRAY_SIZE(mtk_etdm_playback_ch1_mix)),
SND_SOC_DAPM_MIXER("ETDM_OUT_CH2", SND_SOC_NOPM, 0, 0,
mtk_etdm_playback_ch2_mix,
ARRAY_SIZE(mtk_etdm_playback_ch2_mix)),
SND_SOC_DAPM_MIXER("ETDM_OUT_CH3", SND_SOC_NOPM, 0, 0,
mtk_etdm_playback_ch3_mix,
ARRAY_SIZE(mtk_etdm_playback_ch3_mix)),
SND_SOC_DAPM_MIXER("ETDM_OUT_CH4", SND_SOC_NOPM, 0, 0,
mtk_etdm_playback_ch4_mix,
ARRAY_SIZE(mtk_etdm_playback_ch4_mix)),
SND_SOC_DAPM_MIXER("ETDM_OUT_CH5", SND_SOC_NOPM, 0, 0,
mtk_etdm_playback_ch5_mix,
ARRAY_SIZE(mtk_etdm_playback_ch5_mix)),
SND_SOC_DAPM_MIXER("ETDM_OUT_CH6", SND_SOC_NOPM, 0, 0,
mtk_etdm_playback_ch6_mix,
ARRAY_SIZE(mtk_etdm_playback_ch6_mix)),
SND_SOC_DAPM_MIXER("ETDM_OUT_CH7", SND_SOC_NOPM, 0, 0,
mtk_etdm_playback_ch7_mix,
ARRAY_SIZE(mtk_etdm_playback_ch7_mix)),
SND_SOC_DAPM_MIXER("ETDM_OUT_CH8", SND_SOC_NOPM, 0, 0,
mtk_etdm_playback_ch8_mix,
ARRAY_SIZE(mtk_etdm_playback_ch8_mix)),
/* tiny-connections */
SND_SOC_DAPM_MUX_E("ETDM_OUT_CH1_TINYCONN_MUX", SND_SOC_NOPM, 0, 0,
&etdm_out_ch1_tinyconn_mux_control,
etdm_out_tinyconn_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_MUX_E("ETDM_OUT_CH2_TINYCONN_MUX", SND_SOC_NOPM, 0, 0,
&etdm_out_ch2_tinyconn_mux_control,
etdm_out_tinyconn_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_MUX_E("ETDM_OUT_CH3_TINYCONN_MUX", SND_SOC_NOPM, 0, 0,
&etdm_out_ch3_tinyconn_mux_control,
etdm_out_tinyconn_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_MUX_E("ETDM_OUT_CH4_TINYCONN_MUX", SND_SOC_NOPM, 0, 0,
&etdm_out_ch4_tinyconn_mux_control,
etdm_out_tinyconn_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_MUX_E("ETDM_OUT_CH5_TINYCONN_MUX", SND_SOC_NOPM, 0, 0,
&etdm_out_ch5_tinyconn_mux_control,
etdm_out_tinyconn_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_MUX_E("ETDM_OUT_CH6_TINYCONN_MUX", SND_SOC_NOPM, 0, 0,
&etdm_out_ch6_tinyconn_mux_control,
etdm_out_tinyconn_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_MUX_E("ETDM_OUT_CH7_TINYCONN_MUX", SND_SOC_NOPM, 0, 0,
&etdm_out_ch7_tinyconn_mux_control,
etdm_out_tinyconn_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_MUX_E("ETDM_OUT_CH8_TINYCONN_MUX", SND_SOC_NOPM, 0, 0,
&etdm_out_ch8_tinyconn_mux_control,
etdm_out_tinyconn_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
/* etdm mclk en */
SND_SOC_DAPM_SUPPLY_S(ETDMIN_MCLK_EN_W_NAME, SUPPLY_SEQ_ETDM_MCLK_EN,
SND_SOC_NOPM, 0, 0,
mtk_mclk_en_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY_S(ETDMOUT_MCLK_EN_W_NAME, SUPPLY_SEQ_ETDM_MCLK_EN,
SND_SOC_NOPM, 0, 0,
mtk_mclk_en_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
/* etdm en*/
SND_SOC_DAPM_SUPPLY_S("ETDM_EN", SUPPLY_SEQ_ETDM_EN,
ETDM_OUT1_CON0, REG_ETDM_OUT_EN_SFT, 0,
mtk_etdm_en_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
/* endpoint */
SND_SOC_DAPM_INPUT("ETDM_INPUT"),
SND_SOC_DAPM_OUTPUT("ETDM_OUTPUT"),
};
static const struct snd_soc_dapm_route mtk_dai_etdm_routes[] = {
{"ETDM_OUT_CH1", "DL11_CH1", "DL11"},
{"ETDM_OUT_CH2", "DL11_CH2", "DL11"},
{"ETDM_OUT_CH3", "DL11_CH3", "DL11"},
{"ETDM_OUT_CH4", "DL11_CH4", "DL11"},
{"ETDM_OUT_CH5", "DL11_CH5", "DL11"},
{"ETDM_OUT_CH6", "DL11_CH6", "DL11"},
{"ETDM_OUT_CH7", "DL11_CH7", "DL11"},
{"ETDM_OUT_CH8", "DL11_CH8", "DL11"},
{"ETDM_OUT_CH7", "DL11_CH1", "DL11"},
{"ETDM_OUT_CH8", "DL11_CH2", "DL11"},
{"ETDM Playback", NULL, "ETDM_OUT_CH1"},
{"ETDM Playback", NULL, "ETDM_OUT_CH2"},
{"ETDM Playback", NULL, "ETDM_OUT_CH3"},
{"ETDM Playback", NULL, "ETDM_OUT_CH4"},
{"ETDM Playback", NULL, "ETDM_OUT_CH5"},
{"ETDM Playback", NULL, "ETDM_OUT_CH6"},
{"ETDM Playback", NULL, "ETDM_OUT_CH7"},
{"ETDM Playback", NULL, "ETDM_OUT_CH8"},
{"ETDM_OUTPUT", NULL, "ETDM Playback"},
{"ETDM Capture", NULL, "ETDM_INPUT"},
{"ETDM Playback", NULL, "aud_tdm_clk"},
{"ETDM Playback", NULL, "ETDM_EN"},
{"ETDM Playback", NULL, APLL1_W_NAME, mtk_afe_etdm_apll_connect},
{"ETDM Playback", NULL, APLL2_W_NAME, mtk_afe_etdm_apll_connect},
{"ETDM Capture", NULL, "aud_tdm_clk"},
{"ETDM Capture", NULL, "ETDM_EN"},
{"ETDM Capture", NULL, APLL1_W_NAME, mtk_afe_etdm_apll_connect},
{"ETDM Capture", NULL, APLL2_W_NAME, mtk_afe_etdm_apll_connect},
{"ETDM_OUT_CH1_TINYCONN_MUX", "DL11_CH1", "DL11"},
{"ETDM_OUT_CH2_TINYCONN_MUX", "DL11_CH2", "DL11"},
{"ETDM_OUT_CH3_TINYCONN_MUX", "DL11_CH3", "DL11"},
{"ETDM_OUT_CH4_TINYCONN_MUX", "DL11_CH4", "DL11"},
{"ETDM_OUT_CH5_TINYCONN_MUX", "DL11_CH5", "DL11"},
{"ETDM_OUT_CH6_TINYCONN_MUX", "DL11_CH6", "DL11"},
{"ETDM_OUT_CH7_TINYCONN_MUX", "DL11_CH7", "DL11"},
{"ETDM_OUT_CH8_TINYCONN_MUX", "DL11_CH8", "DL11"},
{"ETDM Playback", NULL, "ETDM_OUT_CH1_TINYCONN_MUX"},
{"ETDM Playback", NULL, "ETDM_OUT_CH2_TINYCONN_MUX"},
{"ETDM Playback", NULL, "ETDM_OUT_CH3_TINYCONN_MUX"},
{"ETDM Playback", NULL, "ETDM_OUT_CH4_TINYCONN_MUX"},
{"ETDM Playback", NULL, "ETDM_OUT_CH5_TINYCONN_MUX"},
{"ETDM Playback", NULL, "ETDM_OUT_CH6_TINYCONN_MUX"},
{"ETDM Playback", NULL, "ETDM_OUT_CH7_TINYCONN_MUX"},
{"ETDM Playback", NULL, "ETDM_OUT_CH8_TINYCONN_MUX"},
};
/* dai ops */
static int mtk_dai_etdm_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 mt6985_afe_private *afe_priv = afe->platform_priv;
int etdm_id = dai->id;
struct mtk_afe_etdm_priv *etdm_priv = afe_priv->dai_priv[etdm_id];
unsigned int rate = params_rate(params);
unsigned int channels = params_channels(params);
snd_pcm_format_t format = params_format(params);
dev_info(afe->dev, "%s(), %s(%d), stream %d, rate %d channels %d format %d\n",
__func__, dai->name, etdm_id, substream->stream, rate, channels, format);
etdm_priv->etdm_rate = rate;
/* ETDM_IN Supports even channel only */
if ((channels % 2) != 0)
dev_info(afe->dev, "%s(), channels(%d) not even\n", __func__, channels);
if (etdm_id == MT6985_DAI_ETDMIN) {
/* ---etdm in --- */
regmap_update_bits(afe->regmap, ETDM_IN1_CON1,
REG_INITIAL_COUNT_MASK_SFT,
0x5 << REG_INITIAL_COUNT_SFT);
/* 3: pad top 5: no pad top */
regmap_update_bits(afe->regmap, ETDM_IN1_CON1,
REG_INITIAL_POINT_MASK_SFT,
0x3 << REG_INITIAL_POINT_SFT);
regmap_update_bits(afe->regmap, ETDM_IN1_CON1,
REG_LRCK_RESET_MASK_SFT,
0x1 << REG_LRCK_RESET_SFT);
regmap_update_bits(afe->regmap, ETDM_IN1_CON2,
REG_CLOCK_SOURCE_SEL_MASK_SFT,
ETDM_CLK_SOURCE_APLL << REG_CLOCK_SOURCE_SEL_SFT);
/* 0: manual 1: auto */
regmap_update_bits(afe->regmap, ETDM_IN1_CON2,
REG_CK_EN_SEL_AUTO_MASK_SFT,
0x1 << REG_CK_EN_SEL_AUTO_SFT);
regmap_update_bits(afe->regmap, ETDM_IN1_CON3,
REG_FS_TIMING_SEL_MASK_SFT,
get_etdm_rate(rate) << REG_FS_TIMING_SEL_SFT);
regmap_update_bits(afe->regmap, ETDM_IN1_CON4,
REG_RELATCH_1X_EN_SEL_MASK_SFT,
get_etdm_inconn_rate(rate) << REG_RELATCH_1X_EN_SEL_SFT);
regmap_update_bits(afe->regmap, ETDM_IN1_CON8,
REG_ETDM_USE_AFIFO_MASK_SFT,
0x0 << REG_ETDM_USE_AFIFO_SFT);
regmap_update_bits(afe->regmap, ETDM_IN1_CON8,
REG_AFIFO_MODE_MASK_SFT,
0x0 << REG_AFIFO_MODE_SFT);
regmap_update_bits(afe->regmap, ETDM_IN1_CON9,
REG_ALMOST_END_CH_COUNT_MASK_SFT,
0x0 << REG_ALMOST_END_CH_COUNT_SFT);
regmap_update_bits(afe->regmap, ETDM_IN1_CON9,
REG_ALMOST_END_BIT_COUNT_MASK_SFT,
0x0 << REG_ALMOST_END_BIT_COUNT_SFT);
regmap_update_bits(afe->regmap, ETDM_IN1_CON9,
REG_OUT2_LATCH_TIME_MASK_SFT,
0x6 << REG_OUT2_LATCH_TIME_SFT);
/* 5: TDM Mode */
regmap_update_bits(afe->regmap, ETDM_IN1_CON0,
REG_FMT_MASK_SFT, 0x5 << REG_FMT_SFT);
/* APLL */
regmap_update_bits(afe->regmap, ETDM_IN1_CON0,
REG_RELATCH_1X_EN_SEL_DOMAIN_MASK_SFT,
ETDM_RELATCH_SEL_APLL
<< REG_RELATCH_1X_EN_SEL_DOMAIN_SFT);
regmap_update_bits(afe->regmap, ETDM_IN1_CON0,
REG_BIT_LENGTH_MASK_SFT,
get_etdm_lrck_width(format) << REG_BIT_LENGTH_SFT);
regmap_update_bits(afe->regmap, ETDM_IN1_CON0,
REG_WORD_LENGTH_MASK_SFT,
get_etdm_wlen(format) << REG_WORD_LENGTH_SFT);
} else {
/* ---etdm out --- */
regmap_update_bits(afe->regmap, ETDM_OUT1_CON1,
REG_INITIAL_COUNT_MASK_SFT,
0x5 << REG_INITIAL_COUNT_SFT);
regmap_update_bits(afe->regmap, ETDM_OUT1_CON1,
REG_INITIAL_POINT_MASK_SFT,
0x6 << REG_INITIAL_POINT_SFT);
regmap_update_bits(afe->regmap, ETDM_OUT1_CON1,
REG_LRCK_RESET_MASK_SFT,
0x1 << REG_LRCK_RESET_SFT);
regmap_update_bits(afe->regmap, ETDM_OUT1_CON4,
OUT_REG_FS_TIMING_SEL_MASK_SFT,
get_etdm_rate(rate) << OUT_REG_FS_TIMING_SEL_SFT);
regmap_update_bits(afe->regmap, ETDM_OUT1_CON4,
OUT_REG_CLOCK_SOURCE_SEL_MASK_SFT,
ETDM_CLK_SOURCE_APLL << OUT_REG_CLOCK_SOURCE_SEL_SFT);
regmap_update_bits(afe->regmap, ETDM_OUT1_CON4,
INTERCONN_OUT_EN_SEL_MASK_SFT,
get_etdm_inconn_rate(rate) << INTERCONN_OUT_EN_SEL_SFT);
/* 5: TDM Mode */
regmap_update_bits(afe->regmap, ETDM_OUT1_CON0,
REG_FMT_MASK_SFT, 0x5 << REG_FMT_SFT);
/* APLL */
regmap_update_bits(afe->regmap, ETDM_OUT1_CON0,
REG_RELATCH_1X_EN_SEL_DOMAIN_MASK_SFT,
ETDM_RELATCH_SEL_APLL
<< REG_RELATCH_1X_EN_SEL_DOMAIN_SFT);
regmap_update_bits(afe->regmap, ETDM_OUT1_CON0,
REG_BIT_LENGTH_MASK_SFT,
get_etdm_lrck_width(format) << REG_BIT_LENGTH_SFT);
regmap_update_bits(afe->regmap, ETDM_OUT1_CON0,
REG_WORD_LENGTH_MASK_SFT,
get_etdm_wlen(format) << REG_WORD_LENGTH_SFT);
}
if (etdm_id == MT6985_DAI_ETDMIN) {
/* ---etdm cowork --- */
regmap_update_bits(afe->regmap, ETDM_0_3_COWORK_CON0,
ETDM_IN0_SLAVE_SEL_MASK_SFT,
ETDM_SLAVE_SEL_ETDMOUT0_MASTER
<< ETDM_IN0_SLAVE_SEL_SFT);
regmap_update_bits(afe->regmap, ETDM_0_3_COWORK_CON1,
ETDM_IN1_SLAVE_SEL_MASK_SFT,
ETDM_SLAVE_SEL_ETDMOUT1_MASTER
<< ETDM_IN1_SLAVE_SEL_SFT);
} else {
regmap_update_bits(afe->regmap, ETDM_0_3_COWORK_CON0,
ETDM_OUT0_SLAVE_SEL_MASK_SFT,
ETDM_SLAVE_SEL_ETDMIN0_MASTER
<< ETDM_OUT0_SLAVE_SEL_SFT);
regmap_update_bits(afe->regmap, ETDM_0_3_COWORK_CON0,
ETDM_OUT1_SLAVE_SEL_MASK_SFT,
ETDM_SLAVE_SEL_ETDMIN1_MASTER
<< ETDM_OUT1_SLAVE_SEL_SFT);
}
if (etdm_id == MT6985_DAI_ETDMIN) {
/* INTERCONN mux */
regmap_update_bits(afe->regmap, ETDM_0_3_COWORK_CON1,
ETDM_IN0_INTERCONN_MUX_SEL_MASK_SFT,
0x0 << ETDM_IN0_INTERCONN_MUX_SEL_SFT);//24
} else {
regmap_update_bits(afe->regmap, ETDM_0_3_COWORK_CON1,
ETDM_OUT0_INTERCONN_MUX_SEL_MASK_SFT,
0x1 << ETDM_OUT0_INTERCONN_MUX_SEL_SFT);//25
}
return 0;
}
static int mtk_dai_etdm_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
dev_info(afe->dev, "%s(), %s(%d): cmd %d\n", __func__, dai->name, dai->id, cmd);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
/* enable etdm in/out */
if (dai->id == MT6985_DAI_ETDMIN) {
mt6985_afe_gpio_request(afe, true, MT6985_DAI_ETDMIN, 0);
mt6985_afe_gpio_request(afe, true, MT6985_DAI_ETDMOUT, 0);
regmap_update_bits(afe->regmap, ETDM_IN1_CON0,
REG_ETDM_IN_EN_MASK_SFT,
0x1 << REG_ETDM_IN_EN_SFT);
} else {
mt6985_afe_gpio_request(afe, true, MT6985_DAI_ETDMOUT, 0);
regmap_update_bits(afe->regmap, ETDM_OUT1_CON0,
REG_ETDM_OUT_EN_MASK_SFT,
0x1 << REG_ETDM_OUT_EN_SFT);
}
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
/* disable etdm in/out */
if (dai->id == MT6985_DAI_ETDMIN) {
regmap_update_bits(afe->regmap, ETDM_IN1_CON0,
REG_ETDM_IN_EN_MASK_SFT,
0x0 << REG_ETDM_IN_EN_SFT);
mt6985_afe_gpio_request(afe, false, MT6985_DAI_ETDMIN, 0);
mt6985_afe_gpio_request(afe, false, MT6985_DAI_ETDMOUT, 0);
} else {
regmap_update_bits(afe->regmap, ETDM_OUT1_CON0,
REG_ETDM_OUT_EN_MASK_SFT,
0x0 << REG_ETDM_OUT_EN_SFT);
mt6985_afe_gpio_request(afe, false, MT6985_DAI_ETDMOUT, 0);
}
break;
default:
return -EINVAL;
}
return 0;
}
static const struct snd_soc_dai_ops mtk_dai_etdm_ops = {
.hw_params = mtk_dai_etdm_hw_params,
.trigger = mtk_dai_etdm_trigger,
};
/* dai driver */
#define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_384000)
#define MTK_ETDM_FORMATS (SNDRV_PCM_FMTBIT_S8 |\
SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S24_LE |\
SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
{
.name = "ETDMIN",
.id = MT6985_DAI_ETDMIN,
.capture = {
.stream_name = "ETDM Capture",
.channels_min = 2,
.channels_max = 8,
.rates = MTK_ETDM_RATES,
.formats = MTK_ETDM_FORMATS,
},
.ops = &mtk_dai_etdm_ops,
.symmetric_rate = 1,
.symmetric_sample_bits = 1,
},
{
.name = "ETDMOUT",
.id = MT6985_DAI_ETDMOUT,
.playback = {
.stream_name = "ETDM Playback",
.channels_min = 1,
.channels_max = 8,
.rates = MTK_ETDM_RATES,
.formats = MTK_ETDM_FORMATS,
},
.ops = &mtk_dai_etdm_ops,
.symmetric_rate = 1,
.symmetric_sample_bits = 1,
},
};
static int etdm_parse_dt(struct mtk_base_afe *afe)
{
int ret;
unsigned int ch_num_in;
unsigned int ch_num_out;
unsigned int sync_in;
unsigned int sync_out;
/* get etdm ch */
ret = of_property_read_u32(afe->dev->of_node, "etdm-out-ch", &ch_num_out);
if (ret) {
dev_info(afe->dev, "%s() failed to read etdm-out-ch\n", __func__);
return -EINVAL;
}
regmap_update_bits(afe->regmap, ETDM_OUT1_CON0,
REG_CH_NUM_MASK_SFT, (ch_num_out - 1) << REG_CH_NUM_SFT);
dev_info(afe->dev, "%s() etdm-out-ch: %d\n", __func__, ch_num_out);
ret = of_property_read_u32(afe->dev->of_node, "etdm-in-ch", &ch_num_in);
if (ret) {
dev_info(afe->dev, "%s() failed to read etdm-in-ch\n", __func__);
return -EINVAL;
}
regmap_update_bits(afe->regmap, ETDM_IN1_CON0,
REG_CH_NUM_MASK_SFT, (ch_num_in - 1) << REG_CH_NUM_SFT);
dev_info(afe->dev, "%s() etdm-in-ch: %d\n", __func__, ch_num_in);
/* get etdm sync */
ret = of_property_read_u32(afe->dev->of_node, "etdm-out-sync", &sync_out);
if (ret) {
dev_info(afe->dev, "%s() failed to read etdm-out-sync\n", __func__);
return -EINVAL;
}
regmap_update_bits(afe->regmap, ETDM_OUT1_CON0,
REG_SYNC_MODE_MASK_SFT, sync_out << REG_SYNC_MODE_SFT);
dev_info(afe->dev, "%s() etdm-out-sync: %d\n", __func__, sync_out);
ret = of_property_read_u32(afe->dev->of_node, "etdm-in-sync", &sync_in);
if (ret) {
dev_info(afe->dev, "%s() failed to read etdm-in-sync\n", __func__);
return -EINVAL;
}
regmap_update_bits(afe->regmap, ETDM_IN1_CON0,
REG_SYNC_MODE_MASK_SFT, sync_in << REG_SYNC_MODE_SFT);
dev_info(afe->dev, "%s() etdm-in-sync: %d\n", __func__, sync_in);
return 0;
}
int init_etdm_priv_data(struct mtk_base_afe *afe)
{
int i;
int ret;
for (i = 0; i < DAI_ETDM_NUM; i++) {
ret = mt6985_dai_set_priv(afe, mt6985_etdm_priv[i].id,
sizeof(struct mtk_afe_etdm_priv),
&mt6985_etdm_priv[i]);
if (ret)
return ret;
}
return 0;
}
int mt6985_dai_etdm_register(struct mtk_base_afe *afe)
{
struct mtk_base_afe_dai *dai;
int ret = 0;
dev_info(afe->dev, "%s() start success\n", __func__);
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_etdm_driver;
dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_etdm_driver);
dai->dapm_widgets = mtk_dai_etdm_widgets;
dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_etdm_widgets);
dai->dapm_routes = mtk_dai_etdm_routes;
dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_etdm_routes);
dai->controls = mtk_dai_etdm_controls;
dai->num_controls = ARRAY_SIZE(mtk_dai_etdm_controls);
ret = init_etdm_priv_data(afe);
if (ret)
return ret;
/* 0: One IP multi-channel 1: Multi-IP 2-channel */
regmap_update_bits(afe->regmap, ETDM_IN1_CON2,
REG_MULTI_IP_MODE_MASK_SFT,
0x1 << REG_MULTI_IP_MODE_SFT);
ret = etdm_parse_dt(afe);
if (ret) {
dev_info(afe->dev, "%s() fail to parse dts: %d\n", __func__, ret);
return ret;
}
return 0;
}