ASoC: Intel: soc-acpi and machine driver updates

Merge series from Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>:

Small updates to add initial tables for MeteorLake, SoundWire machine
driver support for tests without HDMI and RT1019 for consistency on
Chromebooks.
This commit is contained in:
Mark Brown 2022-06-07 11:52:07 +01:00
Родитель a8b1b9ce5d 8208dd75eb
Коммит 2822388960
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 24D68B725D5487D0
26 изменённых файлов: 9049 добавлений и 26 удалений

Просмотреть файл

@ -30,6 +30,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_sdw_machines[];
@ -37,6 +38,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[];
/*
* generic table used for HDA codec-based platforms, possibly with

Просмотреть файл

@ -2479,6 +2479,7 @@ static int mt6358_platform_driver_probe(struct platform_device *pdev)
static const struct of_device_id mt6358_of_match[] = {
{.compatible = "mediatek,mt6358-sound",},
{.compatible = "mediatek,mt6366-sound",},
{}
};
MODULE_DEVICE_TABLE(of, mt6358_of_match);

Просмотреть файл

@ -660,7 +660,6 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH
depends on MFD_INTEL_LPSS || COMPILE_TEST
depends on SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES || COMPILE_TEST
depends on SOUNDWIRE
depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC
select SND_SOC_MAX98373_I2C
select SND_SOC_MAX98373_SDW
select SND_SOC_RT700_SDW

Просмотреть файл

@ -463,26 +463,26 @@ EXPORT_SYMBOL_NS(sof_rt1308_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);
* 2-amp Configuration for RT1019
*/
static const struct snd_soc_dapm_route rt1019_dapm_routes[] = {
static const struct snd_soc_dapm_route rt1019p_dapm_routes[] = {
/* speaker */
{ "Left Spk", NULL, "Speaker" },
{ "Right Spk", NULL, "Speaker" },
};
static struct snd_soc_dai_link_component rt1019_components[] = {
static struct snd_soc_dai_link_component rt1019p_components[] = {
{
.name = RT1019_DEV0_NAME,
.dai_name = RT1019_CODEC_DAI,
.name = RT1019P_DEV0_NAME,
.dai_name = RT1019P_CODEC_DAI,
},
};
static int rt1019_init(struct snd_soc_pcm_runtime *rtd)
static int rt1019p_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
int ret;
ret = snd_soc_dapm_add_routes(&card->dapm, rt1019_dapm_routes,
ARRAY_SIZE(rt1019_dapm_routes));
ret = snd_soc_dapm_add_routes(&card->dapm, rt1019p_dapm_routes,
ARRAY_SIZE(rt1019p_dapm_routes));
if (ret) {
dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);
return ret;
@ -490,13 +490,13 @@ static int rt1019_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
void sof_rt1019_dai_link(struct snd_soc_dai_link *link)
void sof_rt1019p_dai_link(struct snd_soc_dai_link *link)
{
link->codecs = rt1019_components;
link->num_codecs = ARRAY_SIZE(rt1019_components);
link->init = rt1019_init;
link->codecs = rt1019p_components;
link->num_codecs = ARRAY_SIZE(rt1019p_components);
link->init = rt1019p_init;
}
EXPORT_SYMBOL_NS(sof_rt1019_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);
EXPORT_SYMBOL_NS(sof_rt1019p_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);
MODULE_DESCRIPTION("ASoC Intel SOF Realtek helpers");
MODULE_LICENSE("GPL");

Просмотреть файл

@ -39,9 +39,9 @@ void sof_rt1015_codec_conf(struct snd_soc_card *card);
#define RT1308_DEV0_NAME "i2c-10EC1308:00"
void sof_rt1308_dai_link(struct snd_soc_dai_link *link);
#define RT1019_CODEC_DAI "HiFi"
#define RT1019_DEV0_NAME "RTL1019:00"
#define RT1019P_CODEC_DAI "HiFi"
#define RT1019P_DEV0_NAME "RTL1019:00"
void sof_rt1019_dai_link(struct snd_soc_dai_link *link);
void sof_rt1019p_dai_link(struct snd_soc_dai_link *link);
#endif /* __SOF_REALTEK_COMMON_H */

Просмотреть файл

@ -735,7 +735,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
} else if (sof_rt5682_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) {
sof_rt1015p_dai_link(&links[id]);
} else if (sof_rt5682_quirk & SOF_RT1019_SPEAKER_AMP_PRESENT) {
sof_rt1019_dai_link(&links[id]);
sof_rt1019p_dai_link(&links[id]);
} else if (sof_rt5682_quirk &
SOF_MAX98373_SPEAKER_AMP_PRESENT) {
links[id].codecs = max_98373_components;

Просмотреть файл

@ -1127,10 +1127,14 @@ static int sof_card_dai_links_create(struct device *dev,
for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
codec_info_list[i].amp_num = 0;
if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
hdmi_num = SOF_TGL_HDMI_COUNT;
else
hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
if (mach_params->codec_mask & IDISP_CODEC_MASK) {
ctx->idisp_codec = true;
if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
hdmi_num = SOF_TGL_HDMI_COUNT;
else
hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
}
ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);
/*
@ -1150,9 +1154,6 @@ static int sof_card_dai_links_create(struct device *dev,
return ret;
}
if (mach_params->codec_mask & IDISP_CODEC_MASK)
ctx->idisp_codec = true;
/* enable dmic01 & dmic16k */
dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) ? 2 : 0;
comp_num += dmic_num;
@ -1375,7 +1376,9 @@ HDMI:
static int sof_sdw_card_late_probe(struct snd_soc_card *card)
{
int i, ret;
struct mc_private *ctx = snd_soc_card_get_drvdata(card);
int ret = 0;
int i;
for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
if (!codec_info_list[i].late_probe)
@ -1386,7 +1389,10 @@ static int sof_sdw_card_late_probe(struct snd_soc_card *card)
return ret;
}
return sof_sdw_hdmi_card_late_probe(card);
if (ctx->idisp_codec)
ret = sof_sdw_hdmi_card_late_probe(card);
return ret;
}
/* SoC card */

Просмотреть файл

@ -9,6 +9,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m
soc-acpi-intel-cml-match.o soc-acpi-intel-icl-match.o \
soc-acpi-intel-tgl-match.o soc-acpi-intel-ehl-match.o \
soc-acpi-intel-jsl-match.o soc-acpi-intel-adl-match.o \
soc-acpi-intel-mtl-match.o \
soc-acpi-intel-hda-match.o \
soc-acpi-intel-sdw-mockup-match.o

Просмотреть файл

@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* soc-acpi-intel-mtl-match.c - tables and support for MTL ACPI enumeration.
*
* Copyright (c) 2022, Intel Corporation.
*
*/
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
#include "soc-acpi-intel-sdw-mockup-match.h"
struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[] = {
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_machines);
/* this table is used when there is no I2S codec present */
struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
/* mockup tests need to be first */
{
.link_mask = GENMASK(3, 0),
.links = sdw_mockup_headset_2amps_mic,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt711-rt1308-rt715.tplg",
},
{
.link_mask = BIT(0) | BIT(1) | BIT(3),
.links = sdw_mockup_headset_1amp_mic,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt711-rt1308-mono-rt715.tplg",
},
{
.link_mask = GENMASK(2, 0),
.links = sdw_mockup_mic_headset_1amp,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt715-rt711-rt1308-mono.tplg",
},
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_sdw_machines);

Просмотреть файл

@ -0,0 +1,651 @@
// SPDX-License-Identifier: GPL-2.0
//
// mt8186-afe-clk.c -- Mediatek 8186 afe clock ctrl
//
// Copyright (c) 2022 MediaTek Inc.
// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
#include <linux/clk.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#include "mt8186-afe-common.h"
#include "mt8186-afe-clk.h"
#include "mt8186-audsys-clk.h"
static DEFINE_MUTEX(mutex_request_dram);
static const char *aud_clks[CLK_NUM] = {
[CLK_AFE] = "aud_afe_clk",
[CLK_DAC] = "aud_dac_clk",
[CLK_DAC_PREDIS] = "aud_dac_predis_clk",
[CLK_ADC] = "aud_adc_clk",
[CLK_TML] = "aud_tml_clk",
[CLK_APLL22M] = "aud_apll22m_clk",
[CLK_APLL24M] = "aud_apll24m_clk",
[CLK_APLL1_TUNER] = "aud_apll_tuner_clk",
[CLK_APLL2_TUNER] = "aud_apll2_tuner_clk",
[CLK_TDM] = "aud_tdm_clk",
[CLK_NLE] = "aud_nle_clk",
[CLK_DAC_HIRES] = "aud_dac_hires_clk",
[CLK_ADC_HIRES] = "aud_adc_hires_clk",
[CLK_I2S1_BCLK] = "aud_i2s1_bclk",
[CLK_I2S2_BCLK] = "aud_i2s2_bclk",
[CLK_I2S3_BCLK] = "aud_i2s3_bclk",
[CLK_I2S4_BCLK] = "aud_i2s4_bclk",
[CLK_CONNSYS_I2S_ASRC] = "aud_connsys_i2s_asrc",
[CLK_GENERAL1_ASRC] = "aud_general1_asrc",
[CLK_GENERAL2_ASRC] = "aud_general2_asrc",
[CLK_ADC_HIRES_TML] = "aud_adc_hires_tml",
[CLK_ADDA6_ADC] = "aud_adda6_adc",
[CLK_ADDA6_ADC_HIRES] = "aud_adda6_adc_hires",
[CLK_3RD_DAC] = "aud_3rd_dac",
[CLK_3RD_DAC_PREDIS] = "aud_3rd_dac_predis",
[CLK_3RD_DAC_TML] = "aud_3rd_dac_tml",
[CLK_3RD_DAC_HIRES] = "aud_3rd_dac_hires",
[CLK_ETDM_IN1_BCLK] = "aud_etdm_in1_bclk",
[CLK_ETDM_OUT1_BCLK] = "aud_etdm_out1_bclk",
[CLK_INFRA_SYS_AUDIO] = "aud_infra_clk",
[CLK_INFRA_AUDIO_26M] = "mtkaif_26m_clk",
[CLK_MUX_AUDIO] = "top_mux_audio",
[CLK_MUX_AUDIOINTBUS] = "top_mux_audio_int",
[CLK_TOP_MAINPLL_D2_D4] = "top_mainpll_d2_d4",
[CLK_TOP_MUX_AUD_1] = "top_mux_aud_1",
[CLK_TOP_APLL1_CK] = "top_apll1_ck",
[CLK_TOP_MUX_AUD_2] = "top_mux_aud_2",
[CLK_TOP_APLL2_CK] = "top_apll2_ck",
[CLK_TOP_MUX_AUD_ENG1] = "top_mux_aud_eng1",
[CLK_TOP_APLL1_D8] = "top_apll1_d8",
[CLK_TOP_MUX_AUD_ENG2] = "top_mux_aud_eng2",
[CLK_TOP_APLL2_D8] = "top_apll2_d8",
[CLK_TOP_MUX_AUDIO_H] = "top_mux_audio_h",
[CLK_TOP_I2S0_M_SEL] = "top_i2s0_m_sel",
[CLK_TOP_I2S1_M_SEL] = "top_i2s1_m_sel",
[CLK_TOP_I2S2_M_SEL] = "top_i2s2_m_sel",
[CLK_TOP_I2S4_M_SEL] = "top_i2s4_m_sel",
[CLK_TOP_TDM_M_SEL] = "top_tdm_m_sel",
[CLK_TOP_APLL12_DIV0] = "top_apll12_div0",
[CLK_TOP_APLL12_DIV1] = "top_apll12_div1",
[CLK_TOP_APLL12_DIV2] = "top_apll12_div2",
[CLK_TOP_APLL12_DIV4] = "top_apll12_div4",
[CLK_TOP_APLL12_DIV_TDM] = "top_apll12_div_tdm",
[CLK_CLK26M] = "top_clk26m_clk",
};
int mt8186_set_audio_int_bus_parent(struct mtk_base_afe *afe,
int clk_id)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
int ret;
ret = clk_set_parent(afe_priv->clk[CLK_MUX_AUDIOINTBUS],
afe_priv->clk[clk_id]);
if (ret) {
dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
__func__, aud_clks[CLK_MUX_AUDIOINTBUS],
aud_clks[clk_id], ret);
return ret;
}
return 0;
}
static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
int ret;
if (enable) {
ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_1]);
if (ret) {
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
__func__, aud_clks[CLK_TOP_MUX_AUD_1], ret);
return ret;
}
ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1],
afe_priv->clk[CLK_TOP_APLL1_CK]);
if (ret) {
dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
__func__, aud_clks[CLK_TOP_MUX_AUD_1],
aud_clks[CLK_TOP_APLL1_CK], ret);
return ret;
}
/* 180.6336 / 8 = 22.5792MHz */
ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]);
if (ret) {
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
__func__, aud_clks[CLK_TOP_MUX_AUD_ENG1], ret);
return ret;
}
ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1],
afe_priv->clk[CLK_TOP_APLL1_D8]);
if (ret) {
dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
__func__, aud_clks[CLK_TOP_MUX_AUD_ENG1],
aud_clks[CLK_TOP_APLL1_D8], ret);
return ret;
}
} else {
ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1],
afe_priv->clk[CLK_CLK26M]);
if (ret) {
dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
__func__, aud_clks[CLK_TOP_MUX_AUD_ENG1],
aud_clks[CLK_CLK26M], ret);
return ret;
}
clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]);
ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1],
afe_priv->clk[CLK_CLK26M]);
if (ret) {
dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
__func__, aud_clks[CLK_TOP_MUX_AUD_1],
aud_clks[CLK_CLK26M], ret);
return ret;
}
clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_1]);
}
return 0;
}
static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
int ret;
if (enable) {
ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_2]);
if (ret) {
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
__func__, aud_clks[CLK_TOP_MUX_AUD_2], ret);
return ret;
}
ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2],
afe_priv->clk[CLK_TOP_APLL2_CK]);
if (ret) {
dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
__func__, aud_clks[CLK_TOP_MUX_AUD_2],
aud_clks[CLK_TOP_APLL2_CK], ret);
return ret;
}
/* 196.608 / 8 = 24.576MHz */
ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]);
if (ret) {
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
__func__, aud_clks[CLK_TOP_MUX_AUD_ENG2], ret);
return ret;
}
ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2],
afe_priv->clk[CLK_TOP_APLL2_D8]);
if (ret) {
dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
__func__, aud_clks[CLK_TOP_MUX_AUD_ENG2],
aud_clks[CLK_TOP_APLL2_D8], ret);
return ret;
}
} else {
ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2],
afe_priv->clk[CLK_CLK26M]);
if (ret) {
dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
__func__, aud_clks[CLK_TOP_MUX_AUD_ENG2],
aud_clks[CLK_CLK26M], ret);
return ret;
}
clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]);
ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2],
afe_priv->clk[CLK_CLK26M]);
if (ret) {
dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
__func__, aud_clks[CLK_TOP_MUX_AUD_2],
aud_clks[CLK_CLK26M], ret);
return ret;
}
clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_2]);
}
return 0;
}
int mt8186_afe_enable_cgs(struct mtk_base_afe *afe)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
int ret = 0;
int i;
for (i = CLK_I2S1_BCLK; i <= CLK_ETDM_OUT1_BCLK; i++) {
ret = clk_prepare_enable(afe_priv->clk[i]);
if (ret) {
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
__func__, aud_clks[i], ret);
return ret;
}
}
return 0;
}
void mt8186_afe_disable_cgs(struct mtk_base_afe *afe)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
int i;
for (i = CLK_I2S1_BCLK; i <= CLK_ETDM_OUT1_BCLK; i++)
clk_disable_unprepare(afe_priv->clk[i]);
}
int mt8186_afe_enable_clock(struct mtk_base_afe *afe)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
int ret = 0;
ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_SYS_AUDIO]);
if (ret) {
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
__func__, aud_clks[CLK_INFRA_SYS_AUDIO], ret);
goto clk_infra_sys_audio_err;
}
ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_AUDIO_26M]);
if (ret) {
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
__func__, aud_clks[CLK_INFRA_AUDIO_26M], ret);
goto clk_infra_audio_26m_err;
}
ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIO]);
if (ret) {
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
__func__, aud_clks[CLK_MUX_AUDIO], ret);
goto clk_mux_audio_err;
}
ret = clk_set_parent(afe_priv->clk[CLK_MUX_AUDIO],
afe_priv->clk[CLK_CLK26M]);
if (ret) {
dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
__func__, aud_clks[CLK_MUX_AUDIO],
aud_clks[CLK_CLK26M], ret);
goto clk_mux_audio_err;
}
ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
if (ret) {
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
__func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret);
goto clk_mux_audio_intbus_err;
}
ret = mt8186_set_audio_int_bus_parent(afe,
CLK_TOP_MAINPLL_D2_D4);
if (ret)
goto clk_mux_audio_intbus_parent_err;
ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUDIO_H],
afe_priv->clk[CLK_TOP_APLL2_CK]);
if (ret) {
dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
__func__, aud_clks[CLK_TOP_MUX_AUDIO_H],
aud_clks[CLK_TOP_APLL2_CK], ret);
goto clk_mux_audio_h_parent_err;
}
ret = clk_prepare_enable(afe_priv->clk[CLK_AFE]);
if (ret) {
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
__func__, aud_clks[CLK_AFE], ret);
goto clk_afe_err;
}
return 0;
clk_afe_err:
clk_disable_unprepare(afe_priv->clk[CLK_AFE]);
clk_mux_audio_h_parent_err:
clk_mux_audio_intbus_parent_err:
mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M);
clk_mux_audio_intbus_err:
clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
clk_mux_audio_err:
clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIO]);
clk_infra_sys_audio_err:
clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUDIO]);
clk_infra_audio_26m_err:
clk_disable_unprepare(afe_priv->clk[CLK_INFRA_AUDIO_26M]);
return ret;
}
void mt8186_afe_disable_clock(struct mtk_base_afe *afe)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
clk_disable_unprepare(afe_priv->clk[CLK_AFE]);
mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M);
clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIO]);
clk_disable_unprepare(afe_priv->clk[CLK_INFRA_AUDIO_26M]);
clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUDIO]);
}
int mt8186_afe_suspend_clock(struct mtk_base_afe *afe)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
int ret;
/* set audio int bus to 26M */
ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
if (ret) {
dev_info(afe->dev, "%s clk_prepare_enable %s fail %d\n",
__func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret);
goto clk_mux_audio_intbus_err;
}
ret = mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M);
if (ret)
goto clk_mux_audio_intbus_parent_err;
clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
return 0;
clk_mux_audio_intbus_parent_err:
mt8186_set_audio_int_bus_parent(afe, CLK_TOP_MAINPLL_D2_D4);
clk_mux_audio_intbus_err:
clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
return ret;
}
int mt8186_afe_resume_clock(struct mtk_base_afe *afe)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
int ret;
/* set audio int bus to normal working clock */
ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
if (ret) {
dev_info(afe->dev, "%s clk_prepare_enable %s fail %d\n",
__func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret);
goto clk_mux_audio_intbus_err;
}
ret = mt8186_set_audio_int_bus_parent(afe,
CLK_TOP_MAINPLL_D2_D4);
if (ret)
goto clk_mux_audio_intbus_parent_err;
clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
return 0;
clk_mux_audio_intbus_parent_err:
mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M);
clk_mux_audio_intbus_err:
clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
return ret;
}
int mt8186_apll1_enable(struct mtk_base_afe *afe)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
int ret;
/* setting for APLL */
apll1_mux_setting(afe, true);
ret = clk_prepare_enable(afe_priv->clk[CLK_APLL22M]);
if (ret) {
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
__func__, aud_clks[CLK_APLL22M], ret);
goto err_clk_apll22m;
}
ret = clk_prepare_enable(afe_priv->clk[CLK_APLL1_TUNER]);
if (ret) {
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
__func__, aud_clks[CLK_APLL1_TUNER], ret);
goto err_clk_apll1_tuner;
}
regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0xfff7, 0x832);
regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0x1);
regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
AFE_22M_ON_MASK_SFT, BIT(AFE_22M_ON_SFT));
return 0;
err_clk_apll1_tuner:
clk_disable_unprepare(afe_priv->clk[CLK_APLL1_TUNER]);
err_clk_apll22m:
clk_disable_unprepare(afe_priv->clk[CLK_APLL22M]);
return ret;
}
void mt8186_apll1_disable(struct mtk_base_afe *afe)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
AFE_22M_ON_MASK_SFT, 0);
regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0);
clk_disable_unprepare(afe_priv->clk[CLK_APLL1_TUNER]);
clk_disable_unprepare(afe_priv->clk[CLK_APLL22M]);
apll1_mux_setting(afe, false);
}
int mt8186_apll2_enable(struct mtk_base_afe *afe)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
int ret;
/* setting for APLL */
apll2_mux_setting(afe, true);
ret = clk_prepare_enable(afe_priv->clk[CLK_APLL24M]);
if (ret) {
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
__func__, aud_clks[CLK_APLL24M], ret);
goto err_clk_apll24m;
}
ret = clk_prepare_enable(afe_priv->clk[CLK_APLL2_TUNER]);
if (ret) {
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
__func__, aud_clks[CLK_APLL2_TUNER], ret);
goto err_clk_apll2_tuner;
}
regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0xfff7, 0x634);
regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0x1);
regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
AFE_24M_ON_MASK_SFT, BIT(AFE_24M_ON_SFT));
return 0;
err_clk_apll2_tuner:
clk_disable_unprepare(afe_priv->clk[CLK_APLL2_TUNER]);
err_clk_apll24m:
clk_disable_unprepare(afe_priv->clk[CLK_APLL24M]);
return ret;
}
void mt8186_apll2_disable(struct mtk_base_afe *afe)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
AFE_24M_ON_MASK_SFT, 0);
regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0);
clk_disable_unprepare(afe_priv->clk[CLK_APLL2_TUNER]);
clk_disable_unprepare(afe_priv->clk[CLK_APLL24M]);
apll2_mux_setting(afe, false);
}
int mt8186_get_apll_rate(struct mtk_base_afe *afe, int apll)
{
return (apll == MT8186_APLL1) ? 180633600 : 196608000;
}
int mt8186_get_apll_by_rate(struct mtk_base_afe *afe, int rate)
{
return ((rate % 8000) == 0) ? MT8186_APLL2 : MT8186_APLL1;
}
int mt8186_get_apll_by_name(struct mtk_base_afe *afe, const char *name)
{
if (strcmp(name, APLL1_W_NAME) == 0)
return MT8186_APLL1;
return MT8186_APLL2;
}
/* mck */
struct mt8186_mck_div {
u32 m_sel_id;
u32 div_clk_id;
};
static const struct mt8186_mck_div mck_div[MT8186_MCK_NUM] = {
[MT8186_I2S0_MCK] = {
.m_sel_id = CLK_TOP_I2S0_M_SEL,
.div_clk_id = CLK_TOP_APLL12_DIV0,
},
[MT8186_I2S1_MCK] = {
.m_sel_id = CLK_TOP_I2S1_M_SEL,
.div_clk_id = CLK_TOP_APLL12_DIV1,
},
[MT8186_I2S2_MCK] = {
.m_sel_id = CLK_TOP_I2S2_M_SEL,
.div_clk_id = CLK_TOP_APLL12_DIV2,
},
[MT8186_I2S4_MCK] = {
.m_sel_id = CLK_TOP_I2S4_M_SEL,
.div_clk_id = CLK_TOP_APLL12_DIV4,
},
[MT8186_TDM_MCK] = {
.m_sel_id = CLK_TOP_TDM_M_SEL,
.div_clk_id = CLK_TOP_APLL12_DIV_TDM,
},
};
int mt8186_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
int apll = mt8186_get_apll_by_rate(afe, rate);
int apll_clk_id = apll == MT8186_APLL1 ?
CLK_TOP_MUX_AUD_1 : CLK_TOP_MUX_AUD_2;
int m_sel_id = mck_div[mck_id].m_sel_id;
int div_clk_id = mck_div[mck_id].div_clk_id;
int ret;
/* select apll */
if (m_sel_id >= 0) {
ret = clk_prepare_enable(afe_priv->clk[m_sel_id]);
if (ret) {
dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
__func__, aud_clks[m_sel_id], ret);
return ret;
}
ret = clk_set_parent(afe_priv->clk[m_sel_id],
afe_priv->clk[apll_clk_id]);
if (ret) {
dev_err(afe->dev, "%s(), clk_set_parent %s-%s fail %d\n",
__func__, aud_clks[m_sel_id],
aud_clks[apll_clk_id], ret);
return ret;
}
}
/* enable div, set rate */
ret = clk_prepare_enable(afe_priv->clk[div_clk_id]);
if (ret) {
dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
__func__, aud_clks[div_clk_id], ret);
return ret;
}
ret = clk_set_rate(afe_priv->clk[div_clk_id], rate);
if (ret) {
dev_err(afe->dev, "%s(), clk_set_rate %s, rate %d, fail %d\n",
__func__, aud_clks[div_clk_id], rate, ret);
return ret;
}
return 0;
}
void mt8186_mck_disable(struct mtk_base_afe *afe, int mck_id)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
int m_sel_id = mck_div[mck_id].m_sel_id;
int div_clk_id = mck_div[mck_id].div_clk_id;
clk_disable_unprepare(afe_priv->clk[div_clk_id]);
if (m_sel_id >= 0)
clk_disable_unprepare(afe_priv->clk[m_sel_id]);
}
int mt8186_init_clock(struct mtk_base_afe *afe)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
struct device_node *of_node = afe->dev->of_node;
int i = 0;
mt8186_audsys_clk_register(afe);
afe_priv->clk = devm_kcalloc(afe->dev, CLK_NUM, sizeof(*afe_priv->clk),
GFP_KERNEL);
if (!afe_priv->clk)
return -ENOMEM;
for (i = 0; i < CLK_NUM; i++) {
afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]);
if (IS_ERR(afe_priv->clk[i])) {
dev_err(afe->dev, "%s devm_clk_get %s fail, ret %ld\n",
__func__,
aud_clks[i], PTR_ERR(afe_priv->clk[i]));
afe_priv->clk[i] = NULL;
}
}
afe_priv->apmixedsys = syscon_regmap_lookup_by_phandle(of_node,
"mediatek,apmixedsys");
if (IS_ERR(afe_priv->apmixedsys)) {
dev_err(afe->dev, "%s() Cannot find apmixedsys controller: %ld\n",
__func__, PTR_ERR(afe_priv->apmixedsys));
return PTR_ERR(afe_priv->apmixedsys);
}
afe_priv->topckgen = syscon_regmap_lookup_by_phandle(of_node,
"mediatek,topckgen");
if (IS_ERR(afe_priv->topckgen)) {
dev_err(afe->dev, "%s() Cannot find topckgen controller: %ld\n",
__func__, PTR_ERR(afe_priv->topckgen));
return PTR_ERR(afe_priv->topckgen);
}
afe_priv->infracfg = syscon_regmap_lookup_by_phandle(of_node,
"mediatek,infracfg");
if (IS_ERR(afe_priv->infracfg)) {
dev_err(afe->dev, "%s() Cannot find infracfg: %ld\n",
__func__, PTR_ERR(afe_priv->infracfg));
return PTR_ERR(afe_priv->infracfg);
}
return 0;
}
void mt8186_deinit_clock(struct mtk_base_afe *afe)
{
mt8186_audsys_clk_unregister(afe);
}

