Commit 28223889 authored by Mark Brown's avatar Mark Brown

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.
parents a8b1b9ce 8208dd75
......@@ -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 @@ static int sof_card_dai_links_create(struct device *dev,
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
......
// 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);
This diff is collapsed.
/* 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
// 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;
}
/* 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
// 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);
}
}
/* 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
/* 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
This diff is collapsed.
// 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;
}
// 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;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* 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
// 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;
}
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment