summaryrefslogtreecommitdiff
path: root/sound/soc/intel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-08-06 20:19:51 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2022-08-06 20:19:51 +0300
commit668c3c237f5ddc2889879b08f26d2374231f3287 (patch)
treec8db84c82cba2c0a9dd7a28c5c8bad99d7ffda3d /sound/soc/intel
parentf20c95b46b8fa3ad34b3ea2e134337f88591468b (diff)
parent24df5428ef9d1ca1edd54eca7eb667110f2dfae3 (diff)
downloadlinux-668c3c237f5ddc2889879b08f26d2374231f3287.tar.xz
Merge tag 'sound-6.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai: "As the diffstat shows, we've had lots of developments in a wide range at this time; the majority of changes are about ASoC, including subsystem-wide cleanups, continued SOF / Intel updates and a bunch of new drivers (as usual), while there have been some significant (but almost invisible) improvements in ALSA core side, too. Below are some highlights: Core: - Faster lookups of control elements with Xarray; normal user won't notice, but on the devices with tons of control elements, it can be visibly faster - Support for input validation for controls; this will harden for badly written drivers in general with a slight overhead - Deferred async signal handling for working around the potential deadlocks - Cleanup / refactoring raw MIDI locking code ASoC: - Restructing of the set_fmt() callbacks for making things clearer in situations like CODEC to CODEC links - Clean up and modernizing the DAI naming scheme setups - Merge of more of the Intel AVS driver stack, including some board integrations - New version 4 mechanism for communication with SOF DSPs - Suppoort for dynamically selecting the PLL to use at runtime on i.MX platforms - Improvements for CODEC to CODEC support in the generic cards - Support for AMD Jadeite and various machines, AMD RPL, Intel MetorLake DSPs, Mediatek MT8186 DSPs and MT6366, nVidia Tegra MDDRC, OPE and PEQ, NXP TFA9890, Qualcomm SDM845, WCD9335 and WAS883x, and Texas Instruments TAS2780 HD- and USB-audio: - Continued improvement for CS35L41 (sub)codec support - More quirks for various devices (HP, Lenovo, Dell, Clevo)" * tag 'sound-6.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (778 commits) ALSA: hda/realtek: Add quirk for HP Spectre x360 15-eb0xxx ALSA: line6: Replace sprintf() with sysfs_emit() ALSA: hda: Replace sprintf() with sysfs_emit() ALSA: pcm: Replace sprintf() with sysfs_emit() ALSA: core: Replace scnprintf() with sysfs_emit() ALSA: control-led: Replace sprintf() with sysfs_emit() ALSA: aoa: Replace sprintf() with sysfs_emit() ALSA: ac97: Replace sprintf() with sysfs_emit() ALSA: hda/realtek: Add quirk for Clevo NV45PZ ALSA: hda/realtek: Add quirk for Lenovo Yoga9 14IAP7 ALSA: control: Use deferred fasync helper ALSA: pcm: Use deferred fasync helper ALSA: timer: Use deferred fasync helper ALSA: core: Add async signal helpers ASoC: q6asm: use kcalloc() instead of kzalloc() ACPI: scan: Add CLSA0101 Laptop Support ALSA: hda: cs35l41: Support CLSA0101 ALSA: hda: cs35l41: Use the CS35L41 HDA internal define ASoC: dt-bindings: use spi-peripheral-props.yaml ASoC: codecs: va-macro: use fsgen as clock ...
Diffstat (limited to 'sound/soc/intel')
-rw-r--r--sound/soc/intel/Kconfig5
-rw-r--r--sound/soc/intel/atom/sst-atom-controls.c8
-rw-r--r--sound/soc/intel/atom/sst/sst.c2
-rw-r--r--sound/soc/intel/atom/sst/sst_ipc.c8
-rw-r--r--sound/soc/intel/avs/Makefile3
-rw-r--r--sound/soc/intel/avs/boards/Kconfig121
-rw-r--r--sound/soc/intel/avs/boards/Makefile27
-rw-r--r--sound/soc/intel/avs/boards/da7219.c282
-rw-r--r--sound/soc/intel/avs/boards/dmic.c93
-rw-r--r--sound/soc/intel/avs/boards/hdaudio.c294
-rw-r--r--sound/soc/intel/avs/boards/i2s_test.c180
-rw-r--r--sound/soc/intel/avs/boards/max98357a.c154
-rw-r--r--sound/soc/intel/avs/boards/max98373.c239
-rw-r--r--sound/soc/intel/avs/boards/nau8825.c353
-rw-r--r--sound/soc/intel/avs/boards/rt274.c310
-rw-r--r--sound/soc/intel/avs/boards/rt286.c281
-rw-r--r--sound/soc/intel/avs/boards/rt298.c281
-rw-r--r--sound/soc/intel/avs/boards/rt5682.c340
-rw-r--r--sound/soc/intel/avs/boards/ssm4567.c271
-rw-r--r--sound/soc/intel/avs/cldma.c12
-rw-r--r--sound/soc/intel/avs/core.c13
-rw-r--r--sound/soc/intel/avs/dsp.c11
-rw-r--r--sound/soc/intel/avs/ipc.c1
-rw-r--r--sound/soc/intel/avs/loader.c2
-rw-r--r--sound/soc/intel/avs/messages.c18
-rw-r--r--sound/soc/intel/avs/path.c54
-rw-r--r--sound/soc/intel/avs/pcm.c2
-rw-r--r--sound/soc/intel/avs/topology.c27
-rw-r--r--sound/soc/intel/boards/Kconfig5
-rw-r--r--sound/soc/intel/boards/Makefile4
-rw-r--r--sound/soc/intel/boards/bdw-rt5650.c1
-rw-r--r--sound/soc/intel/boards/bdw-rt5677.c1
-rw-r--r--sound/soc/intel/boards/bdw_rt286.c280
-rw-r--r--sound/soc/intel/boards/broadwell.c336
-rw-r--r--sound/soc/intel/boards/bxt_da7219_max98357a.c21
-rw-r--r--sound/soc/intel/boards/bxt_rt298.c2
-rw-r--r--sound/soc/intel/boards/bytcht_cx2072x.c2
-rw-r--r--sound/soc/intel/boards/bytcht_da7213.c2
-rw-r--r--sound/soc/intel/boards/bytcht_es8316.c2
-rw-r--r--sound/soc/intel/boards/bytcht_nocodec.c2
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c4
-rw-r--r--sound/soc/intel/boards/bytcr_rt5651.c4
-rw-r--r--sound/soc/intel/boards/bytcr_wm5102.c2
-rw-r--r--sound/soc/intel/boards/cht_bsw_max98090_ti.c3
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5645.c8
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5672.c2
-rw-r--r--sound/soc/intel/boards/cml_rt1011_rt5682.c23
-rw-r--r--sound/soc/intel/boards/glk_rt5682_max98357a.c21
-rw-r--r--sound/soc/intel/boards/haswell.c202
-rw-r--r--sound/soc/intel/boards/hda_dsp_common.c4
-rw-r--r--sound/soc/intel/boards/hsw_rt5640.c177
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98357a.c21
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98927.c21
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_max98927.c21
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c21
-rw-r--r--sound/soc/intel/boards/skl_hda_dsp_generic.c4
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_max98357a.c19
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_ssm4567.c19
-rw-r--r--sound/soc/intel/boards/skl_rt286.c2
-rw-r--r--sound/soc/intel/boards/sof_cs42l42.c109
-rw-r--r--sound/soc/intel/boards/sof_da7219_max98373.c23
-rw-r--r--sound/soc/intel/boards/sof_es8336.c160
-rw-r--r--sound/soc/intel/boards/sof_nau8825.c33
-rw-r--r--sound/soc/intel/boards/sof_pcm512x.c2
-rw-r--r--sound/soc/intel/boards/sof_realtek_common.c24
-rw-r--r--sound/soc/intel/boards/sof_realtek_common.h6
-rw-r--r--sound/soc/intel/boards/sof_rt5682.c51
-rw-r--r--sound/soc/intel/boards/sof_sdw.c53
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt711.c3
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt711_sdca.c3
-rw-r--r--sound/soc/intel/catpt/device.c5
-rw-r--r--sound/soc/intel/catpt/pcm.c26
-rw-r--r--sound/soc/intel/catpt/sysfs.c4
-rw-r--r--sound/soc/intel/common/Makefile1
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-adl-match.c61
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c6
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-mtl-match.c89
-rw-r--r--sound/soc/intel/keembay/kmb_platform.c18
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c5
-rw-r--r--sound/soc/intel/skylake/skl-topology.c6
80 files changed, 4526 insertions, 790 deletions
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index 7c85d1bb9c12..ded903f95b67 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -216,7 +216,7 @@ config SND_SOC_INTEL_AVS
depends on COMMON_CLK
select SND_SOC_ACPI if ACPI
select SND_SOC_TOPOLOGY
- select SND_HDA
+ select SND_SOC_HDA
select SND_HDA_EXT_CORE
select SND_HDA_DSP_LOADER
select SND_INTEL_DSP_CONFIG
@@ -226,5 +226,8 @@ config SND_SOC_INTEL_AVS
capabilities. This includes Skylake, Kabylake, Amberlake and
Apollolake.
+# Machine board drivers
+source "sound/soc/intel/avs/boards/Kconfig"
+
# ASoC codec drivers
source "sound/soc/intel/boards/Kconfig"
diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c
index 335c32732994..fd59b35a62ba 100644
--- a/sound/soc/intel/atom/sst-atom-controls.c
+++ b/sound/soc/intel/atom/sst-atom-controls.c
@@ -831,9 +831,9 @@ static int sst_get_ssp_mode(struct snd_soc_dai *dai, unsigned int fmt)
dev_dbg(dai->dev, "Enter:%s, format=%x\n", __func__, format);
switch (format) {
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BP_FP:
return SSP_MODE_PROVIDER;
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BC_FC:
return SSP_MODE_CONSUMER;
default:
dev_err(dai->dev, "Invalid ssp protocol: %d\n", format);
@@ -1328,7 +1328,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute)
{
struct sst_data *drv = snd_soc_dai_get_drvdata(dai);
struct snd_soc_dapm_widget *w;
- struct snd_soc_dapm_path *p = NULL;
+ struct snd_soc_dapm_path *p;
dev_dbg(dai->dev, "enter, dai-name=%s dir=%d\n", dai->name, stream);
@@ -1392,7 +1392,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute)
static int sst_fill_module_list(struct snd_kcontrol *kctl,
struct snd_soc_dapm_widget *w, int type)
{
- struct sst_module *module = NULL;
+ struct sst_module *module;
struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
struct sst_ids *ids = w->priv;
int ret = 0;
diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c
index 3a42d68c0247..160b50f479fb 100644
--- a/sound/soc/intel/atom/sst/sst.c
+++ b/sound/soc/intel/atom/sst/sst.c
@@ -114,7 +114,7 @@ static irqreturn_t intel_sst_interrupt_mrfld(int irq, void *context)
static irqreturn_t intel_sst_irq_thread_mrfld(int irq, void *context)
{
struct intel_sst_drv *drv = (struct intel_sst_drv *) context;
- struct ipc_post *__msg, *msg = NULL;
+ struct ipc_post *__msg, *msg;
unsigned long irq_flags;
spin_lock_irqsave(&drv->rx_msg_lock, irq_flags);
diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c
index 4e8382097e61..4e039c7173d8 100644
--- a/sound/soc/intel/atom/sst/sst_ipc.c
+++ b/sound/soc/intel/atom/sst/sst_ipc.c
@@ -28,7 +28,7 @@
struct sst_block *sst_create_block(struct intel_sst_drv *ctx,
u32 msg_id, u32 drv_id)
{
- struct sst_block *msg = NULL;
+ struct sst_block *msg;
dev_dbg(ctx->dev, "Enter\n");
msg = kzalloc(sizeof(*msg), GFP_KERNEL);
@@ -63,7 +63,7 @@ struct sst_block *sst_create_block(struct intel_sst_drv *ctx,
int sst_wake_up_block(struct intel_sst_drv *ctx, int result,
u32 drv_id, u32 ipc, void *data, u32 size)
{
- struct sst_block *block = NULL;
+ struct sst_block *block;
dev_dbg(ctx->dev, "Enter\n");
@@ -91,7 +91,7 @@ int sst_wake_up_block(struct intel_sst_drv *ctx, int result,
int sst_free_block(struct intel_sst_drv *ctx, struct sst_block *freed)
{
- struct sst_block *block = NULL, *__block;
+ struct sst_block *block, *__block;
dev_dbg(ctx->dev, "Enter\n");
spin_lock_bh(&ctx->block_lock);
@@ -341,7 +341,7 @@ void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx,
}
/* FW sent short error response for an IPC */
- if (msg_high.part.result && drv_id && !msg_high.part.large) {
+ if (msg_high.part.result && !msg_high.part.large) {
/* 32-bit FW error code in msg_low */
dev_err(sst_drv_ctx->dev, "FW sent error response 0x%x", msg_low);
sst_wake_up_block(sst_drv_ctx, msg_high.part.result,
diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile
index b6b93ae80304..919212825f21 100644
--- a/sound/soc/intel/avs/Makefile
+++ b/sound/soc/intel/avs/Makefile
@@ -10,3 +10,6 @@ snd-soc-avs-objs += trace.o
CFLAGS_trace.o := -I$(src)
obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
+
+# Machine support
+obj-$(CONFIG_SND_SOC) += boards/
diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig
new file mode 100644
index 000000000000..4d68e3ef992b
--- /dev/null
+++ b/sound/soc/intel/avs/boards/Kconfig
@@ -0,0 +1,121 @@
+# SPDX-License-Identifier: GPL-2.0-only
+menu "Intel AVS Machine drivers"
+ depends on SND_SOC_INTEL_AVS
+
+comment "Available DSP configurations"
+
+config SND_SOC_INTEL_AVS_MACH_DA7219
+ tristate "da7219 I2S board"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_DA7219
+ help
+ This adds support for AVS with DA7219 I2S codec configuration.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_DMIC
+ tristate "DMIC generic board"
+ select SND_SOC_DMIC
+ help
+ This adds support for AVS with Digital Mic array configuration.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_HDAUDIO
+ tristate "HD-Audio generic board"
+ select SND_SOC_HDA
+ help
+ This adds support for AVS with HDAudio codec configuration.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_I2S_TEST
+ tristate "I2S test board"
+ help
+ This adds support for I2S test-board which can be used to verify
+ transfer over I2S interface with SSP loopback scenarios.
+
+config SND_SOC_INTEL_AVS_MACH_MAX98357A
+ tristate "max98357A I2S board"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_MAX98357A
+ help
+ This adds support for AVS with MAX98357A I2S codec configuration.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_MAX98373
+ tristate "max98373 I2S board"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_MAX98373
+ help
+ This adds support for AVS with MAX98373 I2S codec configuration.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_NAU8825
+ tristate "nau8825 I2S board"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_NAU8825
+ help
+ This adds support for ASoC machine driver with NAU8825 I2S audio codec.
+ It is meant to be used with AVS driver.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_RT274
+ tristate "rt274 in I2S mode"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_RT274
+ help
+ This adds support for ASoC machine driver with RT274 I2S audio codec.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_RT286
+ tristate "rt286 in I2S mode"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_RT286
+ help
+ This adds support for ASoC machine driver with RT286 I2S audio codec.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_RT298
+ tristate "rt298 in I2S mode"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_RT298
+ help
+ This adds support for ASoC machine driver with RT298 I2S audio codec.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_RT5682
+ tristate "rt5682 in I2S mode"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_RT5682_I2C
+ help
+ This adds support for ASoC machine driver with RT5682 I2S audio codec.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_SSM4567
+ tristate "ssm4567 I2S board"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_SSM4567
+ help
+ This adds support for ASoC machine driver with SSM4567 I2S audio codec.
+ It is meant to be used with AVS driver.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
+endmenu
diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile
new file mode 100644
index 000000000000..bc75376d58c2
--- /dev/null
+++ b/sound/soc/intel/avs/boards/Makefile
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+snd-soc-avs-da7219-objs := da7219.o
+snd-soc-avs-dmic-objs := dmic.o
+snd-soc-avs-hdaudio-objs := hdaudio.o
+snd-soc-avs-i2s-test-objs := i2s_test.o
+snd-soc-avs-max98357a-objs := max98357a.o
+snd-soc-avs-max98373-objs := max98373.o
+snd-soc-avs-nau8825-objs := nau8825.o
+snd-soc-avs-rt274-objs := rt274.o
+snd-soc-avs-rt286-objs := rt286.o
+snd-soc-avs-rt298-objs := rt298.o
+snd-soc-avs-rt5682-objs := rt5682.o
+snd-soc-avs-ssm4567-objs := ssm4567.o
+
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DA7219) += snd-soc-avs-da7219.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC) += snd-soc-avs-dmic.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_HDAUDIO) += snd-soc-avs-hdaudio.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_I2S_TEST) += snd-soc-avs-i2s-test.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98357A) += snd-soc-avs-max98357a.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98373) += snd-soc-avs-max98373.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_NAU8825) += snd-soc-avs-nau8825.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT286) += snd-soc-avs-rt286.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT298) += snd-soc-avs-rt298.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5682) += snd-soc-avs-rt5682.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_SSM4567) += snd-soc-avs-ssm4567.o
diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c
new file mode 100644
index 000000000000..02ae542ad779
--- /dev/null
+++ b/sound/soc/intel/avs/boards/da7219.c
@@ -0,0 +1,282 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+#include <uapi/linux/input-event-codes.h>
+#include "../../../codecs/da7219.h"
+#include "../../../codecs/da7219-aad.h"
+
+#define DA7219_DAI_NAME "da7219-hifi"
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static int platform_clock_control(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_dapm_context *dapm = w->dapm;
+ struct snd_soc_card *card = dapm->card;
+ struct snd_soc_dai *codec_dai;
+ int ret = 0;
+
+ codec_dai = snd_soc_card_get_codec_dai(card, DA7219_DAI_NAME);
+ if (!codec_dai) {
+ dev_err(card->dev, "Codec dai not found. Unable to set/unset codec pll\n");
+ return -EIO;
+ }
+
+ if (SND_SOC_DAPM_EVENT_OFF(event)) {
+ ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);
+ if (ret)
+ dev_err(card->dev, "failed to stop PLL: %d\n", ret);
+ } else if (SND_SOC_DAPM_EVENT_ON(event)) {
+ ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM,
+ 0, DA7219_PLL_FREQ_OUT_98304);
+ if (ret)
+ dev_err(card->dev, "failed to start PLL: %d\n", ret);
+ }
+
+ return ret;
+}
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control,
+ SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+ /* HP jack connectors - unknown if we have jack detection */
+ {"Headphone Jack", NULL, "HPL"},
+ {"Headphone Jack", NULL, "HPR"},
+
+ {"MIC", NULL, "Headset Mic"},
+
+ { "Headphone Jack", NULL, "Platform Clock" },
+ { "Headset Mic", NULL, "Platform Clock" },
+};
+
+static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+ struct snd_soc_card *card = runtime->card;
+ struct snd_soc_jack *jack;
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+ int clk_freq;
+ int ret;
+
+ jack = snd_soc_card_get_drvdata(card);
+ clk_freq = 19200000;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, clk_freq, SND_SOC_CLOCK_IN);
+ if (ret) {
+ dev_err(card->dev, "can't set codec sysclk configuration\n");
+ return ret;
+ }
+
+ /*
+ * Headset buttons map to the google Reference headset.
+ * These can be configured by userspace.
+ */
+ ret = snd_soc_card_jack_new(card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_BTN_0 |
+ SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+ SND_JACK_BTN_3 | SND_JACK_LINEOUT, jack);
+ if (ret) {
+ dev_err(card->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_VOLUMEUP);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
+
+ da7219_aad_jack_det(component, jack);
+
+ return 0;
+}
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-DLGS7219:00");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, DA7219_DAI_NAME);
+ if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 1;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->init = avs_da7219_codec_init;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_capture = 1;
+ dl->dpcm_playback = 1;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ const int num_base = ARRAY_SIZE(card_base_routes);
+ const int num_dr = num_base + 2;
+ int idx;
+
+ dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+ idx = num_base;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ idx++;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "Capture");
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ *routes = dr;
+ *num_routes = num_dr;
+
+ return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+ struct snd_soc_component *component;
+
+ for_each_card_components(card, component)
+ snd_soc_component_set_jack(component, jack, NULL);
+ return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+ struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+ return avs_card_set_jack(card, jack);
+}
+
+static int avs_da7219_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct snd_soc_jack *jack;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int num_routes, ssp_port, ret;
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm routes: %d", ret);
+ return ret;
+ }
+
+ jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!jack || !card)
+ return -ENOMEM;
+
+ card->name = "avs_da7219";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->remove = avs_card_remove;
+ card->suspend_pre = avs_card_suspend_pre;
+ card->resume_post = avs_card_resume_post;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = routes;
+ card->num_dapm_routes = num_routes;
+ card->fully_routed = true;
+ snd_soc_card_set_drvdata(card, jack);
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_da7219_driver = {
+ .probe = avs_da7219_probe,
+ .driver = {
+ .name = "avs_da7219",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_da7219_driver);
+
+MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_da7219");
diff --git a/sound/soc/intel/avs/boards/dmic.c b/sound/soc/intel/avs/boards/dmic.c
new file mode 100644
index 000000000000..90a921638572
--- /dev/null
+++ b/sound/soc/intel/avs/boards/dmic.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+
+SND_SOC_DAILINK_DEF(dmic_pin, DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin")));
+SND_SOC_DAILINK_DEF(dmic_wov_pin, DAILINK_COMP_ARRAY(COMP_CPU("DMIC WoV Pin")));
+SND_SOC_DAILINK_DEF(dmic_codec, DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
+/* Name overridden on probe */
+SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("")));
+
+static struct snd_soc_dai_link card_dai_links[] = {
+ /* Back ends */
+ {
+ .name = "DMIC",
+ .id = 0,
+ .dpcm_capture = 1,
+ .nonatomic = 1,
+ .no_pcm = 1,
+ SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
+ },
+ {
+ .name = "DMIC WoV",
+ .id = 1,
+ .dpcm_capture = 1,
+ .nonatomic = 1,
+ .no_pcm = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(dmic_wov_pin, dmic_codec, platform),
+ },
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_MIC("SoC DMIC", NULL),
+};
+
+static const struct snd_soc_dapm_route card_routes[] = {
+ {"DMic", NULL, "SoC DMIC"},
+ {"DMIC Rx", NULL, "Capture"},
+ {"DMIC WoV Rx", NULL, "Capture"},
+};
+
+static int avs_dmic_probe(struct platform_device *pdev)
+{
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ mach = dev_get_platdata(dev);
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ card->name = "avs_dmic";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->dai_link = card_dai_links;
+ card->num_links = ARRAY_SIZE(card_dai_links);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = card_routes;
+ card->num_dapm_routes = ARRAY_SIZE(card_routes);
+ card->fully_routed = true;
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, mach->mach_params.platform);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_dmic_driver = {
+ .probe = avs_dmic_probe,
+ .driver = {
+ .name = "avs_dmic",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_dmic_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_dmic");
diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c
new file mode 100644
index 000000000000..d2fc41d39448
--- /dev/null
+++ b/sound/soc/intel/avs/boards/hdaudio.c
@@ -0,0 +1,294 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/platform_device.h>
+#include <sound/hda_codec.h>
+#include <sound/hda_i915.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/hda.h"
+
+static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int pcm_count,
+ const char *platform_name, struct snd_soc_dai_link **links)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+ struct hda_pcm *pcm;
+ const char *cname = dev_name(&codec->core.dev);
+ int i;
+
+ dl = devm_kcalloc(dev, pcm_count, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+ pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list);
+
+ for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) {
+ dl[i].name = devm_kasprintf(dev, GFP_KERNEL, "%s link%d", cname, i);
+ if (!dl[i].name)
+ return -ENOMEM;
+
+ dl[i].id = i;
+ dl[i].nonatomic = 1;
+ dl[i].no_pcm = 1;
+ dl[i].dpcm_playback = 1;
+ dl[i].dpcm_capture = 1;
+ dl[i].platforms = platform;
+ dl[i].num_platforms = 1;
+
+ dl[i].codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+ dl[i].cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ if (!dl[i].codecs || !dl[i].cpus)
+ return -ENOMEM;
+
+ dl[i].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "%s-cpu%d", cname, i);
+ if (!dl[i].cpus->dai_name)
+ return -ENOMEM;
+
+ dl[i].codecs->name = devm_kstrdup(dev, cname, GFP_KERNEL);
+ dl[i].codecs->dai_name = pcm->name;
+ dl[i].num_codecs = 1;
+ dl[i].num_cpus = 1;
+ }
+
+ *links = dl;
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, struct hda_codec *codec, int pcm_count,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ struct hda_pcm *pcm;
+ const char *cname = dev_name(&codec->core.dev);
+ int i, n = 0;
+
+ /* at max twice the number of pcms */
+ dr = devm_kcalloc(dev, pcm_count * 2, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list);
+
+ for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) {
+ struct hda_pcm_stream *stream;
+ int dir;
+
+ dir = SNDRV_PCM_STREAM_PLAYBACK;
+ stream = &pcm->stream[dir];
+ if (!stream->substreams)
+ goto capture_routes;
+
+ dr[n].sink = devm_kasprintf(dev, GFP_KERNEL, "%s %s", pcm->name,
+ snd_pcm_direction_name(dir));
+ dr[n].source = devm_kasprintf(dev, GFP_KERNEL, "%s-cpu%d Tx", cname, i);
+ if (!dr[n].sink || !dr[n].source)
+ return -ENOMEM;
+ n++;
+
+capture_routes:
+ dir = SNDRV_PCM_STREAM_CAPTURE;
+ stream = &pcm->stream[dir];
+ if (!stream->substreams)
+ continue;
+
+ dr[n].sink = devm_kasprintf(dev, GFP_KERNEL, "%s-cpu%d Rx", cname, i);
+ dr[n].source = devm_kasprintf(dev, GFP_KERNEL, "%s %s", pcm->name,
+ snd_pcm_direction_name(dir));
+ if (!dr[n].sink || !dr[n].source)
+ return -ENOMEM;
+ n++;
+ }
+
+ *routes = dr;
+ *num_routes = n;
+ return 0;
+}
+
+/* Should be aligned with SectionPCM's name from topology */
+#define FEDAI_NAME_PREFIX "HDMI"
+
+static struct snd_pcm *
+avs_card_hdmi_pcm_at(struct snd_soc_card *card, int hdmi_idx)
+{
+ struct snd_soc_pcm_runtime *rtd;
+ int dir = SNDRV_PCM_STREAM_PLAYBACK;
+
+ for_each_card_rtds(card, rtd) {
+ struct snd_pcm *spcm;
+ int ret, n;
+
+ spcm = rtd->pcm ? rtd->pcm->streams[dir].pcm : NULL;
+ if (!spcm || !strstr(spcm->id, FEDAI_NAME_PREFIX))
+ continue;
+
+ ret = sscanf(spcm->id, FEDAI_NAME_PREFIX "%d", &n);
+ if (ret != 1)
+ continue;
+ if (n == hdmi_idx)
+ return rtd->pcm;
+ }
+
+ return NULL;
+}
+
+static int avs_card_late_probe(struct snd_soc_card *card)
+{
+ struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
+ struct hda_codec *codec = mach->pdata;
+ struct hda_pcm *hpcm;
+ /* Topology pcm indexing is 1-based */
+ int i = 1;
+
+ list_for_each_entry(hpcm, &codec->pcm_list_head, list) {
+ struct snd_pcm *spcm;
+
+ spcm = avs_card_hdmi_pcm_at(card, i);
+ if (spcm) {
+ hpcm->pcm = spcm;
+ hpcm->device = spcm->device;
+ dev_info(card->dev, "%s: mapping HDMI converter %d to PCM %d (%p)\n",
+ __func__, i, hpcm->device, spcm);
+ } else {
+ hpcm->pcm = NULL;
+ hpcm->device = SNDRV_PCM_INVALID_DEVICE;
+ dev_warn(card->dev, "%s: no PCM in topology for HDMI converter %d\n",
+ __func__, i);
+ }
+ i++;
+ }
+
+ return hda_codec_probe_complete(codec);
+}
+
+static int avs_probing_link_init(struct snd_soc_pcm_runtime *rtm)
+{
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_dai_link *links = NULL;
+ struct snd_soc_card *card = rtm->card;
+ struct hda_codec *codec;
+ struct hda_pcm *pcm;
+ int ret, n, pcm_count = 0;
+
+ mach = dev_get_platdata(card->dev);
+ codec = mach->pdata;
+
+ if (list_empty(&codec->pcm_list_head))
+ return -EINVAL;
+ list_for_each_entry(pcm, &codec->pcm_list_head, list)
+ pcm_count++;
+
+ ret = avs_create_dai_links(card->dev, codec, pcm_count, mach->mach_params.platform, &links);
+ if (ret < 0) {
+ dev_err(card->dev, "create links failed: %d\n", ret);
+ return ret;
+ }
+
+ for (n = 0; n < pcm_count; n++) {
+ ret = snd_soc_add_pcm_runtime(card, &links[n]);
+ if (ret < 0) {
+ dev_err(card->dev, "add links failed: %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = avs_create_dapm_routes(card->dev, codec, pcm_count, &routes, &n);
+ if (ret < 0) {
+ dev_err(card->dev, "create routes failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dapm_add_routes(&card->dapm, routes, n);
+ if (ret < 0) {
+ dev_err(card->dev, "add routes failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));
+
+static struct snd_soc_dai_link probing_link = {
+ .name = "probing-LINK",
+ .id = -1,
+ .nonatomic = 1,
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .cpus = dummy,
+ .num_cpus = ARRAY_SIZE(dummy),
+ .init = avs_probing_link_init,
+};
+
+static int avs_hdaudio_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dai_link *binder;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct device *dev = &pdev->dev;
+ struct hda_codec *codec;
+
+ mach = dev_get_platdata(dev);
+ codec = mach->pdata;
+
+ /* codec may be unloaded before card's probe() fires */
+ if (!device_is_registered(&codec->core.dev))
+ return -ENODEV;
+
+ binder = devm_kmemdup(dev, &probing_link, sizeof(probing_link), GFP_KERNEL);
+ if (!binder)
+ return -ENOMEM;
+
+ binder->platforms = devm_kzalloc(dev, sizeof(*binder->platforms), GFP_KERNEL);
+ binder->codecs = devm_kzalloc(dev, sizeof(*binder->codecs), GFP_KERNEL);
+ if (!binder->platforms || !binder->codecs)
+ return -ENOMEM;
+
+ binder->codecs->name = devm_kstrdup(dev, dev_name(&codec->core.dev), GFP_KERNEL);
+ if (!binder->codecs->name)
+ return -ENOMEM;
+
+ binder->platforms->name = mach->mach_params.platform;
+ binder->num_platforms = 1;
+ binder->codecs->dai_name = "codec-probing-DAI";
+ binder->num_codecs = 1;
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ card->name = binder->codecs->name;
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->dai_link = binder;
+ card->num_links = 1;
+ card->fully_routed = true;
+ if (hda_codec_is_display(codec))
+ card->late_probe = avs_card_late_probe;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_hdaudio_driver = {
+ .probe = avs_hdaudio_probe,
+ .driver = {
+ .name = "avs_hdaudio",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_hdaudio_driver)
+
+MODULE_DESCRIPTION("Intel HD-Audio machine driver");
+MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_hdaudio");
diff --git a/sound/soc/intel/avs/boards/i2s_test.c b/sound/soc/intel/avs/boards/i2s_test.c
new file mode 100644
index 000000000000..8f0fd87bc866
--- /dev/null
+++ b/sound/soc/intel/avs/boards/i2s_test.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "snd-soc-dummy");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "snd-soc-dummy-dai");
+ if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 1;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_capture = 1;
+ dl->dpcm_playback = 1;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ const int num_dr = 2;
+
+ dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ dr[0].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%dpb", ssp_port);
+ dr[0].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[0].sink || !dr[0].source)
+ return -ENOMEM;
+
+ dr[1].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+ dr[1].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%dcp", ssp_port);
+ if (!dr[1].sink || !dr[1].source)
+ return -ENOMEM;
+
+ *routes = dr;
+ *num_routes = num_dr;
+
+ return 0;
+}
+
+static int avs_create_dapm_widgets(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_widget **widgets, int *num_widgets)
+{
+ struct snd_soc_dapm_widget *dw;
+ const int num_dw = 2;
+
+ dw = devm_kcalloc(dev, num_dw, sizeof(*dw), GFP_KERNEL);
+ if (!dw)
+ return -ENOMEM;
+
+ dw[0].id = snd_soc_dapm_hp;
+ dw[0].reg = SND_SOC_NOPM;
+ dw[0].name = devm_kasprintf(dev, GFP_KERNEL, "ssp%dpb", ssp_port);
+ if (!dw[0].name)
+ return -ENOMEM;
+
+ dw[1].id = snd_soc_dapm_mic;
+ dw[1].reg = SND_SOC_NOPM;
+ dw[1].name = devm_kasprintf(dev, GFP_KERNEL, "ssp%dcp", ssp_port);
+ if (!dw[1].name)
+ return -ENOMEM;
+
+ *widgets = dw;
+ *num_widgets = num_dw;
+
+ return 0;
+}
+
+static int avs_i2s_test_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dapm_widget *widgets;
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int num_routes, num_widgets;
+ int ssp_port, ret;
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ card->name = devm_kasprintf(dev, GFP_KERNEL, "ssp%d-loopback", ssp_port);
+ if (!card->name)
+ return -ENOMEM;
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d\n", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm routes: %d\n", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_widgets(dev, ssp_port, &widgets, &num_widgets);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm widgets: %d\n", ret);
+ return ret;
+ }
+
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->dapm_routes = routes;
+ card->num_dapm_routes = num_routes;
+ card->dapm_widgets = widgets;
+ card->num_dapm_widgets = num_widgets;
+ card->fully_routed = true;
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_i2s_test_driver = {
+ .probe = avs_i2s_test_probe,
+ .driver = {
+ .name = "avs_i2s_test",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_i2s_test_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_i2s_test");
diff --git a/sound/soc/intel/avs/boards/max98357a.c b/sound/soc/intel/avs/boards/max98357a.c
new file mode 100644
index 000000000000..921f42caf7e0
--- /dev/null
+++ b/sound/soc/intel/avs/boards/max98357a.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Spk"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_SPK("Spk", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+ { "Spk", NULL, "Speaker" },
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "MX98357A:00");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "HiFi");
+ if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 1;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_playback = 1;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ const int num_base = ARRAY_SIZE(card_base_routes);
+ const int num_dr = num_base + 1;
+ int idx;
+
+ dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+ idx = num_base;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "HiFi Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ *routes = dr;
+ *num_routes = num_dr;
+
+ return 0;
+}
+
+static int avs_max98357a_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int num_routes, ssp_port, ret;
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm routes: %d", ret);
+ return ret;
+ }
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ card->name = "avs_max98357a";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = routes;
+ card->num_dapm_routes = num_routes;
+ card->fully_routed = true;
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_max98357a_driver = {
+ .probe = avs_max98357a_probe,
+ .driver = {
+ .name = "avs_max98357a",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_max98357a_driver)
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_max98357a");
diff --git a/sound/soc/intel/avs/boards/max98373.c b/sound/soc/intel/avs/boards/max98373.c
new file mode 100644
index 000000000000..0fa8f5606385
--- /dev/null
+++ b/sound/soc/intel/avs/boards/max98373.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+
+#define MAX98373_DEV0_NAME "i2c-MX98373:00"
+#define MAX98373_DEV1_NAME "i2c-MX98373:01"
+#define MAX98373_CODEC_NAME "max98373-aif1"
+
+static struct snd_soc_codec_conf card_codec_conf[] = {
+ {
+ .dlc = COMP_CODEC_CONF(MAX98373_DEV0_NAME),
+ .name_prefix = "Right",
+ },
+ {
+ .dlc = COMP_CODEC_CONF(MAX98373_DEV1_NAME),
+ .name_prefix = "Left",
+ },
+};
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Left Spk"),
+ SOC_DAPM_PIN_SWITCH("Right Spk"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_SPK("Left Spk", NULL),
+ SND_SOC_DAPM_SPK("Right Spk", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+ { "Left Spk", NULL, "Left BE_OUT" },
+ { "Right Spk", NULL, "Right BE_OUT" },
+};
+
+static int
+avs_max98373_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate, *channels;
+ struct snd_mask *fmt;
+
+ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* The ADSP will covert the FE rate to 48k, stereo */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSP0 to 16 bit */
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
+ return 0;
+}
+
+static int avs_max98373_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai;
+ int ret, i;
+
+ for_each_rtd_codec_dais(runtime, i, codec_dai) {
+ if (!strcmp(codec_dai->component->name, MAX98373_DEV0_NAME)) {
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16);
+ if (ret < 0) {
+ dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret);
+ return ret;
+ }
+ }
+ if (!strcmp(codec_dai->component->name, MAX98373_DEV1_NAME)) {
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16);
+ if (ret < 0) {
+ dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret);
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_ops avs_max98373_ops = {
+ .hw_params = avs_max98373_hw_params,
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs[0].name = devm_kasprintf(dev, GFP_KERNEL, MAX98373_DEV0_NAME);
+ dl->codecs[0].dai_name = devm_kasprintf(dev, GFP_KERNEL, MAX98373_CODEC_NAME);
+ dl->codecs[1].name = devm_kasprintf(dev, GFP_KERNEL, MAX98373_DEV1_NAME);
+ dl->codecs[1].dai_name = devm_kasprintf(dev, GFP_KERNEL, MAX98373_CODEC_NAME);
+ if (!dl->cpus->dai_name || !dl->codecs[0].name || !dl->codecs[0].dai_name ||
+ !dl->codecs[1].name || !dl->codecs[1].dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 2;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
+ dl->be_hw_params_fixup = avs_max98373_be_fixup;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_capture = 1;
+ dl->dpcm_playback = 1;
+ dl->ignore_pmdown_time = 1;
+ dl->ops = &avs_max98373_ops;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ const int num_base = ARRAY_SIZE(card_base_routes);
+ const int num_dr = num_base + 2;
+ int idx;
+
+ dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+ idx = num_base;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Left HiFi Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ idx++;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Right HiFi Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ *routes = dr;
+ *num_routes = num_dr;
+
+ return 0;
+}
+
+static int avs_max98373_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int num_routes, ssp_port, ret;
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm routes: %d", ret);
+ return ret;
+ }
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ card->name = "avs_max98373";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->codec_conf = card_codec_conf;
+ card->num_configs = ARRAY_SIZE(card_codec_conf);
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = routes;
+ card->num_dapm_routes = num_routes;
+ card->fully_routed = true;
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_max98373_driver = {
+ .probe = avs_max98373_probe,
+ .driver = {
+ .name = "avs_max98373",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_max98373_driver)
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_max98373");
diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c
new file mode 100644
index 000000000000..f76909e9f990
--- /dev/null
+++ b/sound/soc/intel/avs/boards/nau8825.c
@@ -0,0 +1,353 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/nau8825.h"
+
+#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
+
+static int
+avs_nau8825_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event)
+{
+ struct snd_soc_dapm_context *dapm = w->dapm;
+ struct snd_soc_card *card = dapm->card;
+ struct snd_soc_dai *codec_dai;
+ int ret;
+
+ codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI);
+ if (!codec_dai) {
+ dev_err(card->dev, "Codec dai not found\n");
+ return -EINVAL;
+ }
+
+ if (!SND_SOC_DAPM_EVENT_ON(event)) {
+ ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(card->dev, "set sysclk err = %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, avs_nau8825_clock_control,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+ { "Headphone Jack", NULL, "HPOL" },
+ { "Headphone Jack", NULL, "HPOR" },
+
+ { "MIC", NULL, "Headset Mic" },
+
+ { "Headphone Jack", NULL, "Platform Clock" },
+ { "Headset Mic", NULL, "Platform Clock" },
+};
+
+static struct snd_soc_jack_pin card_headset_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static int avs_nau8825_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+ struct snd_soc_component *component = codec_dai->component;
+ struct snd_soc_jack_pin *pins;
+ struct snd_soc_jack *jack;
+ struct snd_soc_card *card = runtime->card;
+ int num_pins, ret;
+
+ jack = snd_soc_card_get_drvdata(card);
+ num_pins = ARRAY_SIZE(card_headset_pins);
+
+ pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+
+ /*
+ * 4 buttons here map to the google Reference headset.
+ * The use of these buttons can be decided by the user space.
+ */
+ ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0 |
+ SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ jack, pins, num_pins);
+ if (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);
+
+ //snd_soc_component_set_jack(component, jack, NULL);
+ // TODO: Fix nau8825 codec to use .set_jack, like everyone else
+ nau8825_enable_jack_detect(component, jack);
+
+ return 0;
+}
+
+static int
+avs_nau8825_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate, *channels;
+ struct snd_mask *fmt;
+
+ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* The ADSP will convert the FE rate to 48k, stereo */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSP to 24 bit */
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+ return 0;
+}
+
+static int avs_nau8825_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtm = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtm, 0);
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_FS, 0, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "can't set FS clock %d\n", ret);
+ break;
+ }
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, runtime->rate, runtime->rate * 256);
+ if (ret < 0)
+ dev_err(codec_dai->dev, "can't set FLL: %d\n", ret);
+ break;
+
+ case SNDRV_PCM_TRIGGER_RESUME:
+ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, runtime->rate, runtime->rate * 256);
+ if (ret < 0)
+ dev_err(codec_dai->dev, "can't set FLL: %d\n", ret);
+ break;
+ }
+
+ return ret;
+}
+
+
+static const struct snd_soc_ops avs_nau8825_ops = {
+ .trigger = avs_nau8825_trigger,
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-10508825:00");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, SKL_NUVOTON_CODEC_DAI);
+ if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 1;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->init = avs_nau8825_codec_init;
+ dl->be_hw_params_fixup = avs_nau8825_be_fixup;
+ dl->ops = &avs_nau8825_ops;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_capture = 1;
+ dl->dpcm_playback = 1;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ const int num_base = ARRAY_SIZE(card_base_routes);
+ const int num_dr = num_base + 2;
+ int idx;
+
+ dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+ idx = num_base;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ idx++;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "Capture");
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ *routes = dr;
+ *num_routes = num_dr;
+
+ return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+ struct snd_soc_component *component;
+
+ for_each_card_components(card, component)
+ snd_soc_component_set_jack(component, jack, NULL);
+ return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI);
+ struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+ if (!codec_dai) {
+ dev_err(card->dev, "Codec dai not found\n");
+ return -EINVAL;
+ }
+
+ if (codec_dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK] &&
+ codec_dai->playback_widget->active)
+ snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_FS, 0, SND_SOC_CLOCK_IN);
+
+ return avs_card_set_jack(card, jack);
+}
+
+static int avs_nau8825_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct snd_soc_jack *jack;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int num_routes, ssp_port, ret;
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm routes: %d", ret);
+ return ret;
+ }
+
+ jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!jack || !card)
+ return -ENOMEM;
+
+ card->name = "avs_nau8825";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->remove = avs_card_remove;
+ card->suspend_pre = avs_card_suspend_pre;
+ card->resume_post = avs_card_resume_post;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = routes;
+ card->num_dapm_routes = num_routes;
+ card->fully_routed = true;
+ snd_soc_card_set_drvdata(card, jack);
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_nau8825_driver = {
+ .probe = avs_nau8825_probe,
+ .driver = {
+ .name = "avs_nau8825",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_nau8825_driver)
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_nau8825");
diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c
new file mode 100644
index 000000000000..afef5a3ca60b
--- /dev/null
+++ b/sound/soc/intel/avs/boards/rt274.c
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/rt274.h"
+
+#define AVS_RT274_FREQ_OUT 24000000
+#define AVS_RT274_BE_FIXUP_RATE 48000
+#define RT274_CODEC_DAI "rt274-aif1"
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Mic Jack"),
+};
+
+static int
+avs_rt274_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event)
+{
+ struct snd_soc_dapm_context *dapm = w->dapm;
+ struct snd_soc_card *card = dapm->card;
+ struct snd_soc_dai *codec_dai;
+ int ret;
+
+ codec_dai = snd_soc_card_get_codec_dai(card, RT274_CODEC_DAI);
+ if (!codec_dai)
+ return -EINVAL;
+
+ /* Codec needs clock for Jack detection and button press */
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT274_SCLK_S_PLL2, AVS_RT274_FREQ_OUT,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "set codec sysclk failed: %d\n", ret);
+ return ret;
+ }
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ int ratio = 100;
+
+ snd_soc_dai_set_bclk_ratio(codec_dai, ratio);
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0, RT274_PLL2_S_BCLK,
+ AVS_RT274_BE_FIXUP_RATE * ratio, AVS_RT274_FREQ_OUT);
+ if (ret) {
+ dev_err(codec_dai->dev, "failed to enable PLL2: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, avs_rt274_clock_control,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+ {"Headphone Jack", NULL, "HPO Pin"},
+ {"MIC", NULL, "Mic Jack"},
+
+ {"Headphone Jack", NULL, "Platform Clock"},
+ {"MIC", NULL, "Platform Clock"},
+};
+
+static struct snd_soc_jack_pin card_headset_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Mic Jack",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static int avs_rt274_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+ struct snd_soc_component *component = codec_dai->component;
+ struct snd_soc_jack_pin *pins;
+ struct snd_soc_jack *jack;
+ struct snd_soc_card *card = runtime->card;
+ int num_pins, ret;
+
+ jack = snd_soc_card_get_drvdata(card);
+ num_pins = ARRAY_SIZE(card_headset_pins);
+
+ pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+
+ ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET, jack, pins, num_pins);
+ if (ret)
+ return ret;
+
+ snd_soc_component_set_jack(component, jack, NULL);
+
+ /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
+ if (ret < 0) {
+ dev_err(card->dev, "can't set codec pcm format %d\n", ret);
+ return ret;
+ }
+
+ card->dapm.idle_bias_off = true;
+
+ return 0;
+}
+
+static int avs_rt274_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate, *channels;
+ struct snd_mask *fmt;
+
+ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* The ADSP will convert the FE rate to 48k, stereo */
+ rate->min = rate->max = AVS_RT274_BE_FIXUP_RATE;
+ channels->min = channels->max = 2;
+
+ /* set SSPN to 24 bit */
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+ return 0;
+}
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT34C2:00");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt274-aif1");
+ if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 1;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->init = avs_rt274_codec_init;
+ dl->be_hw_params_fixup = avs_rt274_be_fixup;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_capture = 1;
+ dl->dpcm_playback = 1;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ const int num_base = ARRAY_SIZE(card_base_routes);
+ const int num_dr = num_base + 2;
+ int idx;
+
+ dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+ idx = num_base;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ idx++;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Capture");
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ *routes = dr;
+ *num_routes = num_dr;
+
+ return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+ struct snd_soc_component *component;
+
+ for_each_card_components(card, component)
+ snd_soc_component_set_jack(component, jack, NULL);
+ return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+ struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+ return avs_card_set_jack(card, jack);
+}
+
+static int avs_rt274_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct snd_soc_jack *jack;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int num_routes, ssp_port, ret;
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm routes: %d", ret);
+ return ret;
+ }
+
+ jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!jack || !card)
+ return -ENOMEM;
+
+ card->name = "avs_rt274";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->remove = avs_card_remove;
+ card->suspend_pre = avs_card_suspend_pre;
+ card->resume_post = avs_card_resume_post;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = routes;
+ card->num_dapm_routes = num_routes;
+ card->fully_routed = true;
+ snd_soc_card_set_drvdata(card, jack);
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_rt274_driver = {
+ .probe = avs_rt274_probe,
+ .driver = {
+ .name = "avs_rt274",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_rt274_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_rt274");
diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c
new file mode 100644
index 000000000000..e51d4e181274
--- /dev/null
+++ b/sound/soc/intel/avs/boards/rt286.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/rt286.h"
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Mic Jack"),
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+ /* HP jack connectors - unknown if we have jack detect */
+ {"Headphone Jack", NULL, "HPO Pin"},
+ {"MIC1", NULL, "Mic Jack"},
+
+ {"Speaker", NULL, "SPOR"},
+ {"Speaker", NULL, "SPOL"},
+};
+
+static struct snd_soc_jack_pin card_headset_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Mic Jack",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static int avs_rt286_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+ struct snd_soc_jack_pin *pins;
+ struct snd_soc_jack *jack;
+ struct snd_soc_card *card = runtime->card;
+ int num_pins, ret;
+
+ jack = snd_soc_card_get_drvdata(card);
+ num_pins = ARRAY_SIZE(card_headset_pins);
+
+ pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+
+ ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0, jack,
+ pins, num_pins);
+ if (ret)
+ return ret;
+
+ snd_soc_component_set_jack(component, jack, NULL);
+
+ return 0;
+}
+
+static int avs_rt286_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate, *channels;
+ struct snd_mask *fmt;
+
+ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* The ADSP will convert the FE rate to 48k, stereo */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSP0 to 24 bit */
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+ return 0;
+}
+
+static int
+avs_rt286_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *runtime = substream->private_data;
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+ int ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ dev_err(runtime->dev, "Set codec sysclk failed: %d\n", ret);
+
+ return ret;
+}
+
+static const struct snd_soc_ops avs_rt286_ops = {
+ .hw_params = avs_rt286_hw_params,
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343A:00");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt286-aif1");
+ if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 1;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->init = avs_rt286_codec_init;
+ dl->be_hw_params_fixup = avs_rt286_be_fixup;
+ dl->ops = &avs_rt286_ops;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_capture = 1;
+ dl->dpcm_playback = 1;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ const int num_base = ARRAY_SIZE(card_base_routes);
+ const int num_dr = num_base + 2;
+ int idx;
+
+ dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+ idx = num_base;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ idx++;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Capture");
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ *routes = dr;
+ *num_routes = num_dr;
+
+ return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+ struct snd_soc_component *component;
+
+ for_each_card_components(card, component)
+ snd_soc_component_set_jack(component, jack, NULL);
+ return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+ struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+ return avs_card_set_jack(card, jack);
+}
+
+static int avs_rt286_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct snd_soc_jack *jack;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int num_routes, ssp_port, ret;
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm routes: %d", ret);
+ return ret;
+ }
+
+ jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!jack || !card)
+ return -ENOMEM;
+
+ card->name = "avs_rt286";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->remove = avs_card_remove;
+ card->suspend_pre = avs_card_suspend_pre;
+ card->resume_post = avs_card_resume_post;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = routes;
+ card->num_dapm_routes = num_routes;
+ card->fully_routed = true;
+ snd_soc_card_set_drvdata(card, jack);
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_rt286_driver = {
+ .probe = avs_rt286_probe,
+ .driver = {
+ .name = "avs_rt286",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_rt286_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_rt286");
diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c
new file mode 100644
index 000000000000..b28d36872dcb
--- /dev/null
+++ b/sound/soc/intel/avs/boards/rt298.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/rt298.h"
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Mic Jack"),
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+ /* HP jack connectors - unknown if we have jack detect */
+ {"Headphone Jack", NULL, "HPO Pin"},
+ {"MIC1", NULL, "Mic Jack"},
+
+ {"Speaker", NULL, "SPOR"},
+ {"Speaker", NULL, "SPOL"},
+};
+
+static struct snd_soc_jack_pin card_headset_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Mic Jack",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static int avs_rt298_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+ struct snd_soc_jack_pin *pins;
+ struct snd_soc_jack *jack;
+ struct snd_soc_card *card = runtime->card;
+ int num_pins, ret;
+
+ jack = snd_soc_card_get_drvdata(card);
+ num_pins = ARRAY_SIZE(card_headset_pins);
+
+ pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+
+ ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0, jack,
+ pins, num_pins);
+ if (ret)
+ return ret;
+
+ snd_soc_component_set_jack(component, jack, NULL);
+
+ return 0;
+}
+
+static int avs_rt298_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate, *channels;
+ struct snd_mask *fmt;
+
+ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* The ADSP will convert the FE rate to 48k, stereo */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSP0 to 24 bit */
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+ return 0;
+}
+
+static int
+avs_rt298_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ int ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT298_SCLK_S_PLL, 19200000, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ dev_err(rtd->dev, "Set codec sysclk failed: %d\n", ret);
+
+ return ret;
+}
+
+static const struct snd_soc_ops avs_rt298_ops = {
+ .hw_params = avs_rt298_hw_params,
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343A:00");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt298-aif1");
+ if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 1;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->init = avs_rt298_codec_init;
+ dl->be_hw_params_fixup = avs_rt298_be_fixup;
+ dl->ops = &avs_rt298_ops;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_capture = 1;
+ dl->dpcm_playback = 1;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ const int num_base = ARRAY_SIZE(card_base_routes);
+ const int num_dr = num_base + 2;
+ int idx;
+
+ dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+ idx = num_base;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ idx++;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Capture");
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ *routes = dr;
+ *num_routes = num_dr;
+
+ return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+ struct snd_soc_component *component;
+
+ for_each_card_components(card, component)
+ snd_soc_component_set_jack(component, jack, NULL);
+ return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+ struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+ return avs_card_set_jack(card, jack);
+}
+
+static int avs_rt298_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct snd_soc_jack *jack;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int num_routes, ssp_port, ret;
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm routes: %d", ret);
+ return ret;
+ }
+
+ jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!jack || !card)
+ return -ENOMEM;
+
+ card->name = "avs_rt298";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->remove = avs_card_remove;
+ card->suspend_pre = avs_card_suspend_pre;
+ card->resume_post = avs_card_resume_post;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = routes;
+ card->num_dapm_routes = num_routes;
+ card->fully_routed = true;
+ snd_soc_card_set_drvdata(card, jack);
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_rt298_driver = {
+ .probe = avs_rt298_probe,
+ .driver = {
+ .name = "avs_rt298",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_rt298_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_rt298");
diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c
new file mode 100644
index 000000000000..01f9b9f0c12b
--- /dev/null
+++ b/sound/soc/intel/avs/boards/rt5682.c
@@ -0,0 +1,340 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/clk.h>
+#include <linux/dmi.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/rt5682.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../common/soc-intel-quirks.h"
+#include "../../../codecs/rt5682.h"
+
+#define AVS_RT5682_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0))
+#define AVS_RT5682_SSP_CODEC_MASK (GENMASK(2, 0))
+#define AVS_RT5682_MCLK_EN BIT(3)
+#define AVS_RT5682_MCLK_24MHZ BIT(4)
+
+/* Default: MCLK on, MCLK 19.2M, SSP0 */
+static unsigned long avs_rt5682_quirk = AVS_RT5682_MCLK_EN | AVS_RT5682_SSP_CODEC(0);
+
+static int avs_rt5682_quirk_cb(const struct dmi_system_id *id)
+{
+ avs_rt5682_quirk = (unsigned long)id->driver_data;
+ return 1;
+}
+
+static const struct dmi_system_id avs_rt5682_quirk_table[] = {
+ {
+ .callback = avs_rt5682_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "WhiskeyLake Client"),
+ },
+ .driver_data = (void *)(AVS_RT5682_MCLK_EN |
+ AVS_RT5682_MCLK_24MHZ |
+ AVS_RT5682_SSP_CODEC(1)),
+ },
+ {
+ .callback = avs_rt5682_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
+ },
+ .driver_data = (void *)(AVS_RT5682_MCLK_EN |
+ AVS_RT5682_SSP_CODEC(0)),
+ },
+ {}
+};
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+ /* HP jack connectors - unknown if we have jack detect */
+ { "Headphone Jack", NULL, "HPOL" },
+ { "Headphone Jack", NULL, "HPOR" },
+
+ /* other jacks */
+ { "IN1P", NULL, "Headset Mic" },
+};
+
+static int avs_rt5682_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+ struct snd_soc_jack *jack;
+ struct snd_soc_card *card = runtime->card;
+ int ret;
+
+ jack = snd_soc_card_get_drvdata(card);
+
+ /* Need to enable ASRC function for 24MHz mclk rate */
+ if ((avs_rt5682_quirk & AVS_RT5682_MCLK_EN) &&
+ (avs_rt5682_quirk & AVS_RT5682_MCLK_24MHZ)) {
+ rt5682_sel_asrc_clk_src(component, RT5682_DA_STEREO1_FILTER |
+ RT5682_AD_STEREO1_FILTER, RT5682_CLK_SEL_I2S1_ASRC);
+ }
+
+ /*
+ * Headset buttons map to the google Reference headset.
+ * These can be configured by userspace.
+ */
+ ret = snd_soc_card_jack_new(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0 |
+ SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, jack);
+ if (ret) {
+ dev_err(card->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(card->dev, "Headset Jack call-back failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+};
+
+static int
+avs_rt5682_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+ int clk_id, clk_freq;
+ int pll_out, ret;
+
+ if (avs_rt5682_quirk & AVS_RT5682_MCLK_EN) {
+ clk_id = RT5682_PLL1_S_MCLK;
+ if (avs_rt5682_quirk & AVS_RT5682_MCLK_24MHZ)
+ clk_freq = 24000000;
+ else
+ clk_freq = 19200000;
+ } else {
+ clk_id = RT5682_PLL1_S_BCLK1;
+ clk_freq = params_rate(params) * 50;
+ }
+
+ pll_out = params_rate(params) * 512;
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out);
+ if (ret < 0)
+ dev_err(runtime->dev, "snd_soc_dai_set_pll err = %d\n", ret);
+
+ /* Configure sysclk for codec */
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, pll_out, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ dev_err(runtime->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+
+ /* slot_width should equal or large than data length, set them be the same */
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2, params_width(params));
+ if (ret < 0) {
+ dev_err(runtime->dev, "set TDM slot err:%d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_ops avs_rt5682_ops = {
+ .hw_params = avs_rt5682_hw_params,
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-10EC5682:00");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt5682-aif1");
+ if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 1;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->init = avs_rt5682_codec_init;
+ dl->ops = &avs_rt5682_ops;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_capture = 1;
+ dl->dpcm_playback = 1;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ const int num_base = ARRAY_SIZE(card_base_routes);
+ const int num_dr = num_base + 2;
+ int idx;
+
+ dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+ idx = num_base;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ idx++;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Capture");
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ *routes = dr;
+ *num_routes = num_dr;
+
+ return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+ struct snd_soc_component *component;
+
+ for_each_card_components(card, component)
+ snd_soc_component_set_jack(component, jack, NULL);
+ return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+ struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+ return avs_card_set_jack(card, jack);
+}
+
+static int avs_rt5682_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct snd_soc_jack *jack;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int num_routes, ssp_port, ret;
+
+ if (pdev->id_entry && pdev->id_entry->driver_data)
+ avs_rt5682_quirk = (unsigned long)pdev->id_entry->driver_data;
+
+ dmi_check_system(avs_rt5682_quirk_table);
+ dev_dbg(dev, "avs_rt5682_quirk = %lx\n", avs_rt5682_quirk);
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm routes: %d", ret);
+ return ret;
+ }
+
+ jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!jack || !card)
+ return -ENOMEM;
+
+ card->name = "avs_rt5682";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->remove = avs_card_remove;
+ card->suspend_pre = avs_card_suspend_pre;
+ card->resume_post = avs_card_resume_post;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = routes;
+ card->num_dapm_routes = num_routes;
+ card->fully_routed = true;
+ snd_soc_card_set_drvdata(card, jack);
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_rt5682_driver = {
+ .probe = avs_rt5682_probe,
+ .driver = {
+ .name = "avs_rt5682",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_rt5682_driver)
+
+MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_rt5682");
diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c
new file mode 100644
index 000000000000..9f84c8ab3447
--- /dev/null
+++ b/sound/soc/intel/avs/boards/ssm4567.c
@@ -0,0 +1,271 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/nau8825.h"
+
+#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
+#define SKL_SSM_CODEC_DAI "ssm4567-hifi"
+
+static struct snd_soc_codec_conf card_codec_conf[] = {
+ {
+ .dlc = COMP_CODEC_CONF("i2c-INT343B:00"),
+ .name_prefix = "Left",
+ },
+ {
+ .dlc = COMP_CODEC_CONF("i2c-INT343B:01"),
+ .name_prefix = "Right",
+ },
+};
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Left Speaker"),
+ SOC_DAPM_PIN_SWITCH("Right Speaker"),
+};
+
+static int
+platform_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event)
+{
+ struct snd_soc_dapm_context *dapm = w->dapm;
+ struct snd_soc_card *card = dapm->card;
+ struct snd_soc_dai *codec_dai;
+ int ret;
+
+ codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI);
+ if (!codec_dai) {
+ dev_err(card->dev, "Codec dai not found\n");
+ return -EINVAL;
+ }
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_MCLK, 24000000,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ dev_err(card->dev, "set sysclk err = %d\n", ret);
+ } else {
+ ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ dev_err(card->dev, "set sysclk err = %d\n", ret);
+ }
+
+ return ret;
+}
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_SPK("Left Speaker", NULL),
+ SND_SOC_DAPM_SPK("Right Speaker", NULL),
+ SND_SOC_DAPM_SPK("DP1", NULL),
+ SND_SOC_DAPM_SPK("DP2", NULL),
+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+ {"Left Speaker", NULL, "Left OUT"},
+ {"Right Speaker", NULL, "Right OUT"},
+};
+
+static int avs_ssm4567_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+ int ret;
+
+ /* Slot 1 for left */
+ ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(runtime, 0), 0x01, 0x01, 2, 48);
+ if (ret < 0)
+ return ret;
+
+ /* Slot 2 for right */
+ ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(runtime, 1), 0x02, 0x02, 2, 48);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int
+avs_ssm4567_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate, *channels;
+ struct snd_mask *fmt;
+
+ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* The ADSP will covert the FE rate to 48k, stereo */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSP0 to 24 bit */
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+ return 0;
+}
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs[0].name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343B:00");
+ dl->codecs[0].dai_name = devm_kasprintf(dev, GFP_KERNEL, "ssm4567-hifi");
+ dl->codecs[1].name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343B:01");
+ dl->codecs[1].dai_name = devm_kasprintf(dev, GFP_KERNEL, "ssm4567-hifi");
+ if (!dl->cpus->dai_name || !dl->codecs[0].name || !dl->codecs[0].dai_name ||
+ !dl->codecs[1].name || !dl->codecs[1].dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 2;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->init = avs_ssm4567_codec_init;
+ dl->be_hw_params_fixup = avs_ssm4567_be_fixup;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_capture = 1;
+ dl->dpcm_playback = 1;
+ dl->ignore_pmdown_time = 1;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ const int num_base = ARRAY_SIZE(card_base_routes);
+ const int num_dr = num_base + 4;
+ int idx;
+
+ dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+ idx = num_base;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Left Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ idx++;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Right Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ idx++;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "Left Capture Sense");
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ idx++;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "Right Capture Sense");
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ *routes = dr;
+ *num_routes = num_dr;
+
+ return 0;
+}
+
+static int avs_ssm4567_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int num_routes, ssp_port, ret;
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm routes: %d", ret);
+ return ret;
+ }
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ card->name = "avs_ssm4567-adi";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->codec_conf = card_codec_conf;
+ card->num_configs = ARRAY_SIZE(card_codec_conf);
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = routes;
+ card->num_dapm_routes = num_routes;
+ card->fully_routed = true;
+ card->disable_route_checks = true;
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_ssm4567_driver = {
+ .probe = avs_ssm4567_probe,
+ .driver = {
+ .name = "avs_ssm4567",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_ssm4567_driver)
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_ssm4567");
diff --git a/sound/soc/intel/avs/cldma.c b/sound/soc/intel/avs/cldma.c
index d100c6ba4d8a..d7a9390b5e48 100644
--- a/sound/soc/intel/avs/cldma.c
+++ b/sound/soc/intel/avs/cldma.c
@@ -176,17 +176,17 @@ int hda_cldma_reset(struct hda_cldma *cl)
return ret;
}
- snd_hdac_stream_updateb(cl, SD_CTL, 1, 1);
- ret = snd_hdac_stream_readb_poll(cl, SD_CTL, reg, (reg & 1), AVS_CL_OP_INTERVAL_US,
- AVS_CL_OP_TIMEOUT_US);
+ snd_hdac_stream_updateb(cl, SD_CTL, SD_CTL_STREAM_RESET, SD_CTL_STREAM_RESET);
+ ret = snd_hdac_stream_readb_poll(cl, SD_CTL, reg, (reg & SD_CTL_STREAM_RESET),
+ AVS_CL_OP_INTERVAL_US, AVS_CL_OP_TIMEOUT_US);
if (ret < 0) {
dev_err(cl->dev, "cldma set SRST failed: %d\n", ret);
return ret;
}
- snd_hdac_stream_updateb(cl, SD_CTL, 1, 0);
- ret = snd_hdac_stream_readb_poll(cl, SD_CTL, reg, !(reg & 1), AVS_CL_OP_INTERVAL_US,
- AVS_CL_OP_TIMEOUT_US);
+ snd_hdac_stream_updateb(cl, SD_CTL, SD_CTL_STREAM_RESET, 0);
+ ret = snd_hdac_stream_readb_poll(cl, SD_CTL, reg, !(reg & SD_CTL_STREAM_RESET),
+ AVS_CL_OP_INTERVAL_US, AVS_CL_OP_TIMEOUT_US);
if (ret < 0) {
dev_err(cl->dev, "cldma unset SRST failed: %d\n", ret);
return ret;
diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c
index 3a0997c3af2b..c50c20fd681a 100644
--- a/sound/soc/intel/avs/core.c
+++ b/sound/soc/intel/avs/core.c
@@ -23,6 +23,7 @@
#include <sound/hdaudio_ext.h>
#include <sound/intel-dsp-config.h>
#include <sound/intel-nhlt.h>
+#include "../../codecs/hda.h"
#include "avs.h"
#include "cldma.h"
@@ -356,7 +357,7 @@ static int avs_bus_init(struct avs_dev *adev, struct pci_dev *pci, const struct
struct device *dev = &pci->dev;
int ret;
- ret = snd_hdac_ext_bus_init(&bus->core, dev, NULL, NULL);
+ ret = snd_hdac_ext_bus_init(&bus->core, dev, NULL, &soc_hda_ext_bus_ops);
if (ret < 0)
return ret;
@@ -439,12 +440,9 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
if (bus->mlcap)
snd_hdac_ext_bus_get_ml_capabilities(bus);
- if (!dma_set_mask(dev, DMA_BIT_MASK(64))) {
- dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
- } else {
- dma_set_mask(dev, DMA_BIT_MASK(32));
- dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
- }
+ if (!dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)))
+ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+ dma_set_max_seg_size(dev, UINT_MAX);
ret = avs_hdac_bus_init_streams(bus);
if (ret < 0) {
@@ -555,6 +553,7 @@ static int __maybe_unused avs_suspend_common(struct avs_dev *adev)
return AVS_IPC_RET(ret);
}
+ avs_ipc_block(adev->ipc);
avs_dsp_op(adev, int_control, false);
snd_hdac_ext_bus_ppcap_int_enable(bus, false);
diff --git a/sound/soc/intel/avs/dsp.c b/sound/soc/intel/avs/dsp.c
index 06d2f7af520f..b881100d3e02 100644
--- a/sound/soc/intel/avs/dsp.c
+++ b/sound/soc/intel/avs/dsp.c
@@ -13,6 +13,7 @@
#define AVS_ADSPCS_INTERVAL_US 500
#define AVS_ADSPCS_TIMEOUT_US 50000
+#define AVS_ADSPCS_DELAY_US 1000
int avs_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power)
{
@@ -26,6 +27,8 @@ int avs_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power)
value = power ? mask : 0;
snd_hdac_adsp_updatel(adev, AVS_ADSP_REG_ADSPCS, mask, value);
+ /* Delay the polling to avoid false positives. */
+ usleep_range(AVS_ADSPCS_DELAY_US, 2 * AVS_ADSPCS_DELAY_US);
mask = AVS_ADSPCS_CPA_MASK(core_mask);
value = power ? mask : 0;
@@ -82,11 +85,15 @@ int avs_dsp_core_stall(struct avs_dev *adev, u32 core_mask, bool stall)
reg, (reg & mask) == value,
AVS_ADSPCS_INTERVAL_US,
AVS_ADSPCS_TIMEOUT_US);
- if (ret)
+ if (ret) {
dev_err(adev->dev, "core_mask %d %sstall failed: %d\n",
core_mask, stall ? "" : "un", ret);
+ return ret;
+ }
- return ret;
+ /* Give HW time to propagate the change. */
+ usleep_range(AVS_ADSPCS_DELAY_US, 2 * AVS_ADSPCS_DELAY_US);
+ return 0;
}
int avs_dsp_core_enable(struct avs_dev *adev, u32 core_mask)
diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c
index d755ba8b8518..020d85c7520d 100644
--- a/sound/soc/intel/avs/ipc.c
+++ b/sound/soc/intel/avs/ipc.c
@@ -480,6 +480,7 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request
ret = ipc->rx.rsp.status;
if (reply) {
reply->header = ipc->rx.header;
+ reply->size = ipc->rx.size;
if (reply->data && ipc->rx.size)
memcpy(reply->data, ipc->rx.data, reply->size);
}
diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c
index 542fd44aa501..9e3f8ff33a87 100644
--- a/sound/soc/intel/avs/loader.c
+++ b/sound/soc/intel/avs/loader.c
@@ -27,8 +27,8 @@
#define APL_ROM_INIT_RETRIES 3
#define AVS_FW_INIT_POLLING_US 500
-#define AVS_FW_INIT_TIMEOUT_US 3000000
#define AVS_FW_INIT_TIMEOUT_MS 3000
+#define AVS_FW_INIT_TIMEOUT_US (AVS_FW_INIT_TIMEOUT_MS * 1000)
#define AVS_CLDMA_START_DELAY_MS 100
diff --git a/sound/soc/intel/avs/messages.c b/sound/soc/intel/avs/messages.c
index 6404fce8cde4..d4bcee1aabcf 100644
--- a/sound/soc/intel/avs/messages.c
+++ b/sound/soc/intel/avs/messages.c
@@ -59,7 +59,7 @@ int avs_ipc_unload_modules(struct avs_dev *adev, u16 *mod_ids, u32 num_mod_ids)
request.data = mod_ids;
request.size = sizeof(*mod_ids) * num_mod_ids;
- ret = avs_dsp_send_msg_timeout(adev, &request, NULL, AVS_CL_TIMEOUT_MS);
+ ret = avs_dsp_send_msg(adev, &request, NULL);
if (ret)
avs_ipc_err(adev, &request, "unload multiple modules", ret);
@@ -378,7 +378,6 @@ int avs_ipc_get_large_config(struct avs_dev *adev, u16 module_id, u8 instance_id
union avs_module_msg msg = AVS_MODULE_REQUEST(LARGE_CONFIG_GET);
struct avs_ipc_msg request;
struct avs_ipc_msg reply = {{0}};
- size_t size;
void *buf;
int ret;
@@ -406,15 +405,14 @@ int avs_ipc_get_large_config(struct avs_dev *adev, u16 module_id, u8 instance_id
return ret;
}
- size = reply.rsp.ext.large_config.data_off_size;
- buf = krealloc(reply.data, size, GFP_KERNEL);
+ buf = krealloc(reply.data, reply.size, GFP_KERNEL);
if (!buf) {
kfree(reply.data);
return -ENOMEM;
}
*reply_data = buf;
- *reply_size = size;
+ *reply_size = reply.size;
return 0;
}
@@ -476,6 +474,9 @@ int avs_ipc_get_fw_config(struct avs_dev *adev, struct avs_fw_cfg *cfg)
&payload, &payload_size);
if (ret)
return ret;
+ /* Non-zero payload expected for FIRMWARE_CONFIG. */
+ if (!payload_size)
+ return -EREMOTEIO;
while (offset < payload_size) {
tlv = (struct avs_tlv *)(payload + offset);
@@ -561,6 +562,7 @@ int avs_ipc_get_fw_config(struct avs_dev *adev, struct avs_fw_cfg *cfg)
case AVS_FW_CFG_DMA_BUFFER_CONFIG:
case AVS_FW_CFG_SCHEDULER_CONFIG:
case AVS_FW_CFG_CLOCKS_CONFIG:
+ case AVS_FW_CFG_RESERVED:
break;
default:
@@ -589,6 +591,9 @@ int avs_ipc_get_hw_config(struct avs_dev *adev, struct avs_hw_cfg *cfg)
&payload, &payload_size);
if (ret)
return ret;
+ /* Non-zero payload expected for HARDWARE_CONFIG. */
+ if (!payload_size)
+ return -EREMOTEIO;
while (offset < payload_size) {
tlv = (struct avs_tlv *)(payload + offset);
@@ -672,6 +677,9 @@ int avs_ipc_get_modules_info(struct avs_dev *adev, struct avs_mods_info **info)
&payload, &payload_size);
if (ret)
return ret;
+ /* Non-zero payload expected for MODULES_INFO. */
+ if (!payload_size)
+ return -EREMOTEIO;
*info = (struct avs_mods_info *)payload;
return 0;
diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c
index 3d46dd5e5bc4..ce157a8d6552 100644
--- a/sound/soc/intel/avs/path.c
+++ b/sound/soc/intel/avs/path.c
@@ -449,35 +449,39 @@ static int avs_modext_create(struct avs_dev *adev, struct avs_path_module *mod)
return ret;
}
+static int avs_probe_create(struct avs_dev *adev, struct avs_path_module *mod)
+{
+ dev_err(adev->dev, "Probe module can't be instantiated by topology");
+ return -EINVAL;
+}
+
+struct avs_module_create {
+ guid_t *guid;
+ int (*create)(struct avs_dev *adev, struct avs_path_module *mod);
+};
+
+static struct avs_module_create avs_module_create[] = {
+ { &AVS_MIXIN_MOD_UUID, avs_modbase_create },
+ { &AVS_MIXOUT_MOD_UUID, avs_modbase_create },
+ { &AVS_KPBUFF_MOD_UUID, avs_modbase_create },
+ { &AVS_COPIER_MOD_UUID, avs_copier_create },
+ { &AVS_MICSEL_MOD_UUID, avs_micsel_create },
+ { &AVS_MUX_MOD_UUID, avs_mux_create },
+ { &AVS_UPDWMIX_MOD_UUID, avs_updown_mix_create },
+ { &AVS_SRCINTC_MOD_UUID, avs_src_create },
+ { &AVS_AEC_MOD_UUID, avs_aec_create },
+ { &AVS_ASRC_MOD_UUID, avs_asrc_create },
+ { &AVS_INTELWOV_MOD_UUID, avs_wov_create },
+ { &AVS_PROBE_MOD_UUID, avs_probe_create },
+};
+
static int avs_path_module_type_create(struct avs_dev *adev, struct avs_path_module *mod)
{
const guid_t *type = &mod->template->cfg_ext->type;
- if (guid_equal(type, &AVS_MIXIN_MOD_UUID) ||
- guid_equal(type, &AVS_MIXOUT_MOD_UUID) ||
- guid_equal(type, &AVS_KPBUFF_MOD_UUID))
- return avs_modbase_create(adev, mod);
- if (guid_equal(type, &AVS_COPIER_MOD_UUID))
- return avs_copier_create(adev, mod);
- if (guid_equal(type, &AVS_MICSEL_MOD_UUID))
- return avs_micsel_create(adev, mod);
- if (guid_equal(type, &AVS_MUX_MOD_UUID))
- return avs_mux_create(adev, mod);
- if (guid_equal(type, &AVS_UPDWMIX_MOD_UUID))
- return avs_updown_mix_create(adev, mod);
- if (guid_equal(type, &AVS_SRCINTC_MOD_UUID))
- return avs_src_create(adev, mod);
- if (guid_equal(type, &AVS_AEC_MOD_UUID))
- return avs_aec_create(adev, mod);
- if (guid_equal(type, &AVS_ASRC_MOD_UUID))
- return avs_asrc_create(adev, mod);
- if (guid_equal(type, &AVS_INTELWOV_MOD_UUID))
- return avs_wov_create(adev, mod);
-
- if (guid_equal(type, &AVS_PROBE_MOD_UUID)) {
- dev_err(adev->dev, "Probe module can't be instantiated by topology");
- return -EINVAL;
- }
+ for (int i = 0; i < ARRAY_SIZE(avs_module_create); i++)
+ if (guid_equal(type, avs_module_create[i].guid))
+ return avs_module_create[i].create(adev, mod);
return avs_modext_create(adev, mod);
}
diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c
index 668f533578a6..f21b0cdd3206 100644
--- a/sound/soc/intel/avs/pcm.c
+++ b/sound/soc/intel/avs/pcm.c
@@ -846,7 +846,6 @@ static const struct snd_soc_component_driver avs_component_driver = {
.pcm_construct = avs_component_construct,
.module_get_upon_open = 1, /* increment refcount when a pcm is opened */
.topology_name_prefix = "intel/avs",
- .non_legacy_dai_naming = true,
};
static int avs_soc_component_register(struct device *dev, const char *name,
@@ -1172,7 +1171,6 @@ static const struct snd_soc_component_driver avs_hda_component_driver = {
.remove_order = SND_SOC_COMP_ORDER_EARLY,
.module_get_upon_open = 1,
.topology_name_prefix = "intel/avs",
- .non_legacy_dai_naming = true,
};
int avs_hda_platform_register(struct avs_dev *adev, const char *name)
diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c
index 6a06fe387d13..8a9f9fc48938 100644
--- a/sound/soc/intel/avs/topology.c
+++ b/sound/soc/intel/avs/topology.c
@@ -808,6 +808,30 @@ static const struct avs_tplg_token_parser pin_format_parsers[] = {
},
};
+static void
+assign_copier_gtw_instance(struct snd_soc_component *comp, struct avs_tplg_modcfg_ext *cfg)
+{
+ struct snd_soc_acpi_mach *mach;
+
+ if (!guid_equal(&cfg->type, &AVS_COPIER_MOD_UUID))
+ return;
+
+ /* Only I2S boards assign port instance in ->i2s_link_mask. */
+ switch (cfg->copier.dma_type) {
+ case AVS_DMA_I2S_LINK_OUTPUT:
+ case AVS_DMA_I2S_LINK_INPUT:
+ break;
+ default:
+ return;
+ }
+
+ mach = dev_get_platdata(comp->card->dev);
+
+ /* Automatic assignment only when board describes single SSP. */
+ if (hweight_long(mach->mach_params.i2s_link_mask) == 1 && !cfg->copier.vindex.i2s.instance)
+ cfg->copier.vindex.i2s.instance = __ffs(mach->mach_params.i2s_link_mask);
+}
+
static int avs_tplg_parse_modcfg_ext(struct snd_soc_component *comp,
struct avs_tplg_modcfg_ext *cfg,
struct snd_soc_tplg_vendor_array *tuples,
@@ -827,6 +851,9 @@ static int avs_tplg_parse_modcfg_ext(struct snd_soc_component *comp,
if (ret)
return ret;
+ /* Update copier gateway based on board's i2s_link_mask. */
+ assign_copier_gtw_instance(comp, cfg);
+
block_size -= esize;
/* Parse trailing in/out pin formats if any. */
if (block_size) {
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index f3873b5bea87..aa12d7e3dd2f 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -41,7 +41,7 @@ config SND_SOC_INTEL_SOF_CIRRUS_COMMON
if SND_SOC_INTEL_CATPT
config SND_SOC_INTEL_HASWELL_MACH
- tristate "Haswell Lynxpoint"
+ tristate "Haswell with RT5640 I2S codec"
depends on I2C
depends on I2C_DESIGNWARE_PLATFORM || COMPILE_TEST
depends on X86_INTEL_LPSS || COMPILE_TEST
@@ -85,7 +85,7 @@ config SND_SOC_INTEL_BDW_RT5677_MACH
If unsure select "N".
config SND_SOC_INTEL_BROADWELL_MACH
- tristate "Broadwell Wildcatpoint"
+ tristate "Broadwell with RT286 I2S codec"
depends on I2C
depends on I2C_DESIGNWARE_PLATFORM || COMPILE_TEST
depends on X86_INTEL_LPSS || COMPILE_TEST
@@ -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
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index 40c0c3d1c500..eea1e26acfda 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-soc-sst-haswell-objs := haswell.o
+snd-soc-sst-haswell-objs := hsw_rt5640.o
snd-soc-sst-bdw-rt5650-mach-objs := bdw-rt5650.o
snd-soc-sst-bdw-rt5677-mach-objs := bdw-rt5677.o
-snd-soc-sst-broadwell-objs := broadwell.o
+snd-soc-sst-broadwell-objs := bdw_rt286.o
snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o
snd-soc-sst-bxt-rt298-objs := bxt_rt298.o
snd-soc-sst-sof-pcm512x-objs := sof_pcm512x.o
diff --git a/sound/soc/intel/boards/bdw-rt5650.c b/sound/soc/intel/boards/bdw-rt5650.c
index aae857fdcdb8..67c3f49b924c 100644
--- a/sound/soc/intel/boards/bdw-rt5650.c
+++ b/sound/soc/intel/boards/bdw-rt5650.c
@@ -249,6 +249,7 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = {
/* SSP0 - Codec */
.name = "Codec",
.id = 0,
+ .nonatomic = 1,
.no_pcm = 1,
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBC_CFC,
diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c
index d0ecbba2febe..31488702768e 100644
--- a/sound/soc/intel/boards/bdw-rt5677.c
+++ b/sound/soc/intel/boards/bdw-rt5677.c
@@ -349,6 +349,7 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = {
/* SSP0 - Codec */
.name = "Codec",
.id = 0,
+ .nonatomic = 1,
.no_pcm = 1,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBC_CFC,
diff --git a/sound/soc/intel/boards/bdw_rt286.c b/sound/soc/intel/boards/bdw_rt286.c
new file mode 100644
index 000000000000..6b76df0e7c9b
--- /dev/null
+++ b/sound/soc/intel/boards/bdw_rt286.c
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Sound card driver for Intel Broadwell Wildcat Point with Realtek 286
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../codecs/rt286.h"
+
+static struct snd_soc_jack card_headset;
+
+static struct snd_soc_jack_pin card_headset_pins[] = {
+ {
+ .pin = "Mic Jack",
+ .mask = SND_JACK_MICROPHONE,
+ },
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+};
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_MIC("DMIC1", NULL),
+ SND_SOC_DAPM_MIC("DMIC2", NULL),
+ SND_SOC_DAPM_LINE("Line Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route card_routes[] = {
+ {"Speaker", NULL, "SPOR"},
+ {"Speaker", NULL, "SPOL"},
+
+ {"Headphone Jack", NULL, "HPO Pin"},
+
+ {"MIC1", NULL, "Mic Jack"},
+ {"LINE1", NULL, "Line Jack"},
+
+ {"DMIC1 Pin", NULL, "DMIC1"},
+ {"DMIC2 Pin", NULL, "DMIC2"},
+
+ /* CODEC BE connections */
+ {"SSP0 CODEC IN", NULL, "AIF1 Capture"},
+ {"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
+};
+
+static int codec_link_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_component *codec = asoc_rtd_to_codec(rtd, 0)->component;
+ int ret;
+
+ ret = snd_soc_card_jack_new_pins(rtd->card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0,
+ &card_headset, card_headset_pins,
+ ARRAY_SIZE(card_headset_pins));
+ if (ret)
+ return ret;
+
+ return snd_soc_component_set_jack(codec, &card_headset, NULL);
+}
+
+static int codec_link_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+
+ /* The ADSP will convert the FE rate to 48kHz, stereo. */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+ /* Set SSP0 to 16 bit. */
+ params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
+
+ return 0;
+}
+
+static int codec_link_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);
+ int ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(rtd->dev, "set codec sysclk failed: %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static const struct snd_soc_ops codec_link_ops = {
+ .hw_params = codec_link_hw_params,
+};
+
+SND_SOC_DAILINK_DEF(system, DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
+SND_SOC_DAILINK_DEF(offload0, DAILINK_COMP_ARRAY(COMP_CPU("Offload0 Pin")));
+SND_SOC_DAILINK_DEF(offload1, DAILINK_COMP_ARRAY(COMP_CPU("Offload1 Pin")));
+SND_SOC_DAILINK_DEF(loopback, DAILINK_COMP_ARRAY(COMP_CPU("Loopback Pin")));
+
+SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));
+SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio")));
+SND_SOC_DAILINK_DEF(codec, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT343A:00", "rt286-aif1")));
+SND_SOC_DAILINK_DEF(ssp0_port, DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
+
+static struct snd_soc_dai_link card_dai_links[] = {
+ /* Front End DAI links */
+ {
+ .name = "System PCM",
+ .stream_name = "System Playback/Capture",
+ .nonatomic = 1,
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(system, dummy, platform),
+ },
+ {
+ .name = "Offload0",
+ .stream_name = "Offload0 Playback",
+ .nonatomic = 1,
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(offload0, dummy, platform),
+ },
+ {
+ .name = "Offload1",
+ .stream_name = "Offload1 Playback",
+ .nonatomic = 1,
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(offload1, dummy, platform),
+ },
+ {
+ .name = "Loopback PCM",
+ .stream_name = "Loopback",
+ .nonatomic = 1,
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(loopback, dummy, platform),
+ },
+ /* Back End DAI links */
+ {
+ /* SSP0 - Codec */
+ .name = "Codec",
+ .id = 0,
+ .nonatomic = 1,
+ .no_pcm = 1,
+ .init = codec_link_init,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC,
+ .ignore_pmdown_time = 1,
+ .be_hw_params_fixup = codec_link_hw_params_fixup,
+ .ops = &codec_link_ops,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(ssp0_port, codec, platform),
+ },
+};
+
+static void bdw_rt286_disable_jack(struct snd_soc_card *card)
+{
+ struct snd_soc_component *component;
+
+ for_each_card_components(card, component) {
+ if (!strcmp(component->name, "i2c-INT343A:00")) {
+ dev_dbg(component->dev, "disabling jack detect before going to suspend.\n");
+ snd_soc_component_set_jack(component, NULL, NULL);
+ break;
+ }
+ }
+}
+
+static int bdw_rt286_suspend(struct snd_soc_card *card)
+{
+ bdw_rt286_disable_jack(card);
+
+ return 0;
+}
+
+static int bdw_rt286_resume(struct snd_soc_card *card)
+{
+ struct snd_soc_component *component;
+
+ for_each_card_components(card, component) {
+ if (!strcmp(component->name, "i2c-INT343A:00")) {
+ dev_dbg(component->dev, "enabling jack detect for resume.\n");
+ snd_soc_component_set_jack(component, &card_headset, NULL);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static struct snd_soc_card bdw_rt286_card = {
+ .owner = THIS_MODULE,
+ .dai_link = card_dai_links,
+ .num_links = ARRAY_SIZE(card_dai_links),
+ .controls = card_controls,
+ .num_controls = ARRAY_SIZE(card_controls),
+ .dapm_widgets = card_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(card_widgets),
+ .dapm_routes = card_routes,
+ .num_dapm_routes = ARRAY_SIZE(card_routes),
+ .fully_routed = true,
+ .suspend_pre = bdw_rt286_suspend,
+ .resume_post = bdw_rt286_resume,
+};
+
+/* Use space before codec name to simplify card ID, and simplify driver name. */
+#define SOF_CARD_NAME "bdw rt286" /* card name will be 'sof-bdw rt286' */
+#define SOF_DRIVER_NAME "SOF"
+
+#define CARD_NAME "broadwell-rt286"
+
+static int bdw_rt286_probe(struct platform_device *pdev)
+{
+ struct snd_soc_acpi_mach *mach;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ bdw_rt286_card.dev = dev;
+ mach = dev_get_platdata(dev);
+
+ ret = snd_soc_fixup_dai_links_platform_name(&bdw_rt286_card, mach->mach_params.platform);
+ if (ret)
+ return ret;
+
+ if (snd_soc_acpi_sof_parent(dev)) {
+ bdw_rt286_card.name = SOF_CARD_NAME;
+ bdw_rt286_card.driver_name = SOF_DRIVER_NAME;
+ } else {
+ bdw_rt286_card.name = CARD_NAME;
+ }
+
+ return devm_snd_soc_register_card(dev, &bdw_rt286_card);
+}
+
+static int bdw_rt286_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+ bdw_rt286_disable_jack(card);
+
+ return 0;
+}
+
+static struct platform_driver bdw_rt286_driver = {
+ .probe = bdw_rt286_probe,
+ .remove = bdw_rt286_remove,
+ .driver = {
+ .name = "bdw_rt286",
+ .pm = &snd_soc_pm_ops
+ },
+};
+
+module_platform_driver(bdw_rt286_driver)
+
+MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
+MODULE_DESCRIPTION("Sound card driver for Intel Broadwell Wildcat Point with Realtek 286");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:bdw_rt286");
diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c
deleted file mode 100644
index c30a9dca6801..000000000000
--- a/sound/soc/intel/boards/broadwell.c
+++ /dev/null
@@ -1,336 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Intel Broadwell Wildcatpoint SST Audio
- *
- * Copyright (C) 2013, Intel Corporation. All rights reserved.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/jack.h>
-#include <sound/pcm_params.h>
-#include <sound/soc-acpi.h>
-
-#include "../../codecs/rt286.h"
-
-static struct snd_soc_jack broadwell_headset;
-/* Headset jack detection DAPM pins */
-static struct snd_soc_jack_pin broadwell_headset_pins[] = {
- {
- .pin = "Mic Jack",
- .mask = SND_JACK_MICROPHONE,
- },
- {
- .pin = "Headphone Jack",
- .mask = SND_JACK_HEADPHONE,
- },
-};
-
-static const struct snd_kcontrol_new broadwell_controls[] = {
- SOC_DAPM_PIN_SWITCH("Speaker"),
- SOC_DAPM_PIN_SWITCH("Headphone Jack"),
-};
-
-static const struct snd_soc_dapm_widget broadwell_widgets[] = {
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_SPK("Speaker", NULL),
- SND_SOC_DAPM_MIC("Mic Jack", NULL),
- SND_SOC_DAPM_MIC("DMIC1", NULL),
- SND_SOC_DAPM_MIC("DMIC2", NULL),
- SND_SOC_DAPM_LINE("Line Jack", NULL),
-};
-
-static const struct snd_soc_dapm_route broadwell_rt286_map[] = {
-
- /* speaker */
- {"Speaker", NULL, "SPOR"},
- {"Speaker", NULL, "SPOL"},
-
- /* HP jack connectors - unknown if we have jack deteck */
- {"Headphone Jack", NULL, "HPO Pin"},
-
- /* other jacks */
- {"MIC1", NULL, "Mic Jack"},
- {"LINE1", NULL, "Line Jack"},
-
- /* digital mics */
- {"DMIC1 Pin", NULL, "DMIC1"},
- {"DMIC2 Pin", NULL, "DMIC2"},
-
- /* CODEC BE connections */
- {"SSP0 CODEC IN", NULL, "AIF1 Capture"},
- {"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
-};
-
-static int broadwell_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
- int ret = 0;
- ret = snd_soc_card_jack_new_pins(rtd->card, "Headset",
- SND_JACK_HEADSET | SND_JACK_BTN_0, &broadwell_headset,
- broadwell_headset_pins, ARRAY_SIZE(broadwell_headset_pins));
- if (ret)
- return ret;
-
- rt286_mic_detect(component, &broadwell_headset);
- return 0;
-}
-
-
-static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *chan = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
-
- /* The ADSP will covert the FE rate to 48k, stereo */
- rate->min = rate->max = 48000;
- chan->min = chan->max = 2;
-
- /* set SSP0 to 16 bit */
- params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
- return 0;
-}
-
-static int broadwell_rt286_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);
- int ret;
-
- ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000,
- SND_SOC_CLOCK_IN);
-
- if (ret < 0) {
- dev_err(rtd->dev, "can't set codec sysclk configuration\n");
- return ret;
- }
-
- return ret;
-}
-
-static const struct snd_soc_ops broadwell_rt286_ops = {
- .hw_params = broadwell_rt286_hw_params,
-};
-
-static const unsigned int channels[] = {
- 2,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_channels = {
- .count = ARRAY_SIZE(channels),
- .list = channels,
- .mask = 0,
-};
-
-static int broadwell_fe_startup(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- /* Board supports stereo configuration only */
- runtime->hw.channels_max = 2;
- return snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels);
-}
-
-static const struct snd_soc_ops broadwell_fe_ops = {
- .startup = broadwell_fe_startup,
-};
-
-SND_SOC_DAILINK_DEF(system,
- DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
-
-SND_SOC_DAILINK_DEF(offload0,
- DAILINK_COMP_ARRAY(COMP_CPU("Offload0 Pin")));
-
-SND_SOC_DAILINK_DEF(offload1,
- DAILINK_COMP_ARRAY(COMP_CPU("Offload1 Pin")));
-
-SND_SOC_DAILINK_DEF(loopback,
- DAILINK_COMP_ARRAY(COMP_CPU("Loopback Pin")));
-
-SND_SOC_DAILINK_DEF(dummy,
- DAILINK_COMP_ARRAY(COMP_DUMMY()));
-
-SND_SOC_DAILINK_DEF(platform,
- DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio")));
-
-SND_SOC_DAILINK_DEF(codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT343A:00", "rt286-aif1")));
-
-SND_SOC_DAILINK_DEF(ssp0_port,
- DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
-
-/* broadwell digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link broadwell_rt286_dais[] = {
- /* Front End DAI links */
- {
- .name = "System PCM",
- .stream_name = "System Playback/Capture",
- .nonatomic = 1,
- .dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .ops = &broadwell_fe_ops,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- {
- .name = "Offload0",
- .stream_name = "Offload0 Playback",
- .nonatomic = 1,
- .dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- SND_SOC_DAILINK_REG(offload0, dummy, platform),
- },
- {
- .name = "Offload1",
- .stream_name = "Offload1 Playback",
- .nonatomic = 1,
- .dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- SND_SOC_DAILINK_REG(offload1, dummy, platform),
- },
- {
- .name = "Loopback PCM",
- .stream_name = "Loopback",
- .nonatomic = 1,
- .dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(loopback, dummy, platform),
- },
- /* Back End DAI links */
- {
- /* SSP0 - Codec */
- .name = "Codec",
- .id = 0,
- .no_pcm = 1,
- .init = broadwell_rt286_codec_init,
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .ignore_pmdown_time = 1,
- .be_hw_params_fixup = broadwell_ssp0_fixup,
- .ops = &broadwell_rt286_ops,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(ssp0_port, codec, platform),
- },
-};
-
-static int broadwell_disable_jack(struct snd_soc_card *card)
-{
- struct snd_soc_component *component;
-
- for_each_card_components(card, component) {
- if (!strcmp(component->name, "i2c-INT343A:00")) {
-
- dev_dbg(component->dev, "disabling jack detect before going to suspend.\n");
- rt286_mic_detect(component, NULL);
- break;
- }
- }
-
- return 0;
-}
-
-static int broadwell_suspend(struct snd_soc_card *card)
-{
- return broadwell_disable_jack(card);
-}
-
-static int broadwell_resume(struct snd_soc_card *card){
- struct snd_soc_component *component;
-
- for_each_card_components(card, component) {
- if (!strcmp(component->name, "i2c-INT343A:00")) {
-
- dev_dbg(component->dev, "enabling jack detect for resume.\n");
- rt286_mic_detect(component, &broadwell_headset);
- break;
- }
- }
- return 0;
-}
-
-/* use space before codec name to simplify card ID, and simplify driver name */
-#define SOF_CARD_NAME "bdw rt286" /* card name will be 'sof-bdw rt286' */
-#define SOF_DRIVER_NAME "SOF"
-
-#define CARD_NAME "broadwell-rt286"
-#define DRIVER_NAME NULL /* card name will be used for driver name */
-
-/* broadwell audio machine driver for WPT + RT286S */
-static struct snd_soc_card broadwell_rt286 = {
- .owner = THIS_MODULE,
- .dai_link = broadwell_rt286_dais,
- .num_links = ARRAY_SIZE(broadwell_rt286_dais),
- .controls = broadwell_controls,
- .num_controls = ARRAY_SIZE(broadwell_controls),
- .dapm_widgets = broadwell_widgets,
- .num_dapm_widgets = ARRAY_SIZE(broadwell_widgets),
- .dapm_routes = broadwell_rt286_map,
- .num_dapm_routes = ARRAY_SIZE(broadwell_rt286_map),
- .fully_routed = true,
- .suspend_pre = broadwell_suspend,
- .resume_post = broadwell_resume,
-};
-
-static int broadwell_audio_probe(struct platform_device *pdev)
-{
- struct snd_soc_acpi_mach *mach;
- int ret;
-
- broadwell_rt286.dev = &pdev->dev;
-
- /* override platform name, if required */
- mach = pdev->dev.platform_data;
- ret = snd_soc_fixup_dai_links_platform_name(&broadwell_rt286,
- mach->mach_params.platform);
- if (ret)
- return ret;
-
- /* set card and driver name */
- if (snd_soc_acpi_sof_parent(&pdev->dev)) {
- broadwell_rt286.name = SOF_CARD_NAME;
- broadwell_rt286.driver_name = SOF_DRIVER_NAME;
- } else {
- broadwell_rt286.name = CARD_NAME;
- broadwell_rt286.driver_name = DRIVER_NAME;
- }
-
- return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286);
-}
-
-static int broadwell_audio_remove(struct platform_device *pdev)
-{
- struct snd_soc_card *card = platform_get_drvdata(pdev);
-
- return broadwell_disable_jack(card);
-}
-
-static struct platform_driver broadwell_audio = {
- .probe = broadwell_audio_probe,
- .remove = broadwell_audio_remove,
- .driver = {
- .name = "broadwell-audio",
- .pm = &snd_soc_pm_ops
- },
-};
-
-module_platform_driver(broadwell_audio)
-
-/* Module information */
-MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
-MODULE_DESCRIPTION("Intel SST Audio for WPT/Broadwell");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:broadwell-audio");
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c
index d98376da425a..7c6c95e99ade 100644
--- a/sound/soc/intel/boards/bxt_da7219_max98357a.c
+++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c
@@ -186,6 +186,17 @@ static const struct snd_soc_dapm_route gemini_map[] = {
{"ssp2 Rx", NULL, "Capture"},
};
+static struct snd_soc_jack_pin jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -231,10 +242,12 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
* Headset buttons map to the google Reference headset.
* These can be configured by userspace.
*/
- ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
- &broxton_headset);
+ 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 | SND_JACK_LINEOUT,
+ &broxton_headset,
+ jack_pins,
+ ARRAY_SIZE(jack_pins));
if (ret) {
dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
return ret;
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c
index 75995d17597d..4bd93c3ba377 100644
--- a/sound/soc/intel/boards/bxt_rt298.c
+++ b/sound/soc/intel/boards/bxt_rt298.c
@@ -176,7 +176,7 @@ static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd)
if (ret)
return ret;
- rt298_mic_detect(component, &broxton_headset);
+ snd_soc_component_set_jack(component, &broxton_headset, NULL);
snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c
index 0eed68a11f7e..ae899866863e 100644
--- a/sound/soc/intel/boards/bytcht_cx2072x.c
+++ b/sound/soc/intel/boards/bytcht_cx2072x.c
@@ -126,7 +126,7 @@ static int byt_cht_cx2072x_fixup(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC);
+ SND_SOC_DAIFMT_BP_FP);
if (ret < 0) {
dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
return ret;
diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c
index eb19bf16afad..a0c8f1d3f8ce 100644
--- a/sound/soc/intel/boards/bytcht_da7213.c
+++ b/sound/soc/intel/boards/bytcht_da7213.c
@@ -81,7 +81,7 @@ static int codec_fixup(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC);
+ SND_SOC_DAIFMT_BP_FP);
if (ret < 0) {
dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
return ret;
diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c
index a08507783e44..6432b83f616f 100644
--- a/sound/soc/intel/boards/bytcht_es8316.c
+++ b/sound/soc/intel/boards/bytcht_es8316.c
@@ -265,7 +265,7 @@ static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC
+ SND_SOC_DAIFMT_BP_FP
);
if (ret < 0) {
dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
diff --git a/sound/soc/intel/boards/bytcht_nocodec.c b/sound/soc/intel/boards/bytcht_nocodec.c
index 115c2bcaabd4..7fc03f2efd35 100644
--- a/sound/soc/intel/boards/bytcht_nocodec.c
+++ b/sound/soc/intel/boards/bytcht_nocodec.c
@@ -61,7 +61,7 @@ static int codec_fixup(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC);
+ SND_SOC_DAIFMT_BP_FP);
if (ret < 0) {
dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index ed9fa1728722..fb9d9e271845 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -1413,7 +1413,7 @@ static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC);
+ SND_SOC_DAIFMT_BP_FP);
if (ret < 0) {
dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
return ret;
@@ -1636,7 +1636,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
* with the codec driver/pdata are non-existent
*/
- struct acpi_chan_package chan_package;
+ struct acpi_chan_package chan_package = { 0 };
/* format specified: 2 64-bit integers */
struct acpi_buffer format = {sizeof("NN"), "NN"};
diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c
index d467fcaa48ea..2beb686768f2 100644
--- a/sound/soc/intel/boards/bytcr_rt5651.c
+++ b/sound/soc/intel/boards/bytcr_rt5651.c
@@ -706,7 +706,7 @@ static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC
+ SND_SOC_DAIFMT_BP_FP
);
if (ret < 0) {
@@ -952,7 +952,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
* with the codec driver/pdata are non-existent
*/
- struct acpi_chan_package chan_package;
+ struct acpi_chan_package chan_package = { 0 };
/* format specified: 2 64-bit integers */
struct acpi_buffer format = {sizeof("NN"), "NN"};
diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c
index 330c0ace1638..45a6805787f5 100644
--- a/sound/soc/intel/boards/bytcr_wm5102.c
+++ b/sound/soc/intel/boards/bytcr_wm5102.c
@@ -265,7 +265,7 @@ static int byt_wm5102_codec_fixup(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC);
+ SND_SOC_DAIFMT_BP_FP);
if (ret) {
dev_err(rtd->dev, "Error setting format to I2S: %d\n", ret);
return ret;
diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
index a5160f27adea..64eb73525ee3 100644
--- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c
+++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
@@ -264,8 +264,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
return ret;
}
- fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBC_CFC;
+ fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_BP_FP;
ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), fmt);
if (ret < 0) {
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
index 45c301ea5e00..96501aed8bee 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
@@ -362,7 +362,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC
+ SND_SOC_DAIFMT_BP_FP
);
if (ret < 0) {
dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
@@ -372,7 +372,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_dai_set_fmt(asoc_rtd_to_codec(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC
+ SND_SOC_DAIFMT_BC_FC
);
if (ret < 0) {
dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
@@ -396,7 +396,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_dai_set_fmt(asoc_rtd_to_codec(rtd, 0),
SND_SOC_DAIFMT_DSP_B |
SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBC_CFC);
+ SND_SOC_DAIFMT_BC_FC);
if (ret < 0) {
dev_err(rtd->dev, "can't set format to TDM %d\n", ret);
return ret;
@@ -603,7 +603,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
* with the codec driver/pdata are non-existent
*/
- struct acpi_chan_package chan_package;
+ struct acpi_chan_package chan_package = { 0 };
/* format specified: 2 64-bit integers */
struct acpi_buffer format = {sizeof("NN"), "NN"};
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c
index c80324f34b1b..ca47f6476b07 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5672.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5672.c
@@ -300,7 +300,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC);
+ SND_SOC_DAIFMT_BP_FP);
if (ret < 0) {
dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
return ret;
diff --git a/sound/soc/intel/boards/cml_rt1011_rt5682.c b/sound/soc/intel/boards/cml_rt1011_rt5682.c
index a99f74a15b5f..20da83d9eece 100644
--- a/sound/soc/intel/boards/cml_rt1011_rt5682.c
+++ b/sound/soc/intel/boards/cml_rt1011_rt5682.c
@@ -121,6 +121,17 @@ static const struct snd_soc_dapm_route cml_rt1011_tt_map[] = {
{"TR Ext Spk", NULL, "TR SPO" },
};
+static struct snd_soc_jack_pin jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static int cml_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
{
struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
@@ -137,11 +148,13 @@ static int cml_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
* Headset buttons map to the google Reference headset.
* These can be configured by userspace.
*/
- ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0 |
- SND_JACK_BTN_1 | SND_JACK_BTN_2 |
- SND_JACK_BTN_3,
- &ctx->headset);
+ 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,
+ &ctx->headset,
+ jack_pins,
+ ARRAY_SIZE(jack_pins));
if (ret) {
dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
return ret;
diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c
index 170164baae7d..cf0f89db3e20 100644
--- a/sound/soc/intel/boards/glk_rt5682_max98357a.c
+++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c
@@ -78,6 +78,17 @@ static const struct snd_soc_dapm_widget geminilake_widgets[] = {
SND_SOC_DAPM_SPK("HDMI3", NULL),
};
+static struct snd_soc_jack_pin jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static const struct snd_soc_dapm_route geminilake_map[] = {
/* HP jack connectors - unknown if we have jack detection */
{ "Headphone Jack", NULL, "HPOL" },
@@ -173,10 +184,12 @@ static int geminilake_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
* Headset buttons map to the google Reference headset.
* These can be configured by userspace.
*/
- ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
- &ctx->geminilake_headset);
+ 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 | SND_JACK_LINEOUT,
+ &ctx->geminilake_headset,
+ jack_pins,
+ ARRAY_SIZE(jack_pins));
if (ret) {
dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
return ret;
diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c
deleted file mode 100644
index aa61e101f793..000000000000
--- a/sound/soc/intel/boards/haswell.c
+++ /dev/null
@@ -1,202 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Intel Haswell Lynxpoint SST Audio
- *
- * Copyright (C) 2013, Intel Corporation. All rights reserved.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-acpi.h>
-#include <sound/pcm_params.h>
-
-#include "../../codecs/rt5640.h"
-
-/* Haswell ULT platforms have a Headphone and Mic jack */
-static const struct snd_soc_dapm_widget haswell_widgets[] = {
- SND_SOC_DAPM_HP("Headphones", NULL),
- SND_SOC_DAPM_MIC("Mic", NULL),
-};
-
-static const struct snd_soc_dapm_route haswell_rt5640_map[] = {
-
- {"Headphones", NULL, "HPOR"},
- {"Headphones", NULL, "HPOL"},
- {"IN2P", NULL, "Mic"},
-
- /* CODEC BE connections */
- {"SSP0 CODEC IN", NULL, "AIF1 Capture"},
- {"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
-};
-
-static int haswell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *channels = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
-
- /* The ADSP will covert the FE rate to 48k, stereo */
- rate->min = rate->max = 48000;
- channels->min = channels->max = 2;
-
- /* set SSP0 to 16 bit */
- params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
- return 0;
-}
-
-static int haswell_rt5640_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);
- int ret;
-
- ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_MCLK, 12288000,
- SND_SOC_CLOCK_IN);
-
- if (ret < 0) {
- dev_err(rtd->dev, "can't set codec sysclk configuration\n");
- return ret;
- }
-
- /* set correct codec filter for DAI format and clock config */
- snd_soc_component_update_bits(codec_dai->component, 0x83, 0xffff, 0x8000);
-
- return ret;
-}
-
-static const struct snd_soc_ops haswell_rt5640_ops = {
- .hw_params = haswell_rt5640_hw_params,
-};
-
-SND_SOC_DAILINK_DEF(dummy,
- DAILINK_COMP_ARRAY(COMP_DUMMY()));
-
-SND_SOC_DAILINK_DEF(system,
- DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
-
-SND_SOC_DAILINK_DEF(offload0,
- DAILINK_COMP_ARRAY(COMP_CPU("Offload0 Pin")));
-
-SND_SOC_DAILINK_DEF(offload1,
- DAILINK_COMP_ARRAY(COMP_CPU("Offload1 Pin")));
-
-SND_SOC_DAILINK_DEF(loopback,
- DAILINK_COMP_ARRAY(COMP_CPU("Loopback Pin")));
-
-SND_SOC_DAILINK_DEF(codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT33CA:00", "rt5640-aif1")));
-
-SND_SOC_DAILINK_DEF(platform,
- DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio")));
-
-SND_SOC_DAILINK_DEF(ssp0_port,
- DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
-
-static struct snd_soc_dai_link haswell_rt5640_dais[] = {
- /* Front End DAI links */
- {
- .name = "System",
- .stream_name = "System Playback/Capture",
- .nonatomic = 1,
- .dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- {
- .name = "Offload0",
- .stream_name = "Offload0 Playback",
- .nonatomic = 1,
- .dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- SND_SOC_DAILINK_REG(offload0, dummy, platform),
- },
- {
- .name = "Offload1",
- .stream_name = "Offload1 Playback",
- .nonatomic = 1,
- .dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- SND_SOC_DAILINK_REG(offload1, dummy, platform),
- },
- {
- .name = "Loopback",
- .stream_name = "Loopback",
- .nonatomic = 1,
- .dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(loopback, dummy, platform),
- },
-
- /* Back End DAI links */
- {
- /* SSP0 - Codec */
- .name = "Codec",
- .id = 0,
- .no_pcm = 1,
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .ignore_pmdown_time = 1,
- .be_hw_params_fixup = haswell_ssp0_fixup,
- .ops = &haswell_rt5640_ops,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(ssp0_port, codec, platform),
- },
-};
-
-/* audio machine driver for Haswell Lynxpoint DSP + RT5640 */
-static struct snd_soc_card haswell_rt5640 = {
- .name = "haswell-rt5640",
- .owner = THIS_MODULE,
- .dai_link = haswell_rt5640_dais,
- .num_links = ARRAY_SIZE(haswell_rt5640_dais),
- .dapm_widgets = haswell_widgets,
- .num_dapm_widgets = ARRAY_SIZE(haswell_widgets),
- .dapm_routes = haswell_rt5640_map,
- .num_dapm_routes = ARRAY_SIZE(haswell_rt5640_map),
- .fully_routed = true,
-};
-
-static int haswell_audio_probe(struct platform_device *pdev)
-{
- struct snd_soc_acpi_mach *mach;
- int ret;
-
- haswell_rt5640.dev = &pdev->dev;
-
- /* override platform name, if required */
- mach = pdev->dev.platform_data;
- ret = snd_soc_fixup_dai_links_platform_name(&haswell_rt5640,
- mach->mach_params.platform);
- if (ret)
- return ret;
-
- return devm_snd_soc_register_card(&pdev->dev, &haswell_rt5640);
-}
-
-static struct platform_driver haswell_audio = {
- .probe = haswell_audio_probe,
- .driver = {
- .name = "haswell-audio",
- .pm = &snd_soc_pm_ops,
- },
-};
-
-module_platform_driver(haswell_audio)
-
-/* Module information */
-MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
-MODULE_DESCRIPTION("Intel SST Audio for Haswell Lynxpoint");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:haswell-audio");
diff --git a/sound/soc/intel/boards/hda_dsp_common.c b/sound/soc/intel/boards/hda_dsp_common.c
index 5c31ddc0884a..83c7dfbccd9d 100644
--- a/sound/soc/intel/boards/hda_dsp_common.c
+++ b/sound/soc/intel/boards/hda_dsp_common.c
@@ -62,8 +62,8 @@ int hda_dsp_hdmi_build_controls(struct snd_soc_card *card,
hpcm->pcm = spcm;
hpcm->device = spcm->device;
dev_dbg(card->dev,
- "%s: mapping HDMI converter %d to PCM %d (%p)\n",
- __func__, i, hpcm->device, spcm);
+ "mapping HDMI converter %d to PCM %d (%p)\n",
+ i, hpcm->device, spcm);
} else {
hpcm->pcm = NULL;
hpcm->device = SNDRV_PCM_INVALID_DEVICE;
diff --git a/sound/soc/intel/boards/hsw_rt5640.c b/sound/soc/intel/boards/hsw_rt5640.c
new file mode 100644
index 000000000000..050c53ebd6ba
--- /dev/null
+++ b/sound/soc/intel/boards/hsw_rt5640.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Sound card driver for Intel Haswell Lynx Point with Realtek 5640
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../codecs/rt5640.h"
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_HP("Headphones", NULL),
+ SND_SOC_DAPM_MIC("Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route card_routes[] = {
+ {"Headphones", NULL, "HPOR"},
+ {"Headphones", NULL, "HPOL"},
+ {"IN2P", NULL, "Mic"},
+
+ /* CODEC BE connections */
+ {"SSP0 CODEC IN", NULL, "AIF1 Capture"},
+ {"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
+};
+
+static int codec_link_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+
+ /* The ADSP will convert the FE rate to 48k, stereo. */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+ /* Set SSP0 to 16 bit. */
+ params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
+
+ return 0;
+}
+
+static int codec_link_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);
+ int ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_MCLK, 12288000, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(rtd->dev, "set codec sysclk failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Set correct codec filter for DAI format and clock config. */
+ snd_soc_component_update_bits(codec_dai->component, 0x83, 0xffff, 0x8000);
+
+ return ret;
+}
+
+static const struct snd_soc_ops codec_link_ops = {
+ .hw_params = codec_link_hw_params,
+};
+
+SND_SOC_DAILINK_DEF(system, DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
+SND_SOC_DAILINK_DEF(offload0, DAILINK_COMP_ARRAY(COMP_CPU("Offload0 Pin")));
+SND_SOC_DAILINK_DEF(offload1, DAILINK_COMP_ARRAY(COMP_CPU("Offload1 Pin")));
+SND_SOC_DAILINK_DEF(loopback, DAILINK_COMP_ARRAY(COMP_CPU("Loopback Pin")));
+
+SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));
+SND_SOC_DAILINK_DEF(codec, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT33CA:00", "rt5640-aif1")));
+SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio")));
+SND_SOC_DAILINK_DEF(ssp0_port, DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
+
+static struct snd_soc_dai_link card_dai_links[] = {
+ /* Front End DAI links */
+ {
+ .name = "System",
+ .stream_name = "System Playback/Capture",
+ .nonatomic = 1,
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(system, dummy, platform),
+ },
+ {
+ .name = "Offload0",
+ .stream_name = "Offload0 Playback",
+ .nonatomic = 1,
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(offload0, dummy, platform),
+ },
+ {
+ .name = "Offload1",
+ .stream_name = "Offload1 Playback",
+ .nonatomic = 1,
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(offload1, dummy, platform),
+ },
+ {
+ .name = "Loopback",
+ .stream_name = "Loopback",
+ .nonatomic = 1,
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(loopback, dummy, platform),
+ },
+ /* Back End DAI links */
+ {
+ /* SSP0 - Codec */
+ .name = "Codec",
+ .id = 0,
+ .nonatomic = 1,
+ .no_pcm = 1,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC,
+ .ignore_pmdown_time = 1,
+ .be_hw_params_fixup = codec_link_hw_params_fixup,
+ .ops = &codec_link_ops,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(ssp0_port, codec, platform),
+ },
+};
+
+static struct snd_soc_card hsw_rt5640_card = {
+ .name = "haswell-rt5640",
+ .owner = THIS_MODULE,
+ .dai_link = card_dai_links,
+ .num_links = ARRAY_SIZE(card_dai_links),
+ .dapm_widgets = card_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(card_widgets),
+ .dapm_routes = card_routes,
+ .num_dapm_routes = ARRAY_SIZE(card_routes),
+ .fully_routed = true,
+};
+
+static int hsw_rt5640_probe(struct platform_device *pdev)
+{
+ struct snd_soc_acpi_mach *mach;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ hsw_rt5640_card.dev = dev;
+ mach = dev_get_platdata(dev);
+
+ ret = snd_soc_fixup_dai_links_platform_name(&hsw_rt5640_card, mach->mach_params.platform);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, &hsw_rt5640_card);
+}
+
+static struct platform_driver hsw_rt5640_driver = {
+ .probe = hsw_rt5640_probe,
+ .driver = {
+ .name = "hsw_rt5640",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(hsw_rt5640_driver)
+
+MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
+MODULE_DESCRIPTION("Sound card driver for Intel Haswell Lynx Point with Realtek 5640");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:hsw_rt5640");
diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c
index ceabed85e9da..329457e3e3a2 100644
--- a/sound/soc/intel/boards/kbl_da7219_max98357a.c
+++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c
@@ -99,6 +99,17 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = {
SND_SOC_DAPM_POST_PMD),
};
+static struct snd_soc_jack_pin jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static const struct snd_soc_dapm_route kabylake_map[] = {
{ "Headphone Jack", NULL, "HPL" },
{ "Headphone Jack", NULL, "HPR" },
@@ -179,10 +190,12 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
* Headset buttons map to the google Reference headset.
* These can be configured by userspace.
*/
- ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
- &ctx->kabylake_headset);
+ ret = snd_soc_card_jack_new_pins(kabylake_audio_card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
+ &ctx->kabylake_headset,
+ jack_pins,
+ ARRAY_SIZE(jack_pins));
if (ret) {
dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
return ret;
diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c
index 703ccff634b0..362579f25835 100644
--- a/sound/soc/intel/boards/kbl_da7219_max98927.c
+++ b/sound/soc/intel/boards/kbl_da7219_max98927.c
@@ -119,6 +119,17 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = {
SND_SOC_DAPM_POST_PMD),
};
+static struct snd_soc_jack_pin jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static const struct snd_soc_dapm_route kabylake_map[] = {
/* speaker */
{ "Left Spk", NULL, "Left BE_OUT" },
@@ -354,10 +365,12 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
* Headset buttons map to the google Reference headset.
* These can be configured by userspace.
*/
- ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
- &ctx->kabylake_headset);
+ ret = snd_soc_card_jack_new_pins(kabylake_audio_card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
+ &ctx->kabylake_headset,
+ jack_pins,
+ ARRAY_SIZE(jack_pins));
if (ret) {
dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
return ret;
diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c
index 8d37b2676a81..2d4224c5b152 100644
--- a/sound/soc/intel/boards/kbl_rt5663_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c
@@ -206,6 +206,17 @@ static const struct snd_soc_dapm_widget kabylake_5663_widgets[] = {
SND_SOC_DAPM_POST_PMD),
};
+static struct snd_soc_jack_pin jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static const struct snd_soc_dapm_route kabylake_5663_map[] = {
{ "Headphone Jack", NULL, "Platform Clock" },
{ "Headphone Jack", NULL, "HPOL" },
@@ -271,10 +282,12 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
* Headset buttons map to the google Reference headset.
* These can be configured by userspace.
*/
- ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &ctx->kabylake_headset);
+ ret = snd_soc_card_jack_new_pins(kabylake_audio_card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &ctx->kabylake_headset,
+ jack_pins,
+ ARRAY_SIZE(jack_pins));
if (ret) {
dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
return ret;
diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
index 564c70a0fbc8..2c79fca57b19 100644
--- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
@@ -145,6 +145,17 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = {
};
+static struct snd_soc_jack_pin jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static const struct snd_soc_dapm_route kabylake_map[] = {
/* Headphones */
{ "Headphone Jack", NULL, "Platform Clock" },
@@ -228,10 +239,12 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
* Headset buttons map to the google Reference headset.
* These can be configured by userspace.
*/
- ret = snd_soc_card_jack_new(&kabylake_audio_card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &ctx->kabylake_headset);
+ ret = snd_soc_card_jack_new_pins(&kabylake_audio_card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &ctx->kabylake_headset,
+ jack_pins,
+ ARRAY_SIZE(jack_pins));
if (ret) {
dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
return ret;
diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c
index f4b4eeca3e03..81144efb4b44 100644
--- a/sound/soc/intel/boards/skl_hda_dsp_generic.c
+++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c
@@ -75,7 +75,7 @@ skl_hda_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link)
struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card);
int ret = 0;
- dev_dbg(card->dev, "%s: dai link name - %s\n", __func__, link->name);
+ dev_dbg(card->dev, "dai link name - %s\n", link->name);
link->platforms->name = ctx->platform_name;
link->nonatomic = 1;
@@ -203,7 +203,7 @@ static int skl_hda_audio_probe(struct platform_device *pdev)
struct skl_hda_private *ctx;
int ret;
- dev_dbg(&pdev->dev, "%s: entry\n", __func__);
+ dev_dbg(&pdev->dev, "entry\n");
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
index 8e2d03e36079..8dceb0b02581 100644
--- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c
+++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
@@ -97,6 +97,17 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = {
SND_SOC_DAPM_POST_PMD),
};
+static struct snd_soc_jack_pin jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static const struct snd_soc_dapm_route skylake_map[] = {
/* HP jack connectors - unknown if we have jack detection */
{ "Headphone Jack", NULL, "HPOL" },
@@ -163,9 +174,11 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
* Headset buttons map to the google Reference headset.
* These can be configured by userspace.
*/
- ret = snd_soc_card_jack_new(&skylake_audio_card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset);
+ ret = snd_soc_card_jack_new_pins(&skylake_audio_card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset,
+ jack_pins,
+ ARRAY_SIZE(jack_pins));
if (ret) {
dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
return ret;
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
index 501f0bbfc404..62c0d46d0086 100644
--- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
+++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
@@ -101,6 +101,17 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = {
SND_SOC_DAPM_POST_PMD),
};
+static struct snd_soc_jack_pin jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static const struct snd_soc_dapm_route skylake_map[] = {
/* HP jack connectors - unknown if we have jack detection */
{"Headphone Jack", NULL, "HPOL"},
@@ -182,9 +193,11 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
* 4 buttons here map to the google Reference headset
* The use of these buttons can be decided by the user space.
*/
- ret = snd_soc_card_jack_new(&skylake_audio_card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset);
+ ret = snd_soc_card_jack_new_pins(&skylake_audio_card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset,
+ jack_pins,
+ ARRAY_SIZE(jack_pins));
if (ret) {
dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
return ret;
diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c
index e9f9520dcea4..4f3d655e2bfa 100644
--- a/sound/soc/intel/boards/skl_rt286.c
+++ b/sound/soc/intel/boards/skl_rt286.c
@@ -133,7 +133,7 @@ static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
if (ret)
return ret;
- rt286_mic_detect(component, &skylake_headset);
+ snd_soc_component_set_jack(component, &skylake_headset, NULL);
snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
diff --git a/sound/soc/intel/boards/sof_cs42l42.c b/sound/soc/intel/boards/sof_cs42l42.c
index 6a979c333bc5..85ffd065895d 100644
--- a/sound/soc/intel/boards/sof_cs42l42.c
+++ b/sound/soc/intel/boards/sof_cs42l42.c
@@ -41,8 +41,13 @@
#define SOF_CS42L42_DAILINK_MASK (GENMASK(24, 10))
#define SOF_CS42L42_DAILINK(link1, link2, link3, link4, link5) \
((((link1) | ((link2) << 3) | ((link3) << 6) | ((link4) << 9) | ((link5) << 12)) << SOF_CS42L42_DAILINK_SHIFT) & SOF_CS42L42_DAILINK_MASK)
-#define SOF_MAX98357A_SPEAKER_AMP_PRESENT BIT(25)
-#define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(26)
+#define SOF_BT_OFFLOAD_PRESENT BIT(25)
+#define SOF_CS42L42_SSP_BT_SHIFT 26
+#define SOF_CS42L42_SSP_BT_MASK (GENMASK(28, 26))
+#define SOF_CS42L42_SSP_BT(quirk) \
+ (((quirk) << SOF_CS42L42_SSP_BT_SHIFT) & SOF_CS42L42_SSP_BT_MASK)
+#define SOF_MAX98357A_SPEAKER_AMP_PRESENT BIT(29)
+#define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(30)
enum {
LINK_NONE = 0,
@@ -50,6 +55,18 @@ enum {
LINK_SPK = 2,
LINK_DMIC = 3,
LINK_HDMI = 4,
+ LINK_BT = 5,
+};
+
+static struct snd_soc_jack_pin jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
};
/* Default: SSP2 */
@@ -98,11 +115,13 @@ static int sof_cs42l42_init(struct snd_soc_pcm_runtime *rtd)
* Headset buttons map to the google Reference headset.
* These can be configured by userspace.
*/
- ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0 |
- SND_JACK_BTN_1 | SND_JACK_BTN_2 |
- SND_JACK_BTN_3,
- jack);
+ 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,
+ jack_pins,
+ ARRAY_SIZE(jack_pins));
if (ret) {
dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
return ret;
@@ -277,6 +296,13 @@ static struct snd_soc_dai_link_component dmic_component[] = {
}
};
+static struct snd_soc_dai_link_component dummy_component[] = {
+ {
+ .name = "snd-soc-dummy",
+ .dai_name = "snd-soc-dummy-dai",
+ }
+};
+
static int create_spk_amp_dai_links(struct device *dev,
struct snd_soc_dai_link *links,
struct snd_soc_dai_link_component *cpus,
@@ -466,9 +492,50 @@ devm_err:
return -ENOMEM;
}
+static int create_bt_offload_dai_links(struct device *dev,
+ struct snd_soc_dai_link *links,
+ struct snd_soc_dai_link_component *cpus,
+ int *id, int ssp_bt)
+{
+ /* bt offload */
+ if (!(sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT))
+ return 0;
+
+ links[*id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT",
+ ssp_bt);
+ if (!links[*id].name)
+ goto devm_err;
+
+ links[*id].id = *id;
+ links[*id].codecs = dummy_component;
+ links[*id].num_codecs = ARRAY_SIZE(dummy_component);
+ links[*id].platforms = platform_component;
+ links[*id].num_platforms = ARRAY_SIZE(platform_component);
+
+ links[*id].dpcm_playback = 1;
+ links[*id].dpcm_capture = 1;
+ links[*id].no_pcm = 1;
+ links[*id].cpus = &cpus[*id];
+ links[*id].num_cpus = 1;
+
+ links[*id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ "SSP%d Pin",
+ ssp_bt);
+ if (!links[*id].cpus->dai_name)
+ goto devm_err;
+
+ (*id)++;
+
+ return 0;
+
+devm_err:
+ return -ENOMEM;
+}
+
static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
int ssp_codec,
int ssp_amp,
+ int ssp_bt,
int dmic_be_num,
int hdmi_num)
{
@@ -521,6 +588,14 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
goto devm_err;
}
break;
+ case LINK_BT:
+ ret = create_bt_offload_dai_links(dev, links, cpus, &id, ssp_bt);
+ if (ret < 0) {
+ dev_err(dev, "fail to create bt offload dai links, ret %d\n",
+ ret);
+ goto devm_err;
+ }
+ break;
case LINK_NONE:
/* caught here if it's not used as terminator in macro */
default:
@@ -542,7 +617,7 @@ static int sof_audio_probe(struct platform_device *pdev)
struct snd_soc_acpi_mach *mach;
struct sof_card_private *ctx;
int dmic_be_num, hdmi_num;
- int ret, ssp_amp, ssp_codec;
+ int ret, ssp_bt, ssp_amp, ssp_codec;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -567,6 +642,9 @@ static int sof_audio_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "sof_cs42l42_quirk = %lx\n", sof_cs42l42_quirk);
+ ssp_bt = (sof_cs42l42_quirk & SOF_CS42L42_SSP_BT_MASK) >>
+ SOF_CS42L42_SSP_BT_SHIFT;
+
ssp_amp = (sof_cs42l42_quirk & SOF_CS42L42_SSP_AMP_MASK) >>
SOF_CS42L42_SSP_AMP_SHIFT;
@@ -577,9 +655,11 @@ static int sof_audio_probe(struct platform_device *pdev)
if (sof_cs42l42_quirk & SOF_SPEAKER_AMP_PRESENT)
sof_audio_card_cs42l42.num_links++;
+ if (sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT)
+ sof_audio_card_cs42l42.num_links++;
dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp,
- dmic_be_num, hdmi_num);
+ ssp_bt, dmic_be_num, hdmi_num);
if (!dai_links)
return -ENOMEM;
@@ -620,6 +700,17 @@ static const struct platform_device_id board_ids[] = {
SOF_CS42L42_SSP_AMP(1)) |
SOF_CS42L42_DAILINK(LINK_HP, LINK_DMIC, LINK_HDMI, LINK_SPK, LINK_NONE),
},
+ {
+ .name = "adl_mx98360a_cs4242",
+ .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(0) |
+ SOF_SPEAKER_AMP_PRESENT |
+ SOF_MAX98360A_SPEAKER_AMP_PRESENT |
+ SOF_CS42L42_SSP_AMP(1) |
+ SOF_CS42L42_NUM_HDMIDEV(4) |
+ SOF_BT_OFFLOAD_PRESENT |
+ SOF_CS42L42_SSP_BT(2) |
+ SOF_CS42L42_DAILINK(LINK_HP, LINK_DMIC, LINK_HDMI, LINK_SPK, LINK_BT)),
+ },
{ }
};
MODULE_DEVICE_TABLE(platform, board_ids);
diff --git a/sound/soc/intel/boards/sof_da7219_max98373.c b/sound/soc/intel/boards/sof_da7219_max98373.c
index a83f30b687cf..34cf849a8344 100644
--- a/sound/soc/intel/boards/sof_da7219_max98373.c
+++ b/sound/soc/intel/boards/sof_da7219_max98373.c
@@ -135,6 +135,17 @@ static const struct snd_soc_dapm_route max98360a_map[] = {
{"DMic", NULL, "SoC DMIC"},
};
+static struct snd_soc_jack_pin jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static struct snd_soc_jack headset;
static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
@@ -156,11 +167,13 @@ static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
* Headset buttons map to the google Reference headset.
* These can be configured by userspace.
*/
- ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0 |
- SND_JACK_BTN_1 | SND_JACK_BTN_2 |
- SND_JACK_BTN_3 | SND_JACK_LINEOUT,
- &headset);
+ 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 | SND_JACK_LINEOUT,
+ &headset,
+ jack_pins,
+ ARRAY_SIZE(jack_pins));
if (ret) {
dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
return ret;
diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c
index 23d03e0f7759..c7f33c89588e 100644
--- a/sound/soc/intel/boards/sof_es8336.c
+++ b/sound/soc/intel/boards/sof_es8336.c
@@ -28,6 +28,24 @@
#define SOF_ES8336_SSP_CODEC_MASK (GENMASK(3, 0))
#define SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK BIT(4)
+
+/* HDMI capture*/
+#define SOF_SSP_HDMI_CAPTURE_PRESENT BIT(14)
+#define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT 15
+#define SOF_NO_OF_HDMI_CAPTURE_SSP_MASK (GENMASK(16, 15))
+#define SOF_NO_OF_HDMI_CAPTURE_SSP(quirk) \
+ (((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK)
+
+#define SOF_HDMI_CAPTURE_1_SSP_SHIFT 7
+#define SOF_HDMI_CAPTURE_1_SSP_MASK (GENMASK(9, 7))
+#define SOF_HDMI_CAPTURE_1_SSP(quirk) \
+ (((quirk) << SOF_HDMI_CAPTURE_1_SSP_SHIFT) & SOF_HDMI_CAPTURE_1_SSP_MASK)
+
+#define SOF_HDMI_CAPTURE_2_SSP_SHIFT 10
+#define SOF_HDMI_CAPTURE_2_SSP_MASK (GENMASK(12, 10))
+#define SOF_HDMI_CAPTURE_2_SSP(quirk) \
+ (((quirk) << SOF_HDMI_CAPTURE_2_SSP_SHIFT) & SOF_HDMI_CAPTURE_2_SSP_MASK)
+
#define SOF_ES8336_ENABLE_DMIC BIT(5)
#define SOF_ES8336_JD_INVERTED BIT(6)
#define SOF_ES8336_HEADPHONE_GPIO BIT(7)
@@ -57,28 +75,26 @@ static const struct acpi_gpio_params enable_gpio0 = { 0, 0, true };
static const struct acpi_gpio_params enable_gpio1 = { 1, 0, true };
static const struct acpi_gpio_mapping acpi_speakers_enable_gpio0[] = {
- { "speakers-enable-gpios", &enable_gpio0, 1 },
+ { "speakers-enable-gpios", &enable_gpio0, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
{ }
};
static const struct acpi_gpio_mapping acpi_speakers_enable_gpio1[] = {
- { "speakers-enable-gpios", &enable_gpio1, 1 },
+ { "speakers-enable-gpios", &enable_gpio1, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
};
static const struct acpi_gpio_mapping acpi_enable_both_gpios[] = {
- { "speakers-enable-gpios", &enable_gpio0, 1 },
- { "headphone-enable-gpios", &enable_gpio1, 1 },
+ { "speakers-enable-gpios", &enable_gpio0, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
+ { "headphone-enable-gpios", &enable_gpio1, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
{ }
};
static const struct acpi_gpio_mapping acpi_enable_both_gpios_rev_order[] = {
- { "speakers-enable-gpios", &enable_gpio1, 1 },
- { "headphone-enable-gpios", &enable_gpio0, 1 },
+ { "speakers-enable-gpios", &enable_gpio1, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
+ { "headphone-enable-gpios", &enable_gpio0, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
{ }
};
-static const struct acpi_gpio_mapping *gpio_mapping = acpi_speakers_enable_gpio0;
-
static void log_quirks(struct device *dev)
{
dev_info(dev, "quirk mask %#lx\n", quirk);
@@ -272,15 +288,6 @@ static int sof_es8336_quirk_cb(const struct dmi_system_id *id)
{
quirk = (unsigned long)id->driver_data;
- if (quirk & SOF_ES8336_HEADPHONE_GPIO) {
- if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK)
- gpio_mapping = acpi_enable_both_gpios;
- else
- gpio_mapping = acpi_enable_both_gpios_rev_order;
- } else if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) {
- gpio_mapping = acpi_speakers_enable_gpio1;
- }
-
return 1;
}
@@ -356,6 +363,13 @@ static struct snd_soc_dai_link_component dmic_component[] = {
}
};
+static struct snd_soc_dai_link_component dummy_component[] = {
+ {
+ .name = "snd-soc-dummy",
+ .dai_name = "snd-soc-dummy-dai",
+ }
+};
+
static int sof_es8336_late_probe(struct snd_soc_card *card)
{
struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card);
@@ -507,6 +521,37 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
id++;
}
+ /* HDMI-In SSP */
+ if (quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) {
+ int num_of_hdmi_ssp = (quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >>
+ SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
+
+ for (i = 1; i <= num_of_hdmi_ssp; i++) {
+ int port = (i == 1 ? (quirk & SOF_HDMI_CAPTURE_1_SSP_MASK) >>
+ SOF_HDMI_CAPTURE_1_SSP_SHIFT :
+ (quirk & SOF_HDMI_CAPTURE_2_SSP_MASK) >>
+ SOF_HDMI_CAPTURE_2_SSP_SHIFT);
+
+ links[id].cpus = &cpus[id];
+ links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ "SSP%d Pin", port);
+ if (!links[id].cpus->dai_name)
+ return NULL;
+ links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port);
+ if (!links[id].name)
+ return NULL;
+ links[id].id = id + hdmi_id_offset;
+ links[id].codecs = dummy_component;
+ links[id].num_codecs = ARRAY_SIZE(dummy_component);
+ links[id].platforms = platform_component;
+ links[id].num_platforms = ARRAY_SIZE(platform_component);
+ links[id].dpcm_capture = 1;
+ links[id].no_pcm = 1;
+ links[id].num_cpus = 1;
+ id++;
+ }
+ }
+
return links;
devm_err:
@@ -529,6 +574,7 @@ static int sof_es8336_probe(struct platform_device *pdev)
struct acpi_device *adev;
struct snd_soc_dai_link *dai_links;
struct device *codec_dev;
+ const struct acpi_gpio_mapping *gpio_mapping;
unsigned int cnt = 0;
int dmic_be_num = 0;
int hdmi_num = 3;
@@ -541,29 +587,34 @@ static int sof_es8336_probe(struct platform_device *pdev)
card = &sof_es8336_card;
card->dev = dev;
+ if (pdev->id_entry && pdev->id_entry->driver_data)
+ quirk = (unsigned long)pdev->id_entry->driver_data;
+
/* check GPIO DMI quirks */
dmi_check_system(sof_es8336_quirk_table);
- if (!mach->mach_params.i2s_link_mask) {
- dev_warn(dev, "No I2S link information provided, using SSP0. This may need to be modified with the quirk module parameter\n");
- } else {
- /*
- * Set configuration based on platform NHLT.
- * In this machine driver, we can only support one SSP for the
- * ES8336 link, the else-if below are intentional.
- * In some cases multiple SSPs can be reported by NHLT, starting MSB-first
- * seems to pick the right connection.
- */
- unsigned long ssp = 0;
-
- if (mach->mach_params.i2s_link_mask & BIT(2))
- ssp = SOF_ES8336_SSP_CODEC(2);
- else if (mach->mach_params.i2s_link_mask & BIT(1))
- ssp = SOF_ES8336_SSP_CODEC(1);
- else if (mach->mach_params.i2s_link_mask & BIT(0))
- ssp = SOF_ES8336_SSP_CODEC(0);
-
- quirk |= ssp;
+ /* Use NHLT configuration only for Non-HDMI capture use case.
+ * Because more than one SSP will be enabled for HDMI capture hence wrong codec
+ * SSP will be set.
+ */
+ if (mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER) {
+ if (!mach->mach_params.i2s_link_mask) {
+ dev_warn(dev, "No I2S link information provided, using SSP0. This may need to be modified with the quirk module parameter\n");
+ } else {
+ /*
+ * Set configuration based on platform NHLT.
+ * In this machine driver, we can only support one SSP for the
+ * ES8336 link.
+ * In some cases multiple SSPs can be reported by NHLT, starting MSB-first
+ * seems to pick the right connection.
+ */
+ unsigned long ssp;
+
+ /* fls returns 1-based results, SSPs indices are 0-based */
+ ssp = fls(mach->mach_params.i2s_link_mask) - 1;
+
+ quirk |= ssp;
+ }
}
if (mach->mach_params.dmic_num)
@@ -579,7 +630,13 @@ static int sof_es8336_probe(struct platform_device *pdev)
if (quirk & SOF_ES8336_ENABLE_DMIC)
dmic_be_num = 2;
- sof_es8336_card.num_links += dmic_be_num + hdmi_num;
+ /* compute number of dai links */
+ sof_es8336_card.num_links = 1 + dmic_be_num + hdmi_num;
+
+ if (quirk & SOF_SSP_HDMI_CAPTURE_PRESENT)
+ sof_es8336_card.num_links += (quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >>
+ SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
+
dai_links = sof_card_dai_links_create(dev,
SOF_ES8336_SSP_CODEC(quirk),
dmic_be_num, hdmi_num);
@@ -635,6 +692,17 @@ static int sof_es8336_probe(struct platform_device *pdev)
}
/* get speaker enable GPIO */
+ if (quirk & SOF_ES8336_HEADPHONE_GPIO) {
+ if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK)
+ gpio_mapping = acpi_enable_both_gpios;
+ else
+ gpio_mapping = acpi_enable_both_gpios_rev_order;
+ } else if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) {
+ gpio_mapping = acpi_speakers_enable_gpio1;
+ } else {
+ gpio_mapping = acpi_speakers_enable_gpio0;
+ }
+
ret = devm_acpi_dev_add_driver_gpios(codec_dev, gpio_mapping);
if (ret)
dev_warn(codec_dev, "unable to add GPIO mapping table\n");
@@ -690,6 +758,21 @@ static int sof_es8336_remove(struct platform_device *pdev)
return 0;
}
+static const struct platform_device_id board_ids[] = {
+ {
+ .name = "adl_es83x6_c1_h02",
+ .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) |
+ SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
+ SOF_HDMI_CAPTURE_1_SSP(0) |
+ SOF_HDMI_CAPTURE_2_SSP(2) |
+ SOF_SSP_HDMI_CAPTURE_PRESENT |
+ SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK |
+ SOF_ES8336_JD_INVERTED),
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, board_ids);
+
static struct platform_driver sof_es8336_driver = {
.driver = {
.name = "sof-essx8336",
@@ -697,6 +780,7 @@ static struct platform_driver sof_es8336_driver = {
},
.probe = sof_es8336_probe,
.remove = sof_es8336_remove,
+ .id_table = board_ids,
};
module_platform_driver(sof_es8336_driver);
diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c
index 97dcd204a246..8d7e5ba9e516 100644
--- a/sound/soc/intel/boards/sof_nau8825.c
+++ b/sound/soc/intel/boards/sof_nau8825.c
@@ -81,6 +81,17 @@ static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
+static struct snd_soc_jack_pin jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static int sof_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
{
struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
@@ -93,11 +104,13 @@ static int sof_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
* Headset buttons map to the google Reference headset.
* These can be configured by userspace.
*/
- ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0 |
- SND_JACK_BTN_1 | SND_JACK_BTN_2 |
- SND_JACK_BTN_3,
- &ctx->sof_headset);
+ 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,
+ &ctx->sof_headset,
+ jack_pins,
+ ARRAY_SIZE(jack_pins));
if (ret) {
dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
return ret;
@@ -177,11 +190,6 @@ static int sof_card_late_probe(struct snd_soc_card *card)
struct sof_hdmi_pcm *pcm;
int err;
- if (list_empty(&ctx->hdmi_pcm_list))
- return -EINVAL;
-
- pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, head);
-
if (sof_nau8825_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) {
/* Disable Left and Right Spk pin after boot */
snd_soc_dapm_disable_pin(dapm, "Left Spk");
@@ -191,6 +199,11 @@ static int sof_card_late_probe(struct snd_soc_card *card)
return err;
}
+ if (list_empty(&ctx->hdmi_pcm_list))
+ return -EINVAL;
+
+ pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, head);
+
return hda_dsp_hdmi_build_controls(card, pcm->codec_dai->component);
}
diff --git a/sound/soc/intel/boards/sof_pcm512x.c b/sound/soc/intel/boards/sof_pcm512x.c
index 6815204e58d5..d4c67d5340a9 100644
--- a/sound/soc/intel/boards/sof_pcm512x.c
+++ b/sound/soc/intel/boards/sof_pcm512x.c
@@ -419,7 +419,7 @@ static int sof_audio_probe(struct platform_device *pdev)
static int sof_pcm512x_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
- struct snd_soc_component *component = NULL;
+ struct snd_soc_component *component;
for_each_card_components(card, component) {
if (!strcmp(component->name, pcm512x_component[0].name)) {
diff --git a/sound/soc/intel/boards/sof_realtek_common.c b/sound/soc/intel/boards/sof_realtek_common.c
index 2ab568c1d40b..b9643ca2e2f2 100644
--- a/sound/soc/intel/boards/sof_realtek_common.c
+++ b/sound/soc/intel/boards/sof_realtek_common.c
@@ -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");
diff --git a/sound/soc/intel/boards/sof_realtek_common.h b/sound/soc/intel/boards/sof_realtek_common.h
index ec3eea633e04..778443421090 100644
--- a/sound/soc/intel/boards/sof_realtek_common.h
+++ b/sound/soc/intel/boards/sof_realtek_common.h
@@ -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 */
diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c
index 4a90a0a5d831..045965312245 100644
--- a/sound/soc/intel/boards/sof_rt5682.c
+++ b/sound/soc/intel/boards/sof_rt5682.c
@@ -247,6 +247,17 @@ static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
+static struct snd_soc_jack_pin jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
{
struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
@@ -294,11 +305,13 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
* Headset buttons map to the google Reference headset.
* These can be configured by userspace.
*/
- ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0 |
- SND_JACK_BTN_1 | SND_JACK_BTN_2 |
- SND_JACK_BTN_3,
- &ctx->sof_headset);
+ 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,
+ &ctx->sof_headset,
+ jack_pins,
+ ARRAY_SIZE(jack_pins));
if (ret) {
dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
return ret;
@@ -434,6 +447,15 @@ static int sof_card_late_probe(struct snd_soc_card *card)
struct sof_hdmi_pcm *pcm;
int err;
+ if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) {
+ /* Disable Left and Right Spk pin after boot */
+ snd_soc_dapm_disable_pin(dapm, "Left Spk");
+ snd_soc_dapm_disable_pin(dapm, "Right Spk");
+ err = snd_soc_dapm_sync(dapm);
+ if (err < 0)
+ return err;
+ }
+
/* HDMI is not supported by SOF on Baytrail/CherryTrail */
if (is_legacy_cpu || !ctx->idisp_codec)
return 0;
@@ -464,15 +486,6 @@ static int sof_card_late_probe(struct snd_soc_card *card)
return err;
}
- if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) {
- /* Disable Left and Right Spk pin after boot */
- snd_soc_dapm_disable_pin(dapm, "Left Spk");
- snd_soc_dapm_disable_pin(dapm, "Right Spk");
- err = snd_soc_dapm_sync(dapm);
- if (err < 0)
- return err;
- }
-
return hdac_hdmi_jack_port_init(component, &card->dapm);
}
@@ -731,7 +744,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;
@@ -1079,6 +1092,14 @@ static const struct platform_device_id board_ids[] = {
SOF_RT5682_SSP_AMP(1) |
SOF_RT5682_NUM_HDMIDEV(4)),
},
+ {
+ .name = "mtl_mx98357_rt5682",
+ .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
+ SOF_RT5682_SSP_CODEC(0) |
+ SOF_SPEAKER_AMP_PRESENT |
+ SOF_RT5682_SSP_AMP(1) |
+ SOF_RT5682_NUM_HDMIDEV(4)),
+ },
{ }
};
MODULE_DEVICE_TABLE(platform, board_ids);
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index ad826ad82d51..a49bfaab6b21 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -250,6 +250,16 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
.callback = sof_sdw_quirk_cb,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF0")
+ },
+ .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+ RT711_JD2 |
+ SOF_SDW_FOUR_SPK),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF3"),
},
/* No Jack */
@@ -315,6 +325,23 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
RT711_JD2 |
SOF_SDW_FOUR_SPK),
},
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16-k0xxx"),
+ },
+ .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+ RT711_JD2),
+ },
+ /* MeteorLake devices */
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_mtlrvp"),
+ },
+ .driver_data = (void *)(RT711_JD1 | SOF_SDW_TGL_HDMI),
+ },
{}
};
@@ -1127,10 +1154,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 +1181,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 +1403,9 @@ HDMI:
static int sof_sdw_card_late_probe(struct snd_soc_card *card)
{
- int i, ret;
+ struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+ int ret = 0;
+ int i;
for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
if (!codec_info_list[i].late_probe)
@@ -1386,7 +1416,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 */
@@ -1433,7 +1466,7 @@ static int mc_probe(struct platform_device *pdev)
int amp_num = 0, i;
int ret;
- dev_dbg(&pdev->dev, "Entry %s\n", __func__);
+ dev_dbg(&pdev->dev, "Entry\n");
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
diff --git a/sound/soc/intel/boards/sof_sdw_rt711.c b/sound/soc/intel/boards/sof_sdw_rt711.c
index 49ff0871e9e7..8291967f23f3 100644
--- a/sound/soc/intel/boards/sof_sdw_rt711.c
+++ b/sound/soc/intel/boards/sof_sdw_rt711.c
@@ -139,6 +139,9 @@ int sof_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_l
{
struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+ if (!ctx->headset_codec_dev)
+ return 0;
+
device_remove_software_node(ctx->headset_codec_dev);
put_device(ctx->headset_codec_dev);
diff --git a/sound/soc/intel/boards/sof_sdw_rt711_sdca.c b/sound/soc/intel/boards/sof_sdw_rt711_sdca.c
index b3fc32bacfa8..7f16304d025b 100644
--- a/sound/soc/intel/boards/sof_sdw_rt711_sdca.c
+++ b/sound/soc/intel/boards/sof_sdw_rt711_sdca.c
@@ -140,6 +140,9 @@ int sof_sdw_rt711_sdca_exit(struct snd_soc_card *card, struct snd_soc_dai_link *
{
struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+ if (!ctx->headset_codec_dev)
+ return 0;
+
device_remove_software_node(ctx->headset_codec_dev);
put_device(ctx->headset_codec_dev);
diff --git a/sound/soc/intel/catpt/device.c b/sound/soc/intel/catpt/device.c
index 85a34e37316d..d48a71d2cf1e 100644
--- a/sound/soc/intel/catpt/device.c
+++ b/sound/soc/intel/catpt/device.c
@@ -254,14 +254,11 @@ static int catpt_acpi_probe(struct platform_device *pdev)
return -ENODEV;
}
- spec = device_get_match_data(dev);
- if (!spec)
- return -ENODEV;
-
cdev = devm_kzalloc(dev, sizeof(*cdev), GFP_KERNEL);
if (!cdev)
return -ENOMEM;
+ spec = (const struct catpt_spec *)id->driver_data;
catpt_dev_init(cdev, dev, spec);
/* map DSP bar address */
diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c
index a26000cd5ceb..30ca5416c9a3 100644
--- a/sound/soc/intel/catpt/pcm.c
+++ b/sound/soc/intel/catpt/pcm.c
@@ -667,7 +667,9 @@ static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtm,
if (!memcmp(&cdev->devfmt[devfmt.iface], &devfmt, sizeof(devfmt)))
return 0;
- pm_runtime_get_sync(cdev->dev);
+ ret = pm_runtime_resume_and_get(cdev->dev);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
ret = catpt_ipc_set_device_format(cdev, &devfmt);
@@ -853,9 +855,12 @@ static int catpt_mixer_volume_get(struct snd_kcontrol *kcontrol,
snd_soc_kcontrol_component(kcontrol);
struct catpt_dev *cdev = dev_get_drvdata(component->dev);
u32 dspvol;
+ int ret;
int i;
- pm_runtime_get_sync(cdev->dev);
+ ret = pm_runtime_resume_and_get(cdev->dev);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
for (i = 0; i < CATPT_CHANNELS_MAX; i++) {
dspvol = catpt_mixer_volume(cdev, &cdev->mixer, i);
@@ -876,7 +881,9 @@ static int catpt_mixer_volume_put(struct snd_kcontrol *kcontrol,
struct catpt_dev *cdev = dev_get_drvdata(component->dev);
int ret;
- pm_runtime_get_sync(cdev->dev);
+ ret = pm_runtime_resume_and_get(cdev->dev);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
ret = catpt_set_dspvol(cdev, cdev->mixer.mixer_hw_id,
ucontrol->value.integer.value);
@@ -897,6 +904,7 @@ static int catpt_stream_volume_get(struct snd_kcontrol *kcontrol,
struct catpt_dev *cdev = dev_get_drvdata(component->dev);
long *ctlvol = (long *)kcontrol->private_value;
u32 dspvol;
+ int ret;
int i;
stream = catpt_stream_find(cdev, pin_id);
@@ -906,7 +914,9 @@ static int catpt_stream_volume_get(struct snd_kcontrol *kcontrol,
return 0;
}
- pm_runtime_get_sync(cdev->dev);
+ ret = pm_runtime_resume_and_get(cdev->dev);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
for (i = 0; i < CATPT_CHANNELS_MAX; i++) {
dspvol = catpt_stream_volume(cdev, stream, i);
@@ -937,7 +947,9 @@ static int catpt_stream_volume_put(struct snd_kcontrol *kcontrol,
return 0;
}
- pm_runtime_get_sync(cdev->dev);
+ ret = pm_runtime_resume_and_get(cdev->dev);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
ret = catpt_set_dspvol(cdev, stream->info.stream_hw_id,
ucontrol->value.integer.value);
@@ -1013,7 +1025,9 @@ static int catpt_loopback_switch_put(struct snd_kcontrol *kcontrol,
return 0;
}
- pm_runtime_get_sync(cdev->dev);
+ ret = pm_runtime_resume_and_get(cdev->dev);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
ret = catpt_ipc_mute_loopback(cdev, stream->info.stream_hw_id, mute);
diff --git a/sound/soc/intel/catpt/sysfs.c b/sound/soc/intel/catpt/sysfs.c
index 9579e233a15d..1bdbcc04dc71 100644
--- a/sound/soc/intel/catpt/sysfs.c
+++ b/sound/soc/intel/catpt/sysfs.c
@@ -15,7 +15,9 @@ static ssize_t fw_version_show(struct device *dev,
struct catpt_fw_version version;
int ret;
- pm_runtime_get_sync(cdev->dev);
+ ret = pm_runtime_resume_and_get(cdev->dev);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
ret = catpt_ipc_get_fw_version(cdev, &version);
diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile
index fef0b2d1de68..8ca8f872ec80 100644
--- a/sound/soc/intel/common/Makefile
+++ b/sound/soc/intel/common/Makefile
@@ -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
diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c
index c1385161cdc8..9990d5502d26 100644
--- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c
@@ -8,6 +8,11 @@
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
+static const struct snd_soc_acpi_codecs essx_83x6 = {
+ .num_codecs = 3,
+ .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
+};
+
static const struct snd_soc_acpi_endpoint single_endpoint = {
.num = 0,
.aggregated = 0,
@@ -137,6 +142,15 @@ static const struct snd_soc_acpi_adr_device rt1316_2_single_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt1316_3_single_adr[] = {
+ {
+ .adr = 0x000330025D131601ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt1316-1"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt714_0_adr[] = {
{
.adr = 0x000030025D071401ull,
@@ -326,6 +340,20 @@ static const struct snd_soc_acpi_link_adr adl_sdw_rt1316_link2_rt714_link0[] = {
{}
};
+static const struct snd_soc_acpi_link_adr adl_sdw_rt711_link0_rt1316_link3[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
+ .adr_d = rt711_sdca_0_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt1316_3_single_adr),
+ .adr_d = rt1316_3_single_adr,
+ },
+ {}
+};
+
static const struct snd_soc_acpi_adr_device mx8373_2_adr[] = {
{
.adr = 0x000223019F837300ull,
@@ -412,6 +440,11 @@ static const struct snd_soc_acpi_codecs adl_max98390_amp = {
.codecs = {"MX98390"}
};
+static const struct snd_soc_acpi_codecs adl_lt6911_hdmi = {
+ .num_codecs = 1,
+ .codecs = {"INTC10B0"}
+};
+
struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
{
.comp_ids = &adl_rt5682_rt5682s_hp,
@@ -479,12 +512,34 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
.drv_name = "adl_rt5682",
.sof_tplg_filename = "sof-adl-rt5682.tplg",
},
+ {
+ .id = "10134242",
+ .drv_name = "adl_mx98360a_cs4242",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &adl_max98360a_amp,
+ .sof_tplg_filename = "sof-adl-max98360a-cs42l42.tplg",
+ },
/* place amp-only boards in the end of table */
{
.id = "CSC3541",
.drv_name = "adl_cs35l41",
.sof_tplg_filename = "sof-adl-cs35l41.tplg",
},
+ {
+ .comp_ids = &essx_83x6,
+ .drv_name = "adl_es83x6_c1_h02",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &adl_lt6911_hdmi,
+ .sof_tplg_filename = "sof-adl-es83x6-ssp1-hdmi-ssp02.tplg",
+ },
+ {
+ .comp_ids = &essx_83x6,
+ .drv_name = "sof-essx8336",
+ .sof_tplg_filename = "sof-adl-es83x6", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER |
+ SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
+ SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_machines);
@@ -540,6 +595,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = {
.sof_tplg_filename = "sof-adl-rt1316-l2-mono-rt714-l0.tplg",
},
{
+ .link_mask = 0x9, /* 2 active links required */
+ .links = adl_sdw_rt711_link0_rt1316_link3,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-adl-rt711-l0-rt1316-l3.tplg",
+ },
+ {
.link_mask = 0x1, /* link0 required */
.links = adl_rvp,
.drv_name = "sof_sdw",
diff --git a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c
index 0441df97b260..cbcb649604e5 100644
--- a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c
@@ -12,7 +12,7 @@
struct snd_soc_acpi_mach snd_soc_acpi_intel_haswell_machines[] = {
{
.id = "INT33CA",
- .drv_name = "haswell-audio",
+ .drv_name = "hsw_rt5640",
.fw_filename = "intel/IntcSST1.bin",
.sof_tplg_filename = "sof-hsw.tplg",
},
@@ -23,7 +23,7 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_haswell_machines);
struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = {
{
.id = "INT343A",
- .drv_name = "broadwell-audio",
+ .drv_name = "bdw_rt286",
.fw_filename = "intel/IntcSST2.bin",
.sof_tplg_filename = "sof-bdw-rt286.tplg",
},
@@ -41,7 +41,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = {
},
{
.id = "INT33CA",
- .drv_name = "haswell-audio",
+ .drv_name = "hsw_rt5640",
.fw_filename = "intel/IntcSST2.bin",
.sof_tplg_filename = "sof-bdw-rt5640.tplg",
},
diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
new file mode 100644
index 000000000000..36c361fb28a4
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
@@ -0,0 +1,89 @@
+// 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"
+
+static const struct snd_soc_acpi_codecs mtl_max98357a_amp = {
+ .num_codecs = 1,
+ .codecs = {"MX98357A"}
+};
+
+static const struct snd_soc_acpi_codecs mtl_rt5682_rt5682s_hp = {
+ .num_codecs = 2,
+ .codecs = {"10EC5682", "RTL5682"},
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[] = {
+ {
+ .comp_ids = &mtl_rt5682_rt5682s_hp,
+ .drv_name = "mtl_mx98357_rt5682",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &mtl_max98357a_amp,
+ .sof_tplg_filename = "sof-mtl-max98357a-rt5682.tplg",
+ },
+ {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_machines);
+
+static const struct snd_soc_acpi_endpoint single_endpoint = {
+ .num = 0,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+};
+
+static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = {
+ {
+ .adr = 0x000030025D071101ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt711"
+ }
+};
+
+static const struct snd_soc_acpi_link_adr mtl_rvp[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
+ .adr_d = rt711_sdca_0_adr,
+ },
+ {}
+};
+
+/* 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",
+ },
+ {
+ .link_mask = BIT(0),
+ .links = mtl_rvp,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-rt711.tplg",
+ },
+ {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_sdw_machines);
diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c
index a6fb74ba1c42..b4893365d01d 100644
--- a/sound/soc/intel/keembay/kmb_platform.c
+++ b/sound/soc/intel/keembay/kmb_platform.c
@@ -388,15 +388,17 @@ static snd_pcm_uframes_t kmb_pcm_pointer(struct snd_soc_component *component,
}
static const struct snd_soc_component_driver kmb_component = {
- .name = "kmb",
- .pcm_construct = kmb_platform_pcm_new,
- .open = kmb_pcm_open,
- .trigger = kmb_pcm_trigger,
- .pointer = kmb_pcm_pointer,
+ .name = "kmb",
+ .pcm_construct = kmb_platform_pcm_new,
+ .open = kmb_pcm_open,
+ .trigger = kmb_pcm_trigger,
+ .pointer = kmb_pcm_pointer,
+ .legacy_dai_naming = 1,
};
static const struct snd_soc_component_driver kmb_component_dma = {
- .name = "kmb",
+ .name = "kmb",
+ .legacy_dai_naming = 1,
};
static int kmb_probe(struct snd_soc_dai *cpu_dai)
@@ -497,11 +499,11 @@ static int kmb_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
int ret;
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BC_FC:
kmb_i2s->clock_provider = false;
ret = 0;
break;
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BP_FP:
writel(CLOCK_PROVIDER_MODE, kmb_i2s->pss_base + I2S_GEN_CFG_0);
ret = clk_prepare_enable(kmb_i2s->clk_i2s);
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index 55f310e91b55..9d72ebd812af 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -1380,7 +1380,10 @@ static int skl_platform_soc_probe(struct snd_soc_component *component)
const struct skl_dsp_ops *ops;
int ret;
- pm_runtime_get_sync(component->dev);
+ ret = pm_runtime_resume_and_get(component->dev);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
+
if (bus->ppcap) {
skl->component = component;
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index 9bdf020a2b64..e06eac592da1 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -2950,9 +2950,6 @@ static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w,
block_size = ret;
off += array->size;
- array = (struct snd_soc_tplg_vendor_array *)
- (tplg_w->priv.data + off);
-
data = (tplg_w->priv.data + off);
if (block_type == SKL_TYPE_TUPLE) {
@@ -3599,9 +3596,6 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
block_size = ret;
off += array->size;
- array = (struct snd_soc_tplg_vendor_array *)
- (manifest->priv.data + off);
-
data = (manifest->priv.data + off);
if (block_type == SKL_TYPE_TUPLE) {