Просмотреть файл

@ -0,0 +1,106 @@
/* SPDX-License-Identifier: GPL-2.0
*
* mt8186-afe-clk.h -- Mediatek 8186 afe clock ctrl definition
*
* Copyright (c) 2022 MediaTek Inc.
* Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
*/
#ifndef _MT8186_AFE_CLOCK_CTRL_H_
#define _MT8186_AFE_CLOCK_CTRL_H_
#define PERI_BUS_DCM_CTRL 0x74
/* APLL */
#define APLL1_W_NAME "APLL1"
#define APLL2_W_NAME "APLL2"
enum {
MT8186_APLL1 = 0,
MT8186_APLL2,
};
enum {
CLK_AFE = 0,
CLK_DAC,
CLK_DAC_PREDIS,
CLK_ADC,
CLK_TML,
CLK_APLL22M,
CLK_APLL24M,
CLK_APLL1_TUNER,
CLK_APLL2_TUNER,
CLK_TDM,
CLK_NLE,
CLK_DAC_HIRES,
CLK_ADC_HIRES,
CLK_I2S1_BCLK,
CLK_I2S2_BCLK,
CLK_I2S3_BCLK,
CLK_I2S4_BCLK,
CLK_CONNSYS_I2S_ASRC,
CLK_GENERAL1_ASRC,
CLK_GENERAL2_ASRC,
CLK_ADC_HIRES_TML,
CLK_ADDA6_ADC,
CLK_ADDA6_ADC_HIRES,
CLK_3RD_DAC,
CLK_3RD_DAC_PREDIS,
CLK_3RD_DAC_TML,
CLK_3RD_DAC_HIRES,
CLK_ETDM_IN1_BCLK,
CLK_ETDM_OUT1_BCLK,
CLK_INFRA_SYS_AUDIO,
CLK_INFRA_AUDIO_26M,
CLK_MUX_AUDIO,
CLK_MUX_AUDIOINTBUS,
CLK_TOP_MAINPLL_D2_D4,
/* apll related mux */
CLK_TOP_MUX_AUD_1,
CLK_TOP_APLL1_CK,
CLK_TOP_MUX_AUD_2,
CLK_TOP_APLL2_CK,
CLK_TOP_MUX_AUD_ENG1,
CLK_TOP_APLL1_D8,
CLK_TOP_MUX_AUD_ENG2,
CLK_TOP_APLL2_D8,
CLK_TOP_MUX_AUDIO_H,
CLK_TOP_I2S0_M_SEL,
CLK_TOP_I2S1_M_SEL,
CLK_TOP_I2S2_M_SEL,
CLK_TOP_I2S4_M_SEL,
CLK_TOP_TDM_M_SEL,
CLK_TOP_APLL12_DIV0,
CLK_TOP_APLL12_DIV1,
CLK_TOP_APLL12_DIV2,
CLK_TOP_APLL12_DIV4,
CLK_TOP_APLL12_DIV_TDM,
CLK_CLK26M,
CLK_NUM
};
struct mtk_base_afe;
int mt8186_set_audio_int_bus_parent(struct mtk_base_afe *afe, int clk_id);
int mt8186_init_clock(struct mtk_base_afe *afe);
void mt8186_deinit_clock(struct mtk_base_afe *afe);
int mt8186_afe_enable_cgs(struct mtk_base_afe *afe);
void mt8186_afe_disable_cgs(struct mtk_base_afe *afe);
int mt8186_afe_enable_clock(struct mtk_base_afe *afe);
void mt8186_afe_disable_clock(struct mtk_base_afe *afe);
int mt8186_afe_suspend_clock(struct mtk_base_afe *afe);
int mt8186_afe_resume_clock(struct mtk_base_afe *afe);
int mt8186_apll1_enable(struct mtk_base_afe *afe);
void mt8186_apll1_disable(struct mtk_base_afe *afe);
int mt8186_apll2_enable(struct mtk_base_afe *afe);
void mt8186_apll2_disable(struct mtk_base_afe *afe);
int mt8186_get_apll_rate(struct mtk_base_afe *afe, int apll);
int mt8186_get_apll_by_rate(struct mtk_base_afe *afe, int rate);
int mt8186_get_apll_by_name(struct mtk_base_afe *afe, const char *name);
/* these will be replaced by using CCF */
int mt8186_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate);
void mt8186_mck_disable(struct mtk_base_afe *afe, int mck_id);
#endif

Просмотреть файл

@ -0,0 +1,244 @@
// SPDX-License-Identifier: GPL-2.0
//
// mt8186-afe-gpio.c -- Mediatek 8186 afe gpio ctrl
//
// Copyright (c) 2022 MediaTek Inc.
// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
#include <linux/gpio.h>
#include <linux/pinctrl/consumer.h>
#include "mt8186-afe-common.h"
#include "mt8186-afe-gpio.h"
struct pinctrl *aud_pinctrl;
enum mt8186_afe_gpio {
MT8186_AFE_GPIO_CLK_MOSI_OFF,
MT8186_AFE_GPIO_CLK_MOSI_ON,
MT8186_AFE_GPIO_CLK_MISO_OFF,
MT8186_AFE_GPIO_CLK_MISO_ON,
MT8186_AFE_GPIO_DAT_MISO_OFF,
MT8186_AFE_GPIO_DAT_MISO_ON,
MT8186_AFE_GPIO_DAT_MOSI_OFF,
MT8186_AFE_GPIO_DAT_MOSI_ON,
MT8186_AFE_GPIO_I2S0_OFF,
MT8186_AFE_GPIO_I2S0_ON,
MT8186_AFE_GPIO_I2S1_OFF,
MT8186_AFE_GPIO_I2S1_ON,
MT8186_AFE_GPIO_I2S2_OFF,
MT8186_AFE_GPIO_I2S2_ON,
MT8186_AFE_GPIO_I2S3_OFF,
MT8186_AFE_GPIO_I2S3_ON,
MT8186_AFE_GPIO_TDM_OFF,
MT8186_AFE_GPIO_TDM_ON,
MT8186_AFE_GPIO_PCM_OFF,
MT8186_AFE_GPIO_PCM_ON,
MT8186_AFE_GPIO_GPIO_NUM
};
struct audio_gpio_attr {
const char *name;
bool gpio_prepare;
struct pinctrl_state *gpioctrl;
};
static struct audio_gpio_attr aud_gpios[MT8186_AFE_GPIO_GPIO_NUM] = {
[MT8186_AFE_GPIO_CLK_MOSI_OFF] = {"aud_clk_mosi_off", false, NULL},
[MT8186_AFE_GPIO_CLK_MOSI_ON] = {"aud_clk_mosi_on", false, NULL},
[MT8186_AFE_GPIO_CLK_MISO_OFF] = {"aud_clk_miso_off", false, NULL},
[MT8186_AFE_GPIO_CLK_MISO_ON] = {"aud_clk_miso_on", false, NULL},
[MT8186_AFE_GPIO_DAT_MISO_OFF] = {"aud_dat_miso_off", false, NULL},
[MT8186_AFE_GPIO_DAT_MISO_ON] = {"aud_dat_miso_on", false, NULL},
[MT8186_AFE_GPIO_DAT_MOSI_OFF] = {"aud_dat_mosi_off", false, NULL},
[MT8186_AFE_GPIO_DAT_MOSI_ON] = {"aud_dat_mosi_on", false, NULL},
[MT8186_AFE_GPIO_I2S0_OFF] = {"aud_gpio_i2s0_off", false, NULL},
[MT8186_AFE_GPIO_I2S0_ON] = {"aud_gpio_i2s0_on", false, NULL},
[MT8186_AFE_GPIO_I2S1_OFF] = {"aud_gpio_i2s1_off", false, NULL},
[MT8186_AFE_GPIO_I2S1_ON] = {"aud_gpio_i2s1_on", false, NULL},
[MT8186_AFE_GPIO_I2S2_OFF] = {"aud_gpio_i2s2_off", false, NULL},
[MT8186_AFE_GPIO_I2S2_ON] = {"aud_gpio_i2s2_on", false, NULL},
[MT8186_AFE_GPIO_I2S3_OFF] = {"aud_gpio_i2s3_off", false, NULL},
[MT8186_AFE_GPIO_I2S3_ON] = {"aud_gpio_i2s3_on", false, NULL},
[MT8186_AFE_GPIO_TDM_OFF] = {"aud_gpio_tdm_off", false, NULL},
[MT8186_AFE_GPIO_TDM_ON] = {"aud_gpio_tdm_on", false, NULL},
[MT8186_AFE_GPIO_PCM_OFF] = {"aud_gpio_pcm_off", false, NULL},
[MT8186_AFE_GPIO_PCM_ON] = {"aud_gpio_pcm_on", false, NULL},
};
static DEFINE_MUTEX(gpio_request_mutex);
int mt8186_afe_gpio_init(struct device *dev)
{
int i, j, ret;
aud_pinctrl = devm_pinctrl_get(dev);
if (IS_ERR(aud_pinctrl)) {
ret = PTR_ERR(aud_pinctrl);
dev_err(dev, "%s(), ret %d, cannot get aud_pinctrl!\n",
__func__, ret);
return ret;
}
for (i = 0; i < ARRAY_SIZE(aud_gpios); i++) {
aud_gpios[i].gpioctrl = pinctrl_lookup_state(aud_pinctrl,
aud_gpios[i].name);
if (IS_ERR(aud_gpios[i].gpioctrl)) {
ret = PTR_ERR(aud_gpios[i].gpioctrl);
dev_info(dev, "%s(), pinctrl_lookup_state %s fail, ret %d\n",
__func__, aud_gpios[i].name, ret);
} else {
aud_gpios[i].gpio_prepare = true;
}
}
/* gpio status init */
for (i = MT8186_DAI_ADDA; i <= MT8186_DAI_TDM_IN; i++) {
for (j = 0; j <= 1; j++)
mt8186_afe_gpio_request(dev, false, i, j);
}
return 0;
}
EXPORT_SYMBOL_GPL(mt8186_afe_gpio_init);
static int mt8186_afe_gpio_select(struct device *dev,
enum mt8186_afe_gpio type)
{
int ret = 0;
if (type < 0 || type >= MT8186_AFE_GPIO_GPIO_NUM) {
dev_err(dev, "%s(), error, invalid gpio type %d\n",
__func__, type);
return -EINVAL;
}
if (!aud_gpios[type].gpio_prepare) {
dev_err(dev, "%s(), error, gpio type %d not prepared\n",
__func__, type);
return -EIO;
}
ret = pinctrl_select_state(aud_pinctrl,
aud_gpios[type].gpioctrl);
if (ret) {
dev_err(dev, "%s(), error, can not set gpio type %d\n",
__func__, type);
return ret;
}
return 0;
}
static int mt8186_afe_gpio_adda_dl(struct device *dev, bool enable)
{
int ret;
if (enable) {
ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MOSI_ON);
if (ret) {
dev_err(dev, "%s(), MOSI CLK ON slect fail!\n", __func__);
return ret;
}
ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MOSI_ON);
if (ret) {
dev_err(dev, "%s(), MOSI DAT ON slect fail!\n", __func__);
return ret;
}
} else {
ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MOSI_OFF);
if (ret) {
dev_err(dev, "%s(), MOSI DAT OFF slect fail!\n", __func__);
return ret;
}
ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MOSI_OFF);
if (ret) {
dev_err(dev, "%s(), MOSI CLK ON slect fail!\n", __func__);
return ret;
}
}
return 0;
}
static int mt8186_afe_gpio_adda_ul(struct device *dev, bool enable)
{
int ret;
if (enable) {
ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MISO_ON);
if (ret) {
dev_err(dev, "%s(), MISO CLK ON slect fail!\n", __func__);
return ret;
}
ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MISO_ON);
if (ret) {
dev_err(dev, "%s(), MISO DAT ON slect fail!\n", __func__);
return ret;
}
} else {
ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MISO_OFF);
if (ret) {
dev_err(dev, "%s(), MISO DAT OFF slect fail!\n", __func__);
return ret;
}
ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MISO_OFF);
if (ret) {
dev_err(dev, "%s(), MISO CLK OFF slect fail!\n", __func__);
return ret;
}
}
return 0;
}
int mt8186_afe_gpio_request(struct device *dev, bool enable,
int dai, int uplink)
{
enum mt8186_afe_gpio sel;
int ret = -EINVAL;
mutex_lock(&gpio_request_mutex);
switch (dai) {
case MT8186_DAI_ADDA:
if (uplink)
ret = mt8186_afe_gpio_adda_ul(dev, enable);
else
ret = mt8186_afe_gpio_adda_dl(dev, enable);
goto unlock;
case MT8186_DAI_I2S_0:
sel = enable ? MT8186_AFE_GPIO_I2S0_ON : MT8186_AFE_GPIO_I2S0_OFF;
break;
case MT8186_DAI_I2S_1:
sel = enable ? MT8186_AFE_GPIO_I2S1_ON : MT8186_AFE_GPIO_I2S1_OFF;
break;
case MT8186_DAI_I2S_2:
sel = enable ? MT8186_AFE_GPIO_I2S2_ON : MT8186_AFE_GPIO_I2S2_OFF;
break;
case MT8186_DAI_I2S_3:
sel = enable ? MT8186_AFE_GPIO_I2S3_ON : MT8186_AFE_GPIO_I2S3_OFF;
break;
case MT8186_DAI_TDM_IN:
sel = enable ? MT8186_AFE_GPIO_TDM_ON : MT8186_AFE_GPIO_TDM_OFF;
break;
case MT8186_DAI_PCM:
sel = enable ? MT8186_AFE_GPIO_PCM_ON : MT8186_AFE_GPIO_PCM_OFF;
break;
default:
mutex_unlock(&gpio_request_mutex);
dev_err(dev, "%s(), invalid dai %d\n", __func__, dai);
goto unlock;
}
ret = mt8186_afe_gpio_select(dev, sel);
unlock:
mutex_unlock(&gpio_request_mutex);
return ret;
}

Просмотреть файл

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0
*
* mt6833-afe-gpio.h -- Mediatek 6833 afe gpio ctrl definition
*
* Copyright (c) 2022 MediaTek Inc.
* Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
*/
#ifndef _MT8186_AFE_GPIO_H_
#define _MT8186_AFE_GPIO_H_
struct mtk_base_afe;
int mt8186_afe_gpio_init(struct device *dev);
int mt8186_afe_gpio_request(struct device *dev, bool enable,
int dai, int uplink);
#endif

Просмотреть файл

@ -0,0 +1,150 @@
// SPDX-License-Identifier: GPL-2.0
//
// mt8186-audsys-clk.h -- Mediatek 8186 audsys clock control
//
// Copyright (c) 2022 MediaTek Inc.
// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include "mt8186-afe-common.h"
#include "mt8186-audsys-clk.h"
#include "mt8186-audsys-clkid.h"
#include "mt8186-reg.h"
struct afe_gate {
int id;
const char *name;
const char *parent_name;
int reg;
u8 bit;
const struct clk_ops *ops;
unsigned long flags;
u8 cg_flags;
};
#define GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit, _flags, _cgflags) {\
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.reg = _reg, \
.bit = _bit, \
.flags = _flags, \
.cg_flags = _cgflags, \
}
#define GATE_AFE(_id, _name, _parent, _reg, _bit) \
GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit, \
CLK_SET_RATE_PARENT, CLK_GATE_SET_TO_DISABLE)
#define GATE_AUD0(_id, _name, _parent, _bit) \
GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON0, _bit)
#define GATE_AUD1(_id, _name, _parent, _bit) \
GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON1, _bit)
#define GATE_AUD2(_id, _name, _parent, _bit) \
GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON2, _bit)
static const struct afe_gate aud_clks[CLK_AUD_NR_CLK] = {
/* AUD0 */
GATE_AUD0(CLK_AUD_AFE, "aud_afe_clk", "top_audio", 2),
GATE_AUD0(CLK_AUD_22M, "aud_apll22m_clk", "top_aud_engen1", 8),
GATE_AUD0(CLK_AUD_24M, "aud_apll24m_clk", "top_aud_engen2", 9),
GATE_AUD0(CLK_AUD_APLL2_TUNER, "aud_apll2_tuner_clk", "top_aud_engen2", 18),
GATE_AUD0(CLK_AUD_APLL_TUNER, "aud_apll_tuner_clk", "top_aud_engen1", 19),
GATE_AUD0(CLK_AUD_TDM, "aud_tdm_clk", "top_aud_1", 20),
GATE_AUD0(CLK_AUD_ADC, "aud_adc_clk", "top_audio", 24),
GATE_AUD0(CLK_AUD_DAC, "aud_dac_clk", "top_audio", 25),
GATE_AUD0(CLK_AUD_DAC_PREDIS, "aud_dac_predis_clk", "top_audio", 26),
GATE_AUD0(CLK_AUD_TML, "aud_tml_clk", "top_audio", 27),
GATE_AUD0(CLK_AUD_NLE, "aud_nle_clk", "top_audio", 28),
/* AUD1 */
GATE_AUD1(CLK_AUD_I2S1_BCLK, "aud_i2s1_bclk", "top_audio", 4),
GATE_AUD1(CLK_AUD_I2S2_BCLK, "aud_i2s2_bclk", "top_audio", 5),
GATE_AUD1(CLK_AUD_I2S3_BCLK, "aud_i2s3_bclk", "top_audio", 6),
GATE_AUD1(CLK_AUD_I2S4_BCLK, "aud_i2s4_bclk", "top_audio", 7),
GATE_AUD1(CLK_AUD_CONNSYS_I2S_ASRC, "aud_connsys_i2s_asrc", "top_audio", 12),
GATE_AUD1(CLK_AUD_GENERAL1_ASRC, "aud_general1_asrc", "top_audio", 13),
GATE_AUD1(CLK_AUD_GENERAL2_ASRC, "aud_general2_asrc", "top_audio", 14),
GATE_AUD1(CLK_AUD_DAC_HIRES, "aud_dac_hires_clk", "top_audio_h", 15),
GATE_AUD1(CLK_AUD_ADC_HIRES, "aud_adc_hires_clk", "top_audio_h", 16),
GATE_AUD1(CLK_AUD_ADC_HIRES_TML, "aud_adc_hires_tml", "top_audio_h", 17),
GATE_AUD1(CLK_AUD_ADDA6_ADC, "aud_adda6_adc", "top_audio", 20),
GATE_AUD1(CLK_AUD_ADDA6_ADC_HIRES, "aud_adda6_adc_hires", "top_audio_h", 21),
GATE_AUD1(CLK_AUD_3RD_DAC, "aud_3rd_dac", "top_audio", 28),
GATE_AUD1(CLK_AUD_3RD_DAC_PREDIS, "aud_3rd_dac_predis", "top_audio", 29),
GATE_AUD1(CLK_AUD_3RD_DAC_TML, "aud_3rd_dac_tml", "top_audio", 30),
GATE_AUD1(CLK_AUD_3RD_DAC_HIRES, "aud_3rd_dac_hires", "top_audio_h", 31),
/* AUD2 */
GATE_AUD2(CLK_AUD_ETDM_IN1_BCLK, "aud_etdm_in1_bclk", "top_audio", 23),
GATE_AUD2(CLK_AUD_ETDM_OUT1_BCLK, "aud_etdm_out1_bclk", "top_audio", 24),
};
int mt8186_audsys_clk_register(struct mtk_base_afe *afe)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
struct clk *clk;
struct clk_lookup *cl;
int i;
afe_priv->lookup = devm_kcalloc(afe->dev, CLK_AUD_NR_CLK,
sizeof(*afe_priv->lookup),
GFP_KERNEL);
if (!afe_priv->lookup)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
const struct afe_gate *gate = &aud_clks[i];
clk = clk_register_gate(afe->dev, gate->name, gate->parent_name,
gate->flags, afe->base_addr + gate->reg,
gate->bit, gate->cg_flags, NULL);
if (IS_ERR(clk)) {
dev_err(afe->dev, "Failed to register clk %s: %ld\n",
gate->name, PTR_ERR(clk));
continue;
}
/* add clk_lookup for devm_clk_get(SND_SOC_DAPM_CLOCK_SUPPLY) */
cl = kzalloc(sizeof(*cl), GFP_KERNEL);
if (!cl)
return -ENOMEM;
cl->clk = clk;
cl->con_id = gate->name;
cl->dev_id = dev_name(afe->dev);
clkdev_add(cl);
afe_priv->lookup[i] = cl;
}
return 0;
}
void mt8186_audsys_clk_unregister(struct mtk_base_afe *afe)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
struct clk *clk;
struct clk_lookup *cl;
int i;
if (!afe_priv)
return;
for (i = 0; i < CLK_AUD_NR_CLK; i++) {
cl = afe_priv->lookup[i];
if (!cl)
continue;
clk = cl->clk;
clk_unregister_gate(clk);
clkdev_drop(cl);
}
}

Просмотреть файл

@ -0,0 +1,15 @@
/* SPDX-License-Identifier: GPL-2.0
*
* mt8186-audsys-clk.h -- Mediatek 8186 audsys clock definition
*
* Copyright (c) 2022 MediaTek Inc.
* Author: Trevor Wu <trevor.wu@mediatek.com>
*/
#ifndef _MT8186_AUDSYS_CLK_H_
#define _MT8186_AUDSYS_CLK_H_
int mt8186_audsys_clk_register(struct mtk_base_afe *afe);
void mt8186_audsys_clk_unregister(struct mtk_base_afe *afe);
#endif

Просмотреть файл

@ -0,0 +1,45 @@
/* SPDX-License-Identifier: GPL-2.0
*
* mt8186-audsys-clkid.h -- Mediatek 8186 audsys clock id definition
*
* Copyright (c) 2022 MediaTek Inc.
* Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
*/
#ifndef _MT8186_AUDSYS_CLKID_H_
#define _MT8186_AUDSYS_CLKID_H_
enum{
CLK_AUD_AFE,
CLK_AUD_22M,
CLK_AUD_24M,
CLK_AUD_APLL2_TUNER,
CLK_AUD_APLL_TUNER,
CLK_AUD_TDM,
CLK_AUD_ADC,
CLK_AUD_DAC,
CLK_AUD_DAC_PREDIS,
CLK_AUD_TML,
CLK_AUD_NLE,
CLK_AUD_I2S1_BCLK,
CLK_AUD_I2S2_BCLK,
CLK_AUD_I2S3_BCLK,
CLK_AUD_I2S4_BCLK,
CLK_AUD_CONNSYS_I2S_ASRC,
CLK_AUD_GENERAL1_ASRC,
CLK_AUD_GENERAL2_ASRC,
CLK_AUD_DAC_HIRES,
CLK_AUD_ADC_HIRES,
CLK_AUD_ADC_HIRES_TML,
CLK_AUD_ADDA6_ADC,
CLK_AUD_ADDA6_ADC_HIRES,
CLK_AUD_3RD_DAC,
CLK_AUD_3RD_DAC_PREDIS,
CLK_AUD_3RD_DAC_TML,
CLK_AUD_3RD_DAC_HIRES,
CLK_AUD_ETDM_IN1_BCLK,
CLK_AUD_ETDM_OUT1_BCLK,
CLK_AUD_NR_CLK,
};
#endif

Просмотреть файл

