summaryrefslogtreecommitdiff
path: root/sound/soc/intel
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/intel')
-rw-r--r--sound/soc/intel/Kconfig3
-rw-r--r--sound/soc/intel/avs/Makefile4
-rw-r--r--sound/soc/intel/avs/apl.c28
-rw-r--r--sound/soc/intel/avs/avs.h92
-rw-r--r--sound/soc/intel/avs/board_selection.c55
-rw-r--r--sound/soc/intel/avs/boards/Kconfig18
-rw-r--r--sound/soc/intel/avs/boards/Makefile4
-rw-r--r--sound/soc/intel/avs/boards/da7219.c41
-rw-r--r--sound/soc/intel/avs/boards/hdaudio.c1
-rw-r--r--sound/soc/intel/avs/boards/max98373.c2
-rw-r--r--sound/soc/intel/avs/boards/max98927.c236
-rw-r--r--sound/soc/intel/avs/boards/nau8825.c35
-rw-r--r--sound/soc/intel/avs/boards/probe.c64
-rw-r--r--sound/soc/intel/avs/boards/rt274.c30
-rw-r--r--sound/soc/intel/avs/boards/rt286.c37
-rw-r--r--sound/soc/intel/avs/boards/rt298.c61
-rw-r--r--sound/soc/intel/avs/boards/rt5682.c31
-rw-r--r--sound/soc/intel/avs/boards/ssm4567.c2
-rw-r--r--sound/soc/intel/avs/core.c118
-rw-r--r--sound/soc/intel/avs/debugfs.c436
-rw-r--r--sound/soc/intel/avs/ipc.c10
-rw-r--r--sound/soc/intel/avs/loader.c28
-rw-r--r--sound/soc/intel/avs/messages.c117
-rw-r--r--sound/soc/intel/avs/messages.h55
-rw-r--r--sound/soc/intel/avs/pcm.c422
-rw-r--r--sound/soc/intel/avs/probes.c313
-rw-r--r--sound/soc/intel/avs/registers.h3
-rw-r--r--sound/soc/intel/avs/skl.c21
-rw-r--r--sound/soc/intel/avs/topology.c10
-rw-r--r--sound/soc/intel/avs/utils.c22
-rw-r--r--sound/soc/intel/boards/Kconfig1
-rw-r--r--sound/soc/intel/boards/Makefile3
-rw-r--r--sound/soc/intel/boards/bdw-rt5650.c2
-rw-r--r--sound/soc/intel/boards/bdw-rt5677.c2
-rw-r--r--sound/soc/intel/boards/bdw_rt286.c55
-rw-r--r--sound/soc/intel/boards/bxt_da7219_max98357a.c3
-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_es8316.c2
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c2
-rw-r--r--sound/soc/intel/boards/bytcr_rt5651.c2
-rw-r--r--sound/soc/intel/boards/bytcr_wm5102.c2
-rw-r--r--sound/soc/intel/boards/cht_bsw_max98090_ti.c2
-rw-r--r--sound/soc/intel/boards/cht_bsw_nau8824.c2
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5645.c2
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5672.c2
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98357a.c3
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98927.c3
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_max98357a.c2
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_ssm4567.c2
-rw-r--r--sound/soc/intel/boards/sof_cirrus_common.c2
-rw-r--r--sound/soc/intel/boards/sof_da7219_max98373.c4
-rw-r--r--sound/soc/intel/boards/sof_es8336.c2
-rw-r--r--sound/soc/intel/boards/sof_nau8825.c16
-rw-r--r--sound/soc/intel/boards/sof_realtek_common.c3
-rw-r--r--sound/soc/intel/boards/sof_rt5682.c13
-rw-r--r--sound/soc/intel/boards/sof_sdw.c54
-rw-r--r--sound/soc/intel/boards/sof_sdw_amp_coeff_tables.h300
-rw-r--r--sound/soc/intel/boards/sof_sdw_common.h12
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt1308.c158
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt1316.c120
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt_amp.c359
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-adl-match.c16
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-jsl-match.c5
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-mtl-match.c59
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-rpl-match.c157
-rw-r--r--sound/soc/intel/skylake/skl-messages.c6
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c35
-rw-r--r--sound/soc/intel/skylake/skl-sst-cldma.c27
-rw-r--r--sound/soc/intel/skylake/skl-topology.c73
-rw-r--r--sound/soc/intel/skylake/skl-topology.h1
-rw-r--r--sound/soc/intel/skylake/skl.c16
72 files changed, 3055 insertions, 778 deletions
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index d2ca710ac3fa..4b9e498e3303 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -177,7 +177,7 @@ config SND_SOC_INTEL_SKYLAKE_COMMON
select SND_HDA_DSP_LOADER
select SND_SOC_TOPOLOGY
select SND_SOC_INTEL_SST
- select SND_SOC_HDAC_HDA if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC
+ select SND_SOC_HDAC_HDA
select SND_SOC_ACPI_INTEL_MATCH
select SND_INTEL_DSP_CONFIG
help
@@ -217,6 +217,7 @@ config SND_SOC_INTEL_AVS
select SND_SOC_ACPI if ACPI
select SND_SOC_TOPOLOGY
select SND_SOC_HDA
+ select SND_SOC_COMPRESS if DEBUG_FS
select SND_HDA_EXT_CORE
select SND_HDA_DSP_LOADER
select SND_INTEL_DSP_CONFIG
diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile
index 919212825f21..1c6924a1ebca 100644
--- a/sound/soc/intel/avs/Makefile
+++ b/sound/soc/intel/avs/Makefile
@@ -9,6 +9,10 @@ snd-soc-avs-objs += trace.o
# tell define_trace.h where to find the trace header
CFLAGS_trace.o := -I$(src)
+ifneq ($(CONFIG_DEBUG_FS),)
+snd-soc-avs-objs += probes.o debugfs.o
+endif
+
obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
# Machine support
diff --git a/sound/soc/intel/avs/apl.c b/sound/soc/intel/avs/apl.c
index b8e2b23c9f64..02683dce277a 100644
--- a/sound/soc/intel/avs/apl.c
+++ b/sound/soc/intel/avs/apl.c
@@ -13,8 +13,9 @@
#include "path.h"
#include "topology.h"
-static int apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
- u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
+static int __maybe_unused
+apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
+ u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
{
struct apl_log_state_info *info;
u32 size, num_cores = adev->hw_cfg.dsp_cores;
@@ -50,7 +51,6 @@ static int apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32
static int apl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg)
{
struct apl_log_buffer_layout layout;
- unsigned long flags;
void __iomem *addr, *buf;
addr = avs_log_buffer_addr(adev, msg->log.core);
@@ -59,26 +59,20 @@ static int apl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg
memcpy_fromio(&layout, addr, sizeof(layout));
- spin_lock_irqsave(&adev->dbg.trace_lock, flags);
- if (!kfifo_initialized(&adev->dbg.trace_fifo))
+ if (!avs_logging_fw(adev))
/* consume the logs regardless of consumer presence */
goto update_read_ptr;
buf = apl_log_payload_addr(addr);
if (layout.read_ptr > layout.write_ptr) {
- __kfifo_fromio_locked(&adev->dbg.trace_fifo, buf + layout.read_ptr,
- apl_log_payload_size(adev) - layout.read_ptr,
- &adev->dbg.fifo_lock);
+ avs_dump_fw_log(adev, buf + layout.read_ptr,
+ apl_log_payload_size(adev) - layout.read_ptr);
layout.read_ptr = 0;
}
- __kfifo_fromio_locked(&adev->dbg.trace_fifo, buf + layout.read_ptr,
- layout.write_ptr - layout.read_ptr, &adev->dbg.fifo_lock);
-
- wake_up(&adev->dbg.trace_waitq);
+ avs_dump_fw_log_wakeup(adev, buf + layout.read_ptr, layout.write_ptr - layout.read_ptr);
update_read_ptr:
- spin_unlock_irqrestore(&adev->dbg.trace_lock, flags);
writel(layout.write_ptr, addr);
return 0;
}
@@ -133,12 +127,14 @@ static int apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg)
buf = apl_log_payload_addr(addr);
memcpy_fromio(&layout, addr, sizeof(layout));
if (!apl_is_entry_stackdump(buf + layout.read_ptr)) {
+ union avs_notify_msg lbs_msg = AVS_NOTIFICATION(LOG_BUFFER_STATUS);
+
/*
* DSP awaits the remaining logs to be
* gathered before dumping stack
*/
- msg->log.core = msg->ext.coredump.core_id;
- avs_dsp_op(adev, log_buffer_status, msg);
+ lbs_msg.log.core = msg->ext.coredump.core_id;
+ avs_log_buffer_status_locked(adev, &lbs_msg);
}
pos = dump + AVS_FW_REGS_SIZE;
@@ -241,10 +237,10 @@ const struct avs_dsp_ops apl_dsp_ops = {
.load_basefw = avs_hda_load_basefw,
.load_lib = avs_hda_load_library,
.transfer_mods = avs_hda_transfer_modules,
- .enable_logs = apl_enable_logs,
.log_buffer_offset = skl_log_buffer_offset,
.log_buffer_status = apl_log_buffer_status,
.coredump = apl_coredump,
.d0ix_toggle = apl_d0ix_toggle,
.set_d0ix = apl_set_d0ix,
+ AVS_SET_ENABLE_LOGS_OP(apl)
};
diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index 92e37722d280..d7fccdcb9c16 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -9,6 +9,7 @@
#ifndef __SOUND_SOC_INTEL_AVS_H
#define __SOUND_SOC_INTEL_AVS_H
+#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/kfifo.h>
@@ -24,6 +25,13 @@ struct avs_tplg_library;
struct avs_soc_component;
struct avs_ipc_msg;
+#ifdef CONFIG_ACPI
+#define AVS_S0IX_SUPPORTED \
+ (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)
+#else
+#define AVS_S0IX_SUPPORTED false
+#endif
+
/*
* struct avs_dsp_ops - Platform-specific DSP operations
*
@@ -86,16 +94,6 @@ struct avs_fw_entry {
struct list_head node;
};
-struct avs_debug {
- struct kfifo trace_fifo;
- spinlock_t fifo_lock; /* serialize I/O for trace_fifo */
- spinlock_t trace_lock; /* serialize debug window I/O between each LOG_BUFFER_STATUS */
- wait_queue_head_t trace_waitq;
- u32 aging_timer_period;
- u32 fifo_full_timer_period;
- u32 logged_resources; /* context dependent: core or library */
-};
-
/*
* struct avs_dev - Intel HD-Audio driver data
*
@@ -127,6 +125,7 @@ struct avs_dev {
struct list_head fw_list;
int *core_refs; /* reference count per core */
char **lib_names;
+ int num_lp_paths;
struct completion fw_ready;
struct work_struct probe_work;
@@ -138,7 +137,18 @@ struct avs_dev {
spinlock_t path_list_lock;
struct mutex path_mutex;
- struct avs_debug dbg;
+ spinlock_t trace_lock; /* serialize debug window I/O between each LOG_BUFFER_STATUS */
+#ifdef CONFIG_DEBUG_FS
+ struct kfifo trace_fifo;
+ wait_queue_head_t trace_waitq;
+ u32 aging_timer_period;
+ u32 fifo_full_timer_period;
+ u32 logged_resources; /* context dependent: core or library */
+ struct dentry *debugfs_root;
+ /* probes */
+ struct hdac_ext_stream *extractor;
+ unsigned int num_probe_streams;
+#endif
};
/* from hda_bus to avs_dev */
@@ -220,8 +230,10 @@ static inline void avs_ipc_err(struct avs_dev *adev, struct avs_ipc_msg *tx,
/*
* If IPC channel is blocked e.g.: due to ongoing recovery,
* -EPERM error code is expected and thus it's not an actual error.
+ *
+ * Unsupported IPCs are of no harm either.
*/
- if (error == -EPERM)
+ if (error == -EPERM || error == AVS_IPC_NOT_SUPPORTED)
dev_dbg(adev->dev, "%s 0x%08x 0x%08x failed: %d\n", name,
tx->glb.primary, tx->glb.ext.val, error);
else
@@ -311,6 +323,9 @@ struct avs_soc_component {
extern const struct snd_soc_dai_ops avs_dai_fe_ops;
+int avs_soc_component_register(struct device *dev, const char *name,
+ const struct snd_soc_component_driver *drv,
+ struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais);
int avs_dmic_platform_register(struct avs_dev *adev, const char *name);
int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask,
unsigned long *tdms);
@@ -321,9 +336,6 @@ void avs_unregister_all_boards(struct avs_dev *adev);
/* Firmware tracing helpers */
-unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src, unsigned int len,
- spinlock_t *lock);
-
#define avs_log_buffer_size(adev) \
((adev)->fw_cfg.trace_log_bytes / (adev)->hw_cfg.dsp_cores)
@@ -334,6 +346,18 @@ unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src,
(avs_sram_addr(adev, AVS_DEBUG_WINDOW) + __offset); \
})
+static inline int avs_log_buffer_status_locked(struct avs_dev *adev, union avs_notify_msg *msg)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&adev->trace_lock, flags);
+ ret = avs_dsp_op(adev, log_buffer_status, msg);
+ spin_unlock_irqrestore(&adev->trace_lock, flags);
+
+ return ret;
+}
+
struct apl_log_buffer_layout {
u32 read_ptr;
u32 write_ptr;
@@ -346,4 +370,42 @@ struct apl_log_buffer_layout {
#define apl_log_payload_addr(addr) \
(addr + sizeof(struct apl_log_buffer_layout))
+#ifdef CONFIG_DEBUG_FS
+#define AVS_SET_ENABLE_LOGS_OP(name) \
+ .enable_logs = name##_enable_logs
+
+bool avs_logging_fw(struct avs_dev *adev);
+void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len);
+void avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, unsigned int len);
+
+int avs_probe_platform_register(struct avs_dev *adev, const char *name);
+
+void avs_debugfs_init(struct avs_dev *adev);
+void avs_debugfs_exit(struct avs_dev *adev);
+#else
+#define AVS_SET_ENABLE_LOGS_OP(name)
+
+static inline bool avs_logging_fw(struct avs_dev *adev)
+{
+ return false;
+}
+
+static inline void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len)
+{
+}
+
+static inline void
+avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, unsigned int len)
+{
+}
+
+static inline int avs_probe_platform_register(struct avs_dev *adev, const char *name)
+{
+ return 0;
+}
+
+static inline void avs_debugfs_init(struct avs_dev *adev) { }
+static inline void avs_debugfs_exit(struct avs_dev *adev) { }
+#endif
+
#endif /* __SOUND_SOC_INTEL_AVS_H */
diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c
index 87f9c18be238..b2823c2107f7 100644
--- a/sound/soc/intel/avs/board_selection.c
+++ b/sound/soc/intel/avs/board_selection.c
@@ -29,6 +29,12 @@ static const struct dmi_system_id kbl_dmi_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "Skylake Y LPDDR3 RVP3"),
},
},
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_BOARD_NAME, "AmberLake Y"),
+ },
+ },
{}
};
@@ -122,6 +128,14 @@ static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = {
.tplg_filename = "rt298-tplg.bin",
},
{
+ .id = "MX98927",
+ .drv_name = "avs_max98927",
+ .mach_params = {
+ .i2s_link_mask = AVS_SSP(0),
+ },
+ .tplg_filename = "max98927-tplg.bin",
+ },
+ {
.id = "MX98373",
.drv_name = "avs_max98373",
.mach_params = {
@@ -130,6 +144,14 @@ static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = {
.tplg_filename = "max98373-tplg.bin",
},
{
+ .id = "MX98357A",
+ .drv_name = "avs_max98357a",
+ .mach_params = {
+ .i2s_link_mask = AVS_SSP(0),
+ },
+ .tplg_filename = "max98357a-tplg.bin",
+ },
+ {
.id = "DLGS7219",
.drv_name = "avs_da7219",
.mach_params = {
@@ -269,6 +291,33 @@ static void board_pdev_unregister(void *data)
platform_device_unregister(data);
}
+static int __maybe_unused avs_register_probe_board(struct avs_dev *adev)
+{
+ struct platform_device *board;
+ struct snd_soc_acpi_mach mach = {{0}};
+ int ret;
+
+ ret = avs_probe_platform_register(adev, "probe-platform");
+ if (ret < 0)
+ return ret;
+
+ mach.mach_params.platform = "probe-platform";
+
+ board = platform_device_register_data(NULL, "avs_probe_mb", PLATFORM_DEVID_NONE,
+ (const void *)&mach, sizeof(mach));
+ if (IS_ERR(board)) {
+ dev_err(adev->dev, "probe board register failed\n");
+ return PTR_ERR(board);
+ }
+
+ ret = devm_add_action(adev->dev, board_pdev_unregister, board);
+ if (ret < 0) {
+ platform_device_unregister(board);
+ return ret;
+ }
+ return 0;
+}
+
static int avs_register_dmic_board(struct avs_dev *adev)
{
struct platform_device *codec, *board;
@@ -478,6 +527,12 @@ int avs_register_all_boards(struct avs_dev *adev)
{
int ret;
+#ifdef CONFIG_DEBUG_FS
+ ret = avs_register_probe_board(adev);
+ if (ret < 0)
+ dev_warn(adev->dev, "enumerate PROBE endpoints failed: %d\n", ret);
+#endif
+
ret = avs_register_dmic_board(adev);
if (ret < 0)
dev_warn(adev->dev, "enumerate DMIC endpoints failed: %d\n",
diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig
index 4d68e3ef992b..e4c230efe8d7 100644
--- a/sound/soc/intel/avs/boards/Kconfig
+++ b/sound/soc/intel/avs/boards/Kconfig
@@ -36,6 +36,16 @@ config SND_SOC_INTEL_AVS_MACH_I2S_TEST
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_MAX98927
+ tristate "max98927 I2S board"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_MAX98927
+ help
+ This adds support for AVS with MAX98927 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_MAX98357A
tristate "max98357A I2S board"
depends on I2C
@@ -67,6 +77,14 @@ config SND_SOC_INTEL_AVS_MACH_NAU8825
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_PROBE
+ tristate "Probing (data) board"
+ depends on DEBUG_FS
+ select SND_HWDEP
+ help
+ This adds support for data probing board which can be used to
+ gather data from runtime stream over compress operations.
+
config SND_SOC_INTEL_AVS_MACH_RT274
tristate "rt274 in I2S mode"
depends on I2C
diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile
index bc75376d58c2..b81343420370 100644
--- a/sound/soc/intel/avs/boards/Makefile
+++ b/sound/soc/intel/avs/boards/Makefile
@@ -4,9 +4,11 @@ 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-max98927-objs := max98927.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-probe-objs := probe.o
snd-soc-avs-rt274-objs := rt274.o
snd-soc-avs-rt286-objs := rt286.o
snd-soc-avs-rt298-objs := rt298.o
@@ -17,9 +19,11 @@ 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_MAX98927) += snd-soc-avs-max98927.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_PROBE) += snd-soc-avs-probe.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
diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c
index 02ae542ad779..acd43b6108e9 100644
--- a/sound/soc/intel/avs/boards/da7219.c
+++ b/sound/soc/intel/avs/boards/da7219.c
@@ -6,6 +6,7 @@
//
#include <linux/module.h>
+#include <linux/platform_data/x86/soc.h>
#include <linux/platform_device.h>
#include <sound/jack.h>
#include <sound/pcm.h>
@@ -15,7 +16,6 @@
#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"
@@ -72,15 +72,18 @@ static const struct snd_soc_dapm_route card_base_routes[] = {
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_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+ struct snd_soc_component *component = codec_dai->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;
+ if (soc_intel_is_apl())
+ clk_freq = 19200000;
+ else /* kbl */
+ clk_freq = 24576000;
ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, clk_freq, SND_SOC_CLOCK_IN);
if (ret) {
@@ -106,9 +109,12 @@ static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime)
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 snd_soc_component_set_jack(component, jack, NULL);
+}
- return 0;
+static void avs_da7219_codec_exit(struct snd_soc_pcm_runtime *rtd)
+{
+ snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
}
static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
@@ -143,6 +149,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
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->exit = avs_da7219_codec_exit;
dl->nonatomic = 1;
dl->no_pcm = 1;
dl->dpcm_capture = 1;
@@ -185,30 +192,19 @@ static int avs_create_dapm_routes(struct device *dev, int ssp_port,
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);
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, DA7219_DAI_NAME);
+
+ return snd_soc_component_set_jack(codec_dai->component, NULL, 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, DA7219_DAI_NAME);
struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
- return avs_card_set_jack(card, jack);
+ return snd_soc_component_set_jack(codec_dai->component, jack, NULL);
}
static int avs_da7219_probe(struct platform_device *pdev)
@@ -246,7 +242,6 @@ static int avs_da7219_probe(struct platform_device *pdev)
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;
diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c
index 073663ba140d..e68c4c7aa2ba 100644
--- a/sound/soc/intel/avs/boards/hdaudio.c
+++ b/sound/soc/intel/avs/boards/hdaudio.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <sound/hda_codec.h>
#include <sound/hda_i915.h>
diff --git a/sound/soc/intel/avs/boards/max98373.c b/sound/soc/intel/avs/boards/max98373.c
index 0fa8f5606385..8e221ecd34b0 100644
--- a/sound/soc/intel/avs/boards/max98373.c
+++ b/sound/soc/intel/avs/boards/max98373.c
@@ -53,7 +53,7 @@ avs_max98373_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_par
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 */
+ /* The ADSP will convert the FE rate to 48k, stereo */
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
diff --git a/sound/soc/intel/avs/boards/max98927.c b/sound/soc/intel/avs/boards/max98927.c
new file mode 100644
index 000000000000..7cccce99f92e
--- /dev/null
+++ b/sound/soc/intel/avs/boards/max98927.c
@@ -0,0 +1,236 @@
+// 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 MAX98927_DEV0_NAME "i2c-MX98927:00"
+#define MAX98927_DEV1_NAME "i2c-MX98927:01"
+#define MAX98927_CODEC_NAME "max98927-aif1"
+
+static struct snd_soc_codec_conf card_codec_conf[] = {
+ {
+ .dlc = COMP_CODEC_CONF(MAX98927_DEV0_NAME),
+ .name_prefix = "Right",
+ },
+ {
+ .dlc = COMP_CODEC_CONF(MAX98927_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_max98927_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 convert 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_max98927_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 = 0;
+ int i;
+
+ for_each_rtd_codec_dais(runtime, i, codec_dai) {
+ if (!strcmp(codec_dai->component->name, MAX98927_DEV0_NAME))
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16);
+ else if (!strcmp(codec_dai->component->name, MAX98927_DEV1_NAME))
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16);
+
+ if (ret < 0) {
+ dev_err(runtime->dev, "hw_params for %s failed: %d\n",
+ codec_dai->component->name, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_ops avs_max98927_ops = {
+ .hw_params = avs_max98927_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, MAX98927_DEV0_NAME);
+ dl->codecs[0].dai_name = devm_kasprintf(dev, GFP_KERNEL, MAX98927_CODEC_NAME);
+ dl->codecs[1].name = devm_kasprintf(dev, GFP_KERNEL, MAX98927_DEV1_NAME);
+ dl->codecs[1].dai_name = devm_kasprintf(dev, GFP_KERNEL, MAX98927_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_CBS_CFS;
+ dl->be_hw_params_fixup = avs_max98927_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_max98927_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_max98927_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_max98927";
+ 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_max98927_driver = {
+ .probe = avs_max98927_probe,
+ .driver = {
+ .name = "avs_max98927",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_max98927_driver)
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_max98927");
diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c
index f76909e9f990..6731d8a49076 100644
--- a/sound/soc/intel/avs/boards/nau8825.c
+++ b/sound/soc/intel/avs/boards/nau8825.c
@@ -79,11 +79,9 @@ static struct snd_soc_jack_pin card_headset_pins[] = {
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_card *card = runtime->card;
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);
@@ -108,11 +106,12 @@ static int avs_nau8825_codec_init(struct snd_soc_pcm_runtime *runtime)
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 snd_soc_component_set_jack(asoc_rtd_to_codec(runtime, 0)->component, jack, NULL);
+}
- return 0;
+static void avs_nau8825_codec_exit(struct snd_soc_pcm_runtime *rtd)
+{
+ snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
}
static int
@@ -203,6 +202,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
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->exit = avs_nau8825_codec_exit;
dl->be_hw_params_fixup = avs_nau8825_be_fixup;
dl->ops = &avs_nau8825_ops;
dl->nonatomic = 1;
@@ -247,23 +247,11 @@ static int avs_create_dapm_routes(struct device *dev, int ssp_port,
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);
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI);
+
+ return snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
}
static int avs_card_resume_post(struct snd_soc_card *card)
@@ -280,7 +268,7 @@ static int avs_card_resume_post(struct snd_soc_card *card)
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);
+ return snd_soc_component_set_jack(codec_dai->component, jack, NULL);
}
static int avs_nau8825_probe(struct platform_device *pdev)
@@ -318,7 +306,6 @@ static int avs_nau8825_probe(struct platform_device *pdev)
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;
diff --git a/sound/soc/intel/avs/boards/probe.c b/sound/soc/intel/avs/boards/probe.c
new file mode 100644
index 000000000000..411acaee74f9
--- /dev/null
+++ b/sound/soc/intel/avs/boards/probe.c
@@ -0,0 +1,64 @@
+// 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(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));
+SND_SOC_DAILINK_DEF(probe_cp, DAILINK_COMP_ARRAY(COMP_CPU("Probe Extraction CPU DAI")));
+SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("probe-platform")));
+
+static struct snd_soc_dai_link probe_mb_dai_links[] = {
+ {
+ .name = "Compress Probe Capture",
+ .nonatomic = 1,
+ SND_SOC_DAILINK_REG(probe_cp, dummy, platform),
+ },
+};
+
+static int avs_probe_mb_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ int ret;
+
+ mach = dev_get_platdata(dev);
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ card->name = "avs_probe_mb";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->dai_link = probe_mb_dai_links;
+ card->num_links = ARRAY_SIZE(probe_mb_dai_links);
+ 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_probe_mb_driver = {
+ .probe = avs_probe_mb_probe,
+ .driver = {
+ .name = "avs_probe_mb",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_probe_mb_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_probe_mb");
diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c
index afef5a3ca60b..6a1e121f082f 100644
--- a/sound/soc/intel/avs/boards/rt274.c
+++ b/sound/soc/intel/avs/boards/rt274.c
@@ -119,6 +119,11 @@ static int avs_rt274_codec_init(struct snd_soc_pcm_runtime *runtime)
return 0;
}
+static void avs_rt274_codec_exit(struct snd_soc_pcm_runtime *rtd)
+{
+ snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
+}
+
static int avs_rt274_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
{
struct snd_interval *rate, *channels;
@@ -160,7 +165,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
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");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, RT274_CODEC_DAI);
if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
return -ENOMEM;
@@ -171,6 +176,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
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->exit = avs_rt274_codec_exit;
dl->be_hw_params_fixup = avs_rt274_be_fixup;
dl->nonatomic = 1;
dl->no_pcm = 1;
@@ -214,30 +220,19 @@ static int avs_create_dapm_routes(struct device *dev, int ssp_port,
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);
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT274_CODEC_DAI);
+
+ return snd_soc_component_set_jack(codec_dai->component, NULL, 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, RT274_CODEC_DAI);
struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
- return avs_card_set_jack(card, jack);
+ return snd_soc_component_set_jack(codec_dai->component, jack, NULL);
}
static int avs_rt274_probe(struct platform_device *pdev)
@@ -275,7 +270,6 @@ static int avs_rt274_probe(struct platform_device *pdev)
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;
diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c
index e51d4e181274..8447b37a2a41 100644
--- a/sound/soc/intel/avs/boards/rt286.c
+++ b/sound/soc/intel/avs/boards/rt286.c
@@ -14,6 +14,8 @@
#include <sound/soc-acpi.h>
#include "../../../codecs/rt286.h"
+#define RT286_CODEC_DAI "rt286-aif1"
+
static const struct snd_kcontrol_new card_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Mic Jack"),
@@ -48,10 +50,9 @@ static struct snd_soc_jack_pin card_headset_pins[] = {
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_card *card = runtime->card;
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);
@@ -66,9 +67,12 @@ static int avs_rt286_codec_init(struct snd_soc_pcm_runtime *runtime)
if (ret)
return ret;
- snd_soc_component_set_jack(component, jack, NULL);
+ return snd_soc_component_set_jack(asoc_rtd_to_codec(runtime, 0)->component, jack, NULL);
+}
- return 0;
+static void avs_rt286_codec_exit(struct snd_soc_pcm_runtime *rtd)
+{
+ snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
}
static int avs_rt286_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
@@ -130,7 +134,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
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");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, RT286_CODEC_DAI);
if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
return -ENOMEM;
@@ -141,6 +145,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
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->exit = avs_rt286_codec_exit;
dl->be_hw_params_fixup = avs_rt286_be_fixup;
dl->ops = &avs_rt286_ops;
dl->nonatomic = 1;
@@ -185,30 +190,19 @@ static int avs_create_dapm_routes(struct device *dev, int ssp_port,
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);
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT286_CODEC_DAI);
+
+ return snd_soc_component_set_jack(codec_dai->component, NULL, 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, RT286_CODEC_DAI);
struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
- return avs_card_set_jack(card, jack);
+ return snd_soc_component_set_jack(codec_dai->component, jack, NULL);
}
static int avs_rt286_probe(struct platform_device *pdev)
@@ -246,7 +240,6 @@ static int avs_rt286_probe(struct platform_device *pdev)
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;
diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c
index b28d36872dcb..bd25f0fde35e 100644
--- a/sound/soc/intel/avs/boards/rt298.c
+++ b/sound/soc/intel/avs/boards/rt298.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/dmi.h>
#include <linux/module.h>
#include <sound/jack.h>
#include <sound/pcm.h>
@@ -14,6 +15,18 @@
#include <sound/soc-acpi.h>
#include "../../../codecs/rt298.h"
+#define RT298_CODEC_DAI "rt298-aif1"
+
+static const struct dmi_system_id kblr_dmi_table[] = {
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_BOARD_NAME, "Kabylake R DDR4 RVP"),
+ },
+ },
+ {}
+};
+
static const struct snd_kcontrol_new card_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Mic Jack"),
@@ -48,10 +61,9 @@ static struct snd_soc_jack_pin card_headset_pins[] = {
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_card *card = runtime->card;
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);
@@ -66,9 +78,12 @@ static int avs_rt298_codec_init(struct snd_soc_pcm_runtime *runtime)
if (ret)
return ret;
- snd_soc_component_set_jack(component, jack, NULL);
+ return snd_soc_component_set_jack(asoc_rtd_to_codec(runtime, 0)->component, jack, NULL);
+}
- return 0;
+static void avs_rt298_codec_exit(struct snd_soc_pcm_runtime *rtd)
+{
+ snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
}
static int avs_rt298_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
@@ -96,9 +111,15 @@ avs_rt298_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_param
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ unsigned int clk_freq;
int ret;
- ret = snd_soc_dai_set_sysclk(codec_dai, RT298_SCLK_S_PLL, 19200000, SND_SOC_CLOCK_IN);
+ if (dmi_first_match(kblr_dmi_table))
+ clk_freq = 24000000;
+ else
+ clk_freq = 19200000;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT298_SCLK_S_PLL, clk_freq, SND_SOC_CLOCK_IN);
if (ret < 0)
dev_err(rtd->dev, "Set codec sysclk failed: %d\n", ret);
@@ -130,7 +151,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
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");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, RT298_CODEC_DAI);
if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
return -ENOMEM;
@@ -139,8 +160,12 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
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;
+ if (dmi_first_match(kblr_dmi_table))
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ else
+ 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->exit = avs_rt298_codec_exit;
dl->be_hw_params_fixup = avs_rt298_be_fixup;
dl->ops = &avs_rt298_ops;
dl->nonatomic = 1;
@@ -185,30 +210,19 @@ static int avs_create_dapm_routes(struct device *dev, int ssp_port,
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);
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT298_CODEC_DAI);
+
+ return snd_soc_component_set_jack(codec_dai->component, NULL, 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, RT298_CODEC_DAI);
struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
- return avs_card_set_jack(card, jack);
+ return snd_soc_component_set_jack(codec_dai->component, jack, NULL);
}
static int avs_rt298_probe(struct platform_device *pdev)
@@ -246,7 +260,6 @@ static int avs_rt298_probe(struct platform_device *pdev)
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;
diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c
index 01f9b9f0c12b..473e9fe5d0bf 100644
--- a/sound/soc/intel/avs/boards/rt5682.c
+++ b/sound/soc/intel/avs/boards/rt5682.c
@@ -26,6 +26,7 @@
#define AVS_RT5682_SSP_CODEC_MASK (GENMASK(2, 0))
#define AVS_RT5682_MCLK_EN BIT(3)
#define AVS_RT5682_MCLK_24MHZ BIT(4)
+#define AVS_RT5682_CODEC_DAI_NAME "rt5682-aif1"
/* Default: MCLK on, MCLK 19.2M, SSP0 */
static unsigned long avs_rt5682_quirk = AVS_RT5682_MCLK_EN | AVS_RT5682_SSP_CODEC(0);
@@ -119,6 +120,11 @@ static int avs_rt5682_codec_init(struct snd_soc_pcm_runtime *runtime)
return 0;
};
+static void avs_rt5682_codec_exit(struct snd_soc_pcm_runtime *rtd)
+{
+ snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
+}
+
static int
avs_rt5682_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
{
@@ -184,7 +190,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
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");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, AVS_RT5682_CODEC_DAI_NAME);
if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
return -ENOMEM;
@@ -194,6 +200,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->num_platforms = 1;
dl->id = 0;
dl->init = avs_rt5682_codec_init;
+ dl->exit = avs_rt5682_codec_exit;
dl->ops = &avs_rt5682_ops;
dl->nonatomic = 1;
dl->no_pcm = 1;
@@ -237,30 +244,19 @@ static int avs_create_dapm_routes(struct device *dev, int ssp_port,
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);
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, AVS_RT5682_CODEC_DAI_NAME);
+
+ return snd_soc_component_set_jack(codec_dai->component, NULL, 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, AVS_RT5682_CODEC_DAI_NAME);
struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
- return avs_card_set_jack(card, jack);
+ return snd_soc_component_set_jack(codec_dai->component, jack, NULL);
}
static int avs_rt5682_probe(struct platform_device *pdev)
@@ -304,7 +300,6 @@ static int avs_rt5682_probe(struct platform_device *pdev)
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;
diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c
index 9f84c8ab3447..c5db69612762 100644
--- a/sound/soc/intel/avs/boards/ssm4567.c
+++ b/sound/soc/intel/avs/boards/ssm4567.c
@@ -103,7 +103,7 @@ avs_ssm4567_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_para
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 */
+ /* The ADSP will convert the FE rate to 48k, stereo */
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c
index bb0719c58ca4..2ca24273c491 100644
--- a/sound/soc/intel/avs/core.c
+++ b/sound/soc/intel/avs/core.c
@@ -27,6 +27,14 @@
#include "avs.h"
#include "cldma.h"
+static u32 pgctl_mask = AZX_PGCTL_LSRMD_MASK;
+module_param(pgctl_mask, uint, 0444);
+MODULE_PARM_DESC(pgctl_mask, "PCI PGCTL policy override");
+
+static u32 cgctl_mask = AZX_CGCTL_MISCBDCGE_MASK;
+module_param(cgctl_mask, uint, 0444);
+MODULE_PARM_DESC(cgctl_mask, "PCI CGCTL policy override");
+
static void
avs_hda_update_config_dword(struct hdac_bus *bus, u32 reg, u32 mask, u32 value)
{
@@ -41,19 +49,16 @@ avs_hda_update_config_dword(struct hdac_bus *bus, u32 reg, u32 mask, u32 value)
void avs_hda_power_gating_enable(struct avs_dev *adev, bool enable)
{
- u32 value;
+ u32 value = enable ? 0 : pgctl_mask;
- value = enable ? 0 : AZX_PGCTL_LSRMD_MASK;
- avs_hda_update_config_dword(&adev->base.core, AZX_PCIREG_PGCTL,
- AZX_PGCTL_LSRMD_MASK, value);
+ avs_hda_update_config_dword(&adev->base.core, AZX_PCIREG_PGCTL, pgctl_mask, value);
}
static void avs_hdac_clock_gating_enable(struct hdac_bus *bus, bool enable)
{
- u32 value;
+ u32 value = enable ? cgctl_mask : 0;
- value = enable ? AZX_CGCTL_MISCBDCGE_MASK : 0;
- avs_hda_update_config_dword(bus, AZX_PCIREG_CGCTL, AZX_CGCTL_MISCBDCGE_MASK, value);
+ avs_hda_update_config_dword(bus, AZX_PCIREG_CGCTL, cgctl_mask, value);
}
void avs_hda_clock_gating_enable(struct avs_dev *adev, bool enable)
@@ -63,9 +68,8 @@ void avs_hda_clock_gating_enable(struct avs_dev *adev, bool enable)
void avs_hda_l1sen_enable(struct avs_dev *adev, bool enable)
{
- u32 value;
+ u32 value = enable ? AZX_VS_EM2_L1SEN : 0;
- value = enable ? AZX_VS_EM2_L1SEN : 0;
snd_hdac_chip_updatel(&adev->base.core, VS_EM2, AZX_VS_EM2_L1SEN, value);
}
@@ -210,6 +214,7 @@ static void avs_hda_probe_work(struct work_struct *work)
adev->nhlt = intel_nhlt_init(adev->dev);
if (!adev->nhlt)
dev_info(bus->dev, "platform has no NHLT\n");
+ avs_debugfs_init(adev);
avs_register_all_boards(adev);
@@ -440,7 +445,7 @@ 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_and_coherent(dev, DMA_BIT_MASK(64)))
+ 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);
@@ -487,6 +492,7 @@ static void avs_pci_remove(struct pci_dev *pci)
avs_unregister_all_boards(adev);
+ avs_debugfs_exit(adev);
if (adev->nhlt)
intel_nhlt_free(adev->nhlt);
@@ -504,7 +510,7 @@ static void avs_pci_remove(struct pci_dev *pci)
snd_hdac_bus_free_stream_pages(bus);
snd_hdac_ext_stream_free_all(bus);
/* reverse ml_capabilities */
- snd_hdac_link_free_all(bus);
+ snd_hdac_ext_link_free_all(bus);
snd_hdac_ext_bus_exit(bus);
avs_dsp_core_disable(adev, GENMASK(adev->hw_cfg.dsp_cores - 1, 0));
@@ -534,12 +540,30 @@ static void avs_pci_remove(struct pci_dev *pci)
pm_runtime_get_noresume(&pci->dev);
}
-static int __maybe_unused avs_suspend_common(struct avs_dev *adev)
+static int avs_suspend_standby(struct avs_dev *adev)
+{
+ struct hdac_bus *bus = &adev->base.core;
+ struct pci_dev *pci = adev->base.pci;
+
+ if (bus->cmd_dma_state)
+ snd_hdac_bus_stop_cmd_io(bus);
+
+ snd_hdac_ext_bus_link_power_down_all(bus);
+
+ enable_irq_wake(pci->irq);
+ pci_save_state(pci);
+
+ return 0;
+}
+
+static int __maybe_unused avs_suspend_common(struct avs_dev *adev, bool low_power)
{
struct hdac_bus *bus = &adev->base.core;
int ret;
flush_work(&adev->probe_work);
+ if (low_power && adev->num_lp_paths)
+ return avs_suspend_standby(adev);
snd_hdac_ext_bus_link_power_down_all(bus);
@@ -577,12 +601,30 @@ static int __maybe_unused avs_suspend_common(struct avs_dev *adev)
return 0;
}
-static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool purge)
+static int avs_resume_standby(struct avs_dev *adev)
+{
+ struct hdac_bus *bus = &adev->base.core;
+ struct pci_dev *pci = adev->base.pci;
+
+ pci_restore_state(pci);
+ disable_irq_wake(pci->irq);
+
+ snd_hdac_ext_bus_link_power_up_all(bus);
+
+ if (bus->cmd_dma_state)
+ snd_hdac_bus_init_cmd_io(bus);
+
+ return 0;
+}
+
+static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool low_power, bool purge)
{
struct hdac_bus *bus = &adev->base.core;
- struct hdac_ext_link *hlink;
int ret;
+ if (low_power && adev->num_lp_paths)
+ return avs_resume_standby(adev);
+
snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);
avs_hdac_bus_init_chip(bus, true);
@@ -595,41 +637,55 @@ static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool purge)
return ret;
}
- /* turn off the links that were off before suspend */
- list_for_each_entry(hlink, &bus->hlink_list, list) {
- if (!hlink->ref_count)
- snd_hdac_ext_bus_link_power_down(hlink);
- }
-
- /* check dma status and clean up CORB/RIRB buffers */
- if (!bus->cmd_dma_state)
- snd_hdac_bus_stop_cmd_io(bus);
-
return 0;
}
static int __maybe_unused avs_suspend(struct device *dev)
{
- return avs_suspend_common(to_avs_dev(dev));
+ return avs_suspend_common(to_avs_dev(dev), true);
}
static int __maybe_unused avs_resume(struct device *dev)
{
- return avs_resume_common(to_avs_dev(dev), true);
+ return avs_resume_common(to_avs_dev(dev), true, true);
}
static int __maybe_unused avs_runtime_suspend(struct device *dev)
{
- return avs_suspend_common(to_avs_dev(dev));
+ return avs_suspend_common(to_avs_dev(dev), true);
}
static int __maybe_unused avs_runtime_resume(struct device *dev)
{
- return avs_resume_common(to_avs_dev(dev), true);
+ return avs_resume_common(to_avs_dev(dev), true, false);
+}
+
+static int __maybe_unused avs_freeze(struct device *dev)
+{
+ return avs_suspend_common(to_avs_dev(dev), false);
+}
+static int __maybe_unused avs_thaw(struct device *dev)
+{
+ return avs_resume_common(to_avs_dev(dev), false, true);
+}
+
+static int __maybe_unused avs_poweroff(struct device *dev)
+{
+ return avs_suspend_common(to_avs_dev(dev), false);
+}
+
+static int __maybe_unused avs_restore(struct device *dev)
+{
+ return avs_resume_common(to_avs_dev(dev), false, true);
}
static const struct dev_pm_ops avs_dev_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(avs_suspend, avs_resume)
+ .suspend = avs_suspend,
+ .resume = avs_resume,
+ .freeze = avs_freeze,
+ .thaw = avs_thaw,
+ .poweroff = avs_poweroff,
+ .restore = avs_restore,
SET_RUNTIME_PM_OPS(avs_runtime_suspend, avs_runtime_resume, NULL)
};
@@ -667,7 +723,11 @@ static const struct avs_spec apl_desc = {
static const struct pci_device_id avs_ids[] = {
{ PCI_VDEVICE(INTEL, 0x9d70), (unsigned long)&skl_desc }, /* SKL */
+ { PCI_VDEVICE(INTEL, 0xa170), (unsigned long)&skl_desc }, /* SKL-H */
{ PCI_VDEVICE(INTEL, 0x9d71), (unsigned long)&skl_desc }, /* KBL */
+ { PCI_VDEVICE(INTEL, 0xa171), (unsigned long)&skl_desc }, /* KBL-H */
+ { PCI_VDEVICE(INTEL, 0xa2f0), (unsigned long)&skl_desc }, /* KBL-S */
+ { PCI_VDEVICE(INTEL, 0xa3f0), (unsigned long)&skl_desc }, /* CML-V */
{ PCI_VDEVICE(INTEL, 0x5a98), (unsigned long)&apl_desc }, /* APL */
{ PCI_VDEVICE(INTEL, 0x3198), (unsigned long)&apl_desc }, /* GML */
{ 0 }
diff --git a/sound/soc/intel/avs/debugfs.c b/sound/soc/intel/avs/debugfs.c
new file mode 100644
index 000000000000..bdd388ec01ea
--- /dev/null
+++ b/sound/soc/intel/avs/debugfs.c
@@ -0,0 +1,436 @@
+// 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/debugfs.h>
+#include <linux/kfifo.h>
+#include <linux/wait.h>
+#include <linux/sched/signal.h>
+#include <sound/soc.h>
+#include "avs.h"
+#include "messages.h"
+
+static unsigned int __kfifo_fromio(struct kfifo *fifo, const void __iomem *src, unsigned int len)
+{
+ struct __kfifo *__fifo = &fifo->kfifo;
+ unsigned int l, off;
+
+ len = min(len, kfifo_avail(fifo));
+ off = __fifo->in & __fifo->mask;
+ l = min(len, kfifo_size(fifo) - off);
+
+ memcpy_fromio(__fifo->data + off, src, l);
+ memcpy_fromio(__fifo->data, src + l, len - l);
+ /* Make sure data copied from SRAM is visible to all CPUs. */
+ smp_mb();
+ __fifo->in += len;
+
+ return len;
+}
+
+bool avs_logging_fw(struct avs_dev *adev)
+{
+ return kfifo_initialized(&adev->trace_fifo);
+}
+
+void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len)
+{
+ __kfifo_fromio(&adev->trace_fifo, src, len);
+}
+
+void avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, unsigned int len)
+{
+ avs_dump_fw_log(adev, src, len);
+ wake_up(&adev->trace_waitq);
+}
+
+static ssize_t fw_regs_read(struct file *file, char __user *to, size_t count, loff_t *ppos)
+{
+ struct avs_dev *adev = file->private_data;
+ char *buf;
+ int ret;
+
+ buf = kzalloc(AVS_FW_REGS_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ memcpy_fromio(buf, avs_sram_addr(adev, AVS_FW_REGS_WINDOW), AVS_FW_REGS_SIZE);
+
+ ret = simple_read_from_buffer(to, count, ppos, buf, AVS_FW_REGS_SIZE);
+ kfree(buf);
+ return ret;
+}
+
+static const struct file_operations fw_regs_fops = {
+ .open = simple_open,
+ .read = fw_regs_read,
+ .llseek = no_llseek,
+};
+
+static ssize_t debug_window_read(struct file *file, char __user *to, size_t count, loff_t *ppos)
+{
+ struct avs_dev *adev = file->private_data;
+ size_t size;
+ char *buf;
+ int ret;
+
+ size = adev->hw_cfg.dsp_cores * AVS_WINDOW_CHUNK_SIZE;
+ buf = kzalloc(size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ memcpy_fromio(buf, avs_sram_addr(adev, AVS_DEBUG_WINDOW), size);
+
+ ret = simple_read_from_buffer(to, count, ppos, buf, size);
+ kfree(buf);
+ return ret;
+}
+
+static const struct file_operations debug_window_fops = {
+ .open = simple_open,
+ .read = debug_window_read,
+ .llseek = no_llseek,
+};
+
+static ssize_t probe_points_read(struct file *file, char __user *to, size_t count, loff_t *ppos)
+{
+ struct avs_dev *adev = file->private_data;
+ struct avs_probe_point_desc *desc;
+ size_t num_desc, len = 0;
+ char *buf;
+ int i, ret;
+
+ /* Prevent chaining, send and dump IPC value just once. */
+ if (*ppos)
+ return 0;
+
+ buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = avs_ipc_probe_get_points(adev, &desc, &num_desc);
+ if (ret) {
+ ret = AVS_IPC_RET(ret);
+ goto exit;
+ }
+
+ for (i = 0; i < num_desc; i++) {
+ ret = snprintf(buf + len, PAGE_SIZE - len,
+ "Id: %#010x Purpose: %d Node id: %#x\n",
+ desc[i].id.value, desc[i].purpose, desc[i].node_id.val);
+ if (ret < 0)
+ goto free_desc;
+ len += ret;
+ }
+
+ ret = simple_read_from_buffer(to, count, ppos, buf, len);
+free_desc:
+ kfree(desc);
+exit:
+ kfree(buf);
+ return ret;
+}
+
+static ssize_t probe_points_write(struct file *file, const char __user *from, size_t count,
+ loff_t *ppos)
+{
+ struct avs_dev *adev = file->private_data;
+ struct avs_probe_point_desc *desc;
+ u32 *array, num_elems;
+ size_t bytes;
+ int ret;
+
+ ret = parse_int_array_user(from, count, (int **)&array);
+ if (ret < 0)
+ return ret;
+
+ num_elems = *array;
+ bytes = sizeof(*array) * num_elems;
+ if (bytes % sizeof(*desc)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ desc = (struct avs_probe_point_desc *)&array[1];
+ ret = avs_ipc_probe_connect_points(adev, desc, bytes / sizeof(*desc));
+ if (ret)
+ ret = AVS_IPC_RET(ret);
+ else
+ ret = count;
+exit:
+ kfree(array);
+ return ret;
+}
+
+static const struct file_operations probe_points_fops = {
+ .open = simple_open,
+ .read = probe_points_read,
+ .write = probe_points_write,
+ .llseek = no_llseek,
+};
+
+static ssize_t probe_points_disconnect_write(struct file *file, const char __user *from,
+ size_t count, loff_t *ppos)
+{
+ struct avs_dev *adev = file->private_data;
+ union avs_probe_point_id *id;
+ u32 *array, num_elems;
+ size_t bytes;
+ int ret;
+
+ ret = parse_int_array_user(from, count, (int **)&array);
+ if (ret < 0)
+ return ret;
+
+ num_elems = *array;
+ bytes = sizeof(*array) * num_elems;
+ if (bytes % sizeof(*id)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ id = (union avs_probe_point_id *)&array[1];
+ ret = avs_ipc_probe_disconnect_points(adev, id, bytes / sizeof(*id));
+ if (ret)
+ ret = AVS_IPC_RET(ret);
+ else
+ ret = count;
+exit:
+ kfree(array);
+ return ret;
+}
+
+static const struct file_operations probe_points_disconnect_fops = {
+ .open = simple_open,
+ .write = probe_points_disconnect_write,
+ .llseek = default_llseek,
+};
+
+static ssize_t strace_read(struct file *file, char __user *to, size_t count, loff_t *ppos)
+{
+ struct avs_dev *adev = file->private_data;
+ struct kfifo *fifo = &adev->trace_fifo;
+ unsigned int copied;
+
+ if (kfifo_is_empty(fifo)) {
+ DEFINE_WAIT(wait);
+
+ prepare_to_wait(&adev->trace_waitq, &wait, TASK_INTERRUPTIBLE);
+ if (!signal_pending(current))
+ schedule();
+ finish_wait(&adev->trace_waitq, &wait);
+ }
+
+ if (kfifo_to_user(fifo, to, count, &copied))
+ return -EFAULT;
+ *ppos += copied;
+ return copied;
+}
+
+static int strace_open(struct inode *inode, struct file *file)
+{
+ struct avs_dev *adev = inode->i_private;
+ int ret;
+
+ if (kfifo_initialized(&adev->trace_fifo))
+ return -EBUSY;
+
+ ret = kfifo_alloc(&adev->trace_fifo, PAGE_SIZE, GFP_KERNEL);
+ if (ret < 0)
+ return ret;
+
+ file->private_data = adev;
+ return 0;
+}
+
+static int strace_release(struct inode *inode, struct file *file)
+{
+ union avs_notify_msg msg = AVS_NOTIFICATION(LOG_BUFFER_STATUS);
+ struct avs_dev *adev = file->private_data;
+ unsigned long resource_mask;
+ unsigned long flags, i;
+ u32 num_cores;
+
+ resource_mask = adev->logged_resources;
+ num_cores = adev->hw_cfg.dsp_cores;
+
+ spin_lock_irqsave(&adev->trace_lock, flags);
+
+ /* Gather any remaining logs. */
+ for_each_set_bit(i, &resource_mask, num_cores) {
+ msg.log.core = i;
+ avs_dsp_op(adev, log_buffer_status, &msg);
+ }
+
+ kfifo_free(&adev->trace_fifo);
+
+ spin_unlock_irqrestore(&adev->trace_lock, flags);
+
+ return 0;
+}
+
+static const struct file_operations strace_fops = {
+ .llseek = default_llseek,
+ .read = strace_read,
+ .open = strace_open,
+ .release = strace_release,
+};
+
+#define DISABLE_TIMERS UINT_MAX
+
+static int enable_logs(struct avs_dev *adev, u32 resource_mask, u32 *priorities)
+{
+ int ret;
+
+ /* Logging demands D0i0 state from DSP. */
+ if (!adev->logged_resources) {
+ pm_runtime_get_sync(adev->dev);
+
+ ret = avs_dsp_disable_d0ix(adev);
+ if (ret)
+ goto err_d0ix;
+ }
+
+ ret = avs_ipc_set_system_time(adev);
+ if (ret && ret != AVS_IPC_NOT_SUPPORTED) {
+ ret = AVS_IPC_RET(ret);
+ goto err_ipc;
+ }
+
+ ret = avs_dsp_op(adev, enable_logs, AVS_LOG_ENABLE, adev->aging_timer_period,
+ adev->fifo_full_timer_period, resource_mask, priorities);
+ if (ret)
+ goto err_ipc;
+
+ adev->logged_resources |= resource_mask;
+ return 0;
+
+err_ipc:
+ if (!adev->logged_resources) {
+ avs_dsp_enable_d0ix(adev);
+err_d0ix:
+ pm_runtime_mark_last_busy(adev->dev);
+ pm_runtime_put_autosuspend(adev->dev);
+ }
+
+ return ret;
+}
+
+static int disable_logs(struct avs_dev *adev, u32 resource_mask)
+{
+ int ret;
+
+ /* Check if there's anything to do. */
+ if (!adev->logged_resources)
+ return 0;
+
+ ret = avs_dsp_op(adev, enable_logs, AVS_LOG_DISABLE, DISABLE_TIMERS, DISABLE_TIMERS,
+ resource_mask, NULL);
+
+ /*
+ * If IPC fails causing recovery, logged_resources is already zero
+ * so unsetting bits is still safe.
+ */
+ adev->logged_resources &= ~resource_mask;
+
+ /* If that's the last resource, allow for D3. */
+ if (!adev->logged_resources) {
+ avs_dsp_enable_d0ix(adev);
+ pm_runtime_mark_last_busy(adev->dev);
+ pm_runtime_put_autosuspend(adev->dev);
+ }
+
+ return ret;
+}
+
+static ssize_t trace_control_read(struct file *file, char __user *to, size_t count, loff_t *ppos)
+{
+ struct avs_dev *adev = file->private_data;
+ char buf[64];
+ int len;
+
+ len = snprintf(buf, sizeof(buf), "0x%08x\n", adev->logged_resources);
+
+ return simple_read_from_buffer(to, count, ppos, buf, len);
+}
+
+static ssize_t trace_control_write(struct file *file, const char __user *from, size_t count,
+ loff_t *ppos)
+{
+ struct avs_dev *adev = file->private_data;
+ u32 *array, num_elems;
+ u32 resource_mask;
+ int ret;
+
+ ret = parse_int_array_user(from, count, (int **)&array);
+ if (ret < 0)
+ return ret;
+
+ num_elems = *array;
+ resource_mask = array[1];
+
+ /*
+ * Disable if just resource mask is provided - no log priority flags.
+ *
+ * Enable input format: mask, prio1, .., prioN
+ * Where 'N' equals number of bits set in the 'mask'.
+ */
+ if (num_elems == 1) {
+ ret = disable_logs(adev, resource_mask);
+ } else {
+ if (num_elems != (hweight_long(resource_mask) + 1)) {
+ ret = -EINVAL;
+ goto free_array;
+ }
+
+ ret = enable_logs(adev, resource_mask, &array[2]);
+ }
+
+ if (!ret)
+ ret = count;
+free_array:
+ kfree(array);
+ return ret;
+}
+
+static const struct file_operations trace_control_fops = {
+ .llseek = default_llseek,
+ .read = trace_control_read,
+ .write = trace_control_write,
+ .open = simple_open,
+};
+
+void avs_debugfs_init(struct avs_dev *adev)
+{
+ init_waitqueue_head(&adev->trace_waitq);
+ spin_lock_init(&adev->trace_lock);
+
+ adev->debugfs_root = debugfs_create_dir("avs", snd_soc_debugfs_root);
+
+ /* Initialize timer periods with recommended defaults. */
+ adev->aging_timer_period = 10;
+ adev->fifo_full_timer_period = 10;
+
+ debugfs_create_file("strace", 0444, adev->debugfs_root, adev, &strace_fops);
+ debugfs_create_file("trace_control", 0644, adev->debugfs_root, adev, &trace_control_fops);
+ debugfs_create_file("fw_regs", 0444, adev->debugfs_root, adev, &fw_regs_fops);
+ debugfs_create_file("debug_window", 0444, adev->debugfs_root, adev, &debug_window_fops);
+
+ debugfs_create_u32("trace_aging_period", 0644, adev->debugfs_root,
+ &adev->aging_timer_period);
+ debugfs_create_u32("trace_fifo_full_period", 0644, adev->debugfs_root,
+ &adev->fifo_full_timer_period);
+
+ debugfs_create_file("probe_points", 0644, adev->debugfs_root, adev, &probe_points_fops);
+ debugfs_create_file("probe_points_disconnect", 0200, adev->debugfs_root, adev,
+ &probe_points_disconnect_fops);
+}
+
+void avs_debugfs_exit(struct avs_dev *adev)
+{
+ debugfs_remove_recursive(adev->debugfs_root);
+}
diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c
index 020d85c7520d..bdf013c3dd12 100644
--- a/sound/soc/intel/avs/ipc.c
+++ b/sound/soc/intel/avs/ipc.c
@@ -74,7 +74,7 @@ int avs_dsp_disable_d0ix(struct avs_dev *adev)
struct avs_ipc *ipc = adev->ipc;
/* Prevent PG only on the first disable. */
- if (atomic_add_return(1, &ipc->d0ix_disable_depth) == 1) {
+ if (atomic_inc_return(&ipc->d0ix_disable_depth) == 1) {
cancel_delayed_work_sync(&ipc->d0ix_work);
return avs_dsp_set_d0ix(adev, false);
}
@@ -123,7 +123,10 @@ static void avs_dsp_recovery(struct avs_dev *adev)
if (!substream || !substream->runtime)
continue;
+ /* No need for _irq() as we are in nonatomic context. */
+ snd_pcm_stream_lock(substream);
snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
+ snd_pcm_stream_unlock(substream);
}
}
}
@@ -192,7 +195,8 @@ static void avs_dsp_receive_rx(struct avs_dev *adev, u64 header)
/* update size in case of LARGE_CONFIG_GET */
if (msg.msg_target == AVS_MOD_MSG &&
msg.global_msg_type == AVS_MOD_LARGE_CONFIG_GET)
- ipc->rx.size = msg.ext.large_config.data_off_size;
+ ipc->rx.size = min_t(u32, AVS_MAILBOX_SIZE,
+ msg.ext.large_config.data_off_size);
memcpy_fromio(ipc->rx.data, avs_uplink_addr(adev), ipc->rx.size);
trace_avs_msg_payload(ipc->rx.data, ipc->rx.size);
@@ -262,7 +266,7 @@ static void avs_dsp_process_notification(struct avs_dev *adev, u64 header)
break;
case AVS_NOTIFY_LOG_BUFFER_STATUS:
- avs_dsp_op(adev, log_buffer_status, &msg);
+ avs_log_buffer_status_locked(adev, &msg);
break;
case AVS_NOTIFY_EXCEPTION_CAUGHT:
diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c
index 9e3f8ff33a87..56bb0a59249d 100644
--- a/sound/soc/intel/avs/loader.c
+++ b/sound/soc/intel/avs/loader.c
@@ -43,7 +43,7 @@
/* Occasionally, engineering (release candidate) firmware is provided for testing. */
static bool debug_ignore_fw_version;
module_param_named(ignore_fw_version, debug_ignore_fw_version, bool, 0444);
-MODULE_PARM_DESC(ignore_fw_version, "Verify FW version 0=yes (default), 1=no");
+MODULE_PARM_DESC(ignore_fw_version, "Ignore firmware version check 0=no (default), 1=yes");
#define AVS_LIB_NAME_SIZE 8
@@ -224,11 +224,19 @@ static int avs_cldma_load_module(struct avs_dev *adev, struct avs_module_entry *
if (ret < 0)
return ret;
+ avs_hda_power_gating_enable(adev, false);
+ avs_hda_clock_gating_enable(adev, false);
+ avs_hda_l1sen_enable(adev, false);
+
hda_cldma_set_data(cl, (void *)mod->data, mod->size);
hda_cldma_transfer(cl, msecs_to_jiffies(AVS_CLDMA_START_DELAY_MS));
ret = avs_ipc_load_modules(adev, &mentry->module_id, 1);
hda_cldma_stop(cl);
+ avs_hda_l1sen_enable(adev, true);
+ avs_hda_clock_gating_enable(adev, true);
+ avs_hda_power_gating_enable(adev, true);
+
if (ret) {
dev_err(adev->dev, "load module %d failed: %d\n", mentry->module_id, ret);
avs_release_last_firmware(adev);
@@ -369,8 +377,8 @@ int avs_hda_load_basefw(struct avs_dev *adev, struct firmware *fw)
goto release_stream;
/* enable SPIB for hda stream */
- snd_hdac_ext_stream_spbcap_enable(bus, true, hstream->index);
- ret = snd_hdac_ext_stream_set_spib(bus, estream, fw->size);
+ snd_hdac_stream_spbcap_enable(bus, true, hstream->index);
+ ret = snd_hdac_stream_set_spib(bus, hstream, fw->size);
if (ret)
goto cleanup_resources;
@@ -400,8 +408,8 @@ int avs_hda_load_basefw(struct avs_dev *adev, struct firmware *fw)
cleanup_resources:
/* disable SPIB for hda stream */
- snd_hdac_ext_stream_spbcap_enable(bus, false, hstream->index);
- snd_hdac_ext_stream_set_spib(bus, estream, 0);
+ snd_hdac_stream_spbcap_enable(bus, false, hstream->index);
+ snd_hdac_stream_set_spib(bus, hstream, 0);
snd_hdac_dsp_cleanup(hstream, &dmab);
release_stream:
@@ -436,8 +444,8 @@ int avs_hda_load_library(struct avs_dev *adev, struct firmware *lib, u32 id)
goto release_stream;
/* enable SPIB for hda stream */
- snd_hdac_ext_stream_spbcap_enable(bus, true, stream->index);
- snd_hdac_ext_stream_set_spib(bus, estream, lib->size);
+ snd_hdac_stream_spbcap_enable(bus, true, stream->index);
+ snd_hdac_stream_set_spib(bus, stream, lib->size);
memcpy(dmab.area, lib->data, lib->size);
@@ -451,8 +459,8 @@ int avs_hda_load_library(struct avs_dev *adev, struct firmware *lib, u32 id)
}
/* disable SPIB for hda stream */
- snd_hdac_ext_stream_spbcap_enable(bus, false, stream->index);
- snd_hdac_ext_stream_set_spib(bus, estream, 0);
+ snd_hdac_stream_spbcap_enable(bus, false, stream->index);
+ snd_hdac_stream_set_spib(bus, stream, 0);
snd_hdac_dsp_cleanup(stream, &dmab);
release_stream:
@@ -605,6 +613,7 @@ int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge)
for (i = 1; i < adev->fw_cfg.max_libs_count; i++)
memset(adev->lib_names[i], 0, AVS_LIB_NAME_SIZE);
+ avs_hda_power_gating_enable(adev, false);
avs_hda_clock_gating_enable(adev, false);
avs_hda_l1sen_enable(adev, false);
@@ -625,6 +634,7 @@ int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge)
reenable_gating:
avs_hda_l1sen_enable(adev, true);
avs_hda_clock_gating_enable(adev, true);
+ avs_hda_power_gating_enable(adev, true);
if (ret < 0)
return ret;
diff --git a/sound/soc/intel/avs/messages.c b/sound/soc/intel/avs/messages.c
index d4bcee1aabcf..e11ae4246416 100644
--- a/sound/soc/intel/avs/messages.c
+++ b/sound/soc/intel/avs/messages.c
@@ -685,22 +685,33 @@ int avs_ipc_get_modules_info(struct avs_dev *adev, struct avs_mods_info **info)
return 0;
}
-int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size)
+int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id,
+ u8 instance_id, u32 sink_id,
+ const struct avs_audio_format *src_fmt,
+ const struct avs_audio_format *sink_fmt)
{
- int ret;
+ struct avs_copier_sink_format cpr_fmt;
- ret = avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
- AVS_BASEFW_ENABLE_LOGS, log_info, size);
- if (ret)
- dev_err(adev->dev, "enable logs failed: %d\n", ret);
+ cpr_fmt.sink_id = sink_id;
+ /* Firmware expects driver to resend copier's input format. */
+ cpr_fmt.src_fmt = *src_fmt;
+ cpr_fmt.sink_fmt = *sink_fmt;
- return ret;
+ return avs_ipc_set_large_config(adev, module_id, instance_id,
+ AVS_COPIER_SET_SINK_FORMAT,
+ (u8 *)&cpr_fmt, sizeof(cpr_fmt));
+}
+
+#ifdef CONFIG_DEBUG_FS
+int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size)
+{
+ return avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
+ AVS_BASEFW_ENABLE_LOGS, log_info, size);
}
int avs_ipc_set_system_time(struct avs_dev *adev)
{
struct avs_sys_time sys_time;
- int ret;
u64 us;
/* firmware expects UTC time in micro seconds */
@@ -708,27 +719,85 @@ int avs_ipc_set_system_time(struct avs_dev *adev)
sys_time.val_l = us & UINT_MAX;
sys_time.val_u = us >> 32;
- ret = avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
- AVS_BASEFW_SYSTEM_TIME, (u8 *)&sys_time, sizeof(sys_time));
+ return avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
+ AVS_BASEFW_SYSTEM_TIME, (u8 *)&sys_time, sizeof(sys_time));
+}
+
+int avs_ipc_probe_get_dma(struct avs_dev *adev, struct avs_probe_dma **dmas, size_t *num_dmas)
+{
+ size_t payload_size;
+ u32 module_id;
+ u8 *payload;
+ int ret;
+
+ module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
+
+ ret = avs_ipc_get_large_config(adev, module_id, AVS_PROBE_INST_ID, AVS_PROBE_INJECTION_DMA,
+ NULL, 0, &payload, &payload_size);
if (ret)
- dev_err(adev->dev, "set system time failed: %d\n", ret);
+ return ret;
- return ret;
+ *dmas = (struct avs_probe_dma *)payload;
+ *num_dmas = payload_size / sizeof(**dmas);
+
+ return 0;
}
-int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id,
- u8 instance_id, u32 sink_id,
- const struct avs_audio_format *src_fmt,
- const struct avs_audio_format *sink_fmt)
+int avs_ipc_probe_attach_dma(struct avs_dev *adev, struct avs_probe_dma *dmas, size_t num_dmas)
{
- struct avs_copier_sink_format cpr_fmt;
+ u32 module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
- cpr_fmt.sink_id = sink_id;
- /* Firmware expects driver to resend copier's input format. */
- cpr_fmt.src_fmt = *src_fmt;
- cpr_fmt.sink_fmt = *sink_fmt;
+ return avs_ipc_set_large_config(adev, module_id, AVS_PROBE_INST_ID, AVS_PROBE_INJECTION_DMA,
+ (u8 *)dmas, array_size(sizeof(*dmas), num_dmas));
+}
- return avs_ipc_set_large_config(adev, module_id, instance_id,
- AVS_COPIER_SET_SINK_FORMAT,
- (u8 *)&cpr_fmt, sizeof(cpr_fmt));
+int avs_ipc_probe_detach_dma(struct avs_dev *adev, union avs_connector_node_id *node_ids,
+ size_t num_node_ids)
+{
+ u32 module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
+
+ return avs_ipc_set_large_config(adev, module_id, AVS_PROBE_INST_ID,
+ AVS_PROBE_INJECTION_DMA_DETACH, (u8 *)node_ids,
+ array_size(sizeof(*node_ids), num_node_ids));
+}
+
+int avs_ipc_probe_get_points(struct avs_dev *adev, struct avs_probe_point_desc **descs,
+ size_t *num_descs)
+{
+ size_t payload_size;
+ u32 module_id;
+ u8 *payload;
+ int ret;
+
+ module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
+
+ ret = avs_ipc_get_large_config(adev, module_id, AVS_PROBE_INST_ID, AVS_PROBE_POINTS, NULL,
+ 0, &payload, &payload_size);
+ if (ret)
+ return ret;
+
+ *descs = (struct avs_probe_point_desc *)payload;
+ *num_descs = payload_size / sizeof(**descs);
+
+ return 0;
+}
+
+int avs_ipc_probe_connect_points(struct avs_dev *adev, struct avs_probe_point_desc *descs,
+ size_t num_descs)
+{
+ u32 module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
+
+ return avs_ipc_set_large_config(adev, module_id, AVS_PROBE_INST_ID, AVS_PROBE_POINTS,
+ (u8 *)descs, array_size(sizeof(*descs), num_descs));
+}
+
+int avs_ipc_probe_disconnect_points(struct avs_dev *adev, union avs_probe_point_id *ids,
+ size_t num_ids)
+{
+ u32 module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
+
+ return avs_ipc_set_large_config(adev, module_id, AVS_PROBE_INST_ID,
+ AVS_PROBE_POINTS_DISCONNECT, (u8 *)ids,
+ array_size(sizeof(*ids), num_ids));
}
+#endif
diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h
index c0f90dba9af8..9dd835527e02 100644
--- a/sound/soc/intel/avs/messages.h
+++ b/sound/soc/intel/avs/messages.h
@@ -150,6 +150,8 @@ union avs_module_msg {
};
} __packed;
+#define AVS_IPC_NOT_SUPPORTED 15
+
union avs_reply_msg {
u64 val;
struct {
@@ -800,4 +802,57 @@ int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id,
const struct avs_audio_format *src_fmt,
const struct avs_audio_format *sink_fmt);
+#define AVS_PROBE_INST_ID 0
+
+enum avs_probe_runtime_param {
+ AVS_PROBE_INJECTION_DMA = 1,
+ AVS_PROBE_INJECTION_DMA_DETACH,
+ AVS_PROBE_POINTS,
+ AVS_PROBE_POINTS_DISCONNECT,
+};
+
+struct avs_probe_dma {
+ union avs_connector_node_id node_id;
+ u32 dma_buffer_size;
+} __packed;
+
+enum avs_probe_type {
+ AVS_PROBE_TYPE_INPUT = 0,
+ AVS_PROBE_TYPE_OUTPUT,
+ AVS_PROBE_TYPE_INTERNAL
+};
+
+union avs_probe_point_id {
+ u32 value;
+ struct {
+ u32 module_id:16;
+ u32 instance_id:8;
+ u32 type:2;
+ u32 index:6;
+ } id;
+} __packed;
+
+enum avs_connection_purpose {
+ AVS_CONNECTION_PURPOSE_EXTRACT = 0,
+ AVS_CONNECTION_PURPOSE_INJECT,
+ AVS_CONNECTION_PURPOSE_INJECT_REEXTRACT,
+};
+
+struct avs_probe_point_desc {
+ union avs_probe_point_id id;
+ u32 purpose;
+ union avs_connector_node_id node_id;
+} __packed;
+
+int avs_ipc_probe_get_dma(struct avs_dev *adev, struct avs_probe_dma **dmas, size_t *num_dmas);
+int avs_ipc_probe_attach_dma(struct avs_dev *adev, struct avs_probe_dma *dmas, size_t num_dmas);
+int avs_ipc_probe_detach_dma(struct avs_dev *adev, union avs_connector_node_id *node_ids,
+ size_t num_node_ids);
+int avs_ipc_probe_get_points(struct avs_dev *adev, struct avs_probe_point_desc **descs,
+ size_t *num_descs);
+int avs_ipc_probe_connect_points(struct avs_dev *adev, struct avs_probe_point_desc *descs,
+ size_t num_descs);
+int avs_ipc_probe_disconnect_points(struct avs_dev *adev, union avs_probe_point_id *ids,
+ size_t num_ids);
+
#endif /* __SOUND_SOC_INTEL_AVS_MSGS_H */
diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c
index 8fe5917b1e26..f930c5e86a84 100644
--- a/sound/soc/intel/avs/pcm.c
+++ b/sound/soc/intel/avs/pcm.c
@@ -28,6 +28,8 @@ struct avs_dma_data {
* host stream assigned
*/
struct hdac_ext_stream *host_stream;
+
+ struct snd_pcm_substream *substream;
};
static struct avs_tplg_path_template *
@@ -55,8 +57,11 @@ avs_dai_find_path_template(struct snd_soc_dai *dai, bool is_fe, int direction)
return dw->priv;
}
-static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, bool is_fe)
+static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, bool is_fe,
+ const struct snd_soc_dai_ops *ops)
{
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ struct avs_dev *adev = to_avs_dev(dai->dev);
struct avs_tplg_path_template *template;
struct avs_dma_data *data;
@@ -71,9 +76,13 @@ static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_d
if (!data)
return -ENOMEM;
+ data->substream = substream;
data->template = template;
snd_soc_dai_set_dma_data(dai, substream, data);
+ if (rtd->dai_link->ignore_suspend)
+ adev->num_lp_paths++;
+
return 0;
}
@@ -151,15 +160,22 @@ static int avs_dai_prepare(struct avs_dev *adev, struct snd_pcm_substream *subst
return ret;
}
+static const struct snd_soc_dai_ops avs_dai_nonhda_be_ops;
+
static int avs_dai_nonhda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
- return avs_dai_startup(substream, dai, false);
+ return avs_dai_startup(substream, dai, false, &avs_dai_nonhda_be_ops);
}
static void avs_dai_nonhda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ struct avs_dev *adev = to_avs_dev(dai->dev);
struct avs_dma_data *data;
+ if (rtd->dai_link->ignore_suspend)
+ adev->num_lp_paths--;
+
data = snd_soc_dai_get_dma_data(dai, substream);
snd_soc_dai_set_dma_data(dai, substream, NULL);
@@ -202,30 +218,43 @@ static int avs_dai_nonhda_be_prepare(struct snd_pcm_substream *substream, struct
static int avs_dai_nonhda_be_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
struct avs_dma_data *data;
int ret = 0;
data = snd_soc_dai_get_dma_data(dai, substream);
switch (cmd) {
+ case SNDRV_PCM_TRIGGER_RESUME:
+ if (rtd->dai_link->ignore_suspend)
+ break;
+ fallthrough;
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ ret = avs_path_pause(data->path);
+ if (ret < 0) {
+ dev_err(dai->dev, "pause BE path failed: %d\n", ret);
+ break;
+ }
+
ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO);
if (ret < 0)
dev_err(dai->dev, "run BE path failed: %d\n", ret);
break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ if (rtd->dai_link->ignore_suspend)
+ break;
+ fallthrough;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_STOP:
ret = avs_path_pause(data->path);
if (ret < 0)
dev_err(dai->dev, "pause BE path failed: %d\n", ret);
- if (cmd == SNDRV_PCM_TRIGGER_STOP) {
- ret = avs_path_reset(data->path);
- if (ret < 0)
- dev_err(dai->dev, "reset BE path failed: %d\n", ret);
- }
+ ret = avs_path_reset(data->path);
+ if (ret < 0)
+ dev_err(dai->dev, "reset BE path failed: %d\n", ret);
break;
default:
@@ -245,9 +274,11 @@ static const struct snd_soc_dai_ops avs_dai_nonhda_be_ops = {
.trigger = avs_dai_nonhda_be_trigger,
};
+static const struct snd_soc_dai_ops avs_dai_hda_be_ops;
+
static int avs_dai_hda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
- return avs_dai_startup(substream, dai, false);
+ return avs_dai_startup(substream, dai, false, &avs_dai_hda_be_ops);
}
static void avs_dai_hda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
@@ -292,12 +323,12 @@ static int avs_dai_hda_be_hw_free(struct snd_pcm_substream *substream, struct sn
/* clear link <-> stream mapping */
codec = dev_to_hda_codec(asoc_rtd_to_codec(rtd, 0)->dev);
- link = snd_hdac_ext_bus_link_at(&codec->bus->core, codec->core.addr);
+ link = snd_hdac_ext_bus_get_hlink_by_addr(&codec->bus->core, codec->core.addr);
if (!link)
return -EINVAL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- snd_hdac_ext_link_clear_stream_id(link, hdac_stream(link_stream)->stream_tag);
+ snd_hdac_ext_bus_link_clear_stream_id(link, hdac_stream(link_stream)->stream_tag);
return 0;
}
@@ -322,15 +353,15 @@ static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct sn
runtime->sample_bits, 0);
snd_hdac_ext_stream_decouple(bus, link_stream, true);
- snd_hdac_ext_link_stream_reset(link_stream);
- snd_hdac_ext_link_stream_setup(link_stream, format_val);
+ snd_hdac_ext_stream_reset(link_stream);
+ snd_hdac_ext_stream_setup(link_stream, format_val);
- link = snd_hdac_ext_bus_link_at(bus, codec->core.addr);
+ link = snd_hdac_ext_bus_get_hlink_by_addr(bus, codec->core.addr);
if (!link)
return -EINVAL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_stream)->stream_tag);
+ snd_hdac_ext_bus_link_set_stream_id(link, hdac_stream(link_stream)->stream_tag);
ret = avs_dai_prepare(to_avs_dev(dai->dev), substream, dai);
if (ret)
@@ -343,6 +374,7 @@ static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct sn
static int avs_dai_hda_be_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
struct hdac_ext_stream *link_stream;
struct avs_dma_data *data;
int ret = 0;
@@ -353,28 +385,40 @@ static int avs_dai_hda_be_trigger(struct snd_pcm_substream *substream, int cmd,
link_stream = substream->runtime->private_data;
switch (cmd) {
+ case SNDRV_PCM_TRIGGER_RESUME:
+ if (rtd->dai_link->ignore_suspend)
+ break;
+ fallthrough;
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- snd_hdac_ext_link_stream_start(link_stream);
+ snd_hdac_ext_stream_start(link_stream);
+
+ ret = avs_path_pause(data->path);
+ if (ret < 0) {
+ dev_err(dai->dev, "pause BE path failed: %d\n", ret);
+ break;
+ }
ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO);
if (ret < 0)
dev_err(dai->dev, "run BE path failed: %d\n", ret);
break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ if (rtd->dai_link->ignore_suspend)
+ break;
+ fallthrough;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_STOP:
ret = avs_path_pause(data->path);
if (ret < 0)
dev_err(dai->dev, "pause BE path failed: %d\n", ret);
- snd_hdac_ext_link_stream_clear(link_stream);
+ snd_hdac_ext_stream_clear(link_stream);
- if (cmd == SNDRV_PCM_TRIGGER_STOP) {
- ret = avs_path_reset(data->path);
- if (ret < 0)
- dev_err(dai->dev, "reset BE path failed: %d\n", ret);
- }
+ ret = avs_path_reset(data->path);
+ if (ret < 0)
+ dev_err(dai->dev, "reset BE path failed: %d\n", ret);
break;
default:
@@ -407,6 +451,8 @@ static const struct snd_pcm_hw_constraint_list hw_rates = {
.mask = 0,
};
+const struct snd_soc_dai_ops avs_dai_fe_ops;
+
static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -416,7 +462,7 @@ static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_so
struct hdac_ext_stream *host_stream;
int ret;
- ret = avs_dai_startup(substream, dai, true);
+ ret = avs_dai_startup(substream, dai, true, &avs_dai_fe_ops);
if (ret)
return ret;
@@ -443,8 +489,13 @@ static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_so
static void avs_dai_fe_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ struct avs_dev *adev = to_avs_dev(dai->dev);
struct avs_dma_data *data;
+ if (rtd->dai_link->ignore_suspend)
+ adev->num_lp_paths--;
+
data = snd_soc_dai_get_dma_data(dai, substream);
snd_soc_dai_set_dma_data(dai, substream, NULL);
@@ -499,7 +550,7 @@ create_err:
return ret;
}
-static int avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+static int __avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
struct avs_dma_data *data;
struct hdac_ext_stream *host_stream;
@@ -523,9 +574,15 @@ static int avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_so
snd_hdac_stream_cleanup(hdac_stream(host_stream));
hdac_stream(host_stream)->prepared = false;
- ret = snd_pcm_lib_free_pages(substream);
- if (ret < 0)
- dev_dbg(dai->dev, "Failed to free pages!\n");
+ return ret;
+}
+
+static int avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ int ret;
+
+ ret = __avs_dai_fe_hw_free(substream, dai);
+ snd_pcm_lib_free_pages(substream);
return ret;
}
@@ -571,6 +628,7 @@ static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_so
static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
{
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
struct avs_dma_data *data;
struct hdac_ext_stream *host_stream;
struct hdac_bus *bus;
@@ -582,17 +640,36 @@ static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, stru
bus = hdac_stream(host_stream)->bus;
switch (cmd) {
+ case SNDRV_PCM_TRIGGER_RESUME:
+ if (rtd->dai_link->ignore_suspend)
+ break;
+ fallthrough;
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
spin_lock_irqsave(&bus->reg_lock, flags);
snd_hdac_stream_start(hdac_stream(host_stream), true);
spin_unlock_irqrestore(&bus->reg_lock, flags);
+ /* Timeout on DRSM poll shall not stop the resume so ignore the result. */
+ if (cmd == SNDRV_PCM_TRIGGER_RESUME)
+ snd_hdac_stream_wait_drsm(hdac_stream(host_stream));
+
+ ret = avs_path_pause(data->path);
+ if (ret < 0) {
+ dev_err(dai->dev, "pause FE path failed: %d\n", ret);
+ break;
+ }
+
ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO);
if (ret < 0)
dev_err(dai->dev, "run FE path failed: %d\n", ret);
+
break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ if (rtd->dai_link->ignore_suspend)
+ break;
+ fallthrough;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_STOP:
ret = avs_path_pause(data->path);
@@ -603,11 +680,9 @@ static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, stru
snd_hdac_stream_stop(hdac_stream(host_stream));
spin_unlock_irqrestore(&bus->reg_lock, flags);
- if (cmd == SNDRV_PCM_TRIGGER_STOP) {
- ret = avs_path_reset(data->path);
- if (ret < 0)
- dev_err(dai->dev, "reset FE path failed: %d\n", ret);
- }
+ ret = avs_path_reset(data->path);
+ if (ret < 0)
+ dev_err(dai->dev, "reset FE path failed: %d\n", ret);
break;
default:
@@ -662,6 +737,7 @@ static int avs_component_load_libraries(struct avs_soc_component *acomp)
if (ret < 0)
return ret;
+ avs_hda_power_gating_enable(adev, false);
avs_hda_clock_gating_enable(adev, false);
avs_hda_l1sen_enable(adev, false);
@@ -669,6 +745,7 @@ static int avs_component_load_libraries(struct avs_soc_component *acomp)
avs_hda_l1sen_enable(adev, true);
avs_hda_clock_gating_enable(adev, true);
+ avs_hda_power_gating_enable(adev, true);
if (!ret)
ret = avs_module_info_init(adev, false);
@@ -752,33 +829,232 @@ static void avs_component_remove(struct snd_soc_component *component)
}
}
+static int avs_dai_resume_hw_params(struct snd_soc_dai *dai, struct avs_dma_data *data)
+{
+ struct snd_pcm_substream *substream;
+ struct snd_soc_pcm_runtime *rtd;
+ int ret;
+
+ substream = data->substream;
+ rtd = snd_pcm_substream_chip(substream);
+
+ ret = dai->driver->ops->hw_params(substream, &rtd->dpcm[substream->stream].hw_params, dai);
+ if (ret)
+ dev_err(dai->dev, "hw_params on resume failed: %d\n", ret);
+
+ return ret;
+}
+
+static int avs_dai_resume_fe_prepare(struct snd_soc_dai *dai, struct avs_dma_data *data)
+{
+ struct hdac_ext_stream *host_stream;
+ struct hdac_stream *hstream;
+ struct hdac_bus *bus;
+ int ret;
+
+ host_stream = data->host_stream;
+ hstream = hdac_stream(host_stream);
+ bus = hdac_stream(host_stream)->bus;
+
+ /* Set DRSM before programming stream and position registers. */
+ snd_hdac_stream_drsm_enable(bus, true, hstream->index);
+
+ ret = dai->driver->ops->prepare(data->substream, dai);
+ if (ret) {
+ dev_err(dai->dev, "prepare FE on resume failed: %d\n", ret);
+ return ret;
+ }
+
+ writel(host_stream->pphcllpl, host_stream->pphc_addr + AZX_REG_PPHCLLPL);
+ writel(host_stream->pphcllpu, host_stream->pphc_addr + AZX_REG_PPHCLLPU);
+ writel(host_stream->pphcldpl, host_stream->pphc_addr + AZX_REG_PPHCLDPL);
+ writel(host_stream->pphcldpu, host_stream->pphc_addr + AZX_REG_PPHCLDPU);
+
+ /* As per HW spec recommendation, program LPIB and DPIB to the same value. */
+ snd_hdac_stream_set_lpib(hstream, hstream->lpib);
+ snd_hdac_stream_set_dpibr(bus, hstream, hstream->lpib);
+
+ return 0;
+}
+
+static int avs_dai_resume_be_prepare(struct snd_soc_dai *dai, struct avs_dma_data *data)
+{
+ int ret;
+
+ ret = dai->driver->ops->prepare(data->substream, dai);
+ if (ret)
+ dev_err(dai->dev, "prepare BE on resume failed: %d\n", ret);
+
+ return ret;
+}
+
+static int avs_dai_suspend_fe_hw_free(struct snd_soc_dai *dai, struct avs_dma_data *data)
+{
+ struct hdac_ext_stream *host_stream;
+ int ret;
+
+ host_stream = data->host_stream;
+
+ /* Store position addresses so we can resume from them later on. */
+ hdac_stream(host_stream)->lpib = snd_hdac_stream_get_pos_lpib(hdac_stream(host_stream));
+ host_stream->pphcllpl = readl(host_stream->pphc_addr + AZX_REG_PPHCLLPL);
+ host_stream->pphcllpu = readl(host_stream->pphc_addr + AZX_REG_PPHCLLPU);
+ host_stream->pphcldpl = readl(host_stream->pphc_addr + AZX_REG_PPHCLDPL);
+ host_stream->pphcldpu = readl(host_stream->pphc_addr + AZX_REG_PPHCLDPU);
+
+ ret = __avs_dai_fe_hw_free(data->substream, dai);
+ if (ret < 0)
+ dev_err(dai->dev, "hw_free FE on suspend failed: %d\n", ret);
+
+ return ret;
+}
+
+static int avs_dai_suspend_be_hw_free(struct snd_soc_dai *dai, struct avs_dma_data *data)
+{
+ int ret;
+
+ ret = dai->driver->ops->hw_free(data->substream, dai);
+ if (ret < 0)
+ dev_err(dai->dev, "hw_free BE on suspend failed: %d\n", ret);
+
+ return ret;
+}
+
+static int avs_component_pm_op(struct snd_soc_component *component, bool be,
+ int (*op)(struct snd_soc_dai *, struct avs_dma_data *))
+{
+ struct snd_soc_pcm_runtime *rtd;
+ struct avs_dma_data *data;
+ struct snd_soc_dai *dai;
+ int ret;
+
+ for_each_component_dais(component, dai) {
+ data = dai->playback_dma_data;
+ if (data) {
+ rtd = snd_pcm_substream_chip(data->substream);
+ if (rtd->dai_link->no_pcm == be && !rtd->dai_link->ignore_suspend) {
+ ret = op(dai, data);
+ if (ret < 0) {
+ __snd_pcm_set_state(data->substream->runtime,
+ SNDRV_PCM_STATE_DISCONNECTED);
+ return ret;
+ }
+ }
+ }
+
+ data = dai->capture_dma_data;
+ if (data) {
+ rtd = snd_pcm_substream_chip(data->substream);
+ if (rtd->dai_link->no_pcm == be && !rtd->dai_link->ignore_suspend) {
+ ret = op(dai, data);
+ if (ret < 0) {
+ __snd_pcm_set_state(data->substream->runtime,
+ SNDRV_PCM_STATE_DISCONNECTED);
+ return ret;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int avs_component_resume_hw_params(struct snd_soc_component *component, bool be)
+{
+ return avs_component_pm_op(component, be, &avs_dai_resume_hw_params);
+}
+
+static int avs_component_resume_prepare(struct snd_soc_component *component, bool be)
+{
+ int (*prepare_cb)(struct snd_soc_dai *dai, struct avs_dma_data *data);
+
+ if (be)
+ prepare_cb = &avs_dai_resume_be_prepare;
+ else
+ prepare_cb = &avs_dai_resume_fe_prepare;
+
+ return avs_component_pm_op(component, be, prepare_cb);
+}
+
+static int avs_component_suspend_hw_free(struct snd_soc_component *component, bool be)
+{
+ int (*hw_free_cb)(struct snd_soc_dai *dai, struct avs_dma_data *data);
+
+ if (be)
+ hw_free_cb = &avs_dai_suspend_be_hw_free;
+ else
+ hw_free_cb = &avs_dai_suspend_fe_hw_free;
+
+ return avs_component_pm_op(component, be, hw_free_cb);
+}
+
+static int avs_component_suspend(struct snd_soc_component *component)
+{
+ int ret;
+
+ /*
+ * When freeing paths, FEs need to be first as they perform
+ * path unbinding.
+ */
+ ret = avs_component_suspend_hw_free(component, false);
+ if (ret)
+ return ret;
+
+ return avs_component_suspend_hw_free(component, true);
+}
+
+static int avs_component_resume(struct snd_soc_component *component)
+{
+ int ret;
+
+ /*
+ * When creating paths, FEs need to be last as they perform
+ * path binding.
+ */
+ ret = avs_component_resume_hw_params(component, true);
+ if (ret)
+ return ret;
+
+ ret = avs_component_resume_hw_params(component, false);
+ if (ret)
+ return ret;
+
+ /* It is expected that the LINK stream is prepared first. */
+ ret = avs_component_resume_prepare(component, true);
+ if (ret)
+ return ret;
+
+ return avs_component_resume_prepare(component, false);
+}
+
+static const struct snd_pcm_hardware avs_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME |
+ SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .buffer_bytes_max = AZX_MAX_BUF_SIZE,
+ .period_bytes_min = 128,
+ .period_bytes_max = AZX_MAX_BUF_SIZE / 2,
+ .periods_min = 2,
+ .periods_max = AZX_MAX_FRAG,
+ .fifo_size = 0,
+};
+
static int avs_component_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
- struct snd_pcm_hardware hwparams;
/* only FE DAI links are handled here */
if (rtd->dai_link->no_pcm)
return 0;
- hwparams.info = SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_NO_PERIOD_WAKEUP;
-
- hwparams.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S32_LE;
- hwparams.period_bytes_min = 128;
- hwparams.period_bytes_max = AZX_MAX_BUF_SIZE / 2;
- hwparams.periods_min = 2;
- hwparams.periods_max = AZX_MAX_FRAG;
- hwparams.buffer_bytes_max = AZX_MAX_BUF_SIZE;
- hwparams.fifo_size = 0;
-
- return snd_soc_set_runtime_hwparams(substream, &hwparams);
+ return snd_soc_set_runtime_hwparams(substream, &avs_pcm_hardware);
}
static unsigned int avs_hda_stream_dpib_read(struct hdac_ext_stream *stream)
@@ -840,6 +1116,8 @@ static const struct snd_soc_component_driver avs_component_driver = {
.name = "avs-pcm",
.probe = avs_component_probe,
.remove = avs_component_remove,
+ .suspend = avs_component_suspend,
+ .resume = avs_component_resume,
.open = avs_component_open,
.pointer = avs_component_pointer,
.mmap = avs_component_mmap,
@@ -848,9 +1126,9 @@ static const struct snd_soc_component_driver avs_component_driver = {
.topology_name_prefix = "intel/avs",
};
-static int avs_soc_component_register(struct device *dev, const char *name,
- const struct snd_soc_component_driver *drv,
- struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais)
+int avs_soc_component_register(struct device *dev, const char *name,
+ const struct snd_soc_component_driver *drv,
+ struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais)
{
struct avs_soc_component *acomp;
int ret;
@@ -1016,10 +1294,8 @@ static void avs_component_hda_unregister_dais(struct snd_soc_component *componen
if (!strstr(dai->driver->name, name))
continue;
- if (dai->playback_widget)
- snd_soc_dapm_free_widget(dai->playback_widget);
- if (dai->capture_widget)
- snd_soc_dapm_free_widget(dai->capture_widget);
+ snd_soc_dapm_free_widget(dai->playback_widget);
+ snd_soc_dapm_free_widget(dai->capture_widget);
snd_soc_unregister_dai(dai);
}
}
@@ -1122,9 +1398,35 @@ static int avs_component_hda_open(struct snd_soc_component *component,
struct hdac_ext_stream *link_stream;
struct hda_codec *codec;
- /* only BE DAI links are handled here */
- if (!rtd->dai_link->no_pcm)
- return avs_component_open(component, substream);
+ if (!rtd->dai_link->no_pcm) {
+ struct snd_pcm_hardware hwparams = avs_pcm_hardware;
+ struct snd_soc_pcm_runtime *be;
+ struct snd_soc_dpcm *dpcm;
+ int dir = substream->stream;
+
+ /*
+ * Support the DPCM reparenting while still fulfilling expectations of HDAudio
+ * common code - a valid stream pointer at substream->runtime->private_data -
+ * by having all FEs point to the same private data.
+ */
+ for_each_dpcm_be(rtd, dir, dpcm) {
+ struct snd_pcm_substream *be_substream;
+
+ be = dpcm->be;
+ if (be->dpcm[dir].users == 1)
+ break;
+
+ be_substream = snd_soc_dpcm_get_substream(be, dir);
+ substream->runtime->private_data = be_substream->runtime->private_data;
+ break;
+ }
+
+ /* RESUME unsupported for de-coupled HD-Audio capture. */
+ if (dir == SNDRV_PCM_STREAM_CAPTURE)
+ hwparams.info &= ~SNDRV_PCM_INFO_RESUME;
+
+ return snd_soc_set_runtime_hwparams(substream, &hwparams);
+ }
codec = dev_to_hda_codec(asoc_rtd_to_codec(rtd, 0)->dev);
link_stream = snd_hdac_ext_stream_assign(&codec->bus->core, substream,
@@ -1157,6 +1459,8 @@ static const struct snd_soc_component_driver avs_hda_component_driver = {
.name = "avs-hda-pcm",
.probe = avs_component_hda_probe,
.remove = avs_component_hda_remove,
+ .suspend = avs_component_suspend,
+ .resume = avs_component_resume,
.open = avs_component_hda_open,
.close = avs_component_hda_close,
.pointer = avs_component_pointer,
diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c
new file mode 100644
index 000000000000..29d63f2a9616
--- /dev/null
+++ b/sound/soc/intel/avs/probes.c
@@ -0,0 +1,313 @@
+// 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 <sound/compress_driver.h>
+#include <sound/hdaudio_ext.h>
+#include <sound/hdaudio.h>
+#include <sound/soc.h>
+#include "avs.h"
+#include "messages.h"
+
+static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id node_id,
+ size_t buffer_size)
+{
+ struct avs_probe_cfg cfg = {{0}};
+ struct avs_module_entry mentry;
+ u16 dummy;
+
+ avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry);
+
+ /*
+ * Probe module uses no cycles, audio data format and input and output
+ * frame sizes are unused. It is also not owned by any pipeline.
+ */
+ cfg.base.ibs = 1;
+ /* BSS module descriptor is always segment of index=2. */
+ cfg.base.is_pages = mentry.segments[2].flags.length;
+ cfg.gtw_cfg.node_id = node_id;
+ cfg.gtw_cfg.dma_buffer_size = buffer_size;
+
+ return avs_dsp_init_module(adev, mentry.module_id, INVALID_PIPELINE_ID, 0, 0, &cfg,
+ sizeof(cfg), &dummy);
+}
+
+static void avs_dsp_delete_probe(struct avs_dev *adev)
+{
+ struct avs_module_entry mentry;
+
+ avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry);
+
+ /* There is only ever one probe module instance. */
+ avs_dsp_delete_module(adev, mentry.module_id, 0, INVALID_PIPELINE_ID, 0);
+}
+
+static inline struct hdac_ext_stream *avs_compr_get_host_stream(struct snd_compr_stream *cstream)
+{
+ return cstream->runtime->private_data;
+}
+
+static int avs_probe_compr_open(struct snd_compr_stream *cstream, struct snd_soc_dai *dai)
+{
+ struct avs_dev *adev = to_avs_dev(dai->dev);
+ struct hdac_bus *bus = &adev->base.core;
+ struct hdac_ext_stream *host_stream;
+
+ if (adev->extractor) {
+ dev_err(dai->dev, "Cannot open more than one extractor stream\n");
+ return -EEXIST;
+ }
+
+ host_stream = snd_hdac_ext_cstream_assign(bus, cstream);
+ if (!host_stream) {
+ dev_err(dai->dev, "Failed to assign HDAudio stream for extraction\n");
+ return -EBUSY;
+ }
+
+ adev->extractor = host_stream;
+ hdac_stream(host_stream)->curr_pos = 0;
+ cstream->runtime->private_data = host_stream;
+
+ return 0;
+}
+
+static int avs_probe_compr_free(struct snd_compr_stream *cstream, struct snd_soc_dai *dai)
+{
+ struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream);
+ struct avs_dev *adev = to_avs_dev(dai->dev);
+ struct avs_probe_point_desc *desc;
+ /* Extractor node identifier. */
+ unsigned int vindex = INVALID_NODE_ID.vindex;
+ size_t num_desc;
+ int i, ret;
+
+ /* Disconnect all probe points. */
+ ret = avs_ipc_probe_get_points(adev, &desc, &num_desc);
+ if (ret) {
+ dev_err(dai->dev, "get probe points failed: %d\n", ret);
+ ret = AVS_IPC_RET(ret);
+ goto exit;
+ }
+
+ for (i = 0; i < num_desc; i++)
+ if (desc[i].node_id.vindex == vindex)
+ avs_ipc_probe_disconnect_points(adev, &desc[i].id, 1);
+ kfree(desc);
+
+exit:
+ if (adev->num_probe_streams) {
+ adev->num_probe_streams--;
+ if (!adev->num_probe_streams) {
+ avs_dsp_delete_probe(adev);
+ avs_dsp_enable_d0ix(adev);
+ }
+ }
+
+ snd_hdac_stream_cleanup(hdac_stream(host_stream));
+ hdac_stream(host_stream)->prepared = 0;
+ snd_hdac_ext_stream_release(host_stream, HDAC_EXT_STREAM_TYPE_HOST);
+
+ snd_compr_free_pages(cstream);
+ adev->extractor = NULL;
+
+ return ret;
+}
+
+static int avs_probe_compr_set_params(struct snd_compr_stream *cstream,
+ struct snd_compr_params *params, struct snd_soc_dai *dai)
+{
+ struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream);
+ struct snd_compr_runtime *rtd = cstream->runtime;
+ struct avs_dev *adev = to_avs_dev(dai->dev);
+ /* compr params do not store bit depth, default to S32_LE. */
+ snd_pcm_format_t format = SNDRV_PCM_FORMAT_S32_LE;
+ unsigned int format_val;
+ int bps, ret;
+
+ hdac_stream(host_stream)->bufsize = 0;
+ hdac_stream(host_stream)->period_bytes = 0;
+ hdac_stream(host_stream)->format_val = 0;
+ cstream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV_SG;
+ cstream->dma_buffer.dev.dev = adev->dev;
+
+ ret = snd_compr_malloc_pages(cstream, rtd->buffer_size);
+ if (ret < 0)
+ return ret;
+ bps = snd_pcm_format_physical_width(format);
+ if (bps < 0)
+ return bps;
+ format_val = snd_hdac_calc_stream_format(params->codec.sample_rate, params->codec.ch_out,
+ format, bps, 0);
+ ret = snd_hdac_stream_set_params(hdac_stream(host_stream), format_val);
+ if (ret < 0)
+ return ret;
+ ret = snd_hdac_stream_setup(hdac_stream(host_stream));
+ if (ret < 0)
+ return ret;
+
+ hdac_stream(host_stream)->prepared = 1;
+
+ if (!adev->num_probe_streams) {
+ union avs_connector_node_id node_id;
+
+ /* D0ix not allowed during probing. */
+ ret = avs_dsp_disable_d0ix(adev);
+ if (ret)
+ return ret;
+
+ node_id.vindex = hdac_stream(host_stream)->stream_tag - 1;
+ node_id.dma_type = AVS_DMA_HDA_HOST_INPUT;
+
+ ret = avs_dsp_init_probe(adev, node_id, rtd->dma_bytes);
+ if (ret < 0) {
+ dev_err(dai->dev, "probe init failed: %d\n", ret);
+ avs_dsp_enable_d0ix(adev);
+ return ret;
+ }
+ }
+
+ adev->num_probe_streams++;
+ return 0;
+}
+
+static int avs_probe_compr_trigger(struct snd_compr_stream *cstream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream);
+ struct avs_dev *adev = to_avs_dev(dai->dev);
+ struct hdac_bus *bus = &adev->base.core;
+ unsigned long cookie;
+
+ if (!hdac_stream(host_stream)->prepared)
+ return -EPIPE;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ spin_lock_irqsave(&bus->reg_lock, cookie);
+ snd_hdac_stream_start(hdac_stream(host_stream), true);
+ spin_unlock_irqrestore(&bus->reg_lock, cookie);
+ break;
+
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+ spin_lock_irqsave(&bus->reg_lock, cookie);
+ snd_hdac_stream_stop(hdac_stream(host_stream));
+ spin_unlock_irqrestore(&bus->reg_lock, cookie);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int avs_probe_compr_pointer(struct snd_compr_stream *cstream,
+ struct snd_compr_tstamp *tstamp, struct snd_soc_dai *dai)
+{
+ struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream);
+ struct snd_soc_pcm_stream *pstream;
+
+ pstream = &dai->driver->capture;
+ tstamp->copied_total = hdac_stream(host_stream)->curr_pos;
+ tstamp->sampling_rate = snd_pcm_rate_bit_to_rate(pstream->rates);
+
+ return 0;
+}
+
+static int avs_probe_compr_copy(struct snd_soc_component *comp, struct snd_compr_stream *cstream,
+ char __user *buf, size_t count)
+{
+ struct snd_compr_runtime *rtd = cstream->runtime;
+ unsigned int offset, n;
+ void *ptr;
+ int ret;
+
+ if (count > rtd->buffer_size)
+ count = rtd->buffer_size;
+
+ div_u64_rem(rtd->total_bytes_transferred, rtd->buffer_size, &offset);
+ ptr = rtd->dma_area + offset;
+ n = rtd->buffer_size - offset;
+
+ if (count < n) {
+ ret = copy_to_user(buf, ptr, count);
+ } else {
+ ret = copy_to_user(buf, ptr, n);
+ ret += copy_to_user(buf + n, rtd->dma_area, count - n);
+ }
+
+ if (ret)
+ return count - ret;
+ return count;
+}
+
+static const struct snd_soc_cdai_ops avs_probe_dai_ops = {
+ .startup = avs_probe_compr_open,
+ .shutdown = avs_probe_compr_free,
+ .set_params = avs_probe_compr_set_params,
+ .trigger = avs_probe_compr_trigger,
+ .pointer = avs_probe_compr_pointer,
+};
+
+static const struct snd_compress_ops avs_probe_compress_ops = {
+ .copy = avs_probe_compr_copy,
+};
+
+static struct snd_soc_dai_driver probe_cpu_dais[] = {
+{
+ .name = "Probe Extraction CPU DAI",
+ .compress_new = snd_soc_new_compress,
+ .cops = &avs_probe_dai_ops,
+ .capture = {
+ .stream_name = "Probe Extraction",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ },
+},
+};
+
+static int avs_probe_component_probe(struct snd_soc_component *component)
+{
+ struct avs_soc_component *acomp = to_avs_soc_component(component);
+ struct avs_dev *adev = to_avs_dev(component->dev);
+
+ mutex_lock(&adev->comp_list_mutex);
+ list_add_tail(&acomp->node, &adev->comp_list);
+ mutex_unlock(&adev->comp_list_mutex);
+ return 0;
+}
+
+static void avs_probe_component_remove(struct snd_soc_component *component)
+{
+ struct avs_soc_component *acomp = to_avs_soc_component(component);
+ struct avs_dev *adev = to_avs_dev(component->dev);
+
+ mutex_lock(&adev->comp_list_mutex);
+ list_del(&acomp->node);
+ mutex_unlock(&adev->comp_list_mutex);
+}
+
+static const struct snd_soc_component_driver avs_probe_component_driver = {
+ .name = "avs-probe-compr",
+ .probe = avs_probe_component_probe,
+ .remove = avs_probe_component_remove,
+ .compress_ops = &avs_probe_compress_ops,
+ .module_get_upon_open = 1, /* increment refcount when a stream is opened */
+};
+
+int avs_probe_platform_register(struct avs_dev *adev, const char *name)
+{
+ return avs_soc_component_register(adev->dev, name, &avs_probe_component_driver,
+ probe_cpu_dais, ARRAY_SIZE(probe_cpu_dais));
+}
diff --git a/sound/soc/intel/avs/registers.h b/sound/soc/intel/avs/registers.h
index 95be86148cf3..2b464e466ed5 100644
--- a/sound/soc/intel/avs/registers.h
+++ b/sound/soc/intel/avs/registers.h
@@ -59,7 +59,8 @@
#define AVS_FW_REG_STATUS(adev) (AVS_FW_REG_BASE(adev) + 0x0)
#define AVS_FW_REG_ERROR_CODE(adev) (AVS_FW_REG_BASE(adev) + 0x4)
-#define AVS_FW_REGS_SIZE PAGE_SIZE
+#define AVS_WINDOW_CHUNK_SIZE PAGE_SIZE
+#define AVS_FW_REGS_SIZE AVS_WINDOW_CHUNK_SIZE
#define AVS_FW_REGS_WINDOW 0
/* DSP -> HOST communication window */
#define AVS_UPLINK_WINDOW AVS_FW_REGS_WINDOW
diff --git a/sound/soc/intel/avs/skl.c b/sound/soc/intel/avs/skl.c
index bda5ec7510fe..6bb8bbc70442 100644
--- a/sound/soc/intel/avs/skl.c
+++ b/sound/soc/intel/avs/skl.c
@@ -12,8 +12,9 @@
#include "avs.h"
#include "messages.h"
-static int skl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
- u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
+static int __maybe_unused
+skl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
+ u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
{
struct skl_log_state_info *info;
u32 size, num_cores = adev->hw_cfg.dsp_cores;
@@ -28,12 +29,12 @@ static int skl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32
info->core_mask = resource_mask;
if (enable)
- for_each_set_bit(i, &resource_mask, GENMASK(num_cores, 0)) {
+ for_each_set_bit(i, &resource_mask, num_cores) {
info->logs_core[i].enable = enable;
info->logs_core[i].min_priority = *priorities++;
}
else
- for_each_set_bit(i, &resource_mask, GENMASK(num_cores, 0))
+ for_each_set_bit(i, &resource_mask, num_cores)
info->logs_core[i].enable = enable;
ret = avs_ipc_set_enable_logs(adev, (u8 *)info, size);
@@ -55,15 +56,11 @@ int skl_log_buffer_offset(struct avs_dev *adev, u32 core)
static int
skl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg)
{
- unsigned long flags;
void __iomem *buf;
u16 size, write, offset;
- spin_lock_irqsave(&adev->dbg.trace_lock, flags);
- if (!kfifo_initialized(&adev->dbg.trace_fifo)) {
- spin_unlock_irqrestore(&adev->dbg.trace_lock, flags);
+ if (!avs_logging_fw(adev))
return 0;
- }
size = avs_log_buffer_size(adev) / 2;
write = readl(avs_sram_addr(adev, AVS_FW_REGS_WINDOW) + FW_REGS_DBG_LOG_WP(msg->log.core));
@@ -72,9 +69,7 @@ skl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg)
/* Address is guaranteed to exist in SRAM2. */
buf = avs_log_buffer_addr(adev, msg->log.core) + offset;
- __kfifo_fromio_locked(&adev->dbg.trace_fifo, buf, size, &adev->dbg.fifo_lock);
- wake_up(&adev->dbg.trace_waitq);
- spin_unlock_irqrestore(&adev->dbg.trace_lock, flags);
+ avs_dump_fw_log_wakeup(adev, buf, size);
return 0;
}
@@ -116,10 +111,10 @@ const struct avs_dsp_ops skl_dsp_ops = {
.load_basefw = avs_cldma_load_basefw,
.load_lib = avs_cldma_load_library,
.transfer_mods = avs_cldma_transfer_modules,
- .enable_logs = skl_enable_logs,
.log_buffer_offset = skl_log_buffer_offset,
.log_buffer_status = skl_log_buffer_status,
.coredump = skl_coredump,
.d0ix_toggle = skl_d0ix_toggle,
.set_d0ix = skl_set_d0ix,
+ AVS_SET_ENABLE_LOGS_OP(skl)
};
diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c
index 8a9f9fc48938..e845eaf0a1e7 100644
--- a/sound/soc/intel/avs/topology.c
+++ b/sound/soc/intel/avs/topology.c
@@ -1405,6 +1405,11 @@ static int avs_widget_load(struct snd_soc_component *comp, int index,
if (!le32_to_cpu(dw->priv.size))
return 0;
+ if (w->ignore_suspend && !AVS_S0IX_SUPPORTED) {
+ dev_info_once(comp->dev, "Device does not support S0IX, check BIOS settings\n");
+ w->ignore_suspend = false;
+ }
+
tplg = acomp->tplg;
mach = dev_get_platdata(comp->card->dev);
@@ -1442,6 +1447,11 @@ static int avs_dai_load(struct snd_soc_component *comp, int index,
static int avs_link_load(struct snd_soc_component *comp, int index, struct snd_soc_dai_link *link,
struct snd_soc_tplg_link_config *cfg)
{
+ if (link->ignore_suspend && !AVS_S0IX_SUPPORTED) {
+ dev_info_once(comp->dev, "Device does not support S0IX, check BIOS settings\n");
+ link->ignore_suspend = false;
+ }
+
if (!link->no_pcm) {
/* Stream control handled by IPCs. */
link->nonatomic = true;
diff --git a/sound/soc/intel/avs/utils.c b/sound/soc/intel/avs/utils.c
index 13611dee9787..82416b86662d 100644
--- a/sound/soc/intel/avs/utils.c
+++ b/sound/soc/intel/avs/utils.c
@@ -300,25 +300,3 @@ void avs_release_firmwares(struct avs_dev *adev)
kfree(entry);
}
}
-
-unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src, unsigned int len,
- spinlock_t *lock)
-{
- struct __kfifo *__fifo = &fifo->kfifo;
- unsigned long flags;
- unsigned int l, off;
-
- spin_lock_irqsave(lock, flags);
- len = min(len, kfifo_avail(fifo));
- off = __fifo->in & __fifo->mask;
- l = min(len, kfifo_size(fifo) - off);
-
- memcpy_fromio(__fifo->data + off, src, l);
- memcpy_fromio(__fifo->data, src + l, len - l);
- /* Make sure data copied from SRAM is visible to all CPUs. */
- smp_mb();
- __fifo->in += len;
- spin_unlock_irqrestore(lock, flags);
-
- return len;
-}
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index aa12d7e3dd2f..a472de1909f4 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -668,6 +668,7 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH
select SND_SOC_RT1308_SDW
select SND_SOC_RT1308
select SND_SOC_RT1316_SDW
+ select SND_SOC_RT1318_SDW
select SND_SOC_RT715_SDW
select SND_SOC_RT715_SDCA_SDW
select SND_SOC_RT5682_SDW
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index 53458e748191..d1fd7a2b32db 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -37,8 +37,7 @@ snd-soc-sof_da7219_max98373-objs := sof_da7219_max98373.o
snd-soc-ehl-rt5660-objs := ehl_rt5660.o
snd-soc-sof-ssp-amp-objs := sof_ssp_amp.o
snd-soc-sof-sdw-objs += sof_sdw.o \
- sof_sdw_max98373.o \
- sof_sdw_rt1308.o sof_sdw_rt1316.o \
+ sof_sdw_max98373.o sof_sdw_rt_amp.o \
sof_sdw_rt5682.o sof_sdw_rt700.o \
sof_sdw_rt711.o sof_sdw_rt711_sdca.o \
sof_sdw_rt715.o sof_sdw_rt715_sdca.o \
diff --git a/sound/soc/intel/boards/bdw-rt5650.c b/sound/soc/intel/boards/bdw-rt5650.c
index 67c3f49b924c..d0682bc543c9 100644
--- a/sound/soc/intel/boards/bdw-rt5650.c
+++ b/sound/soc/intel/boards/bdw-rt5650.c
@@ -88,7 +88,7 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_interval *chan = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
- /* The ADSP will covert the FE rate to 48k, max 4-channels */
+ /* The ADSP will convert the FE rate to 48k, max 4-channels */
rate->min = rate->max = 48000;
chan->min = 2;
chan->max = 4;
diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c
index 31488702768e..f3e08d258ac1 100644
--- a/sound/soc/intel/boards/bdw-rt5677.c
+++ b/sound/soc/intel/boards/bdw-rt5677.c
@@ -141,7 +141,7 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_interval *chan = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
- /* The ADSP will covert the FE rate to 48k, stereo */
+ /* The ADSP will convert the FE rate to 48k, stereo */
rate->min = rate->max = 48000;
chan->min = chan->max = 2;
diff --git a/sound/soc/intel/boards/bdw_rt286.c b/sound/soc/intel/boards/bdw_rt286.c
index 6b76df0e7c9b..b7687a93a923 100644
--- a/sound/soc/intel/boards/bdw_rt286.c
+++ b/sound/soc/intel/boards/bdw_rt286.c
@@ -73,6 +73,13 @@ static int codec_link_init(struct snd_soc_pcm_runtime *rtd)
return snd_soc_component_set_jack(codec, &card_headset, NULL);
}
+static void codec_link_exit(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_component *codec = asoc_rtd_to_codec(rtd, 0)->component;
+
+ snd_soc_component_set_jack(codec, NULL, NULL);
+}
+
static int codec_link_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -165,6 +172,7 @@ static struct snd_soc_dai_link card_dai_links[] = {
.nonatomic = 1,
.no_pcm = 1,
.init = codec_link_init,
+ .exit = codec_link_exit,
.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,
@@ -175,43 +183,24 @@ static struct snd_soc_dai_link card_dai_links[] = {
},
};
-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)
+static int card_suspend_pre(struct snd_soc_card *card)
{
- bdw_rt286_disable_jack(card);
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, "rt286-aif1");
- return 0;
+ return snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
}
-static int bdw_rt286_resume(struct snd_soc_card *card)
+static int card_resume_post(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;
- }
- }
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, "rt286-aif1");
- return 0;
+ return snd_soc_component_set_jack(codec_dai->component, &card_headset, NULL);
}
static struct snd_soc_card bdw_rt286_card = {
.owner = THIS_MODULE,
+ .suspend_pre = card_suspend_pre,
+ .resume_post = card_resume_post,
.dai_link = card_dai_links,
.num_links = ARRAY_SIZE(card_dai_links),
.controls = card_controls,
@@ -221,8 +210,6 @@ static struct snd_soc_card bdw_rt286_card = {
.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. */
@@ -254,18 +241,8 @@ static int bdw_rt286_probe(struct platform_device *pdev)
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
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c
index 7c6c95e99ade..c593995facaa 100644
--- a/sound/soc/intel/boards/bxt_da7219_max98357a.c
+++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c
@@ -19,7 +19,6 @@
#include <sound/soc-acpi.h>
#include "../../codecs/hdac_hdmi.h"
#include "../../codecs/da7219.h"
-#include "../../codecs/da7219-aad.h"
#include "../common/soc-intel-quirks.h"
#include "hda_dsp_common.h"
@@ -259,7 +258,7 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_3,
KEY_VOICECOMMAND);
- da7219_aad_jack_det(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/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c
index 4bd93c3ba377..bf89fe80423d 100644
--- a/sound/soc/intel/boards/bxt_rt298.c
+++ b/sound/soc/intel/boards/bxt_rt298.c
@@ -210,7 +210,7 @@ static int broxton_ssp5_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
- /* The ADSP will covert the FE rate to 48k, stereo */
+ /* The ADSP will convert the FE rate to 48k, stereo */
rate->min = rate->max = 48000;
chan->min = chan->max = 2;
diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c
index ae899866863e..41cec67157b6 100644
--- a/sound/soc/intel/boards/bytcht_cx2072x.c
+++ b/sound/soc/intel/boards/bytcht_cx2072x.c
@@ -111,7 +111,7 @@ static int byt_cht_cx2072x_fixup(struct snd_soc_pcm_runtime *rtd,
hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
int ret;
- /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+ /* The DSP will convert the FE rate to 48k, stereo, 24bits */
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c
index a935c5fd9edb..09d1f0f6d686 100644
--- a/sound/soc/intel/boards/bytcht_es8316.c
+++ b/sound/soc/intel/boards/bytcht_es8316.c
@@ -243,7 +243,7 @@ static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_CHANNELS);
int ret, bits;
- /* The DSP will covert the FE rate to 48k, stereo */
+ /* The DSP will convert the FE rate to 48k, stereo */
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index fb9d9e271845..6db07b2417ca 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -1390,7 +1390,7 @@ static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_CHANNELS);
int ret, bits;
- /* The DSP will covert the FE rate to 48k, stereo */
+ /* The DSP will convert the FE rate to 48k, stereo */
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c
index 2beb686768f2..81ac6eeda2e6 100644
--- a/sound/soc/intel/boards/bytcr_rt5651.c
+++ b/sound/soc/intel/boards/bytcr_rt5651.c
@@ -683,7 +683,7 @@ static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_CHANNELS);
int ret, bits;
- /* The DSP will covert the FE rate to 48k, stereo */
+ /* The DSP will convert the FE rate to 48k, stereo */
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c
index 45a6805787f5..1669eb3bd80f 100644
--- a/sound/soc/intel/boards/bytcr_wm5102.c
+++ b/sound/soc/intel/boards/bytcr_wm5102.c
@@ -248,7 +248,7 @@ static int byt_wm5102_codec_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_CHANNELS);
int ret;
- /* The DSP will covert the FE rate to 48k, stereo */
+ /* The DSP will convert the FE rate to 48k, stereo */
rate->min = 48000;
rate->max = 48000;
channels->min = 2;
diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
index 64eb73525ee3..2c086e901aae 100644
--- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c
+++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
@@ -272,7 +272,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
return ret;
}
- /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+ /* The DSP will convert the FE rate to 48k, stereo, 24bits */
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
diff --git a/sound/soc/intel/boards/cht_bsw_nau8824.c b/sound/soc/intel/boards/cht_bsw_nau8824.c
index 4c1d83b317c7..af2d9a78465d 100644
--- a/sound/soc/intel/boards/cht_bsw_nau8824.c
+++ b/sound/soc/intel/boards/cht_bsw_nau8824.c
@@ -136,7 +136,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
int ret;
- /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+ /* The DSP will convert the FE rate to 48k, stereo, 24bits */
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
index 96501aed8bee..25a054bd4073 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
@@ -344,7 +344,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
- /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+ /* The DSP will convert the FE rate to 48k, stereo, 24bits */
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c
index ca47f6476b07..49d3da8f7316 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5672.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5672.c
@@ -270,7 +270,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_CHANNELS);
int ret, bits;
- /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+ /* The DSP will convert the FE rate to 48k, stereo, 24bits */
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c
index 329457e3e3a2..18365ce6bcba 100644
--- a/sound/soc/intel/boards/kbl_da7219_max98357a.c
+++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c
@@ -19,7 +19,6 @@
#include <sound/soc.h>
#include "../../codecs/da7219.h"
#include "../../codecs/hdac_hdmi.h"
-#include "../../codecs/da7219-aad.h"
#define KBL_DIALOG_CODEC_DAI "da7219-hifi"
#define KBL_MAXIM_CODEC_DAI "HiFi"
@@ -207,7 +206,7 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
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, &ctx->kabylake_headset);
+ snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL);
ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
if (ret)
diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c
index 362579f25835..ad4223fee0c5 100644
--- a/sound/soc/intel/boards/kbl_da7219_max98927.c
+++ b/sound/soc/intel/boards/kbl_da7219_max98927.c
@@ -19,7 +19,6 @@
#include <sound/soc.h>
#include "../../codecs/da7219.h"
#include "../../codecs/hdac_hdmi.h"
-#include "../../codecs/da7219-aad.h"
#define KBL_DIALOG_CODEC_DAI "da7219-hifi"
#define MAX98927_CODEC_DAI "max98927-aif1"
@@ -382,7 +381,7 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
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, &ctx->kabylake_headset);
+ snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL);
return 0;
}
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
index 8dceb0b02581..e13a5a4d8f7e 100644
--- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c
+++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
@@ -154,7 +154,7 @@ static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
- /* The ADSP will covert the FE rate to 48k, stereo */
+ /* The ADSP will convert the FE rate to 48k, stereo */
rate->min = rate->max = 48000;
chan->min = chan->max = 2;
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
index 62c0d46d0086..575604dc8936 100644
--- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
+++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
@@ -333,7 +333,7 @@ static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
- /* The ADSP will covert the FE rate to 48k, stereo */
+ /* The ADSP will convert the FE rate to 48k, stereo */
rate->min = rate->max = 48000;
chan->min = chan->max = 2;
diff --git a/sound/soc/intel/boards/sof_cirrus_common.c b/sound/soc/intel/boards/sof_cirrus_common.c
index 6e39eda77385..851c516c8f5b 100644
--- a/sound/soc/intel/boards/sof_cirrus_common.c
+++ b/sound/soc/intel/boards/sof_cirrus_common.c
@@ -155,7 +155,7 @@ static const char * const cs35l41_name_prefixes[] = { "WL", "WR", "TL", "TR" };
*/
static int cs35l41_compute_codec_conf(void)
{
- const char * const uid_strings[] = { "0", "1", "2", "3" };
+ static const char * const uid_strings[] = { "0", "1", "2", "3" };
unsigned int uid, sz = 0;
struct acpi_device *adev;
struct device *physdev;
diff --git a/sound/soc/intel/boards/sof_da7219_max98373.c b/sound/soc/intel/boards/sof_da7219_max98373.c
index e048e789e633..740aa11cb019 100644
--- a/sound/soc/intel/boards/sof_da7219_max98373.c
+++ b/sound/soc/intel/boards/sof_da7219_max98373.c
@@ -7,13 +7,13 @@
#include <linux/input.h>
#include <linux/module.h>
+#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <linux/platform_device.h>
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include "../../codecs/da7219.h"
-#include "../../codecs/da7219-aad.h"
#include "hda_dsp_common.h"
#define DIALOG_CODEC_DAI "da7219-hifi"
@@ -184,7 +184,7 @@ static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
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);
+ snd_soc_component_set_jack(component, jack, NULL);
return ret;
}
diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c
index 70713e4b07dc..773e5d1d87d4 100644
--- a/sound/soc/intel/boards/sof_es8336.c
+++ b/sound/soc/intel/boards/sof_es8336.c
@@ -783,7 +783,7 @@ static int sof_es8336_remove(struct platform_device *pdev)
struct snd_soc_card *card = platform_get_drvdata(pdev);
struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card);
- cancel_delayed_work(&priv->pcm_pop_work);
+ cancel_delayed_work_sync(&priv->pcm_pop_work);
gpiod_put(priv->gpio_speakers);
device_remove_software_node(priv->codec_dev);
put_device(priv->codec_dev);
diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c
index 5585c217f78d..27880224359d 100644
--- a/sound/soc/intel/boards/sof_nau8825.c
+++ b/sound/soc/intel/boards/sof_nau8825.c
@@ -47,6 +47,7 @@
#define SOF_RT1019P_SPEAKER_AMP_PRESENT BIT(14)
#define SOF_MAX98373_SPEAKER_AMP_PRESENT BIT(15)
#define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(16)
+#define SOF_RT1015P_SPEAKER_AMP_PRESENT BIT(17)
static unsigned long sof_nau8825_quirk = SOF_NAU8825_SSP_CODEC(0);
@@ -483,6 +484,8 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
} else if (sof_nau8825_quirk &
SOF_MAX98360A_SPEAKER_AMP_PRESENT) {
max_98360a_dai_link(&links[id]);
+ } else if (sof_nau8825_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) {
+ sof_rt1015p_dai_link(&links[id]);
} else {
goto devm_err;
}
@@ -576,6 +579,8 @@ static int sof_audio_probe(struct platform_device *pdev)
if (sof_nau8825_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT)
max_98373_set_codec_conf(&sof_audio_card_nau8825);
+ else if (sof_nau8825_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT)
+ sof_rt1015p_codec_conf(&sof_audio_card_nau8825);
if (sof_nau8825_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
sof_audio_card_nau8825.num_links++;
@@ -642,6 +647,16 @@ static const struct platform_device_id board_ids[] = {
SOF_SSP_BT_OFFLOAD_PRESENT),
},
+ {
+ .name = "adl_rt1015p_nau8825",
+ .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
+ SOF_SPEAKER_AMP_PRESENT |
+ SOF_RT1015P_SPEAKER_AMP_PRESENT |
+ SOF_NAU8825_SSP_AMP(1) |
+ SOF_NAU8825_NUM_HDMIDEV(4) |
+ SOF_BT_OFFLOAD_SSP(2) |
+ SOF_SSP_BT_OFFLOAD_PRESENT),
+ },
{ }
};
MODULE_DEVICE_TABLE(platform, board_ids);
@@ -663,3 +678,4 @@ MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);
+MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON);
diff --git a/sound/soc/intel/boards/sof_realtek_common.c b/sound/soc/intel/boards/sof_realtek_common.c
index ff2851fc8930..6c12ca92f371 100644
--- a/sound/soc/intel/boards/sof_realtek_common.c
+++ b/sound/soc/intel/boards/sof_realtek_common.c
@@ -267,7 +267,8 @@ static int rt1015_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai_link *dai_link = rtd->dai_link;
struct snd_soc_dai *codec_dai;
- int i, clk_freq, ret;
+ int i, clk_freq;
+ int ret = 0;
clk_freq = sof_dai_get_bclk(rtd);
diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c
index 2358be208c1f..2eabc4b0fafa 100644
--- a/sound/soc/intel/boards/sof_rt5682.c
+++ b/sound/soc/intel/boards/sof_rt5682.c
@@ -867,10 +867,6 @@ static int sof_audio_probe(struct platform_device *pdev)
if (acpi_dev_present("RTL5682", NULL, -1))
sof_rt5682_quirk |= SOF_RT5682S_HEADPHONE_CODEC_PRESENT;
- /* Detect the headset codec variant to support machines in DMI quirk */
- if (acpi_dev_present("RTL5682", NULL, -1))
- sof_rt5682_quirk |= SOF_RT5682S_HEADPHONE_CODEC_PRESENT;
-
if (soc_intel_is_byt() || soc_intel_is_cht()) {
is_legacy_cpu = 1;
dmic_be_num = 0;
@@ -1092,10 +1088,9 @@ static const struct platform_device_id board_ids[] = {
SOF_SSP_BT_OFFLOAD_PRESENT),
},
{
- .name = "adl_rt1019_rt5682s",
+ .name = "adl_rt1019_rt5682",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
SOF_RT5682_SSP_CODEC(0) |
- SOF_RT5682S_HEADPHONE_CODEC_PRESENT |
SOF_SPEAKER_AMP_PRESENT |
SOF_RT1019_SPEAKER_AMP_PRESENT |
SOF_RT5682_SSP_AMP(1) |
@@ -1109,6 +1104,12 @@ static const struct platform_device_id board_ids[] = {
SOF_RT5682_SSP_AMP(1) |
SOF_RT5682_NUM_HDMIDEV(4)),
},
+ {
+ .name = "jsl_rt5682",
+ .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
+ SOF_RT5682_MCLK_24MHZ |
+ SOF_RT5682_SSP_CODEC(0)),
+ },
{ }
};
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 ee9857dc3135..d2ed807abde9 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -355,6 +355,47 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
RT711_JD2),
},
+ /* RaptorLake devices */
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C10"),
+ },
+ /* No Jack */
+ .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+ SOF_SDW_FOUR_SPK),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C11")
+ },
+ .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, "0C40")
+ },
+ .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, "0C4F")
+ },
+ .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+ RT711_JD2 |
+ SOF_SDW_FOUR_SPK),
+ },
/* MeteorLake devices */
{
.callback = sof_sdw_quirk_cb,
@@ -509,14 +550,23 @@ static struct sof_sdw_codec_info codec_info_list[] = {
.direction = {true, false},
.dai_name = "rt1308-aif",
.ops = &sof_sdw_rt1308_i2s_ops,
- .init = sof_sdw_rt1308_init,
+ .init = sof_sdw_rt_amp_init,
+ .exit = sof_sdw_rt_amp_exit,
.codec_type = SOF_SDW_CODEC_TYPE_AMP,
},
{
.part_id = 0x1316,
.direction = {true, true},
.dai_name = "rt1316-aif",
- .init = sof_sdw_rt1316_init,
+ .init = sof_sdw_rt_amp_init,
+ .exit = sof_sdw_rt_amp_exit,
+ .codec_type = SOF_SDW_CODEC_TYPE_AMP,
+ },
+ {
+ .part_id = 0x1318,
+ .direction = {true, true},
+ .dai_name = "rt1318-aif",
+ .init = sof_sdw_rt_amp_init,
.codec_type = SOF_SDW_CODEC_TYPE_AMP,
},
{
diff --git a/sound/soc/intel/boards/sof_sdw_amp_coeff_tables.h b/sound/soc/intel/boards/sof_sdw_amp_coeff_tables.h
new file mode 100644
index 000000000000..4a3e6fdbd623
--- /dev/null
+++ b/sound/soc/intel/boards/sof_sdw_amp_coeff_tables.h
@@ -0,0 +1,300 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ */
+
+/*
+ * sof_sdw_amp_coeff_tables.h - related coefficients for amplifier parameters
+ */
+
+#ifndef SND_SOC_SOF_SDW_AMP_COEFF_H
+#define SND_SOC_SOF_SDW_AMP_COEFF_H
+
+#define RT1308_MAX_BQ_REG 480
+#define RT1316_MAX_BQ_REG 580
+
+static const u8 __maybe_unused dell_0a5d_bq_params[] = {
+ 0xb0, 0xc5, 0x00, /* address: 0xc5b0; data: 0x00 */
+ 0xb1, 0xc5, 0x32,
+ 0xb2, 0xc5, 0x44,
+ 0xb3, 0xc5, 0x19,
+ 0xc0, 0xc5, 0x04,
+ 0xc1, 0xc5, 0x00,
+ 0xc2, 0xc5, 0x00,
+ 0xc3, 0xc5, 0x00,
+ 0xd0, 0xc5, 0x02,
+ 0xd1, 0xc5, 0x00,
+ 0xd2, 0xc5, 0x00,
+ 0xd3, 0xc5, 0x00,
+ 0xe0, 0xc5, 0x01,
+ 0xe1, 0xc5, 0xe8,
+ 0xe2, 0xc5, 0x5f,
+ 0xe3, 0xc5, 0x8a,
+ 0xf0, 0xc5, 0x1f,
+ 0xf1, 0xc5, 0x4e,
+ 0xf2, 0xc5, 0x90,
+ 0xf3, 0xc5, 0x11,
+ 0x50, 0xc6, 0x01,
+ 0x51, 0xc6, 0xff,
+ 0x52, 0xc6, 0x45,
+ 0x53, 0xc6, 0x41,
+ 0x60, 0xc6, 0x1c,
+ 0x61, 0xc6, 0x00,
+ 0x62, 0xc6, 0x00,
+ 0x63, 0xc6, 0x00,
+ 0x70, 0xc6, 0x02,
+ 0x71, 0xc6, 0x00,
+ 0x72, 0xc6, 0x00,
+ 0x73, 0xc6, 0x00,
+ 0x80, 0xc6, 0x03,
+ 0x81, 0xc6, 0xfe,
+ 0x82, 0xc6, 0x89,
+ 0x83, 0xc6, 0xfa,
+ 0x90, 0xc6, 0x1e,
+ 0x91, 0xc6, 0x01,
+ 0x92, 0xc6, 0x74,
+ 0x93, 0xc6, 0xf6,
+ 0x00, 0xc6, 0x01,
+ 0x01, 0xc6, 0xd9,
+ 0x02, 0xc6, 0xfb,
+ 0x03, 0xc6, 0xc4,
+ 0x10, 0xc6, 0x1c,
+ 0x11, 0xc6, 0x00,
+ 0x12, 0xc6, 0x00,
+ 0x13, 0xc6, 0x00,
+ 0x20, 0xc6, 0x02,
+ 0x21, 0xc6, 0x00,
+ 0x22, 0xc6, 0x00,
+ 0x23, 0xc6, 0x00,
+ 0x30, 0xc6, 0x03,
+ 0x31, 0xc6, 0xaf,
+ 0x32, 0xc6, 0x23,
+ 0x33, 0xc6, 0xcb,
+ 0x40, 0xc6, 0x1e,
+ 0x41, 0xc6, 0x47,
+ 0x42, 0xc6, 0x34,
+ 0x43, 0xc6, 0xba,
+ 0xa0, 0xc6, 0x01,
+ 0xa1, 0xc6, 0xff,
+ 0xa2, 0xc6, 0x45,
+ 0xa3, 0xc6, 0x41,
+ 0xb0, 0xc6, 0x1c,
+ 0xb1, 0xc6, 0x00,
+ 0xb2, 0xc6, 0x00,
+ 0xb3, 0xc6, 0x00,
+ 0xc0, 0xc6, 0x02,
+ 0xc1, 0xc6, 0x00,
+ 0xc2, 0xc6, 0x00,
+ 0xc3, 0xc6, 0x00,
+ 0xd0, 0xc6, 0x03,
+ 0xd1, 0xc6, 0xfe,
+ 0xd2, 0xc6, 0x89,
+ 0xd3, 0xc6, 0xfa,
+ 0xe0, 0xc6, 0x1e,
+ 0xe1, 0xc6, 0x01,
+ 0xe2, 0xc6, 0x74,
+ 0xe3, 0xc6, 0xf6,
+ 0x40, 0xc5, 0x0d,
+ 0x30, 0xc7, 0x15,
+ 0x31, 0xc7, 0x7c,
+ 0x32, 0xc7, 0x0f,
+ 0x33, 0xc7, 0xa0,
+ 0x40, 0xc7, 0x00,
+ 0x41, 0xc7, 0x00,
+ 0x42, 0xc7, 0xf8,
+ 0x43, 0xc7, 0xf8,
+ 0x50, 0xc7, 0x00,
+ 0x51, 0xc7, 0x00,
+ 0x52, 0xc7, 0x00,
+ 0x53, 0xc7, 0x01,
+ 0x90, 0xc7, 0x00,
+ 0x91, 0xc7, 0x14,
+ 0x92, 0xc7, 0x00,
+ 0x93, 0xc7, 0x14,
+ 0xa0, 0xc7, 0x00,
+ 0xa1, 0xc7, 0x00,
+ 0xa2, 0xc7, 0xf8,
+ 0xa3, 0xc7, 0xf8,
+ 0xb0, 0xc7, 0x00,
+ 0xb1, 0xc7, 0x00,
+ 0xb2, 0xc7, 0x00,
+ 0xb3, 0xc7, 0x00,
+ 0x60, 0xc7, 0x03,
+ 0x61, 0xc7, 0xe8,
+ 0x62, 0xc7, 0x03,
+ 0x63, 0xc7, 0xb6,
+ 0x70, 0xc7, 0x00,
+ 0x71, 0xc7, 0x00,
+ 0x72, 0xc7, 0xf8,
+ 0x73, 0xc7, 0xf8,
+ 0x80, 0xc7, 0x00,
+ 0x81, 0xc7, 0x00,
+ 0x82, 0xc7, 0x00,
+ 0x83, 0xc7, 0x00,
+ 0xc0, 0xc7, 0x00,
+ 0xc1, 0xc7, 0x14,
+ 0xc2, 0xc7, 0x00,
+ 0xc3, 0xc7, 0x14,
+ 0xd0, 0xc7, 0x00,
+ 0xd1, 0xc7, 0x00,
+ 0xd2, 0xc7, 0xf8,
+ 0xd3, 0xc7, 0xf8,
+ 0xe0, 0xc7, 0x00,
+ 0xe1, 0xc7, 0x00,
+ 0xe2, 0xc7, 0x00,
+ 0xe3, 0xc7, 0x00,
+ 0x60, 0xc5, 0x02,
+ 0x61, 0xc5, 0x00,
+ 0x62, 0xc5, 0x00,
+ 0x63, 0xc5, 0x00,
+ 0x70, 0xc5, 0x02,
+ 0x71, 0xc5, 0x00,
+ 0x72, 0xc5, 0x00,
+ 0x73, 0xc5, 0x00,
+ 0x80, 0xc5, 0x02,
+ 0x81, 0xc5, 0x00,
+ 0x82, 0xc5, 0x00,
+ 0x83, 0xc5, 0x00,
+ 0x90, 0xc5, 0x02,
+ 0x91, 0xc5, 0x00,
+ 0x92, 0xc5, 0x00,
+ 0x93, 0xc5, 0x00,
+ 0x50, 0xc5, 0x01,
+};
+
+static const u8 __maybe_unused dell_0b00_bq_params[] = {
+ 0x03, 0xc2, 0x00,
+ 0x04, 0xc2, 0xb2,
+ 0x05, 0xc2, 0xe0,
+ 0x06, 0xc2, 0x3a,
+ 0x07, 0xc2, 0x01,
+ 0x08, 0xc2, 0x65,
+ 0x09, 0xc2, 0xc0,
+ 0x0a, 0xc2, 0x75,
+ 0x0b, 0xc2, 0x00,
+ 0x0c, 0xc2, 0xb2,
+ 0x0d, 0xc2, 0xe0,
+ 0x0e, 0xc2, 0x3a,
+ 0x0f, 0xc2, 0xf7,
+ 0x10, 0xc2, 0x4d,
+ 0x11, 0xc2, 0x5b,
+ 0x12, 0xc2, 0xe9,
+ 0x13, 0xc2, 0x03,
+ 0x14, 0xc2, 0x7e,
+ 0x15, 0xc2, 0x25,
+ 0x16, 0xc2, 0x01,
+ 0x17, 0xc2, 0x07,
+ 0x18, 0xc2, 0xfd,
+ 0x19, 0xc2, 0x15,
+ 0x1a, 0xc2, 0x04,
+ 0x1b, 0xc2, 0xf0,
+ 0x1c, 0xc2, 0x05,
+ 0x1d, 0xc2, 0xd5,
+ 0x1e, 0xc2, 0xf7,
+ 0x1f, 0xc2, 0x07,
+ 0x20, 0xc2, 0xfd,
+ 0x21, 0xc2, 0x15,
+ 0x22, 0xc2, 0x04,
+ 0x23, 0xc2, 0xf0,
+ 0x24, 0xc2, 0x05,
+ 0x25, 0xc2, 0xd8,
+ 0x26, 0xc2, 0x17,
+ 0x27, 0xc2, 0x07,
+ 0x28, 0xc2, 0xfa,
+ 0x29, 0xc2, 0x2c,
+ 0x2a, 0xc2, 0x29,
+ 0x2b, 0xc2, 0x07,
+ 0x2c, 0xc2, 0x74,
+ 0x2d, 0xc2, 0xe0,
+ 0x2e, 0xc2, 0x33,
+ 0x2f, 0xc2, 0xf1,
+ 0x30, 0xc2, 0x16,
+ 0x31, 0xc2, 0x3f,
+ 0x32, 0xc2, 0x9b,
+ 0x33, 0xc2, 0x07,
+ 0x34, 0xc2, 0x74,
+ 0x35, 0xc2, 0xe0,
+ 0x36, 0xc2, 0x33,
+ 0x37, 0xc2, 0xf1,
+ 0x38, 0xc2, 0x29,
+ 0x39, 0xc2, 0xb0,
+ 0x3a, 0xc2, 0x4d,
+ 0x3b, 0xc2, 0x06,
+ 0x3c, 0xc2, 0xfd,
+ 0x3d, 0xc2, 0x31,
+ 0x3e, 0xc2, 0x18,
+ 0x3f, 0xc2, 0x07,
+ 0x40, 0xc2, 0xfd,
+ 0x41, 0xc2, 0x15,
+ 0x42, 0xc2, 0x04,
+ 0x43, 0xc2, 0xf0,
+ 0x44, 0xc2, 0x05,
+ 0x45, 0xc2, 0xd5,
+ 0x46, 0xc2, 0xf7,
+ 0x47, 0xc2, 0x07,
+ 0x48, 0xc2, 0xfd,
+ 0x49, 0xc2, 0x15,
+ 0x4a, 0xc2, 0x04,
+ 0x4b, 0xc2, 0xf0,
+ 0x4c, 0xc2, 0x05,
+ 0x4d, 0xc2, 0xd8,
+ 0x4e, 0xc2, 0x17,
+ 0x4f, 0xc2, 0x07,
+ 0x50, 0xc2, 0xfa,
+ 0x51, 0xc2, 0x2c,
+ 0x52, 0xc2, 0x29,
+ 0x0b, 0xc0, 0x30,
+ 0x80, 0xc3, 0x13,
+ 0x81, 0xc3, 0x88,
+ 0x82, 0xc3, 0x17,
+ 0x83, 0xc3, 0x70,
+ 0x84, 0xc3, 0x00,
+ 0x85, 0xc3, 0x00,
+ 0x86, 0xc3, 0xff,
+ 0x87, 0xc3, 0xee,
+ 0x88, 0xc3, 0x02,
+ 0x92, 0xc3, 0x00,
+ 0x93, 0xc3, 0x14,
+ 0x94, 0xc3, 0x00,
+ 0x95, 0xc3, 0x14,
+ 0x96, 0xc3, 0x00,
+ 0x97, 0xc3, 0x00,
+ 0x98, 0xc3, 0x00,
+ 0x99, 0xc3, 0x00,
+ 0x9a, 0xc3, 0x01,
+ 0x89, 0xc3, 0x03,
+ 0x8a, 0xc3, 0xe8,
+ 0x8b, 0xc3, 0x03,
+ 0x8c, 0xc3, 0xb6,
+ 0x8d, 0xc3, 0x00,
+ 0x8e, 0xc3, 0x00,
+ 0x8f, 0xc3, 0xff,
+ 0x90, 0xc3, 0xee,
+ 0x91, 0xc3, 0x01,
+ 0x9b, 0xc3, 0x00,
+ 0x9c, 0xc3, 0x14,
+ 0x9d, 0xc3, 0x00,
+ 0x9e, 0xc3, 0x14,
+ 0x9f, 0xc3, 0x00,
+ 0xa0, 0xc3, 0x00,
+ 0xa1, 0xc3, 0x00,
+ 0xa2, 0xc3, 0x00,
+ 0xa3, 0xc3, 0x01,
+ 0x61, 0xc2, 0x08,
+ 0x62, 0xc2, 0x00,
+ 0x63, 0xc2, 0x00,
+ 0x64, 0xc2, 0x00,
+ 0x65, 0xc2, 0x08,
+ 0x66, 0xc2, 0x00,
+ 0x67, 0xc2, 0x00,
+ 0x68, 0xc2, 0x00,
+ 0x69, 0xc2, 0x08,
+ 0x6a, 0xc2, 0x00,
+ 0x6b, 0xc2, 0x00,
+ 0x6c, 0xc2, 0x00,
+ 0x6d, 0xc2, 0x08,
+ 0x6e, 0xc2, 0x00,
+ 0x6f, 0xc2, 0x00,
+ 0x70, 0xc2, 0x00,
+ 0x00, 0xc2, 0xc0,
+};
+
+#endif
diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h
index e2457738a332..350010b0e5f4 100644
--- a/sound/soc/intel/boards/sof_sdw_common.h
+++ b/sound/soc/intel/boards/sof_sdw_common.h
@@ -83,6 +83,7 @@ struct mc_private {
bool idisp_codec;
struct snd_soc_jack sdw_headset;
struct device *headset_codec_dev; /* only one headset per card */
+ struct device *amp_dev1, *amp_dev2;
};
extern unsigned long sof_sdw_quirk;
@@ -124,21 +125,18 @@ int sof_sdw_rt700_init(struct snd_soc_card *card,
struct sof_sdw_codec_info *info,
bool playback);
-/* RT1308 support */
+/* RT1308 I2S support */
extern struct snd_soc_ops sof_sdw_rt1308_i2s_ops;
-int sof_sdw_rt1308_init(struct snd_soc_card *card,
+/* generic amp support */
+int sof_sdw_rt_amp_init(struct snd_soc_card *card,
const struct snd_soc_acpi_link_adr *link,
struct snd_soc_dai_link *dai_links,
struct sof_sdw_codec_info *info,
bool playback);
+int sof_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
/* RT1316 support */
-int sof_sdw_rt1316_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback);
/* RT715 support */
int sof_sdw_rt715_init(struct snd_soc_card *card,
diff --git a/sound/soc/intel/boards/sof_sdw_rt1308.c b/sound/soc/intel/boards/sof_sdw_rt1308.c
deleted file mode 100644
index f078fb1aad02..000000000000
--- a/sound/soc/intel/boards/sof_sdw_rt1308.c
+++ /dev/null
@@ -1,158 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-// Copyright (c) 2020 Intel Corporation
-
-/*
- * sof_sdw_rt1308 - Helpers to handle RT1308 from generic machine driver
- */
-
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <sound/control.h>
-#include <sound/soc.h>
-#include <sound/soc-acpi.h>
-#include <sound/soc-dapm.h>
-#include "sof_sdw_common.h"
-#include "../../codecs/rt1308.h"
-
-static const struct snd_soc_dapm_widget rt1308_widgets[] = {
- SND_SOC_DAPM_SPK("Speaker", NULL),
-};
-
-/*
- * dapm routes for rt1308 will be registered dynamically according
- * to the number of rt1308 used. The first two entries will be registered
- * for one codec case, and the last two entries are also registered
- * if two 1308s are used.
- */
-static const struct snd_soc_dapm_route rt1308_map[] = {
- { "Speaker", NULL, "rt1308-1 SPOL" },
- { "Speaker", NULL, "rt1308-1 SPOR" },
- { "Speaker", NULL, "rt1308-2 SPOL" },
- { "Speaker", NULL, "rt1308-2 SPOR" },
-};
-
-static const struct snd_kcontrol_new rt1308_controls[] = {
- SOC_DAPM_PIN_SWITCH("Speaker"),
-};
-
-static int first_spk_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_card *card = rtd->card;
- int ret;
-
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s spk:rt1308",
- card->components);
- if (!card->components)
- return -ENOMEM;
-
- ret = snd_soc_add_card_controls(card, rt1308_controls,
- ARRAY_SIZE(rt1308_controls));
- if (ret) {
- dev_err(card->dev, "rt1308 controls addition failed: %d\n", ret);
- return ret;
- }
-
- ret = snd_soc_dapm_new_controls(&card->dapm, rt1308_widgets,
- ARRAY_SIZE(rt1308_widgets));
- if (ret) {
- dev_err(card->dev, "rt1308 widgets addition failed: %d\n", ret);
- return ret;
- }
-
- ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_map, 2);
- if (ret)
- dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret);
-
- return ret;
-}
-
-static int second_spk_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_card *card = rtd->card;
- int ret;
-
- ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_map + 2, 2);
- if (ret)
- dev_err(rtd->dev, "failed to add second SPK map: %d\n", ret);
-
- return ret;
-}
-
-static int all_spk_init(struct snd_soc_pcm_runtime *rtd)
-{
- int ret;
-
- ret = first_spk_init(rtd);
- if (ret)
- return ret;
-
- return second_spk_init(rtd);
-}
-
-static int rt1308_i2s_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_card *card = rtd->card;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- int clk_id, clk_freq, pll_out;
- int err;
-
- clk_id = RT1308_PLL_S_MCLK;
- clk_freq = 38400000;
-
- pll_out = params_rate(params) * 512;
-
- /* Set rt1308 pll */
- err = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out);
- if (err < 0) {
- dev_err(card->dev, "Failed to set RT1308 PLL: %d\n", err);
- return err;
- }
-
- /* Set rt1308 sysclk */
- err = snd_soc_dai_set_sysclk(codec_dai, RT1308_FS_SYS_S_PLL, pll_out,
- SND_SOC_CLOCK_IN);
- if (err < 0) {
- dev_err(card->dev, "Failed to set RT1308 SYSCLK: %d\n", err);
- return err;
- }
-
- return 0;
-}
-
-/* machine stream operations */
-struct snd_soc_ops sof_sdw_rt1308_i2s_ops = {
- .hw_params = rt1308_i2s_hw_params,
-};
-
-int sof_sdw_rt1308_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback)
-{
- /* Count amp number and do init on playback link only. */
- if (!playback)
- return 0;
-
- info->amp_num++;
- if (info->amp_num == 1)
- dai_links->init = first_spk_init;
-
- if (info->amp_num == 2) {
- /*
- * if two 1308s are in one dai link, the init function
- * in this dai link will be first set for the first speaker,
- * and it should be reset to initialize all speakers when
- * the second speaker is found.
- */
- if (dai_links->init)
- dai_links->init = all_spk_init;
- else
- dai_links->init = second_spk_init;
- }
-
- return 0;
-}
diff --git a/sound/soc/intel/boards/sof_sdw_rt1316.c b/sound/soc/intel/boards/sof_sdw_rt1316.c
deleted file mode 100644
index 58194b380232..000000000000
--- a/sound/soc/intel/boards/sof_sdw_rt1316.c
+++ /dev/null
@@ -1,120 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-// Copyright (c) 2020 Intel Corporation
-
-/*
- * sof_sdw_rt1316 - Helpers to handle RT1316 from generic machine driver
- */
-
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <sound/control.h>
-#include <sound/soc.h>
-#include <sound/soc-acpi.h>
-#include <sound/soc-dapm.h>
-#include "sof_sdw_common.h"
-
-static const struct snd_soc_dapm_widget rt1316_widgets[] = {
- SND_SOC_DAPM_SPK("Speaker", NULL),
-};
-
-/*
- * dapm routes for rt1316 will be registered dynamically according
- * to the number of rt1316 used. The first two entries will be registered
- * for one codec case, and the last two entries are also registered
- * if two 1316s are used.
- */
-static const struct snd_soc_dapm_route rt1316_map[] = {
- { "Speaker", NULL, "rt1316-1 SPOL" },
- { "Speaker", NULL, "rt1316-1 SPOR" },
- { "Speaker", NULL, "rt1316-2 SPOL" },
- { "Speaker", NULL, "rt1316-2 SPOR" },
-};
-
-static const struct snd_kcontrol_new rt1316_controls[] = {
- SOC_DAPM_PIN_SWITCH("Speaker"),
-};
-
-static int first_spk_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_card *card = rtd->card;
- int ret;
-
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s spk:rt1316",
- card->components);
- if (!card->components)
- return -ENOMEM;
-
- ret = snd_soc_add_card_controls(card, rt1316_controls,
- ARRAY_SIZE(rt1316_controls));
- if (ret) {
- dev_err(card->dev, "rt1316 controls addition failed: %d\n", ret);
- return ret;
- }
-
- ret = snd_soc_dapm_new_controls(&card->dapm, rt1316_widgets,
- ARRAY_SIZE(rt1316_widgets));
- if (ret) {
- dev_err(card->dev, "rt1316 widgets addition failed: %d\n", ret);
- return ret;
- }
-
- ret = snd_soc_dapm_add_routes(&card->dapm, rt1316_map, 2);
- if (ret)
- dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret);
-
- return ret;
-}
-
-static int second_spk_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_card *card = rtd->card;
- int ret;
-
- ret = snd_soc_dapm_add_routes(&card->dapm, rt1316_map + 2, 2);
- if (ret)
- dev_err(rtd->dev, "failed to add second SPK map: %d\n", ret);
-
- return ret;
-}
-
-static int all_spk_init(struct snd_soc_pcm_runtime *rtd)
-{
- int ret;
-
- ret = first_spk_init(rtd);
- if (ret)
- return ret;
-
- return second_spk_init(rtd);
-}
-
-int sof_sdw_rt1316_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback)
-{
- /* Count amp number and do init on playback link only. */
- if (!playback)
- return 0;
-
- info->amp_num++;
- if (info->amp_num == 1)
- dai_links->init = first_spk_init;
-
- if (info->amp_num == 2) {
- /*
- * if two 1316s are in one dai link, the init function
- * in this dai link will be first set for the first speaker,
- * and it should be reset to initialize all speakers when
- * the second speaker is found.
- */
- if (dai_links->init)
- dai_links->init = all_spk_init;
- else
- dai_links->init = second_spk_init;
- }
-
- return 0;
-}
diff --git a/sound/soc/intel/boards/sof_sdw_rt_amp.c b/sound/soc/intel/boards/sof_sdw_rt_amp.c
new file mode 100644
index 000000000000..26bf9e0dd3d2
--- /dev/null
+++ b/sound/soc/intel/boards/sof_sdw_rt_amp.c
@@ -0,0 +1,359 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2022 Intel Corporation
+
+/*
+ * sof_sdw_rt_amp - Helpers to handle RT1308/RT1316/RT1318 from generic machine driver
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <sound/control.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <linux/dmi.h>
+#include "sof_sdw_common.h"
+#include "sof_sdw_amp_coeff_tables.h"
+#include "../../codecs/rt1308.h"
+
+#define CODEC_NAME_SIZE 7
+
+/* choose a larger value to resolve compatibility issues */
+#define RT_AMP_MAX_BQ_REG RT1316_MAX_BQ_REG
+
+struct rt_amp_platform_data {
+ const unsigned char *bq_params;
+ const unsigned int bq_params_cnt;
+};
+
+static const struct rt_amp_platform_data dell_0a5d_platform_data = {
+ .bq_params = dell_0a5d_bq_params,
+ .bq_params_cnt = ARRAY_SIZE(dell_0a5d_bq_params),
+};
+
+static const struct rt_amp_platform_data dell_0b00_platform_data = {
+ .bq_params = dell_0b00_bq_params,
+ .bq_params_cnt = ARRAY_SIZE(dell_0b00_bq_params),
+};
+
+static const struct dmi_system_id dmi_platform_data[] = {
+ /* CometLake devices */
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990")
+ },
+ .driver_data = (void *)&dell_0a5d_platform_data,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F")
+ },
+ .driver_data = (void *)&dell_0a5d_platform_data,
+ },
+ /* TigerLake devices */
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5D")
+ },
+ .driver_data = (void *)&dell_0a5d_platform_data,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E")
+ },
+ .driver_data = (void *)&dell_0a5d_platform_data,
+ },
+ /* AlderLake devices */
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00")
+ },
+ .driver_data = (void *)&dell_0b00_platform_data,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01")
+ },
+ .driver_data = (void *)&dell_0b00_platform_data,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF")
+ },
+ .driver_data = (void *)&dell_0b00_platform_data,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE")
+ },
+ .driver_data = (void *)&dell_0b00_platform_data,
+ },
+ {},
+};
+
+static int rt_amp_add_device_props(struct device *sdw_dev)
+{
+ struct property_entry props[3] = {};
+ struct fwnode_handle *fwnode;
+ const struct dmi_system_id *dmi_data;
+ const struct rt_amp_platform_data *pdata;
+ unsigned char params[RT_AMP_MAX_BQ_REG];
+ int ret;
+
+ dmi_data = dmi_first_match(dmi_platform_data);
+ if (!dmi_data)
+ return 0;
+
+ pdata = dmi_data->driver_data;
+ memcpy(&params, pdata->bq_params, sizeof(unsigned char) * pdata->bq_params_cnt);
+
+ props[0] = PROPERTY_ENTRY_U8_ARRAY("realtek,bq-params", params);
+ props[1] = PROPERTY_ENTRY_U32("realtek,bq-params-cnt", pdata->bq_params_cnt);
+
+ fwnode = fwnode_create_software_node(props, NULL);
+ if (IS_ERR(fwnode))
+ return PTR_ERR(fwnode);
+
+ ret = device_add_software_node(sdw_dev, to_software_node(fwnode));
+
+ fwnode_handle_put(fwnode);
+
+ return ret;
+}
+
+static const struct snd_kcontrol_new rt_amp_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+};
+
+static const struct snd_soc_dapm_widget rt_amp_widgets[] = {
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+/*
+ * dapm routes for rt1308/rt1316/rt1318 will be registered dynamically
+ * according to the number of rt1308/rt1316/rt1318 used. The first two
+ * entries will be registered for one codec case, and the last two entries
+ * are also registered if two 1308s/1316s/1318s are used.
+ */
+static const struct snd_soc_dapm_route rt1308_map[] = {
+ { "Speaker", NULL, "rt1308-1 SPOL" },
+ { "Speaker", NULL, "rt1308-1 SPOR" },
+ { "Speaker", NULL, "rt1308-2 SPOL" },
+ { "Speaker", NULL, "rt1308-2 SPOR" },
+};
+
+static const struct snd_soc_dapm_route rt1316_map[] = {
+ { "Speaker", NULL, "rt1316-1 SPOL" },
+ { "Speaker", NULL, "rt1316-1 SPOR" },
+ { "Speaker", NULL, "rt1316-2 SPOL" },
+ { "Speaker", NULL, "rt1316-2 SPOR" },
+};
+
+static const struct snd_soc_dapm_route rt1318_map[] = {
+ { "Speaker", NULL, "rt1318-1 SPOL" },
+ { "Speaker", NULL, "rt1318-1 SPOR" },
+ { "Speaker", NULL, "rt1318-2 SPOL" },
+ { "Speaker", NULL, "rt1318-2 SPOR" },
+};
+
+static const struct snd_soc_dapm_route *get_codec_name_and_route(struct snd_soc_pcm_runtime *rtd,
+ char *codec_name)
+{
+ const char *dai_name;
+
+ dai_name = rtd->dai_link->codecs->dai_name;
+
+ /* get the codec name */
+ snprintf(codec_name, CODEC_NAME_SIZE, "%s", dai_name);
+
+ /* choose the right codec's map */
+ if (strcmp(codec_name, "rt1308") == 0)
+ return rt1308_map;
+ else if (strcmp(codec_name, "rt1316") == 0)
+ return rt1316_map;
+ else
+ return rt1318_map;
+}
+
+static int first_spk_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ const struct snd_soc_dapm_route *rt_amp_map;
+ char codec_name[CODEC_NAME_SIZE];
+ int ret;
+
+ rt_amp_map = get_codec_name_and_route(rtd, codec_name);
+
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s spk:%s",
+ card->components, codec_name);
+ if (!card->components)
+ return -ENOMEM;
+
+ ret = snd_soc_add_card_controls(card, rt_amp_controls,
+ ARRAY_SIZE(rt_amp_controls));
+ if (ret) {
+ dev_err(card->dev, "%s controls addition failed: %d\n", codec_name, ret);
+ return ret;
+ }
+
+ ret = snd_soc_dapm_new_controls(&card->dapm, rt_amp_widgets,
+ ARRAY_SIZE(rt_amp_widgets));
+ if (ret) {
+ dev_err(card->dev, "%s widgets addition failed: %d\n", codec_name, ret);
+ return ret;
+ }
+
+ ret = snd_soc_dapm_add_routes(&card->dapm, rt_amp_map, 2);
+ if (ret)
+ dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret);
+
+ return ret;
+}
+
+static int second_spk_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ const struct snd_soc_dapm_route *rt_amp_map;
+ char codec_name[CODEC_NAME_SIZE];
+ int ret;
+
+ rt_amp_map = get_codec_name_and_route(rtd, codec_name);
+
+ ret = snd_soc_dapm_add_routes(&card->dapm, rt_amp_map + 2, 2);
+ if (ret)
+ dev_err(rtd->dev, "failed to add second SPK map: %d\n", ret);
+
+ return ret;
+}
+
+static int all_spk_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret;
+
+ ret = first_spk_init(rtd);
+ if (ret)
+ return ret;
+
+ return second_spk_init(rtd);
+}
+
+static int rt1308_i2s_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_card *card = rtd->card;
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ int clk_id, clk_freq, pll_out;
+ int err;
+
+ clk_id = RT1308_PLL_S_MCLK;
+ clk_freq = 38400000;
+
+ pll_out = params_rate(params) * 512;
+
+ /* Set rt1308 pll */
+ err = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out);
+ if (err < 0) {
+ dev_err(card->dev, "Failed to set RT1308 PLL: %d\n", err);
+ return err;
+ }
+
+ /* Set rt1308 sysclk */
+ err = snd_soc_dai_set_sysclk(codec_dai, RT1308_FS_SYS_S_PLL, pll_out,
+ SND_SOC_CLOCK_IN);
+ if (err < 0) {
+ dev_err(card->dev, "Failed to set RT1308 SYSCLK: %d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+/* machine stream operations */
+struct snd_soc_ops sof_sdw_rt1308_i2s_ops = {
+ .hw_params = rt1308_i2s_hw_params,
+};
+
+int sof_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
+{
+ struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+
+ if (ctx->amp_dev1) {
+ device_remove_software_node(ctx->amp_dev1);
+ put_device(ctx->amp_dev1);
+ }
+
+ if (ctx->amp_dev2) {
+ device_remove_software_node(ctx->amp_dev2);
+ put_device(ctx->amp_dev2);
+ }
+
+ return 0;
+}
+
+int sof_sdw_rt_amp_init(struct snd_soc_card *card,
+ const struct snd_soc_acpi_link_adr *link,
+ struct snd_soc_dai_link *dai_links,
+ struct sof_sdw_codec_info *info,
+ bool playback)
+{
+ struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct device *sdw_dev1, *sdw_dev2;
+ int ret;
+
+ /* Count amp number and do init on playback link only. */
+ if (!playback)
+ return 0;
+
+ info->amp_num++;
+ if (info->amp_num == 1)
+ dai_links->init = first_spk_init;
+
+ if (info->amp_num == 2) {
+ sdw_dev1 = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[0].name);
+ if (!sdw_dev1)
+ return -EPROBE_DEFER;
+
+ ret = rt_amp_add_device_props(sdw_dev1);
+ if (ret < 0) {
+ put_device(sdw_dev1);
+ return ret;
+ }
+ ctx->amp_dev1 = sdw_dev1;
+
+ sdw_dev2 = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[1].name);
+ if (!sdw_dev2)
+ return -EPROBE_DEFER;
+
+ ret = rt_amp_add_device_props(sdw_dev2);
+ if (ret < 0) {
+ put_device(sdw_dev2);
+ return ret;
+ }
+ ctx->amp_dev2 = sdw_dev2;
+
+ /*
+ * if two amps are in one dai link, the init function
+ * in this dai link will be first set for the first speaker,
+ * and it should be reset to initialize all speakers when
+ * the second speaker is found.
+ */
+ if (dai_links->init)
+ dai_links->init = all_spk_init;
+ else
+ dai_links->init = second_spk_init;
+ }
+
+ return 0;
+}
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 9990d5502d26..60aee56f94bd 100644
--- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c
@@ -430,6 +430,11 @@ static const struct snd_soc_acpi_codecs adl_rt5682_rt5682s_hp = {
.codecs = {"10EC5682", "RTL5682"},
};
+static const struct snd_soc_acpi_codecs adl_rt1015p_amp = {
+ .num_codecs = 1,
+ .codecs = {"RTL1015"}
+};
+
static const struct snd_soc_acpi_codecs adl_rt1019p_amp = {
.num_codecs = 1,
.codecs = {"RTL1019"}
@@ -489,14 +494,21 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
.sof_tplg_filename = "sof-adl-max98360a-nau8825.tplg",
},
{
- .id = "RTL5682",
- .drv_name = "adl_rt1019_rt5682s",
+ .comp_ids = &adl_rt5682_rt5682s_hp,
+ .drv_name = "adl_rt1019_rt5682",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &adl_rt1019p_amp,
.sof_tplg_filename = "sof-adl-rt1019-rt5682.tplg",
},
{
.id = "10508825",
+ .drv_name = "adl_rt1015p_nau8825",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &adl_rt1015p_amp,
+ .sof_tplg_filename = "sof-adl-rt1015-nau8825.tplg",
+ },
+ {
+ .id = "10508825",
.drv_name = "sof_nau8825",
.sof_tplg_filename = "sof-adl-nau8825.tplg",
},
diff --git a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c
index b95c4b2cda94..f5c7e1bbded0 100644
--- a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c
@@ -79,6 +79,11 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = {
.sof_tplg_filename = "sof-jsl-rt5682-mx98360a.tplg",
},
{
+ .comp_ids = &rt5682_rt5682s_hp,
+ .drv_name = "jsl_rt5682",
+ .sof_tplg_filename = "sof-jsl-rt5682.tplg",
+ },
+ {
.id = "10134242",
.drv_name = "jsl_cs4242_mx98360a",
.machine_quirk = snd_soc_acpi_codec_list,
diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
index 36c361fb28a4..b1a66a0f6818 100644
--- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
@@ -39,6 +39,20 @@ static const struct snd_soc_acpi_endpoint single_endpoint = {
.group_id = 0,
};
+static const struct snd_soc_acpi_endpoint spk_l_endpoint = {
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 0,
+ .group_id = 1,
+};
+
+static const struct snd_soc_acpi_endpoint spk_r_endpoint = {
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 1,
+ .group_id = 1,
+};
+
static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = {
{
.adr = 0x000030025D071101ull,
@@ -48,6 +62,45 @@ static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device mx8373_0_adr[] = {
+ {
+ .adr = 0x000023019F837300ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "Left"
+ },
+ {
+ .adr = 0x000027019F837300ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "Right"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt5682_2_adr[] = {
+ {
+ .adr = 0x000221025D568200ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt5682"
+ }
+};
+
+static const struct snd_soc_acpi_link_adr rt5682_link2_max98373_link0[] = {
+ /* Expected order: jack -> amp */
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt5682_2_adr),
+ .adr_d = rt5682_2_adr,
+ },
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(mx8373_0_adr),
+ .adr_d = mx8373_0_adr,
+ },
+ {}
+};
+
static const struct snd_soc_acpi_link_adr mtl_rvp[] = {
{
.mask = BIT(0),
@@ -84,6 +137,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt711.tplg",
},
+ {
+ .link_mask = BIT(0) | BIT(2),
+ .links = rt5682_link2_max98373_link0,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-sdw-rt5682-l2-max98373-l0.tplg",
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_sdw_machines);
diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c
index 9ccf7370157b..3c5229f41bb0 100644
--- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c
@@ -56,6 +56,15 @@ static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt711_sdca_2_adr[] = {
+ {
+ .adr = 0x000230025D071101ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt711"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt1316_1_group1_adr[] = {
{
.adr = 0x000131025D131601ull, /* unique ID is set for some reason */
@@ -65,6 +74,15 @@ static const struct snd_soc_acpi_adr_device rt1316_1_group1_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt1316_2_group1_adr[] = {
+ {
+ .adr = 0x000230025D131601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1316-2"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = {
{
.adr = 0x000330025D131601ull,
@@ -74,6 +92,51 @@ static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt1316_0_group2_adr[] = {
+ {
+ .adr = 0x000030025D131601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "rt1316-1"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1316_1_group2_adr[] = {
+ {
+ .adr = 0x000131025D131601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1316-2"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1318_1_group1_adr[] = {
+ {
+ .adr = 0x000131025D131801ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "rt1318-1"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1318_2_group1_adr[] = {
+ {
+ .adr = 0x000230025D131801ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1318-2"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt714_0_adr[] = {
+ {
+ .adr = 0x000030025D071401ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt714"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt714_2_adr[] = {
{
.adr = 0x000230025D071401ull,
@@ -83,6 +146,15 @@ static const struct snd_soc_acpi_adr_device rt714_2_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt714_3_adr[] = {
+ {
+ .adr = 0x000330025D071401ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt714"
+ }
+};
+
static const struct snd_soc_acpi_link_adr rpl_sdca_3_in_1[] = {
{
.mask = BIT(0),
@@ -107,6 +179,73 @@ static const struct snd_soc_acpi_link_adr rpl_sdca_3_in_1[] = {
{}
};
+static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link2_rt1316_link01_rt714_link3[] = {
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt711_sdca_2_adr),
+ .adr_d = rt711_sdca_2_adr,
+ },
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt1316_0_group2_adr),
+ .adr_d = rt1316_0_group2_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1316_1_group2_adr),
+ .adr_d = rt1316_1_group2_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt714_3_adr),
+ .adr_d = rt714_3_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link0_rt1318_link12_rt714_link3[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
+ .adr_d = rt711_sdca_0_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1318_1_group1_adr),
+ .adr_d = rt1318_1_group1_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt1318_2_group1_adr),
+ .adr_d = rt1318_2_group1_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt714_3_adr),
+ .adr_d = rt714_3_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr rpl_sdw_rt1316_link12_rt714_link0[] = {
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1316_1_group1_adr),
+ .adr_d = rt1316_1_group1_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt1316_2_group1_adr),
+ .adr_d = rt1316_2_group1_adr,
+ },
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt714_0_adr),
+ .adr_d = rt714_0_adr,
+ },
+ {}
+};
+
struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = {
{},
};
@@ -121,6 +260,24 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[] = {
.sof_tplg_filename = "sof-rpl-rt711-l0-rt1316-l13-rt714-l2.tplg",
},
{
+ .link_mask = 0xF, /* 4 active links required */
+ .links = rpl_sdw_rt711_link2_rt1316_link01_rt714_link3,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-rpl-rt711-l2-rt1316-l01-rt714-l3.tplg",
+ },
+ {
+ .link_mask = 0xF, /* 4 active links required */
+ .links = rpl_sdw_rt711_link0_rt1318_link12_rt714_link3,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-rpl-rt711-l0-rt1318-l12-rt714-l3.tplg",
+ },
+ {
+ .link_mask = 0x7, /* rt714 on link0 & two rt1316s on link1 and link2 */
+ .links = rpl_sdw_rt1316_link12_rt714_link0,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-rpl-rt1316-l12-rt714-l0.tplg",
+ },
+ {
.link_mask = 0x1, /* link0 required */
.links = rpl_rvp,
.drv_name = "sof_sdw",
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
index eaad180af42e..5ab0917a2b3d 100644
--- a/sound/soc/intel/skylake/skl-messages.c
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -53,17 +53,15 @@ static int skl_dsp_setup_spib(struct device *dev, unsigned int size,
struct hdac_bus *bus = dev_get_drvdata(dev);
struct hdac_stream *stream = snd_hdac_get_stream(bus,
SNDRV_PCM_STREAM_PLAYBACK, stream_tag);
- struct hdac_ext_stream *estream;
if (!stream)
return -EINVAL;
- estream = stream_to_hdac_ext_stream(stream);
/* enable/disable SPIB for this hdac stream */
- snd_hdac_ext_stream_spbcap_enable(bus, enable, stream->index);
+ snd_hdac_stream_spbcap_enable(bus, enable, stream->index);
/* set the spib value */
- snd_hdac_ext_stream_set_spib(bus, estream, size);
+ snd_hdac_stream_set_spib(bus, stream, size);
return 0;
}
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index 1015716f9336..dc627d18518d 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -190,16 +190,16 @@ int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params)
dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n",
format_val, params->s_freq, params->ch, params->format);
- snd_hdac_ext_link_stream_reset(stream);
+ snd_hdac_ext_stream_reset(stream);
- snd_hdac_ext_link_stream_setup(stream, format_val);
+ snd_hdac_ext_stream_setup(stream, format_val);
stream_tag = hstream->stream_tag;
if (stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) {
list_for_each_entry(link, &bus->hlink_list, list) {
if (link->index == params->link_index)
- snd_hdac_ext_link_set_stream_id(link,
- stream_tag);
+ snd_hdac_ext_bus_link_set_stream_id(link,
+ stream_tag);
}
}
@@ -467,6 +467,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
struct skl_module_cfg *mconfig;
struct hdac_bus *bus = get_bus_ctx(substream);
struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
+ struct hdac_stream *hstream = hdac_stream(stream);
struct snd_soc_dapm_widget *w;
int ret;
@@ -484,11 +485,9 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
* dpib & lpib position to resume before starting the
* DMA
*/
- snd_hdac_ext_stream_drsm_enable(bus, true,
- hdac_stream(stream)->index);
- snd_hdac_ext_stream_set_dpibr(bus, stream,
- stream->lpib);
- snd_hdac_ext_stream_set_lpib(stream, stream->lpib);
+ snd_hdac_stream_drsm_enable(bus, true, hstream->index);
+ snd_hdac_stream_set_dpibr(bus, hstream, hstream->lpib);
+ snd_hdac_stream_set_lpib(hstream, hstream->lpib);
}
fallthrough;
@@ -520,13 +519,13 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
ret = skl_decoupled_trigger(substream, cmd);
if ((cmd == SNDRV_PCM_TRIGGER_SUSPEND) && !w->ignore_suspend) {
/* save the dpib and lpib positions */
- stream->dpib = readl(bus->remap_addr +
+ hstream->dpib = readl(bus->remap_addr +
AZX_REG_VS_SDXDPIB_XBASE +
(AZX_REG_VS_SDXDPIB_XINTERVAL *
- hdac_stream(stream)->index));
+ hstream->index));
+
+ hstream->lpib = snd_hdac_stream_get_pos_lpib(hstream);
- stream->lpib = snd_hdac_stream_get_pos_lpib(
- hdac_stream(stream));
snd_hdac_ext_stream_decouple(bus, stream, false);
}
break;
@@ -558,7 +557,7 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
- link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
+ link = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
if (!link)
return -EINVAL;
@@ -612,13 +611,13 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- snd_hdac_ext_link_stream_start(link_dev);
+ snd_hdac_ext_stream_start(link_dev);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
- snd_hdac_ext_link_stream_clear(link_dev);
+ snd_hdac_ext_stream_clear(link_dev);
if (cmd == SNDRV_PCM_TRIGGER_SUSPEND)
snd_hdac_ext_stream_decouple(bus, stream, false);
break;
@@ -643,13 +642,13 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream,
link_dev->link_prepared = 0;
- link = snd_hdac_ext_bus_get_link(bus, asoc_rtd_to_codec(rtd, 0)->component->name);
+ link = snd_hdac_ext_bus_get_hlink_by_name(bus, asoc_rtd_to_codec(rtd, 0)->component->name);
if (!link)
return -EINVAL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
stream_tag = hdac_stream(link_dev)->stream_tag;
- snd_hdac_ext_link_clear_stream_id(link, stream_tag);
+ snd_hdac_ext_bus_link_clear_stream_id(link, stream_tag);
}
snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK);
diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c
index b91f7a652a2b..b0204ea00f07 100644
--- a/sound/soc/intel/skylake/skl-sst-cldma.c
+++ b/sound/soc/intel/skylake/skl-sst-cldma.c
@@ -11,6 +11,7 @@
#include <linux/io.h>
#include <linux/mm.h>
#include <linux/delay.h>
+#include <sound/hda_register.h>
#include "../common/sst-dsp.h"
#include "../common/sst-dsp-priv.h"
@@ -79,21 +80,25 @@ static void skl_cldma_setup_bdle(struct sst_dsp *ctx,
__le32 **bdlp, int size, int with_ioc)
{
__le32 *bdl = *bdlp;
+ int remaining = ctx->cl_dev.bufsize;
+ int offset = 0;
ctx->cl_dev.frags = 0;
- while (size > 0) {
- phys_addr_t addr = virt_to_phys(dmab_data->area +
- (ctx->cl_dev.frags * ctx->cl_dev.bufsize));
+ while (remaining > 0) {
+ phys_addr_t addr;
+ int chunk;
+ addr = snd_sgbuf_get_addr(dmab_data, offset);
bdl[0] = cpu_to_le32(lower_32_bits(addr));
bdl[1] = cpu_to_le32(upper_32_bits(addr));
+ chunk = snd_sgbuf_get_chunk_size(dmab_data, offset, size);
+ bdl[2] = cpu_to_le32(chunk);
- bdl[2] = cpu_to_le32(ctx->cl_dev.bufsize);
-
- size -= ctx->cl_dev.bufsize;
- bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01);
+ remaining -= chunk;
+ bdl[3] = (remaining > 0) ? 0 : cpu_to_le32(0x01);
bdl += 4;
+ offset += chunk;
ctx->cl_dev.frags++;
}
}
@@ -338,15 +343,15 @@ int skl_cldma_prepare(struct sst_dsp *ctx)
ctx->cl_dev.ops.cl_stop_dma = skl_cldma_stop;
/* Allocate buffer*/
- ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev,
- &ctx->cl_dev.dmab_data, ctx->cl_dev.bufsize);
+ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, ctx->dev, ctx->cl_dev.bufsize,
+ &ctx->cl_dev.dmab_data);
if (ret < 0) {
dev_err(ctx->dev, "Alloc buffer for base fw failed: %x\n", ret);
return ret;
}
+
/* Setup Code loader BDL */
- ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev,
- &ctx->cl_dev.dmab_bdl, PAGE_SIZE);
+ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, ctx->dev, BDL_SIZE, &ctx->cl_dev.dmab_bdl);
if (ret < 0) {
dev_err(ctx->dev, "Alloc buffer for blde failed: %x\n", ret);
ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data);
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index e06eac592da1..b20643b83401 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -582,36 +582,10 @@ static int skl_tplg_unload_pipe_modules(struct skl_dev *skl,
return ret;
}
-static bool skl_tplg_is_multi_fmt(struct skl_dev *skl, struct skl_pipe *pipe)
+static void skl_tplg_set_pipe_config_idx(struct skl_pipe *pipe, int idx)
{
- struct skl_pipe_fmt *cur_fmt;
- struct skl_pipe_fmt *next_fmt;
- int i;
-
- if (pipe->nr_cfgs <= 1)
- return false;
-
- if (pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
- return true;
-
- for (i = 0; i < pipe->nr_cfgs - 1; i++) {
- if (pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) {
- cur_fmt = &pipe->configs[i].out_fmt;
- next_fmt = &pipe->configs[i + 1].out_fmt;
- } else {
- cur_fmt = &pipe->configs[i].in_fmt;
- next_fmt = &pipe->configs[i + 1].in_fmt;
- }
-
- if (!CHECK_HW_PARAMS(cur_fmt->channels, cur_fmt->freq,
- cur_fmt->bps,
- next_fmt->channels,
- next_fmt->freq,
- next_fmt->bps))
- return true;
- }
-
- return false;
+ pipe->cur_config_idx = idx;
+ pipe->memory_pages = pipe->configs[idx].mem_pages;
}
/*
@@ -632,24 +606,14 @@ skl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig)
int i;
if (pipe->nr_cfgs == 0) {
- pipe->cur_config_idx = 0;
- return 0;
- }
-
- if (skl_tplg_is_multi_fmt(skl, pipe)) {
- pipe->cur_config_idx = pipe->pipe_config_idx;
- pipe->memory_pages = pconfig->mem_pages;
- dev_dbg(skl->dev, "found pipe config idx:%d\n",
- pipe->cur_config_idx);
+ skl_tplg_set_pipe_config_idx(pipe, 0);
return 0;
}
if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE || pipe->nr_cfgs == 1) {
dev_dbg(skl->dev, "No conn_type or just 1 pathcfg, taking 0th for %d\n",
pipe->ppl_id);
- pipe->cur_config_idx = 0;
- pipe->memory_pages = pconfig->mem_pages;
-
+ skl_tplg_set_pipe_config_idx(pipe, 0);
return 0;
}
@@ -668,10 +632,8 @@ skl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig)
if (CHECK_HW_PARAMS(params->ch, params->s_freq, params->s_fmt,
fmt->channels, fmt->freq, fmt->bps)) {
- pipe->cur_config_idx = i;
- pipe->memory_pages = pconfig->mem_pages;
+ skl_tplg_set_pipe_config_idx(pipe, i);
dev_dbg(skl->dev, "Using pipe config: %d\n", i);
-
return 0;
}
}
@@ -1391,9 +1353,9 @@ static int skl_tplg_multi_config_set_get(struct snd_kcontrol *kcontrol,
return -EIO;
if (is_set)
- pipe->pipe_config_idx = ucontrol->value.enumerated.item[0];
+ skl_tplg_set_pipe_config_idx(pipe, ucontrol->value.enumerated.item[0]);
else
- ucontrol->value.enumerated.item[0] = pipe->pipe_config_idx;
+ ucontrol->value.enumerated.item[0] = pipe->cur_config_idx;
return 0;
}
@@ -1837,20 +1799,28 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
{
struct nhlt_specific_cfg *cfg;
struct skl_pipe *pipe = mconfig->pipe;
+ struct skl_pipe_params save = *pipe->p_params;
struct skl_pipe_fmt *pipe_fmt;
struct skl_dev *skl = get_skl_ctx(dai->dev);
int link_type = skl_tplg_be_link_type(mconfig->dev_type);
u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type);
+ int ret;
skl_tplg_fill_dma_id(mconfig, params);
if (link_type == NHLT_LINK_HDA)
return 0;
+ *pipe->p_params = *params;
+ ret = skl_tplg_get_pipe_config(skl, mconfig);
+ if (ret)
+ goto err;
+
+ dev_dbg(skl->dev, "%s using pipe config: %d\n", __func__, pipe->cur_config_idx);
if (pipe->direction == SNDRV_PCM_STREAM_PLAYBACK)
- pipe_fmt = &pipe->configs[pipe->pipe_config_idx].out_fmt;
+ pipe_fmt = &pipe->configs[pipe->cur_config_idx].out_fmt;
else
- pipe_fmt = &pipe->configs[pipe->pipe_config_idx].in_fmt;
+ pipe_fmt = &pipe->configs[pipe->cur_config_idx].in_fmt;
/* update the blob based on virtual bus_id*/
cfg = intel_nhlt_get_endpoint_blob(dai->dev, skl->nhlt,
@@ -1865,10 +1835,15 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
dev_err(dai->dev, "Blob NULL for id:%d type:%d dirn:%d ch:%d, freq:%d, fmt:%d\n",
mconfig->vbus_id, link_type, params->stream,
params->ch, params->s_freq, params->s_fmt);
- return -EINVAL;
+ ret = -EINVAL;
+ goto err;
}
return 0;
+
+err:
+ *pipe->p_params = save;
+ return ret;
}
static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai,
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
index 017ac0ef324d..6db0fd7bad49 100644
--- a/sound/soc/intel/skylake/skl-topology.h
+++ b/sound/soc/intel/skylake/skl-topology.h
@@ -324,7 +324,6 @@ struct skl_pipe {
struct skl_path_config configs[SKL_MAX_PATH_CONFIGS];
struct list_head w_list;
bool passthru;
- u32 pipe_config_idx;
};
enum skl_module_state {
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index 3312b57e3c0c..998bd0232cf1 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -387,15 +387,6 @@ static int skl_resume(struct device *dev)
snd_hdac_bus_init_cmd_io(bus);
} else {
ret = _skl_resume(bus);
-
- /* turn off the links which are off before suspend */
- list_for_each_entry(hlink, &bus->hlink_list, list) {
- if (!hlink->ref_count)
- snd_hdac_ext_bus_link_power_down(hlink);
- }
-
- if (!bus->cmd_dma_state)
- snd_hdac_bus_stop_cmd_io(bus);
}
return ret;
@@ -445,7 +436,7 @@ static int skl_free(struct hdac_bus *bus)
free_irq(bus->irq, (void *)bus);
snd_hdac_bus_free_stream_pages(bus);
snd_hdac_ext_stream_free_all(bus);
- snd_hdac_link_free_all(bus);
+ snd_hdac_ext_link_free_all(bus);
if (bus->remap_addr)
iounmap(bus->remap_addr);
@@ -1116,7 +1107,10 @@ static void skl_shutdown(struct pci_dev *pci)
if (!skl->init_done)
return;
- snd_hdac_stop_streams_and_chip(bus);
+ snd_hdac_stop_streams(bus);
+ snd_hdac_ext_bus_link_power_down_all(bus);
+ skl_dsp_sleep(skl->dsp);
+
list_for_each_entry(s, &bus->stream_list, list) {
stream = stream_to_hdac_ext_stream(s);
snd_hdac_ext_stream_decouple(bus, stream, false);