From nobody Sat Oct 4 00:32:11 2025 Received: from mailgw01.mediatek.com (unknown [60.244.123.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A19E42FF15F; Fri, 22 Aug 2025 12:53:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=60.244.123.138 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755867238; cv=none; b=gCJCsDAwm3HArfAew2j1Skqj3CF61/cRdinppWBKBKXe2coGEGQ5e+nRLg8JeHdjkeIkP25+y348NCPLnJ1uW72SfBFW+KnxIDfjlTtrn9imNvfqzSe6wfOS/0tKzvJPT4KLXqeoD5HNxNo6Kp4lQBMrj0ZPbhVQWnDGWGW9NHw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755867238; c=relaxed/simple; bh=itsWIoV9aQ/2HAQL84EdXKr1JTRX3s01C/0iPtrNUbw=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=P8uVUQxEaKbGpGFhgPWsBpP2YXgb+3waNKNH24l7OJkh8AJT+vnikG1zEZjo5Q1OCWLtmmlnIgxaucCh+8R+C5ddcWdvNgV/q6TOOQvGB30bdDoAN4fUFXNM0H5UZaWOt49ol3Z+ocRhj6hGCvZL9oC8+t1yvD1ukWENGNosNnw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=SylXc/jx; arc=none smtp.client-ip=60.244.123.138 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="SylXc/jx" X-UUID: 0c82b8a47f5711f08729452bf625a8b4-20250822 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=e7uyxXfVTQcNb2/a0bA71NPXNGG4e9FHIdmke8w19dQ=; b=SylXc/jxy7KjATA2486Kg6mPGI+cf7J5eBiNFU5f2vigsoPwf6+6T79VBCV+w1tP30ADGnk1CKO7kCT8WDYLupN9OvjjP7n7fe3fuBvBuNqYr0lAXYyV8f83wGh2VPsZsm+2Ibv+43umsITCOaOJrq9sUCxNwjpQWw/Eo0Of6uY=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.3.3,REQID:1ab07292-ff30-4786-bde0-13aa3c82d2ee,IP:0,UR L:0,TC:0,Content:-5,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION: release,TS:-5 X-CID-META: VersionHash:f1326cf,CLOUDID:88f7c344-18c5-4075-a135-4c0afe29f9d6,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:-5,Content:0|15|50,EDM: -3,IP:nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0, AV:0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 2,SSN|SDN X-CID-BAS: 2,SSN|SDN,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-CID-RHF: D41D8CD98F00B204E9800998ECF8427E X-UUID: 0c82b8a47f5711f08729452bf625a8b4-20250822 Received: from mtkmbs13n2.mediatek.inc [(172.21.101.108)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 963380716; Fri, 22 Aug 2025 20:53:49 +0800 Received: from mtkmbs11n2.mediatek.inc (172.21.101.187) by mtkmbs13n2.mediatek.inc (172.21.101.108) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.39; Fri, 22 Aug 2025 20:53:47 +0800 Received: from mhfsdcap04.gcn.mediatek.inc (10.17.3.154) by mtkmbs11n2.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1258.39 via Frontend Transport; Fri, 22 Aug 2025 20:53:46 +0800 From: Darren.Ye To: Liam Girdwood , Mark Brown , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Matthias Brugger , AngeloGioacchino Del Regno , Jaroslav Kysela , Takashi Iwai , Linus Walleij , Bartosz Golaszewski CC: , , , , , , Darren Ye Subject: [PATCH v7 09/10] ASoC: mediatek: mt8196: add machine driver with nau8825 Date: Fri, 22 Aug 2025 20:52:38 +0800 Message-ID: <20250822125301.12333-10-darren.ye@mediatek.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20250822125301.12333-1-darren.ye@mediatek.com> References: <20250822125301.12333-1-darren.ye@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-MTK: N Content-Type: text/plain; charset="utf-8" From: Darren Ye Add support for mt8196 board with nau8825. Signed-off-by: Darren Ye --- sound/soc/mediatek/Kconfig | 20 + sound/soc/mediatek/mt8196/Makefile | 2 + sound/soc/mediatek/mt8196/mt8196-nau8825.c | 868 +++++++++++++++++++++ 3 files changed, 890 insertions(+) create mode 100644 sound/soc/mediatek/mt8196/mt8196-nau8825.c diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 7003d71b847c..2889600652a0 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -332,4 +332,24 @@ config SND_SOC_MT8196 Select Y if you have such device. If unsure select "N". =20 +config SND_SOC_MT8196_NAU8825 + tristate "ASoc Audio driver for MT8196 with NAU8825 and I2S codec" + depends on SND_SOC_MT8196 + depends on I2C + select SND_SOC_HDMI_CODEC + select SND_SOC_DMIC + select SND_SOC_NAU8315 + select SND_SOC_NAU8825 + select SND_SOC_RT5645 + select SND_SOC_RT5682_I2C + select SND_SOC_RT5682S + select SND_SOC_TAS2781_COMLIB + select SND_SOC_TAS2781_FMWLIB + select SND_SOC_TAS2781_I2C + help + This adds support for ASoC machine driver for MediaTek MT8196 + boards with the NAU8825 and other I2S audio codecs. + Select Y if you have such device. + If unsure select "N". + endmenu diff --git a/sound/soc/mediatek/mt8196/Makefile b/sound/soc/mediatek/mt8196= /Makefile index 0c6a018190a2..91de200071d7 100644 --- a/sound/soc/mediatek/mt8196/Makefile +++ b/sound/soc/mediatek/mt8196/Makefile @@ -10,3 +10,5 @@ snd-soc-mt8196-afe-objs +=3D \ =20 obj-$(CONFIG_SND_SOC_MT8196) +=3D snd-soc-mt8196-afe.o =20 +# machine driver +obj-$(CONFIG_SND_SOC_MT8196_NAU8825) +=3D mt8196-nau8825.o diff --git a/sound/soc/mediatek/mt8196/mt8196-nau8825.c b/sound/soc/mediate= k/mt8196/mt8196-nau8825.c new file mode 100644 index 000000000000..e6184c36415e --- /dev/null +++ b/sound/soc/mediatek/mt8196/mt8196-nau8825.c @@ -0,0 +1,868 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * mt8196-nau8825.c -- mt8196 nau8825 ALSA SoC machine driver + * + * Copyright (c) 2025 MediaTek Inc. + * Author: Darren Ye + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "mt8196-afe-common.h" + +#include "../../codecs/nau8825.h" +#include "../../codecs/rt5682s.h" + +#include "../common/mtk-soc-card.h" +#include "../common/mtk-dsp-sof-common.h" +#include "../common/mtk-soundcard-driver.h" +#include "../common/mtk-afe-platform-driver.h" + +#define NAU8825_HS_PRESENT BIT(0) +#define RT5682S_HS_PRESENT BIT(1) +#define RT5650_HS_PRESENT BIT(2) + +/* + * Nau88l25 + */ +#define NAU8825_CODEC_DAI "nau8825-hifi" + +/* + * Rt5682s + */ +#define RT5682S_CODEC_DAI "rt5682s-aif1" + +/* + * Rt5650 + */ +#define RT5650_CODEC_DAI "rt5645-aif1" + +#define SOF_DMA_DL1 "SOF_DMA_DL1" +#define SOF_DMA_DL_24CH "SOF_DMA_DL_24CH" +#define SOF_DMA_UL0 "SOF_DMA_UL0" +#define SOF_DMA_UL1 "SOF_DMA_UL1" +#define SOF_DMA_UL2 "SOF_DMA_UL2" + +enum mt8196_jacks { + MT8196_JACK_HEADSET, + MT8196_JACK_DP, + MT8196_JACK_HDMI, + MT8196_JACK_MAX, +}; + +static struct snd_soc_jack_pin mt8196_dp_jack_pins[] =3D { + { + .pin =3D "DP", + .mask =3D SND_JACK_AVOUT, + }, +}; + +static struct snd_soc_jack_pin mt8196_hdmi_jack_pins[] =3D { + { + .pin =3D "HDMI", + .mask =3D SND_JACK_AVOUT, + }, +}; + +static struct snd_soc_jack_pin nau8825_jack_pins[] =3D { + { + .pin =3D "Headphone Jack", + .mask =3D SND_JACK_HEADPHONE, + }, + { + .pin =3D "Headset Mic", + .mask =3D SND_JACK_MICROPHONE, + }, +}; + +static const struct snd_kcontrol_new mt8196_dumb_spk_controls[] =3D { + SOC_DAPM_PIN_SWITCH("Ext Spk"), +}; + +static const struct snd_soc_dapm_widget mt8196_dumb_spk_widgets[] =3D { + SND_SOC_DAPM_SPK("Ext Spk", NULL), +}; + +static const struct snd_soc_dapm_widget mt8196_nau8825_widgets[] =3D { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_SPK("Ext Spk", NULL), + SND_SOC_DAPM_SINK("DP"), +}; + +static const struct snd_kcontrol_new mt8196_nau8825_controls[] =3D { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +#define EXT_SPK_AMP_W_NAME "Ext_Speaker_Amp" + +static struct snd_soc_card mt8196_nau8825_soc_card; + +static const struct snd_soc_dapm_widget mt8196_nau8825_card_widgets[] =3D { + /* SOF Uplink */ + SND_SOC_DAPM_MIXER("SOF_DMA_UL0", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SOF_DMA_UL1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SOF_DMA_UL2", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* + * SOF Downlink + * the widgets on the machine driver cannot use the parameter with kcontr= ol + * because the widget domain is its platform driver. so sof downlink route + * is written in the i2s dai driver. + */ +}; + +static const struct snd_soc_dapm_route mt8196_nau8825_card_routes[] =3D { + /* SOF Uplink */ + {"SOF_DMA_UL0", NULL, "UL0_CH1"}, + {"SOF_DMA_UL0", NULL, "UL0_CH2"}, + /* SOF Uplink */ + {"SOF_DMA_UL1", NULL, "UL1_CH1"}, + {"SOF_DMA_UL1", NULL, "UL1_CH2"}, + /* SOF Uplink */ + {"SOF_DMA_UL2", NULL, "UL2_CH1"}, + {"SOF_DMA_UL2", NULL, "UL2_CH2"}, +}; + +static const struct snd_kcontrol_new mt8196_nau8825_card_controls[] =3D { + SOC_DAPM_PIN_SWITCH(EXT_SPK_AMP_W_NAME), +}; + +/* + * define mtk_spk_i2s_mck node in dts when need mclk, + * BE i2s need assign snd_soc_ops =3D mt8196_nau8825_i2s_ops + */ +static int mt8196_nau8825_i2s_hw_params(struct snd_pcm_substream *substrea= m, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd =3D substream->private_data; + unsigned int rate =3D params_rate(params); + unsigned int mclk_fs_ratio =3D 128; + unsigned int mclk_fs =3D rate * mclk_fs_ratio; + struct snd_soc_dai *cpu_dai =3D snd_soc_rtd_to_cpu(rtd, 0); + + return snd_soc_dai_set_sysclk(cpu_dai, + 0, mclk_fs, SND_SOC_CLOCK_OUT); +} + +static const struct snd_soc_ops mt8196_nau8825_i2s_ops =3D { + .hw_params =3D mt8196_nau8825_i2s_hw_params, +}; + +static int mt8196_dptx_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd =3D substream->private_data; + unsigned int rate =3D params_rate(params); + unsigned int mclk_fs_ratio =3D 256; + unsigned int mclk_fs =3D rate * mclk_fs_ratio; + struct snd_soc_dai *dai =3D snd_soc_rtd_to_cpu(rtd, 0); + + return snd_soc_dai_set_sysclk(dai, 0, mclk_fs, SND_SOC_CLOCK_OUT); +} + +static const struct snd_soc_ops mt8196_dptx_ops =3D { + .hw_params =3D mt8196_dptx_hw_params, +}; + +static int mt8196_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + dev_info(rtd->dev, "fix format to 32bit\n"); + + /* fix BE i2s format to 32bit, clean param mask first */ + snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), + 0, SNDRV_PCM_FORMAT_LAST); + + params_set_format(params, SNDRV_PCM_FORMAT_S32_LE); + return 0; +} + +static int mt8196_sof_be_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd =3D snd_soc_substream_to_rtd(substream); + struct snd_soc_component *cmpnt_afe =3D NULL; + struct snd_soc_pcm_runtime *runtime; + + /* find afe component */ + for_each_card_rtds(rtd->card, runtime) { + cmpnt_afe =3D snd_soc_rtdcom_lookup(runtime, AFE_PCM_NAME); + if (cmpnt_afe) { + dev_info(rtd->dev, "component->name: %s\n", cmpnt_afe->name); + break; + } + } + + if (cmpnt_afe && !pm_runtime_active(cmpnt_afe->dev)) { + dev_err(rtd->dev, "afe pm runtime is not active!!\n"); + return -EINVAL; + } + + return 0; +} + +static const struct snd_soc_ops mt8196_sof_be_ops =3D { + .hw_params =3D mt8196_sof_be_hw_params, +}; + +static const struct sof_conn_stream g_sof_conn_streams[] =3D { + { + .sof_link =3D "AFE_SOF_DL1", + .sof_dma =3D SOF_DMA_DL1, + .stream_dir =3D SNDRV_PCM_STREAM_PLAYBACK + }, + { + .sof_link =3D "AFE_SOF_DL_24CH", + .sof_dma =3D SOF_DMA_DL_24CH, + .stream_dir =3D SNDRV_PCM_STREAM_PLAYBACK + }, + { + .sof_link =3D "AFE_SOF_UL0", + .sof_dma =3D SOF_DMA_UL0, + .stream_dir =3D SNDRV_PCM_STREAM_CAPTURE + }, + { + .sof_link =3D "AFE_SOF_UL1", + .sof_dma =3D SOF_DMA_UL1, + .stream_dir =3D SNDRV_PCM_STREAM_CAPTURE + }, + { + .sof_link =3D "AFE_SOF_UL2", + .sof_dma =3D SOF_DMA_UL2, + .stream_dir =3D SNDRV_PCM_STREAM_CAPTURE + }, +}; + +/* FE */ +SND_SOC_DAILINK_DEFS(playback1, + DAILINK_COMP_ARRAY(COMP_CPU("DL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(playback_24ch, + DAILINK_COMP_ARRAY(COMP_CPU("DL_24CH")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(capture0, + DAILINK_COMP_ARRAY(COMP_CPU("UL0")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(capture1, + DAILINK_COMP_ARRAY(COMP_CPU("UL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(capture2, + DAILINK_COMP_ARRAY(COMP_CPU("UL2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(playback_hdmi, + DAILINK_COMP_ARRAY(COMP_CPU("HDMI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(playback2, + DAILINK_COMP_ARRAY(COMP_CPU("DL2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(capture_cm0, + DAILINK_COMP_ARRAY(COMP_CPU("UL_CM0")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +/* BE */ +SND_SOC_DAILINK_DEFS(ap_dmic, + DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(ap_dmic_ch34, + DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC_CH34")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(ap_dmic_multich, + DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC_MULTICH")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(i2sin6, + DAILINK_COMP_ARRAY(COMP_CPU("I2SIN6")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(i2sout3, + DAILINK_COMP_ARRAY(COMP_CPU("I2SOUT3")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(i2sout4, + DAILINK_COMP_ARRAY(COMP_CPU("I2SOUT4")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(i2sout6, + DAILINK_COMP_ARRAY(COMP_CPU("I2SOUT6")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(tdm_dptx, + DAILINK_COMP_ARRAY(COMP_CPU("TDM_DPTX")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(AFE_SOF_DL_24CH, + DAILINK_COMP_ARRAY(COMP_CPU("SOF_DL_24CH")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(AFE_SOF_DL1, + DAILINK_COMP_ARRAY(COMP_CPU("SOF_DL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(AFE_SOF_UL0, + DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL0")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(AFE_SOF_UL1, + DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(AFE_SOF_UL2, + DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static struct snd_soc_dai_link mt8196_nau8825_dai_links[] =3D { + /* + * The SOF topology expects PCM streams 0~4 to be available + * for the SOF PCM streams. Put the SOF BE definitions here + * so that the PCM device numbers are skipped over. + * (BE dailinks do not have PCM devices created.) + */ + { + .name =3D "AFE_SOF_DL_24CH", + .no_pcm =3D 1, + .playback_only =3D 1, + .ops =3D &mt8196_sof_be_ops, + SND_SOC_DAILINK_REG(AFE_SOF_DL_24CH), + }, + { + .name =3D "AFE_SOF_DL1", + .no_pcm =3D 1, + .playback_only =3D 1, + .ops =3D &mt8196_sof_be_ops, + SND_SOC_DAILINK_REG(AFE_SOF_DL1), + }, + { + .name =3D "AFE_SOF_UL0", + .no_pcm =3D 1, + .capture_only =3D 1, + .ops =3D &mt8196_sof_be_ops, + SND_SOC_DAILINK_REG(AFE_SOF_UL0), + }, + { + .name =3D "AFE_SOF_UL1", + .no_pcm =3D 1, + .capture_only =3D 1, + .ops =3D &mt8196_sof_be_ops, + SND_SOC_DAILINK_REG(AFE_SOF_UL1), + }, + { + .name =3D "AFE_SOF_UL2", + .no_pcm =3D 1, + .capture_only =3D 1, + .ops =3D &mt8196_sof_be_ops, + SND_SOC_DAILINK_REG(AFE_SOF_UL2), + }, + /* Front End DAI links */ + { + .name =3D "HDMI_FE", + .stream_name =3D "HDMI Playback", + .trigger =3D {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic =3D 1, + .playback_only =3D 1, + SND_SOC_DAILINK_REG(playback_hdmi), + }, + { + .name =3D "DL2_FE", + .stream_name =3D "DL2 Playback", + .trigger =3D {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic =3D 1, + .playback_only =3D 1, + SND_SOC_DAILINK_REG(playback2), + }, + { + .name =3D "UL_CM0_FE", + .stream_name =3D "UL_CM0 Capture", + .trigger =3D {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic =3D 1, + .capture_only =3D 1, + SND_SOC_DAILINK_REG(capture_cm0), + }, + { + .name =3D "DL_24CH_FE", + .stream_name =3D "DL_24CH Playback", + .trigger =3D {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic =3D 1, + .playback_only =3D 1, + SND_SOC_DAILINK_REG(playback_24ch), + }, + { + .name =3D "DL1_FE", + .stream_name =3D "DL1 Playback", + .trigger =3D {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic =3D 1, + .playback_only =3D 1, + SND_SOC_DAILINK_REG(playback1), + }, + { + .name =3D "UL0_FE", + .stream_name =3D "UL0 Capture", + .trigger =3D {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic =3D 1, + .capture_only =3D 1, + SND_SOC_DAILINK_REG(capture0), + }, + { + .name =3D "UL1_FE", + .stream_name =3D "UL1 Capture", + .trigger =3D {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic =3D 1, + .capture_only =3D 1, + SND_SOC_DAILINK_REG(capture1), + }, + { + .name =3D "UL2_FE", + .stream_name =3D "UL2 Capture", + .trigger =3D {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic =3D 1, + .capture_only =3D 1, + SND_SOC_DAILINK_REG(capture2), + }, + /* Back End DAI links */ + { + .name =3D "I2SIN6_BE", + .dai_fmt =3D SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC + | SND_SOC_DAIFMT_GATED, + .ops =3D &mt8196_nau8825_i2s_ops, + .no_pcm =3D 1, + .capture_only =3D 1, + .ignore_suspend =3D 1, + .be_hw_params_fixup =3D mt8196_hw_params_fixup, + SND_SOC_DAILINK_REG(i2sin6), + }, + { + .name =3D "I2SOUT4_BE", + .dai_fmt =3D SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC + | SND_SOC_DAIFMT_GATED, + .ops =3D &mt8196_nau8825_i2s_ops, + .no_pcm =3D 1, + .playback_only =3D 1, + .ignore_suspend =3D 1, + .ignore_pmdown_time =3D 1, + .be_hw_params_fixup =3D mt8196_hw_params_fixup, + SND_SOC_DAILINK_REG(i2sout4), + }, + { + .name =3D "I2SOUT6_BE", + .dai_fmt =3D SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC + | SND_SOC_DAIFMT_GATED, + .ops =3D &mt8196_nau8825_i2s_ops, + .no_pcm =3D 1, + .playback_only =3D 1, + .ignore_suspend =3D 1, + .be_hw_params_fixup =3D mt8196_hw_params_fixup, + SND_SOC_DAILINK_REG(i2sout6), + }, + { + .name =3D "AP_DMIC_BE", + .no_pcm =3D 1, + .capture_only =3D 1, + .ignore_suspend =3D 1, + SND_SOC_DAILINK_REG(ap_dmic), + }, + { + .name =3D "AP_DMIC_CH34_BE", + .no_pcm =3D 1, + .capture_only =3D 1, + .ignore_suspend =3D 1, + SND_SOC_DAILINK_REG(ap_dmic_ch34), + }, + { + .name =3D "AP_DMIC_MULTICH_BE", + .no_pcm =3D 1, + .capture_only =3D 1, + .ignore_suspend =3D 1, + SND_SOC_DAILINK_REG(ap_dmic_multich), + }, + { + .name =3D "TDM_DPTX_BE", + .dai_fmt =3D SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC + | SND_SOC_DAIFMT_GATED, + .ops =3D &mt8196_dptx_ops, + .be_hw_params_fixup =3D mt8196_hw_params_fixup, + .no_pcm =3D 1, + .playback_only =3D 1, + .ignore_suspend =3D 1, + SND_SOC_DAILINK_REG(tdm_dptx), + }, + { + .name =3D "I2SOUT3_BE", + .dai_fmt =3D SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC + | SND_SOC_DAIFMT_GATED, + .ops =3D &mt8196_nau8825_i2s_ops, + .no_pcm =3D 1, + .playback_only =3D 1, + .ignore_suspend =3D 1, + SND_SOC_DAILINK_REG(i2sout3), + }, +}; + +static int mt8196_dumb_amp_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card =3D rtd->card; + int ret =3D 0; + + ret =3D snd_soc_dapm_new_controls(&card->dapm, mt8196_dumb_spk_widgets, + ARRAY_SIZE(mt8196_dumb_spk_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add Dumb Speaker dapm, ret %d\n", ret); + return ret; + } + + ret =3D snd_soc_add_card_controls(card, mt8196_dumb_spk_controls, + ARRAY_SIZE(mt8196_dumb_spk_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add Dumb card controls, ret %d\n", ret); + return ret; + } + + return 0; +} + +static int mt8196_dptx_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + struct mtk_soc_card_data *soc_card_data =3D snd_soc_card_get_drvdata(rtd-= >card); + struct snd_soc_jack *jack =3D &soc_card_data->card_data->jacks[MT8196_JAC= K_DP]; + struct snd_soc_component *component =3D snd_soc_rtd_to_codec(rtd, 0)->com= ponent; + int ret =3D 0; + + ret =3D snd_soc_card_jack_new_pins(rtd->card, "DP Jack", SND_JACK_AVOUT, + jack, mt8196_dp_jack_pins, + ARRAY_SIZE(mt8196_dp_jack_pins)); + if (ret) { + dev_err(rtd->dev, "new jack failed: %d\n", ret); + return ret; + } + + ret =3D snd_soc_component_set_jack(component, jack, NULL); + if (ret) { + dev_err(rtd->dev, "set jack failed on %s (ret=3D%d)\n", + component->name, ret); + return ret; + } + + return 0; +} + +static int mt8196_hdmi_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + struct mtk_soc_card_data *soc_card_data =3D snd_soc_card_get_drvdata(rtd-= >card); + struct snd_soc_jack *jack =3D &soc_card_data->card_data->jacks[MT8196_JAC= K_HDMI]; + struct snd_soc_component *component =3D snd_soc_rtd_to_codec(rtd, 0)->com= ponent; + int ret =3D 0; + + ret =3D snd_soc_card_jack_new_pins(rtd->card, "HDMI Jack", SND_JACK_AVOUT, + jack, mt8196_hdmi_jack_pins, + ARRAY_SIZE(mt8196_hdmi_jack_pins)); + if (ret) { + dev_err(rtd->dev, "new jack failed: %d\n", ret); + return ret; + } + + ret =3D snd_soc_component_set_jack(component, jack, NULL); + if (ret) { + dev_err(rtd->dev, "set jack failed on %s (ret=3D%d)\n", + component->name, ret); + return ret; + } + + return 0; +} + +static int mt8196_headset_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card =3D rtd->card; + struct mtk_soc_card_data *soc_card_data =3D snd_soc_card_get_drvdata(card= ); + struct snd_soc_jack *jack =3D &soc_card_data->card_data->jacks[MT8196_JAC= K_HEADSET]; + struct snd_soc_component *component =3D snd_soc_rtd_to_codec(rtd, 0)->com= ponent; + int ret; + int type; + + ret =3D snd_soc_dapm_new_controls(&card->dapm, mt8196_nau8825_widgets, + ARRAY_SIZE(mt8196_nau8825_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add nau8825 card widget, ret %d\n", ret); + return ret; + } + + ret =3D snd_soc_add_card_controls(card, mt8196_nau8825_controls, + ARRAY_SIZE(mt8196_nau8825_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add nau8825 card controls, ret %d\n", ret); + return ret; + } + + ret =3D 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); + + type =3D SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BT= N_2 | SND_JACK_BTN_3; + ret =3D snd_soc_component_set_jack(component, jack, (void *)&type); + + if (ret) { + dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); + return ret; + } + + return 0; +}; + +static void mt8196_headset_codec_exit(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *component =3D snd_soc_rtd_to_codec(rtd, 0)->com= ponent; + + snd_soc_component_set_jack(component, NULL, NULL); +} + +static int mt8196_nau8825_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd =3D snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai =3D snd_soc_rtd_to_codec(rtd, 0); + unsigned int rate =3D params_rate(params); + unsigned int bit_width =3D params_width(params); + int clk_freq, ret; + + clk_freq =3D rate * 2 * bit_width; + + /* Configure clock for codec */ + ret =3D 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 =3D 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 0; +} + +static const struct snd_soc_ops mt8196_nau8825_ops =3D { + .hw_params =3D mt8196_nau8825_hw_params, +}; + +static int mt8196_rt5682s_i2s_hw_params(struct snd_pcm_substream *substrea= m, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd =3D substream->private_data; + struct snd_soc_card *card =3D rtd->card; + struct snd_soc_dai *cpu_dai =3D snd_soc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *codec_dai =3D snd_soc_rtd_to_codec(rtd, 0); + unsigned int rate =3D params_rate(params); + int bitwidth; + int ret; + + bitwidth =3D snd_pcm_format_width(params_format(params)); + if (bitwidth < 0) { + dev_err(card->dev, "invalid bit width: %d\n", bitwidth); + return bitwidth; + } + + ret =3D snd_soc_dai_set_tdm_slot(codec_dai, 0x00, 0x0, 0x2, bitwidth); + if (ret) { + dev_err(card->dev, "failed to set tdm slot\n"); + return ret; + } + + ret =3D snd_soc_dai_set_pll(codec_dai, RT5682S_PLL1, RT5682S_PLL_S_BCLK1, + rate * 32, rate * 512); + if (ret) { + dev_err(card->dev, "failed to set pll\n"); + return ret; + } + + dev_info(card->dev, "%s set mclk rate: %d\n", __func__, rate * 512); + + ret =3D snd_soc_dai_set_sysclk(codec_dai, RT5682S_SCLK_S_MCLK, + rate * 512, SND_SOC_CLOCK_IN); + if (ret) { + dev_err(card->dev, "failed to set sysclk\n"); + return ret; + } + + return snd_soc_dai_set_sysclk(cpu_dai, 0, rate * 512, + SND_SOC_CLOCK_OUT); +} + +static const struct snd_soc_ops mt8196_rt5682s_i2s_ops =3D { + .hw_params =3D mt8196_rt5682s_i2s_hw_params, +}; + +static int mt8196_nau8825_soc_card_probe(struct mtk_soc_card_data *soc_car= d_data, bool legacy) +{ + struct snd_soc_card *card =3D soc_card_data->card_data->card; + struct snd_soc_dai_link *dai_link; + bool init_nau8825 =3D false; + bool init_rt5682s =3D false; + bool init_rt5650 =3D false; + bool init_dumb =3D false; + int i; + + dev_info(card->dev, "legacy: %d\n", legacy); + + for_each_card_prelinks(card, i, dai_link) { + if (strcmp(dai_link->name, "TDM_DPTX_BE") =3D=3D 0) { + if (dai_link->num_codecs && + strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) + dai_link->init =3D mt8196_dptx_codec_init; + } else if (strcmp(dai_link->name, "I2SOUT3_BE") =3D=3D 0) { + if (dai_link->num_codecs && + strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) + dai_link->init =3D mt8196_hdmi_codec_init; + } else if (strcmp(dai_link->name, "I2SOUT6_BE") =3D=3D 0 || + strcmp(dai_link->name, "I2SIN6_BE") =3D=3D 0) { + if (!strcmp(dai_link->codecs->dai_name, NAU8825_CODEC_DAI)) { + dai_link->ops =3D &mt8196_nau8825_ops; + if (!init_nau8825) { + dai_link->init =3D mt8196_headset_codec_init; + dai_link->exit =3D mt8196_headset_codec_exit; + init_nau8825 =3D true; + } + } else if (!strcmp(dai_link->codecs->dai_name, RT5682S_CODEC_DAI)) { + dai_link->ops =3D &mt8196_rt5682s_i2s_ops; + if (!init_rt5682s) { + dai_link->init =3D mt8196_headset_codec_init; + dai_link->exit =3D mt8196_headset_codec_exit; + init_rt5682s =3D true; + } + } else if (!strcmp(dai_link->codecs->dai_name, RT5650_CODEC_DAI)) { + dai_link->ops =3D &mt8196_rt5682s_i2s_ops; + if (!init_rt5650) { + dai_link->init =3D mt8196_headset_codec_init; + dai_link->exit =3D mt8196_headset_codec_exit; + init_rt5650 =3D true; + } + } else { + if (strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) { + if (!init_dumb) { + dai_link->init =3D mt8196_dumb_amp_init; + init_dumb =3D true; + } + } + } + } + } + + return 0; +} + +static const struct mtk_sof_priv mt8196_sof_priv =3D { + .conn_streams =3D g_sof_conn_streams, + .num_streams =3D ARRAY_SIZE(g_sof_conn_streams), +}; + +static struct snd_soc_card mt8196_nau8825_soc_card =3D { + .owner =3D THIS_MODULE, + .dai_link =3D mt8196_nau8825_dai_links, + .num_links =3D ARRAY_SIZE(mt8196_nau8825_dai_links), + .dapm_widgets =3D mt8196_nau8825_card_widgets, + .num_dapm_widgets =3D ARRAY_SIZE(mt8196_nau8825_card_widgets), + .dapm_routes =3D mt8196_nau8825_card_routes, + .num_dapm_routes =3D ARRAY_SIZE(mt8196_nau8825_card_routes), + .controls =3D mt8196_nau8825_card_controls, + .num_controls =3D ARRAY_SIZE(mt8196_nau8825_card_controls), +}; + +static const struct mtk_soundcard_pdata mt8196_nau8825_card =3D { + .card_name =3D "mt8196_nau8825", + .card_data =3D &(struct mtk_platform_card_data) { + .card =3D &mt8196_nau8825_soc_card, + .num_jacks =3D MT8196_JACK_MAX, + .flags =3D NAU8825_HS_PRESENT + }, + .sof_priv =3D &mt8196_sof_priv, + .soc_probe =3D mt8196_nau8825_soc_card_probe, +}; + +static const struct mtk_soundcard_pdata mt8196_rt5682s_card =3D { + .card_name =3D "mt8196_rt5682s", + .card_data =3D &(struct mtk_platform_card_data) { + .card =3D &mt8196_nau8825_soc_card, + .num_jacks =3D MT8196_JACK_MAX, + .flags =3D RT5682S_HS_PRESENT + }, + .sof_priv =3D &mt8196_sof_priv, + .soc_probe =3D mt8196_nau8825_soc_card_probe, +}; + +static const struct mtk_soundcard_pdata mt8196_rt5650_card =3D { + .card_name =3D "mt8196_rt5650", + .card_data =3D &(struct mtk_platform_card_data) { + .card =3D &mt8196_nau8825_soc_card, + .num_jacks =3D MT8196_JACK_MAX, + .flags =3D RT5650_HS_PRESENT + }, + .sof_priv =3D &mt8196_sof_priv, + .soc_probe =3D mt8196_nau8825_soc_card_probe, +}; + +static const struct of_device_id mt8196_nau8825_dt_match[] =3D { + {.compatible =3D "mediatek,mt8196-nau8825-sound", .data =3D &mt8196_nau88= 25_card,}, + {.compatible =3D "mediatek,mt8196-rt5682s-sound", .data =3D &mt8196_rt568= 2s_card,}, + {.compatible =3D "mediatek,mt8196-rt5650-sound", .data =3D &mt8196_rt5650= _card,}, + {} +}; +MODULE_DEVICE_TABLE(of, mt8196_nau8825_dt_match); + +static struct platform_driver mt8196_nau8825_driver =3D { + .driver =3D { + .name =3D "mt8196-nau8825", + .of_match_table =3D mt8196_nau8825_dt_match, + .pm =3D &snd_soc_pm_ops, + }, + .probe =3D mtk_soundcard_common_probe, +}; +module_platform_driver(mt8196_nau8825_driver); + +/* Module information */ +MODULE_DESCRIPTION("MT8196 nau8825 ALSA SoC machine driver"); +MODULE_AUTHOR("Darren Ye "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("mt8196 nau8825 soc card"); + --=20 2.45.2