@ -0,0 +1,873 @@
// SPDX-License-Identifier: GPL-2.0
//
// MediaTek ALSA SoC Audio DAI ADDA Control
//
// Copyright (c) 2022 MediaTek Inc.
// Author: Jiaxin Yu <jiaxin.yu@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"
enum {
UL_IIR_SW = 0,
UL_IIR_5HZ,
UL_IIR_10HZ,
UL_IIR_25HZ,
UL_IIR_50HZ,
UL_IIR_75HZ,
};
enum {
AUDIO_SDM_LEVEL_MUTE = 0,
AUDIO_SDM_LEVEL_NORMAL = 0x1d,
/* if you change level normal */
/* you need to change formula of hp impedance and dc trim too */
};
enum {
AUDIO_SDM_2ND = 0,
AUDIO_SDM_3RD,
};
enum {
DELAY_DATA_MISO1 = 0,
DELAY_DATA_MISO2,
};
enum {
MTK_AFE_ADDA_DL_RATE_8K = 0,
MTK_AFE_ADDA_DL_RATE_11K = 1,
MTK_AFE_ADDA_DL_RATE_12K = 2,
MTK_AFE_ADDA_DL_RATE_16K = 3,
MTK_AFE_ADDA_DL_RATE_22K = 4,
MTK_AFE_ADDA_DL_RATE_24K = 5,
MTK_AFE_ADDA_DL_RATE_32K = 6,
MTK_AFE_ADDA_DL_RATE_44K = 7,
MTK_AFE_ADDA_DL_RATE_48K = 8,
MTK_AFE_ADDA_DL_RATE_96K = 9,
MTK_AFE_ADDA_DL_RATE_192K = 10,
};
enum {
MTK_AFE_ADDA_UL_RATE_8K = 0,
MTK_AFE_ADDA_UL_RATE_16K = 1,
MTK_AFE_ADDA_UL_RATE_32K = 2,
MTK_AFE_ADDA_UL_RATE_48K = 3,
MTK_AFE_ADDA_UL_RATE_96K = 4,
MTK_AFE_ADDA_UL_RATE_192K = 5,
MTK_AFE_ADDA_UL_RATE_48K_HD = 6,
};
#define SDM_AUTO_RESET_THRESHOLD 0x190000
struct mtk_afe_adda_priv {
int dl_rate;
int ul_rate;
};
static struct mtk_afe_adda_priv *get_adda_priv_by_name(struct mtk_base_afe *afe,
const char *name)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
int dai_id;
if (strncmp(name, "aud_dac_hires_clk", 7) == 0 ||
strncmp(name, "aud_adc_hires_clk", 7) == 0)
dai_id = MT8186_DAI_ADDA;
else
return NULL;
return afe_priv->dai_priv[dai_id];
}
static unsigned int adda_dl_rate_transform(struct mtk_base_afe *afe,
unsigned int rate)
{
switch (rate) {
case 8000:
return MTK_AFE_ADDA_DL_RATE_8K;
case 11025:
return MTK_AFE_ADDA_DL_RATE_11K;
case 12000:
return MTK_AFE_ADDA_DL_RATE_12K;
case 16000:
return MTK_AFE_ADDA_DL_RATE_16K;
case 22050:
return MTK_AFE_ADDA_DL_RATE_22K;
case 24000:
return MTK_AFE_ADDA_DL_RATE_24K;
case 32000:
return MTK_AFE_ADDA_DL_RATE_32K;
case 44100:
return MTK_AFE_ADDA_DL_RATE_44K;
case 48000:
return MTK_AFE_ADDA_DL_RATE_48K;
case 96000:
return MTK_AFE_ADDA_DL_RATE_96K;
case 192000:
return MTK_AFE_ADDA_DL_RATE_192K;
default:
dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
__func__, rate);
}
return MTK_AFE_ADDA_DL_RATE_48K;
}
static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe,
unsigned int rate)
{
switch (rate) {
case 8000:
return MTK_AFE_ADDA_UL_RATE_8K;
case 16000:
return MTK_AFE_ADDA_UL_RATE_16K;
case 32000:
return MTK_AFE_ADDA_UL_RATE_32K;
case 48000:
return MTK_AFE_ADDA_UL_RATE_48K;
case 96000:
return MTK_AFE_ADDA_UL_RATE_96K;
case 192000:
return MTK_AFE_ADDA_UL_RATE_192K;
default:
dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
__func__, rate);
}
return MTK_AFE_ADDA_UL_RATE_48K;
}
/* dai component */
static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN3, I_DL1_CH1, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN3, I_DL12_CH1, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN3, I_DL2_CH1, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN3, I_DL3_CH1, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN3_1, I_DL4_CH1, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN3_1, I_DL5_CH1, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch", AFE_CONN3_1, I_DL6_CH1, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1 Switch", AFE_CONN3_1, I_DL8_CH1, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN3,
I_ADDA_UL_CH2, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN3,
I_ADDA_UL_CH1, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1 Switch", AFE_CONN3,
I_GAIN1_OUT_CH1, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1 Switch", AFE_CONN3,
I_PCM_1_CAP_CH1, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1 Switch", AFE_CONN3,
I_PCM_2_CAP_CH1, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH1 Switch", AFE_CONN3_1,
I_SRC_1_OUT_CH1, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("SRC_2_OUT_CH1 Switch", AFE_CONN3_1,
I_SRC_2_OUT_CH1, 1, 0),
};
static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN4, I_DL1_CH1, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN4, I_DL1_CH2, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN4, I_DL12_CH2, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN4, I_DL2_CH1, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN4, I_DL2_CH2, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN4, I_DL3_CH1, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN4, I_DL3_CH2, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN4_1, I_DL4_CH2, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN4_1, I_DL5_CH2, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch", AFE_CONN4_1, I_DL6_CH2, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2 Switch", AFE_CONN4_1, I_DL8_CH2, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN4,
I_ADDA_UL_CH2, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN4,
I_ADDA_UL_CH1, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2 Switch", AFE_CONN4,
I_GAIN1_OUT_CH2, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2 Switch", AFE_CONN4,
I_PCM_1_CAP_CH2, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2 Switch", AFE_CONN4,
I_PCM_2_CAP_CH2, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH2 Switch", AFE_CONN4_1,
I_SRC_1_OUT_CH2, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("SRC_2_OUT_CH2 Switch", AFE_CONN4_1,
I_SRC_2_OUT_CH2, 1, 0),
};
enum {
SUPPLY_SEQ_ADDA_AFE_ON,
SUPPLY_SEQ_ADDA_DL_ON,
SUPPLY_SEQ_ADDA_AUD_PAD_TOP,
SUPPLY_SEQ_ADDA_MTKAIF_CFG,
SUPPLY_SEQ_ADDA_FIFO,
SUPPLY_SEQ_ADDA_AP_DMIC,
SUPPLY_SEQ_ADDA_UL_ON,
};
static int mtk_adda_ul_src_dmic(struct mtk_base_afe *afe, int id)
{
unsigned int reg;
switch (id) {
case MT8186_DAI_ADDA:
case MT8186_DAI_AP_DMIC:
reg = AFE_ADDA_UL_SRC_CON0;
break;
default:
return -EINVAL;
}
/* dmic mode, 3.25M*/
regmap_update_bits(afe->regmap, reg,
DIGMIC_3P25M_1P625M_SEL_MASK_SFT, 0);
regmap_update_bits(afe->regmap, reg,
DMIC_LOW_POWER_CTL_MASK_SFT, 0);
/* turn on dmic, ch1, ch2 */
regmap_update_bits(afe->regmap, reg,
UL_SDM_3_LEVEL_MASK_SFT,
BIT(UL_SDM_3_LEVEL_SFT));
regmap_update_bits(afe->regmap, reg,
UL_MODE_3P25M_CH1_CTL_MASK_SFT,
BIT(UL_MODE_3P25M_CH1_CTL_SFT));
regmap_update_bits(afe->regmap, reg,
UL_MODE_3P25M_CH2_CTL_MASK_SFT,
BIT(UL_MODE_3P25M_CH2_CTL_SFT));
return 0;
}
static int mtk_adda_ul_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 mtkaif_dmic = afe_priv->mtkaif_dmic;
dev_dbg(afe->dev, "%s(), name %s, event 0x%x, mtkaif_dmic %d\n",
__func__, w->name, event, mtkaif_dmic);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
mt8186_afe_gpio_request(afe->dev, true, MT8186_DAI_ADDA, 1);
/* update setting to dmic */
if (mtkaif_dmic) {
/* mtkaif_rxif_data_mode = 1, dmic */
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0,
0x1, 0x1);
/* dmic mode, 3.25M*/
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0,
MTKAIF_RXIF_VOICE_MODE_MASK_SFT,
0x0);
mtk_adda_ul_src_dmic(afe, MT8186_DAI_ADDA);
}
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, 1);
/* reset dmic */
afe_priv->mtkaif_dmic = 0;
break;
default:
break;
}
return 0;
}
static int mtk_adda_pad_top_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;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2)
regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x39);
else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2)
regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x31);
else
regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x31);
break;
default:
break;
}
return 0;
}
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, 0x10000);
/* mtkaif_rxif_clkinv_adc inverse */
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_CFG0,
MTKAIF_RXIF_CLKINV_ADC_MASK_SFT,
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, 0x10000);
} else {
regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, 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;
int dmic_on;
dmic_on = ucontrol->value.integer.value[0];
dev_dbg(afe->dev, "%s(), kcontrol name %s, dmic_on %d\n",
__func__, kcontrol->id.name, dmic_on);
if (afe_priv->mtkaif_dmic == dmic_on)
return 0;
afe_priv->mtkaif_dmic = dmic_on;
return 1;
}
static const struct snd_kcontrol_new mtk_adda_controls[] = {
SOC_SINGLE("ADDA_DL_GAIN", AFE_ADDA_DL_SRC2_CON1,
DL_2_GAIN_CTL_PRE_SFT, DL_2_GAIN_CTL_PRE_MASK, 0),
SOC_SINGLE_BOOL_EXT("MTKAIF_DMIC Switch", 0,
mt8186_adda_dmic_get, mt8186_adda_dmic_set),
};
/* ADDA UL MUX */
enum {
ADDA_UL_MUX_MTKAIF = 0,
ADDA_UL_MUX_AP_DMIC,
ADDA_UL_MUX_MASK = 0x1,
};
static const char * const adda_ul_mux_map[] = {
"MTKAIF", "AP_DMIC"
};
static int adda_ul_map_value[] = {
ADDA_UL_MUX_MTKAIF,
ADDA_UL_MUX_AP_DMIC,
};
static SOC_VALUE_ENUM_SINGLE_DECL(adda_ul_mux_map_enum,
SND_SOC_NOPM,
0,
ADDA_UL_MUX_MASK,
adda_ul_mux_map,
adda_ul_map_value);
static const struct snd_kcontrol_new adda_ul_mux_control =
SOC_DAPM_ENUM("ADDA_UL_MUX Select", adda_ul_mux_map_enum);
static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = {
/* inter-connections */
SND_SOC_DAPM_MIXER("ADDA_DL_CH1", SND_SOC_NOPM, 0, 0,
mtk_adda_dl_ch1_mix,
ARRAY_SIZE(mtk_adda_dl_ch1_mix)),
SND_SOC_DAPM_MIXER("ADDA_DL_CH2", SND_SOC_NOPM, 0, 0,
mtk_adda_dl_ch2_mix,
ARRAY_SIZE(mtk_adda_dl_ch2_mix)),
SND_SOC_DAPM_SUPPLY_S("ADDA Enable", SUPPLY_SEQ_ADDA_AFE_ON,
AFE_ADDA_UL_DL_CON0, ADDA_AFE_ON_SFT, 0,
NULL, 0),
SND_SOC_DAPM_SUPPLY_S("ADDA Playback Enable", SUPPLY_SEQ_ADDA_DL_ON,
AFE_ADDA_DL_SRC2_CON0,
DL_2_SRC_ON_CTL_PRE_SFT, 0,
mtk_adda_dl_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY_S("ADDA Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
AFE_ADDA_UL_SRC_CON0,
UL_SRC_ON_CTL_SFT, 0,
mtk_adda_ul_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY_S("AUD_PAD_TOP", SUPPLY_SEQ_ADDA_AUD_PAD_TOP,
0, 0, 0,
mtk_adda_pad_top_event,
SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_SUPPLY_S("ADDA_MTKAIF_CFG", SUPPLY_SEQ_ADDA_MTKAIF_CFG,
SND_SOC_NOPM, 0, 0,
mtk_adda_mtkaif_cfg_event,
SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_SUPPLY_S("AP_DMIC_EN", SUPPLY_SEQ_ADDA_AP_DMIC,
AFE_ADDA_UL_SRC_CON0,
UL_AP_DMIC_ON_SFT, 0,
NULL, 0),
SND_SOC_DAPM_SUPPLY_S("ADDA_FIFO", SUPPLY_SEQ_ADDA_FIFO,
AFE_ADDA_UL_DL_CON0,
AFE_ADDA_FIFO_AUTO_RST_SFT, 1,
NULL, 0),
SND_SOC_DAPM_MUX("ADDA_UL_Mux", SND_SOC_NOPM, 0, 0,
&adda_ul_mux_control),
SND_SOC_DAPM_INPUT("AP_DMIC_INPUT"),
/* clock */
SND_SOC_DAPM_CLOCK_SUPPLY("top_mux_audio_h"),
SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_clk"),
SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_hires_clk"),
SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_predis_clk"),
SND_SOC_DAPM_CLOCK_SUPPLY("aud_adc_clk"),
SND_SOC_DAPM_CLOCK_SUPPLY("aud_adc_hires_clk"),
};
#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_err(afe->dev, "%s(), adda_priv == NULL", __func__);
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_err(afe->dev, "%s(), adda_priv == NULL", __func__);
return 0;
}
return (adda_priv->ul_rate > HIRES_THRESHOLD) ? 1 : 0;
}
static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = {
/* playback */
{"ADDA_DL_CH1", "DL1_CH1 Switch", "DL1"},
{"ADDA_DL_CH2", "DL1_CH1 Switch", "DL1"},
{"ADDA_DL_CH2", "DL1_CH2 Switch", "DL1"},
{"ADDA_DL_CH1", "DL12_CH1 Switch", "DL12"},
{"ADDA_DL_CH2", "DL12_CH2 Switch", "DL12"},
{"ADDA_DL_CH1", "DL6_CH1 Switch", "DL6"},
{"ADDA_DL_CH2", "DL6_CH2 Switch", "DL6"},
{"ADDA_DL_CH1", "DL8_CH1 Switch", "DL8"},
{"ADDA_DL_CH2", "DL8_CH2 Switch", "DL8"},
{"ADDA_DL_CH1", "DL2_CH1 Switch", "DL2"},
{"ADDA_DL_CH2", "DL2_CH1 Switch", "DL2"},
{"ADDA_DL_CH2", "DL2_CH2 Switch", "DL2"},
{"ADDA_DL_CH1", "DL3_CH1 Switch", "DL3"},
{"ADDA_DL_CH2", "DL3_CH1 Switch", "DL3"},
{"ADDA_DL_CH2", "DL3_CH2 Switch", "DL3"},
{"ADDA_DL_CH1", "DL4_CH1 Switch", "DL4"},
{"ADDA_DL_CH2", "DL4_CH2 Switch", "DL4"},
{"ADDA_DL_CH1", "DL5_CH1 Switch", "DL5"},
{"ADDA_DL_CH2", "DL5_CH2 Switch", "DL5"},
{"ADDA Playback", NULL, "ADDA_DL_CH1"},
{"ADDA Playback", NULL, "ADDA_DL_CH2"},
{"ADDA Playback", NULL, "ADDA Enable"},
{"ADDA Playback", NULL, "ADDA Playback Enable"},
/* capture */
{"ADDA_UL_Mux", "MTKAIF", "ADDA Capture"},
{"ADDA_UL_Mux", "AP_DMIC", "AP DMIC Capture"},
{"ADDA Capture", NULL, "ADDA Enable"},
{"ADDA Capture", NULL, "ADDA Capture Enable"},
{"ADDA Capture", NULL, "AUD_PAD_TOP"},
{"ADDA Capture", NULL, "ADDA_MTKAIF_CFG"},
{"AP DMIC Capture", NULL, "ADDA Enable"},
{"AP DMIC Capture", NULL, "ADDA Capture Enable"},
{"AP DMIC Capture", NULL, "ADDA_FIFO"},
{"AP DMIC Capture", NULL, "AP_DMIC_EN"},
{"AP DMIC Capture", NULL, "AP_DMIC_INPUT"},
/* clk */
{"ADDA Playback", NULL, "aud_dac_clk"},
{"ADDA Playback", NULL, "aud_dac_predis_clk"},
{"ADDA Playback", NULL, "aud_dac_hires_clk", mtk_afe_dac_hires_connect},
{"ADDA Capture Enable", NULL, "aud_adc_clk"},
{"ADDA Capture Enable", NULL, "aud_adc_hires_clk",
mtk_afe_adc_hires_connect},
/* hires source from apll1 */
{"top_mux_audio_h", NULL, APLL2_W_NAME},
{"aud_dac_hires_clk", NULL, "top_mux_audio_h"},
{"aud_adc_hires_clk", NULL, "top_mux_audio_h"},
};
/* 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_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n",
__func__, id, substream->stream, rate);
if (!adda_priv) {
dev_err(afe->dev, "%s(), adda_priv == NULL", __func__);
return -EINVAL;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
unsigned int dl_src2_con0;
unsigned int dl_src2_con1;
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 |= BIT(DL_2_MUTE_CH2_OFF_CTL_PRE_SFT);
dl_src2_con0 |= BIT(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 |= BIT(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 |= BIT(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,
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,
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,
BIT(SDM_AUTO_RESET_TEST_ON_SFT));
}
} else {
unsigned int ul_src_con0 = 0;
unsigned int voice_mode = adda_ul_rate_transform(afe, rate);
adda_priv->ul_rate = 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, 0);
regmap_write(afe->regmap,
AFE_ADDA_IIR_COEF_04_03, 0x3fb8);
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, 0xc048);
regmap_write(afe->regmap,
AFE_ADDA_UL_SRC_CON0, ul_src_con0);
/* Using Internal ADC */
regmap_update_bits(afe->regmap, AFE_ADDA_TOP_CON0, BIT(0), 0);
/* mtkaif_rxif_data_mode = 0, amic */
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0, BIT(0), 0);
break;
default:
break;
}
/* ap dmic */
switch (id) {
case MT8186_DAI_AP_DMIC:
mtk_adda_ul_src_dmic(afe, id);
break;
default:
break;
}
}
return 0;
}
static const struct snd_soc_dai_ops mtk_dai_adda_ops = {
.hw_params = mtk_dai_adda_hw_params,
};
/* dai driver */
#define MTK_ADDA_PLAYBACK_RATES (SNDRV_PCM_RATE_8000_48000 |\
SNDRV_PCM_RATE_96000 |\
SNDRV_PCM_RATE_192000)
#define MTK_ADDA_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\
SNDRV_PCM_RATE_16000 |\
SNDRV_PCM_RATE_32000 |\
SNDRV_PCM_RATE_48000 |\
SNDRV_PCM_RATE_96000 |\
SNDRV_PCM_RATE_192000)
#define MTK_ADDA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S24_LE |\
SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_driver mtk_dai_adda_driver[] = {
{
.name = "ADDA",
.id = MT8186_DAI_ADDA,
.playback = {
.stream_name = "ADDA Playback",
.channels_min = 1,
.channels_max = 2,
.rates = MTK_ADDA_PLAYBACK_RATES,
.formats = MTK_ADDA_FORMATS,
},
.capture = {
.stream_name = "ADDA Capture",
.channels_min = 1,
.channels_max = 2,
.rates = MTK_ADDA_CAPTURE_RATES,
.formats = MTK_ADDA_FORMATS,
},
.ops = &mtk_dai_adda_ops,
},
{
.name = "AP_DMIC",
.id = MT8186_DAI_AP_DMIC,
.capture = {
.stream_name = "AP DMIC Capture",
.channels_min = 1,
.channels_max = 2,
.rates = MTK_ADDA_CAPTURE_RATES,
.formats = MTK_ADDA_FORMATS,
},
.ops = &mtk_dai_adda_ops,
},
};
int mt8186_dai_adda_register(struct mtk_base_afe *afe)
{
struct mtk_base_afe_dai *dai;
struct mt8186_afe_private *afe_priv = afe->platform_priv;
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_adda_driver;
dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver);
dai->controls = mtk_adda_controls;
dai->num_controls = ARRAY_SIZE(mtk_adda_controls);
dai->dapm_widgets = mtk_dai_adda_widgets;
dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets);
dai->dapm_routes = mtk_dai_adda_routes;
dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes);
/* set dai priv */
ret = mt8186_dai_set_priv(afe, MT8186_DAI_ADDA,
sizeof(struct mtk_afe_adda_priv), NULL);
if (ret)
return ret;
/* ap dmic priv share with adda */
afe_priv->dai_priv[MT8186_DAI_AP_DMIC] =
afe_priv->dai_priv[MT8186_DAI_ADDA];
return 0;
}

Просмотреть файл

