Commit a587601b authored by Takashi Iwai's avatar Takashi Iwai

Merge tag 'asoc-v6.2-2' of...

Merge tag 'asoc-v6.2-2' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-next

ASoC: Updates for v6.2

A few more updates for v6.2 which can hopefully go into a later pull
request, the bulk of these are fixes, minor cleanups or new board quirks
- the one big bit that isn't is support for getting diagnostic data out
of the Intel AVS firmwares.
parents 4bf5bf54 e85b1f5a
...@@ -38,6 +38,7 @@ properties: ...@@ -38,6 +38,7 @@ properties:
- fsl,imx8mq-sai - fsl,imx8mq-sai
- fsl,imx8qm-sai - fsl,imx8qm-sai
- fsl,imx8ulp-sai - fsl,imx8ulp-sai
- fsl,imx93-sai
- fsl,vf610-sai - fsl,vf610-sai
reg: reg:
......
...@@ -75,6 +75,8 @@ struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus, ...@@ -75,6 +75,8 @@ struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus,
struct snd_pcm_substream *substream, struct snd_pcm_substream *substream,
int type); int type);
void snd_hdac_ext_stream_release(struct hdac_ext_stream *hext_stream, int type); void snd_hdac_ext_stream_release(struct hdac_ext_stream *hext_stream, int type);
struct hdac_ext_stream *snd_hdac_ext_cstream_assign(struct hdac_bus *bus,
struct snd_compr_stream *cstream);
void snd_hdac_ext_stream_decouple_locked(struct hdac_bus *bus, void snd_hdac_ext_stream_decouple_locked(struct hdac_bus *bus,
struct hdac_ext_stream *hext_stream, bool decouple); struct hdac_ext_stream *hext_stream, bool decouple);
void snd_hdac_ext_stream_decouple(struct hdac_bus *bus, void snd_hdac_ext_stream_decouple(struct hdac_bus *bus,
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <sound/pcm.h> #include <sound/pcm.h>
#include <sound/hda_register.h> #include <sound/hda_register.h>
#include <sound/hdaudio_ext.h> #include <sound/hdaudio_ext.h>
#include <sound/compress_driver.h>
/** /**
* snd_hdac_ext_stream_init - initialize each stream (aka device) * snd_hdac_ext_stream_init - initialize each stream (aka device)
...@@ -367,3 +368,43 @@ void snd_hdac_ext_stream_release(struct hdac_ext_stream *hext_stream, int type) ...@@ -367,3 +368,43 @@ void snd_hdac_ext_stream_release(struct hdac_ext_stream *hext_stream, int type)
} }
EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_release); EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_release);
/**
* snd_hdac_ext_cstream_assign - assign a host stream for compress
* @bus: HD-audio core bus
* @cstream: Compress stream to assign
*
* Assign an unused host stream for the given compress stream.
* If no stream is free, NULL is returned. Stream is decoupled
* before assignment.
*/
struct hdac_ext_stream *snd_hdac_ext_cstream_assign(struct hdac_bus *bus,
struct snd_compr_stream *cstream)
{
struct hdac_ext_stream *res = NULL;
struct hdac_stream *hstream;
spin_lock_irq(&bus->reg_lock);
list_for_each_entry(hstream, &bus->stream_list, list) {
struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
if (hstream->direction != cstream->direction)
continue;
if (!hstream->opened) {
res = hext_stream;
break;
}
}
if (res) {
snd_hdac_ext_stream_decouple_locked(bus, res, true);
res->hstream.opened = 1;
res->hstream.running = 0;
res->hstream.cstream = cstream;
}
spin_unlock_irq(&bus->reg_lock);
return res;
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_cstream_assign);
...@@ -578,8 +578,8 @@ int snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status, ...@@ -578,8 +578,8 @@ int snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status,
sd_status = snd_hdac_stream_readb(azx_dev, SD_STS); sd_status = snd_hdac_stream_readb(azx_dev, SD_STS);
snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK);
handled |= 1 << azx_dev->index; handled |= 1 << azx_dev->index;
if (!azx_dev->substream || !azx_dev->running || if ((!azx_dev->substream && !azx_dev->cstream) ||
!(sd_status & SD_INT_COMPLETE)) !azx_dev->running || !(sd_status & SD_INT_COMPLETE))
continue; continue;
if (ack) if (ack)
ack(bus, azx_dev); ack(bus, azx_dev);
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/clocksource.h> #include <linux/clocksource.h>
#include <sound/compress_driver.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/pcm.h> #include <sound/pcm.h>
#include <sound/hdaudio.h> #include <sound/hdaudio.h>
...@@ -487,11 +488,20 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev) ...@@ -487,11 +488,20 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev)
{ {
struct hdac_bus *bus = azx_dev->bus; struct hdac_bus *bus = azx_dev->bus;
struct snd_pcm_substream *substream = azx_dev->substream; struct snd_pcm_substream *substream = azx_dev->substream;
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_compr_stream *cstream = azx_dev->cstream;
struct snd_pcm_runtime *runtime = NULL;
struct snd_dma_buffer *dmab;
__le32 *bdl; __le32 *bdl;
int i, ofs, periods, period_bytes; int i, ofs, periods, period_bytes;
int pos_adj, pos_align; int pos_adj, pos_align;
if (substream) {
runtime = substream->runtime;
dmab = snd_pcm_get_dma_buf(substream);
} else if (cstream) {
dmab = snd_pcm_get_dma_buf(cstream);
}
/* reset BDL address */ /* reset BDL address */
snd_hdac_stream_writel(azx_dev, SD_BDLPL, 0); snd_hdac_stream_writel(azx_dev, SD_BDLPL, 0);
snd_hdac_stream_writel(azx_dev, SD_BDLPU, 0); snd_hdac_stream_writel(azx_dev, SD_BDLPU, 0);
...@@ -505,7 +515,7 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev) ...@@ -505,7 +515,7 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev)
azx_dev->frags = 0; azx_dev->frags = 0;
pos_adj = bus->bdl_pos_adj; pos_adj = bus->bdl_pos_adj;
if (!azx_dev->no_period_wakeup && pos_adj > 0) { if (runtime && !azx_dev->no_period_wakeup && pos_adj > 0) {
pos_align = pos_adj; pos_align = pos_adj;
pos_adj = DIV_ROUND_UP(pos_adj * runtime->rate, 48000); pos_adj = DIV_ROUND_UP(pos_adj * runtime->rate, 48000);
if (!pos_adj) if (!pos_adj)
...@@ -518,8 +528,7 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev) ...@@ -518,8 +528,7 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev)
pos_adj); pos_adj);
pos_adj = 0; pos_adj = 0;
} else { } else {
ofs = setup_bdle(bus, snd_pcm_get_dma_buf(substream), ofs = setup_bdle(bus, dmab, azx_dev,
azx_dev,
&bdl, ofs, pos_adj, true); &bdl, ofs, pos_adj, true);
if (ofs < 0) if (ofs < 0)
goto error; goto error;
...@@ -529,13 +538,11 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev) ...@@ -529,13 +538,11 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev)
for (i = 0; i < periods; i++) { for (i = 0; i < periods; i++) {
if (i == periods - 1 && pos_adj) if (i == periods - 1 && pos_adj)
ofs = setup_bdle(bus, snd_pcm_get_dma_buf(substream), ofs = setup_bdle(bus, dmab, azx_dev,
azx_dev, &bdl, ofs, &bdl, ofs, period_bytes - pos_adj, 0);
period_bytes - pos_adj, 0);
else else
ofs = setup_bdle(bus, snd_pcm_get_dma_buf(substream), ofs = setup_bdle(bus, dmab, azx_dev,
azx_dev, &bdl, ofs, &bdl, ofs, period_bytes,
period_bytes,
!azx_dev->no_period_wakeup); !azx_dev->no_period_wakeup);
if (ofs < 0) if (ofs < 0)
goto error; goto error;
...@@ -560,26 +567,32 @@ EXPORT_SYMBOL_GPL(snd_hdac_stream_setup_periods); ...@@ -560,26 +567,32 @@ EXPORT_SYMBOL_GPL(snd_hdac_stream_setup_periods);
int snd_hdac_stream_set_params(struct hdac_stream *azx_dev, int snd_hdac_stream_set_params(struct hdac_stream *azx_dev,
unsigned int format_val) unsigned int format_val)
{ {
unsigned int bufsize, period_bytes;
struct snd_pcm_substream *substream = azx_dev->substream; struct snd_pcm_substream *substream = azx_dev->substream;
struct snd_pcm_runtime *runtime; struct snd_compr_stream *cstream = azx_dev->cstream;
unsigned int bufsize, period_bytes;
unsigned int no_period_wakeup;
int err; int err;
if (!substream) if (substream) {
return -EINVAL;
runtime = substream->runtime;
bufsize = snd_pcm_lib_buffer_bytes(substream); bufsize = snd_pcm_lib_buffer_bytes(substream);
period_bytes = snd_pcm_lib_period_bytes(substream); period_bytes = snd_pcm_lib_period_bytes(substream);
no_period_wakeup = substream->runtime->no_period_wakeup;
} else if (cstream) {
bufsize = cstream->runtime->buffer_size;
period_bytes = cstream->runtime->fragment_size;
no_period_wakeup = 0;
} else {
return -EINVAL;
}
if (bufsize != azx_dev->bufsize || if (bufsize != azx_dev->bufsize ||
period_bytes != azx_dev->period_bytes || period_bytes != azx_dev->period_bytes ||
format_val != azx_dev->format_val || format_val != azx_dev->format_val ||
runtime->no_period_wakeup != azx_dev->no_period_wakeup) { no_period_wakeup != azx_dev->no_period_wakeup) {
azx_dev->bufsize = bufsize; azx_dev->bufsize = bufsize;
azx_dev->period_bytes = period_bytes; azx_dev->period_bytes = period_bytes;
azx_dev->format_val = format_val; azx_dev->format_val = format_val;
azx_dev->no_period_wakeup = runtime->no_period_wakeup; azx_dev->no_period_wakeup = no_period_wakeup;
err = snd_hdac_stream_setup_periods(azx_dev); err = snd_hdac_stream_setup_periods(azx_dev);
if (err < 0) if (err < 0)
return err; return err;
......
...@@ -130,12 +130,6 @@ static inline void wcd_enable_clsh_block(struct wcd_clsh_ctrl *ctrl, ...@@ -130,12 +130,6 @@ static inline void wcd_enable_clsh_block(struct wcd_clsh_ctrl *ctrl,
ctrl->clsh_users = 0; ctrl->clsh_users = 0;
} }
static inline bool wcd_clsh_enable_status(struct snd_soc_component *comp)
{
return snd_soc_component_read(comp, WCD9XXX_A_CDC_CLSH_CRC) &
WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK;
}
static inline void wcd_clsh_set_buck_mode(struct snd_soc_component *comp, static inline void wcd_clsh_set_buck_mode(struct snd_soc_component *comp,
int mode) int mode)
{ {
......
...@@ -75,8 +75,7 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf, ...@@ -75,8 +75,7 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf,
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
ret = scnprintf(buf, PAGE_SIZE, "PDCR: %08x\nPTCR: %08x\n", ret = sysfs_emit(buf, "PDCR: %08x\nPTCR: %08x\n", pdcr, ptcr);
pdcr, ptcr);
if (ptcr & IMX_AUDMUX_V2_PTCR_TFSDIR) if (ptcr & IMX_AUDMUX_V2_PTCR_TFSDIR)
ret += scnprintf(buf + ret, PAGE_SIZE - ret, ret += scnprintf(buf + ret, PAGE_SIZE - ret,
......
...@@ -485,8 +485,10 @@ static int __graph_for_each_link(struct asoc_simple_priv *priv, ...@@ -485,8 +485,10 @@ static int __graph_for_each_link(struct asoc_simple_priv *priv,
of_node_put(codec_ep); of_node_put(codec_ep);
of_node_put(codec_port); of_node_put(codec_port);
if (ret < 0) if (ret < 0) {
of_node_put(cpu_ep);
return ret; return ret;
}
codec_port_old = codec_port; codec_port_old = codec_port;
} }
......
...@@ -217,6 +217,7 @@ config SND_SOC_INTEL_AVS ...@@ -217,6 +217,7 @@ config SND_SOC_INTEL_AVS
select SND_SOC_ACPI if ACPI select SND_SOC_ACPI if ACPI
select SND_SOC_TOPOLOGY select SND_SOC_TOPOLOGY
select SND_SOC_HDA select SND_SOC_HDA
select SND_SOC_COMPRESS if DEBUG_FS
select SND_HDA_EXT_CORE select SND_HDA_EXT_CORE
select SND_HDA_DSP_LOADER select SND_HDA_DSP_LOADER
select SND_INTEL_DSP_CONFIG select SND_INTEL_DSP_CONFIG
......
...@@ -9,6 +9,10 @@ snd-soc-avs-objs += trace.o ...@@ -9,6 +9,10 @@ snd-soc-avs-objs += trace.o
# tell define_trace.h where to find the trace header # tell define_trace.h where to find the trace header
CFLAGS_trace.o := -I$(src) 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 obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
# Machine support # Machine support
......
...@@ -13,7 +13,8 @@ ...@@ -13,7 +13,8 @@
#include "path.h" #include "path.h"
#include "topology.h" #include "topology.h"
static int apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period, 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) u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
{ {
struct apl_log_state_info *info; struct apl_log_state_info *info;
...@@ -50,7 +51,6 @@ static int apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 ...@@ -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) static int apl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg)
{ {
struct apl_log_buffer_layout layout; struct apl_log_buffer_layout layout;
unsigned long flags;
void __iomem *addr, *buf; void __iomem *addr, *buf;
addr = avs_log_buffer_addr(adev, msg->log.core); 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 ...@@ -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)); memcpy_fromio(&layout, addr, sizeof(layout));
spin_lock_irqsave(&adev->dbg.trace_lock, flags); if (!avs_logging_fw(adev))
if (!kfifo_initialized(&adev->dbg.trace_fifo))
/* consume the logs regardless of consumer presence */ /* consume the logs regardless of consumer presence */
goto update_read_ptr; goto update_read_ptr;
buf = apl_log_payload_addr(addr); buf = apl_log_payload_addr(addr);
if (layout.read_ptr > layout.write_ptr) { if (layout.read_ptr > layout.write_ptr) {
__kfifo_fromio_locked(&adev->dbg.trace_fifo, buf + layout.read_ptr, avs_dump_fw_log(adev, buf + layout.read_ptr,
apl_log_payload_size(adev) - layout.read_ptr, apl_log_payload_size(adev) - layout.read_ptr);
&adev->dbg.fifo_lock);
layout.read_ptr = 0; layout.read_ptr = 0;
} }
__kfifo_fromio_locked(&adev->dbg.trace_fifo, buf + layout.read_ptr, avs_dump_fw_log_wakeup(adev, buf + layout.read_ptr, layout.write_ptr - layout.read_ptr);
layout.write_ptr - layout.read_ptr, &adev->dbg.fifo_lock);
wake_up(&adev->dbg.trace_waitq);
update_read_ptr: update_read_ptr:
spin_unlock_irqrestore(&adev->dbg.trace_lock, flags);
writel(layout.write_ptr, addr); writel(layout.write_ptr, addr);
return 0; return 0;
} }
...@@ -140,7 +134,7 @@ static int apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg) ...@@ -140,7 +134,7 @@ static int apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg)
* gathered before dumping stack * gathered before dumping stack
*/ */
lbs_msg.log.core = msg->ext.coredump.core_id; lbs_msg.log.core = msg->ext.coredump.core_id;
avs_dsp_op(adev, log_buffer_status, &lbs_msg); avs_log_buffer_status_locked(adev, &lbs_msg);
} }
pos = dump + AVS_FW_REGS_SIZE; pos = dump + AVS_FW_REGS_SIZE;
...@@ -243,10 +237,10 @@ const struct avs_dsp_ops apl_dsp_ops = { ...@@ -243,10 +237,10 @@ const struct avs_dsp_ops apl_dsp_ops = {
.load_basefw = avs_hda_load_basefw, .load_basefw = avs_hda_load_basefw,
.load_lib = avs_hda_load_library, .load_lib = avs_hda_load_library,
.transfer_mods = avs_hda_transfer_modules, .transfer_mods = avs_hda_transfer_modules,
.enable_logs = apl_enable_logs,
.log_buffer_offset = skl_log_buffer_offset, .log_buffer_offset = skl_log_buffer_offset,
.log_buffer_status = apl_log_buffer_status, .log_buffer_status = apl_log_buffer_status,
.coredump = apl_coredump, .coredump = apl_coredump,
.d0ix_toggle = apl_d0ix_toggle, .d0ix_toggle = apl_d0ix_toggle,
.set_d0ix = apl_set_d0ix, .set_d0ix = apl_set_d0ix,
AVS_SET_ENABLE_LOGS_OP(apl)
}; };
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#ifndef __SOUND_SOC_INTEL_AVS_H #ifndef __SOUND_SOC_INTEL_AVS_H
#define __SOUND_SOC_INTEL_AVS_H #define __SOUND_SOC_INTEL_AVS_H
#include <linux/debugfs.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/kfifo.h> #include <linux/kfifo.h>
...@@ -93,16 +94,6 @@ struct avs_fw_entry { ...@@ -93,16 +94,6 @@ struct avs_fw_entry {
struct list_head node; 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 * struct avs_dev - Intel HD-Audio driver data
* *
...@@ -146,7 +137,18 @@ struct avs_dev { ...@@ -146,7 +137,18 @@ struct avs_dev {
spinlock_t path_list_lock; spinlock_t path_list_lock;
struct mutex path_mutex; 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 */ /* from hda_bus to avs_dev */
...@@ -321,6 +323,9 @@ struct avs_soc_component { ...@@ -321,6 +323,9 @@ struct avs_soc_component {
extern const struct snd_soc_dai_ops avs_dai_fe_ops; 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_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, int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask,
unsigned long *tdms); unsigned long *tdms);
...@@ -331,9 +336,6 @@ void avs_unregister_all_boards(struct avs_dev *adev); ...@@ -331,9 +336,6 @@ void avs_unregister_all_boards(struct avs_dev *adev);
/* Firmware tracing helpers */ /* 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) \ #define avs_log_buffer_size(adev) \
((adev)->fw_cfg.trace_log_bytes / (adev)->hw_cfg.dsp_cores) ((adev)->fw_cfg.trace_log_bytes / (adev)->hw_cfg.dsp_cores)
...@@ -344,6 +346,18 @@ unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src, ...@@ -344,6 +346,18 @@ unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src,
(avs_sram_addr(adev, AVS_DEBUG_WINDOW) + __offset); \ (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 { struct apl_log_buffer_layout {
u32 read_ptr; u32 read_ptr;
u32 write_ptr; u32 write_ptr;
...@@ -356,4 +370,42 @@ struct apl_log_buffer_layout { ...@@ -356,4 +370,42 @@ struct apl_log_buffer_layout {
#define apl_log_payload_addr(addr) \ #define apl_log_payload_addr(addr) \
(addr + sizeof(struct apl_log_buffer_layout)) (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 */ #endif /* __SOUND_SOC_INTEL_AVS_H */
...@@ -291,6 +291,33 @@ static void board_pdev_unregister(void *data) ...@@ -291,6 +291,33 @@ static void board_pdev_unregister(void *data)
platform_device_unregister(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) static int avs_register_dmic_board(struct avs_dev *adev)
{ {
struct platform_device *codec, *board; struct platform_device *codec, *board;
...@@ -500,6 +527,12 @@ int avs_register_all_boards(struct avs_dev *adev) ...@@ -500,6 +527,12 @@ int avs_register_all_boards(struct avs_dev *adev)
{ {
int ret; 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); ret = avs_register_dmic_board(adev);
if (ret < 0) if (ret < 0)
dev_warn(adev->dev, "enumerate DMIC endpoints failed: %d\n", dev_warn(adev->dev, "enumerate DMIC endpoints failed: %d\n",
......
...@@ -77,6 +77,14 @@ config SND_SOC_INTEL_AVS_MACH_NAU8825 ...@@ -77,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. Say Y or m if you have such a device. This is a recommended option.
If unsure select "N". 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 config SND_SOC_INTEL_AVS_MACH_RT274
tristate "rt274 in I2S mode" tristate "rt274 in I2S mode"
depends on I2C depends on I2C
......
...@@ -8,6 +8,7 @@ snd-soc-avs-max98927-objs := max98927.o ...@@ -8,6 +8,7 @@ snd-soc-avs-max98927-objs := max98927.o
snd-soc-avs-max98357a-objs := max98357a.o snd-soc-avs-max98357a-objs := max98357a.o
snd-soc-avs-max98373-objs := max98373.o snd-soc-avs-max98373-objs := max98373.o
snd-soc-avs-nau8825-objs := nau8825.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-rt274-objs := rt274.o
snd-soc-avs-rt286-objs := rt286.o snd-soc-avs-rt286-objs := rt286.o
snd-soc-avs-rt298-objs := rt298.o snd-soc-avs-rt298-objs := rt298.o
...@@ -22,6 +23,7 @@ obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98927) += snd-soc-avs-max98927.o ...@@ -22,6 +23,7 @@ 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_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_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_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_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_RT286) += snd-soc-avs-rt286.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT298) += snd-soc-avs-rt298.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT298) += snd-soc-avs-rt298.o
......
// 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");
...@@ -214,6 +214,7 @@ static void avs_hda_probe_work(struct work_struct *work) ...@@ -214,6 +214,7 @@ static void avs_hda_probe_work(struct work_struct *work)
adev->nhlt = intel_nhlt_init(adev->dev); adev->nhlt = intel_nhlt_init(adev->dev);
if (!adev->nhlt) if (!adev->nhlt)
dev_info(bus->dev, "platform has no NHLT\n"); dev_info(bus->dev, "platform has no NHLT\n");
avs_debugfs_init(adev);
avs_register_all_boards(adev); avs_register_all_boards(adev);
...@@ -491,6 +492,7 @@ static void avs_pci_remove(struct pci_dev *pci) ...@@ -491,6 +492,7 @@ static void avs_pci_remove(struct pci_dev *pci)
avs_unregister_all_boards(adev); avs_unregister_all_boards(adev);
avs_debugfs_exit(adev);
if (adev->nhlt) if (adev->nhlt)
intel_nhlt_free(adev->nhlt); intel_nhlt_free(adev->nhlt);
......
// 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);
}
...@@ -266,7 +266,7 @@ static void avs_dsp_process_notification(struct avs_dev *adev, u64 header) ...@@ -266,7 +266,7 @@ static void avs_dsp_process_notification(struct avs_dev *adev, u64 header)
break; break;
case AVS_NOTIFY_LOG_BUFFER_STATUS: case AVS_NOTIFY_LOG_BUFFER_STATUS:
avs_dsp_op(adev, log_buffer_status, &msg); avs_log_buffer_status_locked(adev, &msg);
break; break;
case AVS_NOTIFY_EXCEPTION_CAUGHT: case AVS_NOTIFY_EXCEPTION_CAUGHT:
......
...@@ -685,6 +685,24 @@ int avs_ipc_get_modules_info(struct avs_dev *adev, struct avs_mods_info **info) ...@@ -685,6 +685,24 @@ int avs_ipc_get_modules_info(struct avs_dev *adev, struct avs_mods_info **info)
return 0; 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)
{
struct avs_copier_sink_format cpr_fmt;
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, 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) 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, return avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
...@@ -705,19 +723,81 @@ int avs_ipc_set_system_time(struct avs_dev *adev) ...@@ -705,19 +723,81 @@ int avs_ipc_set_system_time(struct avs_dev *adev)
AVS_BASEFW_SYSTEM_TIME, (u8 *)&sys_time, sizeof(sys_time)); AVS_BASEFW_SYSTEM_TIME, (u8 *)&sys_time, sizeof(sys_time));
} }
int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id, int avs_ipc_probe_get_dma(struct avs_dev *adev, struct avs_probe_dma **dmas, size_t *num_dmas)
u8 instance_id, u32 sink_id,
const struct avs_audio_format *src_fmt,
const struct avs_audio_format *sink_fmt)
{ {
struct avs_copier_sink_format cpr_fmt; size_t payload_size;
u32 module_id;
u8 *payload;
int ret;
cpr_fmt.sink_id = sink_id; module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
/* 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, instance_id, ret = avs_ipc_get_large_config(adev, module_id, AVS_PROBE_INST_ID, AVS_PROBE_INJECTION_DMA,
AVS_COPIER_SET_SINK_FORMAT, NULL, 0, &payload, &payload_size);
(u8 *)&cpr_fmt, sizeof(cpr_fmt)); if (ret)
return ret;
*dmas = (struct avs_probe_dma *)payload;
*num_dmas = payload_size / sizeof(**dmas);
return 0;
}
int avs_ipc_probe_attach_dma(struct avs_dev *adev, struct avs_probe_dma *dmas, size_t num_dmas)
{
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,
(u8 *)dmas, array_size(sizeof(*dmas), num_dmas));
}
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
...@@ -802,4 +802,57 @@ int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id, ...@@ -802,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 *src_fmt,
const struct avs_audio_format *sink_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 */ #endif /* __SOUND_SOC_INTEL_AVS_MSGS_H */
...@@ -1126,7 +1126,7 @@ static const struct snd_soc_component_driver avs_component_driver = { ...@@ -1126,7 +1126,7 @@ static const struct snd_soc_component_driver avs_component_driver = {
.topology_name_prefix = "intel/avs", .topology_name_prefix = "intel/avs",
}; };
static int avs_soc_component_register(struct device *dev, const char *name, int avs_soc_component_register(struct device *dev, const char *name,
const struct snd_soc_component_driver *drv, const struct snd_soc_component_driver *drv,
struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais) struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais)
{ {
......
// 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));
}
...@@ -59,7 +59,8 @@ ...@@ -59,7 +59,8 @@
#define AVS_FW_REG_STATUS(adev) (AVS_FW_REG_BASE(adev) + 0x0) #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_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 #define AVS_FW_REGS_WINDOW 0
/* DSP -> HOST communication window */ /* DSP -> HOST communication window */
#define AVS_UPLINK_WINDOW AVS_FW_REGS_WINDOW #define AVS_UPLINK_WINDOW AVS_FW_REGS_WINDOW
......
...@@ -12,7 +12,8 @@ ...@@ -12,7 +12,8 @@
#include "avs.h" #include "avs.h"
#include "messages.h" #include "messages.h"
static int skl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period, 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) u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
{ {
struct skl_log_state_info *info; struct skl_log_state_info *info;
...@@ -55,15 +56,11 @@ int skl_log_buffer_offset(struct avs_dev *adev, u32 core) ...@@ -55,15 +56,11 @@ int skl_log_buffer_offset(struct avs_dev *adev, u32 core)
static int static int
skl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg) skl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg)
{ {
unsigned long flags;
void __iomem *buf; void __iomem *buf;
u16 size, write, offset; u16 size, write, offset;
spin_lock_irqsave(&adev->dbg.trace_lock, flags); if (!avs_logging_fw(adev))
if (!kfifo_initialized(&adev->dbg.trace_fifo)) {
spin_unlock_irqrestore(&adev->dbg.trace_lock, flags);
return 0; return 0;
}
size = avs_log_buffer_size(adev) / 2; 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)); 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) ...@@ -72,9 +69,7 @@ skl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg)
/* Address is guaranteed to exist in SRAM2. */ /* Address is guaranteed to exist in SRAM2. */
buf = avs_log_buffer_addr(adev, msg->log.core) + offset; buf = avs_log_buffer_addr(adev, msg->log.core) + offset;
__kfifo_fromio_locked(&adev->dbg.trace_fifo, buf, size, &adev->dbg.fifo_lock); avs_dump_fw_log_wakeup(adev, buf, size);
wake_up(&adev->dbg.trace_waitq);
spin_unlock_irqrestore(&adev->dbg.trace_lock, flags);
return 0; return 0;
} }
...@@ -116,10 +111,10 @@ const struct avs_dsp_ops skl_dsp_ops = { ...@@ -116,10 +111,10 @@ const struct avs_dsp_ops skl_dsp_ops = {
.load_basefw = avs_cldma_load_basefw, .load_basefw = avs_cldma_load_basefw,
.load_lib = avs_cldma_load_library, .load_lib = avs_cldma_load_library,
.transfer_mods = avs_cldma_transfer_modules, .transfer_mods = avs_cldma_transfer_modules,
.enable_logs = skl_enable_logs,
.log_buffer_offset = skl_log_buffer_offset, .log_buffer_offset = skl_log_buffer_offset,
.log_buffer_status = skl_log_buffer_status, .log_buffer_status = skl_log_buffer_status,
.coredump = skl_coredump, .coredump = skl_coredump,
.d0ix_toggle = skl_d0ix_toggle, .d0ix_toggle = skl_d0ix_toggle,
.set_d0ix = skl_set_d0ix, .set_d0ix = skl_set_d0ix,
AVS_SET_ENABLE_LOGS_OP(skl)
}; };
...@@ -300,25 +300,3 @@ void avs_release_firmwares(struct avs_dev *adev) ...@@ -300,25 +300,3 @@ void avs_release_firmwares(struct avs_dev *adev)
kfree(entry); 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;
}
...@@ -37,8 +37,7 @@ snd-soc-sof_da7219_max98373-objs := sof_da7219_max98373.o ...@@ -37,8 +37,7 @@ snd-soc-sof_da7219_max98373-objs := sof_da7219_max98373.o
snd-soc-ehl-rt5660-objs := ehl_rt5660.o snd-soc-ehl-rt5660-objs := ehl_rt5660.o
snd-soc-sof-ssp-amp-objs := sof_ssp_amp.o snd-soc-sof-ssp-amp-objs := sof_ssp_amp.o
snd-soc-sof-sdw-objs += sof_sdw.o \ snd-soc-sof-sdw-objs += sof_sdw.o \
sof_sdw_max98373.o sof_sdw_rt1308.o \ sof_sdw_max98373.o sof_sdw_rt_amp.o \
sof_sdw_rt1316.o sof_sdw_rt1318.o \
sof_sdw_rt5682.o sof_sdw_rt700.o \ sof_sdw_rt5682.o sof_sdw_rt700.o \
sof_sdw_rt711.o sof_sdw_rt711_sdca.o \ sof_sdw_rt711.o sof_sdw_rt711_sdca.o \
sof_sdw_rt715.o sof_sdw_rt715_sdca.o \ sof_sdw_rt715.o sof_sdw_rt715_sdca.o \
......
...@@ -783,7 +783,7 @@ static int sof_es8336_remove(struct platform_device *pdev) ...@@ -783,7 +783,7 @@ static int sof_es8336_remove(struct platform_device *pdev)
struct snd_soc_card *card = platform_get_drvdata(pdev); struct snd_soc_card *card = platform_get_drvdata(pdev);
struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card); 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); gpiod_put(priv->gpio_speakers);
device_remove_software_node(priv->codec_dev); device_remove_software_node(priv->codec_dev);
put_device(priv->codec_dev); put_device(priv->codec_dev);
......
...@@ -267,7 +267,8 @@ static int rt1015_hw_params(struct snd_pcm_substream *substream, ...@@ -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_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai_link *dai_link = rtd->dai_link; struct snd_soc_dai_link *dai_link = rtd->dai_link;
struct snd_soc_dai *codec_dai; 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); clk_freq = sof_dai_get_bclk(rtd);
......
...@@ -1104,6 +1104,12 @@ static const struct platform_device_id board_ids[] = { ...@@ -1104,6 +1104,12 @@ static const struct platform_device_id board_ids[] = {
SOF_RT5682_SSP_AMP(1) | SOF_RT5682_SSP_AMP(1) |
SOF_RT5682_NUM_HDMIDEV(4)), 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); MODULE_DEVICE_TABLE(platform, board_ids);
......
...@@ -550,23 +550,23 @@ static struct sof_sdw_codec_info codec_info_list[] = { ...@@ -550,23 +550,23 @@ static struct sof_sdw_codec_info codec_info_list[] = {
.direction = {true, false}, .direction = {true, false},
.dai_name = "rt1308-aif", .dai_name = "rt1308-aif",
.ops = &sof_sdw_rt1308_i2s_ops, .ops = &sof_sdw_rt1308_i2s_ops,
.init = sof_sdw_rt1308_init, .init = sof_sdw_rt_amp_init,
.exit = sof_sdw_rt1308_exit, .exit = sof_sdw_rt_amp_exit,
.codec_type = SOF_SDW_CODEC_TYPE_AMP, .codec_type = SOF_SDW_CODEC_TYPE_AMP,
}, },
{ {
.part_id = 0x1316, .part_id = 0x1316,
.direction = {true, true}, .direction = {true, true},
.dai_name = "rt1316-aif", .dai_name = "rt1316-aif",
.init = sof_sdw_rt1316_init, .init = sof_sdw_rt_amp_init,
.exit = sof_sdw_rt1316_exit, .exit = sof_sdw_rt_amp_exit,
.codec_type = SOF_SDW_CODEC_TYPE_AMP, .codec_type = SOF_SDW_CODEC_TYPE_AMP,
}, },
{ {
.part_id = 0x1318, .part_id = 0x1318,
.direction = {true, true}, .direction = {true, true},
.dai_name = "rt1318-aif", .dai_name = "rt1318-aif",
.init = sof_sdw_rt1318_init, .init = sof_sdw_rt_amp_init,
.codec_type = SOF_SDW_CODEC_TYPE_AMP, .codec_type = SOF_SDW_CODEC_TYPE_AMP,
}, },
{ {
......
...@@ -125,30 +125,18 @@ int sof_sdw_rt700_init(struct snd_soc_card *card, ...@@ -125,30 +125,18 @@ int sof_sdw_rt700_init(struct snd_soc_card *card,
struct sof_sdw_codec_info *info, struct sof_sdw_codec_info *info,
bool playback); bool playback);
/* RT1308 support */ /* RT1308 I2S support */
extern struct snd_soc_ops sof_sdw_rt1308_i2s_ops; 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, const struct snd_soc_acpi_link_adr *link,
struct snd_soc_dai_link *dai_links, struct snd_soc_dai_link *dai_links,
struct sof_sdw_codec_info *info, struct sof_sdw_codec_info *info,
bool playback); bool playback);
int sof_sdw_rt1308_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); int sof_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
/* RT1316 support */ /* 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);
int sof_sdw_rt1316_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
/* RT1318 support */
int sof_sdw_rt1318_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 */ /* RT715 support */
int sof_sdw_rt715_init(struct snd_soc_card *card, int sof_sdw_rt715_init(struct snd_soc_card *card,
......
// 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 <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"
struct rt1316_platform_data {
const unsigned char *bq_params;
const unsigned int bq_params_cnt;
};
static const struct rt1316_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[] = {
/* 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 rt1316_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 rt1316_platform_data *pdata;
unsigned char params[RT1316_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_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_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_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)
{
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 = rt1316_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 = rt1316_add_device_props(sdw_dev2);
if (ret < 0) {
put_device(sdw_dev2);
return ret;
}
ctx->amp_dev2 = sdw_dev2;
/*
* 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;
}
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2022 Intel Corporation
/*
* sof_sdw_rt1318 - Helpers to handle 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 "sof_sdw_common.h"
static const struct snd_soc_dapm_widget rt1318_widgets[] = {
SND_SOC_DAPM_SPK("Speaker", NULL),
};
/*
* dapm routes for rt1318 will be registered dynamically according
* to the number of rt1318 used. The first two entries will be registered
* for one codec case, and the last two entries are also registered
* if two 1318s are used.
*/
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_kcontrol_new rt1318_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:rt1318",
card->components);
if (!card->components)
return -ENOMEM;
ret = snd_soc_add_card_controls(card, rt1318_controls,
ARRAY_SIZE(rt1318_controls));
if (ret) {
dev_err(card->dev, "rt1318 controls addition failed: %d\n", ret);
return ret;
}
ret = snd_soc_dapm_new_controls(&card->dapm, rt1318_widgets,
ARRAY_SIZE(rt1318_widgets));
if (ret) {
dev_err(card->dev, "rt1318 widgets addition failed: %d\n", ret);
return ret;
}
ret = snd_soc_dapm_add_routes(&card->dapm, rt1318_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, rt1318_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_rt1318_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 1318s 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;
}
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2020 Intel Corporation // Copyright (c) 2022 Intel Corporation
/* /*
* sof_sdw_rt1308 - Helpers to handle RT1308 from generic machine driver * sof_sdw_rt_amp - Helpers to handle RT1308/RT1316/RT1318 from generic machine driver
*/ */
#include <linux/device.h> #include <linux/device.h>
...@@ -18,16 +18,26 @@ ...@@ -18,16 +18,26 @@
#include "sof_sdw_amp_coeff_tables.h" #include "sof_sdw_amp_coeff_tables.h"
#include "../../codecs/rt1308.h" #include "../../codecs/rt1308.h"
struct rt1308_platform_data { #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 char *bq_params;
const unsigned int bq_params_cnt; const unsigned int bq_params_cnt;
}; };
static const struct rt1308_platform_data dell_0a5d_platform_data = { static const struct rt_amp_platform_data dell_0a5d_platform_data = {
.bq_params = dell_0a5d_bq_params, .bq_params = dell_0a5d_bq_params,
.bq_params_cnt = ARRAY_SIZE(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[] = { static const struct dmi_system_id dmi_platform_data[] = {
/* CometLake devices */ /* CometLake devices */
{ {
...@@ -59,15 +69,45 @@ static const struct dmi_system_id dmi_platform_data[] = { ...@@ -59,15 +69,45 @@ static const struct dmi_system_id dmi_platform_data[] = {
}, },
.driver_data = (void *)&dell_0a5d_platform_data, .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 rt1308_add_device_props(struct device *sdw_dev) static int rt_amp_add_device_props(struct device *sdw_dev)
{ {
struct property_entry props[3] = {}; struct property_entry props[3] = {};
struct fwnode_handle *fwnode; struct fwnode_handle *fwnode;
const struct dmi_system_id *dmi_data; const struct dmi_system_id *dmi_data;
const struct rt1308_platform_data *pdata; const struct rt_amp_platform_data *pdata;
unsigned char params[RT1308_MAX_BQ_REG]; unsigned char params[RT_AMP_MAX_BQ_REG];
int ret; int ret;
dmi_data = dmi_first_match(dmi_platform_data); dmi_data = dmi_first_match(dmi_platform_data);
...@@ -91,15 +131,19 @@ static int rt1308_add_device_props(struct device *sdw_dev) ...@@ -91,15 +131,19 @@ static int rt1308_add_device_props(struct device *sdw_dev)
return ret; return ret;
} }
static const struct snd_soc_dapm_widget rt1308_widgets[] = { 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), SND_SOC_DAPM_SPK("Speaker", NULL),
}; };
/* /*
* dapm routes for rt1308 will be registered dynamically according * dapm routes for rt1308/rt1316/rt1318 will be registered dynamically
* to the number of rt1308 used. The first two entries will be registered * according to the number of rt1308/rt1316/rt1318 used. The first two
* for one codec case, and the last two entries are also registered * entries will be registered for one codec case, and the last two entries
* if two 1308s are used. * are also registered if two 1308s/1316s/1318s are used.
*/ */
static const struct snd_soc_dapm_route rt1308_map[] = { static const struct snd_soc_dapm_route rt1308_map[] = {
{ "Speaker", NULL, "rt1308-1 SPOL" }, { "Speaker", NULL, "rt1308-1 SPOL" },
...@@ -108,36 +152,69 @@ static const struct snd_soc_dapm_route rt1308_map[] = { ...@@ -108,36 +152,69 @@ static const struct snd_soc_dapm_route rt1308_map[] = {
{ "Speaker", NULL, "rt1308-2 SPOR" }, { "Speaker", NULL, "rt1308-2 SPOR" },
}; };
static const struct snd_kcontrol_new rt1308_controls[] = { static const struct snd_soc_dapm_route rt1316_map[] = {
SOC_DAPM_PIN_SWITCH("Speaker"), { "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) static int first_spk_init(struct snd_soc_pcm_runtime *rtd)
{ {
struct snd_soc_card *card = rtd->card; struct snd_soc_card *card = rtd->card;
const struct snd_soc_dapm_route *rt_amp_map;
char codec_name[CODEC_NAME_SIZE];
int ret; int ret;
rt_amp_map = get_codec_name_and_route(rtd, codec_name);
card->components = devm_kasprintf(card->dev, GFP_KERNEL, card->components = devm_kasprintf(card->dev, GFP_KERNEL,
"%s spk:rt1308", "%s spk:%s",
card->components); card->components, codec_name);
if (!card->components) if (!card->components)
return -ENOMEM; return -ENOMEM;
ret = snd_soc_add_card_controls(card, rt1308_controls, ret = snd_soc_add_card_controls(card, rt_amp_controls,
ARRAY_SIZE(rt1308_controls)); ARRAY_SIZE(rt_amp_controls));
if (ret) { if (ret) {
dev_err(card->dev, "rt1308 controls addition failed: %d\n", ret); dev_err(card->dev, "%s controls addition failed: %d\n", codec_name, ret);
return ret; return ret;
} }
ret = snd_soc_dapm_new_controls(&card->dapm, rt1308_widgets, ret = snd_soc_dapm_new_controls(&card->dapm, rt_amp_widgets,
ARRAY_SIZE(rt1308_widgets)); ARRAY_SIZE(rt_amp_widgets));
if (ret) { if (ret) {
dev_err(card->dev, "rt1308 widgets addition failed: %d\n", ret); dev_err(card->dev, "%s widgets addition failed: %d\n", codec_name, ret);
return ret; return ret;
} }
ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_map, 2); ret = snd_soc_dapm_add_routes(&card->dapm, rt_amp_map, 2);
if (ret) if (ret)
dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret); dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret);
...@@ -147,9 +224,13 @@ static int first_spk_init(struct snd_soc_pcm_runtime *rtd) ...@@ -147,9 +224,13 @@ static int first_spk_init(struct snd_soc_pcm_runtime *rtd)
static int second_spk_init(struct snd_soc_pcm_runtime *rtd) static int second_spk_init(struct snd_soc_pcm_runtime *rtd)
{ {
struct snd_soc_card *card = rtd->card; struct snd_soc_card *card = rtd->card;
const struct snd_soc_dapm_route *rt_amp_map;
char codec_name[CODEC_NAME_SIZE];
int ret; int ret;
ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_map + 2, 2); 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) if (ret)
dev_err(rtd->dev, "failed to add second SPK map: %d\n", ret); dev_err(rtd->dev, "failed to add second SPK map: %d\n", ret);
...@@ -204,7 +285,7 @@ struct snd_soc_ops sof_sdw_rt1308_i2s_ops = { ...@@ -204,7 +285,7 @@ struct snd_soc_ops sof_sdw_rt1308_i2s_ops = {
.hw_params = rt1308_i2s_hw_params, .hw_params = rt1308_i2s_hw_params,
}; };
int sof_sdw_rt1308_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) 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); struct mc_private *ctx = snd_soc_card_get_drvdata(card);
...@@ -221,7 +302,7 @@ int sof_sdw_rt1308_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_ ...@@ -221,7 +302,7 @@ int sof_sdw_rt1308_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_
return 0; return 0;
} }
int sof_sdw_rt1308_init(struct snd_soc_card *card, int sof_sdw_rt_amp_init(struct snd_soc_card *card,
const struct snd_soc_acpi_link_adr *link, const struct snd_soc_acpi_link_adr *link,
struct snd_soc_dai_link *dai_links, struct snd_soc_dai_link *dai_links,
struct sof_sdw_codec_info *info, struct sof_sdw_codec_info *info,
...@@ -244,7 +325,7 @@ int sof_sdw_rt1308_init(struct snd_soc_card *card, ...@@ -244,7 +325,7 @@ int sof_sdw_rt1308_init(struct snd_soc_card *card,
if (!sdw_dev1) if (!sdw_dev1)
return -EPROBE_DEFER; return -EPROBE_DEFER;
ret = rt1308_add_device_props(sdw_dev1); ret = rt_amp_add_device_props(sdw_dev1);
if (ret < 0) { if (ret < 0) {
put_device(sdw_dev1); put_device(sdw_dev1);
return ret; return ret;
...@@ -255,7 +336,7 @@ int sof_sdw_rt1308_init(struct snd_soc_card *card, ...@@ -255,7 +336,7 @@ int sof_sdw_rt1308_init(struct snd_soc_card *card,
if (!sdw_dev2) if (!sdw_dev2)
return -EPROBE_DEFER; return -EPROBE_DEFER;
ret = rt1308_add_device_props(sdw_dev2); ret = rt_amp_add_device_props(sdw_dev2);
if (ret < 0) { if (ret < 0) {
put_device(sdw_dev2); put_device(sdw_dev2);
return ret; return ret;
...@@ -263,7 +344,7 @@ int sof_sdw_rt1308_init(struct snd_soc_card *card, ...@@ -263,7 +344,7 @@ int sof_sdw_rt1308_init(struct snd_soc_card *card,
ctx->amp_dev2 = sdw_dev2; ctx->amp_dev2 = sdw_dev2;
/* /*
* if two 1308s are in one dai link, the init function * if two amps are in one dai link, the init function
* in this dai link will be first set for the first speaker, * in this dai link will be first set for the first speaker,
* and it should be reset to initialize all speakers when * and it should be reset to initialize all speakers when
* the second speaker is found. * the second speaker is found.
......
...@@ -78,6 +78,11 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = { ...@@ -78,6 +78,11 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = {
.quirk_data = &mx98360a_spk, .quirk_data = &mx98360a_spk,
.sof_tplg_filename = "sof-jsl-rt5682-mx98360a.tplg", .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", .id = "10134242",
.drv_name = "jsl_cs4242_mx98360a", .drv_name = "jsl_cs4242_mx98360a",
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <sound/hda_register.h>
#include "../common/sst-dsp.h" #include "../common/sst-dsp.h"
#include "../common/sst-dsp-priv.h" #include "../common/sst-dsp-priv.h"
...@@ -79,21 +80,25 @@ static void skl_cldma_setup_bdle(struct sst_dsp *ctx, ...@@ -79,21 +80,25 @@ static void skl_cldma_setup_bdle(struct sst_dsp *ctx,
__le32 **bdlp, int size, int with_ioc) __le32 **bdlp, int size, int with_ioc)
{ {
__le32 *bdl = *bdlp; __le32 *bdl = *bdlp;
int remaining = ctx->cl_dev.bufsize;
int offset = 0;
ctx->cl_dev.frags = 0; ctx->cl_dev.frags = 0;
while (size > 0) { while (remaining > 0) {
phys_addr_t addr = virt_to_phys(dmab_data->area + phys_addr_t addr;
(ctx->cl_dev.frags * ctx->cl_dev.bufsize)); int chunk;
addr = snd_sgbuf_get_addr(dmab_data, offset);
bdl[0] = cpu_to_le32(lower_32_bits(addr)); bdl[0] = cpu_to_le32(lower_32_bits(addr));
bdl[1] = cpu_to_le32(upper_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); remaining -= chunk;
bdl[3] = (remaining > 0) ? 0 : cpu_to_le32(0x01);
size -= ctx->cl_dev.bufsize;
bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01);
bdl += 4; bdl += 4;
offset += chunk;
ctx->cl_dev.frags++; ctx->cl_dev.frags++;
} }
} }
...@@ -338,15 +343,15 @@ int skl_cldma_prepare(struct sst_dsp *ctx) ...@@ -338,15 +343,15 @@ int skl_cldma_prepare(struct sst_dsp *ctx)
ctx->cl_dev.ops.cl_stop_dma = skl_cldma_stop; ctx->cl_dev.ops.cl_stop_dma = skl_cldma_stop;
/* Allocate buffer*/ /* Allocate buffer*/
ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev, ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, ctx->dev, ctx->cl_dev.bufsize,
&ctx->cl_dev.dmab_data, ctx->cl_dev.bufsize); &ctx->cl_dev.dmab_data);
if (ret < 0) { if (ret < 0) {
dev_err(ctx->dev, "Alloc buffer for base fw failed: %x\n", ret); dev_err(ctx->dev, "Alloc buffer for base fw failed: %x\n", ret);
return ret; return ret;
} }
/* Setup Code loader BDL */ /* Setup Code loader BDL */
ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev, ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, ctx->dev, BDL_SIZE, &ctx->cl_dev.dmab_bdl);
&ctx->cl_dev.dmab_bdl, PAGE_SIZE);
if (ret < 0) { if (ret < 0) {
dev_err(ctx->dev, "Alloc buffer for blde failed: %x\n", ret); 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); ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data);
......
...@@ -582,36 +582,10 @@ static int skl_tplg_unload_pipe_modules(struct skl_dev *skl, ...@@ -582,36 +582,10 @@ static int skl_tplg_unload_pipe_modules(struct skl_dev *skl,
return ret; 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; pipe->cur_config_idx = idx;
struct skl_pipe_fmt *next_fmt; pipe->memory_pages = pipe->configs[idx].mem_pages;
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;
} }
/* /*
...@@ -632,24 +606,14 @@ skl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig) ...@@ -632,24 +606,14 @@ skl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig)
int i; int i;
if (pipe->nr_cfgs == 0) { if (pipe->nr_cfgs == 0) {
pipe->cur_config_idx = 0; skl_tplg_set_pipe_config_idx(pipe, 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);
return 0; return 0;
} }
if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE || pipe->nr_cfgs == 1) { 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", dev_dbg(skl->dev, "No conn_type or just 1 pathcfg, taking 0th for %d\n",
pipe->ppl_id); pipe->ppl_id);
pipe->cur_config_idx = 0; skl_tplg_set_pipe_config_idx(pipe, 0);
pipe->memory_pages = pconfig->mem_pages;
return 0; return 0;
} }
...@@ -668,10 +632,8 @@ skl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig) ...@@ -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, if (CHECK_HW_PARAMS(params->ch, params->s_freq, params->s_fmt,
fmt->channels, fmt->freq, fmt->bps)) { fmt->channels, fmt->freq, fmt->bps)) {
pipe->cur_config_idx = i; skl_tplg_set_pipe_config_idx(pipe, i);
pipe->memory_pages = pconfig->mem_pages;
dev_dbg(skl->dev, "Using pipe config: %d\n", i); dev_dbg(skl->dev, "Using pipe config: %d\n", i);
return 0; return 0;
} }
} }
...@@ -1391,9 +1353,9 @@ static int skl_tplg_multi_config_set_get(struct snd_kcontrol *kcontrol, ...@@ -1391,9 +1353,9 @@ static int skl_tplg_multi_config_set_get(struct snd_kcontrol *kcontrol,
return -EIO; return -EIO;
if (is_set) 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 else
ucontrol->value.enumerated.item[0] = pipe->pipe_config_idx; ucontrol->value.enumerated.item[0] = pipe->cur_config_idx;
return 0; return 0;
} }
...@@ -1837,20 +1799,28 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai, ...@@ -1837,20 +1799,28 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
{ {
struct nhlt_specific_cfg *cfg; struct nhlt_specific_cfg *cfg;
struct skl_pipe *pipe = mconfig->pipe; struct skl_pipe *pipe = mconfig->pipe;
struct skl_pipe_params save = *pipe->p_params;
struct skl_pipe_fmt *pipe_fmt; struct skl_pipe_fmt *pipe_fmt;
struct skl_dev *skl = get_skl_ctx(dai->dev); struct skl_dev *skl = get_skl_ctx(dai->dev);
int link_type = skl_tplg_be_link_type(mconfig->dev_type); int link_type = skl_tplg_be_link_type(mconfig->dev_type);
u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type); u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type);
int ret;
skl_tplg_fill_dma_id(mconfig, params); skl_tplg_fill_dma_id(mconfig, params);
if (link_type == NHLT_LINK_HDA) if (link_type == NHLT_LINK_HDA)
return 0; 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) 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 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*/ /* update the blob based on virtual bus_id*/
cfg = intel_nhlt_get_endpoint_blob(dai->dev, skl->nhlt, 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, ...@@ -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", 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, mconfig->vbus_id, link_type, params->stream,
params->ch, params->s_freq, params->s_fmt); params->ch, params->s_freq, params->s_fmt);
return -EINVAL; ret = -EINVAL;
goto err;
} }
return 0; return 0;
err:
*pipe->p_params = save;
return ret;
} }
static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai, static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai,
......
...@@ -324,7 +324,6 @@ struct skl_pipe { ...@@ -324,7 +324,6 @@ struct skl_pipe {
struct skl_path_config configs[SKL_MAX_PATH_CONFIGS]; struct skl_path_config configs[SKL_MAX_PATH_CONFIGS];
struct list_head w_list; struct list_head w_list;
bool passthru; bool passthru;
u32 pipe_config_idx;
}; };
enum skl_module_state { enum skl_module_state {
......
...@@ -1107,7 +1107,10 @@ static void skl_shutdown(struct pci_dev *pci) ...@@ -1107,7 +1107,10 @@ static void skl_shutdown(struct pci_dev *pci)
if (!skl->init_done) if (!skl->init_done)
return; 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) { list_for_each_entry(s, &bus->stream_list, list) {
stream = stream_to_hdac_ext_stream(s); stream = stream_to_hdac_ext_stream(s);
snd_hdac_ext_stream_decouple(bus, stream, false); snd_hdac_ext_stream_decouple(bus, stream, false);
......
...@@ -200,14 +200,16 @@ static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev) ...@@ -200,14 +200,16 @@ static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev)
if (!mt8173_rt5650_rt5514_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node) { if (!mt8173_rt5650_rt5514_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"Property 'audio-codec' missing or invalid\n"); "Property 'audio-codec' missing or invalid\n");
return -EINVAL; ret = -EINVAL;
goto out;
} }
mt8173_rt5650_rt5514_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node = mt8173_rt5650_rt5514_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node =
of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1); of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1);
if (!mt8173_rt5650_rt5514_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node) { if (!mt8173_rt5650_rt5514_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"Property 'audio-codec' missing or invalid\n"); "Property 'audio-codec' missing or invalid\n");
return -EINVAL; ret = -EINVAL;
goto out;
} }
mt8173_rt5650_rt5514_codec_conf[0].dlc.of_node = mt8173_rt5650_rt5514_codec_conf[0].dlc.of_node =
mt8173_rt5650_rt5514_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node; mt8173_rt5650_rt5514_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node;
...@@ -216,6 +218,7 @@ static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev) ...@@ -216,6 +218,7 @@ static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev)
ret = devm_snd_soc_register_card(&pdev->dev, card); ret = devm_snd_soc_register_card(&pdev->dev, card);
out:
of_node_put(platform_node); of_node_put(platform_node);
return ret; return ret;
} }
......
...@@ -677,8 +677,10 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev) ...@@ -677,8 +677,10 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev)
} }
card = (struct snd_soc_card *)of_device_get_match_data(&pdev->dev); card = (struct snd_soc_card *)of_device_get_match_data(&pdev->dev);
if (!card) if (!card) {
of_node_put(platform_node);
return -EINVAL; return -EINVAL;
}
card->dev = &pdev->dev; card->dev = &pdev->dev;
ec_codec = of_parse_phandle(pdev->dev.of_node, "mediatek,ec-codec", 0); ec_codec = of_parse_phandle(pdev->dev.of_node, "mediatek,ec-codec", 0);
...@@ -767,8 +769,10 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev) ...@@ -767,8 +769,10 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev)
} }
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv) if (!priv) {
return -ENOMEM; ret = -ENOMEM;
goto out;
}
snd_soc_card_set_drvdata(card, priv); snd_soc_card_set_drvdata(card, priv);
...@@ -776,7 +780,8 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev) ...@@ -776,7 +780,8 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev)
if (IS_ERR(priv->pinctrl)) { if (IS_ERR(priv->pinctrl)) {
dev_err(&pdev->dev, "%s devm_pinctrl_get failed\n", dev_err(&pdev->dev, "%s devm_pinctrl_get failed\n",
__func__); __func__);
return PTR_ERR(priv->pinctrl); ret = PTR_ERR(priv->pinctrl);
goto out;
} }
for (i = 0; i < PIN_STATE_MAX; i++) { for (i = 0; i < PIN_STATE_MAX; i++) {
...@@ -809,6 +814,7 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev) ...@@ -809,6 +814,7 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev)
ret = devm_snd_soc_register_card(&pdev->dev, card); ret = devm_snd_soc_register_card(&pdev->dev, card);
out:
of_node_put(platform_node); of_node_put(platform_node);
of_node_put(ec_codec); of_node_put(ec_codec);
of_node_put(hdmi_codec); of_node_put(hdmi_codec);
......
...@@ -431,6 +431,7 @@ static int rockchip_pdm_runtime_resume(struct device *dev) ...@@ -431,6 +431,7 @@ static int rockchip_pdm_runtime_resume(struct device *dev)
ret = clk_prepare_enable(pdm->hclk); ret = clk_prepare_enable(pdm->hclk);
if (ret) { if (ret) {
clk_disable_unprepare(pdm->clk);
dev_err(pdm->dev, "hclock enable failed %d\n", ret); dev_err(pdm->dev, "hclock enable failed %d\n", ret);
return ret; return ret;
} }
......
...@@ -709,8 +709,17 @@ static int soc_pcm_clean(struct snd_soc_pcm_runtime *rtd, ...@@ -709,8 +709,17 @@ static int soc_pcm_clean(struct snd_soc_pcm_runtime *rtd,
snd_soc_dpcm_mutex_assert_held(rtd); snd_soc_dpcm_mutex_assert_held(rtd);
if (!rollback) if (!rollback) {
snd_soc_runtime_deactivate(rtd, substream->stream); snd_soc_runtime_deactivate(rtd, substream->stream);
/* clear the corresponding DAIs parameters when going to be inactive */
for_each_rtd_dais(rtd, i, dai) {
if (snd_soc_dai_active(dai) == 0)
soc_pcm_set_dai_params(dai, NULL);
if (snd_soc_dai_stream_active(dai, substream->stream) == 0)
snd_soc_dai_digital_mute(dai, 1, substream->stream);
}
}
for_each_rtd_dais(rtd, i, dai) for_each_rtd_dais(rtd, i, dai)
snd_soc_dai_shutdown(dai, substream, rollback); snd_soc_dai_shutdown(dai, substream, rollback);
...@@ -940,15 +949,6 @@ static int soc_pcm_hw_clean(struct snd_soc_pcm_runtime *rtd, ...@@ -940,15 +949,6 @@ static int soc_pcm_hw_clean(struct snd_soc_pcm_runtime *rtd,
snd_soc_dpcm_mutex_assert_held(rtd); snd_soc_dpcm_mutex_assert_held(rtd);
/* clear the corresponding DAIs parameters when going to be inactive */
for_each_rtd_dais(rtd, i, dai) {
if (snd_soc_dai_active(dai) == 1)
soc_pcm_set_dai_params(dai, NULL);
if (snd_soc_dai_stream_active(dai, substream->stream) == 1)
snd_soc_dai_digital_mute(dai, 1, substream->stream);
}
/* run the stream event */ /* run the stream event */
snd_soc_dapm_stream_stop(rtd, substream->stream); snd_soc_dapm_stream_stop(rtd, substream->stream);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment