Commit 9f08dcbd authored by Trevor Wu's avatar Trevor Wu Committed by Mark Brown

ASoC: mediatek: mt8188-mt6359: support new board with nau88255

This patch adds multiple i2s codecs support including NAU88L25,
MAX98390, and the dumb amp like NAU8318 usage. In addition, dmic-codec
is also added to skip the beginning pop noise.
Signed-off-by: default avatarTrevor Wu <trevor.wu@mediatek.com>
Link: https://lore.kernel.org/r/20230526093150.22923-7-trevor.wu@mediatek.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 8ad13cdc
...@@ -225,6 +225,10 @@ config SND_SOC_MT8188_MT6359 ...@@ -225,6 +225,10 @@ config SND_SOC_MT8188_MT6359
depends on SND_SOC_MT8188 && MTK_PMIC_WRAP depends on SND_SOC_MT8188 && MTK_PMIC_WRAP
select SND_SOC_MT6359 select SND_SOC_MT6359
select SND_SOC_HDMI_CODEC select SND_SOC_HDMI_CODEC
select SND_SOC_DMIC
select SND_SOC_MAX98390
select SND_SOC_NAU8315
select SND_SOC_NAU8825
help help
This adds support for ASoC machine driver for MediaTek MT8188 This adds support for ASoC machine driver for MediaTek MT8188
boards with the MT6359 and other I2S audio codecs. boards with the MT6359 and other I2S audio codecs.
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
* Author: Trevor Wu <trevor.wu@mediatek.com> * Author: Trevor Wu <trevor.wu@mediatek.com>
*/ */
#include <linux/input.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
...@@ -13,10 +14,27 @@ ...@@ -13,10 +14,27 @@
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include <sound/soc.h> #include <sound/soc.h>
#include "mt8188-afe-common.h" #include "mt8188-afe-common.h"
#include "../../codecs/nau8825.h"
#include "../../codecs/mt6359.h" #include "../../codecs/mt6359.h"
#include "../common/mtk-afe-platform-driver.h" #include "../common/mtk-afe-platform-driver.h"
#include "../common/mtk-soundcard-driver.h" #include "../common/mtk-soundcard-driver.h"
#define NAU8825_HS_PRESENT BIT(0)
/*
* Maxim MAX98390
*/
#define MAX98390_CODEC_DAI "max98390-aif1"
#define MAX98390_DEV0_NAME "max98390.0-0038" /* rear right */
#define MAX98390_DEV1_NAME "max98390.0-0039" /* rear left */
#define MAX98390_DEV2_NAME "max98390.0-003a" /* front right */
#define MAX98390_DEV3_NAME "max98390.0-003b" /* front left */
/*
* Nau88l25
*/
#define NAU8825_CODEC_DAI "nau8825-hifi"
/* FE */ /* FE */
SND_SOC_DAILINK_DEFS(playback2, SND_SOC_DAILINK_DEFS(playback2,
DAILINK_COMP_ARRAY(COMP_CPU("DL2")), DAILINK_COMP_ARRAY(COMP_CPU("DL2")),
...@@ -143,12 +161,16 @@ SND_SOC_DAILINK_DEFS(pcm1, ...@@ -143,12 +161,16 @@ SND_SOC_DAILINK_DEFS(pcm1,
SND_SOC_DAILINK_DEFS(ul_src, SND_SOC_DAILINK_DEFS(ul_src,
DAILINK_COMP_ARRAY(COMP_CPU("UL_SRC")), DAILINK_COMP_ARRAY(COMP_CPU("UL_SRC")),
DAILINK_COMP_ARRAY(COMP_CODEC("mt6359-sound", DAILINK_COMP_ARRAY(COMP_CODEC("mt6359-sound",
"mt6359-snd-codec-aif1")), "mt6359-snd-codec-aif1"),
COMP_CODEC("dmic-codec",
"dmic-hifi")),
DAILINK_COMP_ARRAY(COMP_EMPTY())); DAILINK_COMP_ARRAY(COMP_EMPTY()));
struct mt8188_mt6359_priv { struct mt8188_mt6359_priv {
struct snd_soc_jack dp_jack; struct snd_soc_jack dp_jack;
struct snd_soc_jack hdmi_jack; struct snd_soc_jack hdmi_jack;
struct snd_soc_jack headset_jack;
void *private_data;
}; };
static struct snd_soc_jack_pin mt8188_hdmi_jack_pins[] = { static struct snd_soc_jack_pin mt8188_hdmi_jack_pins[] = {
...@@ -165,11 +187,50 @@ static struct snd_soc_jack_pin mt8188_dp_jack_pins[] = { ...@@ -165,11 +187,50 @@ static struct snd_soc_jack_pin mt8188_dp_jack_pins[] = {
}, },
}; };
static struct snd_soc_jack_pin nau8825_jack_pins[] = {
{
.pin = "Headphone Jack",
.mask = SND_JACK_HEADPHONE,
},
{
.pin = "Headset Mic",
.mask = SND_JACK_MICROPHONE,
},
};
struct mt8188_card_data { struct mt8188_card_data {
const char *name; const char *name;
unsigned long quirk; unsigned long quirk;
}; };
static const struct snd_kcontrol_new mt8188_dumb_spk_controls[] = {
SOC_DAPM_PIN_SWITCH("Ext Spk"),
};
static const struct snd_soc_dapm_widget mt8188_dumb_spk_widgets[] = {
SND_SOC_DAPM_SPK("Ext Spk", NULL),
};
static const struct snd_kcontrol_new mt8188_dual_spk_controls[] = {
SOC_DAPM_PIN_SWITCH("Left Spk"),
SOC_DAPM_PIN_SWITCH("Right Spk"),
};
static const struct snd_soc_dapm_widget mt8188_dual_spk_widgets[] = {
SND_SOC_DAPM_SPK("Left Spk", NULL),
SND_SOC_DAPM_SPK("Right Spk", NULL),
};
static const struct snd_kcontrol_new mt8188_rear_spk_controls[] = {
SOC_DAPM_PIN_SWITCH("Rear Left Spk"),
SOC_DAPM_PIN_SWITCH("Rear Right Spk"),
};
static const struct snd_soc_dapm_widget mt8188_rear_spk_widgets[] = {
SND_SOC_DAPM_SPK("Rear Left Spk", NULL),
SND_SOC_DAPM_SPK("Rear Right Spk", NULL),
};
static const struct snd_soc_dapm_widget mt8188_mt6359_widgets[] = { static const struct snd_soc_dapm_widget mt8188_mt6359_widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL),
...@@ -182,6 +243,14 @@ static const struct snd_kcontrol_new mt8188_mt6359_controls[] = { ...@@ -182,6 +243,14 @@ static const struct snd_kcontrol_new mt8188_mt6359_controls[] = {
SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Headset Mic"),
}; };
static const struct snd_soc_dapm_widget mt8188_nau8825_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
};
static const struct snd_kcontrol_new mt8188_nau8825_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
};
#define CKSYS_AUD_TOP_CFG 0x032c #define CKSYS_AUD_TOP_CFG 0x032c
#define CKSYS_AUD_TOP_MON 0x0330 #define CKSYS_AUD_TOP_MON 0x0330
...@@ -451,6 +520,189 @@ static int mt8188_dptx_codec_init(struct snd_soc_pcm_runtime *rtd) ...@@ -451,6 +520,189 @@ static int mt8188_dptx_codec_init(struct snd_soc_pcm_runtime *rtd)
return ret; return ret;
} }
static int mt8188_dumb_amp_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
int ret = 0;
ret = snd_soc_dapm_new_controls(&card->dapm, mt8188_dumb_spk_widgets,
ARRAY_SIZE(mt8188_dumb_spk_widgets));
if (ret) {
dev_err(rtd->dev, "unable to add Dumb Speaker dapm, ret %d\n", ret);
return ret;
}
ret = snd_soc_add_card_controls(card, mt8188_dumb_spk_controls,
ARRAY_SIZE(mt8188_dumb_spk_controls));
if (ret) {
dev_err(rtd->dev, "unable to add Dumb card controls, ret %d\n", ret);
return ret;
}
return ret;
}
static int mt8188_max98390_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
unsigned int bit_width = params_width(params);
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct snd_soc_dai *codec_dai;
int i;
snd_soc_dai_set_tdm_slot(cpu_dai, 0xf, 0xf, 4, bit_width);
for_each_rtd_codec_dais(rtd, i, codec_dai) {
if (!strcmp(codec_dai->component->name, MAX98390_DEV0_NAME))
snd_soc_dai_set_tdm_slot(codec_dai, 0x8, 0x3, 4, bit_width);
if (!strcmp(codec_dai->component->name, MAX98390_DEV1_NAME))
snd_soc_dai_set_tdm_slot(codec_dai, 0x4, 0x3, 4, bit_width);
if (!strcmp(codec_dai->component->name, MAX98390_DEV2_NAME))
snd_soc_dai_set_tdm_slot(codec_dai, 0x2, 0x3, 4, bit_width);
if (!strcmp(codec_dai->component->name, MAX98390_DEV3_NAME))
snd_soc_dai_set_tdm_slot(codec_dai, 0x1, 0x3, 4, bit_width);
}
return 0;
}
static const struct snd_soc_ops mt8188_max98390_ops = {
.hw_params = mt8188_max98390_hw_params,
};
static int mt8188_max98390_codec_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
int ret;
/* add regular speakers dapm route */
ret = snd_soc_dapm_new_controls(&card->dapm, mt8188_dual_spk_widgets,
ARRAY_SIZE(mt8188_dual_spk_widgets));
if (ret) {
dev_err(rtd->dev, "unable to add Left/Right Speaker widget, ret %d\n", ret);
return ret;
}
ret = snd_soc_add_card_controls(card, mt8188_dual_spk_controls,
ARRAY_SIZE(mt8188_dual_spk_controls));
if (ret) {
dev_err(rtd->dev, "unable to add Left/Right card controls, ret %d\n", ret);
return ret;
}
if (rtd->dai_link->num_codecs <= 2)
return ret;
/* add widgets/controls/dapm for rear speakers */
ret = snd_soc_dapm_new_controls(&card->dapm, mt8188_rear_spk_widgets,
ARRAY_SIZE(mt8188_rear_spk_widgets));
if (ret) {
dev_err(rtd->dev, "unable to add Rear Speaker widget, ret %d\n", ret);
/* Don't need to add routes if widget addition failed */
return ret;
}
ret = snd_soc_add_card_controls(card, mt8188_rear_spk_controls,
ARRAY_SIZE(mt8188_rear_spk_controls));
if (ret) {
dev_err(rtd->dev, "unable to add Rear card controls, ret %d\n", ret);
return ret;
}
return ret;
}
static int mt8188_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
struct mt8188_mt6359_priv *priv = snd_soc_card_get_drvdata(card);
struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
struct snd_soc_jack *jack = &priv->headset_jack;
int ret;
ret = snd_soc_dapm_new_controls(&card->dapm, mt8188_nau8825_widgets,
ARRAY_SIZE(mt8188_nau8825_widgets));
if (ret) {
dev_err(rtd->dev, "unable to add nau8825 card widget, ret %d\n", ret);
return ret;
}
ret = snd_soc_add_card_controls(card, mt8188_nau8825_controls,
ARRAY_SIZE(mt8188_nau8825_controls));
if (ret) {
dev_err(rtd->dev, "unable to add nau8825 card controls, ret %d\n", ret);
return ret;
}
ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_BTN_0 |
SND_JACK_BTN_1 | SND_JACK_BTN_2 |
SND_JACK_BTN_3,
jack,
nau8825_jack_pins,
ARRAY_SIZE(nau8825_jack_pins));
if (ret) {
dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
return ret;
}
snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
ret = snd_soc_component_set_jack(component, jack, NULL);
if (ret) {
dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
return ret;
}
return ret;
};
static void mt8188_nau8825_codec_exit(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
snd_soc_component_set_jack(component, NULL, NULL);
}
static int mt8188_nau8825_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
unsigned int rate = params_rate(params);
unsigned int bit_width = params_width(params);
int clk_freq, ret;
clk_freq = rate * 2 * bit_width;
/* Configure clock for codec */
ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_BLK, 0,
SND_SOC_CLOCK_IN);
if (ret < 0) {
dev_err(codec_dai->dev, "can't set BCLK clock %d\n", ret);
return ret;
}
/* Configure pll for codec */
ret = snd_soc_dai_set_pll(codec_dai, 0, 0, clk_freq,
params_rate(params) * 256);
if (ret < 0) {
dev_err(codec_dai->dev, "can't set BCLK: %d\n", ret);
return ret;
}
return ret;
}
static const struct snd_soc_ops mt8188_nau8825_ops = {
.hw_params = mt8188_nau8825_hw_params,
};
static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
/* FE */ /* FE */
[DAI_LINK_DL2_FE] = { [DAI_LINK_DL2_FE] = {
...@@ -708,6 +960,40 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { ...@@ -708,6 +960,40 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
}, },
}; };
static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
{
struct snd_ctl_elem_id sid;
memset(&sid, 0, sizeof(sid));
strcpy(sid.name, name);
sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
return snd_ctl_find_id(card, &sid);
}
static void mt8188_fixup_controls(struct snd_soc_card *card)
{
struct mt8188_mt6359_priv *priv = snd_soc_card_get_drvdata(card);
struct mt8188_card_data *card_data = (struct mt8188_card_data *)priv->private_data;
struct snd_kcontrol *kctl;
if (card_data->quirk & NAU8825_HS_PRESENT) {
struct snd_soc_dapm_widget *w, *next_w;
for_each_card_widgets_safe(card, w, next_w) {
if (strcmp(w->name, "Headphone"))
continue;
snd_soc_dapm_free_widget(w);
}
kctl = ctl_find(card->snd_card, "Headphone Switch");
if (kctl)
snd_ctl_remove(card->snd_card, kctl);
else
dev_warn(card->dev, "Cannot find ctl : Headphone Switch\n");
}
}
static struct snd_soc_card mt8188_mt6359_soc_card = { static struct snd_soc_card mt8188_mt6359_soc_card = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.dai_link = mt8188_mt6359_dai_links, .dai_link = mt8188_mt6359_dai_links,
...@@ -716,6 +1002,7 @@ static struct snd_soc_card mt8188_mt6359_soc_card = { ...@@ -716,6 +1002,7 @@ static struct snd_soc_card mt8188_mt6359_soc_card = {
.num_dapm_widgets = ARRAY_SIZE(mt8188_mt6359_widgets), .num_dapm_widgets = ARRAY_SIZE(mt8188_mt6359_widgets),
.controls = mt8188_mt6359_controls, .controls = mt8188_mt6359_controls,
.num_controls = ARRAY_SIZE(mt8188_mt6359_controls), .num_controls = ARRAY_SIZE(mt8188_mt6359_controls),
.fixup_controls = mt8188_fixup_controls,
}; };
static int mt8188_mt6359_dev_probe(struct platform_device *pdev) static int mt8188_mt6359_dev_probe(struct platform_device *pdev)
...@@ -726,6 +1013,9 @@ static int mt8188_mt6359_dev_probe(struct platform_device *pdev) ...@@ -726,6 +1013,9 @@ static int mt8188_mt6359_dev_probe(struct platform_device *pdev)
struct mt8188_card_data *card_data; struct mt8188_card_data *card_data;
struct snd_soc_dai_link *dai_link; struct snd_soc_dai_link *dai_link;
bool init_mt6359 = false; bool init_mt6359 = false;
bool init_nau8825 = false;
bool init_max98390 = false;
bool init_dumb = false;
int ret, i; int ret, i;
card_data = (struct mt8188_card_data *)of_device_get_match_data(&pdev->dev); card_data = (struct mt8188_card_data *)of_device_get_match_data(&pdev->dev);
...@@ -776,9 +1066,35 @@ static int mt8188_mt6359_dev_probe(struct platform_device *pdev) ...@@ -776,9 +1066,35 @@ static int mt8188_mt6359_dev_probe(struct platform_device *pdev)
dai_link->init = mt8188_mt6359_init; dai_link->init = mt8188_mt6359_init;
init_mt6359 = true; init_mt6359 = true;
} }
} else if (strcmp(dai_link->name, "ETDM1_OUT_BE") == 0 ||
strcmp(dai_link->name, "ETDM2_OUT_BE") == 0 ||
strcmp(dai_link->name, "ETDM1_IN_BE") == 0 ||
strcmp(dai_link->name, "ETDM2_IN_BE") == 0) {
if (!strcmp(dai_link->codecs->dai_name, MAX98390_CODEC_DAI)) {
dai_link->ops = &mt8188_max98390_ops;
if (!init_max98390) {
dai_link->init = mt8188_max98390_codec_init;
init_max98390 = true;
}
} else if (!strcmp(dai_link->codecs->dai_name, NAU8825_CODEC_DAI)) {
dai_link->ops = &mt8188_nau8825_ops;
if (!init_nau8825) {
dai_link->init = mt8188_nau8825_codec_init;
dai_link->exit = mt8188_nau8825_codec_exit;
init_nau8825 = true;
}
} else {
if (strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) {
if (!init_dumb) {
dai_link->init = mt8188_dumb_amp_init;
init_dumb = true;
}
}
}
} }
} }
priv->private_data = card_data;
snd_soc_card_set_drvdata(card, priv); snd_soc_card_set_drvdata(card, priv);
ret = devm_snd_soc_register_card(&pdev->dev, card); ret = devm_snd_soc_register_card(&pdev->dev, card);
...@@ -795,11 +1111,20 @@ static struct mt8188_card_data mt8188_evb_card = { ...@@ -795,11 +1111,20 @@ static struct mt8188_card_data mt8188_evb_card = {
.name = "mt8188_mt6359", .name = "mt8188_mt6359",
}; };
static struct mt8188_card_data mt8188_nau8825_card = {
.name = "mt8188_nau8825",
.quirk = NAU8825_HS_PRESENT,
};
static const struct of_device_id mt8188_mt6359_dt_match[] = { static const struct of_device_id mt8188_mt6359_dt_match[] = {
{ {
.compatible = "mediatek,mt8188-mt6359-evb", .compatible = "mediatek,mt8188-mt6359-evb",
.data = &mt8188_evb_card, .data = &mt8188_evb_card,
}, },
{
.compatible = "mediatek,mt8188-nau8825",
.data = &mt8188_nau8825_card,
},
{}, {},
}; };
MODULE_DEVICE_TABLE(of, mt8188_mt6359_dt_match); MODULE_DEVICE_TABLE(of, mt8188_mt6359_dt_match);
......
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