@ -0,0 +1,298 @@
// SPDX-License-Identifier: GPL-2.0
//
// MediaTek ALSA SoC Audio DAI Hostless Control
//
// Copyright (c) 2022 MediaTek Inc.
// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
#include "mt8186-afe-common.h"
static const struct snd_pcm_hardware mt8186_hostless_hardware = {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID),
.period_bytes_min = 256,
.period_bytes_max = 4 * 48 * 1024,
.periods_min = 2,
.periods_max = 256,
.buffer_bytes_max = 4 * 48 * 1024,
.fifo_size = 0,
};
/* dai component */
static const struct snd_soc_dapm_route mtk_dai_hostless_routes[] = {
/* Hostless ADDA Loopback */
{"ADDA_DL_CH1", "ADDA_UL_CH1 Switch", "Hostless LPBK DL"},
{"ADDA_DL_CH1", "ADDA_UL_CH2 Switch", "Hostless LPBK DL"},
{"ADDA_DL_CH2", "ADDA_UL_CH1 Switch", "Hostless LPBK DL"},
{"ADDA_DL_CH2", "ADDA_UL_CH2 Switch", "Hostless LPBK DL"},
{"I2S1_CH1", "ADDA_UL_CH1 Switch", "Hostless LPBK DL"},
{"I2S1_CH2", "ADDA_UL_CH2 Switch", "Hostless LPBK DL"},
{"I2S3_CH1", "ADDA_UL_CH1 Switch", "Hostless LPBK DL"},
{"I2S3_CH1", "ADDA_UL_CH2 Switch", "Hostless LPBK DL"},
{"I2S3_CH2", "ADDA_UL_CH1 Switch", "Hostless LPBK DL"},
{"I2S3_CH2", "ADDA_UL_CH2 Switch", "Hostless LPBK DL"},
{"Hostless LPBK UL", NULL, "ADDA_UL_Mux"},
/* Hostelss FM */
/* connsys_i2s to hw gain 1*/
{"Hostless FM UL", NULL, "Connsys I2S"},
{"HW_GAIN1_IN_CH1", "CONNSYS_I2S_CH1 Switch", "Hostless FM DL"},
{"HW_GAIN1_IN_CH2", "CONNSYS_I2S_CH2 Switch", "Hostless FM DL"},
/* hw gain to adda dl */
{"Hostless FM UL", NULL, "HW Gain 1 Out"},
{"ADDA_DL_CH1", "GAIN1_OUT_CH1 Switch", "Hostless FM DL"},
{"ADDA_DL_CH2", "GAIN1_OUT_CH2 Switch", "Hostless FM DL"},
/* hw gain to i2s3 */
{"I2S3_CH1", "GAIN1_OUT_CH1 Switch", "Hostless FM DL"},
{"I2S3_CH2", "GAIN1_OUT_CH2 Switch", "Hostless FM DL"},
/* hw gain to i2s1 */
{"I2S1_CH1", "GAIN1_OUT_CH1 Switch", "Hostless FM DL"},
{"I2S1_CH2", "GAIN1_OUT_CH2 Switch", "Hostless FM DL"},
/* Hostless_SRC */
{"ADDA_DL_CH1", "SRC_1_OUT_CH1 Switch", "Hostless_SRC_1_DL"},
{"ADDA_DL_CH2", "SRC_1_OUT_CH2 Switch", "Hostless_SRC_1_DL"},
{"I2S1_CH1", "SRC_1_OUT_CH1 Switch", "Hostless_SRC_1_DL"},
{"I2S1_CH2", "SRC_1_OUT_CH2 Switch", "Hostless_SRC_1_DL"},
{"I2S3_CH1", "SRC_1_OUT_CH1 Switch", "Hostless_SRC_1_DL"},
{"I2S3_CH2", "SRC_1_OUT_CH2 Switch", "Hostless_SRC_1_DL"},
{"Hostless_SRC_1_UL", NULL, "HW_SRC_1_Out"},
/* Hostless_SRC_bargein */
{"HW_SRC_1_IN_CH1", "I2S0_CH1 Switch", "Hostless_SRC_Bargein_DL"},
{"HW_SRC_1_IN_CH2", "I2S0_CH2 Switch", "Hostless_SRC_Bargein_DL"},
{"Hostless_SRC_Bargein_UL", NULL, "I2S0"},
/* Hostless AAudio */
{"Hostless HW Gain AAudio In", NULL, "HW Gain 2 In"},
{"Hostless SRC AAudio UL", NULL, "HW Gain 2 Out"},
{"HW_SRC_2_IN_CH1", "HW_GAIN2_OUT_CH1 Switch", "Hostless SRC AAudio DL"},
{"HW_SRC_2_IN_CH2", "HW_GAIN2_OUT_CH2 Switch", "Hostless SRC AAudio DL"},
};
/* dai ops */
static int mtk_dai_hostless_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
struct snd_pcm_runtime *runtime = substream->runtime;
int ret;
snd_soc_set_runtime_hwparams(substream, &mt8186_hostless_hardware);
ret = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0) {
dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n");
return ret;
}
return 0;
}
static const struct snd_soc_dai_ops mtk_dai_hostless_ops = {
.startup = mtk_dai_hostless_startup,
};
/* dai driver */
#define MTK_HOSTLESS_RATES (SNDRV_PCM_RATE_8000_48000 |\
SNDRV_PCM_RATE_88200 |\
SNDRV_PCM_RATE_96000 |\
SNDRV_PCM_RATE_176400 |\
SNDRV_PCM_RATE_192000)
#define MTK_HOSTLESS_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S24_LE |\
SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_driver mtk_dai_hostless_driver[] = {
{
.name = "Hostless LPBK DAI",
.id = MT8186_DAI_HOSTLESS_LPBK,
.playback = {
.stream_name = "Hostless LPBK DL",
.channels_min = 1,
.channels_max = 2,
.rates = MTK_HOSTLESS_RATES,
.formats = MTK_HOSTLESS_FORMATS,
},
.capture = {
.stream_name = "Hostless LPBK UL",
.channels_min = 1,
.channels_max = 2,
.rates = MTK_HOSTLESS_RATES,
.formats = MTK_HOSTLESS_FORMATS,
},
.ops = &mtk_dai_hostless_ops,
},
{
.name = "Hostless FM DAI",
.id = MT8186_DAI_HOSTLESS_FM,
.playback = {
.stream_name = "Hostless FM DL",
.channels_min = 1,
.channels_max = 2,
.rates = MTK_HOSTLESS_RATES,
.formats = MTK_HOSTLESS_FORMATS,
},
.capture = {
.stream_name = "Hostless FM UL",
.channels_min = 1,
.channels_max = 2,
.rates = MTK_HOSTLESS_RATES,
.formats = MTK_HOSTLESS_FORMATS,
},
.ops = &mtk_dai_hostless_ops,
},
{
.name = "Hostless_SRC_1_DAI",
.id = MT8186_DAI_HOSTLESS_SRC_1,
.playback = {
.stream_name = "Hostless_SRC_1_DL",
.channels_min = 1,
.channels_max = 2,
.rates = MTK_HOSTLESS_RATES,
.formats = MTK_HOSTLESS_FORMATS,
},
.capture = {
.stream_name = "Hostless_SRC_1_UL",
.channels_min = 1,
.channels_max = 2,
.rates = MTK_HOSTLESS_RATES,
.formats = MTK_HOSTLESS_FORMATS,
},
.ops = &mtk_dai_hostless_ops,
},
{
.name = "Hostless_SRC_Bargein_DAI",
.id = MT8186_DAI_HOSTLESS_SRC_BARGEIN,
.playback = {
.stream_name = "Hostless_SRC_Bargein_DL",
.channels_min = 1,
.channels_max = 2,
.rates = MTK_HOSTLESS_RATES,
.formats = MTK_HOSTLESS_FORMATS,
},
.capture = {
.stream_name = "Hostless_SRC_Bargein_UL",
.channels_min = 1,
.channels_max = 2,
.rates = MTK_HOSTLESS_RATES,
.formats = MTK_HOSTLESS_FORMATS,
},
.ops = &mtk_dai_hostless_ops,
},
/* BE dai */
{
.name = "Hostless_UL1 DAI",
.id = MT8186_DAI_HOSTLESS_UL1,
.capture = {
.stream_name = "Hostless_UL1 UL",
.channels_min = 1,
.channels_max = 4,
.rates = MTK_HOSTLESS_RATES,
.formats = MTK_HOSTLESS_FORMATS,
},
.ops = &mtk_dai_hostless_ops,
},
{
.name = "Hostless_UL2 DAI",
.id = MT8186_DAI_HOSTLESS_UL2,
.capture = {
.stream_name = "Hostless_UL2 UL",
.channels_min = 1,
.channels_max = 4,
.rates = MTK_HOSTLESS_RATES,
.formats = MTK_HOSTLESS_FORMATS,
},
.ops = &mtk_dai_hostless_ops,
},
{
.name = "Hostless_UL3 DAI",
.id = MT8186_DAI_HOSTLESS_UL3,
.capture = {
.stream_name = "Hostless_UL3 UL",
.channels_min = 1,
.channels_max = 2,
.rates = MTK_HOSTLESS_RATES,
.formats = MTK_HOSTLESS_FORMATS,
},
.ops = &mtk_dai_hostless_ops,
},
{
.name = "Hostless_UL5 DAI",
.id = MT8186_DAI_HOSTLESS_UL5,
.capture = {
.stream_name = "Hostless_UL5 UL",
.channels_min = 1,
.channels_max = 12,
.rates = MTK_HOSTLESS_RATES,
.formats = MTK_HOSTLESS_FORMATS,
},
.ops = &mtk_dai_hostless_ops,
},
{
.name = "Hostless_UL6 DAI",
.id = MT8186_DAI_HOSTLESS_UL6,
.capture = {
.stream_name = "Hostless_UL6 UL",
.channels_min = 1,
.channels_max = 2,
.rates = MTK_HOSTLESS_RATES,
.formats = MTK_HOSTLESS_FORMATS,
},
.ops = &mtk_dai_hostless_ops,
},
{
.name = "Hostless HW Gain AAudio DAI",
.id = MT8186_DAI_HOSTLESS_HW_GAIN_AAUDIO,
.capture = {
.stream_name = "Hostless HW Gain AAudio In",
.channels_min = 1,
.channels_max = 2,
.rates = MTK_HOSTLESS_RATES,
.formats = MTK_HOSTLESS_FORMATS,
},
.ops = &mtk_dai_hostless_ops,
},
{
.name = "Hostless SRC AAudio DAI",
.id = MT8186_DAI_HOSTLESS_SRC_AAUDIO,
.playback = {
.stream_name = "Hostless SRC AAudio DL",
.channels_min = 1,
.channels_max = 2,
.rates = MTK_HOSTLESS_RATES,
.formats = MTK_HOSTLESS_FORMATS,
},
.capture = {
.stream_name = "Hostless SRC AAudio UL",
.channels_min = 1,
.channels_max = 2,
.rates = MTK_HOSTLESS_RATES,
.formats = MTK_HOSTLESS_FORMATS,
},
.ops = &mtk_dai_hostless_ops,
},
};
int mt8186_dai_hostless_register(struct mtk_base_afe *afe)
{
struct mtk_base_afe_dai *dai;
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_hostless_driver;
dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_hostless_driver);
dai->dapm_routes = mtk_dai_hostless_routes;
dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_hostless_routes);
return 0;
}

Просмотреть файл

@ -0,0 +1,236 @@
// SPDX-License-Identifier: GPL-2.0
//
// MediaTek ALSA SoC Audio DAI HW Gain 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"
#define HW_GAIN_1_EN_W_NAME "HW GAIN 1 Enable"
#define HW_GAIN_2_EN_W_NAME "HW GAIN 2 Enable"
/* dai component */
static const struct snd_kcontrol_new mtk_hw_gain1_in_ch1_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH1 Switch", AFE_CONN13_1,
I_CONNSYS_I2S_CH1, 1, 0),
};
static const struct snd_kcontrol_new mtk_hw_gain1_in_ch2_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH2 Switch", AFE_CONN14_1,
I_CONNSYS_I2S_CH2, 1, 0),
};
static const struct snd_kcontrol_new mtk_hw_gain2_in_ch1_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN15,
I_ADDA_UL_CH1, 1, 0),
};
static const struct snd_kcontrol_new mtk_hw_gain2_in_ch2_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN16,
I_ADDA_UL_CH2, 1, 0),
};
static int mtk_hw_gain_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);
unsigned int gain_cur;
unsigned int gain_con1;
dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
__func__, w->name, event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
if (strcmp(w->name, HW_GAIN_1_EN_W_NAME) == 0) {
gain_cur = AFE_GAIN1_CUR;
gain_con1 = AFE_GAIN1_CON1;
} else {
gain_cur = AFE_GAIN2_CUR;
gain_con1 = AFE_GAIN2_CON1;
}
/* let hw gain ramp up, set cur gain to 0 */
regmap_update_bits(afe->regmap, gain_cur, AFE_GAIN1_CUR_MASK_SFT, 0);
/* set target gain to 0 */
regmap_update_bits(afe->regmap, gain_con1, GAIN1_TARGET_MASK_SFT, 0);
break;
default:
break;
}
return 0;
}
static const struct snd_soc_dapm_widget mtk_dai_hw_gain_widgets[] = {
/* inter-connections */
SND_SOC_DAPM_MIXER("HW_GAIN1_IN_CH1", SND_SOC_NOPM, 0, 0,
mtk_hw_gain1_in_ch1_mix,
ARRAY_SIZE(mtk_hw_gain1_in_ch1_mix)),
SND_SOC_DAPM_MIXER("HW_GAIN1_IN_CH2", SND_SOC_NOPM, 0, 0,
mtk_hw_gain1_in_ch2_mix,
ARRAY_SIZE(mtk_hw_gain1_in_ch2_mix)),
SND_SOC_DAPM_MIXER("HW_GAIN2_IN_CH1", SND_SOC_NOPM, 0, 0,
mtk_hw_gain2_in_ch1_mix,
ARRAY_SIZE(mtk_hw_gain2_in_ch1_mix)),
SND_SOC_DAPM_MIXER("HW_GAIN2_IN_CH2", SND_SOC_NOPM, 0, 0,
mtk_hw_gain2_in_ch2_mix,
ARRAY_SIZE(mtk_hw_gain2_in_ch2_mix)),
SND_SOC_DAPM_SUPPLY(HW_GAIN_1_EN_W_NAME,
AFE_GAIN1_CON0, GAIN1_ON_SFT, 0,
mtk_hw_gain_event,
SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_SUPPLY(HW_GAIN_2_EN_W_NAME,
AFE_GAIN2_CON0, GAIN2_ON_SFT, 0,
mtk_hw_gain_event,
SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_INPUT("HW Gain 1 Out Endpoint"),
SND_SOC_DAPM_INPUT("HW Gain 2 Out Endpoint"),
SND_SOC_DAPM_OUTPUT("HW Gain 1 In Endpoint"),
};
static const struct snd_soc_dapm_route mtk_dai_hw_gain_routes[] = {
{"HW Gain 1 In", NULL, "HW_GAIN1_IN_CH1"},
{"HW Gain 1 In", NULL, "HW_GAIN1_IN_CH2"},
{"HW Gain 2 In", NULL, "HW_GAIN2_IN_CH1"},
{"HW Gain 2 In", NULL, "HW_GAIN2_IN_CH2"},
{"HW Gain 1 In", NULL, HW_GAIN_1_EN_W_NAME},
{"HW Gain 1 Out", NULL, HW_GAIN_1_EN_W_NAME},
{"HW Gain 2 In", NULL, HW_GAIN_2_EN_W_NAME},
{"HW Gain 2 Out", NULL, HW_GAIN_2_EN_W_NAME},
{"HW Gain 1 In Endpoint", NULL, "HW Gain 1 In"},
{"HW Gain 1 Out", NULL, "HW Gain 1 Out Endpoint"},
{"HW Gain 2 Out", NULL, "HW Gain 2 Out Endpoint"},
};
static const struct snd_kcontrol_new mtk_hw_gain_controls[] = {
SOC_SINGLE("HW Gain 1 Volume", AFE_GAIN1_CON1,
GAIN1_TARGET_SFT, GAIN1_TARGET_MASK, 0),
SOC_SINGLE("HW Gain 2 Volume", AFE_GAIN2_CON1,
GAIN2_TARGET_SFT, GAIN2_TARGET_MASK, 0),
};
/* dai ops */
static int mtk_dai_gain_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);
unsigned int rate = params_rate(params);
unsigned int rate_reg = mt8186_rate_transform(afe->dev, rate, dai->id);
dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n",
__func__, dai->id, substream->stream, rate);
/* rate */
regmap_update_bits(afe->regmap,
dai->id == MT8186_DAI_HW_GAIN_1 ?
AFE_GAIN1_CON0 : AFE_GAIN2_CON0,
GAIN1_MODE_MASK_SFT,
rate_reg << GAIN1_MODE_SFT);
/* sample per step */
regmap_update_bits(afe->regmap,
dai->id == MT8186_DAI_HW_GAIN_1 ?
AFE_GAIN1_CON0 : AFE_GAIN2_CON0,
GAIN1_SAMPLE_PER_STEP_MASK_SFT,
(dai->id == MT8186_DAI_HW_GAIN_1 ? 0x40 : 0x0) <<
GAIN1_SAMPLE_PER_STEP_SFT);
return 0;
}
static const struct snd_soc_dai_ops mtk_dai_gain_ops = {
.hw_params = mtk_dai_gain_hw_params,
};
/* dai driver */
#define MTK_HW_GAIN_RATES (SNDRV_PCM_RATE_8000_48000 |\
SNDRV_PCM_RATE_88200 |\
SNDRV_PCM_RATE_96000 |\
SNDRV_PCM_RATE_176400 |\
SNDRV_PCM_RATE_192000)
#define MTK_HW_GAIN_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S24_LE |\
SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_driver mtk_dai_gain_driver[] = {
{
.name = "HW Gain 1",
.id = MT8186_DAI_HW_GAIN_1,
.playback = {
.stream_name = "HW Gain 1 In",
.channels_min = 1,
.channels_max = 2,
.rates = MTK_HW_GAIN_RATES,
.formats = MTK_HW_GAIN_FORMATS,
},
.capture = {
.stream_name = "HW Gain 1 Out",
.channels_min = 1,
.channels_max = 2,
.rates = MTK_HW_GAIN_RATES,
.formats = MTK_HW_GAIN_FORMATS,
},
.ops = &mtk_dai_gain_ops,
.symmetric_rate = 1,
.symmetric_channels = 1,
.symmetric_sample_bits = 1,
},
{
.name = "HW Gain 2",
.id = MT8186_DAI_HW_GAIN_2,
.playback = {
.stream_name = "HW Gain 2 In",
.channels_min = 1,
.channels_max = 2,
.rates = MTK_HW_GAIN_RATES,
.formats = MTK_HW_GAIN_FORMATS,
},
.capture = {
.stream_name = "HW Gain 2 Out",
.channels_min = 1,
.channels_max = 2,
.rates = MTK_HW_GAIN_RATES,
.formats = MTK_HW_GAIN_FORMATS,
},
.ops = &mtk_dai_gain_ops,
.symmetric_rate = 1,
.symmetric_channels = 1,
.symmetric_sample_bits = 1,
},
};
int mt8186_dai_hw_gain_register(struct mtk_base_afe *afe)
{
struct mtk_base_afe_dai *dai;
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_gain_driver;
dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_gain_driver);
dai->controls = mtk_hw_gain_controls;
dai->num_controls = ARRAY_SIZE(mtk_hw_gain_controls);
dai->dapm_widgets = mtk_dai_hw_gain_widgets;
dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_hw_gain_widgets);
dai->dapm_routes = mtk_dai_hw_gain_routes;
dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_hw_gain_routes);
return 0;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,423 @@
// SPDX-License-Identifier: GPL-2.0
//
// MediaTek ALSA SoC Audio DAI I2S Control
//
// Copyright (c) 2022 MediaTek Inc.
// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
#include <linux/regmap.h>
#include <sound/pcm_params.h>
#include "mt8186-afe-common.h"
#include "mt8186-afe-gpio.h"
#include "mt8186-interconnection.h"
struct mtk_afe_pcm_priv {
unsigned int id;
unsigned int fmt;
unsigned int bck_invert;
unsigned int lck_invert;
};
enum aud_tx_lch_rpt {
AUD_TX_LCH_RPT_NO_REPEAT = 0,
AUD_TX_LCH_RPT_REPEAT = 1
};
enum aud_vbt_16k_mode {
AUD_VBT_16K_MODE_DISABLE = 0,
AUD_VBT_16K_MODE_ENABLE = 1
};
enum aud_ext_modem {
AUD_EXT_MODEM_SELECT_INTERNAL = 0,
AUD_EXT_MODEM_SELECT_EXTERNAL = 1
};
enum aud_pcm_sync_type {
/* bck sync length = 1 */
AUD_PCM_ONE_BCK_CYCLE_SYNC = 0,
/* bck sync length = PCM_INTF_CON1[9:13] */
AUD_PCM_EXTENDED_BCK_CYCLE_SYNC = 1
};
enum aud_bt_mode {
AUD_BT_MODE_DUAL_MIC_ON_TX = 0,
AUD_BT_MODE_SINGLE_MIC_ON_TX = 1
};
enum aud_pcm_afifo_src {
/* slave mode & external modem uses different crystal */
AUD_PCM_AFIFO_ASRC = 0,
/* slave mode & external modem uses the same crystal */
AUD_PCM_AFIFO_AFIFO = 1
};
enum aud_pcm_clock_source {
AUD_PCM_CLOCK_MASTER_MODE = 0,
AUD_PCM_CLOCK_SLAVE_MODE = 1
};
enum aud_pcm_wlen {
AUD_PCM_WLEN_PCM_32_BCK_CYCLES = 0,
AUD_PCM_WLEN_PCM_64_BCK_CYCLES = 1
};
enum aud_pcm_24bit {
AUD_PCM_24BIT_PCM_16_BITS = 0,
AUD_PCM_24BIT_PCM_24_BITS = 1
};
enum aud_pcm_mode {
AUD_PCM_MODE_PCM_MODE_8K = 0,
AUD_PCM_MODE_PCM_MODE_16K = 1,
AUD_PCM_MODE_PCM_MODE_32K = 2,
AUD_PCM_MODE_PCM_MODE_48K = 3,
};
enum aud_pcm_fmt {
AUD_PCM_FMT_I2S = 0,
AUD_PCM_FMT_EIAJ = 1,
AUD_PCM_FMT_PCM_MODE_A = 2,
AUD_PCM_FMT_PCM_MODE_B = 3
};
enum aud_bclk_out_inv {
AUD_BCLK_OUT_INV_NO_INVERSE = 0,
AUD_BCLK_OUT_INV_INVERSE = 1
};
enum aud_lrclk_out_inv {
AUD_LRCLK_OUT_INV_NO_INVERSE = 0,
AUD_LRCLK_OUT_INV_INVERSE = 1
};
enum aud_pcm_en {
AUD_PCM_EN_DISABLE = 0,
AUD_PCM_EN_ENABLE = 1
};
/* dai component */
static const struct snd_kcontrol_new mtk_pcm_1_playback_ch1_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN7,
I_ADDA_UL_CH1, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN7,
I_DL2_CH1, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN7_1,
I_DL4_CH1, 1, 0),
};
static const struct snd_kcontrol_new mtk_pcm_1_playback_ch2_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN8,
I_ADDA_UL_CH2, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN8,
I_DL2_CH2, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN8_1,
I_DL4_CH2, 1, 0),
};
static int mtk_pcm_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_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_PCM, 0);
break;
case SND_SOC_DAPM_POST_PMD:
mt8186_afe_gpio_request(afe->dev, false, MT8186_DAI_PCM, 0);
break;
}
return 0;
}
/* pcm in/out lpbk */
static const char * const pcm_lpbk_mux_map[] = {
"Normal", "Lpbk",
};
static int pcm_lpbk_mux_map_value[] = {
0, 1,
};
static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(pcm_in_lpbk_mux_map_enum,
PCM_INTF_CON1,
PCM_I2S_PCM_LOOPBACK_SFT,
1,
pcm_lpbk_mux_map,
pcm_lpbk_mux_map_value);
static const struct snd_kcontrol_new pcm_in_lpbk_mux_control =
SOC_DAPM_ENUM("PCM In Lpbk Select", pcm_in_lpbk_mux_map_enum);
static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(pcm_out_lpbk_mux_map_enum,
PCM_INTF_CON1,
PCM_I2S_PCM_LOOPBACK_SFT,
1,
pcm_lpbk_mux_map,
pcm_lpbk_mux_map_value);
static const struct snd_kcontrol_new pcm_out_lpbk_mux_control =
SOC_DAPM_ENUM("PCM Out Lpbk Select", pcm_out_lpbk_mux_map_enum);
static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {
/* inter-connections */
SND_SOC_DAPM_MIXER("PCM_1_PB_CH1", SND_SOC_NOPM, 0, 0,
mtk_pcm_1_playback_ch1_mix,
ARRAY_SIZE(mtk_pcm_1_playback_ch1_mix)),
SND_SOC_DAPM_MIXER("PCM_1_PB_CH2", SND_SOC_NOPM, 0, 0,
mtk_pcm_1_playback_ch2_mix,
ARRAY_SIZE(mtk_pcm_1_playback_ch2_mix)),
SND_SOC_DAPM_SUPPLY("PCM_1_EN",
PCM_INTF_CON1, PCM_EN_SFT, 0,
mtk_pcm_en_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
/* pcm in lpbk */
SND_SOC_DAPM_MUX("PCM_In_Lpbk_Mux",
SND_SOC_NOPM, 0, 0, &pcm_in_lpbk_mux_control),
/* pcm out lpbk */
SND_SOC_DAPM_MUX("PCM_Out_Lpbk_Mux",
SND_SOC_NOPM, 0, 0, &pcm_out_lpbk_mux_control),
};
static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {
{"PCM 1 Playback", NULL, "PCM_1_PB_CH1"},
{"PCM 1 Playback", NULL, "PCM_1_PB_CH2"},
{"PCM 1 Playback", NULL, "PCM_1_EN"},
{"PCM 1 Capture", NULL, "PCM_1_EN"},
{"PCM_1_PB_CH1", "DL2_CH1 Switch", "DL2"},
{"PCM_1_PB_CH2", "DL2_CH2 Switch", "DL2"},
{"PCM_1_PB_CH1", "DL4_CH1 Switch", "DL4"},
{"PCM_1_PB_CH2", "DL4_CH2 Switch", "DL4"},
/* pcm out lpbk */
{"PCM_Out_Lpbk_Mux", "Lpbk", "PCM 1 Playback"},
{"I2S0", NULL, "PCM_Out_Lpbk_Mux"},
/* pcm in lpbk */
{"PCM_In_Lpbk_Mux", "Lpbk", "PCM 1 Capture"},
{"I2S3", NULL, "PCM_In_Lpbk_Mux"},
};
/* dai ops */
static int mtk_dai_pcm_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 pcm_id = dai->id;
struct mtk_afe_pcm_priv *pcm_priv = afe_priv->dai_priv[pcm_id];
unsigned int rate = params_rate(params);
unsigned int rate_reg = mt8186_rate_transform(afe->dev, rate, dai->id);
snd_pcm_format_t format = params_format(params);
unsigned int data_width =
snd_pcm_format_width(format);
unsigned int wlen_width =
snd_pcm_format_physical_width(format);
unsigned int pcm_con = 0;
dev_dbg(afe->dev, "%s(), id %d, stream %d, widget active p %d, c %d\n",
__func__, dai->id, substream->stream, dai->playback_widget->active,
dai->capture_widget->active);
dev_dbg(afe->dev, "%s(), rate %d, rate_reg %d, data_width %d, wlen_width %d\n",
__func__, rate, rate_reg, data_width, wlen_width);
if (dai->playback_widget->active || dai->capture_widget->active)
return 0;
switch (dai->id) {
case MT8186_DAI_PCM:
pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM_TX_LCH_RPT_SFT;
pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM_VBT_16K_MODE_SFT;
pcm_con |= AUD_EXT_MODEM_SELECT_EXTERNAL << PCM_EXT_MODEM_SFT;
pcm_con |= AUD_PCM_ONE_BCK_CYCLE_SYNC << PCM_SYNC_TYPE_SFT;
pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM_BT_MODE_SFT;
pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM_BYP_ASRC_SFT;
pcm_con |= AUD_PCM_CLOCK_MASTER_MODE << PCM_SLAVE_SFT;
pcm_con |= 0 << PCM_SYNC_LENGTH_SFT;
/* sampling rate */
pcm_con |= rate_reg << PCM_MODE_SFT;
/* format */
pcm_con |= pcm_priv->fmt << PCM_FMT_SFT;
/* 24bit data width */
if (data_width > 16)
pcm_con |= AUD_PCM_24BIT_PCM_24_BITS << PCM_24BIT_SFT;
else
pcm_con |= AUD_PCM_24BIT_PCM_16_BITS << PCM_24BIT_SFT;
/* wlen width*/
if (wlen_width > 16)
pcm_con |= AUD_PCM_WLEN_PCM_64_BCK_CYCLES << PCM_WLEN_SFT;
else
pcm_con |= AUD_PCM_WLEN_PCM_32_BCK_CYCLES << PCM_WLEN_SFT;
/* clock invert */
pcm_con |= pcm_priv->lck_invert << PCM_SYNC_OUT_INV_SFT;
pcm_con |= pcm_priv->bck_invert << PCM_BCLK_OUT_INV_SFT;
regmap_update_bits(afe->regmap, PCM_INTF_CON1, 0xfffffffe, pcm_con);
break;
default:
dev_err(afe->dev, "%s(), id %d not support\n", __func__, dai->id);
return -EINVAL;
}
return 0;
}
static int mtk_dai_pcm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
struct mtk_afe_pcm_priv *pcm_priv = afe_priv->dai_priv[dai->id];
if (!pcm_priv) {
dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
return -EINVAL;
}
/* DAI mode*/
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
pcm_priv->fmt = AUD_PCM_FMT_I2S;
break;
case SND_SOC_DAIFMT_LEFT_J:
pcm_priv->fmt = AUD_PCM_FMT_EIAJ;
break;
case SND_SOC_DAIFMT_DSP_A:
pcm_priv->fmt = AUD_PCM_FMT_PCM_MODE_A;
break;
case SND_SOC_DAIFMT_DSP_B:
pcm_priv->fmt = AUD_PCM_FMT_PCM_MODE_B;
break;
default:
pcm_priv->fmt = AUD_PCM_FMT_I2S;
}
/* DAI clock inversion*/
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
pcm_priv->bck_invert = AUD_BCLK_OUT_INV_NO_INVERSE;
pcm_priv->lck_invert = AUD_LRCLK_OUT_INV_NO_INVERSE;
break;
case SND_SOC_DAIFMT_NB_IF:
pcm_priv->bck_invert = AUD_BCLK_OUT_INV_NO_INVERSE;
pcm_priv->lck_invert = AUD_BCLK_OUT_INV_INVERSE;
break;
case SND_SOC_DAIFMT_IB_NF:
pcm_priv->bck_invert = AUD_BCLK_OUT_INV_INVERSE;
pcm_priv->lck_invert = AUD_LRCLK_OUT_INV_NO_INVERSE;
break;
case SND_SOC_DAIFMT_IB_IF:
pcm_priv->bck_invert = AUD_BCLK_OUT_INV_INVERSE;
pcm_priv->lck_invert = AUD_BCLK_OUT_INV_INVERSE;
break;
default:
pcm_priv->bck_invert = AUD_BCLK_OUT_INV_NO_INVERSE;
pcm_priv->lck_invert = AUD_LRCLK_OUT_INV_NO_INVERSE;
break;
}
return 0;
}
static const struct snd_soc_dai_ops mtk_dai_pcm_ops = {
.hw_params = mtk_dai_pcm_hw_params,
.set_fmt = mtk_dai_pcm_set_fmt,
};
/* dai driver */
#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000 |\
SNDRV_PCM_RATE_16000 |\
SNDRV_PCM_RATE_32000 |\
SNDRV_PCM_RATE_48000)
#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S24_LE |\
SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
{
.name = "PCM 1",
.id = MT8186_DAI_PCM,
.playback = {
.stream_name = "PCM 1 Playback",
.channels_min = 1,
.channels_max = 2,
.rates = MTK_PCM_RATES,
.formats = MTK_PCM_FORMATS,
},
.capture = {
.stream_name = "PCM 1 Capture",
.channels_min = 1,
.channels_max = 2,
.rates = MTK_PCM_RATES,
.formats = MTK_PCM_FORMATS,
},
.ops = &mtk_dai_pcm_ops,
.symmetric_rate = 1,
.symmetric_sample_bits = 1,
},
};
static struct mtk_afe_pcm_priv *init_pcm_priv_data(struct mtk_base_afe *afe)
{
struct mtk_afe_pcm_priv *pcm_priv;
pcm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_pcm_priv),
GFP_KERNEL);
if (!pcm_priv)
return NULL;
pcm_priv->id = MT8186_DAI_PCM;
pcm_priv->fmt = AUD_PCM_FMT_I2S;
pcm_priv->bck_invert = AUD_BCLK_OUT_INV_NO_INVERSE;
pcm_priv->lck_invert = AUD_LRCLK_OUT_INV_NO_INVERSE;
return pcm_priv;
}
int mt8186_dai_pcm_register(struct mtk_base_afe *afe)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
struct mtk_afe_pcm_priv *pcm_priv;
struct mtk_base_afe_dai *dai;
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_pcm_driver;
dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
dai->dapm_widgets = mtk_dai_pcm_widgets;
dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
dai->dapm_routes = mtk_dai_pcm_routes;
dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
pcm_priv = init_pcm_priv_data(afe);
if (!pcm_priv)
return -ENOMEM;
afe_priv->dai_priv[MT8186_DAI_PCM] = pcm_priv;
return 0;
}

Просмотреть файл

@ -0,0 +1,695 @@
// 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[] = {
0x0dbae6, 0xff9b0a, 0x0dbae6, 0x05e488, 0xe072b9, 0x000002,
0x0dbae6, 0x000f3b, 0x0dbae6, 0x06a537, 0xe17d79, 0x000002,
0x0dbae6, 0x01246a, 0x0dbae6, 0x087261, 0xe306be, 0x000002,
0x0dbae6, 0x03437d, 0x0dbae6, 0x0bc16f, 0xe57c87, 0x000002,
0x0dbae6, 0x072981, 0x0dbae6, 0x111dd3, 0xe94f2a, 0x000002,
0x0dbae6, 0x0dc4a6, 0x0dbae6, 0x188611, 0xee85a0, 0x000002,
0x0dbae6, 0x168b9a, 0x0dbae6, 0x200e8f, 0xf3ccf1, 0x000002,
0x000000, 0x1b75cb, 0x1b75cb, 0x2374a2, 0x000000, 0x000001
};
static const unsigned int src_iir_coeff_44_to_16[] = {
0x09ae28, 0xf7d97d, 0x09ae28, 0x212a3d, 0xe0ac3a, 0x000002,
0x09ae28, 0xf8525a, 0x09ae28, 0x216d72, 0xe234be, 0x000002,
0x09ae28, 0xf980f5, 0x09ae28, 0x22a057, 0xe45a81, 0x000002,
0x09ae28, 0xfc0a08, 0x09ae28, 0x24d3bd, 0xe7752d, 0x000002,
0x09ae28, 0x016162, 0x09ae28, 0x27da01, 0xeb6ea8, 0x000002,
0x09ae28, 0x0b67df, 0x09ae28, 0x2aca4a, 0xef34c4, 0x000002,
0x000000, 0x135c50, 0x135c50, 0x2c1079, 0x000000, 0x000001
};
static const unsigned int src_iir_coeff_44_to_32[] = {
0x096966, 0x0c4d35, 0x096966, 0xedee81, 0xf05070, 0x000003,
0x12d2cc, 0x193910, 0x12d2cc, 0xddbf4f, 0xe21e1d, 0x000002,
0x12d2cc, 0x1a9e60, 0x12d2cc, 0xe18916, 0xe470fd, 0x000002,
0x12d2cc, 0x1d06e0, 0x12d2cc, 0xe8a4a6, 0xe87b24, 0x000002,
0x12d2cc, 0x207578, 0x12d2cc, 0xf4fe62, 0xef5917, 0x000002,
0x12d2cc, 0x24055f, 0x12d2cc, 0x05ee2b, 0xf8b502, 0x000002,
0x000000, 0x25a599, 0x25a599, 0x0fabe2, 0x000000, 0x000001
};
static const unsigned int src_iir_coeff_48_to_16[] = {
0x0296a4, 0xfd69dd, 0x0296a4, 0x209439, 0xe01ff9, 0x000002,
0x0f4ff3, 0xf0d6d4, 0x0f4ff3, 0x209bc9, 0xe076c3, 0x000002,
0x0e8490, 0xf1fe63, 0x0e8490, 0x20cfd6, 0xe12124, 0x000002,
0x14852f, 0xed794a, 0x14852f, 0x21503d, 0xe28b32, 0x000002,
0x136222, 0xf17677, 0x136222, 0x225be1, 0xe56964, 0x000002,
0x0a8d85, 0xfc4a97, 0x0a8d85, 0x24310c, 0xea6952, 0x000002,
0x05eff5, 0x043455, 0x05eff5, 0x4ced8f, 0xe134d6, 0x000001,
0x000000, 0x3aebe6, 0x3aebe6, 0x04f3b0, 0x000000, 0x000004
};
static const unsigned int src_iir_coeff_48_to_32[] = {
0x10c1b8, 0x10a7df, 0x10c1b8, 0xe7514e, 0xe0b41f, 0x000002,
0x10c1b8, 0x116257, 0x10c1b8, 0xe9402f, 0xe25aaa, 0x000002,
0x10c1b8, 0x130c89, 0x10c1b8, 0xed3cc3, 0xe4dddb, 0x000002,
0x10c1b8, 0x1600dd, 0x10c1b8, 0xf48000, 0xe90c55, 0x000002,
0x10c1b8, 0x1a672e, 0x10c1b8, 0x00494c, 0xefa807, 0x000002,
0x10c1b8, 0x1f38e6, 0x10c1b8, 0x0ee076, 0xf7c5f3, 0x000002,
0x000000, 0x218370, 0x218370, 0x168b40, 0x000000, 0x000001
};
static const unsigned int src_iir_coeff_48_to_44[] = {
0x0bf71c, 0x170f3f, 0x0bf71c, 0xe3a4c8, 0xf096cb, 0x000003,
0x0bf71c, 0x17395e, 0x0bf71c, 0xe58085, 0xf210c8, 0x000003,
0x0bf71c, 0x1782bd, 0x0bf71c, 0xe95ef6, 0xf4c899, 0x000003,
0x0bf71c, 0x17cd97, 0x0bf71c, 0xf1608a, 0xfa3b18, 0x000003,
0x000000, 0x2fdc6f, 0x2fdc6f, 0xf15663, 0x000000, 0x000001
};
static const unsigned int src_iir_coeff_96_to_16[] = {
0x0805a1, 0xf21ae3, 0x0805a1, 0x3840bb, 0xe02a2e, 0x000002,
0x0d5dd8, 0xe8f259, 0x0d5dd8, 0x1c0af6, 0xf04700, 0x000003,
0x0bb422, 0xec08d9, 0x0bb422, 0x1bfccc, 0xf09216, 0x000003,
0x08fde6, 0xf108be, 0x08fde6, 0x1bf096, 0xf10ae0, 0x000003,
0x0ae311, 0xeeeda3, 0x0ae311, 0x37c646, 0xe385f5, 0x000002,
0x044089, 0xfa7242, 0x044089, 0x37a785, 0xe56526, 0x000002,
0x00c75c, 0xffb947, 0x00c75c, 0x378ba3, 0xe72c5f, 0x000002,
0x000000, 0x0ef76e, 0x0ef76e, 0x377fda, 0x000000, 0x000001,
};
static const unsigned int src_iir_coeff_96_to_44[] = {
0x08b543, 0xfd80f4, 0x08b543, 0x0e2332, 0xe06ed0, 0x000002,
0x1b6038, 0xf90e7e, 0x1b6038, 0x0ec1ac, 0xe16f66, 0x000002,
0x188478, 0xfbb921, 0x188478, 0x105859, 0xe2e596, 0x000002,
0x13eff3, 0xffa707, 0x13eff3, 0x13455c, 0xe533b7, 0x000002,
0x0dc239, 0x03d458, 0x0dc239, 0x17f120, 0xe8b617, 0x000002,
0x0745f1, 0x05d790, 0x0745f1, 0x1e3d75, 0xed5f18, 0x000002,
0x05641f, 0x085e2b, 0x05641f, 0x48efd0, 0xe3e9c8, 0x000001,
0x000000, 0x28f632, 0x28f632, 0x273905, 0x000000, 0x000001,
};
static unsigned int mtk_get_src_freq_mode(struct mtk_base_afe *afe, int rate)
{
switch (rate) {
case 8000:
return 0x50000;
case 11025:
return 0x6e400;
case 12000:
return 0x78000;
case 16000:
return 0xa0000;
case 22050:
return 0xdc800;
case 24000:
return 0xf0000;
case 32000:
return 0x140000;
case 44100:
return 0x1b9000;
case 48000:
return 0x1e0000;
case 88200:
return 0x372000;
case 96000:
return 0x3c0000;
case 176400:
return 0x6e4000;
case 192000:
return 0x780000;
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, 0x3f5986);
regmap_write(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON5, 0x3f5987);
regmap_write(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON6, 0x1fbd);
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, 0x3f5986);
regmap_write(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON5, 0x3f5987);
regmap_write(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON6, 0x1fbd);
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 (strcmp(w->name, 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 (strcmp(w->name, 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;
}

Просмотреть файл

@ -0,0 +1,698 @@
// SPDX-License-Identifier: GPL-2.0
//
// MediaTek ALSA SoC Audio DAI TDM Control
//
// Copyright (c) 2022 MediaTek Inc.
// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
#include <linux/regmap.h>
#include <sound/pcm_params.h>
#include "mt8186-afe-clk.h"
#include "mt8186-afe-common.h"
#include "mt8186-afe-gpio.h"
#include "mt8186-interconnection.h"
#define TDM_HD_EN_W_NAME "TDM_HD_EN"
#define TDM_MCLK_EN_W_NAME "TDM_MCLK_EN"
#define MTK_AFE_TDM_KCONTROL_NAME "TDM_HD_Mux"
struct mtk_afe_tdm_priv {
unsigned int id;
unsigned int rate; /* for determine which apll to use */
unsigned int bck_invert;
unsigned int lck_invert;
unsigned int lrck_width;
unsigned int mclk_id;
unsigned int mclk_multiple; /* according to sample rate */
unsigned int mclk_rate;
unsigned int mclk_apll;
unsigned int tdm_mode;
unsigned int data_mode;
unsigned int slave_mode;
unsigned int low_jitter_en;
};
enum {
TDM_IN_I2S = 0,
TDM_IN_LJ = 1,
TDM_IN_RJ = 2,
TDM_IN_DSP_A = 4,
TDM_IN_DSP_B = 5,
};
enum {
TDM_DATA_ONE_PIN = 0,
TDM_DATA_MULTI_PIN,
};
enum {
TDM_BCK_NON_INV = 0,
TDM_BCK_INV = 1,
};
enum {
TDM_LCK_NON_INV = 0,
TDM_LCK_INV = 1,
};
static unsigned int get_tdm_lrck_width(snd_pcm_format_t format,
unsigned int mode)
{
if (mode == TDM_IN_DSP_A || mode == TDM_IN_DSP_B)
return 0;
return snd_pcm_format_physical_width(format) - 1;
}
static unsigned int get_tdm_ch_fixup(unsigned int channels)
{
if (channels > 4)
return 8;
else if (channels > 2)
return 4;
return 2;
}
static unsigned int get_tdm_ch_per_sdata(unsigned int mode,
unsigned int channels)
{
if (mode == TDM_IN_DSP_A || mode == TDM_IN_DSP_B)
return get_tdm_ch_fixup(channels);
return 2;
}
enum {
SUPPLY_SEQ_APLL,
SUPPLY_SEQ_TDM_MCK_EN,
SUPPLY_SEQ_TDM_HD_EN,
SUPPLY_SEQ_TDM_EN,
};
static int get_tdm_id_by_name(const char *name)
{
return MT8186_DAI_TDM_IN;
}
static int mtk_tdm_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 mt8186_afe_private *afe_priv = afe->platform_priv;
int dai_id = get_tdm_id_by_name(w->name);
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
if (!tdm_priv) {
dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
return -EINVAL;
}
dev_dbg(cmpnt->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, tdm_priv->id, 0);
break;
case SND_SOC_DAPM_POST_PMD:
mt8186_afe_gpio_request(afe->dev, false, tdm_priv->id, 0);
break;
default:
break;
}
return 0;
}
static int mtk_tdm_mck_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 mt8186_afe_private *afe_priv = afe->platform_priv;
int dai_id = get_tdm_id_by_name(w->name);
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
if (!tdm_priv) {
dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
return -EINVAL;
}
dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x, dai_id %d\n",
__func__, w->name, event, dai_id);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
mt8186_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate);
break;
case SND_SOC_DAPM_POST_PMD:
tdm_priv->mclk_rate = 0;
mt8186_mck_disable(afe, tdm_priv->mclk_id);
break;
default:
break;
}
return 0;
}
/* dai component */
/* tdm virtual mux to output widget */
static const char * const tdm_mux_map[] = {
"Normal", "Dummy_Widget",
};
static int tdm_mux_map_value[] = {
0, 1,
};
static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(tdm_mux_map_enum,
SND_SOC_NOPM,
0,
1,
tdm_mux_map,
tdm_mux_map_value);
static const struct snd_kcontrol_new tdm_in_mux_control =
SOC_DAPM_ENUM("TDM In Select", tdm_mux_map_enum);
static const struct snd_soc_dapm_widget mtk_dai_tdm_widgets[] = {
SND_SOC_DAPM_CLOCK_SUPPLY("aud_tdm_clk"),
SND_SOC_DAPM_SUPPLY_S("TDM_EN", SUPPLY_SEQ_TDM_EN,
ETDM_IN1_CON0, ETDM_IN1_CON0_REG_ETDM_IN_EN_SFT,
0, mtk_tdm_en_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
/* tdm hd en */
SND_SOC_DAPM_SUPPLY_S(TDM_HD_EN_W_NAME, SUPPLY_SEQ_TDM_HD_EN,
ETDM_IN1_CON2, ETDM_IN1_CON2_REG_CLOCK_SOURCE_SEL_SFT,
0, NULL,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY_S(TDM_MCLK_EN_W_NAME, SUPPLY_SEQ_TDM_MCK_EN,
SND_SOC_NOPM, 0, 0,
mtk_tdm_mck_en_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_INPUT("TDM_DUMMY_IN"),
SND_SOC_DAPM_MUX("TDM_In_Mux",
SND_SOC_NOPM, 0, 0, &tdm_in_mux_control),
};
static int mtk_afe_tdm_mclk_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 mt8186_afe_private *afe_priv = afe->platform_priv;
int dai_id = get_tdm_id_by_name(w->name);
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
if (!tdm_priv) {
dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
return 0;
}
return (tdm_priv->mclk_rate > 0) ? 1 : 0;
}
static int mtk_afe_tdm_mclk_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 mt8186_afe_private *afe_priv = afe->platform_priv;
int dai_id = get_tdm_id_by_name(w->name);
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
int cur_apll;
/* which apll */
cur_apll = mt8186_get_apll_by_name(afe, source->name);
return (tdm_priv->mclk_apll == cur_apll) ? 1 : 0;
}
static int mtk_afe_tdm_hd_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 mt8186_afe_private *afe_priv = afe->platform_priv;
int dai_id = get_tdm_id_by_name(w->name);
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
if (!tdm_priv) {
dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
return 0;
}
return tdm_priv->low_jitter_en;
}
static int mtk_afe_tdm_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 mt8186_afe_private *afe_priv = afe->platform_priv;
int dai_id = get_tdm_id_by_name(w->name);
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
int cur_apll;
int tdm_need_apll;
if (!tdm_priv) {
dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
return 0;
}
/* which apll */
cur_apll = mt8186_get_apll_by_name(afe, source->name);
/* choose APLL from tdm rate */
tdm_need_apll = mt8186_get_apll_by_rate(afe, tdm_priv->rate);
return (tdm_need_apll == cur_apll) ? 1 : 0;
}
/* low jitter control */
static const char * const mt8186_tdm_hd_str[] = {
"Normal", "Low_Jitter"
};
static const struct soc_enum mt8186_tdm_enum[] = {
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8186_tdm_hd_str),
mt8186_tdm_hd_str),
};
static int mt8186_tdm_hd_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;
int dai_id = get_tdm_id_by_name(kcontrol->id.name);
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
if (!tdm_priv) {
dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
return -EINVAL;
}
ucontrol->value.integer.value[0] = tdm_priv->low_jitter_en;
return 0;
}
static int mt8186_tdm_hd_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;
int dai_id = get_tdm_id_by_name(kcontrol->id.name);
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
int hd_en;
if (ucontrol->value.enumerated.item[0] >= e->items)
return -EINVAL;
hd_en = ucontrol->value.integer.value[0];
dev_dbg(afe->dev, "%s(), kcontrol name %s, hd_en %d\n",
__func__, kcontrol->id.name, hd_en);
if (!tdm_priv) {
dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
return -EINVAL;
}
if (tdm_priv->low_jitter_en == hd_en)
return 0;
tdm_priv->low_jitter_en = hd_en;
return 1;
}
static const struct snd_kcontrol_new mtk_dai_tdm_controls[] = {
SOC_ENUM_EXT(MTK_AFE_TDM_KCONTROL_NAME, mt8186_tdm_enum[0],
mt8186_tdm_hd_get, mt8186_tdm_hd_set),
};
static const struct snd_soc_dapm_route mtk_dai_tdm_routes[] = {
{"TDM IN", NULL, "aud_tdm_clk"},
{"TDM IN", NULL, "TDM_EN"},
{"TDM IN", NULL, TDM_HD_EN_W_NAME, mtk_afe_tdm_hd_connect},
{TDM_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect},
{TDM_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect},
{"TDM IN", NULL, TDM_MCLK_EN_W_NAME, mtk_afe_tdm_mclk_connect},
{TDM_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_tdm_mclk_apll_connect},
{TDM_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_tdm_mclk_apll_connect},
/* allow tdm on without codec on */
{"TDM IN", NULL, "TDM_In_Mux"},
{"TDM_In_Mux", "Dummy_Widget", "TDM_DUMMY_IN"},
};
/* dai ops */
static int mtk_dai_tdm_cal_mclk(struct mtk_base_afe *afe,
struct mtk_afe_tdm_priv *tdm_priv,
int freq)
{
int apll;
int apll_rate;
apll = mt8186_get_apll_by_rate(afe, freq);
apll_rate = mt8186_get_apll_rate(afe, apll);
if (!freq || freq > apll_rate) {
dev_err(afe->dev,
"%s(), freq(%d Hz) invalid\n", __func__, freq);
return -EINVAL;
}
if (apll_rate % freq != 0) {
dev_err(afe->dev,
"%s(), APLL cannot generate %d Hz", __func__, freq);
return -EINVAL;
}
tdm_priv->mclk_rate = freq;
tdm_priv->mclk_apll = apll;
return 0;
}
static int mtk_dai_tdm_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 tdm_id = dai->id;
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[tdm_id];
unsigned int tdm_mode = tdm_priv->tdm_mode;
unsigned int data_mode = tdm_priv->data_mode;
unsigned int rate = params_rate(params);
unsigned int channels = params_channels(params);
snd_pcm_format_t format = params_format(params);
unsigned int bit_width =
snd_pcm_format_physical_width(format);
unsigned int tdm_channels = (data_mode == TDM_DATA_ONE_PIN) ?
get_tdm_ch_per_sdata(tdm_mode, channels) : 2;
unsigned int lrck_width =
get_tdm_lrck_width(format, tdm_mode);
unsigned int tdm_con = 0;
bool slave_mode = tdm_priv->slave_mode;
bool lrck_inv = tdm_priv->lck_invert;
bool bck_inv = tdm_priv->bck_invert;
unsigned int tran_rate;
unsigned int tran_relatch_rate;
if (!tdm_priv) {
dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
return -EINVAL;
}
tdm_priv->rate = rate;
tran_rate = mt8186_rate_transform(afe->dev, rate, dai->id);
tran_relatch_rate = mt8186_tdm_relatch_rate_transform(afe->dev, rate);
/* calculate mclk_rate, if not set explicitly */
if (!tdm_priv->mclk_rate) {
tdm_priv->mclk_rate = rate * tdm_priv->mclk_multiple;
mtk_dai_tdm_cal_mclk(afe,
tdm_priv,
tdm_priv->mclk_rate);
}
/* ETDM_IN1_CON0 */
tdm_con |= slave_mode << ETDM_IN1_CON0_REG_SLAVE_MODE_SFT;
tdm_con |= tdm_mode << ETDM_IN1_CON0_REG_FMT_SFT;
tdm_con |= (bit_width - 1) << ETDM_IN1_CON0_REG_BIT_LENGTH_SFT;
tdm_con |= (bit_width - 1) << ETDM_IN1_CON0_REG_WORD_LENGTH_SFT;
tdm_con |= (tdm_channels - 1) << ETDM_IN1_CON0_REG_CH_NUM_SFT;
/* need to disable sync mode otherwise this may cause latch data error */
tdm_con |= 0 << ETDM_IN1_CON0_REG_SYNC_MODE_SFT;
/* relatch 1x en clock fix to h26m */
tdm_con |= 0 << ETDM_IN1_CON0_REG_RELATCH_1X_EN_SEL_DOMAIN_SFT;
regmap_update_bits(afe->regmap, ETDM_IN1_CON0, ETDM_IN_CON0_CTRL_MASK, tdm_con);
/* ETDM_IN1_CON1 */
tdm_con = 0;
tdm_con |= 0 << ETDM_IN1_CON1_REG_LRCK_AUTO_MODE_SFT;
tdm_con |= 1 << ETDM_IN1_CON1_PINMUX_MCLK_CTRL_OE_SFT;
tdm_con |= (lrck_width - 1) << ETDM_IN1_CON1_REG_LRCK_WIDTH_SFT;
regmap_update_bits(afe->regmap, ETDM_IN1_CON1, ETDM_IN_CON1_CTRL_MASK, tdm_con);
/* ETDM_IN1_CON3 */
tdm_con = 0;
tdm_con = ETDM_IN_CON3_FS(tran_rate);
regmap_update_bits(afe->regmap, ETDM_IN1_CON3, ETDM_IN_CON3_CTRL_MASK, tdm_con);
/* ETDM_IN1_CON4 */
tdm_con = 0;
tdm_con = ETDM_IN_CON4_FS(tran_relatch_rate);
if (slave_mode) {
if (lrck_inv)
tdm_con |= ETDM_IN_CON4_CON0_SLAVE_LRCK_INV;
if (bck_inv)
tdm_con |= ETDM_IN_CON4_CON0_SLAVE_BCK_INV;
} else {
if (lrck_inv)
tdm_con |= ETDM_IN_CON4_CON0_MASTER_LRCK_INV;
if (bck_inv)
tdm_con |= ETDM_IN_CON4_CON0_MASTER_BCK_INV;
}
regmap_update_bits(afe->regmap, ETDM_IN1_CON4, ETDM_IN_CON4_CTRL_MASK, tdm_con);
/* ETDM_IN1_CON2 */
tdm_con = 0;
if (data_mode == TDM_DATA_MULTI_PIN) {
tdm_con |= ETDM_IN_CON2_MULTI_IP_2CH_MODE;
tdm_con |= ETDM_IN_CON2_MULTI_IP_CH(channels);
}
regmap_update_bits(afe->regmap, ETDM_IN1_CON2, ETDM_IN_CON2_CTRL_MASK, tdm_con);
/* ETDM_IN1_CON8 */
tdm_con = 0;
if (slave_mode) {
tdm_con |= 1 << ETDM_IN1_CON8_REG_ETDM_USE_AFIFO_SFT;
tdm_con |= 0 << ETDM_IN1_CON8_REG_AFIFO_CLOCK_DOMAIN_SEL_SFT;
tdm_con |= ETDM_IN_CON8_FS(tran_relatch_rate);
} else {
tdm_con |= 0 << ETDM_IN1_CON8_REG_ETDM_USE_AFIFO_SFT;
}
regmap_update_bits(afe->regmap, ETDM_IN1_CON8, ETDM_IN_CON8_CTRL_MASK, tdm_con);
return 0;
}
static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai,
int clk_id, unsigned int freq, int dir)
{
struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];
if (!tdm_priv) {
dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
return -EINVAL;
}
if (dir != SND_SOC_CLOCK_IN) {
dev_err(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__);
return -EINVAL;
}
dev_dbg(afe->dev, "%s(), freq %d\n", __func__, freq);
return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq);
}
static int mtk_dai_tdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];
if (!tdm_priv) {
dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
return -EINVAL;
}
/* DAI mode*/
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
tdm_priv->tdm_mode = TDM_IN_I2S;
tdm_priv->data_mode = TDM_DATA_MULTI_PIN;
break;
case SND_SOC_DAIFMT_LEFT_J:
tdm_priv->tdm_mode = TDM_IN_LJ;
tdm_priv->data_mode = TDM_DATA_MULTI_PIN;
break;
case SND_SOC_DAIFMT_RIGHT_J:
tdm_priv->tdm_mode = TDM_IN_RJ;
tdm_priv->data_mode = TDM_DATA_MULTI_PIN;
break;
case SND_SOC_DAIFMT_DSP_A:
tdm_priv->tdm_mode = TDM_IN_DSP_A;
tdm_priv->data_mode = TDM_DATA_ONE_PIN;
break;
case SND_SOC_DAIFMT_DSP_B:
tdm_priv->tdm_mode = TDM_IN_DSP_B;
tdm_priv->data_mode = TDM_DATA_ONE_PIN;
break;
default:
dev_err(afe->dev, "%s(), invalid DAIFMT_FORMAT_MASK", __func__);
return -EINVAL;
}
/* DAI clock inversion*/
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
tdm_priv->bck_invert = TDM_BCK_NON_INV;
tdm_priv->lck_invert = TDM_LCK_NON_INV;
break;
case SND_SOC_DAIFMT_NB_IF:
tdm_priv->bck_invert = TDM_BCK_NON_INV;
tdm_priv->lck_invert = TDM_LCK_INV;
break;
case SND_SOC_DAIFMT_IB_NF:
tdm_priv->bck_invert = TDM_BCK_INV;
tdm_priv->lck_invert = TDM_LCK_NON_INV;
break;
case SND_SOC_DAIFMT_IB_IF:
tdm_priv->bck_invert = TDM_BCK_INV;
tdm_priv->lck_invert = TDM_LCK_INV;
break;
default:
dev_err(afe->dev, "%s(), invalid DAIFMT_INV_MASK", __func__);
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_CBP_CFP:
tdm_priv->slave_mode = false;
break;
case SND_SOC_DAIFMT_CBC_CFC:
tdm_priv->slave_mode = true;
break;
default:
dev_err(afe->dev, "%s(), invalid DAIFMT_CLOCK_PROVIDER_MASK",
__func__);
return -EINVAL;
}
return 0;
}
static int mtk_dai_tdm_set_tdm_slot(struct snd_soc_dai *dai,
unsigned int tx_mask,
unsigned int rx_mask,
int slots,
int slot_width)
{
struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];
dev_dbg(dai->dev, "%s %d slot_width %d\n", __func__, dai->id, slot_width);
tdm_priv->lrck_width = slot_width;
return 0;
}
static const struct snd_soc_dai_ops mtk_dai_tdm_ops = {
.hw_params = mtk_dai_tdm_hw_params,
.set_sysclk = mtk_dai_tdm_set_sysclk,
.set_fmt = mtk_dai_tdm_set_fmt,
.set_tdm_slot = mtk_dai_tdm_set_tdm_slot,
};
/* dai driver */
#define MTK_TDM_RATES (SNDRV_PCM_RATE_8000_48000 |\
SNDRV_PCM_RATE_88200 |\
SNDRV_PCM_RATE_96000 |\
SNDRV_PCM_RATE_176400 |\
SNDRV_PCM_RATE_192000)
#define MTK_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S24_LE |\
SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_driver mtk_dai_tdm_driver[] = {
{
.name = "TDM IN",
.id = MT8186_DAI_TDM_IN,
.capture = {
.stream_name = "TDM IN",
.channels_min = 2,
.channels_max = 8,
.rates = MTK_TDM_RATES,
.formats = MTK_TDM_FORMATS,
},
.ops = &mtk_dai_tdm_ops,
},
};
static struct mtk_afe_tdm_priv *init_tdm_priv_data(struct mtk_base_afe *afe)
{
struct mtk_afe_tdm_priv *tdm_priv;
tdm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_tdm_priv),
GFP_KERNEL);
if (!tdm_priv)
return NULL;
tdm_priv->mclk_multiple = 512;
tdm_priv->mclk_id = MT8186_TDM_MCK;
tdm_priv->id = MT8186_DAI_TDM_IN;
return tdm_priv;
}
int mt8186_dai_tdm_register(struct mtk_base_afe *afe)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
struct mtk_afe_tdm_priv *tdm_priv;
struct mtk_base_afe_dai *dai;
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_tdm_driver;
dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_tdm_driver);
dai->controls = mtk_dai_tdm_controls;
dai->num_controls = ARRAY_SIZE(mtk_dai_tdm_controls);
dai->dapm_widgets = mtk_dai_tdm_widgets;
dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_tdm_widgets);
dai->dapm_routes = mtk_dai_tdm_routes;
dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_tdm_routes);
tdm_priv = init_tdm_priv_data(afe);
if (!tdm_priv)
return -ENOMEM;
afe_priv->dai_priv[MT8186_DAI_TDM_IN] = tdm_priv;
return 0;
}

Просмотреть файл

@ -0,0 +1,69 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Mediatek MT8186 audio driver interconnection definition
*
* Copyright (c) 2022 MediaTek Inc.
* Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
*/
#ifndef _MT8186_INTERCONNECTION_H_
#define _MT8186_INTERCONNECTION_H_
/* in port define */
#define I_I2S0_CH1 0
#define I_I2S0_CH2 1
#define I_ADDA_UL_CH1 3
#define I_ADDA_UL_CH2 4
#define I_DL1_CH1 5
#define I_DL1_CH2 6
#define I_DL2_CH1 7
#define I_DL2_CH2 8
#define I_PCM_1_CAP_CH1 9
#define I_GAIN1_OUT_CH1 10
#define I_GAIN1_OUT_CH2 11
#define I_GAIN2_OUT_CH1 12
#define I_GAIN2_OUT_CH2 13
#define I_PCM_2_CAP_CH1 14
#define I_ADDA_UL_CH3 17
#define I_ADDA_UL_CH4 18
#define I_DL12_CH1 19
#define I_DL12_CH2 20
#define I_DL12_CH3 5
#define I_DL12_CH4 6
#define I_PCM_2_CAP_CH2 21
#define I_PCM_1_CAP_CH2 22
#define I_DL3_CH1 23
#define I_DL3_CH2 24
#define I_I2S2_CH1 25
#define I_I2S2_CH2 26
#define I_I2S2_CH3 27
#define I_I2S2_CH4 28
/* in port define >= 32 */
#define I_32_OFFSET 32
#define I_CONNSYS_I2S_CH1 (34 - I_32_OFFSET)
#define I_CONNSYS_I2S_CH2 (35 - I_32_OFFSET)
#define I_SRC_1_OUT_CH1 (36 - I_32_OFFSET)
#define I_SRC_1_OUT_CH2 (37 - I_32_OFFSET)
#define I_SRC_2_OUT_CH1 (38 - I_32_OFFSET)
#define I_SRC_2_OUT_CH2 (39 - I_32_OFFSET)
#define I_DL4_CH1 (40 - I_32_OFFSET)
#define I_DL4_CH2 (41 - I_32_OFFSET)
#define I_DL5_CH1 (42 - I_32_OFFSET)
#define I_DL5_CH2 (43 - I_32_OFFSET)
#define I_DL6_CH1 (44 - I_32_OFFSET)
#define I_DL6_CH2 (45 - I_32_OFFSET)
#define I_DL7_CH1 (46 - I_32_OFFSET)
#define I_DL7_CH2 (47 - I_32_OFFSET)
#define I_DL8_CH1 (48 - I_32_OFFSET)
#define I_DL8_CH2 (49 - I_32_OFFSET)
#define I_TDM_IN_CH1 (56 - I_32_OFFSET)
#define I_TDM_IN_CH2 (57 - I_32_OFFSET)
#define I_TDM_IN_CH3 (58 - I_32_OFFSET)
#define I_TDM_IN_CH4 (59 - I_32_OFFSET)
#define I_TDM_IN_CH5 (60 - I_32_OFFSET)
#define I_TDM_IN_CH6 (61 - I_32_OFFSET)
#define I_TDM_IN_CH7 (62 - I_32_OFFSET)
#define I_TDM_IN_CH8 (63 - I_32_OFFSET)
#endif

Просмотреть файл

@ -0,0 +1,252 @@
// SPDX-License-Identifier: GPL-2.0
//
// MediaTek ALSA SoC Audio Misc Control
//
// Copyright (c) 2022 MediaTek Inc.
// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/regmap.h>
#include <sound/soc.h>
#include "../common/mtk-afe-fe-dai.h"
#include "../common/mtk-afe-platform-driver.h"
#include "mt8186-afe-common.h"
static const char * const mt8186_sgen_mode_str[] = {
"I0I1", "I2", "I3I4", "I5I6",
"I7I8", "I9I22", "I10I11", "I12I13",
"I14I21", "I15I16", "I17I18", "I19I20",
"I23I24", "I25I26", "I27I28", "I33",
"I34I35", "I36I37", "I38I39", "I40I41",
"I42I43", "I44I45", "I46I47", "I48I49",
"I56I57", "I58I59", "I60I61", "I62I63",
"O0O1", "O2", "O3O4", "O5O6",
"O7O8", "O9O10", "O11", "O12",
"O13O14", "O15O16", "O17O18", "O19O20",
"O21O22", "O23O24", "O25", "O28O29",
"O34", "O35", "O32O33", "O36O37",
"O38O39", "O30O31", "O40O41", "O42O43",
"O44O45", "O46O47", "O48O49", "O50O51",
"O58O59", "O60O61", "O62O63", "O64O65",
"O66O67", "O68O69", "O26O27", "OFF",
};
static const int mt8186_sgen_mode_idx[] = {
0, 2, 4, 6,
8, 22, 10, 12,
14, -1, 18, 20,
24, 26, 28, 33,
34, 36, 38, 40,
42, 44, 46, 48,
56, 58, 60, 62,
128, 130, 132, 134,
135, 138, 139, 140,
142, 144, 166, 148,
150, 152, 153, 156,
162, 163, 160, 164,
166, -1, 168, 170,
172, 174, 176, 178,
186, 188, 190, 192,
194, 196, -1, -1,
};
static const char * const mt8186_sgen_rate_str[] = {
"8K", "11K", "12K", "16K",
"22K", "24K", "32K", "44K",
"48K", "88k", "96k", "176k",
"192k"
};
static const int mt8186_sgen_rate_idx[] = {
0, 1, 2, 4,
5, 6, 8, 9,
10, 11, 12, 13,
14
};
/* this order must match reg bit amp_div_ch1/2 */
static const char * const mt8186_sgen_amp_str[] = {
"1/128", "1/64", "1/32", "1/16", "1/8", "1/4", "1/2", "1" };
static int mt8186_sgen_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->sgen_mode;
return 0;
}
static int mt8186_sgen_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 mode;
int mode_idx;
if (ucontrol->value.enumerated.item[0] >= e->items)
return -EINVAL;
mode = ucontrol->value.integer.value[0];
mode_idx = mt8186_sgen_mode_idx[mode];
dev_dbg(afe->dev, "%s(), mode %d, mode_idx %d\n",
__func__, mode, mode_idx);
if (mode == afe_priv->sgen_mode)
return 0;
if (mode_idx >= 0) {
regmap_update_bits(afe->regmap, AFE_SINEGEN_CON2,
INNER_LOOP_BACK_MODE_MASK_SFT,
mode_idx << INNER_LOOP_BACK_MODE_SFT);
regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0,
DAC_EN_MASK_SFT, BIT(DAC_EN_SFT));
} else {
/* disable sgen */
regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0,
DAC_EN_MASK_SFT, 0);
regmap_update_bits(afe->regmap, AFE_SINEGEN_CON2,
INNER_LOOP_BACK_MODE_MASK_SFT,
0x3f << INNER_LOOP_BACK_MODE_SFT);
}
afe_priv->sgen_mode = mode;
return 1;
}
static int mt8186_sgen_rate_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->sgen_rate;
return 0;
}
static int mt8186_sgen_rate_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 rate;
if (ucontrol->value.enumerated.item[0] >= e->items)
return -EINVAL;
rate = ucontrol->value.integer.value[0];
dev_dbg(afe->dev, "%s(), rate %d\n", __func__, rate);
if (rate == afe_priv->sgen_rate)
return 0;
regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0,
SINE_MODE_CH1_MASK_SFT,
mt8186_sgen_rate_idx[rate] << SINE_MODE_CH1_SFT);
regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0,
SINE_MODE_CH2_MASK_SFT,
mt8186_sgen_rate_idx[rate] << SINE_MODE_CH2_SFT);
afe_priv->sgen_rate = rate;
return 1;
}
static int mt8186_sgen_amplitude_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->sgen_amplitude;
return 0;
}
static int mt8186_sgen_amplitude_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 amplitude;
if (ucontrol->value.enumerated.item[0] >= e->items)
return -EINVAL;
amplitude = ucontrol->value.integer.value[0];
if (amplitude > AMP_DIV_CH1_MASK) {
dev_err(afe->dev, "%s(), amplitude %d invalid\n",
__func__, amplitude);
return -EINVAL;
}
dev_dbg(afe->dev, "%s(), amplitude %d\n", __func__, amplitude);
if (amplitude == afe_priv->sgen_amplitude)
return 0;
regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0,
AMP_DIV_CH1_MASK_SFT,
amplitude << AMP_DIV_CH1_SFT);
regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0,
AMP_DIV_CH2_MASK_SFT,
amplitude << AMP_DIV_CH2_SFT);
afe_priv->sgen_amplitude = amplitude;
return 1;
}
static const struct soc_enum mt8186_afe_sgen_enum[] = {
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8186_sgen_mode_str),
mt8186_sgen_mode_str),
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8186_sgen_rate_str),
mt8186_sgen_rate_str),
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8186_sgen_amp_str),
mt8186_sgen_amp_str),
};
static const struct snd_kcontrol_new mt8186_afe_sgen_controls[] = {
SOC_ENUM_EXT("Audio_SineGen_Switch", mt8186_afe_sgen_enum[0],
mt8186_sgen_get, mt8186_sgen_set),
SOC_ENUM_EXT("Audio_SineGen_SampleRate", mt8186_afe_sgen_enum[1],
mt8186_sgen_rate_get, mt8186_sgen_rate_set),
SOC_ENUM_EXT("Audio_SineGen_Amplitude", mt8186_afe_sgen_enum[2],
mt8186_sgen_amplitude_get, mt8186_sgen_amplitude_set),
SOC_SINGLE("Audio_SineGen_Mute_Ch1", AFE_SINEGEN_CON0,
MUTE_SW_CH1_MASK_SFT, MUTE_SW_CH1_MASK, 0),
SOC_SINGLE("Audio_SineGen_Mute_Ch2", AFE_SINEGEN_CON0,
MUTE_SW_CH2_MASK_SFT, MUTE_SW_CH2_MASK, 0),
SOC_SINGLE("Audio_SineGen_Freq_Div_Ch1", AFE_SINEGEN_CON0,
FREQ_DIV_CH1_SFT, FREQ_DIV_CH1_MASK, 0),
SOC_SINGLE("Audio_SineGen_Freq_Div_Ch2", AFE_SINEGEN_CON0,
FREQ_DIV_CH2_SFT, FREQ_DIV_CH2_MASK, 0),
};
int mt8186_add_misc_control(struct snd_soc_component *component)
{
snd_soc_add_component_controls(component,
mt8186_afe_sgen_controls,
ARRAY_SIZE(mt8186_afe_sgen_controls));
return 0;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу